Changeset 35027 in webkit for trunk/JavaScriptCore/kjs/ustring.cpp
- Timestamp:
- Jul 6, 2008, 7:49:29 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/kjs/ustring.cpp
r35016 r35027 1 // -*- c-basic-offset: 2 -*-2 1 /* 3 2 * Copyright (C) 1999-2000 Harri Porten ([email protected]) … … 79 78 COMPILE_ASSERT(sizeof(UChar) == 2, uchar_is_2_bytes) 80 79 81 CString::CString(const char *c) 82 { 83 length = strlen(c); 84 data = new char[length+1]; 85 memcpy(data, c, length + 1); 86 } 87 88 CString::CString(const char *c, size_t len) 89 { 90 length = len; 91 data = new char[len+1]; 92 memcpy(data, c, len); 93 data[len] = 0; 94 } 95 96 CString::CString(const CString &b) 97 { 98 length = b.length; 99 if (b.data) { 100 data = new char[length+1]; 101 memcpy(data, b.data, length + 1); 102 } 103 else 104 data = 0; 80 CString::CString(const char* c) 81 : m_length(strlen(c)) 82 , m_data(new char[m_length + 1]) 83 { 84 memcpy(m_data, c, m_length + 1); 85 } 86 87 CString::CString(const char* c, size_t length) 88 : m_length(length) 89 , m_data(new char[length + 1]) 90 { 91 memcpy(m_data, c, m_length); 92 m_data[m_length] = 0; 93 } 94 95 CString::CString(const CString& b) 96 { 97 m_length = b.m_length; 98 if (b.m_data) { 99 m_data = new char[m_length + 1]; 100 memcpy(m_data, b.m_data, m_length + 1); 101 } else 102 m_data = 0; 105 103 } 106 104 107 105 CString::~CString() 108 106 { 109 delete []data;110 } 111 112 CString CString::adopt(char* c, size_t len )107 delete [] m_data; 108 } 109 110 CString CString::adopt(char* c, size_t length) 113 111 { 114 112 CString s; 115 s.data = c; 116 s.length = len; 117 113 s.m_data = c; 114 s.m_length = length; 118 115 return s; 119 116 } 120 117 121 CString &CString::append(const CString &t) 122 { 123 char *n; 124 n = new char[length+t.length+1]; 125 if (length) 126 memcpy(n, data, length); 127 if (t.length) 128 memcpy(n+length, t.data, t.length); 129 length += t.length; 130 n[length] = 0; 131 132 delete [] data; 133 data = n; 134 135 return *this; 136 } 137 138 CString &CString::operator=(const char *c) 139 { 140 if (data) 141 delete [] data; 142 length = strlen(c); 143 data = new char[length+1]; 144 memcpy(data, c, length + 1); 145 146 return *this; 147 } 148 149 CString &CString::operator=(const CString &str) 150 { 151 if (this == &str) 118 CString& CString::append(const CString& t) 119 { 120 char* n; 121 n = new char[m_length + t.m_length + 1]; 122 if (m_length) 123 memcpy(n, m_data, m_length); 124 if (t.m_length) 125 memcpy(n + m_length, t.m_data, t.m_length); 126 m_length += t.m_length; 127 n[m_length] = 0; 128 129 delete [] m_data; 130 m_data = n; 131 152 132 return *this; 153 154 if (data) 155 delete [] data; 156 length = str.length; 157 if (str.data) { 158 data = new char[length + 1]; 159 memcpy(data, str.data, length + 1); 160 } 161 else 162 data = 0; 163 164 return *this; 133 } 134 135 CString& CString::operator=(const char* c) 136 { 137 if (m_data) 138 delete [] m_data; 139 m_length = strlen(c); 140 m_data = new char[m_length + 1]; 141 memcpy(m_data, c, m_length + 1); 142 143 return *this; 144 } 145 146 CString& CString::operator=(const CString& str) 147 { 148 if (this == &str) 149 return *this; 150 151 if (m_data) 152 delete [] m_data; 153 m_length = str.m_length; 154 if (str.m_data) { 155 m_data = new char[m_length + 1]; 156 memcpy(m_data, str.m_data, m_length + 1); 157 } else 158 m_data = 0; 159 160 return *this; 165 161 } 166 162 167 163 bool operator==(const CString& c1, const CString& c2) 168 164 { 169 size_t len = c1.size(); 170 return len == c2.size() && (len == 0 || memcmp(c1.c_str(), c2.c_str(), len) == 0); 171 } 172 173 // These static strings are immutable, except for rc, whose initial value is chosen to reduce the possibility of it becoming zero due to ref/deref not being thread-safe. 165 size_t len = c1.size(); 166 return len == c2.size() && (len == 0 || memcmp(c1.c_str(), c2.c_str(), len) == 0); 167 } 168 169 // These static strings are immutable, except for rc, whose initial value is chosen to 170 // reduce the possibility of it becoming zero due to ref/deref not being thread-safe. 174 171 static UChar sharedEmptyChar; 175 172 UString::Rep UString::Rep::null = { 0, 0, INT_MAX / 2, 0, 0, &UString::Rep::null, true, 0, 0, 0, 0, 0, 0 }; … … 178 175 static char* statBuffer = 0; // Only used for debugging via UString::ascii(). 179 176 180 PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar *d, int l)181 { 182 int sizeInBytes = l * sizeof(UChar);183 UChar *copyD = static_cast<UChar*>(fastMalloc(sizeInBytes));184 memcpy(copyD, d, sizeInBytes);185 186 return create(copyD, l);187 } 188 189 PassRefPtr<UString::Rep> UString::Rep::create(UChar *d, int l)190 { 191 Rep* r = new Rep;192 r->offset = 0;193 r->len = l;194 r->rc = 1;195 r->_hash = 0;196 r->identifierTable = 0;197 r->baseString = r;198 r->isStatic = false;199 r->reportedCost = 0;200 r->buf = d;201 r->usedCapacity = l;202 r->capacity = l;203 r->usedPreCapacity = 0;204 r->preCapacity = 0;205 206 // steal the single reference this Rep was created with207 return adoptRef(r);177 PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar* d, int l) 178 { 179 int sizeInBytes = l * sizeof(UChar); 180 UChar* copyD = static_cast<UChar*>(fastMalloc(sizeInBytes)); 181 memcpy(copyD, d, sizeInBytes); 182 183 return create(copyD, l); 184 } 185 186 PassRefPtr<UString::Rep> UString::Rep::create(UChar* d, int l) 187 { 188 Rep* r = new Rep; 189 r->offset = 0; 190 r->len = l; 191 r->rc = 1; 192 r->_hash = 0; 193 r->identifierTable = 0; 194 r->baseString = r; 195 r->isStatic = false; 196 r->reportedCost = 0; 197 r->buf = d; 198 r->usedCapacity = l; 199 r->capacity = l; 200 r->usedPreCapacity = 0; 201 r->preCapacity = 0; 202 203 // steal the single reference this Rep was created with 204 return adoptRef(r); 208 205 } 209 206 210 207 PassRefPtr<UString::Rep> UString::Rep::create(PassRefPtr<Rep> base, int offset, int length) 211 208 { 212 ASSERT(base);213 214 int baseOffset = base->offset;215 216 base = base->baseString;217 218 ASSERT(-(offset + baseOffset) <= base->usedPreCapacity);219 ASSERT(offset + baseOffset + length <= base->usedCapacity);220 221 Rep *r = new Rep;222 r->offset = baseOffset + offset;223 r->len = length;224 r->rc = 1;225 r->_hash = 0;226 r->identifierTable = 0;227 r->baseString = base.releaseRef();228 r->isStatic = false;229 r->reportedCost = 0;230 r->buf = 0;231 r->usedCapacity = 0;232 r->capacity = 0;233 r->usedPreCapacity = 0;234 r->preCapacity = 0;235 236 // steal the single reference this Rep was created with237 return adoptRef(r);209 ASSERT(base); 210 211 int baseOffset = base->offset; 212 213 base = base->baseString; 214 215 ASSERT(-(offset + baseOffset) <= base->usedPreCapacity); 216 ASSERT(offset + baseOffset + length <= base->usedCapacity); 217 218 Rep* r = new Rep; 219 r->offset = baseOffset + offset; 220 r->len = length; 221 r->rc = 1; 222 r->_hash = 0; 223 r->identifierTable = 0; 224 r->baseString = base.releaseRef(); 225 r->isStatic = false; 226 r->reportedCost = 0; 227 r->buf = 0; 228 r->usedCapacity = 0; 229 r->capacity = 0; 230 r->usedPreCapacity = 0; 231 r->preCapacity = 0; 232 233 // steal the single reference this Rep was created with 234 return adoptRef(r); 238 235 } 239 236 … … 254 251 void UString::Rep::destroy() 255 252 { 256 // Static null and empty strings can never be destroyed, but we cannot rely on reference counting, because ref/deref are not thread-safe. 257 if (!isStatic) { 258 if (identifierTable) 259 Identifier::remove(this); 260 if (baseString == this) 261 fastFree(buf); 262 else 263 baseString->deref(); 264 265 delete this; 266 } 253 // Static null and empty strings can never be destroyed, but we cannot rely on 254 // reference counting, because ref/deref are not thread-safe. 255 if (!isStatic) { 256 if (identifierTable) 257 Identifier::remove(this); 258 if (baseString == this) 259 fastFree(buf); 260 else 261 baseString->deref(); 262 263 delete this; 264 } 267 265 } 268 266 … … 273 271 // Paul Hsieh's SuperFastHash 274 272 // http://www.azillionmonkeys.com/qed/hash.html 275 unsigned UString::Rep::computeHash(const UChar *s, int len)276 { 277 unsigned l = len;278 uint32_t hash = PHI;279 uint32_t tmp;280 281 int rem = l & 1;282 l >>= 1;283 284 // Main loop285 for (; l > 0; l--) {286 hash += s[0];287 tmp = (s[1] << 11) ^ hash;288 hash = (hash << 16) ^ tmp;289 s += 2;290 hash += hash >> 11;291 }292 293 // Handle end case294 if (rem) {295 hash += s[0];296 hash ^= hash << 11;297 hash += hash >> 17;298 }299 300 // Force "avalanching" of final 127 bits301 hash ^= hash << 3;302 hash += hash >> 5;303 hash ^= hash << 2;304 hash += hash >> 15;305 hash ^= hash << 10;306 307 // this avoids ever returning a hash code of 0, since that is used to308 // signal "hash not computed yet", using a value that is likely to be309 // effectively the same as 0 when the low bits are masked310 if (hash == 0)311 hash = 0x80000000;312 313 return hash;273 unsigned UString::Rep::computeHash(const UChar* s, int len) 274 { 275 unsigned l = len; 276 uint32_t hash = PHI; 277 uint32_t tmp; 278 279 int rem = l & 1; 280 l >>= 1; 281 282 // Main loop 283 for (; l > 0; l--) { 284 hash += s[0]; 285 tmp = (s[1] << 11) ^ hash; 286 hash = (hash << 16) ^ tmp; 287 s += 2; 288 hash += hash >> 11; 289 } 290 291 // Handle end case 292 if (rem) { 293 hash += s[0]; 294 hash ^= hash << 11; 295 hash += hash >> 17; 296 } 297 298 // Force "avalanching" of final 127 bits 299 hash ^= hash << 3; 300 hash += hash >> 5; 301 hash ^= hash << 2; 302 hash += hash >> 15; 303 hash ^= hash << 10; 304 305 // this avoids ever returning a hash code of 0, since that is used to 306 // signal "hash not computed yet", using a value that is likely to be 307 // effectively the same as 0 when the low bits are masked 308 if (hash == 0) 309 hash = 0x80000000; 310 311 return hash; 314 312 } 315 313 316 314 // Paul Hsieh's SuperFastHash 317 315 // http://www.azillionmonkeys.com/qed/hash.html 318 unsigned UString::Rep::computeHash(const char *s)319 { 320 // This hash is designed to work on 16-bit chunks at a time. But since the normal case321 // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they322 // were 16-bit chunks, which should give matching results323 324 uint32_t hash = PHI;325 uint32_t tmp;326 size_t l = strlen(s);327 328 size_t rem = l & 1;329 l >>= 1;330 331 // Main loop332 for (; l > 0; l--) {333 hash += (unsigned char)s[0];334 tmp = ((unsigned char)s[1]<< 11) ^ hash;335 hash = (hash << 16) ^ tmp;336 s += 2;337 hash += hash >> 11;338 }339 340 // Handle end case341 if (rem) {342 hash += (unsigned char)s[0];343 hash ^= hash << 11;344 hash += hash >> 17;345 }346 347 // Force "avalanching" of final 127 bits348 hash ^= hash << 3;349 hash += hash >> 5;350 hash ^= hash << 2;351 hash += hash >> 15;352 hash ^= hash << 10;353 354 // this avoids ever returning a hash code of 0, since that is used to355 // signal "hash not computed yet", using a value that is likely to be356 // effectively the same as 0 when the low bits are masked357 if (hash == 0)358 hash = 0x80000000;359 360 return hash;316 unsigned UString::Rep::computeHash(const char* s) 317 { 318 // This hash is designed to work on 16-bit chunks at a time. But since the normal case 319 // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they 320 // were 16-bit chunks, which should give matching results 321 322 uint32_t hash = PHI; 323 uint32_t tmp; 324 size_t l = strlen(s); 325 326 size_t rem = l & 1; 327 l >>= 1; 328 329 // Main loop 330 for (; l > 0; l--) { 331 hash += static_cast<unsigned char>(s[0]); 332 tmp = (static_cast<unsigned char>(s[1]) << 11) ^ hash; 333 hash = (hash << 16) ^ tmp; 334 s += 2; 335 hash += hash >> 11; 336 } 337 338 // Handle end case 339 if (rem) { 340 hash += static_cast<unsigned char>(s[0]); 341 hash ^= hash << 11; 342 hash += hash >> 17; 343 } 344 345 // Force "avalanching" of final 127 bits 346 hash ^= hash << 3; 347 hash += hash >> 5; 348 hash ^= hash << 2; 349 hash += hash >> 15; 350 hash ^= hash << 10; 351 352 // this avoids ever returning a hash code of 0, since that is used to 353 // signal "hash not computed yet", using a value that is likely to be 354 // effectively the same as 0 when the low bits are masked 355 if (hash == 0) 356 hash = 0x80000000; 357 358 return hash; 361 359 } 362 360 … … 379 377 inline int UString::usedCapacity() const 380 378 { 381 return m_rep->baseString->usedCapacity;379 return m_rep->baseString->usedCapacity; 382 380 } 383 381 384 382 inline int UString::usedPreCapacity() const 385 383 { 386 return m_rep->baseString->usedPreCapacity;384 return m_rep->baseString->usedPreCapacity; 387 385 } 388 386 389 387 void UString::expandCapacity(int requiredLength) 390 388 { 391 Rep* r = m_rep->baseString; 392 393 if (requiredLength > r->capacity) { 394 size_t newCapacity = expandedSize(requiredLength, r->preCapacity); 395 UChar* oldBuf = r->buf; 396 r->buf = reallocChars(r->buf, newCapacity); 397 if (!r->buf) { 398 r->buf = oldBuf; 389 Rep* r = m_rep->baseString; 390 391 if (requiredLength > r->capacity) { 392 size_t newCapacity = expandedSize(requiredLength, r->preCapacity); 393 UChar* oldBuf = r->buf; 394 r->buf = reallocChars(r->buf, newCapacity); 395 if (!r->buf) { 396 r->buf = oldBuf; 397 m_rep = &Rep::null; 398 return; 399 } 400 r->capacity = newCapacity - r->preCapacity; 401 } 402 if (requiredLength > r->usedCapacity) 403 r->usedCapacity = requiredLength; 404 } 405 406 void UString::expandPreCapacity(int requiredPreCap) 407 { 408 Rep* r = m_rep->baseString; 409 410 if (requiredPreCap > r->preCapacity) { 411 size_t newCapacity = expandedSize(requiredPreCap, r->capacity); 412 int delta = newCapacity - r->capacity - r->preCapacity; 413 414 UChar* newBuf = allocChars(newCapacity); 415 if (!newBuf) { 416 m_rep = &Rep::null; 417 return; 418 } 419 memcpy(newBuf + delta, r->buf, (r->capacity + r->preCapacity) * sizeof(UChar)); 420 fastFree(r->buf); 421 r->buf = newBuf; 422 423 r->preCapacity = newCapacity - r->capacity; 424 } 425 if (requiredPreCap > r->usedPreCapacity) 426 r->usedPreCapacity = requiredPreCap; 427 } 428 429 UString::UString(const char* c) 430 { 431 if (!c) { 399 432 m_rep = &Rep::null; 400 433 return; 401 434 } 402 r->capacity = newCapacity - r->preCapacity; 403 } 404 if (requiredLength > r->usedCapacity) { 405 r->usedCapacity = requiredLength; 406 } 407 } 408 409 void UString::expandPreCapacity(int requiredPreCap) 410 { 411 Rep* r = m_rep->baseString; 412 413 if (requiredPreCap > r->preCapacity) { 414 size_t newCapacity = expandedSize(requiredPreCap, r->capacity); 415 int delta = newCapacity - r->capacity - r->preCapacity; 416 417 UChar* newBuf = allocChars(newCapacity); 418 if (!newBuf) { 435 436 if (!c[0]) { 437 m_rep = &Rep::empty; 438 return; 439 } 440 441 size_t length = strlen(c); 442 UChar* d = allocChars(length); 443 if (!d) 419 444 m_rep = &Rep::null; 420 return; 421 } 422 memcpy(newBuf + delta, r->buf, (r->capacity + r->preCapacity) * sizeof(UChar)); 423 fastFree(r->buf); 424 r->buf = newBuf; 425 426 r->preCapacity = newCapacity - r->capacity; 427 } 428 if (requiredPreCap > r->usedPreCapacity) { 429 r->usedPreCapacity = requiredPreCap; 430 } 431 } 432 433 UString::UString(const char *c) 434 { 435 if (!c) { 436 m_rep = &Rep::null; 437 return; 438 } 439 440 if (!c[0]) { 441 m_rep = &Rep::empty; 442 return; 443 } 444 445 size_t length = strlen(c); 446 UChar *d = allocChars(length); 447 if (!d) 448 m_rep = &Rep::null; 449 else { 450 for (size_t i = 0; i < length; i++) 451 d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend 452 m_rep = Rep::create(d, static_cast<int>(length)); 453 } 454 } 455 456 UString::UString(const UChar *c, int length) 457 { 458 if (length == 0) 459 m_rep = &Rep::empty; 460 else 461 m_rep = Rep::createCopying(c, length); 462 } 463 464 UString::UString(UChar *c, int length, bool copy) 465 { 466 if (length == 0) 467 m_rep = &Rep::empty; 468 else if (copy) 469 m_rep = Rep::createCopying(c, length); 470 else 471 m_rep = Rep::create(c, length); 445 else { 446 for (size_t i = 0; i < length; i++) 447 d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend 448 m_rep = Rep::create(d, static_cast<int>(length)); 449 } 450 } 451 452 UString::UString(const UChar* c, int length) 453 { 454 if (length == 0) 455 m_rep = &Rep::empty; 456 else 457 m_rep = Rep::createCopying(c, length); 458 } 459 460 UString::UString(UChar* c, int length, bool copy) 461 { 462 if (length == 0) 463 m_rep = &Rep::empty; 464 else if (copy) 465 m_rep = Rep::createCopying(c, length); 466 else 467 m_rep = Rep::create(c, length); 472 468 } 473 469 … … 481 477 482 478 483 UString::UString(const UString &a, const UString &b) 484 { 485 int aSize = a.size(); 486 int aOffset = a.m_rep->offset; 487 int bSize = b.size(); 488 int bOffset = b.m_rep->offset; 489 int length = aSize + bSize; 490 491 // possible cases: 492 493 if (aSize == 0) { 494 // a is empty 495 m_rep = b.m_rep; 496 } else if (bSize == 0) { 497 // b is empty 498 m_rep = a.m_rep; 499 } else if (aOffset + aSize == a.usedCapacity() && aSize >= minShareSize && 4 * aSize >= bSize && 500 (-bOffset != b.usedPreCapacity() || aSize >= bSize)) { 501 // - a reaches the end of its buffer so it qualifies for shared append 502 // - also, it's at least a quarter the length of b - appending to a much shorter 503 // string does more harm than good 504 // - however, if b qualifies for prepend and is longer than a, we'd rather prepend 505 UString x(a); 506 x.expandCapacity(aOffset + length); 507 if (a.data() && x.data()) { 508 memcpy(const_cast<UChar *>(a.data() + aSize), b.data(), bSize * sizeof(UChar)); 509 m_rep = Rep::create(a.m_rep, 0, length); 510 } else 511 m_rep = &Rep::null; 512 } else if (-bOffset == b.usedPreCapacity() && bSize >= minShareSize && 4 * bSize >= aSize) { 513 // - b reaches the beginning of its buffer so it qualifies for shared prepend 514 // - also, it's at least a quarter the length of a - prepending to a much shorter 515 // string does more harm than good 516 UString y(b); 517 y.expandPreCapacity(-bOffset + aSize); 518 if (b.data() && y.data()) { 519 memcpy(const_cast<UChar *>(b.data() - aSize), a.data(), aSize * sizeof(UChar)); 520 m_rep = Rep::create(b.m_rep, -aSize, length); 521 } else 522 m_rep = &Rep::null; 523 } else { 524 // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string 525 size_t newCapacity = expandedSize(length, 0); 526 UChar* d = allocChars(newCapacity); 527 if (!d) 528 m_rep = &Rep::null; 479 UString::UString(const UString& a, const UString& b) 480 { 481 int aSize = a.size(); 482 int aOffset = a.m_rep->offset; 483 int bSize = b.size(); 484 int bOffset = b.m_rep->offset; 485 int length = aSize + bSize; 486 487 // possible cases: 488 489 if (aSize == 0) { 490 // a is empty 491 m_rep = b.m_rep; 492 } else if (bSize == 0) { 493 // b is empty 494 m_rep = a.m_rep; 495 } else if (aOffset + aSize == a.usedCapacity() && aSize >= minShareSize && 4 * aSize >= bSize && 496 (-bOffset != b.usedPreCapacity() || aSize >= bSize)) { 497 // - a reaches the end of its buffer so it qualifies for shared append 498 // - also, it's at least a quarter the length of b - appending to a much shorter 499 // string does more harm than good 500 // - however, if b qualifies for prepend and is longer than a, we'd rather prepend 501 UString x(a); 502 x.expandCapacity(aOffset + length); 503 if (a.data() && x.data()) { 504 memcpy(const_cast<UChar*>(a.data() + aSize), b.data(), bSize * sizeof(UChar)); 505 m_rep = Rep::create(a.m_rep, 0, length); 506 } else 507 m_rep = &Rep::null; 508 } else if (-bOffset == b.usedPreCapacity() && bSize >= minShareSize && 4 * bSize >= aSize) { 509 // - b reaches the beginning of its buffer so it qualifies for shared prepend 510 // - also, it's at least a quarter the length of a - prepending to a much shorter 511 // string does more harm than good 512 UString y(b); 513 y.expandPreCapacity(-bOffset + aSize); 514 if (b.data() && y.data()) { 515 memcpy(const_cast<UChar *>(b.data() - aSize), a.data(), aSize * sizeof(UChar)); 516 m_rep = Rep::create(b.m_rep, -aSize, length); 517 } else 518 m_rep = &Rep::null; 519 } else { 520 // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string 521 size_t newCapacity = expandedSize(length, 0); 522 UChar* d = allocChars(newCapacity); 523 if (!d) 524 m_rep = &Rep::null; 525 else { 526 memcpy(d, a.data(), aSize * sizeof(UChar)); 527 memcpy(d + aSize, b.data(), bSize * sizeof(UChar)); 528 m_rep = Rep::create(d, length); 529 m_rep->capacity = newCapacity; 530 } 531 } 532 } 533 534 const UString& UString::null() 535 { 536 static UString* n = new UString; // Should be called from main thread at least once to be safely initialized. 537 return *n; 538 } 539 540 UString UString::from(int i) 541 { 542 UChar buf[1 + sizeof(i) * 3]; 543 UChar* end = buf + sizeof(buf) / sizeof(UChar); 544 UChar* p = end; 545 546 if (i == 0) 547 *--p = '0'; 548 else if (i == INT_MIN) { 549 char minBuf[1 + sizeof(i) * 3]; 550 sprintf(minBuf, "%d", INT_MIN); 551 return UString(minBuf); 552 } else { 553 bool negative = false; 554 if (i < 0) { 555 negative = true; 556 i = -i; 557 } 558 while (i) { 559 *--p = static_cast<unsigned short>((i % 10) + '0'); 560 i /= 10; 561 } 562 if (negative) 563 *--p = '-'; 564 } 565 566 return UString(p, static_cast<int>(end - p)); 567 } 568 569 UString UString::from(unsigned int u) 570 { 571 UChar buf[sizeof(u) * 3]; 572 UChar* end = buf + sizeof(buf) / sizeof(UChar); 573 UChar* p = end; 574 575 if (u == 0) 576 *--p = '0'; 529 577 else { 530 memcpy(d, a.data(), aSize * sizeof(UChar)); 531 memcpy(d + aSize, b.data(), bSize * sizeof(UChar)); 532 m_rep = Rep::create(d, length); 533 m_rep->capacity = newCapacity; 534 } 535 } 536 } 537 538 const UString& UString::null() 539 { 540 static UString* n = new UString; // Should be called from main thread at least once to be safely initialized. 541 return *n; 542 } 543 544 UString UString::from(int i) 545 { 546 UChar buf[1 + sizeof(i) * 3]; 547 UChar *end = buf + sizeof(buf) / sizeof(UChar); 548 UChar *p = end; 578 while (u) { 579 *--p = static_cast<unsigned short>((u % 10) + '0'); 580 u /= 10; 581 } 582 } 583 584 return UString(p, static_cast<int>(end - p)); 585 } 586 587 UString UString::from(long l) 588 { 589 UChar buf[1 + sizeof(l) * 3]; 590 UChar* end = buf + sizeof(buf) / sizeof(UChar); 591 UChar* p = end; 592 593 if (l == 0) 594 *--p = '0'; 595 else if (l == LONG_MIN) { 596 char minBuf[1 + sizeof(l) * 3]; 597 sprintf(minBuf, "%ld", LONG_MIN); 598 return UString(minBuf); 599 } else { 600 bool negative = false; 601 if (l < 0) { 602 negative = true; 603 l = -l; 604 } 605 while (l) { 606 *--p = static_cast<unsigned short>((l % 10) + '0'); 607 l /= 10; 608 } 609 if (negative) 610 *--p = '-'; 611 } 612 613 return UString(p, static_cast<int>(end - p)); 614 } 615 616 UString UString::from(double d) 617 { 618 // avoid ever printing -NaN, in JS conceptually there is only one NaN value 619 if (isnan(d)) 620 return "NaN"; 621 622 char buf[80]; 623 int decimalPoint; 624 int sign; 625 626 char* result = dtoa(d, 0, &decimalPoint, &sign, NULL); 627 int length = static_cast<int>(strlen(result)); 549 628 550 if (i == 0) { 551 *--p = '0'; 552 } else if (i == INT_MIN) { 553 char minBuf[1 + sizeof(i) * 3]; 554 sprintf(minBuf, "%d", INT_MIN); 555 return UString(minBuf); 556 } else { 557 bool negative = false; 558 if (i < 0) { 559 negative = true; 560 i = -i; 561 } 562 while (i) { 563 *--p = (unsigned short)((i % 10) + '0'); 564 i /= 10; 565 } 566 if (negative) { 567 *--p = '-'; 568 } 569 } 629 int i = 0; 630 if (sign) 631 buf[i++] = '-'; 570 632 571 return UString(p, static_cast<int>(end - p)); 572 } 573 574 UString UString::from(unsigned int u) 575 { 576 UChar buf[sizeof(u) * 3]; 577 UChar *end = buf + sizeof(buf) / sizeof(UChar); 578 UChar *p = end; 579 580 if (u == 0) { 581 *--p = '0'; 582 } else { 583 while (u) { 584 *--p = (unsigned short)((u % 10) + '0'); 585 u /= 10; 586 } 587 } 588 589 return UString(p, static_cast<int>(end - p)); 590 } 591 592 UString UString::from(long l) 593 { 594 UChar buf[1 + sizeof(l) * 3]; 595 UChar *end = buf + sizeof(buf) / sizeof(UChar); 596 UChar *p = end; 597 598 if (l == 0) { 599 *--p = '0'; 600 } else if (l == LONG_MIN) { 601 char minBuf[1 + sizeof(l) * 3]; 602 sprintf(minBuf, "%ld", LONG_MIN); 603 return UString(minBuf); 604 } else { 605 bool negative = false; 606 if (l < 0) { 607 negative = true; 608 l = -l; 609 } 610 while (l) { 611 *--p = (unsigned short)((l % 10) + '0'); 612 l /= 10; 613 } 614 if (negative) { 615 *--p = '-'; 616 } 617 } 618 619 return UString(p, static_cast<int>(end - p)); 620 } 621 622 UString UString::from(double d) 623 { 624 // avoid ever printing -NaN, in JS conceptually there is only one NaN value 625 if (isnan(d)) 626 return "NaN"; 627 628 char buf[80]; 629 int decimalPoint; 630 int sign; 631 632 char *result = dtoa(d, 0, &decimalPoint, &sign, NULL); 633 int length = static_cast<int>(strlen(result)); 634 635 int i = 0; 636 if (sign) { 637 buf[i++] = '-'; 638 } 639 640 if (decimalPoint <= 0 && decimalPoint > -6) { 641 buf[i++] = '0'; 642 buf[i++] = '.'; 643 for (int j = decimalPoint; j < 0; j++) { 644 buf[i++] = '0'; 645 } 646 strcpy(buf + i, result); 647 } else if (decimalPoint <= 21 && decimalPoint > 0) { 648 if (length <= decimalPoint) { 649 strcpy(buf + i, result); 650 i += length; 651 for (int j = 0; j < decimalPoint - length; j++) { 633 if (decimalPoint <= 0 && decimalPoint > -6) { 652 634 buf[i++] = '0'; 653 } 654 buf[i] = '\0'; 635 buf[i++] = '.'; 636 for (int j = decimalPoint; j < 0; j++) 637 buf[i++] = '0'; 638 strcpy(buf + i, result); 639 } else if (decimalPoint <= 21 && decimalPoint > 0) { 640 if (length <= decimalPoint) { 641 strcpy(buf + i, result); 642 i += length; 643 for (int j = 0; j < decimalPoint - length; j++) 644 buf[i++] = '0'; 645 buf[i] = '\0'; 646 } else { 647 strncpy(buf + i, result, decimalPoint); 648 i += decimalPoint; 649 buf[i++] = '.'; 650 strcpy(buf + i, result + decimalPoint); 651 } 652 } else if (result[0] < '0' || result[0] > '9') 653 strcpy(buf + i, result); 654 else { 655 buf[i++] = result[0]; 656 if (length > 1) { 657 buf[i++] = '.'; 658 strcpy(buf + i, result + 1); 659 i += length - 1; 660 } 661 662 buf[i++] = 'e'; 663 buf[i++] = (decimalPoint >= 0) ? '+' : '-'; 664 // decimalPoint can't be more than 3 digits decimal given the 665 // nature of float representation 666 int exponential = decimalPoint - 1; 667 if (exponential < 0) 668 exponential = -exponential; 669 if (exponential >= 100) 670 buf[i++] = static_cast<char>('0' + exponential / 100); 671 if (exponential >= 10) 672 buf[i++] = static_cast<char>('0' + (exponential % 100) / 10); 673 buf[i++] = static_cast<char>('0' + exponential % 10); 674 buf[i++] = '\0'; 675 } 676 677 freedtoa(result); 678 679 return UString(buf); 680 } 681 682 UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const 683 { 684 if (rangeCount == 1 && separatorCount == 0) { 685 int thisSize = size(); 686 int position = substringRanges[0].position; 687 int length = substringRanges[0].length; 688 if (position <= 0 && length >= thisSize) 689 return *this; 690 return UString::Rep::create(m_rep, max(0, position), min(thisSize, length)); 691 } 692 693 int totalLength = 0; 694 for (int i = 0; i < rangeCount; i++) 695 totalLength += substringRanges[i].length; 696 for (int i = 0; i < separatorCount; i++) 697 totalLength += separators[i].size(); 698 699 if (totalLength == 0) 700 return ""; 701 702 UChar* buffer = allocChars(totalLength); 703 if (!buffer) 704 return null(); 705 706 int maxCount = max(rangeCount, separatorCount); 707 int bufferPos = 0; 708 for (int i = 0; i < maxCount; i++) { 709 if (i < rangeCount) { 710 memcpy(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length * sizeof(UChar)); 711 bufferPos += substringRanges[i].length; 712 } 713 if (i < separatorCount) { 714 memcpy(buffer + bufferPos, separators[i].data(), separators[i].size() * sizeof(UChar)); 715 bufferPos += separators[i].size(); 716 } 717 } 718 719 return UString::Rep::create(buffer, totalLength); 720 } 721 722 UString& UString::append(const UString &t) 723 { 724 int thisSize = size(); 725 int thisOffset = m_rep->offset; 726 int tSize = t.size(); 727 int length = thisSize + tSize; 728 729 // possible cases: 730 if (thisSize == 0) { 731 // this is empty 732 *this = t; 733 } else if (tSize == 0) { 734 // t is empty 735 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) { 736 // this is direct and has refcount of 1 (so we can just alter it directly) 737 expandCapacity(thisOffset + length); 738 if (data()) { 739 memcpy(const_cast<UChar*>(data() + thisSize), t.data(), tSize * sizeof(UChar)); 740 m_rep->len = length; 741 m_rep->_hash = 0; 742 } 743 } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) { 744 // this reaches the end of the buffer - extend it if it's long enough to append to 745 expandCapacity(thisOffset + length); 746 if (data()) { 747 memcpy(const_cast<UChar*>(data() + thisSize), t.data(), tSize * sizeof(UChar)); 748 m_rep = Rep::create(m_rep, 0, length); 749 } 655 750 } else { 656 strncpy(buf + i, result, decimalPoint); 657 i += decimalPoint; 658 buf[i++] = '.'; 659 strcpy(buf + i, result + decimalPoint); 660 } 661 } else if (result[0] < '0' || result[0] > '9') { 662 strcpy(buf + i, result); 663 } else { 664 buf[i++] = result[0]; 665 if (length > 1) { 666 buf[i++] = '.'; 667 strcpy(buf + i, result + 1); 668 i += length - 1; 669 } 670 671 buf[i++] = 'e'; 672 buf[i++] = (decimalPoint >= 0) ? '+' : '-'; 673 // decimalPoint can't be more than 3 digits decimal given the 674 // nature of float representation 675 int exponential = decimalPoint - 1; 676 if (exponential < 0) 677 exponential = -exponential; 678 if (exponential >= 100) 679 buf[i++] = static_cast<char>('0' + exponential / 100); 680 if (exponential >= 10) 681 buf[i++] = static_cast<char>('0' + (exponential % 100) / 10); 682 buf[i++] = static_cast<char>('0' + exponential % 10); 683 buf[i++] = '\0'; 684 } 685 686 freedtoa(result); 687 688 return UString(buf); 689 } 690 691 UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const 692 { 693 if (rangeCount == 1 && separatorCount == 0) { 751 // this is shared with someone using more capacity, gotta make a whole new string 752 size_t newCapacity = expandedSize(length, 0); 753 UChar* d = allocChars(newCapacity); 754 if (!d) 755 m_rep = &Rep::null; 756 else { 757 memcpy(d, data(), thisSize * sizeof(UChar)); 758 memcpy(const_cast<UChar*>(d + thisSize), t.data(), tSize * sizeof(UChar)); 759 m_rep = Rep::create(d, length); 760 m_rep->capacity = newCapacity; 761 } 762 } 763 764 return *this; 765 } 766 767 UString& UString::append(const UChar* tData, int tSize) 768 { 694 769 int thisSize = size(); 695 int position = substringRanges[0].position; 696 int length = substringRanges[0].length; 697 if (position <= 0 && length >= thisSize) 698 return *this; 699 return UString::Rep::create(m_rep, max(0, position), min(thisSize, length)); 700 } 701 702 int totalLength = 0; 703 for (int i = 0; i < rangeCount; i++) 704 totalLength += substringRanges[i].length; 705 for (int i = 0; i < separatorCount; i++) 706 totalLength += separators[i].size(); 707 708 if (totalLength == 0) 709 return ""; 710 711 UChar* buffer = allocChars(totalLength); 712 if (!buffer) 713 return null(); 714 715 int maxCount = max(rangeCount, separatorCount); 716 int bufferPos = 0; 717 for (int i = 0; i < maxCount; i++) { 718 if (i < rangeCount) { 719 memcpy(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length * sizeof(UChar)); 720 bufferPos += substringRanges[i].length; 721 } 722 if (i < separatorCount) { 723 memcpy(buffer + bufferPos, separators[i].data(), separators[i].size() * sizeof(UChar)); 724 bufferPos += separators[i].size(); 725 } 726 } 727 728 return UString::Rep::create(buffer, totalLength); 729 } 730 731 UString& UString::append(const UString &t) 732 { 733 int thisSize = size(); 734 int thisOffset = m_rep->offset; 735 int tSize = t.size(); 736 int length = thisSize + tSize; 737 738 // possible cases: 739 if (thisSize == 0) { 740 // this is empty 741 *this = t; 742 } else if (tSize == 0) { 743 // t is empty 744 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) { 745 // this is direct and has refcount of 1 (so we can just alter it directly) 746 expandCapacity(thisOffset + length); 747 if (data()) { 748 memcpy(const_cast<UChar*>(data() + thisSize), t.data(), tSize * sizeof(UChar)); 749 m_rep->len = length; 750 m_rep->_hash = 0; 751 } 752 } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) { 753 // this reaches the end of the buffer - extend it if it's long enough to append to 754 expandCapacity(thisOffset + length); 755 if (data()) { 756 memcpy(const_cast<UChar*>(data() + thisSize), t.data(), tSize * sizeof(UChar)); 757 m_rep = Rep::create(m_rep, 0, length); 758 } 759 } else { 760 // this is shared with someone using more capacity, gotta make a whole new string 761 size_t newCapacity = expandedSize(length, 0); 762 UChar* d = allocChars(newCapacity); 763 if (!d) 764 m_rep = &Rep::null; 765 else { 766 memcpy(d, data(), thisSize * sizeof(UChar)); 767 memcpy(const_cast<UChar*>(d + thisSize), t.data(), tSize * sizeof(UChar)); 768 m_rep = Rep::create(d, length); 769 m_rep->capacity = newCapacity; 770 } 771 } 772 773 return *this; 774 } 775 776 UString& UString::append(const UChar* tData, int tSize) 777 { 778 int thisSize = size(); 779 int thisOffset = m_rep->offset; 780 int length = thisSize + tSize; 781 782 // possible cases: 783 if (tSize == 0) { 784 // t is empty 785 } else if (thisSize == 0) { 786 // this is empty 787 m_rep = Rep::createCopying(tData, tSize); 788 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) { 789 // this is direct and has refcount of 1 (so we can just alter it directly) 790 expandCapacity(thisOffset + length); 791 if (data()) { 792 memcpy(const_cast<UChar*>(data() + thisSize), tData, tSize * sizeof(UChar)); 793 m_rep->len = length; 794 m_rep->_hash = 0; 795 } 796 } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) { 797 // this reaches the end of the buffer - extend it if it's long enough to append to 798 expandCapacity(thisOffset + length); 799 if (data()) { 800 memcpy(const_cast<UChar*>(data() + thisSize), tData, tSize * sizeof(UChar)); 801 m_rep = Rep::create(m_rep, 0, length); 802 } 803 } else { 804 // this is shared with someone using more capacity, gotta make a whole new string 805 size_t newCapacity = expandedSize(length, 0); 806 UChar* d = allocChars(newCapacity); 807 if (!d) 808 m_rep = &Rep::null; 809 else { 810 memcpy(d, data(), thisSize * sizeof(UChar)); 811 memcpy(const_cast<UChar*>(d + thisSize), tData, tSize * sizeof(UChar)); 812 m_rep = Rep::create(d, length); 813 m_rep->capacity = newCapacity; 814 } 815 } 816 817 return *this; 818 } 819 820 UString& UString::append(const char *t) 821 { 822 int thisSize = size(); 823 int thisOffset = m_rep->offset; 824 int tSize = static_cast<int>(strlen(t)); 825 int length = thisSize + tSize; 826 827 // possible cases: 828 if (thisSize == 0) { 829 // this is empty 830 *this = t; 831 } else if (tSize == 0) { 832 // t is empty, we'll just return *this below. 833 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) { 834 // this is direct and has refcount of 1 (so we can just alter it directly) 835 expandCapacity(thisOffset + length); 836 UChar *d = const_cast<UChar *>(data()); 837 if (d) { 838 for (int i = 0; i < tSize; ++i) 839 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend 840 m_rep->len = length; 841 m_rep->_hash = 0; 842 } 843 } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) { 844 // this string reaches the end of the buffer - extend it 845 expandCapacity(thisOffset + length); 846 UChar *d = const_cast<UChar *>(data()); 847 if (d) { 848 for (int i = 0; i < tSize; ++i) 849 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend 850 m_rep = Rep::create(m_rep, 0, length); 851 } 852 } else { 853 // this is shared with someone using more capacity, gotta make a whole new string 854 size_t newCapacity = expandedSize(length, 0); 855 UChar* d = allocChars(newCapacity); 856 if (!d) 857 m_rep = &Rep::null; 858 else { 859 memcpy(d, data(), thisSize * sizeof(UChar)); 860 for (int i = 0; i < tSize; ++i) 861 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend 862 m_rep = Rep::create(d, length); 863 m_rep->capacity = newCapacity; 864 } 865 } 866 867 return *this; 770 int thisOffset = m_rep->offset; 771 int length = thisSize + tSize; 772 773 // possible cases: 774 if (tSize == 0) { 775 // t is empty 776 } else if (thisSize == 0) { 777 // this is empty 778 m_rep = Rep::createCopying(tData, tSize); 779 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) { 780 // this is direct and has refcount of 1 (so we can just alter it directly) 781 expandCapacity(thisOffset + length); 782 if (data()) { 783 memcpy(const_cast<UChar*>(data() + thisSize), tData, tSize * sizeof(UChar)); 784 m_rep->len = length; 785 m_rep->_hash = 0; 786 } 787 } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) { 788 // this reaches the end of the buffer - extend it if it's long enough to append to 789 expandCapacity(thisOffset + length); 790 if (data()) { 791 memcpy(const_cast<UChar*>(data() + thisSize), tData, tSize * sizeof(UChar)); 792 m_rep = Rep::create(m_rep, 0, length); 793 } 794 } else { 795 // this is shared with someone using more capacity, gotta make a whole new string 796 size_t newCapacity = expandedSize(length, 0); 797 UChar* d = allocChars(newCapacity); 798 if (!d) 799 m_rep = &Rep::null; 800 else { 801 memcpy(d, data(), thisSize * sizeof(UChar)); 802 memcpy(const_cast<UChar*>(d + thisSize), tData, tSize * sizeof(UChar)); 803 m_rep = Rep::create(d, length); 804 m_rep->capacity = newCapacity; 805 } 806 } 807 808 return *this; 809 } 810 811 UString& UString::append(const char* t) 812 { 813 int thisSize = size(); 814 int thisOffset = m_rep->offset; 815 int tSize = static_cast<int>(strlen(t)); 816 int length = thisSize + tSize; 817 818 // possible cases: 819 if (thisSize == 0) { 820 // this is empty 821 *this = t; 822 } else if (tSize == 0) { 823 // t is empty, we'll just return *this below. 824 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) { 825 // this is direct and has refcount of 1 (so we can just alter it directly) 826 expandCapacity(thisOffset + length); 827 UChar* d = const_cast<UChar*>(data()); 828 if (d) { 829 for (int i = 0; i < tSize; ++i) 830 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend 831 m_rep->len = length; 832 m_rep->_hash = 0; 833 } 834 } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) { 835 // this string reaches the end of the buffer - extend it 836 expandCapacity(thisOffset + length); 837 UChar* d = const_cast<UChar*>(data()); 838 if (d) { 839 for (int i = 0; i < tSize; ++i) 840 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend 841 m_rep = Rep::create(m_rep, 0, length); 842 } 843 } else { 844 // this is shared with someone using more capacity, gotta make a whole new string 845 size_t newCapacity = expandedSize(length, 0); 846 UChar* d = allocChars(newCapacity); 847 if (!d) 848 m_rep = &Rep::null; 849 else { 850 memcpy(d, data(), thisSize * sizeof(UChar)); 851 for (int i = 0; i < tSize; ++i) 852 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend 853 m_rep = Rep::create(d, length); 854 m_rep->capacity = newCapacity; 855 } 856 } 857 858 return *this; 868 859 } 869 860 870 861 UString& UString::append(UChar c) 871 862 { 872 int thisOffset = m_rep->offset;873 int length = size();874 875 // possible cases:876 if (length == 0) {877 // this is empty - must make a new m_rep because we don't want to pollute the shared empty one878 size_t newCapacity = expandedSize(1, 0);879 UChar* d = allocChars(newCapacity);880 if (!d)881 m_rep = &Rep::null;882 else {883 d[0] = c;884 m_rep = Rep::create(d, 1);885 m_rep->capacity = newCapacity;886 }887 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) {888 // this is direct and has refcount of 1 (so we can just alter it directly)889 expandCapacity(thisOffset + length + 1);890 UChar *d = const_cast<UChar*>(data());891 if (d) {892 d[length] = c;893 m_rep->len = length + 1;894 m_rep->_hash = 0;895 }896 } else if (thisOffset + length == usedCapacity() && length >= minShareSize) {897 // this reaches the end of the string - extend it and share898 expandCapacity(thisOffset + length + 1);899 UChar *d = const_cast<UChar*>(data());900 if (d) {901 d[length] = c;902 m_rep = Rep::create(m_rep, 0, length + 1);903 }904 } else {905 // this is shared with someone using more capacity, gotta make a whole new string906 size_t newCapacity = expandedSize(length + 1, 0);907 UChar* d = allocChars(newCapacity);908 if (!d)909 m_rep = &Rep::null;910 else {911 memcpy(d, data(), length * sizeof(UChar));912 d[length] = c;913 m_rep = Rep::create(d, length + 1);914 m_rep->capacity = newCapacity;915 }916 }917 918 return *this;863 int thisOffset = m_rep->offset; 864 int length = size(); 865 866 // possible cases: 867 if (length == 0) { 868 // this is empty - must make a new m_rep because we don't want to pollute the shared empty one 869 size_t newCapacity = expandedSize(1, 0); 870 UChar* d = allocChars(newCapacity); 871 if (!d) 872 m_rep = &Rep::null; 873 else { 874 d[0] = c; 875 m_rep = Rep::create(d, 1); 876 m_rep->capacity = newCapacity; 877 } 878 } else if (m_rep->baseIsSelf() && m_rep->rc == 1) { 879 // this is direct and has refcount of 1 (so we can just alter it directly) 880 expandCapacity(thisOffset + length + 1); 881 UChar* d = const_cast<UChar*>(data()); 882 if (d) { 883 d[length] = c; 884 m_rep->len = length + 1; 885 m_rep->_hash = 0; 886 } 887 } else if (thisOffset + length == usedCapacity() && length >= minShareSize) { 888 // this reaches the end of the string - extend it and share 889 expandCapacity(thisOffset + length + 1); 890 UChar* d = const_cast<UChar*>(data()); 891 if (d) { 892 d[length] = c; 893 m_rep = Rep::create(m_rep, 0, length + 1); 894 } 895 } else { 896 // this is shared with someone using more capacity, gotta make a whole new string 897 size_t newCapacity = expandedSize(length + 1, 0); 898 UChar* d = allocChars(newCapacity); 899 if (!d) 900 m_rep = &Rep::null; 901 else { 902 memcpy(d, data(), length * sizeof(UChar)); 903 d[length] = c; 904 m_rep = Rep::create(d, length + 1); 905 m_rep->capacity = newCapacity; 906 } 907 } 908 909 return *this; 919 910 } 920 911 … … 925 916 buffer.resize(neededSize); 926 917 char* buf = buffer.data(); 927 918 928 919 UChar ored = 0; 929 920 const UChar* p = data(); … … 938 929 } 939 930 *q = '\0'; 940 931 941 932 return !(ored & 0xFF00); 942 933 } 943 934 944 char *UString::ascii() const945 { 946 int length = size();947 int neededSize = length + 1;948 delete[] statBuffer;949 statBuffer = new char[neededSize];950 951 const UChar *p = data();952 char *q = statBuffer;953 const UChar *limit = p + length;954 while (p != limit) {955 *q = static_cast<char>(p[0]);956 ++p;957 ++q;958 }959 *q = '\0';960 961 return statBuffer;962 } 963 964 UString& UString::operator=(const char *c)935 char* UString::ascii() const 936 { 937 int length = size(); 938 int neededSize = length + 1; 939 delete[] statBuffer; 940 statBuffer = new char[neededSize]; 941 942 const UChar* p = data(); 943 char* q = statBuffer; 944 const UChar* limit = p + length; 945 while (p != limit) { 946 *q = static_cast<char>(p[0]); 947 ++p; 948 ++q; 949 } 950 *q = '\0'; 951 952 return statBuffer; 953 } 954 955 UString& UString::operator=(const char* c) 965 956 { 966 957 if (!c) { … … 974 965 } 975 966 976 int l = static_cast<int>(strlen(c)); 977 UChar *d; 978 if (m_rep->rc == 1 && l <= m_rep->capacity && m_rep->baseIsSelf() && m_rep->offset == 0 && m_rep->preCapacity == 0) { 979 d = m_rep->buf; 980 m_rep->_hash = 0; 981 m_rep->len = l; 982 } else { 983 d = allocChars(l); 984 if (!d) { 985 m_rep = &Rep::null; 967 int l = static_cast<int>(strlen(c)); 968 UChar* d; 969 if (m_rep->rc == 1 && l <= m_rep->capacity && m_rep->baseIsSelf() && m_rep->offset == 0 && m_rep->preCapacity == 0) { 970 d = m_rep->buf; 971 m_rep->_hash = 0; 972 m_rep->len = l; 973 } else { 974 d = allocChars(l); 975 if (!d) { 976 m_rep = &Rep::null; 977 return *this; 978 } 979 m_rep = Rep::create(d, l); 980 } 981 for (int i = 0; i < l; i++) 982 d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend 983 984 return *this; 985 } 986 987 bool UString::is8Bit() const 988 { 989 const UChar* u = data(); 990 const UChar* limit = u + size(); 991 while (u < limit) { 992 if (u[0] > 0xFF) 993 return false; 994 ++u; 995 } 996 997 return true; 998 } 999 1000 UChar UString::operator[](int pos) const 1001 { 1002 if (pos >= size()) 1003 return '\0'; 1004 return data()[pos]; 1005 } 1006 1007 double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const 1008 { 1009 double d; 1010 1011 // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk 1012 // after the number, so this is too strict a check. 1013 CStringBuffer s; 1014 if (!getCString(s)) 1015 return NaN; 1016 const char* c = s.data(); 1017 1018 // skip leading white space 1019 while (isASCIISpace(*c)) 1020 c++; 1021 1022 // empty string ? 1023 if (*c == '\0') 1024 return tolerateEmptyString ? 0.0 : NaN; 1025 1026 // hex number ? 1027 if (*c == '0' && (*(c + 1) == 'x' || *(c + 1) == 'X')) { 1028 const char* firstDigitPosition = c + 2; 1029 c++; 1030 d = 0.0; 1031 while (*(++c)) { 1032 if (*c >= '0' && *c <= '9') 1033 d = d * 16.0 + *c - '0'; 1034 else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f')) 1035 d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0; 1036 else 1037 break; 1038 } 1039 1040 if (d >= mantissaOverflowLowerBound) 1041 d = parseIntOverflow(firstDigitPosition, c - firstDigitPosition, 16); 1042 } else { 1043 // regular number ? 1044 char* end; 1045 d = strtod(c, &end); 1046 if ((d != 0.0 || end != c) && d != Inf && d != -Inf) { 1047 c = end; 1048 } else { 1049 double sign = 1.0; 1050 1051 if (*c == '+') 1052 c++; 1053 else if (*c == '-') { 1054 sign = -1.0; 1055 c++; 1056 } 1057 1058 // We used strtod() to do the conversion. However, strtod() handles 1059 // infinite values slightly differently than JavaScript in that it 1060 // converts the string "inf" with any capitalization to infinity, 1061 // whereas the ECMA spec requires that it be converted to NaN. 1062 1063 if (c[0] == 'I' && c[1] == 'n' && c[2] == 'f' && c[3] == 'i' && c[4] == 'n' && c[5] == 'i' && c[6] == 't' && c[7] == 'y') { 1064 d = sign * Inf; 1065 c += 8; 1066 } else if ((d == Inf || d == -Inf) && *c != 'I' && *c != 'i') 1067 c = end; 1068 else 1069 return NaN; 1070 } 1071 } 1072 1073 // allow trailing white space 1074 while (isASCIISpace(*c)) 1075 c++; 1076 // don't allow anything after - unless tolerant=true 1077 if (!tolerateTrailingJunk && *c != '\0') 1078 d = NaN; 1079 1080 return d; 1081 } 1082 1083 double UString::toDouble(bool tolerateTrailingJunk) const 1084 { 1085 return toDouble(tolerateTrailingJunk, true); 1086 } 1087 1088 double UString::toDouble() const 1089 { 1090 return toDouble(false, true); 1091 } 1092 1093 uint32_t UString::toUInt32(bool* ok) const 1094 { 1095 double d = toDouble(); 1096 bool b = true; 1097 1098 if (d != static_cast<uint32_t>(d)) { 1099 b = false; 1100 d = 0; 1101 } 1102 1103 if (ok) 1104 *ok = b; 1105 1106 return static_cast<uint32_t>(d); 1107 } 1108 1109 uint32_t UString::toUInt32(bool* ok, bool tolerateEmptyString) const 1110 { 1111 double d = toDouble(false, tolerateEmptyString); 1112 bool b = true; 1113 1114 if (d != static_cast<uint32_t>(d)) { 1115 b = false; 1116 d = 0; 1117 } 1118 1119 if (ok) 1120 *ok = b; 1121 1122 return static_cast<uint32_t>(d); 1123 } 1124 1125 uint32_t UString::toStrictUInt32(bool* ok) const 1126 { 1127 if (ok) 1128 *ok = false; 1129 1130 // Empty string is not OK. 1131 int len = m_rep->len; 1132 if (len == 0) 1133 return 0; 1134 const UChar* p = m_rep->data(); 1135 unsigned short c = p[0]; 1136 1137 // If the first digit is 0, only 0 itself is OK. 1138 if (c == '0') { 1139 if (len == 1 && ok) 1140 *ok = true; 1141 return 0; 1142 } 1143 1144 // Convert to UInt32, checking for overflow. 1145 uint32_t i = 0; 1146 while (1) { 1147 // Process character, turning it into a digit. 1148 if (c < '0' || c > '9') 1149 return 0; 1150 const unsigned d = c - '0'; 1151 1152 // Multiply by 10, checking for overflow out of 32 bits. 1153 if (i > 0xFFFFFFFFU / 10) 1154 return 0; 1155 i *= 10; 1156 1157 // Add in the digit, checking for overflow out of 32 bits. 1158 const unsigned max = 0xFFFFFFFFU - d; 1159 if (i > max) 1160 return 0; 1161 i += d; 1162 1163 // Handle end of string. 1164 if (--len == 0) { 1165 if (ok) 1166 *ok = true; 1167 return i; 1168 } 1169 1170 // Get next character. 1171 c = *(++p); 1172 } 1173 } 1174 1175 int UString::find(const UString& f, int pos) const 1176 { 1177 int sz = size(); 1178 int fsz = f.size(); 1179 if (sz < fsz) 1180 return -1; 1181 if (pos < 0) 1182 pos = 0; 1183 if (fsz == 0) 1184 return pos; 1185 const UChar* end = data() + sz - fsz; 1186 int fsizeminusone = (fsz - 1) * sizeof(UChar); 1187 const UChar* fdata = f.data(); 1188 unsigned short fchar = fdata[0]; 1189 ++fdata; 1190 for (const UChar* c = data() + pos; c <= end; c++) { 1191 if (c[0] == fchar && !memcmp(c + 1, fdata, fsizeminusone)) 1192 return static_cast<int>(c - data()); 1193 } 1194 1195 return -1; 1196 } 1197 1198 int UString::find(UChar ch, int pos) const 1199 { 1200 if (pos < 0) 1201 pos = 0; 1202 const UChar* end = data() + size(); 1203 for (const UChar* c = data() + pos; c < end; c++) { 1204 if (*c == ch) 1205 return static_cast<int>(c - data()); 1206 } 1207 1208 return -1; 1209 } 1210 1211 int UString::rfind(const UString& f, int pos) const 1212 { 1213 int sz = size(); 1214 int fsz = f.size(); 1215 if (sz < fsz) 1216 return -1; 1217 if (pos < 0) 1218 pos = 0; 1219 if (pos > sz - fsz) 1220 pos = sz - fsz; 1221 if (fsz == 0) 1222 return pos; 1223 int fsizeminusone = (fsz - 1) * sizeof(UChar); 1224 const UChar* fdata = f.data(); 1225 for (const UChar* c = data() + pos; c >= data(); c--) { 1226 if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone)) 1227 return static_cast<int>(c - data()); 1228 } 1229 1230 return -1; 1231 } 1232 1233 int UString::rfind(UChar ch, int pos) const 1234 { 1235 if (isEmpty()) 1236 return -1; 1237 if (pos + 1 >= size()) 1238 pos = size() - 1; 1239 for (const UChar* c = data() + pos; c >= data(); c--) { 1240 if (*c == ch) 1241 return static_cast<int>(c - data()); 1242 } 1243 1244 return -1; 1245 } 1246 1247 UString UString::substr(int pos, int len) const 1248 { 1249 int s = size(); 1250 1251 if (pos < 0) 1252 pos = 0; 1253 else if (pos >= s) 1254 pos = s; 1255 if (len < 0) 1256 len = s; 1257 if (pos + len >= s) 1258 len = s - pos; 1259 1260 if (pos == 0 && len == s) 986 1261 return *this; 987 } 988 m_rep = Rep::create(d, l); 989 } 990 for (int i = 0; i < l; i++) 991 d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend 992 993 return *this; 994 } 995 996 bool UString::is8Bit() const 997 { 998 const UChar *u = data(); 999 const UChar *limit = u + size(); 1000 while (u < limit) { 1001 if (u[0] > 0xFF) 1002 return false; 1003 ++u; 1004 } 1005 1006 return true; 1007 } 1008 1009 UChar UString::operator[](int pos) const 1010 { 1011 if (pos >= size()) 1012 return '\0'; 1013 return data()[pos]; 1014 } 1015 1016 double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const 1017 { 1018 double d; 1019 1020 // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk 1021 // after the number, so this is too strict a check. 1022 CStringBuffer s; 1023 if (!getCString(s)) 1024 return NaN; 1025 const char* c = s.data(); 1026 1027 // skip leading white space 1028 while (isASCIISpace(*c)) 1029 c++; 1030 1031 // empty string ? 1032 if (*c == '\0') 1033 return tolerateEmptyString ? 0.0 : NaN; 1034 1035 // hex number ? 1036 if (*c == '0' && (*(c+1) == 'x' || *(c+1) == 'X')) { 1037 const char* firstDigitPosition = c + 2; 1038 c++; 1039 d = 0.0; 1040 while (*(++c)) { 1041 if (*c >= '0' && *c <= '9') 1042 d = d * 16.0 + *c - '0'; 1043 else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f')) 1044 d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0; 1045 else 1046 break; 1047 } 1048 1049 if (d >= mantissaOverflowLowerBound) 1050 d = parseIntOverflow(firstDigitPosition, c - firstDigitPosition, 16); 1051 } else { 1052 // regular number ? 1053 char *end; 1054 d = strtod(c, &end); 1055 if ((d != 0.0 || end != c) && d != Inf && d != -Inf) { 1056 c = end; 1057 } else { 1058 double sign = 1.0; 1059 1060 if (*c == '+') 1061 c++; 1062 else if (*c == '-') { 1063 sign = -1.0; 1064 c++; 1065 } 1066 1067 // We used strtod() to do the conversion. However, strtod() handles 1068 // infinite values slightly differently than JavaScript in that it 1069 // converts the string "inf" with any capitalization to infinity, 1070 // whereas the ECMA spec requires that it be converted to NaN. 1071 1072 if (c[0] == 'I' && c[1] == 'n' && c[2] == 'f' && c[3] == 'i' && c[4] == 'n' && c[5] == 'i' && c[6] == 't' && c[7] == 'y') { 1073 d = sign * Inf; 1074 c += 8; 1075 } else if ((d == Inf || d == -Inf) && *c != 'I' && *c != 'i') 1076 c = end; 1077 else 1078 return NaN; 1079 } 1080 } 1081 1082 // allow trailing white space 1083 while (isASCIISpace(*c)) 1084 c++; 1085 // don't allow anything after - unless tolerant=true 1086 if (!tolerateTrailingJunk && *c != '\0') 1087 d = NaN; 1088 1089 return d; 1090 } 1091 1092 double UString::toDouble(bool tolerateTrailingJunk) const 1093 { 1094 return toDouble(tolerateTrailingJunk, true); 1095 } 1096 1097 double UString::toDouble() const 1098 { 1099 return toDouble(false, true); 1100 } 1101 1102 uint32_t UString::toUInt32(bool *ok) const 1103 { 1104 double d = toDouble(); 1105 bool b = true; 1106 1107 if (d != static_cast<uint32_t>(d)) { 1108 b = false; 1109 d = 0; 1110 } 1111 1112 if (ok) 1113 *ok = b; 1114 1115 return static_cast<uint32_t>(d); 1116 } 1117 1118 uint32_t UString::toUInt32(bool *ok, bool tolerateEmptyString) const 1119 { 1120 double d = toDouble(false, tolerateEmptyString); 1121 bool b = true; 1122 1123 if (d != static_cast<uint32_t>(d)) { 1124 b = false; 1125 d = 0; 1126 } 1127 1128 if (ok) 1129 *ok = b; 1130 1131 return static_cast<uint32_t>(d); 1132 } 1133 1134 uint32_t UString::toStrictUInt32(bool *ok) const 1135 { 1136 if (ok) 1137 *ok = false; 1138 1139 // Empty string is not OK. 1140 int len = m_rep->len; 1141 if (len == 0) 1142 return 0; 1143 const UChar *p = m_rep->data(); 1144 unsigned short c = p[0]; 1145 1146 // If the first digit is 0, only 0 itself is OK. 1147 if (c == '0') { 1148 if (len == 1 && ok) 1149 *ok = true; 1150 return 0; 1151 } 1152 1153 // Convert to UInt32, checking for overflow. 1154 uint32_t i = 0; 1155 while (1) { 1156 // Process character, turning it into a digit. 1157 if (c < '0' || c > '9') 1158 return 0; 1159 const unsigned d = c - '0'; 1160 1161 // Multiply by 10, checking for overflow out of 32 bits. 1162 if (i > 0xFFFFFFFFU / 10) 1163 return 0; 1164 i *= 10; 1165 1166 // Add in the digit, checking for overflow out of 32 bits. 1167 const unsigned max = 0xFFFFFFFFU - d; 1168 if (i > max) 1262 1263 return UString(Rep::create(m_rep, pos, len)); 1264 } 1265 1266 bool operator==(const UString& s1, const UString& s2) 1267 { 1268 if (s1.m_rep->len != s2.m_rep->len) 1269 return false; 1270 1271 return (memcmp(s1.m_rep->data(), s2.m_rep->data(), s1.m_rep->len * sizeof(UChar)) == 0); 1272 } 1273 1274 bool operator==(const UString& s1, const char *s2) 1275 { 1276 if (s2 == 0) 1277 return s1.isEmpty(); 1278 1279 const UChar* u = s1.data(); 1280 const UChar* uend = u + s1.size(); 1281 while (u != uend && *s2) { 1282 if (u[0] != (unsigned char)*s2) 1283 return false; 1284 s2++; 1285 u++; 1286 } 1287 1288 return u == uend && *s2 == 0; 1289 } 1290 1291 bool operator<(const UString& s1, const UString& s2) 1292 { 1293 const int l1 = s1.size(); 1294 const int l2 = s2.size(); 1295 const int lmin = l1 < l2 ? l1 : l2; 1296 const UChar* c1 = s1.data(); 1297 const UChar* c2 = s2.data(); 1298 int l = 0; 1299 while (l < lmin && *c1 == *c2) { 1300 c1++; 1301 c2++; 1302 l++; 1303 } 1304 if (l < lmin) 1305 return (c1[0] < c2[0]); 1306 1307 return (l1 < l2); 1308 } 1309 1310 bool operator>(const UString& s1, const UString& s2) 1311 { 1312 const int l1 = s1.size(); 1313 const int l2 = s2.size(); 1314 const int lmin = l1 < l2 ? l1 : l2; 1315 const UChar* c1 = s1.data(); 1316 const UChar* c2 = s2.data(); 1317 int l = 0; 1318 while (l < lmin && *c1 == *c2) { 1319 c1++; 1320 c2++; 1321 l++; 1322 } 1323 if (l < lmin) 1324 return (c1[0] > c2[0]); 1325 1326 return (l1 > l2); 1327 } 1328 1329 int compare(const UString& s1, const UString& s2) 1330 { 1331 const int l1 = s1.size(); 1332 const int l2 = s2.size(); 1333 const int lmin = l1 < l2 ? l1 : l2; 1334 const UChar* c1 = s1.data(); 1335 const UChar* c2 = s2.data(); 1336 int l = 0; 1337 while (l < lmin && *c1 == *c2) { 1338 c1++; 1339 c2++; 1340 l++; 1341 } 1342 1343 if (l < lmin) 1344 return (c1[0] > c2[0]) ? 1 : -1; 1345 1346 if (l1 == l2) 1169 1347 return 0; 1170 i += d; 1171 1172 // Handle end of string. 1173 if (--len == 0) { 1174 if (ok) 1175 *ok = true; 1176 return i; 1177 } 1178 1179 // Get next character. 1180 c = *(++p); 1181 } 1182 } 1183 1184 int UString::find(const UString &f, int pos) const 1185 { 1186 int sz = size(); 1187 int fsz = f.size(); 1188 if (sz < fsz) 1189 return -1; 1190 if (pos < 0) 1191 pos = 0; 1192 if (fsz == 0) 1193 return pos; 1194 const UChar *end = data() + sz - fsz; 1195 int fsizeminusone = (fsz - 1) * sizeof(UChar); 1196 const UChar *fdata = f.data(); 1197 unsigned short fchar = fdata[0]; 1198 ++fdata; 1199 for (const UChar *c = data() + pos; c <= end; c++) 1200 if (c[0] == fchar && !memcmp(c + 1, fdata, fsizeminusone)) 1201 return static_cast<int>(c - data()); 1202 1203 return -1; 1204 } 1205 1206 int UString::find(UChar ch, int pos) const 1207 { 1208 if (pos < 0) 1209 pos = 0; 1210 const UChar *end = data() + size(); 1211 for (const UChar *c = data() + pos; c < end; c++) 1212 if (*c == ch) 1213 return static_cast<int>(c - data()); 1214 1215 return -1; 1216 } 1217 1218 int UString::rfind(const UString &f, int pos) const 1219 { 1220 int sz = size(); 1221 int fsz = f.size(); 1222 if (sz < fsz) 1223 return -1; 1224 if (pos < 0) 1225 pos = 0; 1226 if (pos > sz - fsz) 1227 pos = sz - fsz; 1228 if (fsz == 0) 1229 return pos; 1230 int fsizeminusone = (fsz - 1) * sizeof(UChar); 1231 const UChar *fdata = f.data(); 1232 for (const UChar *c = data() + pos; c >= data(); c--) { 1233 if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone)) 1234 return static_cast<int>(c - data()); 1235 } 1236 1237 return -1; 1238 } 1239 1240 int UString::rfind(UChar ch, int pos) const 1241 { 1242 if (isEmpty()) 1243 return -1; 1244 if (pos + 1 >= size()) 1245 pos = size() - 1; 1246 for (const UChar *c = data() + pos; c >= data(); c--) { 1247 if (*c == ch) 1248 return static_cast<int>(c-data()); 1249 } 1250 1251 return -1; 1252 } 1253 1254 UString UString::substr(int pos, int len) const 1255 { 1256 int s = size(); 1257 1258 if (pos < 0) 1259 pos = 0; 1260 else if (pos >= s) 1261 pos = s; 1262 if (len < 0) 1263 len = s; 1264 if (pos + len >= s) 1265 len = s - pos; 1266 1267 if (pos == 0 && len == s) 1268 return *this; 1269 1270 return UString(Rep::create(m_rep, pos, len)); 1271 } 1272 1273 bool operator==(const UString& s1, const UString& s2) 1274 { 1275 if (s1.m_rep->len != s2.m_rep->len) 1276 return false; 1277 1278 return (memcmp(s1.m_rep->data(), s2.m_rep->data(), 1279 s1.m_rep->len * sizeof(UChar)) == 0); 1280 } 1281 1282 bool operator==(const UString& s1, const char *s2) 1283 { 1284 if (s2 == 0) { 1285 return s1.isEmpty(); 1286 } 1287 1288 const UChar *u = s1.data(); 1289 const UChar *uend = u + s1.size(); 1290 while (u != uend && *s2) { 1291 if (u[0] != (unsigned char)*s2) 1292 return false; 1293 s2++; 1294 u++; 1295 } 1296 1297 return u == uend && *s2 == 0; 1298 } 1299 1300 bool operator<(const UString& s1, const UString& s2) 1301 { 1302 const int l1 = s1.size(); 1303 const int l2 = s2.size(); 1304 const int lmin = l1 < l2 ? l1 : l2; 1305 const UChar *c1 = s1.data(); 1306 const UChar *c2 = s2.data(); 1307 int l = 0; 1308 while (l < lmin && *c1 == *c2) { 1309 c1++; 1310 c2++; 1311 l++; 1312 } 1313 if (l < lmin) 1314 return (c1[0] < c2[0]); 1315 1316 return (l1 < l2); 1317 } 1318 1319 bool operator>(const UString& s1, const UString& s2) 1320 { 1321 const int l1 = s1.size(); 1322 const int l2 = s2.size(); 1323 const int lmin = l1 < l2 ? l1 : l2; 1324 const UChar *c1 = s1.data(); 1325 const UChar *c2 = s2.data(); 1326 int l = 0; 1327 while (l < lmin && *c1 == *c2) { 1328 c1++; 1329 c2++; 1330 l++; 1331 } 1332 if (l < lmin) 1333 return (c1[0] > c2[0]); 1334 1335 return (l1 > l2); 1336 } 1337 1338 int compare(const UString& s1, const UString& s2) 1339 { 1340 const int l1 = s1.size(); 1341 const int l2 = s2.size(); 1342 const int lmin = l1 < l2 ? l1 : l2; 1343 const UChar *c1 = s1.data(); 1344 const UChar *c2 = s2.data(); 1345 int l = 0; 1346 while (l < lmin && *c1 == *c2) { 1347 c1++; 1348 c2++; 1349 l++; 1350 } 1351 1352 if (l < lmin) 1353 return (c1[0] > c2[0]) ? 1 : -1; 1354 1355 if (l1 == l2) 1356 return 0; 1357 1358 return (l1 > l2) ? 1 : -1; 1348 1349 return (l1 > l2) ? 1 : -1; 1359 1350 } 1360 1351 … … 1366 1357 const UChar* d = r->data(); 1367 1358 const UChar* s = b->data(); 1368 for (int i = 0; i != length; ++i) 1359 for (int i = 0; i != length; ++i) { 1369 1360 if (d[i] != s[i]) 1370 1361 return false; 1362 } 1371 1363 return true; 1372 1364 } … … 1374 1366 CString UString::UTF8String(bool strict) const 1375 1367 { 1376 // Allocate a buffer big enough to hold all the characters.1377 const int length = size();1378 Vector<char, 1024> buffer(length * 3);1379 1380 // Convert to runs of 8-bit characters.1381 char* p = buffer.data();1382 const UChar* d = reinterpret_cast<const UChar*>(&data()[0]);1383 ConversionResult result = convertUTF16ToUTF8(&d, d + length, &p, p + buffer.size(), strict);1384 if (result != conversionOK)1385 return CString();1386 1387 return CString(buffer.data(), p - buffer.data());1368 // Allocate a buffer big enough to hold all the characters. 1369 const int length = size(); 1370 Vector<char, 1024> buffer(length * 3); 1371 1372 // Convert to runs of 8-bit characters. 1373 char* p = buffer.data(); 1374 const UChar* d = reinterpret_cast<const UChar*>(&data()[0]); 1375 ConversionResult result = convertUTF16ToUTF8(&d, d + length, &p, p + buffer.size(), strict); 1376 if (result != conversionOK) 1377 return CString(); 1378 1379 return CString(buffer.data(), p - buffer.data()); 1388 1380 } 1389 1381
Note:
See TracChangeset
for help on using the changeset viewer.