Bug Summary

File:out/../deps/icu-small/source/common/umutex.h
Warning:line 89, column 12
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name unistr.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/maurizio/node-v18.6.0/out -resource-dir /usr/local/lib/clang/16.0.0 -D V8_DEPRECATION_WARNINGS -D V8_IMMINENT_DEPRECATION_WARNINGS -D _GLIBCXX_USE_CXX11_ABI=1 -D NODE_OPENSSL_CONF_NAME=nodejs_conf -D NODE_OPENSSL_HAS_QUIC -D __STDC_FORMAT_MACROS -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D U_COMMON_IMPLEMENTATION=1 -D U_ATTRIBUTE_DEPRECATED= -D _CRT_SECURE_NO_DEPRECATE= -D U_STATIC_IMPLEMENTATION=1 -D UCONFIG_NO_SERVICE=1 -D U_ENABLE_DYLOAD=0 -D U_HAVE_STD_STRING=1 -D UCONFIG_NO_BREAK_ITERATION=0 -I ../deps/icu-small/source/common -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward -internal-isystem /usr/local/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-deprecated-declarations -Wno-strict-aliasing -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/home/maurizio/node-v18.6.0/out -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-08-22-142216-507842-1 -x c++ ../deps/icu-small/source/common/unistr.cpp

../deps/icu-small/source/common/unistr.cpp

1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4******************************************************************************
5* Copyright (C) 1999-2016, International Business Machines Corporation and
6* others. All Rights Reserved.
7******************************************************************************
8*
9* File unistr.cpp
10*
11* Modification History:
12*
13* Date Name Description
14* 09/25/98 stephen Creation.
15* 04/20/99 stephen Overhauled per 4/16 code review.
16* 07/09/99 stephen Renamed {hi,lo},{byte,word} to icu_X for HP/UX
17* 11/18/99 aliu Added handleReplaceBetween() to make inherit from
18* Replaceable.
19* 06/25/01 grhoten Removed the dependency on iostream
20******************************************************************************
21*/
22
23#include "unicode/utypes.h"
24#include "unicode/appendable.h"
25#include "unicode/putil.h"
26#include "cstring.h"
27#include "cmemory.h"
28#include "unicode/ustring.h"
29#include "unicode/unistr.h"
30#include "unicode/utf.h"
31#include "unicode/utf16.h"
32#include "uelement.h"
33#include "ustr_imp.h"
34#include "umutex.h"
35#include "uassert.h"
36
37#if 0
38
39#include <iostream>
40using namespace std;
41
42//DEBUGGING
43void
44print(const UnicodeString& s,
45 const char *name)
46{
47 UChar c;
48 cout << name << ":|";
49 for(int i = 0; i < s.length(); ++i) {
50 c = s[i];
51 if(c>= 0x007E || c < 0x0020)
52 cout << "[0x" << hex << s[i] << "]";
53 else
54 cout << (char) s[i];
55 }
56 cout << '|' << endl;
57}
58
59void
60print(const UChar *s,
61 int32_t len,
62 const char *name)
63{
64 UChar c;
65 cout << name << ":|";
66 for(int i = 0; i < len; ++i) {
67 c = s[i];
68 if(c>= 0x007E || c < 0x0020)
69 cout << "[0x" << hex << s[i] << "]";
70 else
71 cout << (char) s[i];
72 }
73 cout << '|' << endl;
74}
75// END DEBUGGING
76#endif
77
78// Local function definitions for now
79
80// need to copy areas that may overlap
81static
82inline void
83us_arrayCopy(const UChar *src, int32_t srcStart,
84 UChar *dst, int32_t dstStart, int32_t count)
85{
86 if(count>0) {
87 uprv_memmove(dst+dstStart, src+srcStart, (size_t)count*sizeof(*src))do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memmove(dst+dstStart
, src+srcStart, (size_t)count*sizeof(*src)); } while (false)
;
88 }
89}
90
91// u_unescapeAt() callback to get a UChar from a UnicodeString
92U_CDECL_BEGINextern "C" {
93static UChar U_CALLCONV
94UnicodeString_charAt(int32_t offset, void *context) {
95 return ((icu::UnicodeString*) context)->charAt(offset);
96}
97U_CDECL_END}
98
99U_NAMESPACE_BEGINnamespace icu_71 {
100
101/* The Replaceable virtual destructor can't be defined in the header
102 due to how AIX works with multiple definitions of virtual functions.
103*/
104Replaceable::~Replaceable() {}
105
106UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UnicodeString)UClassID UnicodeString::getStaticClassID() { static char classID
= 0; return (UClassID)&classID; } UClassID UnicodeString
::getDynamicClassID() const { return UnicodeString::getStaticClassID
(); }
107
108UnicodeString U_EXPORT2
109operator+ (const UnicodeString &s1, const UnicodeString &s2) {
110 return
111 UnicodeString(s1.length()+s2.length()+1, (UChar32)0, 0).
112 append(s1).
113 append(s2);
114}
115
116//========================================
117// Reference Counting functions, put at top of file so that optimizing compilers
118// have a chance to automatically inline.
119//========================================
120
121void
122UnicodeString::addRef() {
123 umtx_atomic_inc((u_atomic_int32_t *)fUnion.fFields.fArray - 1);
124}
125
126int32_t
127UnicodeString::removeRef() {
128 return umtx_atomic_dec((u_atomic_int32_t *)fUnion.fFields.fArray - 1);
21
Passing null pointer value via 1st parameter 'var'
22
Calling 'umtx_atomic_dec'
129}
130
131int32_t
132UnicodeString::refCount() const {
133 return umtx_loadAcquire(*((u_atomic_int32_t *)fUnion.fFields.fArray - 1));
134}
135
136void
137UnicodeString::releaseArray() {
138 if((fUnion.fFields.fLengthAndFlags & kRefCounted) && removeRef() == 0) {
19
Assuming the condition is true
20
Calling 'UnicodeString::removeRef'
139 uprv_freeuprv_free_71((int32_t *)fUnion.fFields.fArray - 1);
140 }
141}
142
143
144
145//========================================
146// Constructors
147//========================================
148
149// The default constructor is inline in unistr.h.
150
151UnicodeString::UnicodeString(int32_t capacity, UChar32 c, int32_t count) {
152 fUnion.fFields.fLengthAndFlags = 0;
153 if(count <= 0 || (uint32_t)c > 0x10ffff) {
154 // just allocate and do not do anything else
155 allocate(capacity);
156 } else if(c <= 0xffff) {
157 int32_t length = count;
158 if(capacity < length) {
159 capacity = length;
160 }
161 if(allocate(capacity)) {
162 UChar *array = getArrayStart();
163 UChar unit = (UChar)c;
164 for(int32_t i = 0; i < length; ++i) {
165 array[i] = unit;
166 }
167 setLength(length);
168 }
169 } else { // supplementary code point, write surrogate pairs
170 if(count > (INT32_MAX(2147483647) / 2)) {
171 // We would get more than 2G UChars.
172 allocate(capacity);
173 return;
174 }
175 int32_t length = count * 2;
176 if(capacity < length) {
177 capacity = length;
178 }
179 if(allocate(capacity)) {
180 UChar *array = getArrayStart();
181 UChar lead = U16_LEAD(c)(UChar)(((c)>>10)+0xd7c0);
182 UChar trail = U16_TRAIL(c)(UChar)(((c)&0x3ff)|0xdc00);
183 for(int32_t i = 0; i < length; i += 2) {
184 array[i] = lead;
185 array[i + 1] = trail;
186 }
187 setLength(length);
188 }
189 }
190}
191
192UnicodeString::UnicodeString(UChar ch) {
193 fUnion.fFields.fLengthAndFlags = kLength1 | kShortString;
194 fUnion.fStackFields.fBuffer[0] = ch;
195}
196
197UnicodeString::UnicodeString(UChar32 ch) {
198 fUnion.fFields.fLengthAndFlags = kShortString;
199 int32_t i = 0;
200 UBool isError = FALSE0;
201 U16_APPEND(fUnion.fStackFields.fBuffer, i, US_STACKBUF_SIZE, ch, isError)do { if((uint32_t)(ch)<=0xffff) { (fUnion.fStackFields.fBuffer
)[(i)++]=(uint16_t)(ch); } else if((uint32_t)(ch)<=0x10ffff
&& (i)+1<(US_STACKBUF_SIZE)) { (fUnion.fStackFields
.fBuffer)[(i)++]=(uint16_t)(((ch)>>10)+0xd7c0); (fUnion
.fStackFields.fBuffer)[(i)++]=(uint16_t)(((ch)&0x3ff)|0xdc00
); } else { (isError)=true; } } while (false)
;
202 // We test isError so that the compiler does not complain that we don't.
203 // If isError then i==0 which is what we want anyway.
204 if(!isError) {
205 setShortLength(i);
206 }
207}
208
209UnicodeString::UnicodeString(const UChar *text) {
210 fUnion.fFields.fLengthAndFlags = kShortString;
211 doAppend(text, 0, -1);
212}
213
214UnicodeString::UnicodeString(const UChar *text,
215 int32_t textLength) {
216 fUnion.fFields.fLengthAndFlags = kShortString;
217 doAppend(text, 0, textLength);
218}
219
220UnicodeString::UnicodeString(UBool isTerminated,
221 ConstChar16Ptr textPtr,
222 int32_t textLength) {
223 fUnion.fFields.fLengthAndFlags = kReadonlyAlias;
224 const UChar *text = textPtr;
225 if(text == NULL__null) {
226 // treat as an empty string, do not alias
227 setToEmpty();
228 } else if(textLength < -1 ||
229 (textLength == -1 && !isTerminated) ||
230 (textLength >= 0 && isTerminated && text[textLength] != 0)
231 ) {
232 setToBogus();
233 } else {
234 if(textLength == -1) {
235 // text is terminated, or else it would have failed the above test
236 textLength = u_strlenu_strlen_71(text);
237 }
238 setArray(const_cast<UChar *>(text), textLength,
239 isTerminated ? textLength + 1 : textLength);
240 }
241}
242
243UnicodeString::UnicodeString(UChar *buff,
244 int32_t buffLength,
245 int32_t buffCapacity) {
246 fUnion.fFields.fLengthAndFlags = kWritableAlias;
247 if(buff == NULL__null) {
248 // treat as an empty string, do not alias
249 setToEmpty();
250 } else if(buffLength < -1 || buffCapacity < 0 || buffLength > buffCapacity) {
251 setToBogus();
252 } else {
253 if(buffLength == -1) {
254 // fLength = u_strlen(buff); but do not look beyond buffCapacity
255 const UChar *p = buff, *limit = buff + buffCapacity;
256 while(p != limit && *p != 0) {
257 ++p;
258 }
259 buffLength = (int32_t)(p - buff);
260 }
261 setArray(buff, buffLength, buffCapacity);
262 }
263}
264
265UnicodeString::UnicodeString(const char *src, int32_t length, EInvariant) {
266 fUnion.fFields.fLengthAndFlags = kShortString;
267 if(src==NULL__null) {
268 // treat as an empty string
269 } else {
270 if(length<0) {
271 length=(int32_t)uprv_strlen(src):: strlen(src);
272 }
273 if(cloneArrayIfNeeded(length, length, FALSE0)) {
274 u_charsToUCharsu_charsToUChars_71(src, getArrayStart(), length);
275 setLength(length);
276 } else {
277 setToBogus();
278 }
279 }
280}
281
282#if U_CHARSET_IS_UTF81
283
284UnicodeString::UnicodeString(const char *codepageData) {
285 fUnion.fFields.fLengthAndFlags = kShortString;
286 if(codepageData != 0) {
287 setToUTF8(codepageData);
288 }
289}
290
291UnicodeString::UnicodeString(const char *codepageData, int32_t dataLength) {
292 fUnion.fFields.fLengthAndFlags = kShortString;
293 // if there's nothing to convert, do nothing
294 if(codepageData == 0 || dataLength == 0 || dataLength < -1) {
295 return;
296 }
297 if(dataLength == -1) {
298 dataLength = (int32_t)uprv_strlen(codepageData):: strlen(codepageData);
299 }
300 setToUTF8(StringPiece(codepageData, dataLength));
301}
302
303// else see unistr_cnv.cpp
304#endif
305
306UnicodeString::UnicodeString(const UnicodeString& that) {
307 fUnion.fFields.fLengthAndFlags = kShortString;
308 copyFrom(that);
309}
310
311UnicodeString::UnicodeString(UnicodeString &&src) U_NOEXCEPTnoexcept {
312 copyFieldsFrom(src, TRUE1);
313}
314
315UnicodeString::UnicodeString(const UnicodeString& that,
316 int32_t srcStart) {
317 fUnion.fFields.fLengthAndFlags = kShortString;
318 setTo(that, srcStart);
319}
320
321UnicodeString::UnicodeString(const UnicodeString& that,
322 int32_t srcStart,
323 int32_t srcLength) {
324 fUnion.fFields.fLengthAndFlags = kShortString;
325 setTo(that, srcStart, srcLength);
326}
327
328// Replaceable base class clone() default implementation, does not clone
329Replaceable *
330Replaceable::clone() const {
331 return NULL__null;
332}
333
334// UnicodeString overrides clone() with a real implementation
335UnicodeString *
336UnicodeString::clone() const {
337 LocalPointer<UnicodeString> clonedString(new UnicodeString(*this));
338 return clonedString.isValid() && !clonedString->isBogus() ? clonedString.orphan() : nullptr;
339}
340
341//========================================
342// array allocation
343//========================================
344
345namespace {
346
347const int32_t kGrowSize = 128;
348
349// The number of bytes for one int32_t reference counter and capacity UChars
350// must fit into a 32-bit size_t (at least when on a 32-bit platform).
351// We also add one for the NUL terminator, to avoid reallocation in getTerminatedBuffer(),
352// and round up to a multiple of 16 bytes.
353// This means that capacity must be at most (0xfffffff0 - 4) / 2 - 1 = 0x7ffffff5.
354// (With more complicated checks we could go up to 0x7ffffffd without rounding up,
355// but that does not seem worth it.)
356const int32_t kMaxCapacity = 0x7ffffff5;
357
358int32_t getGrowCapacity(int32_t newLength) {
359 int32_t growSize = (newLength >> 2) + kGrowSize;
360 if(growSize <= (kMaxCapacity - newLength)) {
361 return newLength + growSize;
362 } else {
363 return kMaxCapacity;
364 }
365}
366
367} // namespace
368
369UBool
370UnicodeString::allocate(int32_t capacity) {
371 if(capacity
10.1
'capacity' is > US_STACKBUF_SIZE
10.1
'capacity' is > US_STACKBUF_SIZE
<= US_STACKBUF_SIZE) {
11
Taking false branch
372 fUnion.fFields.fLengthAndFlags = kShortString;
373 return TRUE1;
374 }
375 if(capacity <= kMaxCapacity) {
12
Assuming 'capacity' is > 'kMaxCapacity'
13
Taking false branch
376 ++capacity; // for the NUL
377 // Switch to size_t which is unsigned so that we can allocate up to 4GB.
378 // Reference counter + UChars.
379 size_t numBytes = sizeof(int32_t) + (size_t)capacity * U_SIZEOF_UCHAR2;
380 // Round up to a multiple of 16.
381 numBytes = (numBytes + 15) & ~15;
382 int32_t *array = (int32_t *) uprv_mallocuprv_malloc_71(numBytes);
383 if(array != NULL__null) {
384 // set initial refCount and point behind the refCount
385 *array++ = 1;
386 numBytes -= sizeof(int32_t);
387
388 // have fArray point to the first UChar
389 fUnion.fFields.fArray = (UChar *)array;
390 fUnion.fFields.fCapacity = (int32_t)(numBytes / U_SIZEOF_UCHAR2);
391 fUnion.fFields.fLengthAndFlags = kLongString;
392 return TRUE1;
393 }
394 }
395 fUnion.fFields.fLengthAndFlags = kIsBogus;
396 fUnion.fFields.fArray = 0;
14
Null pointer value stored to field 'fArray'
397 fUnion.fFields.fCapacity = 0;
398 return FALSE0;
399}
400
401//========================================
402// Destructor
403//========================================
404
405#ifdef UNISTR_COUNT_FINAL_STRING_LENGTHS
406static u_atomic_int32_t finalLengthCounts[0x400]; // UnicodeString::kMaxShortLength+1
407static u_atomic_int32_t beyondCount(0);
408
409U_CAPIextern "C" void unistr_printLengths() {
410 int32_t i;
411 for(i = 0; i <= 59; ++i) {
412 printf("%2d, %9d\n", i, (int32_t)finalLengthCounts[i]);
413 }
414 int32_t beyond = beyondCount;
415 for(; i < UPRV_LENGTHOF(finalLengthCounts)(int32_t)(sizeof(finalLengthCounts)/sizeof((finalLengthCounts
)[0]))
; ++i) {
416 beyond += finalLengthCounts[i];
417 }
418 printf(">59, %9d\n", beyond);
419}
420#endif
421
422UnicodeString::~UnicodeString()
423{
424#ifdef UNISTR_COUNT_FINAL_STRING_LENGTHS
425 // Count lengths of strings at the end of their lifetime.
426 // Useful for discussion of a desirable stack buffer size.
427 // Count the contents length, not the optional NUL terminator nor further capacity.
428 // Ignore open-buffer strings and strings which alias external storage.
429 if((fUnion.fFields.fLengthAndFlags&(kOpenGetBuffer|kReadonlyAlias|kWritableAlias)) == 0) {
430 if(hasShortLength()) {
431 umtx_atomic_inc(finalLengthCounts + getShortLength());
432 } else {
433 umtx_atomic_inc(&beyondCount);
434 }
435 }
436#endif
437
438 releaseArray();
439}
440
441//========================================
442// Factory methods
443//========================================
444
445UnicodeString UnicodeString::fromUTF8(StringPiece utf8) {
446 UnicodeString result;
447 result.setToUTF8(utf8);
448 return result;
449}
450
451UnicodeString UnicodeString::fromUTF32(const UChar32 *utf32, int32_t length) {
452 UnicodeString result;
453 int32_t capacity;
454 // Most UTF-32 strings will be BMP-only and result in a same-length
455 // UTF-16 string. We overestimate the capacity just slightly,
456 // just in case there are a few supplementary characters.
457 if(length <= US_STACKBUF_SIZE) {
458 capacity = US_STACKBUF_SIZE;
459 } else {
460 capacity = length + (length >> 4) + 4;
461 }
462 do {
463 UChar *utf16 = result.getBuffer(capacity);
464 int32_t length16;
465 UErrorCode errorCode = U_ZERO_ERROR;
466 u_strFromUTF32WithSubu_strFromUTF32WithSub_71(utf16, result.getCapacity(), &length16,
467 utf32, length,
468 0xfffd, // Substitution character.
469 NULL__null, // Don't care about number of substitutions.
470 &errorCode);
471 result.releaseBuffer(length16);
472 if(errorCode == U_BUFFER_OVERFLOW_ERROR) {
473 capacity = length16 + 1; // +1 for the terminating NUL.
474 continue;
475 } else if(U_FAILURE(errorCode)) {
476 result.setToBogus();
477 }
478 break;
479 } while(TRUE1);
480 return result;
481}
482
483//========================================
484// Assignment
485//========================================
486
487UnicodeString &
488UnicodeString::operator=(const UnicodeString &src) {
489 return copyFrom(src);
490}
491
492UnicodeString &
493UnicodeString::fastCopyFrom(const UnicodeString &src) {
494 return copyFrom(src, TRUE1);
495}
496
497UnicodeString &
498UnicodeString::copyFrom(const UnicodeString &src, UBool fastCopy) {
499 // if assigning to ourselves, do nothing
500 if(this == &src) {
501 return *this;
502 }
503
504 // is the right side bogus?
505 if(src.isBogus()) {
506 setToBogus();
507 return *this;
508 }
509
510 // delete the current contents
511 releaseArray();
512
513 if(src.isEmpty()) {
514 // empty string - use the stack buffer
515 setToEmpty();
516 return *this;
517 }
518
519 // fLength>0 and not an "open" src.getBuffer(minCapacity)
520 fUnion.fFields.fLengthAndFlags = src.fUnion.fFields.fLengthAndFlags;
521 switch(src.fUnion.fFields.fLengthAndFlags & kAllStorageFlags) {
522 case kShortString:
523 // short string using the stack buffer, do the same
524 uprv_memcpy(fUnion.fStackFields.fBuffer, src.fUnion.fStackFields.fBuffer,do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(fUnion.fStackFields
.fBuffer, src.fUnion.fStackFields.fBuffer, getShortLength() *
2); } while (false)
525 getShortLength() * U_SIZEOF_UCHAR)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(fUnion.fStackFields
.fBuffer, src.fUnion.fStackFields.fBuffer, getShortLength() *
2); } while (false)
;
526 break;
527 case kLongString:
528 // src uses a refCounted string buffer, use that buffer with refCount
529 // src is const, use a cast - we don't actually change it
530 ((UnicodeString &)src).addRef();
531 // copy all fields, share the reference-counted buffer
532 fUnion.fFields.fArray = src.fUnion.fFields.fArray;
533 fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity;
534 if(!hasShortLength()) {
535 fUnion.fFields.fLength = src.fUnion.fFields.fLength;
536 }
537 break;
538 case kReadonlyAlias:
539 if(fastCopy) {
540 // src is a readonly alias, do the same
541 // -> maintain the readonly alias as such
542 fUnion.fFields.fArray = src.fUnion.fFields.fArray;
543 fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity;
544 if(!hasShortLength()) {
545 fUnion.fFields.fLength = src.fUnion.fFields.fLength;
546 }
547 break;
548 }
549 // else if(!fastCopy) fall through to case kWritableAlias
550 // -> allocate a new buffer and copy the contents
551 U_FALLTHROUGH[[clang::fallthrough]];
552 case kWritableAlias: {
553 // src is a writable alias; we make a copy of that instead
554 int32_t srcLength = src.length();
555 if(allocate(srcLength)) {
556 u_memcpyu_memcpy_71(getArrayStart(), src.getArrayStart(), srcLength);
557 setLength(srcLength);
558 break;
559 }
560 // if there is not enough memory, then fall through to setting to bogus
561 U_FALLTHROUGH[[clang::fallthrough]];
562 }
563 default:
564 // if src is bogus, set ourselves to bogus
565 // do not call setToBogus() here because fArray and flags are not consistent here
566 fUnion.fFields.fLengthAndFlags = kIsBogus;
567 fUnion.fFields.fArray = 0;
568 fUnion.fFields.fCapacity = 0;
569 break;
570 }
571
572 return *this;
573}
574
575UnicodeString &UnicodeString::operator=(UnicodeString &&src) U_NOEXCEPTnoexcept {
576 // No explicit check for self move assignment, consistent with standard library.
577 // Self move assignment causes no crash nor leak but might make the object bogus.
578 releaseArray();
579 copyFieldsFrom(src, TRUE1);
580 return *this;
581}
582
583// Same as move assignment except without memory management.
584void UnicodeString::copyFieldsFrom(UnicodeString &src, UBool setSrcToBogus) U_NOEXCEPTnoexcept {
585 int16_t lengthAndFlags = fUnion.fFields.fLengthAndFlags = src.fUnion.fFields.fLengthAndFlags;
586 if(lengthAndFlags & kUsingStackBuffer) {
587 // Short string using the stack buffer, copy the contents.
588 // Check for self assignment to prevent "overlap in memcpy" warnings,
589 // although it should be harmless to copy a buffer to itself exactly.
590 if(this != &src) {
591 uprv_memcpy(fUnion.fStackFields.fBuffer, src.fUnion.fStackFields.fBuffer,do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(fUnion.fStackFields
.fBuffer, src.fUnion.fStackFields.fBuffer, getShortLength() *
2); } while (false)
592 getShortLength() * U_SIZEOF_UCHAR)do { clang diagnostic push clang diagnostic ignored "-Waddress"
(void)0; (void)0; clang diagnostic pop :: memcpy(fUnion.fStackFields
.fBuffer, src.fUnion.fStackFields.fBuffer, getShortLength() *
2); } while (false)
;
593 }
594 } else {
595 // In all other cases, copy all fields.
596 fUnion.fFields.fArray = src.fUnion.fFields.fArray;
597 fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity;
598 if(!hasShortLength()) {
599 fUnion.fFields.fLength = src.fUnion.fFields.fLength;
600 }
601 if(setSrcToBogus) {
602 // Set src to bogus without releasing any memory.
603 src.fUnion.fFields.fLengthAndFlags = kIsBogus;
604 src.fUnion.fFields.fArray = NULL__null;
605 src.fUnion.fFields.fCapacity = 0;
606 }
607 }
608}
609
610void UnicodeString::swap(UnicodeString &other) U_NOEXCEPTnoexcept {
611 UnicodeString temp; // Empty short string: Known not to need releaseArray().
612 // Copy fields without resetting source values in between.
613 temp.copyFieldsFrom(*this, FALSE0);
614 this->copyFieldsFrom(other, FALSE0);
615 other.copyFieldsFrom(temp, FALSE0);
616 // Set temp to an empty string so that other's memory is not released twice.
617 temp.fUnion.fFields.fLengthAndFlags = kShortString;
618}
619
620//========================================
621// Miscellaneous operations
622//========================================
623
624UnicodeString UnicodeString::unescape() const {
625 UnicodeString result(length(), (UChar32)0, (int32_t)0); // construct with capacity
626 if (result.isBogus()) {
627 return result;
628 }
629 const UChar *array = getBuffer();
630 int32_t len = length();
631 int32_t prev = 0;
632 for (int32_t i=0;;) {
633 if (i == len) {
634 result.append(array, prev, len - prev);
635 break;
636 }
637 if (array[i++] == 0x5C /*'\\'*/) {
638 result.append(array, prev, (i - 1) - prev);
639 UChar32 c = unescapeAt(i); // advances i
640 if (c < 0) {
641 result.remove(); // return empty string
642 break; // invalid escape sequence
643 }
644 result.append(c);
645 prev = i;
646 }
647 }
648 return result;
649}
650
651UChar32 UnicodeString::unescapeAt(int32_t &offset) const {
652 return u_unescapeAtu_unescapeAt_71(UnicodeString_charAt, &offset, length(), (void*)this);
653}
654
655//========================================
656// Read-only implementation
657//========================================
658UBool
659UnicodeString::doEquals(const UnicodeString &text, int32_t len) const {
660 // Requires: this & text not bogus and have same lengths.
661 // Byte-wise comparison works for equality regardless of endianness.
662 return uprv_memcmp(getArrayStart(), text.getArrayStart(), len * U_SIZEOF_UCHAR):: memcmp(getArrayStart(), text.getArrayStart(),len * 2) == 0;
663}
664
665int8_t
666UnicodeString::doCompare( int32_t start,
667 int32_t length,
668 const UChar *srcChars,
669 int32_t srcStart,
670 int32_t srcLength) const
671{
672 // compare illegal string values
673 if(isBogus()) {
674 return -1;
675 }
676
677 // pin indices to legal values
678 pinIndices(start, length);
679
680 if(srcChars == NULL__null) {
681 // treat const UChar *srcChars==NULL as an empty string
682 return length == 0 ? 0 : 1;
683 }
684
685 // get the correct pointer
686 const UChar *chars = getArrayStart();
687
688 chars += start;
689 srcChars += srcStart;
690
691 int32_t minLength;
692 int8_t lengthResult;
693
694 // get the srcLength if necessary
695 if(srcLength < 0) {
696 srcLength = u_strlenu_strlen_71(srcChars + srcStart);
697 }
698
699 // are we comparing different lengths?
700 if(length != srcLength) {
701 if(length < srcLength) {
702 minLength = length;
703 lengthResult = -1;
704 } else {
705 minLength = srcLength;
706 lengthResult = 1;
707 }
708 } else {
709 minLength = length;
710 lengthResult = 0;
711 }
712
713 /*
714 * note that uprv_memcmp() returns an int but we return an int8_t;
715 * we need to take care not to truncate the result -
716 * one way to do this is to right-shift the value to
717 * move the sign bit into the lower 8 bits and making sure that this
718 * does not become 0 itself
719 */
720
721 if(minLength > 0 && chars != srcChars) {
722 int32_t result;
723
724# if U_IS_BIG_ENDIAN(1234 == 4321)
725 // big-endian: byte comparison works
726 result = uprv_memcmp(chars, srcChars, minLength * sizeof(UChar)):: memcmp(chars, srcChars,minLength * sizeof(UChar));
727 if(result != 0) {
728 return (int8_t)(result >> 15 | 1);
729 }
730# else
731 // little-endian: compare UChar units
732 do {
733 result = ((int32_t)*(chars++) - (int32_t)*(srcChars++));
734 if(result != 0) {
735 return (int8_t)(result >> 15 | 1);
736 }
737 } while(--minLength > 0);
738# endif
739 }
740 return lengthResult;
741}
742
743/* String compare in code point order - doCompare() compares in code unit order. */
744int8_t
745UnicodeString::doCompareCodePointOrder(int32_t start,
746 int32_t length,
747 const UChar *srcChars,
748 int32_t srcStart,
749 int32_t srcLength) const
750{
751 // compare illegal string values
752 // treat const UChar *srcChars==NULL as an empty string
753 if(isBogus()) {
754 return -1;
755 }
756
757 // pin indices to legal values
758 pinIndices(start, length);
759
760 if(srcChars == NULL__null) {
761 srcStart = srcLength = 0;
762 }
763
764 int32_t diff = uprv_strCompareuprv_strCompare_71(getArrayStart() + start, length, (srcChars!=NULL__null)?(srcChars + srcStart):NULL__null, srcLength, FALSE0, TRUE1);
765 /* translate the 32-bit result into an 8-bit one */
766 if(diff!=0) {
767 return (int8_t)(diff >> 15 | 1);
768 } else {
769 return 0;
770 }
771}
772
773int32_t
774UnicodeString::getLength() const {
775 return length();
776}
777
778UChar
779UnicodeString::getCharAt(int32_t offset) const {
780 return charAt(offset);
781}
782
783UChar32
784UnicodeString::getChar32At(int32_t offset) const {
785 return char32At(offset);
786}
787
788UChar32
789UnicodeString::char32At(int32_t offset) const
790{
791 int32_t len = length();
792 if((uint32_t)offset < (uint32_t)len) {
793 const UChar *array = getArrayStart();
794 UChar32 c;
795 U16_GET(array, 0, offset, len, c)do { (c)=(array)[offset]; if((((c)&0xfffff800)==0xd800)) {
uint16_t __c2; if((((c)&0x400)==0)) { if((offset)+1!=(len
) && (((__c2=(array)[(offset)+1])&0xfffffc00)==0xdc00
)) { (c)=(((UChar32)((c))<<10UL)+(UChar32)(__c2)-((0xd800
<<10UL)+0xdc00-0x10000)); } } else { if((offset)>(0)
&& (((__c2=(array)[(offset)-1])&0xfffffc00)==0xd800
)) { (c)=(((UChar32)(__c2)<<10UL)+(UChar32)((c))-((0xd800
<<10UL)+0xdc00-0x10000)); } } } } while (false)
;
796 return c;
797 } else {
798 return kInvalidUChar;
799 }
800}
801
802int32_t
803UnicodeString::getChar32Start(int32_t offset) const {
804 if((uint32_t)offset < (uint32_t)length()) {
805 const UChar *array = getArrayStart();
806 U16_SET_CP_START(array, 0, offset)do { if(((((array)[offset])&0xfffffc00)==0xdc00) &&
(offset)>(0) && ((((array)[(offset)-1])&0xfffffc00
)==0xd800)) { --(offset); } } while (false)
;
807 return offset;
808 } else {
809 return 0;
810 }
811}
812
813int32_t
814UnicodeString::getChar32Limit(int32_t offset) const {
815 int32_t len = length();
816 if((uint32_t)offset < (uint32_t)len) {
817 const UChar *array = getArrayStart();
818 U16_SET_CP_LIMIT(array, 0, offset, len)do { if((0)<(offset) && ((offset)<(len) || (len
)<0) && ((((array)[(offset)-1])&0xfffffc00)==0xd800
) && ((((array)[offset])&0xfffffc00)==0xdc00)) { ++
(offset); } } while (false)
;
819 return offset;
820 } else {
821 return len;
822 }
823}
824
825int32_t
826UnicodeString::countChar32(int32_t start, int32_t length) const {
827 pinIndices(start, length);
828 // if(isBogus()) then fArray==0 and start==0 - u_countChar32() checks for NULL
829 return u_countChar32u_countChar32_71(getArrayStart()+start, length);
830}
831
832UBool
833UnicodeString::hasMoreChar32Than(int32_t start, int32_t length, int32_t number) const {
834 pinIndices(start, length);
835 // if(isBogus()) then fArray==0 and start==0 - u_strHasMoreChar32Than() checks for NULL
836 return u_strHasMoreChar32Thanu_strHasMoreChar32Than_71(getArrayStart()+start, length, number);
837}
838
839int32_t
840UnicodeString::moveIndex32(int32_t index, int32_t delta) const {
841 // pin index
842 int32_t len = length();
843 if(index<0) {
844 index=0;
845 } else if(index>len) {
846 index=len;
847 }
848
849 const UChar *array = getArrayStart();
850 if(delta>0) {
851 U16_FWD_N(array, index, len, delta)do { int32_t __N=(delta); while(__N>0 && ((index)<
(len) || ((len)<0 && (array)[index]!=0))) { do { if
(((((array)[(index)++])&0xfffffc00)==0xd800) && (
index)!=(len) && ((((array)[index])&0xfffffc00)==
0xdc00)) { ++(index); } } while (false); --__N; } } while (false
)
;
852 } else {
853 U16_BACK_N(array, 0, index, -delta)do { int32_t __N=(-delta); while(__N>0 && (index)>
(0)) { do { if(((((array)[--(index)])&0xfffffc00)==0xdc00
) && (index)>(0) && ((((array)[(index)-1])
&0xfffffc00)==0xd800)) { --(index); } } while (false); --
__N; } } while (false)
;
854 }
855
856 return index;
857}
858
859void
860UnicodeString::doExtract(int32_t start,
861 int32_t length,
862 UChar *dst,
863 int32_t dstStart) const
864{
865 // pin indices to legal values
866 pinIndices(start, length);
867
868 // do not copy anything if we alias dst itself
869 const UChar *array = getArrayStart();
870 if(array + start != dst + dstStart) {
871 us_arrayCopy(array, start, dst, dstStart, length);
872 }
873}
874
875int32_t
876UnicodeString::extract(Char16Ptr dest, int32_t destCapacity,
877 UErrorCode &errorCode) const {
878 int32_t len = length();
879 if(U_SUCCESS(errorCode)) {
880 if(isBogus() || destCapacity<0 || (destCapacity>0 && dest==0)) {
881 errorCode=U_ILLEGAL_ARGUMENT_ERROR;
882 } else {
883 const UChar *array = getArrayStart();
884 if(len>0 && len<=destCapacity && array!=dest) {
885 u_memcpyu_memcpy_71(dest, array, len);
886 }
887 return u_terminateUCharsu_terminateUChars_71(dest, destCapacity, len, &errorCode);
888 }
889 }
890
891 return len;
892}
893
894int32_t
895UnicodeString::extract(int32_t start,
896 int32_t length,
897 char *target,
898 int32_t targetCapacity,
899 enum EInvariant) const
900{
901 // if the arguments are illegal, then do nothing
902 if(targetCapacity < 0 || (targetCapacity > 0 && target == NULL__null)) {
903 return 0;
904 }
905
906 // pin the indices to legal values
907 pinIndices(start, length);
908
909 if(length <= targetCapacity) {
910 u_UCharsToCharsu_UCharsToChars_71(getArrayStart() + start, target, length);
911 }
912 UErrorCode status = U_ZERO_ERROR;
913 return u_terminateCharsu_terminateChars_71(target, targetCapacity, length, &status);
914}
915
916UnicodeString
917UnicodeString::tempSubString(int32_t start, int32_t len) const {
918 pinIndices(start, len);
919 const UChar *array = getBuffer(); // not getArrayStart() to check kIsBogus & kOpenGetBuffer
920 if(array==NULL__null) {
921 array=fUnion.fStackFields.fBuffer; // anything not NULL because that would make an empty string
922 len=-2; // bogus result string
923 }
924 return UnicodeString(FALSE0, array + start, len);
925}
926
927int32_t
928UnicodeString::toUTF8(int32_t start, int32_t len,
929 char *target, int32_t capacity) const {
930 pinIndices(start, len);
931 int32_t length8;
932 UErrorCode errorCode = U_ZERO_ERROR;
933 u_strToUTF8WithSubu_strToUTF8WithSub_71(target, capacity, &length8,
934 getBuffer() + start, len,
935 0xFFFD, // Standard substitution character.
936 NULL__null, // Don't care about number of substitutions.
937 &errorCode);
938 return length8;
939}
940
941#if U_CHARSET_IS_UTF81
942
943int32_t
944UnicodeString::extract(int32_t start, int32_t len,
945 char *target, uint32_t dstSize) const {
946 // if the arguments are illegal, then do nothing
947 if(/*dstSize < 0 || */(dstSize > 0 && target == 0)) {
948 return 0;
949 }
950 return toUTF8(start, len, target, dstSize <= 0x7fffffff ? (int32_t)dstSize : 0x7fffffff);
951}
952
953// else see unistr_cnv.cpp
954#endif
955
956void
957UnicodeString::extractBetween(int32_t start,
958 int32_t limit,
959 UnicodeString& target) const {
960 pinIndex(start);
961 pinIndex(limit);
962 doExtract(start, limit - start, target);
963}
964
965// When converting from UTF-16 to UTF-8, the result will have at most 3 times
966// as many bytes as the source has UChars.
967// The "worst cases" are writing systems like Indic, Thai and CJK with
968// 3:1 bytes:UChars.
969void
970UnicodeString::toUTF8(ByteSink &sink) const {
971 int32_t length16 = length();
972 if(length16 != 0) {
973 char stackBuffer[1024];
974 int32_t capacity = (int32_t)sizeof(stackBuffer);
975 UBool utf8IsOwned = FALSE0;
976 char *utf8 = sink.GetAppendBuffer(length16 < capacity ? length16 : capacity,
977 3*length16,
978 stackBuffer, capacity,
979 &capacity);
980 int32_t length8 = 0;
981 UErrorCode errorCode = U_ZERO_ERROR;
982 u_strToUTF8WithSubu_strToUTF8WithSub_71(utf8, capacity, &length8,
983 getBuffer(), length16,
984 0xFFFD, // Standard substitution character.
985 NULL__null, // Don't care about number of substitutions.
986 &errorCode);
987 if(errorCode == U_BUFFER_OVERFLOW_ERROR) {
988 utf8 = (char *)uprv_mallocuprv_malloc_71(length8);
989 if(utf8 != NULL__null) {
990 utf8IsOwned = TRUE1;
991 errorCode = U_ZERO_ERROR;
992 u_strToUTF8WithSubu_strToUTF8WithSub_71(utf8, length8, &length8,
993 getBuffer(), length16,
994 0xFFFD, // Standard substitution character.
995 NULL__null, // Don't care about number of substitutions.
996 &errorCode);
997 } else {
998 errorCode = U_MEMORY_ALLOCATION_ERROR;
999 }
1000 }
1001 if(U_SUCCESS(errorCode)) {
1002 sink.Append(utf8, length8);
1003 sink.Flush();
1004 }
1005 if(utf8IsOwned) {
1006 uprv_freeuprv_free_71(utf8);
1007 }
1008 }
1009}
1010
1011int32_t
1012UnicodeString::toUTF32(UChar32 *utf32, int32_t capacity, UErrorCode &errorCode) const {
1013 int32_t length32=0;
1014 if(U_SUCCESS(errorCode)) {
1015 // getBuffer() and u_strToUTF32WithSub() check for illegal arguments.
1016 u_strToUTF32WithSubu_strToUTF32WithSub_71(utf32, capacity, &length32,
1017 getBuffer(), length(),
1018 0xfffd, // Substitution character.
1019 NULL__null, // Don't care about number of substitutions.
1020 &errorCode);
1021 }
1022 return length32;
1023}
1024
1025int32_t
1026UnicodeString::indexOf(const UChar *srcChars,
1027 int32_t srcStart,
1028 int32_t srcLength,
1029 int32_t start,
1030 int32_t length) const
1031{
1032 if(isBogus() || srcChars == 0 || srcStart < 0 || srcLength == 0) {
1033 return -1;
1034 }
1035
1036 // UnicodeString does not find empty substrings
1037 if(srcLength < 0 && srcChars[srcStart] == 0) {
1038 return -1;
1039 }
1040
1041 // get the indices within bounds
1042 pinIndices(start, length);
1043
1044 // find the first occurrence of the substring
1045 const UChar *array = getArrayStart();
1046 const UChar *match = u_strFindFirstu_strFindFirst_71(array + start, length, srcChars + srcStart, srcLength);
1047 if(match == NULL__null) {
1048 return -1;
1049 } else {
1050 return (int32_t)(match - array);
1051 }
1052}
1053
1054int32_t
1055UnicodeString::doIndexOf(UChar c,
1056 int32_t start,
1057 int32_t length) const
1058{
1059 // pin indices
1060 pinIndices(start, length);
1061
1062 // find the first occurrence of c
1063 const UChar *array = getArrayStart();
1064 const UChar *match = u_memchru_memchr_71(array + start, c, length);
1065 if(match == NULL__null) {
1066 return -1;
1067 } else {
1068 return (int32_t)(match - array);
1069 }
1070}
1071
1072int32_t
1073UnicodeString::doIndexOf(UChar32 c,
1074 int32_t start,
1075 int32_t length) const {
1076 // pin indices
1077 pinIndices(start, length);
1078
1079 // find the first occurrence of c
1080 const UChar *array = getArrayStart();
1081 const UChar *match = u_memchr32u_memchr32_71(array + start, c, length);
1082 if(match == NULL__null) {
1083 return -1;
1084 } else {
1085 return (int32_t)(match - array);
1086 }
1087}
1088
1089int32_t
1090UnicodeString::lastIndexOf(const UChar *srcChars,
1091 int32_t srcStart,
1092 int32_t srcLength,
1093 int32_t start,
1094 int32_t length) const
1095{
1096 if(isBogus() || srcChars == 0 || srcStart < 0 || srcLength == 0) {
1097 return -1;
1098 }
1099
1100 // UnicodeString does not find empty substrings
1101 if(srcLength < 0 && srcChars[srcStart] == 0) {
1102 return -1;
1103 }
1104
1105 // get the indices within bounds
1106 pinIndices(start, length);
1107
1108 // find the last occurrence of the substring
1109 const UChar *array = getArrayStart();
1110 const UChar *match = u_strFindLastu_strFindLast_71(array + start, length, srcChars + srcStart, srcLength);
1111 if(match == NULL__null) {
1112 return -1;
1113 } else {
1114 return (int32_t)(match - array);
1115 }
1116}
1117
1118int32_t
1119UnicodeString::doLastIndexOf(UChar c,
1120 int32_t start,
1121 int32_t length) const
1122{
1123 if(isBogus()) {
1124 return -1;
1125 }
1126
1127 // pin indices
1128 pinIndices(start, length);
1129
1130 // find the last occurrence of c
1131 const UChar *array = getArrayStart();
1132 const UChar *match = u_memrchru_memrchr_71(array + start, c, length);
1133 if(match == NULL__null) {
1134 return -1;
1135 } else {
1136 return (int32_t)(match - array);
1137 }
1138}
1139
1140int32_t
1141UnicodeString::doLastIndexOf(UChar32 c,
1142 int32_t start,
1143 int32_t length) const {
1144 // pin indices
1145 pinIndices(start, length);
1146
1147 // find the last occurrence of c
1148 const UChar *array = getArrayStart();
1149 const UChar *match = u_memrchr32u_memrchr32_71(array + start, c, length);
1150 if(match == NULL__null) {
1151 return -1;
1152 } else {
1153 return (int32_t)(match - array);
1154 }
1155}
1156
1157//========================================
1158// Write implementation
1159//========================================
1160
1161UnicodeString&
1162UnicodeString::findAndReplace(int32_t start,
1163 int32_t length,
1164 const UnicodeString& oldText,
1165 int32_t oldStart,
1166 int32_t oldLength,
1167 const UnicodeString& newText,
1168 int32_t newStart,
1169 int32_t newLength)
1170{
1171 if(isBogus() || oldText.isBogus() || newText.isBogus()) {
1172 return *this;
1173 }
1174
1175 pinIndices(start, length);
1176 oldText.pinIndices(oldStart, oldLength);
1177 newText.pinIndices(newStart, newLength);
1178
1179 if(oldLength == 0) {
1180 return *this;
1181 }
1182
1183 while(length > 0 && length >= oldLength) {
1184 int32_t pos = indexOf(oldText, oldStart, oldLength, start, length);
1185 if(pos < 0) {
1186 // no more oldText's here: done
1187 break;
1188 } else {
1189 // we found oldText, replace it by newText and go beyond it
1190 replace(pos, oldLength, newText, newStart, newLength);
1191 length -= pos + oldLength - start;
1192 start = pos + newLength;
1193 }
1194 }
1195
1196 return *this;
1197}
1198
1199
1200void
1201UnicodeString::setToBogus()
1202{
1203 releaseArray();
18
Calling 'UnicodeString::releaseArray'
1204
1205 fUnion.fFields.fLengthAndFlags = kIsBogus;
1206 fUnion.fFields.fArray = 0;
1207 fUnion.fFields.fCapacity = 0;
1208}
1209
1210// turn a bogus string into an empty one
1211void
1212UnicodeString::unBogus() {
1213 if(fUnion.fFields.fLengthAndFlags & kIsBogus) {
1214 setToEmpty();
1215 }
1216}
1217
1218const char16_t *
1219UnicodeString::getTerminatedBuffer() {
1220 if(!isWritable()) {
1221 return nullptr;
1222 }
1223 UChar *array = getArrayStart();
1224 int32_t len = length();
1225 if(len < getCapacity()) {
1226 if(fUnion.fFields.fLengthAndFlags & kBufferIsReadonly) {
1227 // If len<capacity on a read-only alias, then array[len] is
1228 // either the original NUL (if constructed with (TRUE, s, length))
1229 // or one of the original string contents characters (if later truncated),
1230 // therefore we can assume that array[len] is initialized memory.
1231 if(array[len] == 0) {
1232 return array;
1233 }
1234 } else if(((fUnion.fFields.fLengthAndFlags & kRefCounted) == 0 || refCount() == 1)) {
1235 // kRefCounted: Do not write the NUL if the buffer is shared.
1236 // That is mostly safe, except when the length of one copy was modified
1237 // without copy-on-write, e.g., via truncate(newLength) or remove(void).
1238 // Then the NUL would be written into the middle of another copy's string.
1239
1240 // Otherwise, the buffer is fully writable and it is anyway safe to write the NUL.
1241 // Do not test if there is a NUL already because it might be uninitialized memory.
1242 // (That would be safe, but tools like valgrind & Purify would complain.)
1243 array[len] = 0;
1244 return array;
1245 }
1246 }
1247 if(len<INT32_MAX(2147483647) && cloneArrayIfNeeded(len+1)) {
1248 array = getArrayStart();
1249 array[len] = 0;
1250 return array;
1251 } else {
1252 return nullptr;
1253 }
1254}
1255
1256// setTo() analogous to the readonly-aliasing constructor with the same signature
1257UnicodeString &
1258UnicodeString::setTo(UBool isTerminated,
1259 ConstChar16Ptr textPtr,
1260 int32_t textLength)
1261{
1262 if(fUnion.fFields.fLengthAndFlags & kOpenGetBuffer) {
1263 // do not modify a string that has an "open" getBuffer(minCapacity)
1264 return *this;
1265 }
1266
1267 const UChar *text = textPtr;
1268 if(text == NULL__null) {
1269 // treat as an empty string, do not alias
1270 releaseArray();
1271 setToEmpty();
1272 return *this;
1273 }
1274
1275 if( textLength < -1 ||
1276 (textLength == -1 && !isTerminated) ||
1277 (textLength >= 0 && isTerminated && text[textLength] != 0)
1278 ) {
1279 setToBogus();
1280 return *this;
1281 }
1282
1283 releaseArray();
1284
1285 if(textLength == -1) {
1286 // text is terminated, or else it would have failed the above test
1287 textLength = u_strlenu_strlen_71(text);
1288 }
1289 fUnion.fFields.fLengthAndFlags = kReadonlyAlias;
1290 setArray((UChar *)text, textLength, isTerminated ? textLength + 1 : textLength);
1291 return *this;
1292}
1293
1294// setTo() analogous to the writable-aliasing constructor with the same signature
1295UnicodeString &
1296UnicodeString::setTo(UChar *buffer,
1297 int32_t buffLength,
1298 int32_t buffCapacity) {
1299 if(fUnion.fFields.fLengthAndFlags & kOpenGetBuffer) {
1300 // do not modify a string that has an "open" getBuffer(minCapacity)
1301 return *this;
1302 }
1303
1304 if(buffer == NULL__null) {
1305 // treat as an empty string, do not alias
1306 releaseArray();
1307 setToEmpty();
1308 return *this;
1309 }
1310
1311 if(buffLength < -1 || buffCapacity < 0 || buffLength > buffCapacity) {
1312 setToBogus();
1313 return *this;
1314 } else if(buffLength == -1) {
1315 // buffLength = u_strlen(buff); but do not look beyond buffCapacity
1316 const UChar *p = buffer, *limit = buffer + buffCapacity;
1317 while(p != limit && *p != 0) {
1318 ++p;
1319 }
1320 buffLength = (int32_t)(p - buffer);
1321 }
1322
1323 releaseArray();
1324
1325 fUnion.fFields.fLengthAndFlags = kWritableAlias;
1326 setArray(buffer, buffLength, buffCapacity);
1327 return *this;
1328}
1329
1330UnicodeString &UnicodeString::setToUTF8(StringPiece utf8) {
1331 unBogus();
1332 int32_t length = utf8.length();
1333 int32_t capacity;
1334 // The UTF-16 string will be at most as long as the UTF-8 string.
1335 if(length <= US_STACKBUF_SIZE) {
1336 capacity = US_STACKBUF_SIZE;
1337 } else {
1338 capacity = length + 1; // +1 for the terminating NUL.
1339 }
1340 UChar *utf16 = getBuffer(capacity);
1341 int32_t length16;
1342 UErrorCode errorCode = U_ZERO_ERROR;
1343 u_strFromUTF8WithSubu_strFromUTF8WithSub_71(utf16, getCapacity(), &length16,
1344 utf8.data(), length,
1345 0xfffd, // Substitution character.
1346 NULL__null, // Don't care about number of substitutions.
1347 &errorCode);
1348 releaseBuffer(length16);
1349 if(U_FAILURE(errorCode)) {
1350 setToBogus();
1351 }
1352 return *this;
1353}
1354
1355UnicodeString&
1356UnicodeString::setCharAt(int32_t offset,
1357 UChar c)
1358{
1359 int32_t len = length();
1360 if(cloneArrayIfNeeded() && len > 0) {
1361 if(offset < 0) {
1362 offset = 0;
1363 } else if(offset >= len) {
1364 offset = len - 1;
1365 }
1366
1367 getArrayStart()[offset] = c;
1368 }
1369 return *this;
1370}
1371
1372UnicodeString&
1373UnicodeString::replace(int32_t start,
1374 int32_t _length,
1375 UChar32 srcChar) {
1376 UChar buffer[U16_MAX_LENGTH2];
1377 int32_t count = 0;
1378 UBool isError = FALSE0;
1379 U16_APPEND(buffer, count, U16_MAX_LENGTH, srcChar, isError)do { if((uint32_t)(srcChar)<=0xffff) { (buffer)[(count)++]
=(uint16_t)(srcChar); } else if((uint32_t)(srcChar)<=0x10ffff
&& (count)+1<(2)) { (buffer)[(count)++]=(uint16_t
)(((srcChar)>>10)+0xd7c0); (buffer)[(count)++]=(uint16_t
)(((srcChar)&0x3ff)|0xdc00); } else { (isError)=true; } }
while (false)
;
1380 // We test isError so that the compiler does not complain that we don't.
1381 // If isError (srcChar is not a valid code point) then count==0 which means
1382 // we remove the source segment rather than replacing it with srcChar.
1383 return doReplace(start, _length, buffer, 0, isError ? 0 : count);
1384}
1385
1386UnicodeString&
1387UnicodeString::append(UChar32 srcChar) {
1388 UChar buffer[U16_MAX_LENGTH2];
1389 int32_t _length = 0;
1390 UBool isError = FALSE0;
1391 U16_APPEND(buffer, _length, U16_MAX_LENGTH, srcChar, isError)do { if((uint32_t)(srcChar)<=0xffff) { (buffer)[(_length)++
]=(uint16_t)(srcChar); } else if((uint32_t)(srcChar)<=0x10ffff
&& (_length)+1<(2)) { (buffer)[(_length)++]=(uint16_t
)(((srcChar)>>10)+0xd7c0); (buffer)[(_length)++]=(uint16_t
)(((srcChar)&0x3ff)|0xdc00); } else { (isError)=true; } }
while (false)
;
1392 // We test isError so that the compiler does not complain that we don't.
1393 // If isError then _length==0 which turns the doAppend() into a no-op anyway.
1394 return isError ? *this : doAppend(buffer, 0, _length);
1395}
1396
1397UnicodeString&
1398UnicodeString::doReplace( int32_t start,
1399 int32_t length,
1400 const UnicodeString& src,
1401 int32_t srcStart,
1402 int32_t srcLength)
1403{
1404 // pin the indices to legal values
1405 src.pinIndices(srcStart, srcLength);
1406
1407 // get the characters from src
1408 // and replace the range in ourselves with them
1409 return doReplace(start, length, src.getArrayStart(), srcStart, srcLength);
1410}
1411
1412UnicodeString&
1413UnicodeString::doReplace(int32_t start,
1414 int32_t length,
1415 const UChar *srcChars,
1416 int32_t srcStart,
1417 int32_t srcLength)
1418{
1419 if(!isWritable()) {
1420 return *this;
1421 }
1422
1423 int32_t oldLength = this->length();
1424
1425 // optimize (read-only alias).remove(0, start) and .remove(start, end)
1426 if((fUnion.fFields.fLengthAndFlags&kBufferIsReadonly) && srcLength == 0) {
1427 if(start == 0) {
1428 // remove prefix by adjusting the array pointer
1429 pinIndex(length);
1430 fUnion.fFields.fArray += length;
1431 fUnion.fFields.fCapacity -= length;
1432 setLength(oldLength - length);
1433 return *this;
1434 } else {
1435 pinIndex(start);
1436 if(length >= (oldLength - start)) {
1437 // remove suffix by reducing the length (like truncate())
1438 setLength(start);
1439 fUnion.fFields.fCapacity = start; // not NUL-terminated any more
1440 return *this;
1441 }
1442 }
1443 }
1444
1445 if(start == oldLength) {
1446 return doAppend(srcChars, srcStart, srcLength);
1447 }
1448
1449 if(srcChars == 0) {
1450 srcLength = 0;
1451 } else {
1452 // Perform all remaining operations relative to srcChars + srcStart.
1453 // From this point forward, do not use srcStart.
1454 srcChars += srcStart;
1455 if (srcLength < 0) {
1456 // get the srcLength if necessary
1457 srcLength = u_strlenu_strlen_71(srcChars);
1458 }
1459 }
1460
1461 // pin the indices to legal values
1462 pinIndices(start, length);
1463
1464 // Calculate the size of the string after the replace.
1465 // Avoid int32_t overflow.
1466 int32_t newLength = oldLength - length;
1467 if(srcLength > (INT32_MAX(2147483647) - newLength)) {
1468 setToBogus();
1469 return *this;
1470 }
1471 newLength += srcLength;
1472
1473 // Check for insertion into ourself
1474 const UChar *oldArray = getArrayStart();
1475 if (isBufferWritable() &&
1476 oldArray < srcChars + srcLength &&
1477 srcChars < oldArray + oldLength) {
1478 // Copy into a new UnicodeString and start over
1479 UnicodeString copy(srcChars, srcLength);
1480 if (copy.isBogus()) {
1481 setToBogus();
1482 return *this;
1483 }
1484 return doReplace(start, length, copy.getArrayStart(), 0, srcLength);
1485 }
1486
1487 // cloneArrayIfNeeded(doCopyArray=FALSE) may change fArray but will not copy the current contents;
1488 // therefore we need to keep the current fArray
1489 UChar oldStackBuffer[US_STACKBUF_SIZE];
1490 if((fUnion.fFields.fLengthAndFlags&kUsingStackBuffer) && (newLength > US_STACKBUF_SIZE)) {
1491 // copy the stack buffer contents because it will be overwritten with
1492 // fUnion.fFields values
1493 u_memcpyu_memcpy_71(oldStackBuffer, oldArray, oldLength);
1494 oldArray = oldStackBuffer;
1495 }
1496
1497 // clone our array and allocate a bigger array if needed
1498 int32_t *bufferToDelete = 0;
1499 if(!cloneArrayIfNeeded(newLength, getGrowCapacity(newLength),
1500 FALSE0, &bufferToDelete)
1501 ) {
1502 return *this;
1503 }
1504
1505 // now do the replace
1506
1507 UChar *newArray = getArrayStart();
1508 if(newArray != oldArray) {
1509 // if fArray changed, then we need to copy everything except what will change
1510 us_arrayCopy(oldArray, 0, newArray, 0, start);
1511 us_arrayCopy(oldArray, start + length,
1512 newArray, start + srcLength,
1513 oldLength - (start + length));
1514 } else if(length != srcLength) {
1515 // fArray did not change; copy only the portion that isn't changing, leaving a hole
1516 us_arrayCopy(oldArray, start + length,
1517 newArray, start + srcLength,
1518 oldLength - (start + length));
1519 }
1520
1521 // now fill in the hole with the new string
1522 us_arrayCopy(srcChars, 0, newArray, start, srcLength);
1523
1524 setLength(newLength);
1525
1526 // delayed delete in case srcChars == fArray when we started, and
1527 // to keep oldArray alive for the above operations
1528 if (bufferToDelete) {
1529 uprv_freeuprv_free_71(bufferToDelete);
1530 }
1531
1532 return *this;
1533}
1534
1535// Versions of doReplace() only for append() variants.
1536// doReplace() and doAppend() optimize for different cases.
1537
1538UnicodeString&
1539UnicodeString::doAppend(const UnicodeString& src, int32_t srcStart, int32_t srcLength) {
1540 if(srcLength == 0) {
1541 return *this;
1542 }
1543
1544 // pin the indices to legal values
1545 src.pinIndices(srcStart, srcLength);
1546 return doAppend(src.getArrayStart(), srcStart, srcLength);
1547}
1548
1549UnicodeString&
1550UnicodeString::doAppend(const UChar *srcChars, int32_t srcStart, int32_t srcLength) {
1551 if(!isWritable() || srcLength == 0 || srcChars == NULL__null) {
1552 return *this;
1553 }
1554
1555 // Perform all remaining operations relative to srcChars + srcStart.
1556 // From this point forward, do not use srcStart.
1557 srcChars += srcStart;
1558
1559 if(srcLength < 0) {
1560 // get the srcLength if necessary
1561 if((srcLength = u_strlenu_strlen_71(srcChars)) == 0) {
1562 return *this;
1563 }
1564 }
1565
1566 int32_t oldLength = length();
1567 int32_t newLength;
1568 if (uprv_add32_overflowuprv_add32_overflow_71(oldLength, srcLength, &newLength)) {
1569 setToBogus();
1570 return *this;
1571 }
1572
1573 // Check for append onto ourself
1574 const UChar* oldArray = getArrayStart();
1575 if (isBufferWritable() &&
1576 oldArray < srcChars + srcLength &&
1577 srcChars < oldArray + oldLength) {
1578 // Copy into a new UnicodeString and start over
1579 UnicodeString copy(srcChars, srcLength);
1580 if (copy.isBogus()) {
1581 setToBogus();
1582 return *this;
1583 }
1584 return doAppend(copy.getArrayStart(), 0, srcLength);
1585 }
1586
1587 // optimize append() onto a large-enough, owned string
1588 if((newLength <= getCapacity() && isBufferWritable()) ||
1589 cloneArrayIfNeeded(newLength, getGrowCapacity(newLength))) {
1590 UChar *newArray = getArrayStart();
1591 // Do not copy characters when
1592 // UChar *buffer=str.getAppendBuffer(...);
1593 // is followed by
1594 // str.append(buffer, length);
1595 // or
1596 // str.appendString(buffer, length)
1597 // or similar.
1598 if(srcChars != newArray + oldLength) {
1599 us_arrayCopy(srcChars, 0, newArray, oldLength, srcLength);
1600 }
1601 setLength(newLength);
1602 }
1603 return *this;
1604}
1605
1606/**
1607 * Replaceable API
1608 */
1609void
1610UnicodeString::handleReplaceBetween(int32_t start,
1611 int32_t limit,
1612 const UnicodeString& text) {
1613 replaceBetween(start, limit, text);
1614}
1615
1616/**
1617 * Replaceable API
1618 */
1619void
1620UnicodeString::copy(int32_t start, int32_t limit, int32_t dest) {
1621 if (limit <= start) {
1622 return; // Nothing to do; avoid bogus malloc call
1623 }
1624 UChar* text = (UChar*) uprv_mallocuprv_malloc_71( sizeof(UChar) * (limit - start) );
1625 // Check to make sure text is not null.
1626 if (text != NULL__null) {
1627 extractBetween(start, limit, text, 0);
1628 insert(dest, text, 0, limit - start);
1629 uprv_freeuprv_free_71(text);
1630 }
1631}
1632
1633/**
1634 * Replaceable API
1635 *
1636 * NOTE: This is for the Replaceable class. There is no rep.cpp,
1637 * so we implement this function here.
1638 */
1639UBool Replaceable::hasMetaData() const {
1640 return TRUE1;
1641}
1642
1643/**
1644 * Replaceable API
1645 */
1646UBool UnicodeString::hasMetaData() const {
1647 return FALSE0;
1648}
1649
1650UnicodeString&
1651UnicodeString::doReverse(int32_t start, int32_t length) {
1652 if(length <= 1 || !cloneArrayIfNeeded()) {
1653 return *this;
1654 }
1655
1656 // pin the indices to legal values
1657 pinIndices(start, length);
1658 if(length <= 1) { // pinIndices() might have shrunk the length
1659 return *this;
1660 }
1661
1662 UChar *left = getArrayStart() + start;
1663 UChar *right = left + length - 1; // -1 for inclusive boundary (length>=2)
1664 UChar swap;
1665 UBool hasSupplementary = FALSE0;
1666
1667 // Before the loop we know left<right because length>=2.
1668 do {
1669 hasSupplementary |= (UBool)U16_IS_LEAD(swap = *left)(((swap = *left)&0xfffffc00)==0xd800);
1670 hasSupplementary |= (UBool)U16_IS_LEAD(*left++ = *right)(((*left++ = *right)&0xfffffc00)==0xd800);
1671 *right-- = swap;
1672 } while(left < right);
1673 // Make sure to test the middle code unit of an odd-length string.
1674 // Redundant if the length is even.
1675 hasSupplementary |= (UBool)U16_IS_LEAD(*left)(((*left)&0xfffffc00)==0xd800);
1676
1677 /* if there are supplementary code points in the reversed range, then re-swap their surrogates */
1678 if(hasSupplementary) {
1679 UChar swap2;
1680
1681 left = getArrayStart() + start;
1682 right = left + length - 1; // -1 so that we can look at *(left+1) if left<right
1683 while(left < right) {
1684 if(U16_IS_TRAIL(swap = *left)(((swap = *left)&0xfffffc00)==0xdc00) && U16_IS_LEAD(swap2 = *(left + 1))(((swap2 = *(left + 1))&0xfffffc00)==0xd800)) {
1685 *left++ = swap2;
1686 *left++ = swap;
1687 } else {
1688 ++left;
1689 }
1690 }
1691 }
1692
1693 return *this;
1694}
1695
1696UBool
1697UnicodeString::padLeading(int32_t targetLength,
1698 UChar padChar)
1699{
1700 int32_t oldLength = length();
1701 if(oldLength >= targetLength || !cloneArrayIfNeeded(targetLength)) {
1702 return FALSE0;
1703 } else {
1704 // move contents up by padding width
1705 UChar *array = getArrayStart();
1706 int32_t start = targetLength - oldLength;
1707 us_arrayCopy(array, 0, array, start, oldLength);
1708
1709 // fill in padding character
1710 while(--start >= 0) {
1711 array[start] = padChar;
1712 }
1713 setLength(targetLength);
1714 return TRUE1;
1715 }
1716}
1717
1718UBool
1719UnicodeString::padTrailing(int32_t targetLength,
1720 UChar padChar)
1721{
1722 int32_t oldLength = length();
1723 if(oldLength >= targetLength || !cloneArrayIfNeeded(targetLength)) {
1724 return FALSE0;
1725 } else {
1726 // fill in padding character
1727 UChar *array = getArrayStart();
1728 int32_t length = targetLength;
1729 while(--length >= oldLength) {
1730 array[length] = padChar;
1731 }
1732 setLength(targetLength);
1733 return TRUE1;
1734 }
1735}
1736
1737//========================================
1738// Hashing
1739//========================================
1740int32_t
1741UnicodeString::doHashCode() const
1742{
1743 /* Delegate hash computation to uhash. This makes UnicodeString
1744 * hashing consistent with UChar* hashing. */
1745 int32_t hashCode = ustr_hashUCharsNustr_hashUCharsN_71(getArrayStart(), length());
1746 if (hashCode == kInvalidHashCode) {
1747 hashCode = kEmptyHashCode;
1748 }
1749 return hashCode;
1750}
1751
1752//========================================
1753// External Buffer
1754//========================================
1755
1756char16_t *
1757UnicodeString::getBuffer(int32_t minCapacity) {
1758 if(minCapacity>=-1 && cloneArrayIfNeeded(minCapacity)) {
1759 fUnion.fFields.fLengthAndFlags|=kOpenGetBuffer;
1760 setZeroLength();
1761 return getArrayStart();
1762 } else {
1763 return nullptr;
1764 }
1765}
1766
1767void
1768UnicodeString::releaseBuffer(int32_t newLength) {
1769 if(fUnion.fFields.fLengthAndFlags&kOpenGetBuffer && newLength>=-1) {
1770 // set the new fLength
1771 int32_t capacity=getCapacity();
1772 if(newLength==-1) {
1773 // the new length is the string length, capped by fCapacity
1774 const UChar *array=getArrayStart(), *p=array, *limit=array+capacity;
1775 while(p<limit && *p!=0) {
1776 ++p;
1777 }
1778 newLength=(int32_t)(p-array);
1779 } else if(newLength>capacity) {
1780 newLength=capacity;
1781 }
1782 setLength(newLength);
1783 fUnion.fFields.fLengthAndFlags&=~kOpenGetBuffer;
1784 }
1785}
1786
1787//========================================
1788// Miscellaneous
1789//========================================
1790UBool
1791UnicodeString::cloneArrayIfNeeded(int32_t newCapacity,
1792 int32_t growCapacity,
1793 UBool doCopyArray,
1794 int32_t **pBufferToDelete,
1795 UBool forceClone) {
1796 // default parameters need to be static, therefore
1797 // the defaults are -1 to have convenience defaults
1798 if(newCapacity == -1) {
2
Assuming the condition is false
3
Taking false branch
1799 newCapacity = getCapacity();
1800 }
1801
1802 // while a getBuffer(minCapacity) is "open",
1803 // prevent any modifications of the string by returning FALSE here
1804 // if the string is bogus, then only an assignment or similar can revive it
1805 if(!isWritable()) {
1806 return FALSE0;
1807 }
1808
1809 /*
1810 * We need to make a copy of the array if
1811 * the buffer is read-only, or
1812 * the buffer is refCounted (shared), and refCount>1, or
1813 * the buffer is too small.
1814 * Return FALSE if memory could not be allocated.
1815 */
1816 if(forceClone
3.1
'forceClone' is 0
3.1
'forceClone' is 0
||
1817 fUnion.fFields.fLengthAndFlags & kBufferIsReadonly ||
4
Assuming the condition is true
1818 (fUnion.fFields.fLengthAndFlags & kRefCounted && refCount() > 1) ||
1819 newCapacity > getCapacity()
1820 ) {
1821 // check growCapacity for default value and use of the stack buffer
1822 if(growCapacity
4.1
'growCapacity' is < 0
4.1
'growCapacity' is < 0
< 0) {
5
Taking true branch
1823 growCapacity = newCapacity;
1824 } else if(newCapacity <= US_STACKBUF_SIZE && growCapacity > US_STACKBUF_SIZE) {
1825 growCapacity = US_STACKBUF_SIZE;
1826 }
1827
1828 // save old values
1829 UChar oldStackBuffer[US_STACKBUF_SIZE];
1830 UChar *oldArray;
1831 int32_t oldLength = length();
1832 int16_t flags = fUnion.fFields.fLengthAndFlags;
1833
1834 if(flags&kUsingStackBuffer) {
6
Assuming the condition is true
7
Taking true branch
1835 U_ASSERT(!(flags&kRefCounted))(void)0; /* kRefCounted and kUsingStackBuffer are mutally exclusive */
1836 if(doCopyArray
7.1
'doCopyArray' is 1
7.1
'doCopyArray' is 1
&& growCapacity > US_STACKBUF_SIZE) {
8
Assuming 'growCapacity' is > US_STACKBUF_SIZE
9
Taking true branch
1837 // copy the stack buffer contents because it will be overwritten with
1838 // fUnion.fFields values
1839 us_arrayCopy(fUnion.fStackFields.fBuffer, 0, oldStackBuffer, 0, oldLength);
1840 oldArray = oldStackBuffer;
1841 } else {
1842 oldArray = NULL__null; // no need to copy from the stack buffer to itself
1843 }
1844 } else {
1845 oldArray = fUnion.fFields.fArray;
1846 U_ASSERT(oldArray!=NULL)(void)0; /* when stack buffer is not used, oldArray must have a non-NULL reference */
1847 }
1848
1849 // allocate a new array
1850 if(allocate(growCapacity) ||
10
Calling 'UnicodeString::allocate'
15
Returning from 'UnicodeString::allocate'
1851 (newCapacity
15.1
'newCapacity' is >= 'growCapacity'
15.1
'newCapacity' is >= 'growCapacity'
< growCapacity && allocate(newCapacity))
1852 ) {
1853 if(doCopyArray) {
1854 // copy the contents
1855 // do not copy more than what fits - it may be smaller than before
1856 int32_t minLength = oldLength;
1857 newCapacity = getCapacity();
1858 if(newCapacity < minLength) {
1859 minLength = newCapacity;
1860 }
1861 if(oldArray != NULL__null) {
1862 us_arrayCopy(oldArray, 0, getArrayStart(), 0, minLength);
1863 }
1864 setLength(minLength);
1865 } else {
1866 setZeroLength();
1867 }
1868
1869 // release the old array
1870 if(flags & kRefCounted) {
1871 // the array is refCounted; decrement and release if 0
1872 u_atomic_int32_t *pRefCount = ((u_atomic_int32_t *)oldArray - 1);
1873 if(umtx_atomic_dec(pRefCount) == 0) {
1874 if(pBufferToDelete == 0) {
1875 // Note: cast to (void *) is needed with MSVC, where u_atomic_int32_t
1876 // is defined as volatile. (Volatile has useful non-standard behavior
1877 // with this compiler.)
1878 uprv_freeuprv_free_71((void *)pRefCount);
1879 } else {
1880 // the caller requested to delete it himself
1881 *pBufferToDelete = (int32_t *)pRefCount;
1882 }
1883 }
1884 }
1885 } else {
1886 // not enough memory for growCapacity and not even for the smaller newCapacity
1887 // reset the old values for setToBogus() to release the array
1888 if(!(flags&kUsingStackBuffer)) {
16
Taking false branch
1889 fUnion.fFields.fArray = oldArray;
1890 }
1891 fUnion.fFields.fLengthAndFlags = flags;
1892 setToBogus();
17
Calling 'UnicodeString::setToBogus'
1893 return FALSE0;
1894 }
1895 }
1896 return TRUE1;
1897}
1898
1899// UnicodeStringAppendable ------------------------------------------------- ***
1900
1901UnicodeStringAppendable::~UnicodeStringAppendable() {}
1902
1903UBool
1904UnicodeStringAppendable::appendCodeUnit(UChar c) {
1905 return str.doAppend(&c, 0, 1).isWritable();
1906}
1907
1908UBool
1909UnicodeStringAppendable::appendCodePoint(UChar32 c) {
1910 UChar buffer[U16_MAX_LENGTH2];
1911 int32_t cLength = 0;
1912 UBool isError = FALSE0;
1913 U16_APPEND(buffer, cLength, U16_MAX_LENGTH, c, isError)do { if((uint32_t)(c)<=0xffff) { (buffer)[(cLength)++]=(uint16_t
)(c); } else if((uint32_t)(c)<=0x10ffff && (cLength
)+1<(2)) { (buffer)[(cLength)++]=(uint16_t)(((c)>>10
)+0xd7c0); (buffer)[(cLength)++]=(uint16_t)(((c)&0x3ff)|0xdc00
); } else { (isError)=true; } } while (false)
;
1914 return !isError && str.doAppend(buffer, 0, cLength).isWritable();
1915}
1916
1917UBool
1918UnicodeStringAppendable::appendString(const UChar *s, int32_t length) {
1919 return str.doAppend(s, 0, length).isWritable();
1920}
1921
1922UBool
1923UnicodeStringAppendable::reserveAppendCapacity(int32_t appendCapacity) {
1924 return str.cloneArrayIfNeeded(str.length() + appendCapacity);
1
Calling 'UnicodeString::cloneArrayIfNeeded'
1925}
1926
1927UChar *
1928UnicodeStringAppendable::getAppendBuffer(int32_t minCapacity,
1929 int32_t desiredCapacityHint,
1930 UChar *scratch, int32_t scratchCapacity,
1931 int32_t *resultCapacity) {
1932 if(minCapacity < 1 || scratchCapacity < minCapacity) {
1933 *resultCapacity = 0;
1934 return NULL__null;
1935 }
1936 int32_t oldLength = str.length();
1937 if(minCapacity <= (kMaxCapacity - oldLength) &&
1938 desiredCapacityHint <= (kMaxCapacity - oldLength) &&
1939 str.cloneArrayIfNeeded(oldLength + minCapacity, oldLength + desiredCapacityHint)) {
1940 *resultCapacity = str.getCapacity() - oldLength;
1941 return str.getArrayStart() + oldLength;
1942 }
1943 *resultCapacity = scratchCapacity;
1944 return scratch;
1945}
1946
1947U_NAMESPACE_END}
1948
1949U_NAMESPACE_USEusing namespace icu_71;
1950
1951U_CAPIextern "C" int32_t U_EXPORT2
1952uhash_hashUnicodeStringuhash_hashUnicodeString_71(const UElement key) {
1953 const UnicodeString *str = (const UnicodeString*) key.pointer;
1954 return (str == NULL__null) ? 0 : str->hashCode();
1955}
1956
1957// Moved here from uhash_us.cpp so that using a UVector of UnicodeString*
1958// does not depend on hashtable code.
1959U_CAPIextern "C" UBool U_EXPORT2
1960uhash_compareUnicodeStringuhash_compareUnicodeString_71(const UElement key1, const UElement key2) {
1961 const UnicodeString *str1 = (const UnicodeString*) key1.pointer;
1962 const UnicodeString *str2 = (const UnicodeString*) key2.pointer;
1963 if (str1 == str2) {
1964 return TRUE1;
1965 }
1966 if (str1 == NULL__null || str2 == NULL__null) {
1967 return FALSE0;
1968 }
1969 return *str1 == *str2;
1970}
1971
1972#ifdef U_STATIC_IMPLEMENTATION1
1973/*
1974This should never be called. It is defined here to make sure that the
1975virtual vector deleting destructor is defined within unistr.cpp.
1976The vector deleting destructor is already a part of UObject,
1977but defining it here makes sure that it is included with this object file.
1978This makes sure that static library dependencies are kept to a minimum.
1979*/
1980#if defined(__clang__1) || U_GCC_MAJOR_MINOR(4 * 100 + 2) >= 1100
1981#pragma GCC diagnostic push
1982#pragma GCC diagnostic ignored "-Wunused-function"
1983static void uprv_UnicodeStringDummy(void) {
1984 delete [] (new UnicodeString[2]);
1985}
1986#pragma GCC diagnostic pop
1987#endif
1988#endif

../deps/icu-small/source/common/umutex.h

1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4**********************************************************************
5* Copyright (C) 1997-2015, International Business Machines
6* Corporation and others. All Rights Reserved.
7**********************************************************************
8*
9* File UMUTEX.H
10*
11* Modification History:
12*
13* Date Name Description
14* 04/02/97 aliu Creation.
15* 04/07/99 srl rewrite - C interface, multiple mutices
16* 05/13/99 stephen Changed to umutex (from cmutex)
17******************************************************************************
18*/
19
20#ifndef UMUTEX_H
21#define UMUTEX_H
22
23#include <atomic>
24#include <condition_variable>
25#include <mutex>
26#include <type_traits>
27
28#include "unicode/utypes.h"
29#include "unicode/uclean.h"
30#include "unicode/uobject.h"
31
32#include "putilimp.h"
33
34#if defined(U_USER_ATOMICS_H) || defined(U_USER_MUTEX_H)
35// Support for including an alternate implementation of atomic & mutex operations has been withdrawn.
36// See issue ICU-20185.
37#error U_USER_ATOMICS and U_USER_MUTEX_H are not supported
38#endif
39
40// Export an explicit template instantiation of std::atomic<int32_t>.
41// When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
42// See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
43//
44// Similar story for std::atomic<std::mutex *>, and the exported UMutex class.
45#if U_PF_WINDOWS1000 <= U_PLATFORM4000 && U_PLATFORM4000 <= U_PF_CYGWIN1900 && !defined(U_IN_DOXYGEN)
46#if defined(__clang__1) || defined(_MSC_VER)
47 #if defined(__clang__1)
48 // Suppress the warning that the explicit instantiation after explicit specialization has no effect.
49 #pragma clang diagnostic push
50 #pragma clang diagnostic ignored "-Winstantiation-after-specialization"
51 #endif
52template struct U_COMMON_API std::atomic<int32_t>;
53template struct U_COMMON_API std::atomic<std::mutex *>;
54 #if defined(__clang__1)
55 #pragma clang diagnostic pop
56 #endif
57#elif defined(__GNUC__4)
58// For GCC this class is already exported/visible, so no need for U_COMMON_API.
59template struct std::atomic<int32_t>;
60template struct std::atomic<std::mutex *>;
61#endif
62#endif
63
64
65U_NAMESPACE_BEGINnamespace icu_71 {
66
67/****************************************************************************
68 *
69 * Low Level Atomic Operations, ICU wrappers for.
70 *
71 ****************************************************************************/
72
73typedef std::atomic<int32_t> u_atomic_int32_t;
74#define ATOMIC_INT32_T_INITIALIZER(val){ val } ATOMIC_VAR_INIT(val){ val }
75
76inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
77 return var.load(std::memory_order_acquire);
78}
79
80inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
81 var.store(val, std::memory_order_release);
82}
83
84inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
85 return var->fetch_add(1) + 1;
86}
87
88inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
89 return var->fetch_sub(1) - 1;
23
Called C++ object pointer is null
90}
91
92
93/*************************************************************************************************
94 *
95 * UInitOnce Definitions.
96 *
97 *************************************************************************************************/
98
99struct UInitOnce {
100 u_atomic_int32_t fState;
101 UErrorCode fErrCode;
102 void reset() {fState = 0;}
103 UBool isReset() {return umtx_loadAcquire(fState) == 0;}
104// Note: isReset() is used by service registration code.
105// Thread safety of this usage needs review.
106};
107
108#define U_INITONCE_INITIALIZER{{ 0 }, U_ZERO_ERROR} {ATOMIC_INT32_T_INITIALIZER(0){ 0 }, U_ZERO_ERROR}
109
110
111U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
112U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
113
114template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (U_CALLCONV T::*fp)()) {
115 if (umtx_loadAcquire(uio.fState) == 2) {
116 return;
117 }
118 if (umtx_initImplPreInit(uio)) {
119 (obj->*fp)();
120 umtx_initImplPostInit(uio);
121 }
122}
123
124
125// umtx_initOnce variant for plain functions, or static class functions.
126// No context parameter.
127inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)()) {
128 if (umtx_loadAcquire(uio.fState) == 2) {
129 return;
130 }
131 if (umtx_initImplPreInit(uio)) {
132 (*fp)();
133 umtx_initImplPostInit(uio);
134 }
135}
136
137// umtx_initOnce variant for plain functions, or static class functions.
138// With ErrorCode, No context parameter.
139inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(UErrorCode &), UErrorCode &errCode) {
140 if (U_FAILURE(errCode)) {
141 return;
142 }
143 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
144 // We run the initialization.
145 (*fp)(errCode);
146 uio.fErrCode = errCode;
147 umtx_initImplPostInit(uio);
148 } else {
149 // Someone else already ran the initialization.
150 if (U_FAILURE(uio.fErrCode)) {
151 errCode = uio.fErrCode;
152 }
153 }
154}
155
156// umtx_initOnce variant for plain functions, or static class functions,
157// with a context parameter.
158template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T), T context) {
159 if (umtx_loadAcquire(uio.fState) == 2) {
160 return;
161 }
162 if (umtx_initImplPreInit(uio)) {
163 (*fp)(context);
164 umtx_initImplPostInit(uio);
165 }
166}
167
168// umtx_initOnce variant for plain functions, or static class functions,
169// with a context parameter and an error code.
170template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
171 if (U_FAILURE(errCode)) {
172 return;
173 }
174 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
175 // We run the initialization.
176 (*fp)(context, errCode);
177 uio.fErrCode = errCode;
178 umtx_initImplPostInit(uio);
179 } else {
180 // Someone else already ran the initialization.
181 if (U_FAILURE(uio.fErrCode)) {
182 errCode = uio.fErrCode;
183 }
184 }
185}
186
187// UMutex should be constexpr-constructible, so that no initialization code
188// is run during startup.
189// This works on all C++ libraries except MS VS before VS2019.
190#if (defined(_CPPLIB_VER) && !defined(_MSVC_STL_VERSION)) || \
191 (defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142)
192 // (VS std lib older than VS2017) || (VS std lib version < VS2019)
193# define UMUTEX_CONSTEXPRconstexpr
194#else
195# define UMUTEX_CONSTEXPRconstexpr constexpr
196#endif
197
198/**
199 * UMutex - ICU Mutex class.
200 *
201 * This is the preferred Mutex class for use within ICU implementation code.
202 * It is a thin wrapper over C++ std::mutex, with these additions:
203 * - Static instances are safe, not triggering static construction or destruction,
204 * and the associated order of construction or destruction issues.
205 * - Plumbed into u_cleanup() for destructing the underlying std::mutex,
206 * which frees any OS level resources they may be holding.
207 *
208 * Limitations:
209 * - Static or global instances only. Cannot be heap allocated. Cannot appear as a
210 * member of another class.
211 * - No condition variables or other advanced features. If needed, you will need to use
212 * std::mutex and std::condition_variable directly. For an example, see unifiedcache.cpp
213 *
214 * Typical Usage:
215 * static UMutex myMutex;
216 *
217 * {
218 * Mutex lock(myMutex);
219 * ... // Do stuff that is protected by myMutex;
220 * } // myMutex is released when lock goes out of scope.
221 */
222
223class U_COMMON_API UMutex {
224public:
225 UMUTEX_CONSTEXPRconstexpr UMutex() {}
226 ~UMutex() = default;
227
228 UMutex(const UMutex &other) = delete;
229 UMutex &operator =(const UMutex &other) = delete;
230 void *operator new(size_t) = delete;
231
232 // requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard
233 void lock() {
234 std::mutex *m = fMutex.load(std::memory_order_acquire);
235 if (m == nullptr) { m = getMutex(); }
236 m->lock();
237 }
238 void unlock() { fMutex.load(std::memory_order_relaxed)->unlock(); }
239
240 static void cleanup();
241
242private:
243 alignas(std::mutex) char fStorage[sizeof(std::mutex)] {};
244 std::atomic<std::mutex *> fMutex { nullptr };
245
246 /** All initialized UMutexes are kept in a linked list, so that they can be found,
247 * and the underlying std::mutex destructed, by u_cleanup().
248 */
249 UMutex *fListLink { nullptr };
250 static UMutex *gListHead;
251
252 /** Out-of-line function to lazily initialize a UMutex on first use.
253 * Initial fast check is inline, in lock(). The returned value may never
254 * be nullptr.
255 */
256 std::mutex *getMutex();
257};
258
259
260/* Lock a mutex.
261 * @param mutex The given mutex to be locked. Pass NULL to specify
262 * the global ICU mutex. Recursive locks are an error
263 * and may cause a deadlock on some platforms.
264 */
265U_CAPIextern "C" void U_EXPORT2 umtx_lockumtx_lock_71(UMutex* mutex);
266
267/* Unlock a mutex.
268 * @param mutex The given mutex to be unlocked. Pass NULL to specify
269 * the global ICU mutex.
270 */
271U_CAPIextern "C" void U_EXPORT2 umtx_unlockumtx_unlock_71 (UMutex* mutex);
272
273
274U_NAMESPACE_END}
275
276#endif /* UMUTEX_H */
277/*eof*/