OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
3 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights
reserved. | 3 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights
reserved. |
4 * Copyright (C) 2009 Google Inc. All rights reserved. | 4 * Copyright (C) 2009 Google Inc. All rights reserved. |
5 * | 5 * |
6 * This library is free software; you can redistribute it and/or | 6 * This library is free software; you can redistribute it and/or |
7 * modify it under the terms of the GNU Library General Public | 7 * modify it under the terms of the GNU Library General Public |
8 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
9 * version 2 of the License, or (at your option) any later version. | 9 * version 2 of the License, or (at your option) any later version. |
10 * | 10 * |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 friend struct WTF::HashAndUTF8CharactersTranslator; | 108 friend struct WTF::HashAndUTF8CharactersTranslator; |
109 friend struct WTF::CharBufferFromLiteralDataTranslator; | 109 friend struct WTF::CharBufferFromLiteralDataTranslator; |
110 friend struct WTF::LCharBufferTranslator; | 110 friend struct WTF::LCharBufferTranslator; |
111 friend struct WTF::SubstringTranslator; | 111 friend struct WTF::SubstringTranslator; |
112 friend struct WTF::UCharBufferTranslator; | 112 friend struct WTF::UCharBufferTranslator; |
113 | 113 |
114 private: | 114 private: |
115 // Used to construct static strings, which have an special refCount that can
never hit zero. | 115 // Used to construct static strings, which have an special refCount that can
never hit zero. |
116 // This means that the static string will never be destroyed, which is impor
tant because | 116 // This means that the static string will never be destroyed, which is impor
tant because |
117 // static strings will be shared across threads & ref-counted in a non-threa
dsafe manner. | 117 // static strings will be shared across threads & ref-counted in a non-threa
dsafe manner. |
118 enum ConstructStaticStringTag { ConstructStaticString }; | 118 enum ConstructEmptyStringTag { ConstructEmptyString }; |
119 StringImpl(const LChar* characters, unsigned length, ConstructStaticStringTa
g) | 119 explicit StringImpl(ConstructEmptyStringTag) |
120 : m_data8(characters) | 120 : m_refCount(s_refCountFlagIsStaticString) |
121 , m_refCount(s_refCountFlagIsStaticString) | 121 , m_length(0) |
122 , m_length(length) | |
123 , m_hashAndFlags(s_hashFlag8BitBuffer) | 122 , m_hashAndFlags(s_hashFlag8BitBuffer) |
124 { | 123 { |
125 // Ensure that the hash is computed so that AtomicStringHash can call ex
istingHash() | 124 // Ensure that the hash is computed so that AtomicStringHash can call ex
istingHash() |
126 // with impunity. The empty string is special because it is never entere
d into | 125 // with impunity. The empty string is special because it is never entere
d into |
127 // AtomicString's HashKey, but still needs to compare correctly. | 126 // AtomicString's HashKey, but still needs to compare correctly. |
128 STRING_STATS_ADD_8BIT_STRING(m_length); | 127 STRING_STATS_ADD_8BIT_STRING(m_length); |
129 | |
130 hash(); | 128 hash(); |
131 } | 129 } |
132 | 130 |
133 // FIXME: there has to be a less hacky way to do this. | 131 // FIXME: there has to be a less hacky way to do this. |
134 enum Force8Bit { Force8BitConstructor }; | 132 enum Force8Bit { Force8BitConstructor }; |
135 StringImpl(unsigned length, Force8Bit) | 133 StringImpl(unsigned length, Force8Bit) |
136 : m_data8(reinterpret_cast<const LChar*>(this + 1)) | 134 : m_refCount(s_refCountIncrement) |
137 , m_refCount(s_refCountIncrement) | |
138 , m_length(length) | 135 , m_length(length) |
139 , m_hashAndFlags(s_hashFlag8BitBuffer) | 136 , m_hashAndFlags(s_hashFlag8BitBuffer) |
140 { | 137 { |
141 ASSERT(m_data8); | |
142 ASSERT(m_length); | 138 ASSERT(m_length); |
143 | |
144 STRING_STATS_ADD_8BIT_STRING(m_length); | 139 STRING_STATS_ADD_8BIT_STRING(m_length); |
145 } | 140 } |
146 | 141 |
147 StringImpl(unsigned length) | 142 StringImpl(unsigned length) |
148 : m_data16(reinterpret_cast<const UChar*>(this + 1)) | 143 : m_refCount(s_refCountIncrement) |
149 , m_refCount(s_refCountIncrement) | |
150 , m_length(length) | 144 , m_length(length) |
151 , m_hashAndFlags(0) | 145 , m_hashAndFlags(0) |
152 { | 146 { |
153 ASSERT(m_data16); | |
154 ASSERT(m_length); | 147 ASSERT(m_length); |
155 | |
156 STRING_STATS_ADD_16BIT_STRING(m_length); | 148 STRING_STATS_ADD_16BIT_STRING(m_length); |
157 } | 149 } |
158 | 150 |
159 public: | 151 public: |
160 ~StringImpl(); | 152 ~StringImpl(); |
161 | 153 |
| 154 enum StaticStringTag { StaticString }; |
| 155 StringImpl(unsigned length, unsigned hash, StaticStringTag) |
| 156 : m_refCount(s_refCountFlagIsStaticString) |
| 157 , m_length(length) |
| 158 , m_hashAndFlags(hash << s_flagCount | s_hashFlag8BitBuffer) |
| 159 { |
| 160 #ifndef NDEBUG |
| 161 assertHashIsCorrect(); |
| 162 #endif |
| 163 } |
| 164 |
162 static PassRefPtr<StringImpl> create(const UChar*, unsigned length); | 165 static PassRefPtr<StringImpl> create(const UChar*, unsigned length); |
163 static PassRefPtr<StringImpl> create(const LChar*, unsigned length); | 166 static PassRefPtr<StringImpl> create(const LChar*, unsigned length); |
164 static PassRefPtr<StringImpl> create8BitIfPossible(const UChar*, unsigned le
ngth); | 167 static PassRefPtr<StringImpl> create8BitIfPossible(const UChar*, unsigned le
ngth); |
165 template<size_t inlineCapacity> | 168 template<size_t inlineCapacity> |
166 static PassRefPtr<StringImpl> create8BitIfPossible(const Vector<UChar, inlin
eCapacity>& vector) | 169 static PassRefPtr<StringImpl> create8BitIfPossible(const Vector<UChar, inlin
eCapacity>& vector) |
167 { | 170 { |
168 return create8BitIfPossible(vector.data(), vector.size()); | 171 return create8BitIfPossible(vector.data(), vector.size()); |
169 } | 172 } |
170 | 173 |
171 ALWAYS_INLINE static PassRefPtr<StringImpl> create(const char* s, unsigned l
ength) { return create(reinterpret_cast<const LChar*>(s), length); } | 174 ALWAYS_INLINE static PassRefPtr<StringImpl> create(const char* s, unsigned l
ength) { return create(reinterpret_cast<const LChar*>(s), length); } |
(...skipping 13 matching lines...) Expand all Loading... |
185 void truncateAssumingIsolated(unsigned length) | 188 void truncateAssumingIsolated(unsigned length) |
186 { | 189 { |
187 ASSERT(hasOneRef()); | 190 ASSERT(hasOneRef()); |
188 ASSERT(length <= m_length); | 191 ASSERT(length <= m_length); |
189 m_length = length; | 192 m_length = length; |
190 } | 193 } |
191 | 194 |
192 unsigned length() const { return m_length; } | 195 unsigned length() const { return m_length; } |
193 bool is8Bit() const { return m_hashAndFlags & s_hashFlag8BitBuffer; } | 196 bool is8Bit() const { return m_hashAndFlags & s_hashFlag8BitBuffer; } |
194 | 197 |
195 ALWAYS_INLINE const LChar* characters8() const { ASSERT(is8Bit()); return m_
data8; } | 198 ALWAYS_INLINE const LChar* characters8() const { ASSERT(is8Bit()); return re
interpret_cast<const LChar*>(this + 1); } |
196 ALWAYS_INLINE const UChar* characters16() const { ASSERT(!is8Bit()); return
m_data16; } | 199 ALWAYS_INLINE const UChar* characters16() const { ASSERT(!is8Bit()); return
reinterpret_cast<const UChar*>(this + 1); } |
197 | 200 |
198 template <typename CharType> | 201 template <typename CharType> |
199 ALWAYS_INLINE const CharType * getCharacters() const; | 202 ALWAYS_INLINE const CharType * getCharacters() const; |
200 | 203 |
201 size_t sizeInBytes() const; | 204 size_t sizeInBytes() const; |
202 | 205 |
203 bool isAtomic() const { return m_hashAndFlags & s_hashFlagIsAtomic; } | 206 bool isAtomic() const { return m_hashAndFlags & s_hashFlagIsAtomic; } |
204 void setIsAtomic(bool isAtomic) | 207 void setIsAtomic(bool isAtomic) |
205 { | 208 { |
206 if (isAtomic) | 209 if (isAtomic) |
207 m_hashAndFlags |= s_hashFlagIsAtomic; | 210 m_hashAndFlags |= s_hashFlagIsAtomic; |
208 else | 211 else |
209 m_hashAndFlags &= ~s_hashFlagIsAtomic; | 212 m_hashAndFlags &= ~s_hashFlagIsAtomic; |
210 } | 213 } |
211 | 214 |
212 bool isStatic() const { return m_refCount & s_refCountFlagIsStaticString; } | 215 bool isStatic() const { return m_refCount & s_refCountFlagIsStaticString; } |
213 | 216 |
214 private: | 217 private: |
215 // The high bits of 'hash' are always empty, but we prefer to store our flag
s | 218 // The high bits of 'hash' are always empty, but we prefer to store our flag
s |
216 // in the low bits because it makes them slightly more efficient to access. | 219 // in the low bits because it makes them slightly more efficient to access. |
217 // So, we shift left and right when setting and getting our hash code. | 220 // So, we shift left and right when setting and getting our hash code. |
218 void setHash(unsigned hash) const | 221 void setHash(unsigned hash) const |
219 { | 222 { |
220 ASSERT(!hasHash()); | 223 ASSERT(!hasHash()); |
221 // Multiple clients assume that StringHasher is the canonical string has
h function. | 224 // Multiple clients assume that StringHasher is the canonical string has
h function. |
222 ASSERT(hash == (is8Bit() ? StringHasher::computeHashAndMaskTop8Bits(m_da
ta8, m_length) : StringHasher::computeHashAndMaskTop8Bits(m_data16, m_length))); | 225 ASSERT(hash == (is8Bit() ? StringHasher::computeHashAndMaskTop8Bits(char
acters8(), m_length) : StringHasher::computeHashAndMaskTop8Bits(characters16(),
m_length))); |
223 ASSERT(!(hash & (s_flagMask << (8 * sizeof(hash) - s_flagCount)))); // V
erify that enough high bits are empty. | 226 ASSERT(!(hash & (s_flagMask << (8 * sizeof(hash) - s_flagCount)))); // V
erify that enough high bits are empty. |
224 | 227 |
225 hash <<= s_flagCount; | 228 hash <<= s_flagCount; |
226 ASSERT(!(hash & m_hashAndFlags)); // Verify that enough low bits are emp
ty after shift. | 229 ASSERT(!(hash & m_hashAndFlags)); // Verify that enough low bits are emp
ty after shift. |
227 ASSERT(hash); // Verify that 0 is a valid sentinel hash value. | 230 ASSERT(hash); // Verify that 0 is a valid sentinel hash value. |
228 | 231 |
229 m_hashAndFlags |= hash; // Store hash with flags in low bits. | 232 m_hashAndFlags |= hash; // Store hash with flags in low bits. |
230 } | 233 } |
231 | 234 |
232 unsigned rawHash() const | 235 unsigned rawHash() const |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 // thread-safe. We achieve thread safety by isolation, giving each thread | 317 // thread-safe. We achieve thread safety by isolation, giving each thread |
315 // its own copy of the string. | 318 // its own copy of the string. |
316 PassRefPtr<StringImpl> isolatedCopy() const; | 319 PassRefPtr<StringImpl> isolatedCopy() const; |
317 | 320 |
318 PassRefPtr<StringImpl> substring(unsigned pos, unsigned len = UINT_MAX); | 321 PassRefPtr<StringImpl> substring(unsigned pos, unsigned len = UINT_MAX); |
319 | 322 |
320 UChar operator[](unsigned i) const | 323 UChar operator[](unsigned i) const |
321 { | 324 { |
322 ASSERT_WITH_SECURITY_IMPLICATION(i < m_length); | 325 ASSERT_WITH_SECURITY_IMPLICATION(i < m_length); |
323 if (is8Bit()) | 326 if (is8Bit()) |
324 return m_data8[i]; | 327 return characters8()[i]; |
325 return m_data16[i]; | 328 return characters16()[i]; |
326 } | 329 } |
327 UChar32 characterStartingAt(unsigned); | 330 UChar32 characterStartingAt(unsigned); |
328 | 331 |
329 bool containsOnlyWhitespace(); | 332 bool containsOnlyWhitespace(); |
330 | 333 |
331 int toIntStrict(bool* ok = 0, int base = 10); | 334 int toIntStrict(bool* ok = 0, int base = 10); |
332 unsigned toUIntStrict(bool* ok = 0, int base = 10); | 335 unsigned toUIntStrict(bool* ok = 0, int base = 10); |
333 int64_t toInt64Strict(bool* ok = 0, int base = 10); | 336 int64_t toInt64Strict(bool* ok = 0, int base = 10); |
334 uint64_t toUInt64Strict(bool* ok = 0, int base = 10); | 337 uint64_t toUInt64Strict(bool* ok = 0, int base = 10); |
335 intptr_t toIntPtrStrict(bool* ok = 0, int base = 10); | 338 intptr_t toIntPtrStrict(bool* ok = 0, int base = 10); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
432 static const unsigned s_flagMask = (1u << s_flagCount) - 1; | 435 static const unsigned s_flagMask = (1u << s_flagCount) - 1; |
433 COMPILE_ASSERT(s_flagCount == StringHasher::flagCount, StringHasher_reserves
_enough_bits_for_StringImpl_flags); | 436 COMPILE_ASSERT(s_flagCount == StringHasher::flagCount, StringHasher_reserves
_enough_bits_for_StringImpl_flags); |
434 | 437 |
435 static const unsigned s_hashFlagIsAtomic = 1u << 1; | 438 static const unsigned s_hashFlagIsAtomic = 1u << 1; |
436 static const unsigned s_hashFlag8BitBuffer = 1u << 0; | 439 static const unsigned s_hashFlag8BitBuffer = 1u << 0; |
437 | 440 |
438 #ifdef STRING_STATS | 441 #ifdef STRING_STATS |
439 static StringStats m_stringStats; | 442 static StringStats m_stringStats; |
440 #endif | 443 #endif |
441 | 444 |
442 public: | |
443 struct StaticASCIILiteral { | |
444 // These member variables must match the layout of StringImpl. | |
445 const LChar* m_data8; | |
446 unsigned m_refCount; | |
447 unsigned m_length; | |
448 unsigned m_hashAndFlags; | |
449 | |
450 static const unsigned s_initialRefCount = s_refCountFlagIsStaticString; | |
451 static const unsigned s_initialFlags = s_hashFlag8BitBuffer; | |
452 static const unsigned s_hashShift = s_flagCount; | |
453 }; | |
454 | |
455 #ifndef NDEBUG | 445 #ifndef NDEBUG |
456 void assertHashIsCorrect() | 446 void assertHashIsCorrect() |
457 { | 447 { |
458 ASSERT(hasHash()); | 448 ASSERT(hasHash()); |
459 ASSERT(existingHash() == StringHasher::computeHashAndMaskTop8Bits(charac
ters8(), length())); | 449 ASSERT(existingHash() == StringHasher::computeHashAndMaskTop8Bits(charac
ters8(), length())); |
460 } | 450 } |
461 #endif | 451 #endif |
462 | 452 |
463 private: | 453 private: |
464 // These member variables must match the layout of StaticASCIILiteral. | |
465 union { // Pointers first: crbug.com/232031 | |
466 const LChar* m_data8; | |
467 const UChar* m_data16; | |
468 }; | |
469 unsigned m_refCount; | 454 unsigned m_refCount; |
470 unsigned m_length; | 455 unsigned m_length; |
471 mutable unsigned m_hashAndFlags; | 456 mutable unsigned m_hashAndFlags; |
472 }; | 457 }; |
473 | 458 |
474 COMPILE_ASSERT(sizeof(StringImpl) == sizeof(StringImpl::StaticASCIILiteral), Str
ingImpl_should_match_its_StaticASCIILiteral); | |
475 | |
476 template <> | 459 template <> |
477 ALWAYS_INLINE const LChar* StringImpl::getCharacters<LChar>() const { return cha
racters8(); } | 460 ALWAYS_INLINE const LChar* StringImpl::getCharacters<LChar>() const { return cha
racters8(); } |
478 | 461 |
479 template <> | 462 template <> |
480 ALWAYS_INLINE const UChar* StringImpl::getCharacters<UChar>() const { return cha
racters16(); } | 463 ALWAYS_INLINE const UChar* StringImpl::getCharacters<UChar>() const { return cha
racters16(); } |
481 | 464 |
482 WTF_EXPORT bool equal(const StringImpl*, const StringImpl*); | 465 WTF_EXPORT bool equal(const StringImpl*, const StringImpl*); |
483 WTF_EXPORT bool equal(const StringImpl*, const LChar*); | 466 WTF_EXPORT bool equal(const StringImpl*, const LChar*); |
484 inline bool equal(const StringImpl* a, const char* b) { return equal(a, reinterp
ret_cast<const LChar*>(b)); } | 467 inline bool equal(const StringImpl* a, const char* b) { return equal(a, reinterp
ret_cast<const LChar*>(b)); } |
485 WTF_EXPORT bool equal(const StringImpl*, const LChar*, unsigned); | 468 WTF_EXPORT bool equal(const StringImpl*, const LChar*, unsigned); |
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
735 static inline bool isSpaceOrNewline(UChar c) | 718 static inline bool isSpaceOrNewline(UChar c) |
736 { | 719 { |
737 // Use isASCIISpace() for basic Latin-1. | 720 // Use isASCIISpace() for basic Latin-1. |
738 // This will include newlines, which aren't included in Unicode DirWS. | 721 // This will include newlines, which aren't included in Unicode DirWS. |
739 return c <= 0x7F ? WTF::isASCIISpace(c) : WTF::Unicode::direction(c) == WTF:
:Unicode::WhiteSpaceNeutral; | 722 return c <= 0x7F ? WTF::isASCIISpace(c) : WTF::Unicode::direction(c) == WTF:
:Unicode::WhiteSpaceNeutral; |
740 } | 723 } |
741 | 724 |
742 inline PassRefPtr<StringImpl> StringImpl::isolatedCopy() const | 725 inline PassRefPtr<StringImpl> StringImpl::isolatedCopy() const |
743 { | 726 { |
744 if (is8Bit()) | 727 if (is8Bit()) |
745 return create(m_data8, m_length); | 728 return create(characters8(), m_length); |
746 return create(m_data16, m_length); | 729 return create(characters16(), m_length); |
747 } | 730 } |
748 | 731 |
749 struct StringHash; | 732 struct StringHash; |
750 | 733 |
751 // StringHash is the default hash for StringImpl* and RefPtr<StringImpl> | 734 // StringHash is the default hash for StringImpl* and RefPtr<StringImpl> |
752 template<typename T> struct DefaultHash; | 735 template<typename T> struct DefaultHash; |
753 template<> struct DefaultHash<StringImpl*> { | 736 template<> struct DefaultHash<StringImpl*> { |
754 typedef StringHash Hash; | 737 typedef StringHash Hash; |
755 }; | 738 }; |
756 template<> struct DefaultHash<RefPtr<StringImpl> > { | 739 template<> struct DefaultHash<RefPtr<StringImpl> > { |
757 typedef StringHash Hash; | 740 typedef StringHash Hash; |
758 }; | 741 }; |
759 | 742 |
760 } | 743 } |
761 | 744 |
762 using WTF::StringImpl; | 745 using WTF::StringImpl; |
763 using WTF::equal; | 746 using WTF::equal; |
764 using WTF::equalNonNull; | 747 using WTF::equalNonNull; |
765 using WTF::TextCaseSensitivity; | 748 using WTF::TextCaseSensitivity; |
766 using WTF::TextCaseSensitive; | 749 using WTF::TextCaseSensitive; |
767 using WTF::TextCaseInsensitive; | 750 using WTF::TextCaseInsensitive; |
768 | 751 |
769 #endif | 752 #endif |
OLD | NEW |