OLD | NEW |
1 /* | 1 /* |
2 ****************************************************************************** | 2 ****************************************************************************** |
3 * Copyright (C) 1999-2014, International Business Machines Corporation and | 3 * Copyright (C) 1999-2015, International Business Machines Corporation and |
4 * others. All Rights Reserved. | 4 * others. All Rights Reserved. |
5 ****************************************************************************** | 5 ****************************************************************************** |
6 * | 6 * |
7 * File unistr.cpp | 7 * File unistr.cpp |
8 * | 8 * |
9 * Modification History: | 9 * Modification History: |
10 * | 10 * |
11 * Date Name Description | 11 * Date Name Description |
12 * 09/25/98 stephen Creation. | 12 * 09/25/98 stephen Creation. |
13 * 04/20/99 stephen Overhauled per 4/16 code review. | 13 * 04/20/99 stephen Overhauled per 4/16 code review. |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 return umtx_atomic_dec((u_atomic_int32_t *)fUnion.fFields.fArray - 1); | 126 return umtx_atomic_dec((u_atomic_int32_t *)fUnion.fFields.fArray - 1); |
127 } | 127 } |
128 | 128 |
129 int32_t | 129 int32_t |
130 UnicodeString::refCount() const { | 130 UnicodeString::refCount() const { |
131 return umtx_loadAcquire(*((u_atomic_int32_t *)fUnion.fFields.fArray - 1)); | 131 return umtx_loadAcquire(*((u_atomic_int32_t *)fUnion.fFields.fArray - 1)); |
132 } | 132 } |
133 | 133 |
134 void | 134 void |
135 UnicodeString::releaseArray() { | 135 UnicodeString::releaseArray() { |
136 if((fFlags & kRefCounted) && removeRef() == 0) { | 136 if((fUnion.fFields.fLengthAndFlags & kRefCounted) && removeRef() == 0) { |
137 uprv_free((int32_t *)fUnion.fFields.fArray - 1); | 137 uprv_free((int32_t *)fUnion.fFields.fArray - 1); |
138 } | 138 } |
139 } | 139 } |
140 | 140 |
141 | 141 |
142 | 142 |
143 //======================================== | 143 //======================================== |
144 // Constructors | 144 // Constructors |
145 //======================================== | 145 //======================================== |
146 | 146 |
147 // The default constructor is inline in unistr.h. | 147 // The default constructor is inline in unistr.h. |
148 | 148 |
149 UnicodeString::UnicodeString(int32_t capacity, UChar32 c, int32_t count) | 149 UnicodeString::UnicodeString(int32_t capacity, UChar32 c, int32_t count) { |
150 : fShortLength(0), | 150 fUnion.fFields.fLengthAndFlags = 0; |
151 fFlags(0) | |
152 { | |
153 if(count <= 0 || (uint32_t)c > 0x10ffff) { | 151 if(count <= 0 || (uint32_t)c > 0x10ffff) { |
154 // just allocate and do not do anything else | 152 // just allocate and do not do anything else |
155 allocate(capacity); | 153 allocate(capacity); |
156 } else { | 154 } else { |
157 // count > 0, allocate and fill the new string with count c's | 155 // count > 0, allocate and fill the new string with count c's |
158 int32_t unitCount = U16_LENGTH(c), length = count * unitCount; | 156 int32_t unitCount = U16_LENGTH(c), length = count * unitCount; |
159 if(capacity < length) { | 157 if(capacity < length) { |
160 capacity = length; | 158 capacity = length; |
161 } | 159 } |
162 if(allocate(capacity)) { | 160 if(allocate(capacity)) { |
(...skipping 21 matching lines...) Expand all Loading... |
184 while(unitIdx < unitCount) { | 182 while(unitIdx < unitCount) { |
185 array[i++]=units[unitIdx++]; | 183 array[i++]=units[unitIdx++]; |
186 } | 184 } |
187 } | 185 } |
188 } | 186 } |
189 } | 187 } |
190 setLength(length); | 188 setLength(length); |
191 } | 189 } |
192 } | 190 } |
193 | 191 |
194 UnicodeString::UnicodeString(UChar ch) | 192 UnicodeString::UnicodeString(UChar ch) { |
195 : fShortLength(1), | 193 fUnion.fFields.fLengthAndFlags = kLength1 | kShortString; |
196 fFlags(kShortString) | 194 fUnion.fStackFields.fBuffer[0] = ch; |
197 { | |
198 fUnion.fStackBuffer[0] = ch; | |
199 } | 195 } |
200 | 196 |
201 UnicodeString::UnicodeString(UChar32 ch) | 197 UnicodeString::UnicodeString(UChar32 ch) { |
202 : fShortLength(0), | 198 fUnion.fFields.fLengthAndFlags = kShortString; |
203 fFlags(kShortString) | |
204 { | |
205 int32_t i = 0; | 199 int32_t i = 0; |
206 UBool isError = FALSE; | 200 UBool isError = FALSE; |
207 U16_APPEND(fUnion.fStackBuffer, i, US_STACKBUF_SIZE, ch, isError); | 201 U16_APPEND(fUnion.fStackFields.fBuffer, i, US_STACKBUF_SIZE, ch, isError); |
208 // We test isError so that the compiler does not complain that we don't. | 202 // We test isError so that the compiler does not complain that we don't. |
209 // If isError then i==0 which is what we want anyway. | 203 // If isError then i==0 which is what we want anyway. |
210 if(!isError) { | 204 if(!isError) { |
211 fShortLength = (int8_t)i; | 205 setShortLength(i); |
212 } | 206 } |
213 } | 207 } |
214 | 208 |
215 UnicodeString::UnicodeString(const UChar *text) | 209 UnicodeString::UnicodeString(const UChar *text) { |
216 : fShortLength(0), | 210 fUnion.fFields.fLengthAndFlags = kShortString; |
217 fFlags(kShortString) | 211 doAppend(text, 0, -1); |
218 { | |
219 doReplace(0, 0, text, 0, -1); | |
220 } | 212 } |
221 | 213 |
222 UnicodeString::UnicodeString(const UChar *text, | 214 UnicodeString::UnicodeString(const UChar *text, |
223 int32_t textLength) | 215 int32_t textLength) { |
224 : fShortLength(0), | 216 fUnion.fFields.fLengthAndFlags = kShortString; |
225 fFlags(kShortString) | 217 doAppend(text, 0, textLength); |
226 { | |
227 doReplace(0, 0, text, 0, textLength); | |
228 } | 218 } |
229 | 219 |
230 UnicodeString::UnicodeString(UBool isTerminated, | 220 UnicodeString::UnicodeString(UBool isTerminated, |
231 const UChar *text, | 221 const UChar *text, |
232 int32_t textLength) | 222 int32_t textLength) { |
233 : fShortLength(0), | 223 fUnion.fFields.fLengthAndFlags = kReadonlyAlias; |
234 fFlags(kReadonlyAlias) | |
235 { | |
236 if(text == NULL) { | 224 if(text == NULL) { |
237 // treat as an empty string, do not alias | 225 // treat as an empty string, do not alias |
238 setToEmpty(); | 226 setToEmpty(); |
239 } else if(textLength < -1 || | 227 } else if(textLength < -1 || |
240 (textLength == -1 && !isTerminated) || | 228 (textLength == -1 && !isTerminated) || |
241 (textLength >= 0 && isTerminated && text[textLength] != 0) | 229 (textLength >= 0 && isTerminated && text[textLength] != 0) |
242 ) { | 230 ) { |
243 setToBogus(); | 231 setToBogus(); |
244 } else { | 232 } else { |
245 if(textLength == -1) { | 233 if(textLength == -1) { |
246 // text is terminated, or else it would have failed the above test | 234 // text is terminated, or else it would have failed the above test |
247 textLength = u_strlen(text); | 235 textLength = u_strlen(text); |
248 } | 236 } |
249 setArray((UChar *)text, textLength, isTerminated ? textLength + 1 : textLeng
th); | 237 setArray((UChar *)text, textLength, isTerminated ? textLength + 1 : textLeng
th); |
250 } | 238 } |
251 } | 239 } |
252 | 240 |
253 UnicodeString::UnicodeString(UChar *buff, | 241 UnicodeString::UnicodeString(UChar *buff, |
254 int32_t buffLength, | 242 int32_t buffLength, |
255 int32_t buffCapacity) | 243 int32_t buffCapacity) { |
256 : fShortLength(0), | 244 fUnion.fFields.fLengthAndFlags = kWritableAlias; |
257 fFlags(kWritableAlias) | |
258 { | |
259 if(buff == NULL) { | 245 if(buff == NULL) { |
260 // treat as an empty string, do not alias | 246 // treat as an empty string, do not alias |
261 setToEmpty(); | 247 setToEmpty(); |
262 } else if(buffLength < -1 || buffCapacity < 0 || buffLength > buffCapacity) { | 248 } else if(buffLength < -1 || buffCapacity < 0 || buffLength > buffCapacity) { |
263 setToBogus(); | 249 setToBogus(); |
264 } else { | 250 } else { |
265 if(buffLength == -1) { | 251 if(buffLength == -1) { |
266 // fLength = u_strlen(buff); but do not look beyond buffCapacity | 252 // fLength = u_strlen(buff); but do not look beyond buffCapacity |
267 const UChar *p = buff, *limit = buff + buffCapacity; | 253 const UChar *p = buff, *limit = buff + buffCapacity; |
268 while(p != limit && *p != 0) { | 254 while(p != limit && *p != 0) { |
269 ++p; | 255 ++p; |
270 } | 256 } |
271 buffLength = (int32_t)(p - buff); | 257 buffLength = (int32_t)(p - buff); |
272 } | 258 } |
273 setArray(buff, buffLength, buffCapacity); | 259 setArray(buff, buffLength, buffCapacity); |
274 } | 260 } |
275 } | 261 } |
276 | 262 |
277 UnicodeString::UnicodeString(const char *src, int32_t length, EInvariant) | 263 UnicodeString::UnicodeString(const char *src, int32_t length, EInvariant) { |
278 : fShortLength(0), | 264 fUnion.fFields.fLengthAndFlags = kShortString; |
279 fFlags(kShortString) | |
280 { | |
281 if(src==NULL) { | 265 if(src==NULL) { |
282 // treat as an empty string | 266 // treat as an empty string |
283 } else { | 267 } else { |
284 if(length<0) { | 268 if(length<0) { |
285 length=(int32_t)uprv_strlen(src); | 269 length=(int32_t)uprv_strlen(src); |
286 } | 270 } |
287 if(cloneArrayIfNeeded(length, length, FALSE)) { | 271 if(cloneArrayIfNeeded(length, length, FALSE)) { |
288 u_charsToUChars(src, getArrayStart(), length); | 272 u_charsToUChars(src, getArrayStart(), length); |
289 setLength(length); | 273 setLength(length); |
290 } else { | 274 } else { |
291 setToBogus(); | 275 setToBogus(); |
292 } | 276 } |
293 } | 277 } |
294 } | 278 } |
295 | 279 |
296 #if U_CHARSET_IS_UTF8 | 280 #if U_CHARSET_IS_UTF8 |
297 | 281 |
298 UnicodeString::UnicodeString(const char *codepageData) | 282 UnicodeString::UnicodeString(const char *codepageData) { |
299 : fShortLength(0), | 283 fUnion.fFields.fLengthAndFlags = kShortString; |
300 fFlags(kShortString) { | |
301 if(codepageData != 0) { | 284 if(codepageData != 0) { |
302 setToUTF8(codepageData); | 285 setToUTF8(codepageData); |
303 } | 286 } |
304 } | 287 } |
305 | 288 |
306 UnicodeString::UnicodeString(const char *codepageData, int32_t dataLength) | 289 UnicodeString::UnicodeString(const char *codepageData, int32_t dataLength) { |
307 : fShortLength(0), | 290 fUnion.fFields.fLengthAndFlags = kShortString; |
308 fFlags(kShortString) { | |
309 // if there's nothing to convert, do nothing | 291 // if there's nothing to convert, do nothing |
310 if(codepageData == 0 || dataLength == 0 || dataLength < -1) { | 292 if(codepageData == 0 || dataLength == 0 || dataLength < -1) { |
311 return; | 293 return; |
312 } | 294 } |
313 if(dataLength == -1) { | 295 if(dataLength == -1) { |
314 dataLength = (int32_t)uprv_strlen(codepageData); | 296 dataLength = (int32_t)uprv_strlen(codepageData); |
315 } | 297 } |
316 setToUTF8(StringPiece(codepageData, dataLength)); | 298 setToUTF8(StringPiece(codepageData, dataLength)); |
317 } | 299 } |
318 | 300 |
319 // else see unistr_cnv.cpp | 301 // else see unistr_cnv.cpp |
320 #endif | 302 #endif |
321 | 303 |
322 UnicodeString::UnicodeString(const UnicodeString& that) | 304 UnicodeString::UnicodeString(const UnicodeString& that) { |
323 : Replaceable(), | 305 fUnion.fFields.fLengthAndFlags = kShortString; |
324 fShortLength(0), | |
325 fFlags(kShortString) | |
326 { | |
327 copyFrom(that); | 306 copyFrom(that); |
328 } | 307 } |
329 | 308 |
| 309 #if U_HAVE_RVALUE_REFERENCES |
| 310 UnicodeString::UnicodeString(UnicodeString &&src) U_NOEXCEPT { |
| 311 fUnion.fFields.fLengthAndFlags = kShortString; |
| 312 moveFrom(src); |
| 313 } |
| 314 #endif |
| 315 |
330 UnicodeString::UnicodeString(const UnicodeString& that, | 316 UnicodeString::UnicodeString(const UnicodeString& that, |
331 int32_t srcStart) | 317 int32_t srcStart) { |
332 : Replaceable(), | 318 fUnion.fFields.fLengthAndFlags = kShortString; |
333 fShortLength(0), | |
334 fFlags(kShortString) | |
335 { | |
336 setTo(that, srcStart); | 319 setTo(that, srcStart); |
337 } | 320 } |
338 | 321 |
339 UnicodeString::UnicodeString(const UnicodeString& that, | 322 UnicodeString::UnicodeString(const UnicodeString& that, |
340 int32_t srcStart, | 323 int32_t srcStart, |
341 int32_t srcLength) | 324 int32_t srcLength) { |
342 : Replaceable(), | 325 fUnion.fFields.fLengthAndFlags = kShortString; |
343 fShortLength(0), | |
344 fFlags(kShortString) | |
345 { | |
346 setTo(that, srcStart, srcLength); | 326 setTo(that, srcStart, srcLength); |
347 } | 327 } |
348 | 328 |
349 // Replaceable base class clone() default implementation, does not clone | 329 // Replaceable base class clone() default implementation, does not clone |
350 Replaceable * | 330 Replaceable * |
351 Replaceable::clone() const { | 331 Replaceable::clone() const { |
352 return NULL; | 332 return NULL; |
353 } | 333 } |
354 | 334 |
355 // UnicodeString overrides clone() with a real implementation | 335 // UnicodeString overrides clone() with a real implementation |
356 Replaceable * | 336 Replaceable * |
357 UnicodeString::clone() const { | 337 UnicodeString::clone() const { |
358 return new UnicodeString(*this); | 338 return new UnicodeString(*this); |
359 } | 339 } |
360 | 340 |
361 //======================================== | 341 //======================================== |
362 // array allocation | 342 // array allocation |
363 //======================================== | 343 //======================================== |
364 | 344 |
365 UBool | 345 UBool |
366 UnicodeString::allocate(int32_t capacity) { | 346 UnicodeString::allocate(int32_t capacity) { |
367 if(capacity <= US_STACKBUF_SIZE) { | 347 if(capacity <= US_STACKBUF_SIZE) { |
368 fFlags = kShortString; | 348 fUnion.fFields.fLengthAndFlags = kShortString; |
369 } else { | 349 } else { |
370 // count bytes for the refCounter and the string capacity, and | 350 // count bytes for the refCounter and the string capacity, and |
371 // round up to a multiple of 16; then divide by 4 and allocate int32_t's | 351 // round up to a multiple of 16; then divide by 4 and allocate int32_t's |
372 // to be safely aligned for the refCount | 352 // to be safely aligned for the refCount |
373 // the +1 is for the NUL terminator, to avoid reallocation in getTerminatedB
uffer() | 353 // the +1 is for the NUL terminator, to avoid reallocation in getTerminatedB
uffer() |
374 int32_t words = (int32_t)(((sizeof(int32_t) + (capacity + 1) * U_SIZEOF_UCHA
R + 15) & ~15) >> 2); | 354 int32_t words = (int32_t)(((sizeof(int32_t) + (capacity + 1) * U_SIZEOF_UCHA
R + 15) & ~15) >> 2); |
375 int32_t *array = (int32_t*) uprv_malloc( sizeof(int32_t) * words ); | 355 int32_t *array = (int32_t*) uprv_malloc( sizeof(int32_t) * words ); |
376 if(array != 0) { | 356 if(array != 0) { |
377 // set initial refCount and point behind the refCount | 357 // set initial refCount and point behind the refCount |
378 *array++ = 1; | 358 *array++ = 1; |
379 | 359 |
380 // have fArray point to the first UChar | 360 // have fArray point to the first UChar |
381 fUnion.fFields.fArray = (UChar *)array; | 361 fUnion.fFields.fArray = (UChar *)array; |
382 fUnion.fFields.fCapacity = (int32_t)((words - 1) * (sizeof(int32_t) / U_SI
ZEOF_UCHAR)); | 362 fUnion.fFields.fCapacity = (int32_t)((words - 1) * (sizeof(int32_t) / U_SI
ZEOF_UCHAR)); |
383 fFlags = kLongString; | 363 fUnion.fFields.fLengthAndFlags = kLongString; |
384 } else { | 364 } else { |
385 fShortLength = 0; | 365 fUnion.fFields.fLengthAndFlags = kIsBogus; |
386 fUnion.fFields.fArray = 0; | 366 fUnion.fFields.fArray = 0; |
387 fUnion.fFields.fCapacity = 0; | 367 fUnion.fFields.fCapacity = 0; |
388 fFlags = kIsBogus; | |
389 return FALSE; | 368 return FALSE; |
390 } | 369 } |
391 } | 370 } |
392 return TRUE; | 371 return TRUE; |
393 } | 372 } |
394 | 373 |
395 //======================================== | 374 //======================================== |
396 // Destructor | 375 // Destructor |
397 //======================================== | 376 //======================================== |
| 377 |
| 378 #ifdef UNISTR_COUNT_FINAL_STRING_LENGTHS |
| 379 static u_atomic_int32_t finalLengthCounts[0x400]; // UnicodeString::kMaxShortLe
ngth+1 |
| 380 static u_atomic_int32_t beyondCount(0); |
| 381 |
| 382 U_CAPI void unistr_printLengths() { |
| 383 int32_t i; |
| 384 for(i = 0; i <= 59; ++i) { |
| 385 printf("%2d, %9d\n", i, (int32_t)finalLengthCounts[i]); |
| 386 } |
| 387 int32_t beyond = beyondCount; |
| 388 for(; i < UPRV_LENGTHOF(finalLengthCounts); ++i) { |
| 389 beyond += finalLengthCounts[i]; |
| 390 } |
| 391 printf(">59, %9d\n", beyond); |
| 392 } |
| 393 #endif |
| 394 |
398 UnicodeString::~UnicodeString() | 395 UnicodeString::~UnicodeString() |
399 { | 396 { |
| 397 #ifdef UNISTR_COUNT_FINAL_STRING_LENGTHS |
| 398 // Count lengths of strings at the end of their lifetime. |
| 399 // Useful for discussion of a desirable stack buffer size. |
| 400 // Count the contents length, not the optional NUL terminator nor further capa
city. |
| 401 // Ignore open-buffer strings and strings which alias external storage. |
| 402 if((fUnion.fFields.fLengthAndFlags&(kOpenGetBuffer|kReadonlyAlias|kWritableAli
as)) == 0) { |
| 403 if(hasShortLength()) { |
| 404 umtx_atomic_inc(finalLengthCounts + getShortLength()); |
| 405 } else { |
| 406 umtx_atomic_inc(&beyondCount); |
| 407 } |
| 408 } |
| 409 #endif |
| 410 |
400 releaseArray(); | 411 releaseArray(); |
401 } | 412 } |
402 | 413 |
403 //======================================== | 414 //======================================== |
404 // Factory methods | 415 // Factory methods |
405 //======================================== | 416 //======================================== |
406 | 417 |
407 UnicodeString UnicodeString::fromUTF8(const StringPiece &utf8) { | 418 UnicodeString UnicodeString::fromUTF8(const StringPiece &utf8) { |
408 UnicodeString result; | 419 UnicodeString result; |
409 result.setToUTF8(utf8); | 420 result.setToUTF8(utf8); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
471 | 482 |
472 // delete the current contents | 483 // delete the current contents |
473 releaseArray(); | 484 releaseArray(); |
474 | 485 |
475 if(src.isEmpty()) { | 486 if(src.isEmpty()) { |
476 // empty string - use the stack buffer | 487 // empty string - use the stack buffer |
477 setToEmpty(); | 488 setToEmpty(); |
478 return *this; | 489 return *this; |
479 } | 490 } |
480 | 491 |
481 // we always copy the length | |
482 int32_t srcLength = src.length(); | |
483 setLength(srcLength); | |
484 | |
485 // fLength>0 and not an "open" src.getBuffer(minCapacity) | 492 // fLength>0 and not an "open" src.getBuffer(minCapacity) |
486 switch(src.fFlags) { | 493 fUnion.fFields.fLengthAndFlags = src.fUnion.fFields.fLengthAndFlags; |
| 494 switch(src.fUnion.fFields.fLengthAndFlags & kAllStorageFlags) { |
487 case kShortString: | 495 case kShortString: |
488 // short string using the stack buffer, do the same | 496 // short string using the stack buffer, do the same |
489 fFlags = kShortString; | 497 uprv_memcpy(fUnion.fStackFields.fBuffer, src.fUnion.fStackFields.fBuffer, |
490 uprv_memcpy(fUnion.fStackBuffer, src.fUnion.fStackBuffer, srcLength * U_SIZE
OF_UCHAR); | 498 getShortLength() * U_SIZEOF_UCHAR); |
491 break; | 499 break; |
492 case kLongString: | 500 case kLongString: |
493 // src uses a refCounted string buffer, use that buffer with refCount | 501 // src uses a refCounted string buffer, use that buffer with refCount |
494 // src is const, use a cast - we don't really change it | 502 // src is const, use a cast - we don't actually change it |
495 ((UnicodeString &)src).addRef(); | 503 ((UnicodeString &)src).addRef(); |
496 // copy all fields, share the reference-counted buffer | 504 // copy all fields, share the reference-counted buffer |
497 fUnion.fFields.fArray = src.fUnion.fFields.fArray; | 505 fUnion.fFields.fArray = src.fUnion.fFields.fArray; |
498 fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity; | 506 fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity; |
499 fFlags = src.fFlags; | 507 if(!hasShortLength()) { |
| 508 fUnion.fFields.fLength = src.fUnion.fFields.fLength; |
| 509 } |
500 break; | 510 break; |
501 case kReadonlyAlias: | 511 case kReadonlyAlias: |
502 if(fastCopy) { | 512 if(fastCopy) { |
503 // src is a readonly alias, do the same | 513 // src is a readonly alias, do the same |
504 // -> maintain the readonly alias as such | 514 // -> maintain the readonly alias as such |
505 fUnion.fFields.fArray = src.fUnion.fFields.fArray; | 515 fUnion.fFields.fArray = src.fUnion.fFields.fArray; |
506 fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity; | 516 fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity; |
507 fFlags = src.fFlags; | 517 if(!hasShortLength()) { |
| 518 fUnion.fFields.fLength = src.fUnion.fFields.fLength; |
| 519 } |
508 break; | 520 break; |
509 } | 521 } |
510 // else if(!fastCopy) fall through to case kWritableAlias | 522 // else if(!fastCopy) fall through to case kWritableAlias |
511 // -> allocate a new buffer and copy the contents | 523 // -> allocate a new buffer and copy the contents |
512 case kWritableAlias: | 524 case kWritableAlias: { |
513 // src is a writable alias; we make a copy of that instead | 525 // src is a writable alias; we make a copy of that instead |
| 526 int32_t srcLength = src.length(); |
514 if(allocate(srcLength)) { | 527 if(allocate(srcLength)) { |
515 uprv_memcpy(getArrayStart(), src.getArrayStart(), srcLength * U_SIZEOF_UCH
AR); | 528 uprv_memcpy(getArrayStart(), src.getArrayStart(), srcLength * U_SIZEOF_UCH
AR); |
| 529 setLength(srcLength); |
516 break; | 530 break; |
517 } | 531 } |
518 // if there is not enough memory, then fall through to setting to bogus | 532 // if there is not enough memory, then fall through to setting to bogus |
| 533 } |
519 default: | 534 default: |
520 // if src is bogus, set ourselves to bogus | 535 // if src is bogus, set ourselves to bogus |
521 // do not call setToBogus() here because fArray and fFlags are not consisten
t here | 536 // do not call setToBogus() here because fArray and flags are not consistent
here |
522 fShortLength = 0; | 537 fUnion.fFields.fLengthAndFlags = kIsBogus; |
523 fUnion.fFields.fArray = 0; | 538 fUnion.fFields.fArray = 0; |
524 fUnion.fFields.fCapacity = 0; | 539 fUnion.fFields.fCapacity = 0; |
525 fFlags = kIsBogus; | |
526 break; | 540 break; |
527 } | 541 } |
528 | 542 |
529 return *this; | 543 return *this; |
530 } | 544 } |
531 | 545 |
| 546 UnicodeString &UnicodeString::moveFrom(UnicodeString &src) U_NOEXCEPT { |
| 547 // No explicit check for self move assignment, consistent with standard librar
y. |
| 548 // Self move assignment causes no crash nor leak but might make the object bog
us. |
| 549 releaseArray(); |
| 550 copyFieldsFrom(src, TRUE); |
| 551 return *this; |
| 552 } |
| 553 |
| 554 // Same as moveFrom() except without memory management. |
| 555 void UnicodeString::copyFieldsFrom(UnicodeString &src, UBool setSrcToBogus) U_NO
EXCEPT { |
| 556 int16_t lengthAndFlags = fUnion.fFields.fLengthAndFlags = src.fUnion.fFields.f
LengthAndFlags; |
| 557 if(lengthAndFlags & kUsingStackBuffer) { |
| 558 // Short string using the stack buffer, copy the contents. |
| 559 // Check for self assignment to prevent "overlap in memcpy" warnings, |
| 560 // although it should be harmless to copy a buffer to itself exactly. |
| 561 if(this != &src) { |
| 562 uprv_memcpy(fUnion.fStackFields.fBuffer, src.fUnion.fStackFields.fBuffer, |
| 563 getShortLength() * U_SIZEOF_UCHAR); |
| 564 } |
| 565 } else { |
| 566 // In all other cases, copy all fields. |
| 567 fUnion.fFields.fArray = src.fUnion.fFields.fArray; |
| 568 fUnion.fFields.fCapacity = src.fUnion.fFields.fCapacity; |
| 569 if(!hasShortLength()) { |
| 570 fUnion.fFields.fLength = src.fUnion.fFields.fLength; |
| 571 } |
| 572 if(setSrcToBogus) { |
| 573 // Set src to bogus without releasing any memory. |
| 574 src.fUnion.fFields.fLengthAndFlags = kIsBogus; |
| 575 src.fUnion.fFields.fArray = NULL; |
| 576 src.fUnion.fFields.fCapacity = 0; |
| 577 } |
| 578 } |
| 579 } |
| 580 |
| 581 void UnicodeString::swap(UnicodeString &other) U_NOEXCEPT { |
| 582 UnicodeString temp; // Empty short string: Known not to need releaseArray(). |
| 583 // Copy fields without resetting source values in between. |
| 584 temp.copyFieldsFrom(*this, FALSE); |
| 585 this->copyFieldsFrom(other, FALSE); |
| 586 other.copyFieldsFrom(temp, FALSE); |
| 587 // Set temp to an empty string so that other's memory is not released twice. |
| 588 temp.fUnion.fFields.fLengthAndFlags = kShortString; |
| 589 } |
| 590 |
532 //======================================== | 591 //======================================== |
533 // Miscellaneous operations | 592 // Miscellaneous operations |
534 //======================================== | 593 //======================================== |
535 | 594 |
536 UnicodeString UnicodeString::unescape() const { | 595 UnicodeString UnicodeString::unescape() const { |
537 UnicodeString result(length(), (UChar32)0, (int32_t)0); // construct with ca
pacity | 596 UnicodeString result(length(), (UChar32)0, (int32_t)0); // construct with ca
pacity |
| 597 if (result.isBogus()) { |
| 598 return result; |
| 599 } |
538 const UChar *array = getBuffer(); | 600 const UChar *array = getBuffer(); |
539 int32_t len = length(); | 601 int32_t len = length(); |
540 int32_t prev = 0; | 602 int32_t prev = 0; |
541 for (int32_t i=0;;) { | 603 for (int32_t i=0;;) { |
542 if (i == len) { | 604 if (i == len) { |
543 result.append(array, prev, len - prev); | 605 result.append(array, prev, len - prev); |
544 break; | 606 break; |
545 } | 607 } |
546 if (array[i++] == 0x5C /*'\\'*/) { | 608 if (array[i++] == 0x5C /*'\\'*/) { |
547 result.append(array, prev, (i - 1) - prev); | 609 result.append(array, prev, (i - 1) - prev); |
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
820 } | 882 } |
821 UErrorCode status = U_ZERO_ERROR; | 883 UErrorCode status = U_ZERO_ERROR; |
822 return u_terminateChars(target, targetCapacity, length, &status); | 884 return u_terminateChars(target, targetCapacity, length, &status); |
823 } | 885 } |
824 | 886 |
825 UnicodeString | 887 UnicodeString |
826 UnicodeString::tempSubString(int32_t start, int32_t len) const { | 888 UnicodeString::tempSubString(int32_t start, int32_t len) const { |
827 pinIndices(start, len); | 889 pinIndices(start, len); |
828 const UChar *array = getBuffer(); // not getArrayStart() to check kIsBogus &
kOpenGetBuffer | 890 const UChar *array = getBuffer(); // not getArrayStart() to check kIsBogus &
kOpenGetBuffer |
829 if(array==NULL) { | 891 if(array==NULL) { |
830 array=fUnion.fStackBuffer; // anything not NULL because that would make an
empty string | 892 array=fUnion.fStackFields.fBuffer; // anything not NULL because that would
make an empty string |
831 len=-2; // bogus result string | 893 len=-2; // bogus result string |
832 } | 894 } |
833 return UnicodeString(FALSE, array + start, len); | 895 return UnicodeString(FALSE, array + start, len); |
834 } | 896 } |
835 | 897 |
836 int32_t | 898 int32_t |
837 UnicodeString::toUTF8(int32_t start, int32_t len, | 899 UnicodeString::toUTF8(int32_t start, int32_t len, |
838 char *target, int32_t capacity) const { | 900 char *target, int32_t capacity) const { |
839 pinIndices(start, len); | 901 pinIndices(start, len); |
840 int32_t length8; | 902 int32_t length8; |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1104 | 1166 |
1105 return *this; | 1167 return *this; |
1106 } | 1168 } |
1107 | 1169 |
1108 | 1170 |
1109 void | 1171 void |
1110 UnicodeString::setToBogus() | 1172 UnicodeString::setToBogus() |
1111 { | 1173 { |
1112 releaseArray(); | 1174 releaseArray(); |
1113 | 1175 |
1114 fShortLength = 0; | 1176 fUnion.fFields.fLengthAndFlags = kIsBogus; |
1115 fUnion.fFields.fArray = 0; | 1177 fUnion.fFields.fArray = 0; |
1116 fUnion.fFields.fCapacity = 0; | 1178 fUnion.fFields.fCapacity = 0; |
1117 fFlags = kIsBogus; | |
1118 } | 1179 } |
1119 | 1180 |
1120 // turn a bogus string into an empty one | 1181 // turn a bogus string into an empty one |
1121 void | 1182 void |
1122 UnicodeString::unBogus() { | 1183 UnicodeString::unBogus() { |
1123 if(fFlags & kIsBogus) { | 1184 if(fUnion.fFields.fLengthAndFlags & kIsBogus) { |
1124 setToEmpty(); | 1185 setToEmpty(); |
1125 } | 1186 } |
1126 } | 1187 } |
1127 | 1188 |
1128 const UChar * | 1189 const UChar * |
1129 UnicodeString::getTerminatedBuffer() { | 1190 UnicodeString::getTerminatedBuffer() { |
1130 if(!isWritable()) { | 1191 if(!isWritable()) { |
1131 return 0; | 1192 return 0; |
1132 } | 1193 } |
1133 UChar *array = getArrayStart(); | 1194 UChar *array = getArrayStart(); |
1134 int32_t len = length(); | 1195 int32_t len = length(); |
1135 if(len < getCapacity()) { | 1196 if(len < getCapacity()) { |
1136 if(fFlags & kBufferIsReadonly) { | 1197 if(fUnion.fFields.fLengthAndFlags & kBufferIsReadonly) { |
1137 // If len<capacity on a read-only alias, then array[len] is | 1198 // If len<capacity on a read-only alias, then array[len] is |
1138 // either the original NUL (if constructed with (TRUE, s, length)) | 1199 // either the original NUL (if constructed with (TRUE, s, length)) |
1139 // or one of the original string contents characters (if later truncated), | 1200 // or one of the original string contents characters (if later truncated), |
1140 // therefore we can assume that array[len] is initialized memory. | 1201 // therefore we can assume that array[len] is initialized memory. |
1141 if(array[len] == 0) { | 1202 if(array[len] == 0) { |
1142 return array; | 1203 return array; |
1143 } | 1204 } |
1144 } else if(((fFlags & kRefCounted) == 0 || refCount() == 1)) { | 1205 } else if(((fUnion.fFields.fLengthAndFlags & kRefCounted) == 0 || refCount()
== 1)) { |
1145 // kRefCounted: Do not write the NUL if the buffer is shared. | 1206 // kRefCounted: Do not write the NUL if the buffer is shared. |
1146 // That is mostly safe, except when the length of one copy was modified | 1207 // That is mostly safe, except when the length of one copy was modified |
1147 // without copy-on-write, e.g., via truncate(newLength) or remove(void). | 1208 // without copy-on-write, e.g., via truncate(newLength) or remove(void). |
1148 // Then the NUL would be written into the middle of another copy's string. | 1209 // Then the NUL would be written into the middle of another copy's string. |
1149 | 1210 |
1150 // Otherwise, the buffer is fully writable and it is anyway safe to write
the NUL. | 1211 // Otherwise, the buffer is fully writable and it is anyway safe to write
the NUL. |
1151 // Do not test if there is a NUL already because it might be uninitialized
memory. | 1212 // Do not test if there is a NUL already because it might be uninitialized
memory. |
1152 // (That would be safe, but tools like valgrind & Purify would complain.) | 1213 // (That would be safe, but tools like valgrind & Purify would complain.) |
1153 array[len] = 0; | 1214 array[len] = 0; |
1154 return array; | 1215 return array; |
1155 } | 1216 } |
1156 } | 1217 } |
1157 if(cloneArrayIfNeeded(len+1)) { | 1218 if(cloneArrayIfNeeded(len+1)) { |
1158 array = getArrayStart(); | 1219 array = getArrayStart(); |
1159 array[len] = 0; | 1220 array[len] = 0; |
1160 return array; | 1221 return array; |
1161 } else { | 1222 } else { |
1162 return NULL; | 1223 return NULL; |
1163 } | 1224 } |
1164 } | 1225 } |
1165 | 1226 |
1166 // setTo() analogous to the readonly-aliasing constructor with the same signatur
e | 1227 // setTo() analogous to the readonly-aliasing constructor with the same signatur
e |
1167 UnicodeString & | 1228 UnicodeString & |
1168 UnicodeString::setTo(UBool isTerminated, | 1229 UnicodeString::setTo(UBool isTerminated, |
1169 const UChar *text, | 1230 const UChar *text, |
1170 int32_t textLength) | 1231 int32_t textLength) |
1171 { | 1232 { |
1172 if(fFlags & kOpenGetBuffer) { | 1233 if(fUnion.fFields.fLengthAndFlags & kOpenGetBuffer) { |
1173 // do not modify a string that has an "open" getBuffer(minCapacity) | 1234 // do not modify a string that has an "open" getBuffer(minCapacity) |
1174 return *this; | 1235 return *this; |
1175 } | 1236 } |
1176 | 1237 |
1177 if(text == NULL) { | 1238 if(text == NULL) { |
1178 // treat as an empty string, do not alias | 1239 // treat as an empty string, do not alias |
1179 releaseArray(); | 1240 releaseArray(); |
1180 setToEmpty(); | 1241 setToEmpty(); |
1181 return *this; | 1242 return *this; |
1182 } | 1243 } |
1183 | 1244 |
1184 if( textLength < -1 || | 1245 if( textLength < -1 || |
1185 (textLength == -1 && !isTerminated) || | 1246 (textLength == -1 && !isTerminated) || |
1186 (textLength >= 0 && isTerminated && text[textLength] != 0) | 1247 (textLength >= 0 && isTerminated && text[textLength] != 0) |
1187 ) { | 1248 ) { |
1188 setToBogus(); | 1249 setToBogus(); |
1189 return *this; | 1250 return *this; |
1190 } | 1251 } |
1191 | 1252 |
1192 releaseArray(); | 1253 releaseArray(); |
1193 | 1254 |
1194 if(textLength == -1) { | 1255 if(textLength == -1) { |
1195 // text is terminated, or else it would have failed the above test | 1256 // text is terminated, or else it would have failed the above test |
1196 textLength = u_strlen(text); | 1257 textLength = u_strlen(text); |
1197 } | 1258 } |
| 1259 fUnion.fFields.fLengthAndFlags = kReadonlyAlias; |
1198 setArray((UChar *)text, textLength, isTerminated ? textLength + 1 : textLength
); | 1260 setArray((UChar *)text, textLength, isTerminated ? textLength + 1 : textLength
); |
1199 | |
1200 fFlags = kReadonlyAlias; | |
1201 return *this; | 1261 return *this; |
1202 } | 1262 } |
1203 | 1263 |
1204 // setTo() analogous to the writable-aliasing constructor with the same signatur
e | 1264 // setTo() analogous to the writable-aliasing constructor with the same signatur
e |
1205 UnicodeString & | 1265 UnicodeString & |
1206 UnicodeString::setTo(UChar *buffer, | 1266 UnicodeString::setTo(UChar *buffer, |
1207 int32_t buffLength, | 1267 int32_t buffLength, |
1208 int32_t buffCapacity) { | 1268 int32_t buffCapacity) { |
1209 if(fFlags & kOpenGetBuffer) { | 1269 if(fUnion.fFields.fLengthAndFlags & kOpenGetBuffer) { |
1210 // do not modify a string that has an "open" getBuffer(minCapacity) | 1270 // do not modify a string that has an "open" getBuffer(minCapacity) |
1211 return *this; | 1271 return *this; |
1212 } | 1272 } |
1213 | 1273 |
1214 if(buffer == NULL) { | 1274 if(buffer == NULL) { |
1215 // treat as an empty string, do not alias | 1275 // treat as an empty string, do not alias |
1216 releaseArray(); | 1276 releaseArray(); |
1217 setToEmpty(); | 1277 setToEmpty(); |
1218 return *this; | 1278 return *this; |
1219 } | 1279 } |
1220 | 1280 |
1221 if(buffLength < -1 || buffCapacity < 0 || buffLength > buffCapacity) { | 1281 if(buffLength < -1 || buffCapacity < 0 || buffLength > buffCapacity) { |
1222 setToBogus(); | 1282 setToBogus(); |
1223 return *this; | 1283 return *this; |
1224 } else if(buffLength == -1) { | 1284 } else if(buffLength == -1) { |
1225 // buffLength = u_strlen(buff); but do not look beyond buffCapacity | 1285 // buffLength = u_strlen(buff); but do not look beyond buffCapacity |
1226 const UChar *p = buffer, *limit = buffer + buffCapacity; | 1286 const UChar *p = buffer, *limit = buffer + buffCapacity; |
1227 while(p != limit && *p != 0) { | 1287 while(p != limit && *p != 0) { |
1228 ++p; | 1288 ++p; |
1229 } | 1289 } |
1230 buffLength = (int32_t)(p - buffer); | 1290 buffLength = (int32_t)(p - buffer); |
1231 } | 1291 } |
1232 | 1292 |
1233 releaseArray(); | 1293 releaseArray(); |
1234 | 1294 |
| 1295 fUnion.fFields.fLengthAndFlags = kWritableAlias; |
1235 setArray(buffer, buffLength, buffCapacity); | 1296 setArray(buffer, buffLength, buffCapacity); |
1236 fFlags = kWritableAlias; | |
1237 return *this; | 1297 return *this; |
1238 } | 1298 } |
1239 | 1299 |
1240 UnicodeString &UnicodeString::setToUTF8(const StringPiece &utf8) { | 1300 UnicodeString &UnicodeString::setToUTF8(const StringPiece &utf8) { |
1241 unBogus(); | 1301 unBogus(); |
1242 int32_t length = utf8.length(); | 1302 int32_t length = utf8.length(); |
1243 int32_t capacity; | 1303 int32_t capacity; |
1244 // The UTF-16 string will be at most as long as the UTF-8 string. | 1304 // The UTF-16 string will be at most as long as the UTF-8 string. |
1245 if(length <= US_STACKBUF_SIZE) { | 1305 if(length <= US_STACKBUF_SIZE) { |
1246 capacity = US_STACKBUF_SIZE; | 1306 capacity = US_STACKBUF_SIZE; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1293 return doReplace(start, _length, buffer, 0, isError ? 0 : count); | 1353 return doReplace(start, _length, buffer, 0, isError ? 0 : count); |
1294 } | 1354 } |
1295 | 1355 |
1296 UnicodeString& | 1356 UnicodeString& |
1297 UnicodeString::append(UChar32 srcChar) { | 1357 UnicodeString::append(UChar32 srcChar) { |
1298 UChar buffer[U16_MAX_LENGTH]; | 1358 UChar buffer[U16_MAX_LENGTH]; |
1299 int32_t _length = 0; | 1359 int32_t _length = 0; |
1300 UBool isError = FALSE; | 1360 UBool isError = FALSE; |
1301 U16_APPEND(buffer, _length, U16_MAX_LENGTH, srcChar, isError); | 1361 U16_APPEND(buffer, _length, U16_MAX_LENGTH, srcChar, isError); |
1302 // We test isError so that the compiler does not complain that we don't. | 1362 // We test isError so that the compiler does not complain that we don't. |
1303 // If isError then _length==0 which turns the doReplace() into a no-op anyway. | 1363 // If isError then _length==0 which turns the doAppend() into a no-op anyway. |
1304 return isError ? *this : doReplace(length(), 0, buffer, 0, _length); | 1364 return isError ? *this : doAppend(buffer, 0, _length); |
1305 } | 1365 } |
1306 | 1366 |
1307 UnicodeString& | 1367 UnicodeString& |
1308 UnicodeString::doReplace( int32_t start, | 1368 UnicodeString::doReplace( int32_t start, |
1309 int32_t length, | 1369 int32_t length, |
1310 const UnicodeString& src, | 1370 const UnicodeString& src, |
1311 int32_t srcStart, | 1371 int32_t srcStart, |
1312 int32_t srcLength) | 1372 int32_t srcLength) |
1313 { | 1373 { |
1314 if(!src.isBogus()) { | 1374 // pin the indices to legal values |
1315 // pin the indices to legal values | 1375 src.pinIndices(srcStart, srcLength); |
1316 src.pinIndices(srcStart, srcLength); | |
1317 | 1376 |
1318 // get the characters from src | 1377 // get the characters from src |
1319 // and replace the range in ourselves with them | 1378 // and replace the range in ourselves with them |
1320 return doReplace(start, length, src.getArrayStart(), srcStart, srcLength); | 1379 return doReplace(start, length, src.getArrayStart(), srcStart, srcLength); |
1321 } else { | |
1322 // remove the range | |
1323 return doReplace(start, length, 0, 0, 0); | |
1324 } | |
1325 } | 1380 } |
1326 | 1381 |
1327 UnicodeString& | 1382 UnicodeString& |
1328 UnicodeString::doReplace(int32_t start, | 1383 UnicodeString::doReplace(int32_t start, |
1329 int32_t length, | 1384 int32_t length, |
1330 const UChar *srcChars, | 1385 const UChar *srcChars, |
1331 int32_t srcStart, | 1386 int32_t srcStart, |
1332 int32_t srcLength) | 1387 int32_t srcLength) |
1333 { | 1388 { |
1334 if(!isWritable()) { | 1389 if(!isWritable()) { |
1335 return *this; | 1390 return *this; |
1336 } | 1391 } |
1337 | 1392 |
1338 int32_t oldLength = this->length(); | 1393 int32_t oldLength = this->length(); |
1339 | 1394 |
1340 // optimize (read-only alias).remove(0, start) and .remove(start, end) | 1395 // optimize (read-only alias).remove(0, start) and .remove(start, end) |
1341 if((fFlags&kBufferIsReadonly) && srcLength == 0) { | 1396 if((fUnion.fFields.fLengthAndFlags&kBufferIsReadonly) && srcLength == 0) { |
1342 if(start == 0) { | 1397 if(start == 0) { |
1343 // remove prefix by adjusting the array pointer | 1398 // remove prefix by adjusting the array pointer |
1344 pinIndex(length); | 1399 pinIndex(length); |
1345 fUnion.fFields.fArray += length; | 1400 fUnion.fFields.fArray += length; |
1346 fUnion.fFields.fCapacity -= length; | 1401 fUnion.fFields.fCapacity -= length; |
1347 setLength(oldLength - length); | 1402 setLength(oldLength - length); |
1348 return *this; | 1403 return *this; |
1349 } else { | 1404 } else { |
1350 pinIndex(start); | 1405 pinIndex(start); |
1351 if(length >= (oldLength - start)) { | 1406 if(length >= (oldLength - start)) { |
1352 // remove suffix by reducing the length (like truncate()) | 1407 // remove suffix by reducing the length (like truncate()) |
1353 setLength(start); | 1408 setLength(start); |
1354 fUnion.fFields.fCapacity = start; // not NUL-terminated any more | 1409 fUnion.fFields.fCapacity = start; // not NUL-terminated any more |
1355 return *this; | 1410 return *this; |
1356 } | 1411 } |
1357 } | 1412 } |
1358 } | 1413 } |
1359 | 1414 |
| 1415 if(start == oldLength) { |
| 1416 return doAppend(srcChars, srcStart, srcLength); |
| 1417 } |
| 1418 |
1360 if(srcChars == 0) { | 1419 if(srcChars == 0) { |
1361 srcStart = srcLength = 0; | 1420 srcStart = srcLength = 0; |
1362 } else if(srcLength < 0) { | 1421 } else if(srcLength < 0) { |
1363 // get the srcLength if necessary | 1422 // get the srcLength if necessary |
1364 srcLength = u_strlen(srcChars + srcStart); | 1423 srcLength = u_strlen(srcChars + srcStart); |
1365 } | 1424 } |
1366 | 1425 |
| 1426 // pin the indices to legal values |
| 1427 pinIndices(start, length); |
| 1428 |
1367 // calculate the size of the string after the replace | 1429 // calculate the size of the string after the replace |
1368 int32_t newLength; | 1430 int32_t newLength = oldLength - length + srcLength; |
1369 | 1431 |
1370 // optimize append() onto a large-enough, owned string | 1432 // cloneArrayIfNeeded(doCopyArray=FALSE) may change fArray but will not copy t
he current contents; |
1371 if(start >= oldLength) { | |
1372 if(srcLength == 0) { | |
1373 return *this; | |
1374 } | |
1375 newLength = oldLength + srcLength; | |
1376 if(newLength <= getCapacity() && isBufferWritable()) { | |
1377 UChar *oldArray = getArrayStart(); | |
1378 // Do not copy characters when | |
1379 // UChar *buffer=str.getAppendBuffer(...); | |
1380 // is followed by | |
1381 // str.append(buffer, length); | |
1382 // or | |
1383 // str.appendString(buffer, length) | |
1384 // or similar. | |
1385 if(srcChars + srcStart != oldArray + start || start > oldLength) { | |
1386 us_arrayCopy(srcChars, srcStart, oldArray, oldLength, srcLength); | |
1387 } | |
1388 setLength(newLength); | |
1389 return *this; | |
1390 } else { | |
1391 // pin the indices to legal values | |
1392 start = oldLength; | |
1393 length = 0; | |
1394 } | |
1395 } else { | |
1396 // pin the indices to legal values | |
1397 pinIndices(start, length); | |
1398 | |
1399 newLength = oldLength - length + srcLength; | |
1400 } | |
1401 | |
1402 // the following may change fArray but will not copy the current contents; | |
1403 // therefore we need to keep the current fArray | 1433 // therefore we need to keep the current fArray |
1404 UChar oldStackBuffer[US_STACKBUF_SIZE]; | 1434 UChar oldStackBuffer[US_STACKBUF_SIZE]; |
1405 UChar *oldArray; | 1435 UChar *oldArray; |
1406 if((fFlags&kUsingStackBuffer) && (newLength > US_STACKBUF_SIZE)) { | 1436 if((fUnion.fFields.fLengthAndFlags&kUsingStackBuffer) && (newLength > US_STACK
BUF_SIZE)) { |
1407 // copy the stack buffer contents because it will be overwritten with | 1437 // copy the stack buffer contents because it will be overwritten with |
1408 // fUnion.fFields values | 1438 // fUnion.fFields values |
1409 u_memcpy(oldStackBuffer, fUnion.fStackBuffer, oldLength); | 1439 u_memcpy(oldStackBuffer, fUnion.fStackFields.fBuffer, oldLength); |
1410 oldArray = oldStackBuffer; | 1440 oldArray = oldStackBuffer; |
1411 } else { | 1441 } else { |
1412 oldArray = getArrayStart(); | 1442 oldArray = getArrayStart(); |
1413 } | 1443 } |
1414 | 1444 |
1415 // clone our array and allocate a bigger array if needed | 1445 // clone our array and allocate a bigger array if needed |
1416 int32_t *bufferToDelete = 0; | 1446 int32_t *bufferToDelete = 0; |
1417 if(!cloneArrayIfNeeded(newLength, newLength + (newLength >> 2) + kGrowSize, | 1447 if(!cloneArrayIfNeeded(newLength, newLength + (newLength >> 2) + kGrowSize, |
1418 FALSE, &bufferToDelete) | 1448 FALSE, &bufferToDelete) |
1419 ) { | 1449 ) { |
(...skipping 23 matching lines...) Expand all Loading... |
1443 | 1473 |
1444 // delayed delete in case srcChars == fArray when we started, and | 1474 // delayed delete in case srcChars == fArray when we started, and |
1445 // to keep oldArray alive for the above operations | 1475 // to keep oldArray alive for the above operations |
1446 if (bufferToDelete) { | 1476 if (bufferToDelete) { |
1447 uprv_free(bufferToDelete); | 1477 uprv_free(bufferToDelete); |
1448 } | 1478 } |
1449 | 1479 |
1450 return *this; | 1480 return *this; |
1451 } | 1481 } |
1452 | 1482 |
| 1483 // Versions of doReplace() only for append() variants. |
| 1484 // doReplace() and doAppend() optimize for different cases. |
| 1485 |
| 1486 UnicodeString& |
| 1487 UnicodeString::doAppend(const UnicodeString& src, int32_t srcStart, int32_t srcL
ength) { |
| 1488 if(srcLength == 0) { |
| 1489 return *this; |
| 1490 } |
| 1491 |
| 1492 // pin the indices to legal values |
| 1493 src.pinIndices(srcStart, srcLength); |
| 1494 return doAppend(src.getArrayStart(), srcStart, srcLength); |
| 1495 } |
| 1496 |
| 1497 UnicodeString& |
| 1498 UnicodeString::doAppend(const UChar *srcChars, int32_t srcStart, int32_t srcLeng
th) { |
| 1499 if(!isWritable() || srcLength == 0 || srcChars == NULL) { |
| 1500 return *this; |
| 1501 } |
| 1502 |
| 1503 if(srcLength < 0) { |
| 1504 // get the srcLength if necessary |
| 1505 if((srcLength = u_strlen(srcChars + srcStart)) == 0) { |
| 1506 return *this; |
| 1507 } |
| 1508 } |
| 1509 |
| 1510 int32_t oldLength = length(); |
| 1511 int32_t newLength = oldLength + srcLength; |
| 1512 // optimize append() onto a large-enough, owned string |
| 1513 if((newLength <= getCapacity() && isBufferWritable()) || |
| 1514 cloneArrayIfNeeded(newLength, newLength + (newLength >> 2) + kGrowSize)) { |
| 1515 UChar *newArray = getArrayStart(); |
| 1516 // Do not copy characters when |
| 1517 // UChar *buffer=str.getAppendBuffer(...); |
| 1518 // is followed by |
| 1519 // str.append(buffer, length); |
| 1520 // or |
| 1521 // str.appendString(buffer, length) |
| 1522 // or similar. |
| 1523 if(srcChars + srcStart != newArray + oldLength) { |
| 1524 us_arrayCopy(srcChars, srcStart, newArray, oldLength, srcLength); |
| 1525 } |
| 1526 setLength(newLength); |
| 1527 } |
| 1528 return *this; |
| 1529 } |
| 1530 |
1453 /** | 1531 /** |
1454 * Replaceable API | 1532 * Replaceable API |
1455 */ | 1533 */ |
1456 void | 1534 void |
1457 UnicodeString::handleReplaceBetween(int32_t start, | 1535 UnicodeString::handleReplaceBetween(int32_t start, |
1458 int32_t limit, | 1536 int32_t limit, |
1459 const UnicodeString& text) { | 1537 const UnicodeString& text) { |
1460 replaceBetween(start, limit, text); | 1538 replaceBetween(start, limit, text); |
1461 } | 1539 } |
1462 | 1540 |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1596 return hashCode; | 1674 return hashCode; |
1597 } | 1675 } |
1598 | 1676 |
1599 //======================================== | 1677 //======================================== |
1600 // External Buffer | 1678 // External Buffer |
1601 //======================================== | 1679 //======================================== |
1602 | 1680 |
1603 UChar * | 1681 UChar * |
1604 UnicodeString::getBuffer(int32_t minCapacity) { | 1682 UnicodeString::getBuffer(int32_t minCapacity) { |
1605 if(minCapacity>=-1 && cloneArrayIfNeeded(minCapacity)) { | 1683 if(minCapacity>=-1 && cloneArrayIfNeeded(minCapacity)) { |
1606 fFlags|=kOpenGetBuffer; | 1684 fUnion.fFields.fLengthAndFlags|=kOpenGetBuffer; |
1607 fShortLength=0; | 1685 setZeroLength(); |
1608 return getArrayStart(); | 1686 return getArrayStart(); |
1609 } else { | 1687 } else { |
1610 return 0; | 1688 return 0; |
1611 } | 1689 } |
1612 } | 1690 } |
1613 | 1691 |
1614 void | 1692 void |
1615 UnicodeString::releaseBuffer(int32_t newLength) { | 1693 UnicodeString::releaseBuffer(int32_t newLength) { |
1616 if(fFlags&kOpenGetBuffer && newLength>=-1) { | 1694 if(fUnion.fFields.fLengthAndFlags&kOpenGetBuffer && newLength>=-1) { |
1617 // set the new fLength | 1695 // set the new fLength |
1618 int32_t capacity=getCapacity(); | 1696 int32_t capacity=getCapacity(); |
1619 if(newLength==-1) { | 1697 if(newLength==-1) { |
1620 // the new length is the string length, capped by fCapacity | 1698 // the new length is the string length, capped by fCapacity |
1621 const UChar *array=getArrayStart(), *p=array, *limit=array+capacity; | 1699 const UChar *array=getArrayStart(), *p=array, *limit=array+capacity; |
1622 while(p<limit && *p!=0) { | 1700 while(p<limit && *p!=0) { |
1623 ++p; | 1701 ++p; |
1624 } | 1702 } |
1625 newLength=(int32_t)(p-array); | 1703 newLength=(int32_t)(p-array); |
1626 } else if(newLength>capacity) { | 1704 } else if(newLength>capacity) { |
1627 newLength=capacity; | 1705 newLength=capacity; |
1628 } | 1706 } |
1629 setLength(newLength); | 1707 setLength(newLength); |
1630 fFlags&=~kOpenGetBuffer; | 1708 fUnion.fFields.fLengthAndFlags&=~kOpenGetBuffer; |
1631 } | 1709 } |
1632 } | 1710 } |
1633 | 1711 |
1634 //======================================== | 1712 //======================================== |
1635 // Miscellaneous | 1713 // Miscellaneous |
1636 //======================================== | 1714 //======================================== |
1637 UBool | 1715 UBool |
1638 UnicodeString::cloneArrayIfNeeded(int32_t newCapacity, | 1716 UnicodeString::cloneArrayIfNeeded(int32_t newCapacity, |
1639 int32_t growCapacity, | 1717 int32_t growCapacity, |
1640 UBool doCopyArray, | 1718 UBool doCopyArray, |
(...skipping 13 matching lines...) Expand all Loading... |
1654 } | 1732 } |
1655 | 1733 |
1656 /* | 1734 /* |
1657 * We need to make a copy of the array if | 1735 * We need to make a copy of the array if |
1658 * the buffer is read-only, or | 1736 * the buffer is read-only, or |
1659 * the buffer is refCounted (shared), and refCount>1, or | 1737 * the buffer is refCounted (shared), and refCount>1, or |
1660 * the buffer is too small. | 1738 * the buffer is too small. |
1661 * Return FALSE if memory could not be allocated. | 1739 * Return FALSE if memory could not be allocated. |
1662 */ | 1740 */ |
1663 if(forceClone || | 1741 if(forceClone || |
1664 fFlags & kBufferIsReadonly || | 1742 fUnion.fFields.fLengthAndFlags & kBufferIsReadonly || |
1665 (fFlags & kRefCounted && refCount() > 1) || | 1743 (fUnion.fFields.fLengthAndFlags & kRefCounted && refCount() > 1) || |
1666 newCapacity > getCapacity() | 1744 newCapacity > getCapacity() |
1667 ) { | 1745 ) { |
1668 // check growCapacity for default value and use of the stack buffer | 1746 // check growCapacity for default value and use of the stack buffer |
1669 if(growCapacity < 0) { | 1747 if(growCapacity < 0) { |
1670 growCapacity = newCapacity; | 1748 growCapacity = newCapacity; |
1671 } else if(newCapacity <= US_STACKBUF_SIZE && growCapacity > US_STACKBUF_SIZE
) { | 1749 } else if(newCapacity <= US_STACKBUF_SIZE && growCapacity > US_STACKBUF_SIZE
) { |
1672 growCapacity = US_STACKBUF_SIZE; | 1750 growCapacity = US_STACKBUF_SIZE; |
1673 } | 1751 } |
1674 | 1752 |
1675 // save old values | 1753 // save old values |
1676 UChar oldStackBuffer[US_STACKBUF_SIZE]; | 1754 UChar oldStackBuffer[US_STACKBUF_SIZE]; |
1677 UChar *oldArray; | 1755 UChar *oldArray; |
1678 uint8_t flags = fFlags; | 1756 int32_t oldLength = length(); |
| 1757 int16_t flags = fUnion.fFields.fLengthAndFlags; |
1679 | 1758 |
1680 if(flags&kUsingStackBuffer) { | 1759 if(flags&kUsingStackBuffer) { |
1681 U_ASSERT(!(flags&kRefCounted)); /* kRefCounted and kUsingStackBuffer are m
utally exclusive */ | 1760 U_ASSERT(!(flags&kRefCounted)); /* kRefCounted and kUsingStackBuffer are m
utally exclusive */ |
1682 if(doCopyArray && growCapacity > US_STACKBUF_SIZE) { | 1761 if(doCopyArray && growCapacity > US_STACKBUF_SIZE) { |
1683 // copy the stack buffer contents because it will be overwritten with | 1762 // copy the stack buffer contents because it will be overwritten with |
1684 // fUnion.fFields values | 1763 // fUnion.fFields values |
1685 us_arrayCopy(fUnion.fStackBuffer, 0, oldStackBuffer, 0, fShortLength); | 1764 us_arrayCopy(fUnion.fStackFields.fBuffer, 0, oldStackBuffer, 0, oldLengt
h); |
1686 oldArray = oldStackBuffer; | 1765 oldArray = oldStackBuffer; |
1687 } else { | 1766 } else { |
1688 oldArray = 0; // no need to copy from stack buffer to itself | 1767 oldArray = NULL; // no need to copy from the stack buffer to itself |
1689 } | 1768 } |
1690 } else { | 1769 } else { |
1691 oldArray = fUnion.fFields.fArray; | 1770 oldArray = fUnion.fFields.fArray; |
1692 U_ASSERT(oldArray!=NULL); /* when stack buffer is not used, oldArray must
have a non-NULL reference */ | 1771 U_ASSERT(oldArray!=NULL); /* when stack buffer is not used, oldArray must
have a non-NULL reference */ |
1693 } | 1772 } |
1694 | 1773 |
1695 // allocate a new array | 1774 // allocate a new array |
1696 if(allocate(growCapacity) || | 1775 if(allocate(growCapacity) || |
1697 (newCapacity < growCapacity && allocate(newCapacity)) | 1776 (newCapacity < growCapacity && allocate(newCapacity)) |
1698 ) { | 1777 ) { |
1699 if(doCopyArray && oldArray != 0) { | 1778 if(doCopyArray) { |
1700 // copy the contents | 1779 // copy the contents |
1701 // do not copy more than what fits - it may be smaller than before | 1780 // do not copy more than what fits - it may be smaller than before |
1702 int32_t minLength = length(); | 1781 int32_t minLength = oldLength; |
1703 newCapacity = getCapacity(); | 1782 newCapacity = getCapacity(); |
1704 if(newCapacity < minLength) { | 1783 if(newCapacity < minLength) { |
1705 minLength = newCapacity; | 1784 minLength = newCapacity; |
1706 setLength(minLength); | |
1707 } | 1785 } |
1708 us_arrayCopy(oldArray, 0, getArrayStart(), 0, minLength); | 1786 if(oldArray != NULL) { |
| 1787 us_arrayCopy(oldArray, 0, getArrayStart(), 0, minLength); |
| 1788 } |
| 1789 setLength(minLength); |
1709 } else { | 1790 } else { |
1710 fShortLength = 0; | 1791 setZeroLength(); |
1711 } | 1792 } |
1712 | 1793 |
1713 // release the old array | 1794 // release the old array |
1714 if(flags & kRefCounted) { | 1795 if(flags & kRefCounted) { |
1715 // the array is refCounted; decrement and release if 0 | 1796 // the array is refCounted; decrement and release if 0 |
1716 u_atomic_int32_t *pRefCount = ((u_atomic_int32_t *)oldArray - 1); | 1797 u_atomic_int32_t *pRefCount = ((u_atomic_int32_t *)oldArray - 1); |
1717 if(umtx_atomic_dec(pRefCount) == 0) { | 1798 if(umtx_atomic_dec(pRefCount) == 0) { |
1718 if(pBufferToDelete == 0) { | 1799 if(pBufferToDelete == 0) { |
1719 // Note: cast to (void *) is needed with MSVC, where u_atomic_int3
2_t | 1800 // Note: cast to (void *) is needed with MSVC, where u_atomic_int3
2_t |
1720 // is defined as volatile. (Volatile has useful non-standard behav
ior | 1801 // is defined as volatile. (Volatile has useful non-standard behav
ior |
1721 // with this compiler.) | 1802 // with this compiler.) |
1722 uprv_free((void *)pRefCount); | 1803 uprv_free((void *)pRefCount); |
1723 } else { | 1804 } else { |
1724 // the caller requested to delete it himself | 1805 // the caller requested to delete it himself |
1725 *pBufferToDelete = (int32_t *)pRefCount; | 1806 *pBufferToDelete = (int32_t *)pRefCount; |
1726 } | 1807 } |
1727 } | 1808 } |
1728 } | 1809 } |
1729 } else { | 1810 } else { |
1730 // not enough memory for growCapacity and not even for the smaller newCapa
city | 1811 // not enough memory for growCapacity and not even for the smaller newCapa
city |
1731 // reset the old values for setToBogus() to release the array | 1812 // reset the old values for setToBogus() to release the array |
1732 if(!(flags&kUsingStackBuffer)) { | 1813 if(!(flags&kUsingStackBuffer)) { |
1733 fUnion.fFields.fArray = oldArray; | 1814 fUnion.fFields.fArray = oldArray; |
1734 } | 1815 } |
1735 fFlags = flags; | 1816 fUnion.fFields.fLengthAndFlags = flags; |
1736 setToBogus(); | 1817 setToBogus(); |
1737 return FALSE; | 1818 return FALSE; |
1738 } | 1819 } |
1739 } | 1820 } |
1740 return TRUE; | 1821 return TRUE; |
1741 } | 1822 } |
1742 | 1823 |
1743 // UnicodeStringAppendable ------------------------------------------------- *** | 1824 // UnicodeStringAppendable ------------------------------------------------- *** |
1744 | 1825 |
1745 UnicodeStringAppendable::~UnicodeStringAppendable() {} | 1826 UnicodeStringAppendable::~UnicodeStringAppendable() {} |
1746 | 1827 |
1747 UBool | 1828 UBool |
1748 UnicodeStringAppendable::appendCodeUnit(UChar c) { | 1829 UnicodeStringAppendable::appendCodeUnit(UChar c) { |
1749 return str.doReplace(str.length(), 0, &c, 0, 1).isWritable(); | 1830 return str.doAppend(&c, 0, 1).isWritable(); |
1750 } | 1831 } |
1751 | 1832 |
1752 UBool | 1833 UBool |
1753 UnicodeStringAppendable::appendCodePoint(UChar32 c) { | 1834 UnicodeStringAppendable::appendCodePoint(UChar32 c) { |
1754 UChar buffer[U16_MAX_LENGTH]; | 1835 UChar buffer[U16_MAX_LENGTH]; |
1755 int32_t cLength = 0; | 1836 int32_t cLength = 0; |
1756 UBool isError = FALSE; | 1837 UBool isError = FALSE; |
1757 U16_APPEND(buffer, cLength, U16_MAX_LENGTH, c, isError); | 1838 U16_APPEND(buffer, cLength, U16_MAX_LENGTH, c, isError); |
1758 return !isError && str.doReplace(str.length(), 0, buffer, 0, cLength).isWritab
le(); | 1839 return !isError && str.doAppend(buffer, 0, cLength).isWritable(); |
1759 } | 1840 } |
1760 | 1841 |
1761 UBool | 1842 UBool |
1762 UnicodeStringAppendable::appendString(const UChar *s, int32_t length) { | 1843 UnicodeStringAppendable::appendString(const UChar *s, int32_t length) { |
1763 return str.doReplace(str.length(), 0, s, 0, length).isWritable(); | 1844 return str.doAppend(s, 0, length).isWritable(); |
1764 } | 1845 } |
1765 | 1846 |
1766 UBool | 1847 UBool |
1767 UnicodeStringAppendable::reserveAppendCapacity(int32_t appendCapacity) { | 1848 UnicodeStringAppendable::reserveAppendCapacity(int32_t appendCapacity) { |
1768 return str.cloneArrayIfNeeded(str.length() + appendCapacity); | 1849 return str.cloneArrayIfNeeded(str.length() + appendCapacity); |
1769 } | 1850 } |
1770 | 1851 |
1771 UChar * | 1852 UChar * |
1772 UnicodeStringAppendable::getAppendBuffer(int32_t minCapacity, | 1853 UnicodeStringAppendable::getAppendBuffer(int32_t minCapacity, |
1773 int32_t desiredCapacityHint, | 1854 int32_t desiredCapacityHint, |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1816 This should never be called. It is defined here to make sure that the | 1897 This should never be called. It is defined here to make sure that the |
1817 virtual vector deleting destructor is defined within unistr.cpp. | 1898 virtual vector deleting destructor is defined within unistr.cpp. |
1818 The vector deleting destructor is already a part of UObject, | 1899 The vector deleting destructor is already a part of UObject, |
1819 but defining it here makes sure that it is included with this object file. | 1900 but defining it here makes sure that it is included with this object file. |
1820 This makes sure that static library dependencies are kept to a minimum. | 1901 This makes sure that static library dependencies are kept to a minimum. |
1821 */ | 1902 */ |
1822 static void uprv_UnicodeStringDummy(void) { | 1903 static void uprv_UnicodeStringDummy(void) { |
1823 delete [] (new UnicodeString[2]); | 1904 delete [] (new UnicodeString[2]); |
1824 } | 1905 } |
1825 #endif | 1906 #endif |
OLD | NEW |