| 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 |