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

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

JavaScriptCore:

  • JavaScriptCore part of <rdar://problem/6121636> Make fast*alloc() abort() on failure and add "try" variants that return NULL on failure.

Reviewed by Darin Adler.

  • JavaScriptCore.exp: Exported tryFastCalloc().
  • VM/RegisterFile.h: (KJS::RegisterFile::RegisterFile): Removed an ASSERT().
  • kjs/JSArray.cpp: (KJS::JSArray::putSlowCase): Changed to use tryFastRealloc(). (KJS::JSArray::increaseVectorLength): Ditto.
  • kjs/ustring.cpp: (KJS::allocChars): Changed to use tryFastMalloc(). (KJS::reallocChars): Changed to use tryFastRealloc().
  • wtf/FastMalloc.cpp: (WTF::fastZeroedMalloc): Removed null checking of fastMalloc()'s result and removed extra call to InvokeNewHook(). (WTF::tryFastZeroedMalloc): Added. Uses tryFastMalloc(). (WTF::tryFastMalloc): Renamed fastMalloc() to this. (WTF::fastMalloc): Added. This version abort()s if allocation fails. (WTF::tryFastCalloc): Renamed fastCalloc() to this. (WTF::fastCalloc): Added. This version abort()s if allocation fails. (WTF::tryFastRealloc): Renamed fastRealloc() to this. (WTF::fastRealloc): Added. This version abort()s if allocation fails. (WTF::do_malloc): Made this a function template. When the abortOnFailure template parameter is set, the function abort()s on failure to allocate. Otherwise, it sets errno to ENOMEM and returns zero. (WTF::TCMallocStats::fastMalloc): Defined to abort() on failure. (WTF::TCMallocStats::tryFastMalloc): Added. Does not abort() on failure. (WTF::TCMallocStats::fastCalloc): Defined to abort() on failure. (WTF::TCMallocStats::tryFastCalloc): Added. Does not abort() on failure. (WTF::TCMallocStats::fastRealloc): Defined to abort() on failure. (WTF::TCMallocStats::tryFastRealloc): Added. Does not abort() on failure.
  • wtf/FastMalloc.h: Declared the "try" variants.

WebCore:

  • WebCore part of <rdar://problem/6121636> Make fast*alloc() abort() on failure and add "try" variants that return NULL on failure.

Reviewed by Darin Adler.

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