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