2 * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4 * Copyright (C) 2009 Google Inc. All rights reserved.
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.
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.
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.
26 #include "Collector.h"
27 #include "UStringImpl.h"
30 #include <wtf/Assertions.h>
31 #include <wtf/CrossThreadRefCounted.h>
32 #include <wtf/OwnFastMallocPtr.h>
33 #include <wtf/PassRefPtr.h>
34 #include <wtf/RefPtr.h>
35 #include <wtf/Vector.h>
36 #include <wtf/text/CString.h>
37 #include <wtf/unicode/Unicode.h>
41 using WTF::PlacementNewAdoptType
;
42 using WTF::PlacementNewAdopt
;
48 typedef UStringImpl Rep
;
52 UString(const char*); // Constructor for null-terminated string.
53 UString(const char*, unsigned length
);
54 UString(const UChar
*, unsigned length
);
55 UString(const Vector
<UChar
>& buffer
);
57 UString(const UString
& s
)
62 // Special constructor for cases where we overwrite an object in place.
63 UString(PlacementNewAdoptType
)
64 : m_rep(PlacementNewAdopt
)
68 template<size_t inlineCapacity
>
69 static PassRefPtr
<UStringImpl
> adopt(Vector
<UChar
, inlineCapacity
>& vector
)
71 return Rep::adopt(vector
);
74 static UString
from(int);
75 static UString
from(long long);
76 static UString
from(unsigned);
77 static UString
from(long);
78 static UString
from(double);
80 // NOTE: This method should only be used for *debugging* purposes as it
81 // is neither Unicode safe nor free from side effects nor thread-safe.
85 * Convert the string to UTF-8, assuming it is UTF-16 encoded.
86 * In non-strict mode, this function is tolerant of badly formed UTF-16, it
87 * can create UTF-8 strings that are invalid because they have characters in
88 * the range U+D800-U+DDFF, U+FFFE, or U+FFFF, but the UTF-8 string is
89 * guaranteed to be otherwise valid.
90 * In strict mode, error is returned as null CString.
92 CString
UTF8String(bool strict
= false) const;
94 const UChar
* data() const
98 return m_rep
->characters();
101 unsigned size() const
105 return m_rep
->length();
108 bool isNull() const { return !m_rep
; }
109 bool isEmpty() const { return !m_rep
|| !m_rep
->length(); }
113 UChar
operator[](unsigned pos
) const;
115 double toDouble(bool tolerateTrailingJunk
, bool tolerateEmptyString
) const;
116 double toDouble(bool tolerateTrailingJunk
) const;
117 double toDouble() const;
119 uint32_t toUInt32(bool* ok
= 0) const;
120 uint32_t toUInt32(bool* ok
, bool tolerateEmptyString
) const;
121 uint32_t toStrictUInt32(bool* ok
= 0) const;
123 unsigned toArrayIndex(bool* ok
= 0) const;
125 static const unsigned NotFound
= 0xFFFFFFFFu
;
126 unsigned find(const UString
& f
, unsigned pos
= 0) const;
127 unsigned find(UChar
, unsigned pos
= 0) const;
128 unsigned rfind(const UString
& f
, unsigned pos
) const;
129 unsigned rfind(UChar
, unsigned pos
) const;
131 UString
substr(unsigned pos
= 0, unsigned len
= 0xFFFFFFFF) const;
133 static const UString
& null() { return *s_nullUString
; }
135 Rep
* rep() const { return m_rep
.get(); }
137 UString(PassRefPtr
<Rep
> r
)
146 return m_rep
->cost();
152 static UString
* s_nullUString
;
154 friend void initializeUString();
155 friend bool operator==(const UString
&, const UString
&);
158 ALWAYS_INLINE
bool operator==(const UString
& s1
, const UString
& s2
)
160 UString::Rep
* rep1
= s1
.rep();
161 UString::Rep
* rep2
= s2
.rep();
165 if (rep1
== rep2
) // If they're the same rep, they're equal.
169 size1
= rep1
->length();
172 size2
= rep2
->length();
174 if (size1
!= size2
) // If the lengths are not the same, we're done.
180 // At this point we know
181 // (a) that the strings are the same length and
182 // (b) that they are greater than zero length.
183 const UChar
* d1
= rep1
->characters();
184 const UChar
* d2
= rep2
->characters();
186 if (d1
== d2
) // Check to see if the data pointers are the same.
189 // Do quick checks for sizes 1 and 2.
192 return d1
[0] == d2
[0];
194 return (d1
[0] == d2
[0]) & (d1
[1] == d2
[1]);
196 return memcmp(d1
, d2
, size1
* sizeof(UChar
)) == 0;
201 inline bool operator!=(const UString
& s1
, const UString
& s2
)
203 return !JSC::operator==(s1
, s2
);
206 bool operator<(const UString
& s1
, const UString
& s2
);
207 bool operator>(const UString
& s1
, const UString
& s2
);
209 bool operator==(const UString
& s1
, const char* s2
);
211 inline bool operator!=(const UString
& s1
, const char* s2
)
213 return !JSC::operator==(s1
, s2
);
216 inline bool operator==(const char *s1
, const UString
& s2
)
218 return operator==(s2
, s1
);
221 inline bool operator!=(const char *s1
, const UString
& s2
)
223 return !JSC::operator==(s1
, s2
);
226 int compare(const UString
&, const UString
&);
228 // Rule from ECMA 15.2 about what an array index is.
229 // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1.
230 inline unsigned UString::toArrayIndex(bool* ok
) const
232 unsigned i
= toStrictUInt32(ok
);
233 if (ok
&& i
>= 0xFFFFFFFFU
)
238 // We'd rather not do shared substring append for small strings, since
239 // this runs too much risk of a tiny initial string holding down a
241 static const unsigned minShareSize
= Heap::minExtraCost
/ sizeof(UChar
);
243 struct IdentifierRepHash
: PtrHash
<RefPtr
<JSC::UString::Rep
> > {
244 static unsigned hash(const RefPtr
<JSC::UString::Rep
>& key
) { return key
->existingHash(); }
245 static unsigned hash(JSC::UString::Rep
* key
) { return key
->existingHash(); }
248 void initializeUString();
250 template<typename StringType
>
251 class StringTypeAdapter
{
255 class StringTypeAdapter
<char*> {
257 StringTypeAdapter
<char*>(char* buffer
)
258 : m_buffer((unsigned char*)buffer
)
259 , m_length(strlen(buffer
))
263 unsigned length() { return m_length
; }
265 void writeTo(UChar
* destination
)
267 for (unsigned i
= 0; i
< m_length
; ++i
)
268 destination
[i
] = m_buffer
[i
];
272 const unsigned char* m_buffer
;
277 class StringTypeAdapter
<const char*> {
279 StringTypeAdapter
<const char*>(const char* buffer
)
280 : m_buffer((unsigned char*)buffer
)
281 , m_length(strlen(buffer
))
285 unsigned length() { return m_length
; }
287 void writeTo(UChar
* destination
)
289 for (unsigned i
= 0; i
< m_length
; ++i
)
290 destination
[i
] = m_buffer
[i
];
294 const unsigned char* m_buffer
;
299 class StringTypeAdapter
<UString
> {
301 StringTypeAdapter
<UString
>(UString
& string
)
302 : m_data(string
.data())
303 , m_length(string
.size())
307 unsigned length() { return m_length
; }
309 void writeTo(UChar
* destination
)
311 for (unsigned i
= 0; i
< m_length
; ++i
)
312 destination
[i
] = m_data
[i
];
320 inline void sumWithOverflow(unsigned& total
, unsigned addend
, bool& overflow
)
322 unsigned oldTotal
= total
;
323 total
= oldTotal
+ addend
;
324 if (total
< oldTotal
)
328 template<typename StringType1
, typename StringType2
>
329 PassRefPtr
<UStringImpl
> tryMakeString(StringType1 string1
, StringType2 string2
)
331 StringTypeAdapter
<StringType1
> adapter1(string1
);
332 StringTypeAdapter
<StringType2
> adapter2(string2
);
335 bool overflow
= false;
336 unsigned length
= adapter1
.length();
337 sumWithOverflow(length
, adapter2
.length(), overflow
);
340 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
344 UChar
* result
= buffer
;
345 adapter1
.writeTo(result
);
346 result
+= adapter1
.length();
347 adapter2
.writeTo(result
);
352 template<typename StringType1
, typename StringType2
, typename StringType3
>
353 PassRefPtr
<UStringImpl
> tryMakeString(StringType1 string1
, StringType2 string2
, StringType3 string3
)
355 StringTypeAdapter
<StringType1
> adapter1(string1
);
356 StringTypeAdapter
<StringType2
> adapter2(string2
);
357 StringTypeAdapter
<StringType3
> adapter3(string3
);
360 bool overflow
= false;
361 unsigned length
= adapter1
.length();
362 sumWithOverflow(length
, adapter2
.length(), overflow
);
363 sumWithOverflow(length
, adapter3
.length(), overflow
);
366 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
370 UChar
* result
= buffer
;
371 adapter1
.writeTo(result
);
372 result
+= adapter1
.length();
373 adapter2
.writeTo(result
);
374 result
+= adapter2
.length();
375 adapter3
.writeTo(result
);
380 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
>
381 PassRefPtr
<UStringImpl
> tryMakeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
)
383 StringTypeAdapter
<StringType1
> adapter1(string1
);
384 StringTypeAdapter
<StringType2
> adapter2(string2
);
385 StringTypeAdapter
<StringType3
> adapter3(string3
);
386 StringTypeAdapter
<StringType4
> adapter4(string4
);
389 bool overflow
= false;
390 unsigned length
= adapter1
.length();
391 sumWithOverflow(length
, adapter2
.length(), overflow
);
392 sumWithOverflow(length
, adapter3
.length(), overflow
);
393 sumWithOverflow(length
, adapter4
.length(), overflow
);
396 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
400 UChar
* result
= buffer
;
401 adapter1
.writeTo(result
);
402 result
+= adapter1
.length();
403 adapter2
.writeTo(result
);
404 result
+= adapter2
.length();
405 adapter3
.writeTo(result
);
406 result
+= adapter3
.length();
407 adapter4
.writeTo(result
);
412 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
, typename StringType5
>
413 PassRefPtr
<UStringImpl
> tryMakeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
, StringType5 string5
)
415 StringTypeAdapter
<StringType1
> adapter1(string1
);
416 StringTypeAdapter
<StringType2
> adapter2(string2
);
417 StringTypeAdapter
<StringType3
> adapter3(string3
);
418 StringTypeAdapter
<StringType4
> adapter4(string4
);
419 StringTypeAdapter
<StringType5
> adapter5(string5
);
422 bool overflow
= false;
423 unsigned length
= adapter1
.length();
424 sumWithOverflow(length
, adapter2
.length(), overflow
);
425 sumWithOverflow(length
, adapter3
.length(), overflow
);
426 sumWithOverflow(length
, adapter4
.length(), overflow
);
427 sumWithOverflow(length
, adapter5
.length(), overflow
);
430 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
434 UChar
* result
= buffer
;
435 adapter1
.writeTo(result
);
436 result
+= adapter1
.length();
437 adapter2
.writeTo(result
);
438 result
+= adapter2
.length();
439 adapter3
.writeTo(result
);
440 result
+= adapter3
.length();
441 adapter4
.writeTo(result
);
442 result
+= adapter4
.length();
443 adapter5
.writeTo(result
);
448 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
, typename StringType5
, typename StringType6
>
449 PassRefPtr
<UStringImpl
> tryMakeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
, StringType5 string5
, StringType6 string6
)
451 StringTypeAdapter
<StringType1
> adapter1(string1
);
452 StringTypeAdapter
<StringType2
> adapter2(string2
);
453 StringTypeAdapter
<StringType3
> adapter3(string3
);
454 StringTypeAdapter
<StringType4
> adapter4(string4
);
455 StringTypeAdapter
<StringType5
> adapter5(string5
);
456 StringTypeAdapter
<StringType6
> adapter6(string6
);
459 bool overflow
= false;
460 unsigned length
= adapter1
.length();
461 sumWithOverflow(length
, adapter2
.length(), overflow
);
462 sumWithOverflow(length
, adapter3
.length(), overflow
);
463 sumWithOverflow(length
, adapter4
.length(), overflow
);
464 sumWithOverflow(length
, adapter5
.length(), overflow
);
465 sumWithOverflow(length
, adapter6
.length(), overflow
);
468 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
472 UChar
* result
= buffer
;
473 adapter1
.writeTo(result
);
474 result
+= adapter1
.length();
475 adapter2
.writeTo(result
);
476 result
+= adapter2
.length();
477 adapter3
.writeTo(result
);
478 result
+= adapter3
.length();
479 adapter4
.writeTo(result
);
480 result
+= adapter4
.length();
481 adapter5
.writeTo(result
);
482 result
+= adapter5
.length();
483 adapter6
.writeTo(result
);
488 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
, typename StringType5
, typename StringType6
, typename StringType7
>
489 PassRefPtr
<UStringImpl
> tryMakeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
, StringType5 string5
, StringType6 string6
, StringType7 string7
)
491 StringTypeAdapter
<StringType1
> adapter1(string1
);
492 StringTypeAdapter
<StringType2
> adapter2(string2
);
493 StringTypeAdapter
<StringType3
> adapter3(string3
);
494 StringTypeAdapter
<StringType4
> adapter4(string4
);
495 StringTypeAdapter
<StringType5
> adapter5(string5
);
496 StringTypeAdapter
<StringType6
> adapter6(string6
);
497 StringTypeAdapter
<StringType7
> adapter7(string7
);
500 bool overflow
= false;
501 unsigned length
= adapter1
.length();
502 sumWithOverflow(length
, adapter2
.length(), overflow
);
503 sumWithOverflow(length
, adapter3
.length(), overflow
);
504 sumWithOverflow(length
, adapter4
.length(), overflow
);
505 sumWithOverflow(length
, adapter5
.length(), overflow
);
506 sumWithOverflow(length
, adapter6
.length(), overflow
);
507 sumWithOverflow(length
, adapter7
.length(), overflow
);
510 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
514 UChar
* result
= buffer
;
515 adapter1
.writeTo(result
);
516 result
+= adapter1
.length();
517 adapter2
.writeTo(result
);
518 result
+= adapter2
.length();
519 adapter3
.writeTo(result
);
520 result
+= adapter3
.length();
521 adapter4
.writeTo(result
);
522 result
+= adapter4
.length();
523 adapter5
.writeTo(result
);
524 result
+= adapter5
.length();
525 adapter6
.writeTo(result
);
526 result
+= adapter6
.length();
527 adapter7
.writeTo(result
);
532 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
, typename StringType5
, typename StringType6
, typename StringType7
, typename StringType8
>
533 PassRefPtr
<UStringImpl
> tryMakeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
, StringType5 string5
, StringType6 string6
, StringType7 string7
, StringType8 string8
)
535 StringTypeAdapter
<StringType1
> adapter1(string1
);
536 StringTypeAdapter
<StringType2
> adapter2(string2
);
537 StringTypeAdapter
<StringType3
> adapter3(string3
);
538 StringTypeAdapter
<StringType4
> adapter4(string4
);
539 StringTypeAdapter
<StringType5
> adapter5(string5
);
540 StringTypeAdapter
<StringType6
> adapter6(string6
);
541 StringTypeAdapter
<StringType7
> adapter7(string7
);
542 StringTypeAdapter
<StringType8
> adapter8(string8
);
545 bool overflow
= false;
546 unsigned length
= adapter1
.length();
547 sumWithOverflow(length
, adapter2
.length(), overflow
);
548 sumWithOverflow(length
, adapter3
.length(), overflow
);
549 sumWithOverflow(length
, adapter4
.length(), overflow
);
550 sumWithOverflow(length
, adapter5
.length(), overflow
);
551 sumWithOverflow(length
, adapter6
.length(), overflow
);
552 sumWithOverflow(length
, adapter7
.length(), overflow
);
553 sumWithOverflow(length
, adapter8
.length(), overflow
);
556 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
560 UChar
* result
= buffer
;
561 adapter1
.writeTo(result
);
562 result
+= adapter1
.length();
563 adapter2
.writeTo(result
);
564 result
+= adapter2
.length();
565 adapter3
.writeTo(result
);
566 result
+= adapter3
.length();
567 adapter4
.writeTo(result
);
568 result
+= adapter4
.length();
569 adapter5
.writeTo(result
);
570 result
+= adapter5
.length();
571 adapter6
.writeTo(result
);
572 result
+= adapter6
.length();
573 adapter7
.writeTo(result
);
574 result
+= adapter7
.length();
575 adapter8
.writeTo(result
);
580 template<typename StringType1
, typename StringType2
>
581 UString
makeString(StringType1 string1
, StringType2 string2
)
583 PassRefPtr
<UStringImpl
> resultImpl
= tryMakeString(string1
, string2
);
589 template<typename StringType1
, typename StringType2
, typename StringType3
>
590 UString
makeString(StringType1 string1
, StringType2 string2
, StringType3 string3
)
592 PassRefPtr
<UStringImpl
> resultImpl
= tryMakeString(string1
, string2
, string3
);
598 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
>
599 UString
makeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
)
601 PassRefPtr
<UStringImpl
> resultImpl
= tryMakeString(string1
, string2
, string3
, string4
);
607 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
, typename StringType5
>
608 UString
makeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
, StringType5 string5
)
610 PassRefPtr
<UStringImpl
> resultImpl
= tryMakeString(string1
, string2
, string3
, string4
, string5
);
616 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
, typename StringType5
, typename StringType6
>
617 UString
makeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
, StringType5 string5
, StringType6 string6
)
619 PassRefPtr
<UStringImpl
> resultImpl
= tryMakeString(string1
, string2
, string3
, string4
, string5
, string6
);
625 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
, typename StringType5
, typename StringType6
, typename StringType7
>
626 UString
makeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
, StringType5 string5
, StringType6 string6
, StringType7 string7
)
628 PassRefPtr
<UStringImpl
> resultImpl
= tryMakeString(string1
, string2
, string3
, string4
, string5
, string6
, string7
);
634 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
, typename StringType5
, typename StringType6
, typename StringType7
, typename StringType8
>
635 UString
makeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
, StringType5 string5
, StringType6 string6
, StringType7 string7
, StringType8 string8
)
637 PassRefPtr
<UStringImpl
> resultImpl
= tryMakeString(string1
, string2
, string3
, string4
, string5
, string6
, string7
, string8
);
647 template<typename T
> struct DefaultHash
;
648 template<typename T
> struct StrHash
;
650 template<> struct StrHash
<JSC::UString::Rep
*> {
651 static unsigned hash(const JSC::UString::Rep
* key
) { return key
->hash(); }
652 static bool equal(const JSC::UString::Rep
* a
, const JSC::UString::Rep
* b
) { return ::equal(a
, b
); }
653 static const bool safeToCompareToEmptyOrDeleted
= false;
656 template<> struct StrHash
<RefPtr
<JSC::UString::Rep
> > : public StrHash
<JSC::UString::Rep
*> {
657 using StrHash
<JSC::UString::Rep
*>::hash
;
658 static unsigned hash(const RefPtr
<JSC::UString::Rep
>& key
) { return key
->hash(); }
659 using StrHash
<JSC::UString::Rep
*>::equal
;
660 static bool equal(const RefPtr
<JSC::UString::Rep
>& a
, const RefPtr
<JSC::UString::Rep
>& b
) { return ::equal(a
.get(), b
.get()); }
661 static bool equal(const JSC::UString::Rep
* a
, const RefPtr
<JSC::UString::Rep
>& b
) { return ::equal(a
, b
.get()); }
662 static bool equal(const RefPtr
<JSC::UString::Rep
>& a
, const JSC::UString::Rep
* b
) { return ::equal(a
.get(), b
); }
664 static const bool safeToCompareToEmptyOrDeleted
= false;
667 template <> struct VectorTraits
<JSC::UString
> : SimpleClassVectorTraits
669 static const bool canInitializeWithMemset
= true;