source: webkit/trunk/JavaScriptCore/kjs/ustring.cpp@ 37799

Last change on this file since 37799 was 37415, checked in by [email protected], 17 years ago

JavaScriptCore:

2008-10-08 Maciej Stachowiak <[email protected]>

Reviewed by Oliver Hunt.


  • correctly handle appending -0 to a string, it should stringify as just 0
  • kjs/ustring.cpp: (JSC::concatenate):

LayoutTests:

2008-10-08 Maciej Stachowiak <[email protected]>

Reviewed by Oliver Hunt.

  • added test case for: correctly handle appending -0 to a string, it should stringify as just 0 (added to existing test)


  • fast/js/number-toString-expected.txt:
  • fast/js/resources/number-toString.js:
  • updated results in light of above fix


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