source: webkit/trunk/JavaScriptCore/runtime/UString.cpp@ 46180

Last change on this file since 46180 was 46180, checked in by Adam Roben, 16 years ago

Roll out r46153, r46154, and r46155

These changes were causing build failures and assertion failures on
Windows.

JavaScriptCore:

  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • runtime/JSArray.cpp:
  • runtime/StringPrototype.cpp:
  • runtime/UString.cpp:
  • runtime/UString.h:
  • wtf/FastMalloc.cpp:
  • wtf/FastMalloc.h:
  • wtf/Platform.h:
  • wtf/PossiblyNull.h: Removed.

WebCore:

  • ForwardingHeaders/wtf/PossiblyNull.h: Removed.
  • platform/graphics/cg/ImageBufferCG.cpp:
  • Property svn:eol-style set to native
File size: 48.6 KB
Line 
1/*
2 * Copyright (C) 1999-2000 Harri Porten ([email protected])
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4 * Copyright (C) 2007 Cameron Zwarich ([email protected])
5 * Copyright (C) 2009 Google Inc. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#include "config.h"
25#include "UString.h"
26
27#include "JSGlobalObjectFunctions.h"
28#include "Collector.h"
29#include "dtoa.h"
30#include "Identifier.h"
31#include "Operations.h"
32#include <ctype.h>
33#include <float.h>
34#include <limits.h>
35#include <math.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <wtf/ASCIICType.h>
39#include <wtf/Assertions.h>
40#include <wtf/MathExtras.h>
41#include <wtf/Vector.h>
42#include <wtf/unicode/UTF8.h>
43
44#if HAVE(STRING_H)
45#include <string.h>
46#endif
47#if HAVE(STRINGS_H)
48#include <strings.h>
49#endif
50
51using namespace WTF;
52using namespace WTF::Unicode;
53using namespace std;
54
55// This can be tuned differently per platform by putting platform #ifs right here.
56// If you don't define this macro at all, then copyChars will just call directly
57// to memcpy.
58#define USTRING_COPY_CHARS_INLINE_CUTOFF 20
59
60namespace JSC {
61
62extern const double NaN;
63extern const double Inf;
64
65// This number must be at least 2 to avoid sharing empty, null as well as 1 character strings from SmallStrings.
66static const int minLengthToShare = 10;
67
68static inline size_t overflowIndicator() { return std::numeric_limits<size_t>::max(); }
69static inline size_t maxUChars() { return std::numeric_limits<size_t>::max() / sizeof(UChar); }
70
71static inline UChar* allocChars(size_t length)
72{
73 ASSERT(length);
74 if (length > maxUChars())
75 return 0;
76 return static_cast<UChar*>(tryFastMalloc(sizeof(UChar) * length));
77}
78
79static inline UChar* reallocChars(UChar* buffer, size_t length)
80{
81 ASSERT(length);
82 if (length > maxUChars())
83 return 0;
84 return static_cast<UChar*>(tryFastRealloc(buffer, sizeof(UChar) * length));
85}
86
87static inline void copyChars(UChar* destination, const UChar* source, unsigned numCharacters)
88{
89#ifdef USTRING_COPY_CHARS_INLINE_CUTOFF
90 if (numCharacters <= USTRING_COPY_CHARS_INLINE_CUTOFF) {
91 for (unsigned i = 0; i < numCharacters; ++i)
92 destination[i] = source[i];
93 return;
94 }
95#endif
96 memcpy(destination, source, numCharacters * sizeof(UChar));
97}
98
99COMPILE_ASSERT(sizeof(UChar) == 2, uchar_is_2_bytes);
100
101CString::CString(const char* c)
102 : m_length(strlen(c))
103 , m_data(new char[m_length + 1])
104{
105 memcpy(m_data, c, m_length + 1);
106}
107
108CString::CString(const char* c, size_t length)
109 : m_length(length)
110 , m_data(new char[length + 1])
111{
112 memcpy(m_data, c, m_length);
113 m_data[m_length] = 0;
114}
115
116CString::CString(const CString& b)
117{
118 m_length = b.m_length;
119 if (b.m_data) {
120 m_data = new char[m_length + 1];
121 memcpy(m_data, b.m_data, m_length + 1);
122 } else
123 m_data = 0;
124}
125
126CString::~CString()
127{
128 delete [] m_data;
129}
130
131CString CString::adopt(char* c, size_t length)
132{
133 CString s;
134 s.m_data = c;
135 s.m_length = length;
136 return s;
137}
138
139CString& CString::append(const CString& t)
140{
141 char* n;
142 n = new char[m_length + t.m_length + 1];
143 if (m_length)
144 memcpy(n, m_data, m_length);
145 if (t.m_length)
146 memcpy(n + m_length, t.m_data, t.m_length);
147 m_length += t.m_length;
148 n[m_length] = 0;
149
150 delete [] m_data;
151 m_data = n;
152
153 return *this;
154}
155
156CString& CString::operator=(const char* c)
157{
158 if (m_data)
159 delete [] m_data;
160 m_length = strlen(c);
161 m_data = new char[m_length + 1];
162 memcpy(m_data, c, m_length + 1);
163
164 return *this;
165}
166
167CString& CString::operator=(const CString& str)
168{
169 if (this == &str)
170 return *this;
171
172 if (m_data)
173 delete [] m_data;
174 m_length = str.m_length;
175 if (str.m_data) {
176 m_data = new char[m_length + 1];
177 memcpy(m_data, str.m_data, m_length + 1);
178 } else
179 m_data = 0;
180
181 return *this;
182}
183
184bool operator==(const CString& c1, const CString& c2)
185{
186 size_t len = c1.size();
187 return len == c2.size() && (len == 0 || memcmp(c1.c_str(), c2.c_str(), len) == 0);
188}
189
190// These static strings are immutable, except for rc, whose initial value is chosen to
191// reduce the possibility of it becoming zero due to ref/deref not being thread-safe.
192static UChar sharedEmptyChar;
193UString::BaseString* UString::Rep::nullBaseString;
194UString::BaseString* UString::Rep::emptyBaseString;
195UString* UString::nullUString;
196
197static void initializeStaticBaseString(UString::BaseString& base)
198{
199 base.rc = INT_MAX / 2;
200 base.m_identifierTableAndFlags.setFlag(UString::Rep::StaticFlag);
201 base.checkConsistency();
202}
203
204void initializeUString()
205{
206 UString::Rep::nullBaseString = new UString::BaseString(0, 0);
207 initializeStaticBaseString(*UString::Rep::nullBaseString);
208
209 UString::Rep::emptyBaseString = new UString::BaseString(&sharedEmptyChar, 0);
210 initializeStaticBaseString(*UString::Rep::emptyBaseString);
211
212 UString::nullUString = new UString;
213}
214
215static char* statBuffer = 0; // Only used for debugging via UString::ascii().
216
217PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar* d, int l)
218{
219 UChar* copyD = static_cast<UChar*>(fastMalloc(l * sizeof(UChar)));
220 copyChars(copyD, d, l);
221 return create(copyD, l);
222}
223
224PassRefPtr<UString::Rep> UString::Rep::createFromUTF8(const char* string)
225{
226 if (!string)
227 return &UString::Rep::null();
228
229 size_t length = strlen(string);
230 Vector<UChar, 1024> buffer(length);
231 UChar* p = buffer.data();
232 if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length))
233 return &UString::Rep::null();
234
235 return UString::Rep::createCopying(buffer.data(), p - buffer.data());
236}
237
238PassRefPtr<UString::Rep> UString::Rep::create(UChar* string, int length, PassRefPtr<UString::SharedUChar> sharedBuffer)
239{
240 PassRefPtr<UString::Rep> rep = create(string, length);
241 rep->baseString()->setSharedBuffer(sharedBuffer);
242 rep->checkConsistency();
243 return rep;
244}
245
246UString::SharedUChar* UString::Rep::sharedBuffer()
247{
248 UString::BaseString* base = baseString();
249 if (len < minLengthToShare)
250 return 0;
251
252 return base->sharedBuffer();
253}
254
255void UString::Rep::destroy()
256{
257 checkConsistency();
258
259 // Static null and empty strings can never be destroyed, but we cannot rely on
260 // reference counting, because ref/deref are not thread-safe.
261 if (!isStatic()) {
262 if (identifierTable())
263 Identifier::remove(this);
264
265 UString::BaseString* base = baseString();
266 if (base == this) {
267 if (m_sharedBuffer)
268 m_sharedBuffer->deref();
269 else
270 fastFree(base->buf);
271 } else
272 base->deref();
273
274 delete this;
275 }
276}
277
278// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
279// or anything like that.
280const unsigned PHI = 0x9e3779b9U;
281
282// Paul Hsieh's SuperFastHash
283// http://www.azillionmonkeys.com/qed/hash.html
284unsigned UString::Rep::computeHash(const UChar* s, int len)
285{
286 unsigned l = len;
287 uint32_t hash = PHI;
288 uint32_t tmp;
289
290 int rem = l & 1;
291 l >>= 1;
292
293 // Main loop
294 for (; l > 0; l--) {
295 hash += s[0];
296 tmp = (s[1] << 11) ^ hash;
297 hash = (hash << 16) ^ tmp;
298 s += 2;
299 hash += hash >> 11;
300 }
301
302 // Handle end case
303 if (rem) {
304 hash += s[0];
305 hash ^= hash << 11;
306 hash += hash >> 17;
307 }
308
309 // Force "avalanching" of final 127 bits
310 hash ^= hash << 3;
311 hash += hash >> 5;
312 hash ^= hash << 2;
313 hash += hash >> 15;
314 hash ^= hash << 10;
315
316 // this avoids ever returning a hash code of 0, since that is used to
317 // signal "hash not computed yet", using a value that is likely to be
318 // effectively the same as 0 when the low bits are masked
319 if (hash == 0)
320 hash = 0x80000000;
321
322 return hash;
323}
324
325// Paul Hsieh's SuperFastHash
326// http://www.azillionmonkeys.com/qed/hash.html
327unsigned UString::Rep::computeHash(const char* s, int l)
328{
329 // This hash is designed to work on 16-bit chunks at a time. But since the normal case
330 // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
331 // were 16-bit chunks, which should give matching results
332
333 uint32_t hash = PHI;
334 uint32_t tmp;
335
336 size_t rem = l & 1;
337 l >>= 1;
338
339 // Main loop
340 for (; l > 0; l--) {
341 hash += static_cast<unsigned char>(s[0]);
342 tmp = (static_cast<unsigned char>(s[1]) << 11) ^ hash;
343 hash = (hash << 16) ^ tmp;
344 s += 2;
345 hash += hash >> 11;
346 }
347
348 // Handle end case
349 if (rem) {
350 hash += static_cast<unsigned char>(s[0]);
351 hash ^= hash << 11;
352 hash += hash >> 17;
353 }
354
355 // Force "avalanching" of final 127 bits
356 hash ^= hash << 3;
357 hash += hash >> 5;
358 hash ^= hash << 2;
359 hash += hash >> 15;
360 hash ^= hash << 10;
361
362 // this avoids ever returning a hash code of 0, since that is used to
363 // signal "hash not computed yet", using a value that is likely to be
364 // effectively the same as 0 when the low bits are masked
365 if (hash == 0)
366 hash = 0x80000000;
367
368 return hash;
369}
370
371#ifndef NDEBUG
372void UString::Rep::checkConsistency() const
373{
374 const UString::BaseString* base = baseString();
375
376 // There is no recursion for base strings.
377 ASSERT(base == base->baseString());
378
379 if (isStatic()) {
380 // There are only two static strings: null and empty.
381 ASSERT(!len);
382
383 // Static strings cannot get in identifier tables, because they are globally shared.
384 ASSERT(!identifierTable());
385 }
386
387 // The string fits in buffer.
388 ASSERT(base->usedPreCapacity <= base->preCapacity);
389 ASSERT(base->usedCapacity <= base->capacity);
390 ASSERT(-offset <= base->usedPreCapacity);
391 ASSERT(offset + len <= base->usedCapacity);
392}
393#endif
394
395UString::SharedUChar* UString::BaseString::sharedBuffer()
396{
397 if (!m_sharedBuffer)
398 setSharedBuffer(SharedUChar::create(new OwnFastMallocPtr<UChar>(buf)));
399 return m_sharedBuffer;
400}
401
402void UString::BaseString::setSharedBuffer(PassRefPtr<UString::SharedUChar> sharedBuffer)
403{
404 // The manual steps below are because m_sharedBuffer can't be a RefPtr. m_sharedBuffer
405 // is in a union with another variable to avoid making BaseString any larger.
406 if (m_sharedBuffer)
407 m_sharedBuffer->deref();
408 m_sharedBuffer = sharedBuffer.releaseRef();
409}
410
411bool UString::BaseString::slowIsBufferReadOnly()
412{
413 // The buffer may not be modified as soon as the underlying data has been shared with another class.
414 if (m_sharedBuffer->isShared())
415 return true;
416
417 // At this point, we know it that the underlying buffer isn't shared outside of this base class,
418 // so get rid of m_sharedBuffer.
419 OwnPtr<OwnFastMallocPtr<UChar> > mallocPtr(m_sharedBuffer->release());
420 UChar* unsharedBuf = const_cast<UChar*>(mallocPtr->release());
421 setSharedBuffer(0);
422 preCapacity += (buf - unsharedBuf);
423 buf = unsharedBuf;
424 return false;
425}
426
427// Put these early so they can be inlined.
428static inline size_t expandedSize(size_t capacitySize, size_t precapacitySize)
429{
430 // Combine capacitySize & precapacitySize to produce a single size to allocate,
431 // check that doing so does not result in overflow.
432 size_t size = capacitySize + precapacitySize;
433 if (size < capacitySize)
434 return overflowIndicator();
435
436 // Small Strings (up to 4 pages):
437 // Expand the allocation size to 112.5% of the amount requested. This is largely sicking
438 // to our previous policy, however 112.5% is cheaper to calculate.
439 if (size < 0x4000) {
440 size_t expandedSize = ((size + (size >> 3)) | 15) + 1;
441 // Given the limited range within which we calculate the expansion in this
442 // fashion the above calculation should never overflow.
443 ASSERT(expandedSize >= size);
444 ASSERT(expandedSize < maxUChars());
445 return expandedSize;
446 }
447
448 // Medium Strings (up to 128 pages):
449 // For pages covering multiple pages over-allocation is less of a concern - any unused
450 // space will not be paged in if it is not used, so this is purely a VM overhead. For
451 // these strings allocate 2x the requested size.
452 if (size < 0x80000) {
453 size_t expandedSize = ((size + size) | 0xfff) + 1;
454 // Given the limited range within which we calculate the expansion in this
455 // fashion the above calculation should never overflow.
456 ASSERT(expandedSize >= size);
457 ASSERT(expandedSize < maxUChars());
458 return expandedSize;
459 }
460
461 // Large Strings (to infinity and beyond!):
462 // Revert to our 112.5% policy - probably best to limit the amount of unused VM we allow
463 // any individual string be responsible for.
464 size_t expandedSize = ((size + (size >> 3)) | 0xfff) + 1;
465
466 // Check for overflow - any result that is at least as large as requested (but
467 // still below the limit) is okay.
468 if ((expandedSize >= size) && (expandedSize < maxUChars()))
469 return expandedSize;
470 return overflowIndicator();
471}
472
473static inline bool expandCapacity(UString::Rep* rep, int requiredLength)
474{
475 rep->checkConsistency();
476 ASSERT(!rep->baseString()->isBufferReadOnly());
477
478 UString::BaseString* base = rep->baseString();
479
480 if (requiredLength > base->capacity) {
481 size_t newCapacity = expandedSize(requiredLength, base->preCapacity);
482 UChar* oldBuf = base->buf;
483 base->buf = reallocChars(base->buf, newCapacity);
484 if (!base->buf) {
485 base->buf = oldBuf;
486 return false;
487 }
488 base->capacity = newCapacity - base->preCapacity;
489 }
490 if (requiredLength > base->usedCapacity)
491 base->usedCapacity = requiredLength;
492
493 rep->checkConsistency();
494 return true;
495}
496
497bool UString::Rep::reserveCapacity(int capacity)
498{
499 // If this is an empty string there is no point 'growing' it - just allocate a new one.
500 // If the BaseString is shared with another string that is using more capacity than this
501 // string is, then growing the buffer won't help.
502 // If the BaseString's buffer is readonly, then it isn't allowed to grow.
503 UString::BaseString* base = baseString();
504 if (!base->buf || !base->capacity || (offset + len) != base->usedCapacity || base->isBufferReadOnly())
505 return false;
506
507 // If there is already sufficient capacity, no need to grow!
508 if (capacity <= base->capacity)
509 return true;
510
511 checkConsistency();
512
513 size_t newCapacity = expandedSize(capacity, base->preCapacity);
514 UChar* oldBuf = base->buf;
515 base->buf = reallocChars(base->buf, newCapacity);
516 if (!base->buf) {
517 base->buf = oldBuf;
518 return false;
519 }
520 base->capacity = newCapacity - base->preCapacity;
521
522 checkConsistency();
523 return true;
524}
525
526void UString::expandCapacity(int requiredLength)
527{
528 if (!JSC::expandCapacity(m_rep.get(), requiredLength))
529 makeNull();
530}
531
532void UString::expandPreCapacity(int requiredPreCap)
533{
534 m_rep->checkConsistency();
535 ASSERT(!m_rep->baseString()->isBufferReadOnly());
536
537 BaseString* base = m_rep->baseString();
538
539 if (requiredPreCap > base->preCapacity) {
540 size_t newCapacity = expandedSize(requiredPreCap, base->capacity);
541 int delta = newCapacity - base->capacity - base->preCapacity;
542
543 UChar* newBuf = allocChars(newCapacity);
544 if (!newBuf) {
545 makeNull();
546 return;
547 }
548 copyChars(newBuf + delta, base->buf, base->capacity + base->preCapacity);
549 fastFree(base->buf);
550 base->buf = newBuf;
551
552 base->preCapacity = newCapacity - base->capacity;
553 }
554 if (requiredPreCap > base->usedPreCapacity)
555 base->usedPreCapacity = requiredPreCap;
556
557 m_rep->checkConsistency();
558}
559
560static PassRefPtr<UString::Rep> createRep(const char* c)
561{
562 if (!c)
563 return &UString::Rep::null();
564
565 if (!c[0])
566 return &UString::Rep::empty();
567
568 size_t length = strlen(c);
569 UChar* d = allocChars(length);
570 if (!d)
571 return &UString::Rep::null();
572 else {
573 for (size_t i = 0; i < length; i++)
574 d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
575 return UString::Rep::create(d, static_cast<int>(length));
576 }
577
578}
579
580UString::UString(const char* c)
581 : m_rep(createRep(c))
582{
583}
584
585UString::UString(const UChar* c, int length)
586{
587 if (length == 0)
588 m_rep = &Rep::empty();
589 else
590 m_rep = Rep::createCopying(c, length);
591}
592
593UString::UString(UChar* c, int length, bool copy)
594{
595 if (length == 0)
596 m_rep = &Rep::empty();
597 else if (copy)
598 m_rep = Rep::createCopying(c, length);
599 else
600 m_rep = Rep::create(c, length);
601}
602
603UString::UString(const Vector<UChar>& buffer)
604{
605 if (!buffer.size())
606 m_rep = &Rep::empty();
607 else
608 m_rep = Rep::createCopying(buffer.data(), buffer.size());
609}
610
611static ALWAYS_INLINE int newCapacityWithOverflowCheck(const int currentCapacity, const int extendLength, const bool plusOne = false)
612{
613 ASSERT_WITH_MESSAGE(extendLength >= 0, "extendedLength = %d", extendLength);
614
615 const int plusLength = plusOne ? 1 : 0;
616 if (currentCapacity > std::numeric_limits<int>::max() - extendLength - plusLength)
617 CRASH();
618
619 return currentCapacity + extendLength + plusLength;
620}
621
622static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const UChar* tData, int tSize)
623{
624 RefPtr<UString::Rep> rep = r;
625
626 rep->checkConsistency();
627
628 int thisSize = rep->size();
629 int thisOffset = rep->offset;
630 int length = thisSize + tSize;
631 UString::BaseString* base = rep->baseString();
632
633 // possible cases:
634 if (tSize == 0) {
635 // t is empty
636 } else if (thisSize == 0) {
637 // this is empty
638 rep = UString::Rep::createCopying(tData, tSize);
639 } else if (rep == base && !base->isShared()) {
640 // this is direct and has refcount of 1 (so we can just alter it directly)
641 if (!expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length)))
642 rep = &UString::Rep::null();
643 if (rep->data()) {
644 copyChars(rep->data() + thisSize, tData, tSize);
645 rep->len = length;
646 rep->_hash = 0;
647 }
648 } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) {
649 // this reaches the end of the buffer - extend it if it's long enough to append to
650 if (!expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length)))
651 rep = &UString::Rep::null();
652 if (rep->data()) {
653 copyChars(rep->data() + thisSize, tData, tSize);
654 rep = UString::Rep::create(rep, 0, length);
655 }
656 } else {
657 // This is shared in some way that prevents us from modifying base, so we must make a whole new string.
658 size_t newCapacity = expandedSize(length, 0);
659 UChar* d = allocChars(newCapacity);
660 if (!d)
661 rep = &UString::Rep::null();
662 else {
663 copyChars(d, rep->data(), thisSize);
664 copyChars(d + thisSize, tData, tSize);
665 rep = UString::Rep::create(d, length);
666 rep->baseString()->capacity = newCapacity;
667 }
668 }
669
670 rep->checkConsistency();
671
672 return rep.release();
673}
674
675static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const char* t)
676{
677 RefPtr<UString::Rep> rep = r;
678
679 rep->checkConsistency();
680
681 int thisSize = rep->size();
682 int thisOffset = rep->offset;
683 int tSize = static_cast<int>(strlen(t));
684 int length = thisSize + tSize;
685 UString::BaseString* base = rep->baseString();
686
687 // possible cases:
688 if (thisSize == 0) {
689 // this is empty
690 rep = createRep(t);
691 } else if (tSize == 0) {
692 // t is empty, we'll just return *this below.
693 } else if (rep == base && !base->isShared()) {
694 // this is direct and has refcount of 1 (so we can just alter it directly)
695 expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length));
696 UChar* d = rep->data();
697 if (d) {
698 for (int i = 0; i < tSize; ++i)
699 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend
700 rep->len = length;
701 rep->_hash = 0;
702 }
703 } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) {
704 // this string reaches the end of the buffer - extend it
705 expandCapacity(rep.get(), newCapacityWithOverflowCheck(thisOffset, length));
706 UChar* d = rep->data();
707 if (d) {
708 for (int i = 0; i < tSize; ++i)
709 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend
710 rep = UString::Rep::create(rep, 0, length);
711 }
712 } else {
713 // This is shared in some way that prevents us from modifying base, so we must make a whole new string.
714 size_t newCapacity = expandedSize(length, 0);
715 UChar* d = allocChars(newCapacity);
716 if (!d)
717 rep = &UString::Rep::null();
718 else {
719 copyChars(d, rep->data(), thisSize);
720 for (int i = 0; i < tSize; ++i)
721 d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend
722 rep = UString::Rep::create(d, length);
723 rep->baseString()->capacity = newCapacity;
724 }
725 }
726
727 rep->checkConsistency();
728
729 return rep.release();
730}
731
732PassRefPtr<UString::Rep> concatenate(UString::Rep* a, UString::Rep* b)
733{
734 a->checkConsistency();
735 b->checkConsistency();
736
737 int aSize = a->size();
738 int bSize = b->size();
739 int aOffset = a->offset;
740
741 // possible cases:
742
743 UString::BaseString* aBase = a->baseString();
744 if (bSize == 1 && aOffset + aSize == aBase->usedCapacity && aOffset + aSize < aBase->capacity && !aBase->isBufferReadOnly()) {
745 // b is a single character (common fast case)
746 ++aBase->usedCapacity;
747 a->data()[aSize] = b->data()[0];
748 return UString::Rep::create(a, 0, aSize + 1);
749 }
750
751 // a is empty
752 if (aSize == 0)
753 return b;
754 // b is empty
755 if (bSize == 0)
756 return a;
757
758 int bOffset = b->offset;
759 int length = aSize + bSize;
760
761 UString::BaseString* bBase = b->baseString();
762 if (aOffset + aSize == aBase->usedCapacity && aSize >= minShareSize && 4 * aSize >= bSize
763 && (-bOffset != bBase->usedPreCapacity || aSize >= bSize) && !aBase->isBufferReadOnly()) {
764 // - a reaches the end of its buffer so it qualifies for shared append
765 // - also, it's at least a quarter the length of b - appending to a much shorter
766 // string does more harm than good
767 // - however, if b qualifies for prepend and is longer than a, we'd rather prepend
768
769 UString x(a);
770 x.expandCapacity(newCapacityWithOverflowCheck(aOffset, length));
771 if (!a->data() || !x.data())
772 return 0;
773 copyChars(a->data() + aSize, b->data(), bSize);
774 PassRefPtr<UString::Rep> result = UString::Rep::create(a, 0, length);
775
776 a->checkConsistency();
777 b->checkConsistency();
778 result->checkConsistency();
779
780 return result;
781 }
782
783 if (-bOffset == bBase->usedPreCapacity && bSize >= minShareSize && 4 * bSize >= aSize && !bBase->isBufferReadOnly()) {
784 // - b reaches the beginning of its buffer so it qualifies for shared prepend
785 // - also, it's at least a quarter the length of a - prepending to a much shorter
786 // string does more harm than good
787 UString y(b);
788 y.expandPreCapacity(-bOffset + aSize);
789 if (!b->data() || !y.data())
790 return 0;
791 copyChars(b->data() - aSize, a->data(), aSize);
792 PassRefPtr<UString::Rep> result = UString::Rep::create(b, -aSize, length);
793
794 a->checkConsistency();
795 b->checkConsistency();
796 result->checkConsistency();
797
798 return result;
799 }
800
801 // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string
802 size_t newCapacity = expandedSize(length, 0);
803 UChar* d = allocChars(newCapacity);
804 if (!d)
805 return 0;
806 copyChars(d, a->data(), aSize);
807 copyChars(d + aSize, b->data(), bSize);
808 PassRefPtr<UString::Rep> result = UString::Rep::create(d, length);
809 result->baseString()->capacity = newCapacity;
810
811 a->checkConsistency();
812 b->checkConsistency();
813 result->checkConsistency();
814
815 return result;
816}
817
818PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, int i)
819{
820 UChar buf[1 + sizeof(i) * 3];
821 UChar* end = buf + sizeof(buf) / sizeof(UChar);
822 UChar* p = end;
823
824 if (i == 0)
825 *--p = '0';
826 else if (i == INT_MIN) {
827 char minBuf[1 + sizeof(i) * 3];
828 sprintf(minBuf, "%d", INT_MIN);
829 return concatenate(rep, minBuf);
830 } else {
831 bool negative = false;
832 if (i < 0) {
833 negative = true;
834 i = -i;
835 }
836 while (i) {
837 *--p = static_cast<unsigned short>((i % 10) + '0');
838 i /= 10;
839 }
840 if (negative)
841 *--p = '-';
842 }
843
844 return concatenate(rep, p, static_cast<int>(end - p));
845
846}
847
848PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, double d)
849{
850 // avoid ever printing -NaN, in JS conceptually there is only one NaN value
851 if (isnan(d))
852 return concatenate(rep, "NaN");
853
854 if (d == 0.0) // stringify -0 as 0
855 d = 0.0;
856
857 char buf[80];
858 int decimalPoint;
859 int sign;
860
861 char result[80];
862 WTF::dtoa(result, d, 0, &decimalPoint, &sign, NULL);
863 int length = static_cast<int>(strlen(result));
864
865 int i = 0;
866 if (sign)
867 buf[i++] = '-';
868
869 if (decimalPoint <= 0 && decimalPoint > -6) {
870 buf[i++] = '0';
871 buf[i++] = '.';
872 for (int j = decimalPoint; j < 0; j++)
873 buf[i++] = '0';
874 strcpy(buf + i, result);
875 } else if (decimalPoint <= 21 && decimalPoint > 0) {
876 if (length <= decimalPoint) {
877 strcpy(buf + i, result);
878 i += length;
879 for (int j = 0; j < decimalPoint - length; j++)
880 buf[i++] = '0';
881 buf[i] = '\0';
882 } else {
883 strncpy(buf + i, result, decimalPoint);
884 i += decimalPoint;
885 buf[i++] = '.';
886 strcpy(buf + i, result + decimalPoint);
887 }
888 } else if (result[0] < '0' || result[0] > '9')
889 strcpy(buf + i, result);
890 else {
891 buf[i++] = result[0];
892 if (length > 1) {
893 buf[i++] = '.';
894 strcpy(buf + i, result + 1);
895 i += length - 1;
896 }
897
898 buf[i++] = 'e';
899 buf[i++] = (decimalPoint >= 0) ? '+' : '-';
900 // decimalPoint can't be more than 3 digits decimal given the
901 // nature of float representation
902 int exponential = decimalPoint - 1;
903 if (exponential < 0)
904 exponential = -exponential;
905 if (exponential >= 100)
906 buf[i++] = static_cast<char>('0' + exponential / 100);
907 if (exponential >= 10)
908 buf[i++] = static_cast<char>('0' + (exponential % 100) / 10);
909 buf[i++] = static_cast<char>('0' + exponential % 10);
910 buf[i++] = '\0';
911 }
912
913 return concatenate(rep, buf);
914}
915
916UString UString::from(int i)
917{
918 UChar buf[1 + sizeof(i) * 3];
919 UChar* end = buf + sizeof(buf) / sizeof(UChar);
920 UChar* p = end;
921
922 if (i == 0)
923 *--p = '0';
924 else if (i == INT_MIN) {
925 char minBuf[1 + sizeof(i) * 3];
926 sprintf(minBuf, "%d", INT_MIN);
927 return UString(minBuf);
928 } else {
929 bool negative = false;
930 if (i < 0) {
931 negative = true;
932 i = -i;
933 }
934 while (i) {
935 *--p = static_cast<unsigned short>((i % 10) + '0');
936 i /= 10;
937 }
938 if (negative)
939 *--p = '-';
940 }
941
942 return UString(p, static_cast<int>(end - p));
943}
944
945UString UString::from(unsigned int u)
946{
947 UChar buf[sizeof(u) * 3];
948 UChar* end = buf + sizeof(buf) / sizeof(UChar);
949 UChar* p = end;
950
951 if (u == 0)
952 *--p = '0';
953 else {
954 while (u) {
955 *--p = static_cast<unsigned short>((u % 10) + '0');
956 u /= 10;
957 }
958 }
959
960 return UString(p, static_cast<int>(end - p));
961}
962
963UString UString::from(long l)
964{
965 UChar buf[1 + sizeof(l) * 3];
966 UChar* end = buf + sizeof(buf) / sizeof(UChar);
967 UChar* p = end;
968
969 if (l == 0)
970 *--p = '0';
971 else if (l == LONG_MIN) {
972 char minBuf[1 + sizeof(l) * 3];
973 sprintf(minBuf, "%ld", LONG_MIN);
974 return UString(minBuf);
975 } else {
976 bool negative = false;
977 if (l < 0) {
978 negative = true;
979 l = -l;
980 }
981 while (l) {
982 *--p = static_cast<unsigned short>((l % 10) + '0');
983 l /= 10;
984 }
985 if (negative)
986 *--p = '-';
987 }
988
989 return UString(p, static_cast<int>(end - p));
990}
991
992UString UString::from(double d)
993{
994 // avoid ever printing -NaN, in JS conceptually there is only one NaN value
995 if (isnan(d))
996 return "NaN";
997
998 char buf[80];
999 int decimalPoint;
1000 int sign;
1001
1002 char result[80];
1003 WTF::dtoa(result, d, 0, &decimalPoint, &sign, NULL);
1004 int length = static_cast<int>(strlen(result));
1005
1006 int i = 0;
1007 if (sign)
1008 buf[i++] = '-';
1009
1010 if (decimalPoint <= 0 && decimalPoint > -6) {
1011 buf[i++] = '0';
1012 buf[i++] = '.';
1013 for (int j = decimalPoint; j < 0; j++)
1014 buf[i++] = '0';
1015 strcpy(buf + i, result);
1016 } else if (decimalPoint <= 21 && decimalPoint > 0) {
1017 if (length <= decimalPoint) {
1018 strcpy(buf + i, result);
1019 i += length;
1020 for (int j = 0; j < decimalPoint - length; j++)
1021 buf[i++] = '0';
1022 buf[i] = '\0';
1023 } else {
1024 strncpy(buf + i, result, decimalPoint);
1025 i += decimalPoint;
1026 buf[i++] = '.';
1027 strcpy(buf + i, result + decimalPoint);
1028 }
1029 } else if (result[0] < '0' || result[0] > '9')
1030 strcpy(buf + i, result);
1031 else {
1032 buf[i++] = result[0];
1033 if (length > 1) {
1034 buf[i++] = '.';
1035 strcpy(buf + i, result + 1);
1036 i += length - 1;
1037 }
1038
1039 buf[i++] = 'e';
1040 buf[i++] = (decimalPoint >= 0) ? '+' : '-';
1041 // decimalPoint can't be more than 3 digits decimal given the
1042 // nature of float representation
1043 int exponential = decimalPoint - 1;
1044 if (exponential < 0)
1045 exponential = -exponential;
1046 if (exponential >= 100)
1047 buf[i++] = static_cast<char>('0' + exponential / 100);
1048 if (exponential >= 10)
1049 buf[i++] = static_cast<char>('0' + (exponential % 100) / 10);
1050 buf[i++] = static_cast<char>('0' + exponential % 10);
1051 buf[i++] = '\0';
1052 }
1053
1054 return UString(buf);
1055}
1056
1057UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const
1058{
1059 m_rep->checkConsistency();
1060
1061 if (rangeCount == 1 && separatorCount == 0) {
1062 int thisSize = size();
1063 int position = substringRanges[0].position;
1064 int length = substringRanges[0].length;
1065 if (position <= 0 && length >= thisSize)
1066 return *this;
1067 return UString::Rep::create(m_rep, max(0, position), min(thisSize, length));
1068 }
1069
1070 int totalLength = 0;
1071 for (int i = 0; i < rangeCount; i++)
1072 totalLength += substringRanges[i].length;
1073 for (int i = 0; i < separatorCount; i++)
1074 totalLength += separators[i].size();
1075
1076 if (totalLength == 0)
1077 return "";
1078
1079 UChar* buffer = allocChars(totalLength);
1080 if (!buffer)
1081 return null();
1082
1083 int maxCount = max(rangeCount, separatorCount);
1084 int bufferPos = 0;
1085 for (int i = 0; i < maxCount; i++) {
1086 if (i < rangeCount) {
1087 copyChars(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length);
1088 bufferPos += substringRanges[i].length;
1089 }
1090 if (i < separatorCount) {
1091 copyChars(buffer + bufferPos, separators[i].data(), separators[i].size());
1092 bufferPos += separators[i].size();
1093 }
1094 }
1095
1096 return UString::Rep::create(buffer, totalLength);
1097}
1098
1099UString UString::replaceRange(int rangeStart, int rangeLength, const UString& replacement) const
1100{
1101 m_rep->checkConsistency();
1102
1103 int replacementLength = replacement.size();
1104 int totalLength = size() - rangeLength + replacementLength;
1105 if (totalLength == 0)
1106 return "";
1107
1108 UChar* buffer = allocChars(totalLength);
1109 if (!buffer)
1110 return null();
1111
1112 copyChars(buffer, data(), rangeStart);
1113 copyChars(buffer + rangeStart, replacement.data(), replacementLength);
1114 int rangeEnd = rangeStart + rangeLength;
1115 copyChars(buffer + rangeStart + replacementLength, data() + rangeEnd, size() - rangeEnd);
1116
1117 return UString::Rep::create(buffer, totalLength);
1118}
1119
1120
1121UString& UString::append(const UString &t)
1122{
1123 m_rep->checkConsistency();
1124 t.rep()->checkConsistency();
1125
1126 int thisSize = size();
1127 int thisOffset = m_rep->offset;
1128 int tSize = t.size();
1129 int length = thisSize + tSize;
1130 BaseString* base = m_rep->baseString();
1131
1132 // possible cases:
1133 if (thisSize == 0) {
1134 // this is empty
1135 *this = t;
1136 } else if (tSize == 0) {
1137 // t is empty
1138 } else if (m_rep == base && !base->isShared()) {
1139 // this is direct and has refcount of 1 (so we can just alter it directly)
1140 expandCapacity(newCapacityWithOverflowCheck(thisOffset, length));
1141 if (data()) {
1142 copyChars(m_rep->data() + thisSize, t.data(), tSize);
1143 m_rep->len = length;
1144 m_rep->_hash = 0;
1145 }
1146 } else if (thisOffset + thisSize == base->usedCapacity && thisSize >= minShareSize && !base->isBufferReadOnly()) {
1147 // this reaches the end of the buffer - extend it if it's long enough to append to
1148 expandCapacity(newCapacityWithOverflowCheck(thisOffset, length));
1149 if (data()) {
1150 copyChars(m_rep->data() + thisSize, t.data(), tSize);
1151 m_rep = Rep::create(m_rep, 0, length);
1152 }
1153 } else {
1154 // This is shared in some way that prevents us from modifying base, so we must make a whole new string.
1155 size_t newCapacity = expandedSize(length, 0);
1156 UChar* d = allocChars(newCapacity);
1157 if (!d)
1158 makeNull();
1159 else {
1160 copyChars(d, data(), thisSize);
1161 copyChars(d + thisSize, t.data(), tSize);
1162 m_rep = Rep::create(d, length);
1163 m_rep->baseString()->capacity = newCapacity;
1164 }
1165 }
1166
1167 m_rep->checkConsistency();
1168 t.rep()->checkConsistency();
1169
1170 return *this;
1171}
1172
1173UString& UString::append(const UChar* tData, int tSize)
1174{
1175 m_rep = concatenate(m_rep.release(), tData, tSize);
1176 return *this;
1177}
1178
1179UString& UString::appendNumeric(int i)
1180{
1181 m_rep = concatenate(rep(), i);
1182 return *this;
1183}
1184
1185UString& UString::appendNumeric(double d)
1186{
1187 m_rep = concatenate(rep(), d);
1188 return *this;
1189}
1190
1191UString& UString::append(const char* t)
1192{
1193 m_rep = concatenate(m_rep.release(), t);
1194 return *this;
1195}
1196
1197UString& UString::append(UChar c)
1198{
1199 m_rep->checkConsistency();
1200
1201 int thisOffset = m_rep->offset;
1202 int length = size();
1203 BaseString* base = m_rep->baseString();
1204
1205 // possible cases:
1206 if (length == 0) {
1207 // this is empty - must make a new m_rep because we don't want to pollute the shared empty one
1208 size_t newCapacity = expandedSize(1, 0);
1209 UChar* d = allocChars(newCapacity);
1210 if (!d)
1211 makeNull();
1212 else {
1213 d[0] = c;
1214 m_rep = Rep::create(d, 1);
1215 m_rep->baseString()->capacity = newCapacity;
1216 }
1217 } else if (m_rep == base && !base->isShared()) {
1218 // this is direct and has refcount of 1 (so we can just alter it directly)
1219 expandCapacity(newCapacityWithOverflowCheck(thisOffset, length, true));
1220 UChar* d = m_rep->data();
1221 if (d) {
1222 d[length] = c;
1223 m_rep->len = length + 1;
1224 m_rep->_hash = 0;
1225 }
1226 } else if (thisOffset + length == base->usedCapacity && length >= minShareSize && !base->isBufferReadOnly()) {
1227 // this reaches the end of the string - extend it and share
1228 expandCapacity(newCapacityWithOverflowCheck(thisOffset, length, true));
1229 UChar* d = m_rep->data();
1230 if (d) {
1231 d[length] = c;
1232 m_rep = Rep::create(m_rep, 0, length + 1);
1233 }
1234 } else {
1235 // This is shared in some way that prevents us from modifying base, so we must make a whole new string.
1236 size_t newCapacity = expandedSize(length + 1, 0);
1237 UChar* d = allocChars(newCapacity);
1238 if (!d)
1239 makeNull();
1240 else {
1241 copyChars(d, data(), length);
1242 d[length] = c;
1243 m_rep = Rep::create(d, length + 1);
1244 m_rep->baseString()->capacity = newCapacity;
1245 }
1246 }
1247
1248 m_rep->checkConsistency();
1249
1250 return *this;
1251}
1252
1253bool UString::getCString(CStringBuffer& buffer) const
1254{
1255 int length = size();
1256 int neededSize = length + 1;
1257 buffer.resize(neededSize);
1258 char* buf = buffer.data();
1259
1260 UChar ored = 0;
1261 const UChar* p = data();
1262 char* q = buf;
1263 const UChar* limit = p + length;
1264 while (p != limit) {
1265 UChar c = p[0];
1266 ored |= c;
1267 *q = static_cast<char>(c);
1268 ++p;
1269 ++q;
1270 }
1271 *q = '\0';
1272
1273 return !(ored & 0xFF00);
1274}
1275
1276char* UString::ascii() const
1277{
1278 int length = size();
1279 int neededSize = length + 1;
1280 delete[] statBuffer;
1281 statBuffer = new char[neededSize];
1282
1283 const UChar* p = data();
1284 char* q = statBuffer;
1285 const UChar* limit = p + length;
1286 while (p != limit) {
1287 *q = static_cast<char>(p[0]);
1288 ++p;
1289 ++q;
1290 }
1291 *q = '\0';
1292
1293 return statBuffer;
1294}
1295
1296UString& UString::operator=(const char* c)
1297{
1298 if (!c) {
1299 m_rep = &Rep::null();
1300 return *this;
1301 }
1302
1303 if (!c[0]) {
1304 m_rep = &Rep::empty();
1305 return *this;
1306 }
1307
1308 int l = static_cast<int>(strlen(c));
1309 UChar* d;
1310 BaseString* base = m_rep->baseString();
1311 if (!base->isShared() && l <= base->capacity && m_rep == base && m_rep->offset == 0 && base->preCapacity == 0) {
1312 d = base->buf;
1313 m_rep->_hash = 0;
1314 m_rep->len = l;
1315 } else {
1316 d = allocChars(l);
1317 if (!d) {
1318 makeNull();
1319 return *this;
1320 }
1321 m_rep = Rep::create(d, l);
1322 }
1323 for (int i = 0; i < l; i++)
1324 d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
1325
1326 return *this;
1327}
1328
1329bool UString::is8Bit() const
1330{
1331 const UChar* u = data();
1332 const UChar* limit = u + size();
1333 while (u < limit) {
1334 if (u[0] > 0xFF)
1335 return false;
1336 ++u;
1337 }
1338
1339 return true;
1340}
1341
1342UChar UString::operator[](int pos) const
1343{
1344 if (pos >= size())
1345 return '\0';
1346 return data()[pos];
1347}
1348
1349double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
1350{
1351 if (size() == 1) {
1352 UChar c = data()[0];
1353 if (isASCIIDigit(c))
1354 return c - '0';
1355 if (isASCIISpace(c) && tolerateEmptyString)
1356 return 0;
1357 return NaN;
1358 }
1359
1360 // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk
1361 // after the number, so this is too strict a check.
1362 CStringBuffer s;
1363 if (!getCString(s))
1364 return NaN;
1365 const char* c = s.data();
1366
1367 // skip leading white space
1368 while (isASCIISpace(*c))
1369 c++;
1370
1371 // empty string ?
1372 if (*c == '\0')
1373 return tolerateEmptyString ? 0.0 : NaN;
1374
1375 double d;
1376
1377 // hex number ?
1378 if (*c == '0' && (*(c + 1) == 'x' || *(c + 1) == 'X')) {
1379 const char* firstDigitPosition = c + 2;
1380 c++;
1381 d = 0.0;
1382 while (*(++c)) {
1383 if (*c >= '0' && *c <= '9')
1384 d = d * 16.0 + *c - '0';
1385 else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f'))
1386 d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0;
1387 else
1388 break;
1389 }
1390
1391 if (d >= mantissaOverflowLowerBound)
1392 d = parseIntOverflow(firstDigitPosition, c - firstDigitPosition, 16);
1393 } else {
1394 // regular number ?
1395 char* end;
1396 d = WTF::strtod(c, &end);
1397 if ((d != 0.0 || end != c) && d != Inf && d != -Inf) {
1398 c = end;
1399 } else {
1400 double sign = 1.0;
1401
1402 if (*c == '+')
1403 c++;
1404 else if (*c == '-') {
1405 sign = -1.0;
1406 c++;
1407 }
1408
1409 // We used strtod() to do the conversion. However, strtod() handles
1410 // infinite values slightly differently than JavaScript in that it
1411 // converts the string "inf" with any capitalization to infinity,
1412 // whereas the ECMA spec requires that it be converted to NaN.
1413
1414 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') {
1415 d = sign * Inf;
1416 c += 8;
1417 } else if ((d == Inf || d == -Inf) && *c != 'I' && *c != 'i')
1418 c = end;
1419 else
1420 return NaN;
1421 }
1422 }
1423
1424 // allow trailing white space
1425 while (isASCIISpace(*c))
1426 c++;
1427 // don't allow anything after - unless tolerant=true
1428 if (!tolerateTrailingJunk && *c != '\0')
1429 d = NaN;
1430
1431 return d;
1432}
1433
1434double UString::toDouble(bool tolerateTrailingJunk) const
1435{
1436 return toDouble(tolerateTrailingJunk, true);
1437}
1438
1439double UString::toDouble() const
1440{
1441 return toDouble(false, true);
1442}
1443
1444uint32_t UString::toUInt32(bool* ok) const
1445{
1446 double d = toDouble();
1447 bool b = true;
1448
1449 if (d != static_cast<uint32_t>(d)) {
1450 b = false;
1451 d = 0;
1452 }
1453
1454 if (ok)
1455 *ok = b;
1456
1457 return static_cast<uint32_t>(d);
1458}
1459
1460uint32_t UString::toUInt32(bool* ok, bool tolerateEmptyString) const
1461{
1462 double d = toDouble(false, tolerateEmptyString);
1463 bool b = true;
1464
1465 if (d != static_cast<uint32_t>(d)) {
1466 b = false;
1467 d = 0;
1468 }
1469
1470 if (ok)
1471 *ok = b;
1472
1473 return static_cast<uint32_t>(d);
1474}
1475
1476uint32_t UString::toStrictUInt32(bool* ok) const
1477{
1478 if (ok)
1479 *ok = false;
1480
1481 // Empty string is not OK.
1482 int len = m_rep->len;
1483 if (len == 0)
1484 return 0;
1485 const UChar* p = m_rep->data();
1486 unsigned short c = p[0];
1487
1488 // If the first digit is 0, only 0 itself is OK.
1489 if (c == '0') {
1490 if (len == 1 && ok)
1491 *ok = true;
1492 return 0;
1493 }
1494
1495 // Convert to UInt32, checking for overflow.
1496 uint32_t i = 0;
1497 while (1) {
1498 // Process character, turning it into a digit.
1499 if (c < '0' || c > '9')
1500 return 0;
1501 const unsigned d = c - '0';
1502
1503 // Multiply by 10, checking for overflow out of 32 bits.
1504 if (i > 0xFFFFFFFFU / 10)
1505 return 0;
1506 i *= 10;
1507
1508 // Add in the digit, checking for overflow out of 32 bits.
1509 const unsigned max = 0xFFFFFFFFU - d;
1510 if (i > max)
1511 return 0;
1512 i += d;
1513
1514 // Handle end of string.
1515 if (--len == 0) {
1516 if (ok)
1517 *ok = true;
1518 return i;
1519 }
1520
1521 // Get next character.
1522 c = *(++p);
1523 }
1524}
1525
1526int UString::find(const UString& f, int pos) const
1527{
1528 int fsz = f.size();
1529
1530 if (pos < 0)
1531 pos = 0;
1532
1533 if (fsz == 1) {
1534 UChar ch = f[0];
1535 const UChar* end = data() + size();
1536 for (const UChar* c = data() + pos; c < end; c++) {
1537 if (*c == ch)
1538 return static_cast<int>(c - data());
1539 }
1540 return -1;
1541 }
1542
1543 int sz = size();
1544 if (sz < fsz)
1545 return -1;
1546 if (fsz == 0)
1547 return pos;
1548 const UChar* end = data() + sz - fsz;
1549 int fsizeminusone = (fsz - 1) * sizeof(UChar);
1550 const UChar* fdata = f.data();
1551 unsigned short fchar = fdata[0];
1552 ++fdata;
1553 for (const UChar* c = data() + pos; c <= end; c++) {
1554 if (c[0] == fchar && !memcmp(c + 1, fdata, fsizeminusone))
1555 return static_cast<int>(c - data());
1556 }
1557
1558 return -1;
1559}
1560
1561int UString::find(UChar ch, int pos) const
1562{
1563 if (pos < 0)
1564 pos = 0;
1565 const UChar* end = data() + size();
1566 for (const UChar* c = data() + pos; c < end; c++) {
1567 if (*c == ch)
1568 return static_cast<int>(c - data());
1569 }
1570
1571 return -1;
1572}
1573
1574int UString::rfind(const UString& f, int pos) const
1575{
1576 int sz = size();
1577 int fsz = f.size();
1578 if (sz < fsz)
1579 return -1;
1580 if (pos < 0)
1581 pos = 0;
1582 if (pos > sz - fsz)
1583 pos = sz - fsz;
1584 if (fsz == 0)
1585 return pos;
1586 int fsizeminusone = (fsz - 1) * sizeof(UChar);
1587 const UChar* fdata = f.data();
1588 for (const UChar* c = data() + pos; c >= data(); c--) {
1589 if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone))
1590 return static_cast<int>(c - data());
1591 }
1592
1593 return -1;
1594}
1595
1596int UString::rfind(UChar ch, int pos) const
1597{
1598 if (isEmpty())
1599 return -1;
1600 if (pos + 1 >= size())
1601 pos = size() - 1;
1602 for (const UChar* c = data() + pos; c >= data(); c--) {
1603 if (*c == ch)
1604 return static_cast<int>(c - data());
1605 }
1606
1607 return -1;
1608}
1609
1610UString UString::substr(int pos, int len) const
1611{
1612 int s = size();
1613
1614 if (pos < 0)
1615 pos = 0;
1616 else if (pos >= s)
1617 pos = s;
1618 if (len < 0)
1619 len = s;
1620 if (pos + len >= s)
1621 len = s - pos;
1622
1623 if (pos == 0 && len == s)
1624 return *this;
1625
1626 return UString(Rep::create(m_rep, pos, len));
1627}
1628
1629bool operator==(const UString& s1, const char *s2)
1630{
1631 if (s2 == 0)
1632 return s1.isEmpty();
1633
1634 const UChar* u = s1.data();
1635 const UChar* uend = u + s1.size();
1636 while (u != uend && *s2) {
1637 if (u[0] != (unsigned char)*s2)
1638 return false;
1639 s2++;
1640 u++;
1641 }
1642
1643 return u == uend && *s2 == 0;
1644}
1645
1646bool operator<(const UString& s1, const UString& s2)
1647{
1648 const int l1 = s1.size();
1649 const int l2 = s2.size();
1650 const int lmin = l1 < l2 ? l1 : l2;
1651 const UChar* c1 = s1.data();
1652 const UChar* c2 = s2.data();
1653 int l = 0;
1654 while (l < lmin && *c1 == *c2) {
1655 c1++;
1656 c2++;
1657 l++;
1658 }
1659 if (l < lmin)
1660 return (c1[0] < c2[0]);
1661
1662 return (l1 < l2);
1663}
1664
1665bool operator>(const UString& s1, const UString& s2)
1666{
1667 const int l1 = s1.size();
1668 const int l2 = s2.size();
1669 const int lmin = l1 < l2 ? l1 : l2;
1670 const UChar* c1 = s1.data();
1671 const UChar* c2 = s2.data();
1672 int l = 0;
1673 while (l < lmin && *c1 == *c2) {
1674 c1++;
1675 c2++;
1676 l++;
1677 }
1678 if (l < lmin)
1679 return (c1[0] > c2[0]);
1680
1681 return (l1 > l2);
1682}
1683
1684int compare(const UString& s1, const UString& s2)
1685{
1686 const int l1 = s1.size();
1687 const int l2 = s2.size();
1688 const int lmin = l1 < l2 ? l1 : l2;
1689 const UChar* c1 = s1.data();
1690 const UChar* c2 = s2.data();
1691 int l = 0;
1692 while (l < lmin && *c1 == *c2) {
1693 c1++;
1694 c2++;
1695 l++;
1696 }
1697
1698 if (l < lmin)
1699 return (c1[0] > c2[0]) ? 1 : -1;
1700
1701 if (l1 == l2)
1702 return 0;
1703
1704 return (l1 > l2) ? 1 : -1;
1705}
1706
1707bool equal(const UString::Rep* r, const UString::Rep* b)
1708{
1709 int length = r->len;
1710 if (length != b->len)
1711 return false;
1712 const UChar* d = r->data();
1713 const UChar* s = b->data();
1714 for (int i = 0; i != length; ++i) {
1715 if (d[i] != s[i])
1716 return false;
1717 }
1718 return true;
1719}
1720
1721CString UString::UTF8String(bool strict) const
1722{
1723 // Allocate a buffer big enough to hold all the characters.
1724 const int length = size();
1725 Vector<char, 1024> buffer(length * 3);
1726
1727 // Convert to runs of 8-bit characters.
1728 char* p = buffer.data();
1729 const UChar* d = reinterpret_cast<const UChar*>(&data()[0]);
1730 ConversionResult result = convertUTF16ToUTF8(&d, d + length, &p, p + buffer.size(), strict);
1731 if (result != conversionOK)
1732 return CString();
1733
1734 return CString(buffer.data(), p - buffer.data());
1735}
1736
1737// For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X.
1738NEVER_INLINE void UString::makeNull()
1739{
1740 m_rep = &Rep::null();
1741}
1742
1743// For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X.
1744NEVER_INLINE UString::Rep* UString::nullRep()
1745{
1746 return &Rep::null();
1747}
1748
1749} // namespace JSC
Note: See TracBrowser for help on using the repository browser.