| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "wtf/text/AtomicStringTable.h" | |
| 6 | |
| 7 #include "wtf/text/StringHash.h" | |
| 8 #include "wtf/text/UTF8.h" | |
| 9 | |
| 10 namespace WTF { | |
| 11 | |
| 12 using namespace Unicode; | |
| 13 | |
| 14 AtomicStringTable::AtomicStringTable() { | |
| 15 for (StringImpl* string : StringImpl::allStaticStrings().values()) | |
| 16 add(string); | |
| 17 } | |
| 18 | |
| 19 AtomicStringTable::~AtomicStringTable() { | |
| 20 for (StringImpl* string : m_table) { | |
| 21 if (!string->isStatic()) { | |
| 22 DCHECK(string->isAtomic()); | |
| 23 string->setIsAtomic(false); | |
| 24 } | |
| 25 } | |
| 26 } | |
| 27 | |
| 28 void AtomicStringTable::reserveCapacity(unsigned size) { | |
| 29 m_table.reserveCapacityForSize(size); | |
| 30 } | |
| 31 | |
| 32 template <typename T, typename HashTranslator> | |
| 33 PassRefPtr<StringImpl> AtomicStringTable::addToStringTable(const T& value) { | |
| 34 HashSet<StringImpl*>::AddResult addResult = | |
| 35 m_table.addWithTranslator<HashTranslator>(value); | |
| 36 | |
| 37 // If the string is newly-translated, then we need to adopt it. | |
| 38 // The boolean in the pair tells us if that is so. | |
| 39 return addResult.isNewEntry ? adoptRef(*addResult.storedValue) | |
| 40 : *addResult.storedValue; | |
| 41 } | |
| 42 | |
| 43 template <typename CharacterType> | |
| 44 struct HashTranslatorCharBuffer { | |
| 45 const CharacterType* s; | |
| 46 unsigned length; | |
| 47 }; | |
| 48 | |
| 49 typedef HashTranslatorCharBuffer<UChar> UCharBuffer; | |
| 50 struct UCharBufferTranslator { | |
| 51 static unsigned hash(const UCharBuffer& buf) { | |
| 52 return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length); | |
| 53 } | |
| 54 | |
| 55 static bool equal(StringImpl* const& str, const UCharBuffer& buf) { | |
| 56 return WTF::equal(str, buf.s, buf.length); | |
| 57 } | |
| 58 | |
| 59 static void translate(StringImpl*& location, | |
| 60 const UCharBuffer& buf, | |
| 61 unsigned hash) { | |
| 62 location = StringImpl::create8BitIfPossible(buf.s, buf.length).leakRef(); | |
| 63 location->setHash(hash); | |
| 64 location->setIsAtomic(true); | |
| 65 } | |
| 66 }; | |
| 67 | |
| 68 struct HashAndUTF8Characters { | |
| 69 unsigned hash; | |
| 70 const char* characters; | |
| 71 unsigned length; | |
| 72 unsigned utf16Length; | |
| 73 }; | |
| 74 | |
| 75 struct HashAndUTF8CharactersTranslator { | |
| 76 static unsigned hash(const HashAndUTF8Characters& buffer) { | |
| 77 return buffer.hash; | |
| 78 } | |
| 79 | |
| 80 static bool equal(StringImpl* const& string, | |
| 81 const HashAndUTF8Characters& buffer) { | |
| 82 if (buffer.utf16Length != string->length()) | |
| 83 return false; | |
| 84 | |
| 85 // If buffer contains only ASCII characters UTF-8 and UTF16 length are the | |
| 86 // same. | |
| 87 if (buffer.utf16Length != buffer.length) { | |
| 88 if (string->is8Bit()) { | |
| 89 const LChar* characters8 = string->characters8(); | |
| 90 return equalLatin1WithUTF8(characters8, characters8 + string->length(), | |
| 91 buffer.characters, | |
| 92 buffer.characters + buffer.length); | |
| 93 } | |
| 94 const UChar* characters16 = string->characters16(); | |
| 95 return equalUTF16WithUTF8(characters16, characters16 + string->length(), | |
| 96 buffer.characters, | |
| 97 buffer.characters + buffer.length); | |
| 98 } | |
| 99 | |
| 100 if (string->is8Bit()) { | |
| 101 const LChar* stringCharacters = string->characters8(); | |
| 102 | |
| 103 for (unsigned i = 0; i < buffer.length; ++i) { | |
| 104 DCHECK(isASCII(buffer.characters[i])); | |
| 105 if (stringCharacters[i] != buffer.characters[i]) | |
| 106 return false; | |
| 107 } | |
| 108 | |
| 109 return true; | |
| 110 } | |
| 111 | |
| 112 const UChar* stringCharacters = string->characters16(); | |
| 113 | |
| 114 for (unsigned i = 0; i < buffer.length; ++i) { | |
| 115 DCHECK(isASCII(buffer.characters[i])); | |
| 116 if (stringCharacters[i] != buffer.characters[i]) | |
| 117 return false; | |
| 118 } | |
| 119 | |
| 120 return true; | |
| 121 } | |
| 122 | |
| 123 static void translate(StringImpl*& location, | |
| 124 const HashAndUTF8Characters& buffer, | |
| 125 unsigned hash) { | |
| 126 UChar* target; | |
| 127 RefPtr<StringImpl> newString = | |
| 128 StringImpl::createUninitialized(buffer.utf16Length, target); | |
| 129 | |
| 130 bool isAllASCII; | |
| 131 const char* source = buffer.characters; | |
| 132 if (convertUTF8ToUTF16(&source, source + buffer.length, &target, | |
| 133 target + buffer.utf16Length, | |
| 134 &isAllASCII) != conversionOK) | |
| 135 NOTREACHED(); | |
| 136 | |
| 137 if (isAllASCII) | |
| 138 newString = StringImpl::create(buffer.characters, buffer.length); | |
| 139 | |
| 140 location = newString.leakRef(); | |
| 141 location->setHash(hash); | |
| 142 location->setIsAtomic(true); | |
| 143 } | |
| 144 }; | |
| 145 | |
| 146 PassRefPtr<StringImpl> AtomicStringTable::add(const UChar* s, unsigned length) { | |
| 147 if (!s) | |
| 148 return nullptr; | |
| 149 | |
| 150 if (!length) | |
| 151 return StringImpl::empty; | |
| 152 | |
| 153 UCharBuffer buffer = {s, length}; | |
| 154 return addToStringTable<UCharBuffer, UCharBufferTranslator>(buffer); | |
| 155 } | |
| 156 | |
| 157 typedef HashTranslatorCharBuffer<LChar> LCharBuffer; | |
| 158 struct LCharBufferTranslator { | |
| 159 static unsigned hash(const LCharBuffer& buf) { | |
| 160 return StringHasher::computeHashAndMaskTop8Bits(buf.s, buf.length); | |
| 161 } | |
| 162 | |
| 163 static bool equal(StringImpl* const& str, const LCharBuffer& buf) { | |
| 164 return WTF::equal(str, buf.s, buf.length); | |
| 165 } | |
| 166 | |
| 167 static void translate(StringImpl*& location, | |
| 168 const LCharBuffer& buf, | |
| 169 unsigned hash) { | |
| 170 location = StringImpl::create(buf.s, buf.length).leakRef(); | |
| 171 location->setHash(hash); | |
| 172 location->setIsAtomic(true); | |
| 173 } | |
| 174 }; | |
| 175 | |
| 176 PassRefPtr<StringImpl> AtomicStringTable::add(const LChar* s, unsigned length) { | |
| 177 if (!s) | |
| 178 return nullptr; | |
| 179 | |
| 180 if (!length) | |
| 181 return StringImpl::empty; | |
| 182 | |
| 183 LCharBuffer buffer = {s, length}; | |
| 184 return addToStringTable<LCharBuffer, LCharBufferTranslator>(buffer); | |
| 185 } | |
| 186 | |
| 187 StringImpl* AtomicStringTable::add(StringImpl* string) { | |
| 188 if (!string->length()) | |
| 189 return StringImpl::empty; | |
| 190 | |
| 191 StringImpl* result = *m_table.insert(string).storedValue; | |
| 192 | |
| 193 if (!result->isAtomic()) | |
| 194 result->setIsAtomic(true); | |
| 195 | |
| 196 DCHECK(!string->isStatic() || result->isStatic()); | |
| 197 return result; | |
| 198 } | |
| 199 | |
| 200 PassRefPtr<StringImpl> AtomicStringTable::addUTF8(const char* charactersStart, | |
| 201 const char* charactersEnd) { | |
| 202 HashAndUTF8Characters buffer; | |
| 203 buffer.characters = charactersStart; | |
| 204 buffer.hash = calculateStringHashAndLengthFromUTF8MaskingTop8Bits( | |
| 205 charactersStart, charactersEnd, buffer.length, buffer.utf16Length); | |
| 206 | |
| 207 if (!buffer.hash) | |
| 208 return nullptr; | |
| 209 | |
| 210 return addToStringTable<HashAndUTF8Characters, | |
| 211 HashAndUTF8CharactersTranslator>(buffer); | |
| 212 } | |
| 213 | |
| 214 void AtomicStringTable::remove(StringImpl* string) { | |
| 215 DCHECK(string->isAtomic()); | |
| 216 auto iterator = m_table.find(string); | |
| 217 RELEASE_ASSERT(iterator != m_table.end()); | |
| 218 m_table.erase(iterator); | |
| 219 } | |
| 220 | |
| 221 } // namespace WTF | |
| OLD | NEW |