| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserv
ed. | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2013 Apple Inc. All rights reserv
ed. |
| 3 * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> | 3 * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com> |
| 4 * Copyright (C) 2012 Google Inc. All rights reserved. | 4 * Copyright (C) 2012 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 19 matching lines...) Expand all Loading... |
| 30 #include "wtf/text/IntegerToStringConversion.h" | 30 #include "wtf/text/IntegerToStringConversion.h" |
| 31 #include "wtf/text/UTF8.h" | 31 #include "wtf/text/UTF8.h" |
| 32 | 32 |
| 33 namespace WTF { | 33 namespace WTF { |
| 34 | 34 |
| 35 using namespace Unicode; | 35 using namespace Unicode; |
| 36 | 36 |
| 37 static_assert(sizeof(AtomicString) == sizeof(String), "AtomicString and String m
ust be same size"); | 37 static_assert(sizeof(AtomicString) == sizeof(String), "AtomicString and String m
ust be same size"); |
| 38 | 38 |
| 39 class AtomicStringTable { | 39 class AtomicStringTable { |
| 40 WTF_MAKE_NONCOPYABLE(AtomicStringTable); | 40 WTF_MAKE_NONCOPYABLE(AtomicStringTable); |
| 41 public: | 41 |
| 42 static AtomicStringTable* create(WTFThreadData& data) | 42 public: |
| 43 { | 43 static AtomicStringTable* create(WTFThreadData& data) { |
| 44 data.m_atomicStringTable = new AtomicStringTable; | 44 data.m_atomicStringTable = new AtomicStringTable; |
| 45 data.m_atomicStringTableDestructor = AtomicStringTable::destroy; | 45 data.m_atomicStringTableDestructor = AtomicStringTable::destroy; |
| 46 data.m_atomicStringTable->addStaticStrings(); | 46 data.m_atomicStringTable->addStaticStrings(); |
| 47 return data.m_atomicStringTable; | 47 return data.m_atomicStringTable; |
| 48 } |
| 49 |
| 50 StringImpl* addStringImpl(StringImpl* string) { |
| 51 if (!string->length()) |
| 52 return StringImpl::empty(); |
| 53 |
| 54 StringImpl* result = *m_table.add(string).storedValue; |
| 55 |
| 56 if (!result->isAtomic()) |
| 57 result->setIsAtomic(true); |
| 58 |
| 59 ASSERT(!string->isStatic() || result->isStatic()); |
| 60 return result; |
| 61 } |
| 62 |
| 63 HashSet<StringImpl*>& table() { |
| 64 return m_table; |
| 65 } |
| 66 |
| 67 private: |
| 68 AtomicStringTable() {} |
| 69 |
| 70 void addStaticStrings() { |
| 71 const StaticStringsTable& staticStrings = StringImpl::allStaticStrings(); |
| 72 |
| 73 StaticStringsTable::const_iterator it = staticStrings.begin(); |
| 74 for (; it != staticStrings.end(); ++it) { |
| 75 addStringImpl(it->value); |
| 48 } | 76 } |
| 49 | 77 } |
| 50 StringImpl* addStringImpl(StringImpl* string) | 78 |
| 51 { | 79 static void destroy(AtomicStringTable* table) { |
| 52 if (!string->length()) | 80 HashSet<StringImpl*>::iterator end = table->m_table.end(); |
| 53 return StringImpl::empty(); | 81 for (HashSet<StringImpl*>::iterator iter = table->m_table.begin(); iter != e
nd; ++iter) { |
| 54 | 82 StringImpl* string = *iter; |
| 55 StringImpl* result = *m_table.add(string).storedValue; | 83 if (!string->isStatic()) { |
| 56 | 84 ASSERT(string->isAtomic()); |
| 57 if (!result->isAtomic()) | 85 string->setIsAtomic(false); |
| 58 result->setIsAtomic(true); | 86 } |
| 59 | |
| 60 ASSERT(!string->isStatic() || result->isStatic()); | |
| 61 return result; | |
| 62 } | 87 } |
| 63 | 88 delete table; |
| 64 HashSet<StringImpl*>& table() | 89 } |
| 65 { | 90 |
| 66 return m_table; | 91 HashSet<StringImpl*> m_table; |
| 67 } | 92 }; |
| 68 | 93 |
| 69 private: | 94 static inline AtomicStringTable& atomicStringTable() { |
| 70 AtomicStringTable() { } | 95 // Once possible we should make this non-lazy (constructed in WTFThreadData's
constructor). |
| 71 | 96 WTFThreadData& data = wtfThreadData(); |
| 72 void addStaticStrings() | 97 AtomicStringTable* table = data.atomicStringTable(); |
| 73 { | 98 if (UNLIKELY(!table)) |
| 74 const StaticStringsTable& staticStrings = StringImpl::allStaticStrings()
; | 99 table = AtomicStringTable::create(data); |
| 75 | 100 return *table; |
| 76 StaticStringsTable::const_iterator it = staticStrings.begin(); | 101 } |
| 77 for (; it != staticStrings.end(); ++it) { | 102 |
| 78 addStringImpl(it->value); | 103 static inline HashSet<StringImpl*>& atomicStrings() { |
| 79 } | 104 return atomicStringTable().table(); |
| 80 } | 105 } |
| 81 | 106 |
| 82 static void destroy(AtomicStringTable* table) | 107 void AtomicString::reserveTableCapacity(size_t size) { |
| 83 { | 108 atomicStringTable().table().reserveCapacityForSize(size); |
| 84 HashSet<StringImpl*>::iterator end = table->m_table.end(); | 109 } |
| 85 for (HashSet<StringImpl*>::iterator iter = table->m_table.begin(); iter
!= end; ++iter) { | 110 |
| 86 StringImpl* string = *iter; | 111 template <typename T, typename HashTranslator> |
| 87 if (!string->isStatic()) { | 112 static inline PassRefPtr<StringImpl> addToStringTable(const T& value) { |
| 88 ASSERT(string->isAtomic()); | 113 HashSet<StringImpl*>::AddResult addResult = atomicStrings().add<HashTranslator
>(value); |
| 89 string->setIsAtomic(false); | 114 |
| 90 } | 115 // If the string is newly-translated, then we need to adopt it. |
| 91 } | 116 // The boolean in the pair tells us if that is so. |
| 92 delete table; | 117 return addResult.isNewEntry ? adoptRef(*addResult.storedValue) : *addResult.st
oredValue; |
| 93 } | 118 } |
| 94 | 119 |
| 95 HashSet<StringImpl*> m_table; | 120 PassRefPtr<StringImpl> AtomicString::add(const LChar* c) { |
| 96 }; | 121 if (!c) |
| 97 | 122 return nullptr; |
| 98 static inline AtomicStringTable& atomicStringTable() | 123 if (!*c) |
| 99 { | 124 return StringImpl::empty(); |
| 100 // Once possible we should make this non-lazy (constructed in WTFThreadData'
s constructor). | 125 |
| 101 WTFThreadData& data = wtfThreadData(); | 126 return add(c, strlen(reinterpret_cast<const char*>(c))); |
| 102 AtomicStringTable* table = data.atomicStringTable(); | 127 } |
| 103 if (UNLIKELY(!table)) | 128 |
| 104 table = AtomicStringTable::create(data); | 129 template <typename CharacterType> |
| 105 return *table; | |
| 106 } | |
| 107 | |
| 108 static inline HashSet<StringImpl*>& atomicStrings() | |
| 109 { | |
| 110 return atomicStringTable().table(); | |
| 111 } | |
| 112 | |
| 113 void AtomicString::reserveTableCapacity(size_t size) | |
| 114 { | |
| 115 atomicStringTable().table().reserveCapacityForSize(size); | |
| 116 } | |
| 117 | |
| 118 template<typename T, typename HashTranslator> | |
| 119 static inline PassRefPtr<StringImpl> addToStringTable(const T& value) | |
| 120 { | |
| 121 HashSet<StringImpl*>::AddResult addResult = atomicStrings().add<HashTranslat
or>(value); | |
| 122 | |
| 123 // If the string is newly-translated, then we need to adopt it. | |
| 124 // The boolean in the pair tells us if that is so. | |
| 125 return addResult.isNewEntry ? adoptRef(*addResult.storedValue) : *addResult.
storedValue; | |
| 126 } | |
| 127 | |
| 128 PassRefPtr<StringImpl> AtomicString::add(const LChar* c) | |
| 129 { | |
| 130 if (!c) | |
| 131 return nullptr; | |
| 132 if (!*c) | |
| 133 return StringImpl::empty(); | |
| 134 | |
| 135 return add(c, strlen(reinterpret_cast<const char*>(c))); | |
| 136 } | |
| 137 | |
| 138 template<typename CharacterType> | |
| 139 struct HashTranslatorCharBuffer { | 130 struct HashTranslatorCharBuffer { |
| 140 const CharacterType* s; | 131 const CharacterType* s; |
| 141 unsigned length; | 132 unsigned length; |
| 142 }; | 133 }; |
| 143 | 134 |
| 144 typedef HashTranslatorCharBuffer<UChar> UCharBuffer; | 135 typedef HashTranslatorCharBuffer<UChar> UCharBuffer; |
| 145 struct UCharBufferTranslator { | 136 struct UCharBufferTranslator { |
| 146 static unsigned hash(const UCharBuffer& buf) | 137 static unsigned hash(const UCharBuffer& buf) { |
| 147 { | 138 return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length); |
| 148 return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length); | 139 } |
| 140 |
| 141 static bool equal(StringImpl* const& str, const UCharBuffer& buf) { |
| 142 return WTF::equal(str, buf.s, buf.length); |
| 143 } |
| 144 |
| 145 static void translate(StringImpl*& location, const UCharBuffer& buf, unsigned
hash) { |
| 146 location = StringImpl::create8BitIfPossible(buf.s, buf.length).leakRef(); |
| 147 location->setHash(hash); |
| 148 location->setIsAtomic(true); |
| 149 } |
| 150 }; |
| 151 |
| 152 template <typename CharacterType> |
| 153 struct HashAndCharacters { |
| 154 unsigned hash; |
| 155 const CharacterType* characters; |
| 156 unsigned length; |
| 157 }; |
| 158 |
| 159 template <typename CharacterType> |
| 160 struct HashAndCharactersTranslator { |
| 161 static unsigned hash(const HashAndCharacters<CharacterType>& buffer) { |
| 162 ASSERT(buffer.hash == StringHasher::computeHashAndMaskTop8Bits(buffer.charac
ters, buffer.length)); |
| 163 return buffer.hash; |
| 164 } |
| 165 |
| 166 static bool equal(StringImpl* const& string, const HashAndCharacters<Character
Type>& buffer) { |
| 167 return WTF::equal(string, buffer.characters, buffer.length); |
| 168 } |
| 169 |
| 170 static void translate(StringImpl*& location, const HashAndCharacters<Character
Type>& buffer, unsigned hash) { |
| 171 location = StringImpl::create(buffer.characters, buffer.length).leakRef(); |
| 172 location->setHash(hash); |
| 173 location->setIsAtomic(true); |
| 174 } |
| 175 }; |
| 176 |
| 177 struct HashAndUTF8Characters { |
| 178 unsigned hash; |
| 179 const char* characters; |
| 180 unsigned length; |
| 181 unsigned utf16Length; |
| 182 }; |
| 183 |
| 184 struct HashAndUTF8CharactersTranslator { |
| 185 static unsigned hash(const HashAndUTF8Characters& buffer) { |
| 186 return buffer.hash; |
| 187 } |
| 188 |
| 189 static bool equal(StringImpl* const& string, const HashAndUTF8Characters& buff
er) { |
| 190 if (buffer.utf16Length != string->length()) |
| 191 return false; |
| 192 |
| 193 // If buffer contains only ASCII characters UTF-8 and UTF16 length are the s
ame. |
| 194 if (buffer.utf16Length != buffer.length) { |
| 195 if (string->is8Bit()) { |
| 196 const LChar* characters8 = string->characters8(); |
| 197 return equalLatin1WithUTF8(characters8, characters8 + string->length(),
buffer.characters, buffer.characters + buffer.length); |
| 198 } |
| 199 const UChar* characters16 = string->characters16(); |
| 200 return equalUTF16WithUTF8(characters16, characters16 + string->length(), b
uffer.characters, buffer.characters + buffer.length); |
| 149 } | 201 } |
| 150 | 202 |
| 151 static bool equal(StringImpl* const& str, const UCharBuffer& buf) | 203 if (string->is8Bit()) { |
| 152 { | 204 const LChar* stringCharacters = string->characters8(); |
| 153 return WTF::equal(str, buf.s, buf.length); | 205 |
| 206 for (unsigned i = 0; i < buffer.length; ++i) { |
| 207 ASSERT(isASCII(buffer.characters[i])); |
| 208 if (stringCharacters[i] != buffer.characters[i]) |
| 209 return false; |
| 210 } |
| 211 |
| 212 return true; |
| 154 } | 213 } |
| 155 | 214 |
| 156 static void translate(StringImpl*& location, const UCharBuffer& buf, unsigne
d hash) | 215 const UChar* stringCharacters = string->characters16(); |
| 157 { | 216 |
| 158 location = StringImpl::create8BitIfPossible(buf.s, buf.length).leakRef()
; | 217 for (unsigned i = 0; i < buffer.length; ++i) { |
| 159 location->setHash(hash); | 218 ASSERT(isASCII(buffer.characters[i])); |
| 160 location->setIsAtomic(true); | 219 if (stringCharacters[i] != buffer.characters[i]) |
| 220 return false; |
| 161 } | 221 } |
| 162 }; | 222 |
| 163 | 223 return true; |
| 164 template<typename CharacterType> | 224 } |
| 165 struct HashAndCharacters { | 225 |
| 166 unsigned hash; | 226 static void translate(StringImpl*& location, const HashAndUTF8Characters& buff
er, unsigned hash) { |
| 167 const CharacterType* characters; | 227 UChar* target; |
| 168 unsigned length; | 228 RefPtr<StringImpl> newString = StringImpl::createUninitialized(buffer.utf16L
ength, target); |
| 169 }; | 229 |
| 170 | 230 bool isAllASCII; |
| 171 template<typename CharacterType> | 231 const char* source = buffer.characters; |
| 172 struct HashAndCharactersTranslator { | 232 if (convertUTF8ToUTF16(&source, source + buffer.length, &target, target + bu
ffer.utf16Length, &isAllASCII) != conversionOK) |
| 173 static unsigned hash(const HashAndCharacters<CharacterType>& buffer) | 233 ASSERT_NOT_REACHED(); |
| 174 { | 234 |
| 175 ASSERT(buffer.hash == StringHasher::computeHashAndMaskTop8Bits(buffer.ch
aracters, buffer.length)); | 235 if (isAllASCII) |
| 176 return buffer.hash; | 236 newString = StringImpl::create(buffer.characters, buffer.length); |
| 177 } | 237 |
| 178 | 238 location = newString.release().leakRef(); |
| 179 static bool equal(StringImpl* const& string, const HashAndCharacters<Charact
erType>& buffer) | 239 location->setHash(hash); |
| 180 { | 240 location->setIsAtomic(true); |
| 181 return WTF::equal(string, buffer.characters, buffer.length); | 241 } |
| 182 } | 242 }; |
| 183 | 243 |
| 184 static void translate(StringImpl*& location, const HashAndCharacters<Charact
erType>& buffer, unsigned hash) | 244 PassRefPtr<StringImpl> AtomicString::add(const UChar* s, unsigned length) { |
| 185 { | 245 if (!s) |
| 186 location = StringImpl::create(buffer.characters, buffer.length).leakRef(
); | 246 return nullptr; |
| 187 location->setHash(hash); | 247 |
| 188 location->setIsAtomic(true); | 248 if (!length) |
| 189 } | 249 return StringImpl::empty(); |
| 190 }; | 250 |
| 191 | 251 UCharBuffer buffer = {s, length}; |
| 192 struct HashAndUTF8Characters { | 252 return addToStringTable<UCharBuffer, UCharBufferTranslator>(buffer); |
| 193 unsigned hash; | 253 } |
| 194 const char* characters; | 254 |
| 195 unsigned length; | 255 PassRefPtr<StringImpl> AtomicString::add(const UChar* s, unsigned length, unsign
ed existingHash) { |
| 196 unsigned utf16Length; | 256 ASSERT(s); |
| 197 }; | 257 ASSERT(existingHash); |
| 198 | 258 |
| 199 struct HashAndUTF8CharactersTranslator { | 259 if (!length) |
| 200 static unsigned hash(const HashAndUTF8Characters& buffer) | 260 return StringImpl::empty(); |
| 201 { | 261 |
| 202 return buffer.hash; | 262 HashAndCharacters<UChar> buffer = {existingHash, s, length}; |
| 203 } | 263 return addToStringTable<HashAndCharacters<UChar>, HashAndCharactersTranslator<
UChar>>(buffer); |
| 204 | 264 } |
| 205 static bool equal(StringImpl* const& string, const HashAndUTF8Characters& bu
ffer) | 265 |
| 206 { | 266 PassRefPtr<StringImpl> AtomicString::add(const UChar* s) { |
| 207 if (buffer.utf16Length != string->length()) | 267 if (!s) |
| 208 return false; | 268 return nullptr; |
| 209 | 269 |
| 210 // If buffer contains only ASCII characters UTF-8 and UTF16 length are t
he same. | 270 unsigned length = 0; |
| 211 if (buffer.utf16Length != buffer.length) { | 271 while (s[length] != UChar(0)) |
| 212 if (string->is8Bit()) { | 272 ++length; |
| 213 const LChar* characters8 = string->characters8(); | 273 |
| 214 return equalLatin1WithUTF8(characters8, characters8 + string->le
ngth(), buffer.characters, buffer.characters + buffer.length); | 274 if (!length) |
| 215 } | 275 return StringImpl::empty(); |
| 216 const UChar* characters16 = string->characters16(); | 276 |
| 217 return equalUTF16WithUTF8(characters16, characters16 + string->lengt
h(), buffer.characters, buffer.characters + buffer.length); | 277 UCharBuffer buffer = {s, length}; |
| 218 } | 278 return addToStringTable<UCharBuffer, UCharBufferTranslator>(buffer); |
| 219 | |
| 220 if (string->is8Bit()) { | |
| 221 const LChar* stringCharacters = string->characters8(); | |
| 222 | |
| 223 for (unsigned i = 0; i < buffer.length; ++i) { | |
| 224 ASSERT(isASCII(buffer.characters[i])); | |
| 225 if (stringCharacters[i] != buffer.characters[i]) | |
| 226 return false; | |
| 227 } | |
| 228 | |
| 229 return true; | |
| 230 } | |
| 231 | |
| 232 const UChar* stringCharacters = string->characters16(); | |
| 233 | |
| 234 for (unsigned i = 0; i < buffer.length; ++i) { | |
| 235 ASSERT(isASCII(buffer.characters[i])); | |
| 236 if (stringCharacters[i] != buffer.characters[i]) | |
| 237 return false; | |
| 238 } | |
| 239 | |
| 240 return true; | |
| 241 } | |
| 242 | |
| 243 static void translate(StringImpl*& location, const HashAndUTF8Characters& bu
ffer, unsigned hash) | |
| 244 { | |
| 245 UChar* target; | |
| 246 RefPtr<StringImpl> newString = StringImpl::createUninitialized(buffer.ut
f16Length, target); | |
| 247 | |
| 248 bool isAllASCII; | |
| 249 const char* source = buffer.characters; | |
| 250 if (convertUTF8ToUTF16(&source, source + buffer.length, &target, target
+ buffer.utf16Length, &isAllASCII) != conversionOK) | |
| 251 ASSERT_NOT_REACHED(); | |
| 252 | |
| 253 if (isAllASCII) | |
| 254 newString = StringImpl::create(buffer.characters, buffer.length); | |
| 255 | |
| 256 location = newString.release().leakRef(); | |
| 257 location->setHash(hash); | |
| 258 location->setIsAtomic(true); | |
| 259 } | |
| 260 }; | |
| 261 | |
| 262 PassRefPtr<StringImpl> AtomicString::add(const UChar* s, unsigned length) | |
| 263 { | |
| 264 if (!s) | |
| 265 return nullptr; | |
| 266 | |
| 267 if (!length) | |
| 268 return StringImpl::empty(); | |
| 269 | |
| 270 UCharBuffer buffer = { s, length }; | |
| 271 return addToStringTable<UCharBuffer, UCharBufferTranslator>(buffer); | |
| 272 } | |
| 273 | |
| 274 PassRefPtr<StringImpl> AtomicString::add(const UChar* s, unsigned length, unsign
ed existingHash) | |
| 275 { | |
| 276 ASSERT(s); | |
| 277 ASSERT(existingHash); | |
| 278 | |
| 279 if (!length) | |
| 280 return StringImpl::empty(); | |
| 281 | |
| 282 HashAndCharacters<UChar> buffer = { existingHash, s, length }; | |
| 283 return addToStringTable<HashAndCharacters<UChar>, HashAndCharactersTranslato
r<UChar>>(buffer); | |
| 284 } | |
| 285 | |
| 286 PassRefPtr<StringImpl> AtomicString::add(const UChar* s) | |
| 287 { | |
| 288 if (!s) | |
| 289 return nullptr; | |
| 290 | |
| 291 unsigned length = 0; | |
| 292 while (s[length] != UChar(0)) | |
| 293 ++length; | |
| 294 | |
| 295 if (!length) | |
| 296 return StringImpl::empty(); | |
| 297 | |
| 298 UCharBuffer buffer = { s, length }; | |
| 299 return addToStringTable<UCharBuffer, UCharBufferTranslator>(buffer); | |
| 300 } | 279 } |
| 301 | 280 |
| 302 struct SubstringLocation { | 281 struct SubstringLocation { |
| 303 StringImpl* baseString; | 282 StringImpl* baseString; |
| 304 unsigned start; | 283 unsigned start; |
| 305 unsigned length; | 284 unsigned length; |
| 306 }; | 285 }; |
| 307 | 286 |
| 308 struct SubstringTranslator { | 287 struct SubstringTranslator { |
| 309 static unsigned hash(const SubstringLocation& buffer) | 288 static unsigned hash(const SubstringLocation& buffer) { |
| 310 { | 289 if (buffer.baseString->is8Bit()) |
| 311 if (buffer.baseString->is8Bit()) | 290 return StringHasher::computeHashAndMaskTop8Bits(buffer.baseString->charact
ers8() + buffer.start, buffer.length); |
| 312 return StringHasher::computeHashAndMaskTop8Bits(buffer.baseString->c
haracters8() + buffer.start, buffer.length); | 291 return StringHasher::computeHashAndMaskTop8Bits(buffer.baseString->character
s16() + buffer.start, buffer.length); |
| 313 return StringHasher::computeHashAndMaskTop8Bits(buffer.baseString->chara
cters16() + buffer.start, buffer.length); | 292 } |
| 314 } | 293 |
| 315 | 294 static bool equal(StringImpl* const& string, const SubstringLocation& buffer)
{ |
| 316 static bool equal(StringImpl* const& string, const SubstringLocation& buffer
) | 295 if (buffer.baseString->is8Bit()) |
| 317 { | 296 return WTF::equal(string, buffer.baseString->characters8() + buffer.start,
buffer.length); |
| 318 if (buffer.baseString->is8Bit()) | 297 return WTF::equal(string, buffer.baseString->characters16() + buffer.start,
buffer.length); |
| 319 return WTF::equal(string, buffer.baseString->characters8() + buffer.
start, buffer.length); | 298 } |
| 320 return WTF::equal(string, buffer.baseString->characters16() + buffer.sta
rt, buffer.length); | 299 |
| 321 } | 300 static void translate(StringImpl*& location, const SubstringLocation& buffer,
unsigned hash) { |
| 322 | 301 location = buffer.baseString->substring(buffer.start, buffer.length).leakRef
(); |
| 323 static void translate(StringImpl*& location, const SubstringLocation& buffer
, unsigned hash) | 302 location->setHash(hash); |
| 324 { | 303 location->setIsAtomic(true); |
| 325 location = buffer.baseString->substring(buffer.start, buffer.length).lea
kRef(); | 304 } |
| 326 location->setHash(hash); | 305 }; |
| 327 location->setIsAtomic(true); | 306 |
| 328 } | 307 PassRefPtr<StringImpl> AtomicString::add(StringImpl* baseString, unsigned start,
unsigned length) { |
| 329 }; | 308 if (!baseString) |
| 330 | 309 return nullptr; |
| 331 PassRefPtr<StringImpl> AtomicString::add(StringImpl* baseString, unsigned start,
unsigned length) | 310 |
| 332 { | 311 if (!length || start >= baseString->length()) |
| 333 if (!baseString) | 312 return StringImpl::empty(); |
| 334 return nullptr; | 313 |
| 335 | 314 unsigned maxLength = baseString->length() - start; |
| 336 if (!length || start >= baseString->length()) | 315 if (length >= maxLength) { |
| 337 return StringImpl::empty(); | 316 if (!start) |
| 338 | 317 return add(baseString); |
| 339 unsigned maxLength = baseString->length() - start; | 318 length = maxLength; |
| 340 if (length >= maxLength) { | 319 } |
| 341 if (!start) | 320 |
| 342 return add(baseString); | 321 SubstringLocation buffer = {baseString, start, length}; |
| 343 length = maxLength; | 322 return addToStringTable<SubstringLocation, SubstringTranslator>(buffer); |
| 344 } | |
| 345 | |
| 346 SubstringLocation buffer = { baseString, start, length }; | |
| 347 return addToStringTable<SubstringLocation, SubstringTranslator>(buffer); | |
| 348 } | 323 } |
| 349 | 324 |
| 350 typedef HashTranslatorCharBuffer<LChar> LCharBuffer; | 325 typedef HashTranslatorCharBuffer<LChar> LCharBuffer; |
| 351 struct LCharBufferTranslator { | 326 struct LCharBufferTranslator { |
| 352 static unsigned hash(const LCharBuffer& buf) | 327 static unsigned hash(const LCharBuffer& buf) { |
| 353 { | 328 return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length); |
| 354 return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length); | 329 } |
| 355 } | 330 |
| 356 | 331 static bool equal(StringImpl* const& str, const LCharBuffer& buf) { |
| 357 static bool equal(StringImpl* const& str, const LCharBuffer& buf) | 332 return WTF::equal(str, buf.s, buf.length); |
| 358 { | 333 } |
| 359 return WTF::equal(str, buf.s, buf.length); | 334 |
| 360 } | 335 static void translate(StringImpl*& location, const LCharBuffer& buf, unsigned
hash) { |
| 361 | 336 location = StringImpl::create(buf.s, buf.length).leakRef(); |
| 362 static void translate(StringImpl*& location, const LCharBuffer& buf, unsigne
d hash) | 337 location->setHash(hash); |
| 363 { | 338 location->setIsAtomic(true); |
| 364 location = StringImpl::create(buf.s, buf.length).leakRef(); | 339 } |
| 365 location->setHash(hash); | |
| 366 location->setIsAtomic(true); | |
| 367 } | |
| 368 }; | 340 }; |
| 369 | 341 |
| 370 typedef HashTranslatorCharBuffer<char> CharBuffer; | 342 typedef HashTranslatorCharBuffer<char> CharBuffer; |
| 371 struct CharBufferFromLiteralDataTranslator { | 343 struct CharBufferFromLiteralDataTranslator { |
| 372 static unsigned hash(const CharBuffer& buf) | 344 static unsigned hash(const CharBuffer& buf) { |
| 373 { | 345 return StringHasher::computeHashAndMaskTop8Bits(reinterpret_cast<const LChar
*>(buf.s), buf.length); |
| 374 return StringHasher::computeHashAndMaskTop8Bits(reinterpret_cast<const L
Char*>(buf.s), buf.length); | 346 } |
| 375 } | 347 |
| 376 | 348 static bool equal(StringImpl* const& str, const CharBuffer& buf) { |
| 377 static bool equal(StringImpl* const& str, const CharBuffer& buf) | 349 return WTF::equal(str, buf.s, buf.length); |
| 378 { | 350 } |
| 379 return WTF::equal(str, buf.s, buf.length); | 351 |
| 380 } | 352 static void translate(StringImpl*& location, const CharBuffer& buf, unsigned h
ash) { |
| 381 | 353 location = StringImpl::create(buf.s, buf.length).leakRef(); |
| 382 static void translate(StringImpl*& location, const CharBuffer& buf, unsigned
hash) | 354 location->setHash(hash); |
| 383 { | 355 location->setIsAtomic(true); |
| 384 location = StringImpl::create(buf.s, buf.length).leakRef(); | 356 } |
| 385 location->setHash(hash); | 357 }; |
| 386 location->setIsAtomic(true); | 358 |
| 387 } | 359 PassRefPtr<StringImpl> AtomicString::add(const LChar* s, unsigned length) { |
| 388 }; | 360 if (!s) |
| 389 | 361 return nullptr; |
| 390 PassRefPtr<StringImpl> AtomicString::add(const LChar* s, unsigned length) | 362 |
| 391 { | 363 if (!length) |
| 392 if (!s) | 364 return StringImpl::empty(); |
| 393 return nullptr; | 365 |
| 394 | 366 LCharBuffer buffer = {s, length}; |
| 395 if (!length) | 367 return addToStringTable<LCharBuffer, LCharBufferTranslator>(buffer); |
| 396 return StringImpl::empty(); | 368 } |
| 397 | 369 |
| 398 LCharBuffer buffer = { s, length }; | 370 PassRefPtr<StringImpl> AtomicString::addFromLiteralData(const char* characters,
unsigned length) { |
| 399 return addToStringTable<LCharBuffer, LCharBufferTranslator>(buffer); | 371 ASSERT(characters); |
| 400 } | 372 ASSERT(length); |
| 401 | 373 |
| 402 PassRefPtr<StringImpl> AtomicString::addFromLiteralData(const char* characters,
unsigned length) | 374 CharBuffer buffer = {characters, length}; |
| 403 { | 375 return addToStringTable<CharBuffer, CharBufferFromLiteralDataTranslator>(buffe
r); |
| 404 ASSERT(characters); | 376 } |
| 405 ASSERT(length); | 377 |
| 406 | 378 PassRefPtr<StringImpl> AtomicString::addSlowCase(StringImpl* string) { |
| 407 CharBuffer buffer = { characters, length }; | 379 return atomicStringTable().addStringImpl(string); |
| 408 return addToStringTable<CharBuffer, CharBufferFromLiteralDataTranslator>(buf
fer); | 380 } |
| 409 } | 381 |
| 410 | 382 template <typename CharacterType> |
| 411 PassRefPtr<StringImpl> AtomicString::addSlowCase(StringImpl* string) | 383 static inline HashSet<StringImpl*>::iterator findString(const StringImpl* string
Impl) { |
| 412 { | 384 HashAndCharacters<CharacterType> buffer = {stringImpl->existingHash(), stringI
mpl->getCharacters<CharacterType>(), stringImpl->length()}; |
| 413 return atomicStringTable().addStringImpl(string); | 385 return atomicStrings().find<HashAndCharactersTranslator<CharacterType>>(buffer
); |
| 414 } | 386 } |
| 415 | 387 |
| 416 template<typename CharacterType> | 388 StringImpl* AtomicString::find(const StringImpl* stringImpl) { |
| 417 static inline HashSet<StringImpl*>::iterator findString(const StringImpl* string
Impl) | 389 ASSERT(stringImpl); |
| 418 { | 390 ASSERT(stringImpl->existingHash()); |
| 419 HashAndCharacters<CharacterType> buffer = { stringImpl->existingHash(), stri
ngImpl->getCharacters<CharacterType>(), stringImpl->length() }; | 391 |
| 420 return atomicStrings().find<HashAndCharactersTranslator<CharacterType>>(buff
er); | 392 if (!stringImpl->length()) |
| 421 } | 393 return StringImpl::empty(); |
| 422 | 394 |
| 423 StringImpl* AtomicString::find(const StringImpl* stringImpl) | 395 HashSet<StringImpl*>::iterator iterator; |
| 424 { | 396 if (stringImpl->is8Bit()) |
| 425 ASSERT(stringImpl); | 397 iterator = findString<LChar>(stringImpl); |
| 426 ASSERT(stringImpl->existingHash()); | 398 else |
| 427 | 399 iterator = findString<UChar>(stringImpl); |
| 428 if (!stringImpl->length()) | 400 if (iterator == atomicStrings().end()) |
| 429 return StringImpl::empty(); | 401 return 0; |
| 430 | 402 return *iterator; |
| 431 HashSet<StringImpl*>::iterator iterator; | 403 } |
| 432 if (stringImpl->is8Bit()) | 404 |
| 433 iterator = findString<LChar>(stringImpl); | 405 void AtomicString::remove(StringImpl* r) { |
| 434 else | 406 HashSet<StringImpl*>::iterator iterator; |
| 435 iterator = findString<UChar>(stringImpl); | 407 if (r->is8Bit()) |
| 436 if (iterator == atomicStrings().end()) | 408 iterator = findString<LChar>(r); |
| 437 return 0; | 409 else |
| 438 return *iterator; | 410 iterator = findString<UChar>(r); |
| 439 } | 411 RELEASE_ASSERT(iterator != atomicStrings().end()); |
| 440 | 412 atomicStrings().remove(iterator); |
| 441 void AtomicString::remove(StringImpl* r) | 413 } |
| 442 { | 414 |
| 443 HashSet<StringImpl*>::iterator iterator; | 415 AtomicString AtomicString::lower() const { |
| 444 if (r->is8Bit()) | 416 // Note: This is a hot function in the Dromaeo benchmark. |
| 445 iterator = findString<LChar>(r); | 417 StringImpl* impl = this->impl(); |
| 446 else | 418 if (UNLIKELY(!impl)) |
| 447 iterator = findString<UChar>(r); | 419 return *this; |
| 448 RELEASE_ASSERT(iterator != atomicStrings().end()); | 420 RefPtr<StringImpl> newImpl = impl->lower(); |
| 449 atomicStrings().remove(iterator); | 421 if (LIKELY(newImpl == impl)) |
| 450 } | 422 return *this; |
| 451 | 423 return AtomicString(newImpl.release()); |
| 452 AtomicString AtomicString::lower() const | 424 } |
| 453 { | 425 |
| 454 // Note: This is a hot function in the Dromaeo benchmark. | 426 AtomicString AtomicString::fromUTF8Internal(const char* charactersStart, const c
har* charactersEnd) { |
| 455 StringImpl* impl = this->impl(); | 427 HashAndUTF8Characters buffer; |
| 456 if (UNLIKELY(!impl)) | 428 buffer.characters = charactersStart; |
| 457 return *this; | 429 buffer.hash = calculateStringHashAndLengthFromUTF8MaskingTop8Bits(charactersSt
art, charactersEnd, buffer.length, buffer.utf16Length); |
| 458 RefPtr<StringImpl> newImpl = impl->lower(); | 430 |
| 459 if (LIKELY(newImpl == impl)) | 431 if (!buffer.hash) |
| 460 return *this; | 432 return nullAtom; |
| 461 return AtomicString(newImpl.release()); | 433 |
| 462 } | 434 AtomicString atomicString; |
| 463 | 435 atomicString.m_string = addToStringTable<HashAndUTF8Characters, HashAndUTF8Cha
ractersTranslator>(buffer); |
| 464 AtomicString AtomicString::fromUTF8Internal(const char* charactersStart, const c
har* charactersEnd) | 436 return atomicString; |
| 465 { | 437 } |
| 466 HashAndUTF8Characters buffer; | 438 |
| 467 buffer.characters = charactersStart; | 439 AtomicString AtomicString::number(int number) { |
| 468 buffer.hash = calculateStringHashAndLengthFromUTF8MaskingTop8Bits(characters
Start, charactersEnd, buffer.length, buffer.utf16Length); | 440 return numberToStringSigned<AtomicString>(number); |
| 469 | 441 } |
| 470 if (!buffer.hash) | 442 |
| 471 return nullAtom; | 443 AtomicString AtomicString::number(unsigned number) { |
| 472 | 444 return numberToStringUnsigned<AtomicString>(number); |
| 473 AtomicString atomicString; | 445 } |
| 474 atomicString.m_string = addToStringTable<HashAndUTF8Characters, HashAndUTF8C
haractersTranslator>(buffer); | 446 |
| 475 return atomicString; | 447 AtomicString AtomicString::number(long number) { |
| 476 } | 448 return numberToStringSigned<AtomicString>(number); |
| 477 | 449 } |
| 478 AtomicString AtomicString::number(int number) | 450 |
| 479 { | 451 AtomicString AtomicString::number(unsigned long number) { |
| 480 return numberToStringSigned<AtomicString>(number); | 452 return numberToStringUnsigned<AtomicString>(number); |
| 481 } | 453 } |
| 482 | 454 |
| 483 AtomicString AtomicString::number(unsigned number) | 455 AtomicString AtomicString::number(long long number) { |
| 484 { | 456 return numberToStringSigned<AtomicString>(number); |
| 485 return numberToStringUnsigned<AtomicString>(number); | 457 } |
| 486 } | 458 |
| 487 | 459 AtomicString AtomicString::number(unsigned long long number) { |
| 488 AtomicString AtomicString::number(long number) | 460 return numberToStringUnsigned<AtomicString>(number); |
| 489 { | 461 } |
| 490 return numberToStringSigned<AtomicString>(number); | 462 |
| 491 } | 463 AtomicString AtomicString::number(double number, unsigned precision, TrailingZer
osTruncatingPolicy trailingZerosTruncatingPolicy) { |
| 492 | 464 NumberToStringBuffer buffer; |
| 493 AtomicString AtomicString::number(unsigned long number) | 465 return AtomicString(numberToFixedPrecisionString(number, precision, buffer, tr
ailingZerosTruncatingPolicy == TruncateTrailingZeros)); |
| 494 { | |
| 495 return numberToStringUnsigned<AtomicString>(number); | |
| 496 } | |
| 497 | |
| 498 AtomicString AtomicString::number(long long number) | |
| 499 { | |
| 500 return numberToStringSigned<AtomicString>(number); | |
| 501 } | |
| 502 | |
| 503 AtomicString AtomicString::number(unsigned long long number) | |
| 504 { | |
| 505 return numberToStringUnsigned<AtomicString>(number); | |
| 506 } | |
| 507 | |
| 508 AtomicString AtomicString::number(double number, unsigned precision, TrailingZer
osTruncatingPolicy trailingZerosTruncatingPolicy) | |
| 509 { | |
| 510 NumberToStringBuffer buffer; | |
| 511 return AtomicString(numberToFixedPrecisionString(number, precision, buffer,
trailingZerosTruncatingPolicy == TruncateTrailingZeros)); | |
| 512 } | 466 } |
| 513 | 467 |
| 514 #ifndef NDEBUG | 468 #ifndef NDEBUG |
| 515 void AtomicString::show() const | 469 void AtomicString::show() const { |
| 516 { | 470 m_string.show(); |
| 517 m_string.show(); | |
| 518 } | 471 } |
| 519 #endif | 472 #endif |
| 520 | 473 |
| 521 } // namespace WTF | 474 } // namespace WTF |
| OLD | NEW |