]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/unistr.cpp
ICU-62135.0.1.tar.gz
[apple/icu.git] / icuSources / common / unistr.cpp
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
b75a7d8f
A
3/*
4******************************************************************************
2ca993e8 5* Copyright (C) 1999-2016, International Business Machines Corporation and
4388f060 6* others. All Rights Reserved.
b75a7d8f
A
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"
4388f060 24#include "unicode/appendable.h"
b75a7d8f 25#include "unicode/putil.h"
b75a7d8f
A
26#include "cstring.h"
27#include "cmemory.h"
28#include "unicode/ustring.h"
29#include "unicode/unistr.h"
4388f060
A
30#include "unicode/utf.h"
31#include "unicode/utf16.h"
32#include "uelement.h"
b75a7d8f 33#include "ustr_imp.h"
b75a7d8f 34#include "umutex.h"
4388f060 35#include "uassert.h"
b75a7d8f
A
36
37#if 0
38
b75a7d8f
A
39#include <iostream>
40using namespace std;
b75a7d8f
A
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) {
a62d09fc 87 uprv_memmove(dst+dstStart, src+srcStart, (size_t)count*sizeof(*src));
b75a7d8f
A
88 }
89}
90
91// u_unescapeAt() callback to get a UChar from a UnicodeString
92U_CDECL_BEGIN
93static UChar U_CALLCONV
94UnicodeString_charAt(int32_t offset, void *context) {
4388f060 95 return ((icu::UnicodeString*) context)->charAt(offset);
b75a7d8f
A
96}
97U_CDECL_END
98
99U_NAMESPACE_BEGIN
100
374ca955
A
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() {}
51004dcb 105
374ca955
A
106UOBJECT_DEFINE_RTTI_IMPLEMENTATION(UnicodeString)
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}
b75a7d8f
A
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
57a6839d
A
122UnicodeString::addRef() {
123 umtx_atomic_inc((u_atomic_int32_t *)fUnion.fFields.fArray - 1);
124}
b75a7d8f
A
125
126int32_t
57a6839d
A
127UnicodeString::removeRef() {
128 return umtx_atomic_dec((u_atomic_int32_t *)fUnion.fFields.fArray - 1);
129}
b75a7d8f
A
130
131int32_t
57a6839d
A
132UnicodeString::refCount() const {
133 return umtx_loadAcquire(*((u_atomic_int32_t *)fUnion.fFields.fArray - 1));
134}
b75a7d8f
A
135
136void
137UnicodeString::releaseArray() {
b331163b 138 if((fUnion.fFields.fLengthAndFlags & kRefCounted) && removeRef() == 0) {
46f4442e 139 uprv_free((int32_t *)fUnion.fFields.fArray - 1);
b75a7d8f
A
140 }
141}
142
143
144
145//========================================
146// Constructors
147//========================================
51004dcb
A
148
149// The default constructor is inline in unistr.h.
b75a7d8f 150
b331163b
A
151UnicodeString::UnicodeString(int32_t capacity, UChar32 c, int32_t count) {
152 fUnion.fFields.fLengthAndFlags = 0;
b75a7d8f
A
153 if(count <= 0 || (uint32_t)c > 0x10ffff) {
154 // just allocate and do not do anything else
155 allocate(capacity);
a62d09fc
A
156 } else if(c <= 0xffff) {
157 int32_t length = count;
b75a7d8f
A
158 if(capacity < length) {
159 capacity = length;
160 }
161 if(allocate(capacity)) {
46f4442e 162 UChar *array = getArrayStart();
a62d09fc
A
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 / 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);
182 UChar trail = U16_TRAIL(c);
183 for(int32_t i = 0; i < length; i += 2) {
184 array[i] = lead;
185 array[i + 1] = trail;
b75a7d8f 186 }
a62d09fc 187 setLength(length);
b75a7d8f 188 }
b75a7d8f
A
189 }
190}
191
b331163b
A
192UnicodeString::UnicodeString(UChar ch) {
193 fUnion.fFields.fLengthAndFlags = kLength1 | kShortString;
194 fUnion.fStackFields.fBuffer[0] = ch;
b75a7d8f
A
195}
196
b331163b
A
197UnicodeString::UnicodeString(UChar32 ch) {
198 fUnion.fFields.fLengthAndFlags = kShortString;
b75a7d8f
A
199 int32_t i = 0;
200 UBool isError = FALSE;
b331163b 201 U16_APPEND(fUnion.fStackFields.fBuffer, i, US_STACKBUF_SIZE, ch, isError);
4388f060
A
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) {
b331163b 205 setShortLength(i);
4388f060 206 }
b75a7d8f
A
207}
208
b331163b
A
209UnicodeString::UnicodeString(const UChar *text) {
210 fUnion.fFields.fLengthAndFlags = kShortString;
2ca993e8 211 doAppend(text, 0, -1);
b75a7d8f
A
212}
213
214UnicodeString::UnicodeString(const UChar *text,
b331163b
A
215 int32_t textLength) {
216 fUnion.fFields.fLengthAndFlags = kShortString;
2ca993e8 217 doAppend(text, 0, textLength);
b75a7d8f
A
218}
219
220UnicodeString::UnicodeString(UBool isTerminated,
f3c0d7a5 221 ConstChar16Ptr textPtr,
b331163b
A
222 int32_t textLength) {
223 fUnion.fFields.fLengthAndFlags = kReadonlyAlias;
f3c0d7a5 224 const UChar *text = textPtr;
b75a7d8f
A
225 if(text == NULL) {
226 // treat as an empty string, do not alias
46f4442e 227 setToEmpty();
b75a7d8f
A
228 } else if(textLength < -1 ||
229 (textLength == -1 && !isTerminated) ||
230 (textLength >= 0 && isTerminated && text[textLength] != 0)
231 ) {
232 setToBogus();
46f4442e
A
233 } else {
234 if(textLength == -1) {
235 // text is terminated, or else it would have failed the above test
236 textLength = u_strlen(text);
237 }
f3c0d7a5
A
238 setArray(const_cast<UChar *>(text), textLength,
239 isTerminated ? textLength + 1 : textLength);
b75a7d8f
A
240 }
241}
242
243UnicodeString::UnicodeString(UChar *buff,
244 int32_t buffLength,
b331163b
A
245 int32_t buffCapacity) {
246 fUnion.fFields.fLengthAndFlags = kWritableAlias;
b75a7d8f
A
247 if(buff == NULL) {
248 // treat as an empty string, do not alias
46f4442e 249 setToEmpty();
374ca955 250 } else if(buffLength < -1 || buffCapacity < 0 || buffLength > buffCapacity) {
b75a7d8f 251 setToBogus();
46f4442e
A
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);
b75a7d8f 260 }
46f4442e 261 setArray(buff, buffLength, buffCapacity);
b75a7d8f
A
262 }
263}
264
b331163b
A
265UnicodeString::UnicodeString(const char *src, int32_t length, EInvariant) {
266 fUnion.fFields.fLengthAndFlags = kShortString;
374ca955
A
267 if(src==NULL) {
268 // treat as an empty string
269 } else {
270 if(length<0) {
73c04bcf 271 length=(int32_t)uprv_strlen(src);
b75a7d8f 272 }
374ca955
A
273 if(cloneArrayIfNeeded(length, length, FALSE)) {
274 u_charsToUChars(src, getArrayStart(), length);
46f4442e 275 setLength(length);
374ca955 276 } else {
b75a7d8f
A
277 setToBogus();
278 }
279 }
280}
281
729e4ab9
A
282#if U_CHARSET_IS_UTF8
283
b331163b
A
284UnicodeString::UnicodeString(const char *codepageData) {
285 fUnion.fFields.fLengthAndFlags = kShortString;
729e4ab9
A
286 if(codepageData != 0) {
287 setToUTF8(codepageData);
288 }
289}
290
b331163b
A
291UnicodeString::UnicodeString(const char *codepageData, int32_t dataLength) {
292 fUnion.fFields.fLengthAndFlags = kShortString;
729e4ab9
A
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);
299 }
300 setToUTF8(StringPiece(codepageData, dataLength));
301}
302
303// else see unistr_cnv.cpp
304#endif
305
b331163b
A
306UnicodeString::UnicodeString(const UnicodeString& that) {
307 fUnion.fFields.fLengthAndFlags = kShortString;
b75a7d8f
A
308 copyFrom(that);
309}
310
2ca993e8
A
311UnicodeString::UnicodeString(UnicodeString &&src) U_NOEXCEPT {
312 fUnion.fFields.fLengthAndFlags = kShortString;
313 moveFrom(src);
314}
2ca993e8 315
b75a7d8f 316UnicodeString::UnicodeString(const UnicodeString& that,
b331163b
A
317 int32_t srcStart) {
318 fUnion.fFields.fLengthAndFlags = kShortString;
b75a7d8f
A
319 setTo(that, srcStart);
320}
321
322UnicodeString::UnicodeString(const UnicodeString& that,
323 int32_t srcStart,
b331163b
A
324 int32_t srcLength) {
325 fUnion.fFields.fLengthAndFlags = kShortString;
b75a7d8f
A
326 setTo(that, srcStart, srcLength);
327}
328
329// Replaceable base class clone() default implementation, does not clone
330Replaceable *
331Replaceable::clone() const {
332 return NULL;
333}
334
335// UnicodeString overrides clone() with a real implementation
336Replaceable *
337UnicodeString::clone() const {
338 return new UnicodeString(*this);
339}
340
341//========================================
342// array allocation
343//========================================
344
a62d09fc
A
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
b75a7d8f
A
369UBool
370UnicodeString::allocate(int32_t capacity) {
371 if(capacity <= US_STACKBUF_SIZE) {
b331163b 372 fUnion.fFields.fLengthAndFlags = kShortString;
a62d09fc
A
373 return TRUE;
374 }
375 if(capacity <= kMaxCapacity) {
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_UCHAR;
380 // Round up to a multiple of 16.
381 numBytes = (numBytes + 15) & ~15;
382 int32_t *array = (int32_t *) uprv_malloc(numBytes);
383 if(array != NULL) {
b75a7d8f
A
384 // set initial refCount and point behind the refCount
385 *array++ = 1;
a62d09fc 386 numBytes -= sizeof(int32_t);
b75a7d8f
A
387
388 // have fArray point to the first UChar
46f4442e 389 fUnion.fFields.fArray = (UChar *)array;
a62d09fc 390 fUnion.fFields.fCapacity = (int32_t)(numBytes / U_SIZEOF_UCHAR);
b331163b 391 fUnion.fFields.fLengthAndFlags = kLongString;
a62d09fc 392 return TRUE;
b75a7d8f
A
393 }
394 }
a62d09fc
A
395 fUnion.fFields.fLengthAndFlags = kIsBogus;
396 fUnion.fFields.fArray = 0;
397 fUnion.fFields.fCapacity = 0;
398 return FALSE;
b75a7d8f
A
399}
400
401//========================================
402// Destructor
403//========================================
2ca993e8
A
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_CAPI 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); ++i) {
416 beyond += finalLengthCounts[i];
417 }
418 printf(">59, %9d\n", beyond);
419}
420#endif
421
b75a7d8f
A
422UnicodeString::~UnicodeString()
423{
2ca993e8
A
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
b75a7d8f
A
438 releaseArray();
439}
440
729e4ab9
A
441//========================================
442// Factory methods
443//========================================
444
f3c0d7a5 445UnicodeString UnicodeString::fromUTF8(StringPiece utf8) {
729e4ab9
A
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_strFromUTF32WithSub(utf16, result.getCapacity(), &length16,
467 utf32, length,
468 0xfffd, // Substitution character.
469 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(TRUE);
480 return result;
481}
b75a7d8f
A
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, TRUE);
495}
496
497UnicodeString &
498UnicodeString::copyFrom(const UnicodeString &src, UBool fastCopy) {
499 // if assigning to ourselves, do nothing
b331163b 500 if(this == &src) {
b75a7d8f
A
501 return *this;
502 }
503
504 // is the right side bogus?
b331163b 505 if(src.isBogus()) {
b75a7d8f
A
506 setToBogus();
507 return *this;
508 }
509
510 // delete the current contents
511 releaseArray();
512
46f4442e 513 if(src.isEmpty()) {
b75a7d8f 514 // empty string - use the stack buffer
46f4442e 515 setToEmpty();
b75a7d8f
A
516 return *this;
517 }
518
519 // fLength>0 and not an "open" src.getBuffer(minCapacity)
b331163b
A
520 fUnion.fFields.fLengthAndFlags = src.fUnion.fFields.fLengthAndFlags;
521 switch(src.fUnion.fFields.fLengthAndFlags & kAllStorageFlags) {
b75a7d8f
A
522 case kShortString:
523 // short string using the stack buffer, do the same
b331163b
A
524 uprv_memcpy(fUnion.fStackFields.fBuffer, src.fUnion.fStackFields.fBuffer,
525 getShortLength() * U_SIZEOF_UCHAR);
b75a7d8f
A
526 break;
527 case kLongString:
528 // src uses a refCounted string buffer, use that buffer with refCount
b331163b 529 // src is const, use a cast - we don't actually change it
b75a7d8f
A
530 ((UnicodeString &)src).addRef();
531 // copy all fields, share the reference-counted buffer
46f4442e
A
532 fUnion.fFields.fArray = src.fUnion.fFields.fArray;
533 fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity;
b331163b
A
534 if(!hasShortLength()) {
535 fUnion.fFields.fLength = src.fUnion.fFields.fLength;
536 }
b75a7d8f
A
537 break;
538 case kReadonlyAlias:
539 if(fastCopy) {
540 // src is a readonly alias, do the same
541 // -> maintain the readonly alias as such
46f4442e
A
542 fUnion.fFields.fArray = src.fUnion.fFields.fArray;
543 fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity;
b331163b
A
544 if(!hasShortLength()) {
545 fUnion.fFields.fLength = src.fUnion.fFields.fLength;
546 }
b75a7d8f
A
547 break;
548 }
549 // else if(!fastCopy) fall through to case kWritableAlias
550 // -> allocate a new buffer and copy the contents
2ca993e8 551 U_FALLTHROUGH;
b331163b 552 case kWritableAlias: {
b75a7d8f 553 // src is a writable alias; we make a copy of that instead
b331163b 554 int32_t srcLength = src.length();
46f4442e 555 if(allocate(srcLength)) {
a62d09fc 556 u_memcpy(getArrayStart(), src.getArrayStart(), srcLength);
b331163b 557 setLength(srcLength);
b75a7d8f
A
558 break;
559 }
560 // if there is not enough memory, then fall through to setting to bogus
2ca993e8 561 U_FALLTHROUGH;
b331163b 562 }
b75a7d8f
A
563 default:
564 // if src is bogus, set ourselves to bogus
b331163b
A
565 // do not call setToBogus() here because fArray and flags are not consistent here
566 fUnion.fFields.fLengthAndFlags = kIsBogus;
46f4442e
A
567 fUnion.fFields.fArray = 0;
568 fUnion.fFields.fCapacity = 0;
b75a7d8f
A
569 break;
570 }
571
572 return *this;
573}
574
2ca993e8
A
575UnicodeString &UnicodeString::moveFrom(UnicodeString &src) U_NOEXCEPT {
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, TRUE);
580 return *this;
581}
582
583// Same as moveFrom() except without memory management.
584void UnicodeString::copyFieldsFrom(UnicodeString &src, UBool setSrcToBogus) U_NOEXCEPT {
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,
592 getShortLength() * U_SIZEOF_UCHAR);
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;
605 src.fUnion.fFields.fCapacity = 0;
606 }
607 }
608}
609
610void UnicodeString::swap(UnicodeString &other) U_NOEXCEPT {
611 UnicodeString temp; // Empty short string: Known not to need releaseArray().
612 // Copy fields without resetting source values in between.
613 temp.copyFieldsFrom(*this, FALSE);
614 this->copyFieldsFrom(other, FALSE);
615 other.copyFieldsFrom(temp, FALSE);
616 // Set temp to an empty string so that other's memory is not released twice.
617 temp.fUnion.fFields.fLengthAndFlags = kShortString;
618}
619
b75a7d8f
A
620//========================================
621// Miscellaneous operations
622//========================================
623
624UnicodeString UnicodeString::unescape() const {
46f4442e 625 UnicodeString result(length(), (UChar32)0, (int32_t)0); // construct with capacity
2ca993e8
A
626 if (result.isBogus()) {
627 return result;
628 }
46f4442e
A
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) {
b75a7d8f
A
641 result.remove(); // return empty string
642 break; // invalid escape sequence
643 }
46f4442e
A
644 result.append(c);
645 prev = i;
b75a7d8f 646 }
b75a7d8f
A
647 }
648 return result;
649}
650
651UChar32 UnicodeString::unescapeAt(int32_t &offset) const {
652 return u_unescapeAt(UnicodeString_charAt, &offset, length(), (void*)this);
653}
654
655//========================================
656// Read-only implementation
657//========================================
51004dcb
A
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) == 0;
663}
664
b75a7d8f
A
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
b75a7d8f
A
673 if(isBogus()) {
674 return -1;
675 }
676
677 // pin indices to legal values
678 pinIndices(start, length);
679
680 if(srcChars == NULL) {
4388f060
A
681 // treat const UChar *srcChars==NULL as an empty string
682 return length == 0 ? 0 : 1;
b75a7d8f
A
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_strlen(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
725 // big-endian: byte comparison works
726 result = uprv_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) {
761 srcStart = srcLength = 0;
762 }
763
4388f060 764 int32_t diff = uprv_strCompare(getArrayStart() + start, length, (srcChars!=NULL)?(srcChars + srcStart):NULL, srcLength, FALSE, TRUE);
b75a7d8f
A
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
b75a7d8f
A
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
4388f060
A
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);
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);
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);
819 return offset;
820 } else {
821 return len;
822 }
823}
824
b75a7d8f
A
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
46f4442e 829 return u_countChar32(getArrayStart()+start, length);
b75a7d8f
A
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
46f4442e 836 return u_strHasMoreChar32Than(getArrayStart()+start, length, number);
b75a7d8f
A
837}
838
839int32_t
840UnicodeString::moveIndex32(int32_t index, int32_t delta) const {
841 // pin index
46f4442e 842 int32_t len = length();
b75a7d8f
A
843 if(index<0) {
844 index=0;
46f4442e
A
845 } else if(index>len) {
846 index=len;
b75a7d8f
A
847 }
848
46f4442e 849 const UChar *array = getArrayStart();
b75a7d8f 850 if(delta>0) {
4388f060 851 U16_FWD_N(array, index, len, delta);
b75a7d8f 852 } else {
4388f060 853 U16_BACK_N(array, 0, index, -delta);
b75a7d8f
A
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
46f4442e
A
869 const UChar *array = getArrayStart();
870 if(array + start != dst + dstStart) {
871 us_arrayCopy(array, start, dst, dstStart, length);
b75a7d8f
A
872 }
873}
874
875int32_t
f3c0d7a5 876UnicodeString::extract(Char16Ptr dest, int32_t destCapacity,
b75a7d8f 877 UErrorCode &errorCode) const {
46f4442e 878 int32_t len = length();
b75a7d8f
A
879 if(U_SUCCESS(errorCode)) {
880 if(isBogus() || destCapacity<0 || (destCapacity>0 && dest==0)) {
881 errorCode=U_ILLEGAL_ARGUMENT_ERROR;
882 } else {
46f4442e
A
883 const UChar *array = getArrayStart();
884 if(len>0 && len<=destCapacity && array!=dest) {
a62d09fc 885 u_memcpy(dest, array, len);
b75a7d8f 886 }
46f4442e 887 return u_terminateUChars(dest, destCapacity, len, &errorCode);
b75a7d8f
A
888 }
889 }
890
46f4442e 891 return len;
b75a7d8f
A
892}
893
374ca955
A
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)) {
903 return 0;
904 }
905
906 // pin the indices to legal values
907 pinIndices(start, length);
908
909 if(length <= targetCapacity) {
910 u_UCharsToChars(getArrayStart() + start, target, length);
911 }
912 UErrorCode status = U_ZERO_ERROR;
913 return u_terminateChars(target, targetCapacity, length, &status);
914}
915
729e4ab9
A
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) {
b331163b 921 array=fUnion.fStackFields.fBuffer; // anything not NULL because that would make an empty string
729e4ab9
A
922 len=-2; // bogus result string
923 }
924 return UnicodeString(FALSE, 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_strToUTF8WithSub(target, capacity, &length8,
934 getBuffer() + start, len,
935 0xFFFD, // Standard substitution character.
936 NULL, // Don't care about number of substitutions.
937 &errorCode);
938 return length8;
939}
940
941#if U_CHARSET_IS_UTF8
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
374ca955
A
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
729e4ab9
A
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 = FALSE;
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_strToUTF8WithSub(utf8, capacity, &length8,
983 getBuffer(), length16,
984 0xFFFD, // Standard substitution character.
985 NULL, // Don't care about number of substitutions.
986 &errorCode);
987 if(errorCode == U_BUFFER_OVERFLOW_ERROR) {
988 utf8 = (char *)uprv_malloc(length8);
989 if(utf8 != NULL) {
990 utf8IsOwned = TRUE;
991 errorCode = U_ZERO_ERROR;
992 u_strToUTF8WithSub(utf8, length8, &length8,
993 getBuffer(), length16,
994 0xFFFD, // Standard substitution character.
995 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_free(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_strToUTF32WithSub(utf32, capacity, &length32,
1017 getBuffer(), length(),
1018 0xfffd, // Substitution character.
1019 NULL, // Don't care about number of substitutions.
1020 &errorCode);
1021 }
1022 return length32;
1023}
1024
b75a7d8f
A
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
46f4442e
A
1045 const UChar *array = getArrayStart();
1046 const UChar *match = u_strFindFirst(array + start, length, srcChars + srcStart, srcLength);
b75a7d8f
A
1047 if(match == NULL) {
1048 return -1;
1049 } else {
46f4442e 1050 return (int32_t)(match - array);
b75a7d8f
A
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
46f4442e
A
1063 const UChar *array = getArrayStart();
1064 const UChar *match = u_memchr(array + start, c, length);
b75a7d8f
A
1065 if(match == NULL) {
1066 return -1;
1067 } else {
46f4442e 1068 return (int32_t)(match - array);
b75a7d8f
A
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
46f4442e
A
1080 const UChar *array = getArrayStart();
1081 const UChar *match = u_memchr32(array + start, c, length);
b75a7d8f
A
1082 if(match == NULL) {
1083 return -1;
1084 } else {
46f4442e 1085 return (int32_t)(match - array);
b75a7d8f
A
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
46f4442e
A
1109 const UChar *array = getArrayStart();
1110 const UChar *match = u_strFindLast(array + start, length, srcChars + srcStart, srcLength);
b75a7d8f
A
1111 if(match == NULL) {
1112 return -1;
1113 } else {
46f4442e 1114 return (int32_t)(match - array);
b75a7d8f
A
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
46f4442e
A
1131 const UChar *array = getArrayStart();
1132 const UChar *match = u_memrchr(array + start, c, length);
b75a7d8f
A
1133 if(match == NULL) {
1134 return -1;
1135 } else {
46f4442e 1136 return (int32_t)(match - array);
b75a7d8f
A
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
46f4442e
A
1148 const UChar *array = getArrayStart();
1149 const UChar *match = u_memrchr32(array + start, c, length);
b75a7d8f
A
1150 if(match == NULL) {
1151 return -1;
1152 } else {
46f4442e 1153 return (int32_t)(match - array);
b75a7d8f
A
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();
1204
b331163b 1205 fUnion.fFields.fLengthAndFlags = kIsBogus;
46f4442e
A
1206 fUnion.fFields.fArray = 0;
1207 fUnion.fFields.fCapacity = 0;
b75a7d8f
A
1208}
1209
1210// turn a bogus string into an empty one
1211void
1212UnicodeString::unBogus() {
b331163b 1213 if(fUnion.fFields.fLengthAndFlags & kIsBogus) {
46f4442e 1214 setToEmpty();
b75a7d8f
A
1215 }
1216}
1217
f3c0d7a5 1218const char16_t *
57a6839d
A
1219UnicodeString::getTerminatedBuffer() {
1220 if(!isWritable()) {
f3c0d7a5 1221 return nullptr;
57a6839d
A
1222 }
1223 UChar *array = getArrayStart();
1224 int32_t len = length();
1225 if(len < getCapacity()) {
b331163b 1226 if(fUnion.fFields.fLengthAndFlags & kBufferIsReadonly) {
57a6839d
A
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 }
b331163b 1234 } else if(((fUnion.fFields.fLengthAndFlags & kRefCounted) == 0 || refCount() == 1)) {
57a6839d
A
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 }
a62d09fc 1247 if(len<INT32_MAX && cloneArrayIfNeeded(len+1)) {
57a6839d
A
1248 array = getArrayStart();
1249 array[len] = 0;
1250 return array;
1251 } else {
f3c0d7a5 1252 return nullptr;
57a6839d
A
1253 }
1254}
1255
b75a7d8f
A
1256// setTo() analogous to the readonly-aliasing constructor with the same signature
1257UnicodeString &
1258UnicodeString::setTo(UBool isTerminated,
f3c0d7a5 1259 ConstChar16Ptr textPtr,
b75a7d8f
A
1260 int32_t textLength)
1261{
b331163b 1262 if(fUnion.fFields.fLengthAndFlags & kOpenGetBuffer) {
b75a7d8f
A
1263 // do not modify a string that has an "open" getBuffer(minCapacity)
1264 return *this;
1265 }
1266
f3c0d7a5 1267 const UChar *text = textPtr;
b75a7d8f
A
1268 if(text == NULL) {
1269 // treat as an empty string, do not alias
1270 releaseArray();
46f4442e 1271 setToEmpty();
b75a7d8f
A
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
46f4442e 1285 if(textLength == -1) {
b75a7d8f 1286 // text is terminated, or else it would have failed the above test
46f4442e 1287 textLength = u_strlen(text);
b75a7d8f 1288 }
b331163b 1289 fUnion.fFields.fLengthAndFlags = kReadonlyAlias;
46f4442e 1290 setArray((UChar *)text, textLength, isTerminated ? textLength + 1 : textLength);
b75a7d8f
A
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) {
b331163b 1299 if(fUnion.fFields.fLengthAndFlags & kOpenGetBuffer) {
b75a7d8f
A
1300 // do not modify a string that has an "open" getBuffer(minCapacity)
1301 return *this;
1302 }
1303
1304 if(buffer == NULL) {
1305 // treat as an empty string, do not alias
1306 releaseArray();
46f4442e 1307 setToEmpty();
b75a7d8f
A
1308 return *this;
1309 }
1310
374ca955 1311 if(buffLength < -1 || buffCapacity < 0 || buffLength > buffCapacity) {
b75a7d8f
A
1312 setToBogus();
1313 return *this;
374ca955
A
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);
b75a7d8f
A
1321 }
1322
1323 releaseArray();
1324
b331163b 1325 fUnion.fFields.fLengthAndFlags = kWritableAlias;
46f4442e 1326 setArray(buffer, buffLength, buffCapacity);
b75a7d8f
A
1327 return *this;
1328}
1329
f3c0d7a5 1330UnicodeString &UnicodeString::setToUTF8(StringPiece utf8) {
729e4ab9
A
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_strFromUTF8WithSub(utf16, getCapacity(), &length16,
1344 utf8.data(), length,
1345 0xfffd, // Substitution character.
1346 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
b75a7d8f
A
1355UnicodeString&
1356UnicodeString::setCharAt(int32_t offset,
1357 UChar c)
1358{
46f4442e
A
1359 int32_t len = length();
1360 if(cloneArrayIfNeeded() && len > 0) {
b75a7d8f
A
1361 if(offset < 0) {
1362 offset = 0;
46f4442e
A
1363 } else if(offset >= len) {
1364 offset = len - 1;
b75a7d8f
A
1365 }
1366
46f4442e 1367 getArrayStart()[offset] = c;
b75a7d8f
A
1368 }
1369 return *this;
1370}
1371
4388f060
A
1372UnicodeString&
1373UnicodeString::replace(int32_t start,
1374 int32_t _length,
1375 UChar32 srcChar) {
1376 UChar buffer[U16_MAX_LENGTH];
1377 int32_t count = 0;
1378 UBool isError = FALSE;
1379 U16_APPEND(buffer, count, U16_MAX_LENGTH, srcChar, isError);
1380 // We test isError so that the compiler does not complain that we don't.
51004dcb
A
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);
4388f060
A
1384}
1385
1386UnicodeString&
1387UnicodeString::append(UChar32 srcChar) {
1388 UChar buffer[U16_MAX_LENGTH];
1389 int32_t _length = 0;
1390 UBool isError = FALSE;
1391 U16_APPEND(buffer, _length, U16_MAX_LENGTH, srcChar, isError);
1392 // We test isError so that the compiler does not complain that we don't.
2ca993e8
A
1393 // If isError then _length==0 which turns the doAppend() into a no-op anyway.
1394 return isError ? *this : doAppend(buffer, 0, _length);
4388f060
A
1395}
1396
b75a7d8f
A
1397UnicodeString&
1398UnicodeString::doReplace( int32_t start,
1399 int32_t length,
1400 const UnicodeString& src,
1401 int32_t srcStart,
1402 int32_t srcLength)
1403{
2ca993e8
A
1404 // pin the indices to legal values
1405 src.pinIndices(srcStart, srcLength);
b75a7d8f 1406
2ca993e8
A
1407 // get the characters from src
1408 // and replace the range in ourselves with them
1409 return doReplace(start, length, src.getArrayStart(), srcStart, srcLength);
b75a7d8f
A
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{
46f4442e 1419 if(!isWritable()) {
b75a7d8f
A
1420 return *this;
1421 }
1422
729e4ab9
A
1423 int32_t oldLength = this->length();
1424
1425 // optimize (read-only alias).remove(0, start) and .remove(start, end)
b331163b 1426 if((fUnion.fFields.fLengthAndFlags&kBufferIsReadonly) && srcLength == 0) {
729e4ab9
A
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
2ca993e8
A
1445 if(start == oldLength) {
1446 return doAppend(srcChars, srcStart, srcLength);
1447 }
1448
b75a7d8f
A
1449 if(srcChars == 0) {
1450 srcStart = srcLength = 0;
1451 } else if(srcLength < 0) {
1452 // get the srcLength if necessary
1453 srcLength = u_strlen(srcChars + srcStart);
1454 }
1455
2ca993e8
A
1456 // pin the indices to legal values
1457 pinIndices(start, length);
b75a7d8f 1458
a62d09fc
A
1459 // Calculate the size of the string after the replace.
1460 // Avoid int32_t overflow.
1461 int32_t newLength = oldLength - length;
1462 if(srcLength > (INT32_MAX - newLength)) {
1463 setToBogus();
1464 return *this;
1465 }
1466 newLength += srcLength;
b75a7d8f 1467
2ca993e8 1468 // cloneArrayIfNeeded(doCopyArray=FALSE) may change fArray but will not copy the current contents;
46f4442e
A
1469 // therefore we need to keep the current fArray
1470 UChar oldStackBuffer[US_STACKBUF_SIZE];
1471 UChar *oldArray;
b331163b 1472 if((fUnion.fFields.fLengthAndFlags&kUsingStackBuffer) && (newLength > US_STACKBUF_SIZE)) {
46f4442e
A
1473 // copy the stack buffer contents because it will be overwritten with
1474 // fUnion.fFields values
b331163b 1475 u_memcpy(oldStackBuffer, fUnion.fStackFields.fBuffer, oldLength);
46f4442e
A
1476 oldArray = oldStackBuffer;
1477 } else {
1478 oldArray = getArrayStart();
1479 }
b75a7d8f
A
1480
1481 // clone our array and allocate a bigger array if needed
46f4442e 1482 int32_t *bufferToDelete = 0;
a62d09fc 1483 if(!cloneArrayIfNeeded(newLength, getGrowCapacity(newLength),
b75a7d8f
A
1484 FALSE, &bufferToDelete)
1485 ) {
1486 return *this;
1487 }
1488
1489 // now do the replace
1490
46f4442e
A
1491 UChar *newArray = getArrayStart();
1492 if(newArray != oldArray) {
b75a7d8f 1493 // if fArray changed, then we need to copy everything except what will change
46f4442e 1494 us_arrayCopy(oldArray, 0, newArray, 0, start);
b75a7d8f 1495 us_arrayCopy(oldArray, start + length,
46f4442e 1496 newArray, start + srcLength,
b75a7d8f
A
1497 oldLength - (start + length));
1498 } else if(length != srcLength) {
1499 // fArray did not change; copy only the portion that isn't changing, leaving a hole
1500 us_arrayCopy(oldArray, start + length,
46f4442e 1501 newArray, start + srcLength,
b75a7d8f
A
1502 oldLength - (start + length));
1503 }
1504
1505 // now fill in the hole with the new string
46f4442e 1506 us_arrayCopy(srcChars, srcStart, newArray, start, srcLength);
b75a7d8f 1507
4388f060 1508 setLength(newLength);
b75a7d8f
A
1509
1510 // delayed delete in case srcChars == fArray when we started, and
1511 // to keep oldArray alive for the above operations
1512 if (bufferToDelete) {
1513 uprv_free(bufferToDelete);
1514 }
1515
1516 return *this;
1517}
1518
2ca993e8
A
1519// Versions of doReplace() only for append() variants.
1520// doReplace() and doAppend() optimize for different cases.
1521
1522UnicodeString&
1523UnicodeString::doAppend(const UnicodeString& src, int32_t srcStart, int32_t srcLength) {
1524 if(srcLength == 0) {
1525 return *this;
1526 }
1527
1528 // pin the indices to legal values
1529 src.pinIndices(srcStart, srcLength);
1530 return doAppend(src.getArrayStart(), srcStart, srcLength);
1531}
1532
1533UnicodeString&
1534UnicodeString::doAppend(const UChar *srcChars, int32_t srcStart, int32_t srcLength) {
1535 if(!isWritable() || srcLength == 0 || srcChars == NULL) {
1536 return *this;
1537 }
1538
1539 if(srcLength < 0) {
1540 // get the srcLength if necessary
1541 if((srcLength = u_strlen(srcChars + srcStart)) == 0) {
1542 return *this;
1543 }
1544 }
1545
1546 int32_t oldLength = length();
1547 int32_t newLength = oldLength + srcLength;
1548 // optimize append() onto a large-enough, owned string
1549 if((newLength <= getCapacity() && isBufferWritable()) ||
a62d09fc 1550 cloneArrayIfNeeded(newLength, getGrowCapacity(newLength))) {
2ca993e8
A
1551 UChar *newArray = getArrayStart();
1552 // Do not copy characters when
1553 // UChar *buffer=str.getAppendBuffer(...);
1554 // is followed by
1555 // str.append(buffer, length);
1556 // or
1557 // str.appendString(buffer, length)
1558 // or similar.
1559 if(srcChars + srcStart != newArray + oldLength) {
1560 us_arrayCopy(srcChars, srcStart, newArray, oldLength, srcLength);
1561 }
1562 setLength(newLength);
1563 }
1564 return *this;
1565}
1566
b75a7d8f
A
1567/**
1568 * Replaceable API
1569 */
1570void
1571UnicodeString::handleReplaceBetween(int32_t start,
1572 int32_t limit,
1573 const UnicodeString& text) {
1574 replaceBetween(start, limit, text);
1575}
1576
1577/**
1578 * Replaceable API
1579 */
1580void
1581UnicodeString::copy(int32_t start, int32_t limit, int32_t dest) {
1582 if (limit <= start) {
1583 return; // Nothing to do; avoid bogus malloc call
1584 }
1585 UChar* text = (UChar*) uprv_malloc( sizeof(UChar) * (limit - start) );
46f4442e
A
1586 // Check to make sure text is not null.
1587 if (text != NULL) {
1588 extractBetween(start, limit, text, 0);
1589 insert(dest, text, 0, limit - start);
1590 uprv_free(text);
1591 }
b75a7d8f
A
1592}
1593
1594/**
1595 * Replaceable API
1596 *
1597 * NOTE: This is for the Replaceable class. There is no rep.cpp,
1598 * so we implement this function here.
1599 */
1600UBool Replaceable::hasMetaData() const {
1601 return TRUE;
1602}
1603
1604/**
1605 * Replaceable API
1606 */
1607UBool UnicodeString::hasMetaData() const {
1608 return FALSE;
1609}
1610
1611UnicodeString&
729e4ab9
A
1612UnicodeString::doReverse(int32_t start, int32_t length) {
1613 if(length <= 1 || !cloneArrayIfNeeded()) {
b75a7d8f
A
1614 return *this;
1615 }
1616
1617 // pin the indices to legal values
1618 pinIndices(start, length);
729e4ab9
A
1619 if(length <= 1) { // pinIndices() might have shrunk the length
1620 return *this;
1621 }
b75a7d8f
A
1622
1623 UChar *left = getArrayStart() + start;
729e4ab9 1624 UChar *right = left + length - 1; // -1 for inclusive boundary (length>=2)
b75a7d8f
A
1625 UChar swap;
1626 UBool hasSupplementary = FALSE;
1627
729e4ab9
A
1628 // Before the loop we know left<right because length>=2.
1629 do {
1630 hasSupplementary |= (UBool)U16_IS_LEAD(swap = *left);
1631 hasSupplementary |= (UBool)U16_IS_LEAD(*left++ = *right);
1632 *right-- = swap;
1633 } while(left < right);
1634 // Make sure to test the middle code unit of an odd-length string.
1635 // Redundant if the length is even.
1636 hasSupplementary |= (UBool)U16_IS_LEAD(*left);
b75a7d8f
A
1637
1638 /* if there are supplementary code points in the reversed range, then re-swap their surrogates */
1639 if(hasSupplementary) {
1640 UChar swap2;
1641
1642 left = getArrayStart() + start;
46f4442e 1643 right = left + length - 1; // -1 so that we can look at *(left+1) if left<right
b75a7d8f 1644 while(left < right) {
729e4ab9 1645 if(U16_IS_TRAIL(swap = *left) && U16_IS_LEAD(swap2 = *(left + 1))) {
b75a7d8f
A
1646 *left++ = swap2;
1647 *left++ = swap;
1648 } else {
1649 ++left;
1650 }
1651 }
1652 }
1653
1654 return *this;
1655}
1656
1657UBool
1658UnicodeString::padLeading(int32_t targetLength,
1659 UChar padChar)
1660{
46f4442e
A
1661 int32_t oldLength = length();
1662 if(oldLength >= targetLength || !cloneArrayIfNeeded(targetLength)) {
b75a7d8f
A
1663 return FALSE;
1664 } else {
1665 // move contents up by padding width
46f4442e
A
1666 UChar *array = getArrayStart();
1667 int32_t start = targetLength - oldLength;
1668 us_arrayCopy(array, 0, array, start, oldLength);
b75a7d8f
A
1669
1670 // fill in padding character
1671 while(--start >= 0) {
46f4442e 1672 array[start] = padChar;
b75a7d8f 1673 }
46f4442e 1674 setLength(targetLength);
b75a7d8f
A
1675 return TRUE;
1676 }
1677}
1678
1679UBool
1680UnicodeString::padTrailing(int32_t targetLength,
1681 UChar padChar)
1682{
46f4442e
A
1683 int32_t oldLength = length();
1684 if(oldLength >= targetLength || !cloneArrayIfNeeded(targetLength)) {
b75a7d8f
A
1685 return FALSE;
1686 } else {
1687 // fill in padding character
46f4442e 1688 UChar *array = getArrayStart();
b75a7d8f 1689 int32_t length = targetLength;
46f4442e
A
1690 while(--length >= oldLength) {
1691 array[length] = padChar;
b75a7d8f 1692 }
46f4442e 1693 setLength(targetLength);
b75a7d8f
A
1694 return TRUE;
1695 }
1696}
1697
b75a7d8f
A
1698//========================================
1699// Hashing
1700//========================================
1701int32_t
1702UnicodeString::doHashCode() const
1703{
1704 /* Delegate hash computation to uhash. This makes UnicodeString
1705 * hashing consistent with UChar* hashing. */
4388f060 1706 int32_t hashCode = ustr_hashUCharsN(getArrayStart(), length());
b75a7d8f
A
1707 if (hashCode == kInvalidHashCode) {
1708 hashCode = kEmptyHashCode;
1709 }
1710 return hashCode;
1711}
1712
b75a7d8f
A
1713//========================================
1714// External Buffer
1715//========================================
1716
f3c0d7a5 1717char16_t *
b75a7d8f
A
1718UnicodeString::getBuffer(int32_t minCapacity) {
1719 if(minCapacity>=-1 && cloneArrayIfNeeded(minCapacity)) {
b331163b
A
1720 fUnion.fFields.fLengthAndFlags|=kOpenGetBuffer;
1721 setZeroLength();
46f4442e 1722 return getArrayStart();
b75a7d8f 1723 } else {
f3c0d7a5 1724 return nullptr;
b75a7d8f
A
1725 }
1726}
1727
1728void
1729UnicodeString::releaseBuffer(int32_t newLength) {
b331163b 1730 if(fUnion.fFields.fLengthAndFlags&kOpenGetBuffer && newLength>=-1) {
b75a7d8f 1731 // set the new fLength
46f4442e 1732 int32_t capacity=getCapacity();
b75a7d8f
A
1733 if(newLength==-1) {
1734 // the new length is the string length, capped by fCapacity
46f4442e 1735 const UChar *array=getArrayStart(), *p=array, *limit=array+capacity;
b75a7d8f
A
1736 while(p<limit && *p!=0) {
1737 ++p;
1738 }
46f4442e
A
1739 newLength=(int32_t)(p-array);
1740 } else if(newLength>capacity) {
1741 newLength=capacity;
b75a7d8f 1742 }
46f4442e 1743 setLength(newLength);
b331163b 1744 fUnion.fFields.fLengthAndFlags&=~kOpenGetBuffer;
b75a7d8f
A
1745 }
1746}
1747
1748//========================================
1749// Miscellaneous
1750//========================================
1751UBool
1752UnicodeString::cloneArrayIfNeeded(int32_t newCapacity,
1753 int32_t growCapacity,
1754 UBool doCopyArray,
1755 int32_t **pBufferToDelete,
1756 UBool forceClone) {
1757 // default parameters need to be static, therefore
1758 // the defaults are -1 to have convenience defaults
1759 if(newCapacity == -1) {
46f4442e 1760 newCapacity = getCapacity();
b75a7d8f
A
1761 }
1762
1763 // while a getBuffer(minCapacity) is "open",
1764 // prevent any modifications of the string by returning FALSE here
1765 // if the string is bogus, then only an assignment or similar can revive it
46f4442e 1766 if(!isWritable()) {
b75a7d8f
A
1767 return FALSE;
1768 }
1769
1770 /*
1771 * We need to make a copy of the array if
1772 * the buffer is read-only, or
1773 * the buffer is refCounted (shared), and refCount>1, or
1774 * the buffer is too small.
1775 * Return FALSE if memory could not be allocated.
1776 */
1777 if(forceClone ||
b331163b
A
1778 fUnion.fFields.fLengthAndFlags & kBufferIsReadonly ||
1779 (fUnion.fFields.fLengthAndFlags & kRefCounted && refCount() > 1) ||
46f4442e 1780 newCapacity > getCapacity()
b75a7d8f 1781 ) {
b75a7d8f 1782 // check growCapacity for default value and use of the stack buffer
4388f060 1783 if(growCapacity < 0) {
b75a7d8f
A
1784 growCapacity = newCapacity;
1785 } else if(newCapacity <= US_STACKBUF_SIZE && growCapacity > US_STACKBUF_SIZE) {
1786 growCapacity = US_STACKBUF_SIZE;
1787 }
1788
46f4442e
A
1789 // save old values
1790 UChar oldStackBuffer[US_STACKBUF_SIZE];
1791 UChar *oldArray;
b331163b
A
1792 int32_t oldLength = length();
1793 int16_t flags = fUnion.fFields.fLengthAndFlags;
46f4442e
A
1794
1795 if(flags&kUsingStackBuffer) {
4388f060 1796 U_ASSERT(!(flags&kRefCounted)); /* kRefCounted and kUsingStackBuffer are mutally exclusive */
46f4442e
A
1797 if(doCopyArray && growCapacity > US_STACKBUF_SIZE) {
1798 // copy the stack buffer contents because it will be overwritten with
1799 // fUnion.fFields values
b331163b 1800 us_arrayCopy(fUnion.fStackFields.fBuffer, 0, oldStackBuffer, 0, oldLength);
46f4442e
A
1801 oldArray = oldStackBuffer;
1802 } else {
b331163b 1803 oldArray = NULL; // no need to copy from the stack buffer to itself
46f4442e
A
1804 }
1805 } else {
1806 oldArray = fUnion.fFields.fArray;
4388f060 1807 U_ASSERT(oldArray!=NULL); /* when stack buffer is not used, oldArray must have a non-NULL reference */
46f4442e
A
1808 }
1809
b75a7d8f
A
1810 // allocate a new array
1811 if(allocate(growCapacity) ||
729e4ab9 1812 (newCapacity < growCapacity && allocate(newCapacity))
b75a7d8f 1813 ) {
b331163b 1814 if(doCopyArray) {
b75a7d8f
A
1815 // copy the contents
1816 // do not copy more than what fits - it may be smaller than before
b331163b 1817 int32_t minLength = oldLength;
46f4442e
A
1818 newCapacity = getCapacity();
1819 if(newCapacity < minLength) {
1820 minLength = newCapacity;
b75a7d8f 1821 }
b331163b
A
1822 if(oldArray != NULL) {
1823 us_arrayCopy(oldArray, 0, getArrayStart(), 0, minLength);
1824 }
1825 setLength(minLength);
b75a7d8f 1826 } else {
b331163b 1827 setZeroLength();
b75a7d8f
A
1828 }
1829
1830 // release the old array
1831 if(flags & kRefCounted) {
1832 // the array is refCounted; decrement and release if 0
57a6839d 1833 u_atomic_int32_t *pRefCount = ((u_atomic_int32_t *)oldArray - 1);
b75a7d8f
A
1834 if(umtx_atomic_dec(pRefCount) == 0) {
1835 if(pBufferToDelete == 0) {
57a6839d
A
1836 // Note: cast to (void *) is needed with MSVC, where u_atomic_int32_t
1837 // is defined as volatile. (Volatile has useful non-standard behavior
1838 // with this compiler.)
1839 uprv_free((void *)pRefCount);
b75a7d8f
A
1840 } else {
1841 // the caller requested to delete it himself
57a6839d 1842 *pBufferToDelete = (int32_t *)pRefCount;
b75a7d8f
A
1843 }
1844 }
1845 }
1846 } else {
1847 // not enough memory for growCapacity and not even for the smaller newCapacity
1848 // reset the old values for setToBogus() to release the array
46f4442e
A
1849 if(!(flags&kUsingStackBuffer)) {
1850 fUnion.fFields.fArray = oldArray;
1851 }
b331163b 1852 fUnion.fFields.fLengthAndFlags = flags;
b75a7d8f
A
1853 setToBogus();
1854 return FALSE;
1855 }
1856 }
1857 return TRUE;
1858}
4388f060
A
1859
1860// UnicodeStringAppendable ------------------------------------------------- ***
1861
1862UnicodeStringAppendable::~UnicodeStringAppendable() {}
1863
1864UBool
1865UnicodeStringAppendable::appendCodeUnit(UChar c) {
2ca993e8 1866 return str.doAppend(&c, 0, 1).isWritable();
4388f060
A
1867}
1868
1869UBool
1870UnicodeStringAppendable::appendCodePoint(UChar32 c) {
1871 UChar buffer[U16_MAX_LENGTH];
1872 int32_t cLength = 0;
1873 UBool isError = FALSE;
1874 U16_APPEND(buffer, cLength, U16_MAX_LENGTH, c, isError);
2ca993e8 1875 return !isError && str.doAppend(buffer, 0, cLength).isWritable();
4388f060
A
1876}
1877
1878UBool
1879UnicodeStringAppendable::appendString(const UChar *s, int32_t length) {
2ca993e8 1880 return str.doAppend(s, 0, length).isWritable();
4388f060
A
1881}
1882
1883UBool
1884UnicodeStringAppendable::reserveAppendCapacity(int32_t appendCapacity) {
1885 return str.cloneArrayIfNeeded(str.length() + appendCapacity);
1886}
1887
1888UChar *
1889UnicodeStringAppendable::getAppendBuffer(int32_t minCapacity,
1890 int32_t desiredCapacityHint,
1891 UChar *scratch, int32_t scratchCapacity,
1892 int32_t *resultCapacity) {
1893 if(minCapacity < 1 || scratchCapacity < minCapacity) {
1894 *resultCapacity = 0;
1895 return NULL;
1896 }
1897 int32_t oldLength = str.length();
a62d09fc
A
1898 if(minCapacity <= (kMaxCapacity - oldLength) &&
1899 desiredCapacityHint <= (kMaxCapacity - oldLength) &&
1900 str.cloneArrayIfNeeded(oldLength + minCapacity, oldLength + desiredCapacityHint)) {
4388f060
A
1901 *resultCapacity = str.getCapacity() - oldLength;
1902 return str.getArrayStart() + oldLength;
1903 }
1904 *resultCapacity = scratchCapacity;
1905 return scratch;
1906}
1907
b75a7d8f 1908U_NAMESPACE_END
73c04bcf 1909
4388f060
A
1910U_NAMESPACE_USE
1911
1912U_CAPI int32_t U_EXPORT2
1913uhash_hashUnicodeString(const UElement key) {
1914 const UnicodeString *str = (const UnicodeString*) key.pointer;
1915 return (str == NULL) ? 0 : str->hashCode();
1916}
1917
1918// Moved here from uhash_us.cpp so that using a UVector of UnicodeString*
1919// does not depend on hashtable code.
1920U_CAPI UBool U_EXPORT2
1921uhash_compareUnicodeString(const UElement key1, const UElement key2) {
1922 const UnicodeString *str1 = (const UnicodeString*) key1.pointer;
1923 const UnicodeString *str2 = (const UnicodeString*) key2.pointer;
1924 if (str1 == str2) {
1925 return TRUE;
1926 }
1927 if (str1 == NULL || str2 == NULL) {
1928 return FALSE;
1929 }
1930 return *str1 == *str2;
1931}
1932
73c04bcf
A
1933#ifdef U_STATIC_IMPLEMENTATION
1934/*
1935This should never be called. It is defined here to make sure that the
1936virtual vector deleting destructor is defined within unistr.cpp.
1937The vector deleting destructor is already a part of UObject,
1938but defining it here makes sure that it is included with this object file.
1939This makes sure that static library dependencies are kept to a minimum.
1940*/
1941static void uprv_UnicodeStringDummy(void) {
73c04bcf
A
1942 delete [] (new UnicodeString[2]);
1943}
1944#endif