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 |