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/PtrAndFlags.h>
35 #include <wtf/RefPtr.h>
36 #include <wtf/Vector.h>
37 #include <wtf/unicode/Unicode.h>
41 using WTF::PlacementNewAdoptType
;
42 using WTF::PlacementNewAdopt
;
53 CString(const char*, size_t);
54 CString(const CString
&);
58 static CString
adopt(char*, size_t); // buffer should be allocated with new[].
60 CString
& append(const CString
&);
61 CString
& operator=(const char* c
);
62 CString
& operator=(const CString
&);
63 CString
& operator+=(const CString
& c
) { return append(c
); }
65 size_t size() const { return m_length
; }
66 const char* c_str() const { return m_data
; }
73 bool operator==(const CString
&, const CString
&);
75 typedef Vector
<char, 32> CStringBuffer
;
81 typedef UStringImpl Rep
;
84 // UString constructors passed char*s assume ISO Latin-1 encoding; for UTF8 use 'createFromUTF8', below.
86 UString(const char*); // Constructor for null-terminated string.
87 UString(const char*, int length
);
88 UString(const UChar
*, int length
);
89 UString(const Vector
<UChar
>& buffer
);
91 UString(const UString
& s
)
96 // Special constructor for cases where we overwrite an object in place.
97 UString(PlacementNewAdoptType
)
98 : m_rep(PlacementNewAdopt
)
106 template<size_t inlineCapacity
>
107 static PassRefPtr
<UStringImpl
> adopt(Vector
<UChar
, inlineCapacity
>& vector
)
109 return Rep::adopt(vector
);
112 static UString
createFromUTF8(const char*);
114 static UString
from(int);
115 static UString
from(long long);
116 static UString
from(unsigned int);
117 static UString
from(long);
118 static UString
from(double);
122 Range(int pos
, int len
)
136 UString
spliceSubstringsWithSeparators(const Range
* substringRanges
, int rangeCount
, const UString
* separators
, int separatorCount
) const;
138 UString
replaceRange(int rangeStart
, int RangeEnd
, const UString
& replacement
) const;
140 bool getCString(CStringBuffer
&) const;
142 // NOTE: This method should only be used for *debugging* purposes as it
143 // is neither Unicode safe nor free from side effects nor thread-safe.
147 * Convert the string to UTF-8, assuming it is UTF-16 encoded.
148 * In non-strict mode, this function is tolerant of badly formed UTF-16, it
149 * can create UTF-8 strings that are invalid because they have characters in
150 * the range U+D800-U+DDFF, U+FFFE, or U+FFFF, but the UTF-8 string is
151 * guaranteed to be otherwise valid.
152 * In strict mode, error is returned as null CString.
154 CString
UTF8String(bool strict
= false) const;
156 UString
& operator=(const char*c
);
158 const UChar
* data() const { return m_rep
->data(); }
160 bool isNull() const { return m_rep
== &Rep::null(); }
161 bool isEmpty() const { return !m_rep
->size(); }
165 int size() const { return m_rep
->size(); }
167 UChar
operator[](int pos
) const;
169 double toDouble(bool tolerateTrailingJunk
, bool tolerateEmptyString
) const;
170 double toDouble(bool tolerateTrailingJunk
) const;
171 double toDouble() const;
173 uint32_t toUInt32(bool* ok
= 0) const;
174 uint32_t toUInt32(bool* ok
, bool tolerateEmptyString
) const;
175 uint32_t toStrictUInt32(bool* ok
= 0) const;
177 unsigned toArrayIndex(bool* ok
= 0) const;
179 int find(const UString
& f
, int pos
= 0) const;
180 int find(UChar
, int pos
= 0) const;
181 int rfind(const UString
& f
, int pos
) const;
182 int rfind(UChar
, int pos
) const;
184 UString
substr(int pos
= 0, int len
= -1) const;
186 static const UString
& null() { return *nullUString
; }
188 Rep
* rep() const { return m_rep
.get(); }
189 static Rep
* nullRep();
191 UString(PassRefPtr
<Rep
> r
)
197 size_t cost() const { return m_rep
->cost(); }
203 static UString
* nullUString
;
205 friend void initializeUString();
206 friend bool operator==(const UString
&, const UString
&);
209 ALWAYS_INLINE
bool operator==(const UString
& s1
, const UString
& s2
)
211 int size
= s1
.size();
216 return s2
.size() == 1 && s1
.data()[0] == s2
.data()[0];
220 const UChar
* d1
= s1
.data();
221 const UChar
* d2
= s2
.data();
222 return (d1
[0] == d2
[0]) & (d1
[1] == d2
[1]);
225 return s2
.size() == size
&& memcmp(s1
.data(), s2
.data(), size
* sizeof(UChar
)) == 0;
230 inline bool operator!=(const UString
& s1
, const UString
& s2
)
232 return !JSC::operator==(s1
, s2
);
235 bool operator<(const UString
& s1
, const UString
& s2
);
236 bool operator>(const UString
& s1
, const UString
& s2
);
238 bool operator==(const UString
& s1
, const char* s2
);
240 inline bool operator!=(const UString
& s1
, const char* s2
)
242 return !JSC::operator==(s1
, s2
);
245 inline bool operator==(const char *s1
, const UString
& s2
)
247 return operator==(s2
, s1
);
250 inline bool operator!=(const char *s1
, const UString
& s2
)
252 return !JSC::operator==(s1
, s2
);
255 int compare(const UString
&, const UString
&);
257 inline UString::UString()
258 : m_rep(&Rep::null())
262 // Rule from ECMA 15.2 about what an array index is.
263 // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1.
264 inline unsigned UString::toArrayIndex(bool* ok
) const
266 unsigned i
= toStrictUInt32(ok
);
267 if (ok
&& i
>= 0xFFFFFFFFU
)
272 // We'd rather not do shared substring append for small strings, since
273 // this runs too much risk of a tiny initial string holding down a
275 // FIXME: this should be size_t but that would cause warnings until we
276 // fix UString sizes to be size_t instead of int
277 static const int minShareSize
= Heap::minExtraCost
/ sizeof(UChar
);
279 struct IdentifierRepHash
: PtrHash
<RefPtr
<JSC::UString::Rep
> > {
280 static unsigned hash(const RefPtr
<JSC::UString::Rep
>& key
) { return key
->existingHash(); }
281 static unsigned hash(JSC::UString::Rep
* key
) { return key
->existingHash(); }
284 void initializeUString();
286 template<typename StringType
>
287 class StringTypeAdapter
{
291 class StringTypeAdapter
<char*> {
293 StringTypeAdapter
<char*>(char* buffer
)
294 : m_buffer((unsigned char*)buffer
)
295 , m_length(strlen(buffer
))
299 unsigned length() { return m_length
; }
301 void writeTo(UChar
* destination
)
303 for (unsigned i
= 0; i
< m_length
; ++i
)
304 destination
[i
] = m_buffer
[i
];
308 const unsigned char* m_buffer
;
313 class StringTypeAdapter
<const char*> {
315 StringTypeAdapter
<const char*>(const char* buffer
)
316 : m_buffer((unsigned char*)buffer
)
317 , m_length(strlen(buffer
))
321 unsigned length() { return m_length
; }
323 void writeTo(UChar
* destination
)
325 for (unsigned i
= 0; i
< m_length
; ++i
)
326 destination
[i
] = m_buffer
[i
];
330 const unsigned char* m_buffer
;
335 class StringTypeAdapter
<UString
> {
337 StringTypeAdapter
<UString
>(UString
& string
)
338 : m_data(string
.data())
339 , m_length(string
.size())
343 unsigned length() { return m_length
; }
345 void writeTo(UChar
* destination
)
347 for (unsigned i
= 0; i
< m_length
; ++i
)
348 destination
[i
] = m_data
[i
];
356 template<typename StringType1
, typename StringType2
>
357 UString
makeString(StringType1 string1
, StringType2 string2
)
359 StringTypeAdapter
<StringType1
> adapter1(string1
);
360 StringTypeAdapter
<StringType2
> adapter2(string2
);
363 unsigned length
= adapter1
.length() + adapter2
.length();
364 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
368 UChar
* result
= buffer
;
369 adapter1
.writeTo(result
);
370 result
+= adapter1
.length();
371 adapter2
.writeTo(result
);
376 template<typename StringType1
, typename StringType2
, typename StringType3
>
377 UString
makeString(StringType1 string1
, StringType2 string2
, StringType3 string3
)
379 StringTypeAdapter
<StringType1
> adapter1(string1
);
380 StringTypeAdapter
<StringType2
> adapter2(string2
);
381 StringTypeAdapter
<StringType3
> adapter3(string3
);
384 unsigned length
= adapter1
.length() + adapter2
.length() + adapter3
.length();
385 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
389 UChar
* result
= buffer
;
390 adapter1
.writeTo(result
);
391 result
+= adapter1
.length();
392 adapter2
.writeTo(result
);
393 result
+= adapter2
.length();
394 adapter3
.writeTo(result
);
399 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
>
400 UString
makeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
)
402 StringTypeAdapter
<StringType1
> adapter1(string1
);
403 StringTypeAdapter
<StringType2
> adapter2(string2
);
404 StringTypeAdapter
<StringType3
> adapter3(string3
);
405 StringTypeAdapter
<StringType4
> adapter4(string4
);
408 unsigned length
= adapter1
.length() + adapter2
.length() + adapter3
.length() + adapter4
.length();
409 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
413 UChar
* result
= buffer
;
414 adapter1
.writeTo(result
);
415 result
+= adapter1
.length();
416 adapter2
.writeTo(result
);
417 result
+= adapter2
.length();
418 adapter3
.writeTo(result
);
419 result
+= adapter3
.length();
420 adapter4
.writeTo(result
);
425 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
, typename StringType5
>
426 UString
makeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
, StringType5 string5
)
428 StringTypeAdapter
<StringType1
> adapter1(string1
);
429 StringTypeAdapter
<StringType2
> adapter2(string2
);
430 StringTypeAdapter
<StringType3
> adapter3(string3
);
431 StringTypeAdapter
<StringType4
> adapter4(string4
);
432 StringTypeAdapter
<StringType5
> adapter5(string5
);
435 unsigned length
= adapter1
.length() + adapter2
.length() + adapter3
.length() + adapter4
.length() + adapter5
.length();
436 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
440 UChar
* result
= buffer
;
441 adapter1
.writeTo(result
);
442 result
+= adapter1
.length();
443 adapter2
.writeTo(result
);
444 result
+= adapter2
.length();
445 adapter3
.writeTo(result
);
446 result
+= adapter3
.length();
447 adapter4
.writeTo(result
);
448 result
+= adapter4
.length();
449 adapter5
.writeTo(result
);
454 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
, typename StringType5
, typename StringType6
>
455 UString
makeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
, StringType5 string5
, StringType6 string6
)
457 StringTypeAdapter
<StringType1
> adapter1(string1
);
458 StringTypeAdapter
<StringType2
> adapter2(string2
);
459 StringTypeAdapter
<StringType3
> adapter3(string3
);
460 StringTypeAdapter
<StringType4
> adapter4(string4
);
461 StringTypeAdapter
<StringType5
> adapter5(string5
);
462 StringTypeAdapter
<StringType6
> adapter6(string6
);
465 unsigned length
= adapter1
.length() + adapter2
.length() + adapter3
.length() + adapter4
.length() + adapter5
.length() + adapter6
.length();
466 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
470 UChar
* result
= buffer
;
471 adapter1
.writeTo(result
);
472 result
+= adapter1
.length();
473 adapter2
.writeTo(result
);
474 result
+= adapter2
.length();
475 adapter3
.writeTo(result
);
476 result
+= adapter3
.length();
477 adapter4
.writeTo(result
);
478 result
+= adapter4
.length();
479 adapter5
.writeTo(result
);
480 result
+= adapter5
.length();
481 adapter6
.writeTo(result
);
486 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
, typename StringType5
, typename StringType6
, typename StringType7
>
487 UString
makeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
, StringType5 string5
, StringType6 string6
, StringType7 string7
)
489 StringTypeAdapter
<StringType1
> adapter1(string1
);
490 StringTypeAdapter
<StringType2
> adapter2(string2
);
491 StringTypeAdapter
<StringType3
> adapter3(string3
);
492 StringTypeAdapter
<StringType4
> adapter4(string4
);
493 StringTypeAdapter
<StringType5
> adapter5(string5
);
494 StringTypeAdapter
<StringType6
> adapter6(string6
);
495 StringTypeAdapter
<StringType7
> adapter7(string7
);
498 unsigned length
= adapter1
.length() + adapter2
.length() + adapter3
.length() + adapter4
.length() + adapter5
.length() + adapter6
.length() + adapter7
.length();
499 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
503 UChar
* result
= buffer
;
504 adapter1
.writeTo(result
);
505 result
+= adapter1
.length();
506 adapter2
.writeTo(result
);
507 result
+= adapter2
.length();
508 adapter3
.writeTo(result
);
509 result
+= adapter3
.length();
510 adapter4
.writeTo(result
);
511 result
+= adapter4
.length();
512 adapter5
.writeTo(result
);
513 result
+= adapter5
.length();
514 adapter6
.writeTo(result
);
515 result
+= adapter6
.length();
516 adapter7
.writeTo(result
);
521 template<typename StringType1
, typename StringType2
, typename StringType3
, typename StringType4
, typename StringType5
, typename StringType6
, typename StringType7
, typename StringType8
>
522 UString
makeString(StringType1 string1
, StringType2 string2
, StringType3 string3
, StringType4 string4
, StringType5 string5
, StringType6 string6
, StringType7 string7
, StringType8 string8
)
524 StringTypeAdapter
<StringType1
> adapter1(string1
);
525 StringTypeAdapter
<StringType2
> adapter2(string2
);
526 StringTypeAdapter
<StringType3
> adapter3(string3
);
527 StringTypeAdapter
<StringType4
> adapter4(string4
);
528 StringTypeAdapter
<StringType5
> adapter5(string5
);
529 StringTypeAdapter
<StringType6
> adapter6(string6
);
530 StringTypeAdapter
<StringType7
> adapter7(string7
);
531 StringTypeAdapter
<StringType8
> adapter8(string8
);
534 unsigned length
= adapter1
.length() + adapter2
.length() + adapter3
.length() + adapter4
.length() + adapter5
.length() + adapter6
.length() + adapter7
.length() + adapter8
.length();
535 PassRefPtr
<UStringImpl
> resultImpl
= UStringImpl::tryCreateUninitialized(length
, buffer
);
539 UChar
* result
= buffer
;
540 adapter1
.writeTo(result
);
541 result
+= adapter1
.length();
542 adapter2
.writeTo(result
);
543 result
+= adapter2
.length();
544 adapter3
.writeTo(result
);
545 result
+= adapter3
.length();
546 adapter4
.writeTo(result
);
547 result
+= adapter4
.length();
548 adapter5
.writeTo(result
);
549 result
+= adapter5
.length();
550 adapter6
.writeTo(result
);
551 result
+= adapter6
.length();
552 adapter7
.writeTo(result
);
553 result
+= adapter7
.length();
554 adapter8
.writeTo(result
);
563 template<typename T
> struct DefaultHash
;
564 template<typename T
> struct StrHash
;
566 template<> struct StrHash
<JSC::UString::Rep
*> {
567 static unsigned hash(const JSC::UString::Rep
* key
) { return key
->hash(); }
568 static bool equal(const JSC::UString::Rep
* a
, const JSC::UString::Rep
* b
) { return JSC::equal(a
, b
); }
569 static const bool safeToCompareToEmptyOrDeleted
= false;
572 template<> struct StrHash
<RefPtr
<JSC::UString::Rep
> > : public StrHash
<JSC::UString::Rep
*> {
573 using StrHash
<JSC::UString::Rep
*>::hash
;
574 static unsigned hash(const RefPtr
<JSC::UString::Rep
>& key
) { return key
->hash(); }
575 using StrHash
<JSC::UString::Rep
*>::equal
;
576 static bool equal(const RefPtr
<JSC::UString::Rep
>& a
, const RefPtr
<JSC::UString::Rep
>& b
) { return JSC::equal(a
.get(), b
.get()); }
577 static bool equal(const JSC::UString::Rep
* a
, const RefPtr
<JSC::UString::Rep
>& b
) { return JSC::equal(a
, b
.get()); }
578 static bool equal(const RefPtr
<JSC::UString::Rep
>& a
, const JSC::UString::Rep
* b
) { return JSC::equal(a
.get(), b
); }
580 static const bool safeToCompareToEmptyOrDeleted
= false;
583 template<> struct DefaultHash
<JSC::UString::Rep
*> {
584 typedef StrHash
<JSC::UString::Rep
*> Hash
;
587 template<> struct DefaultHash
<RefPtr
<JSC::UString::Rep
> > {
588 typedef StrHash
<RefPtr
<JSC::UString::Rep
> > Hash
;