OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. | |
3 * | |
4 * This library is free software; you can redistribute it and/or | |
5 * modify it under the terms of the GNU Library General Public | |
6 * License as published by the Free Software Foundation; either | |
7 * version 2 of the License, or (at your option) any later version. | |
8 * | |
9 * This library is distributed in the hope that it will be useful, | |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 * Library General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU Library General Public License | |
15 * along with this library; see the file COPYING.LIB. If not, write to | |
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
17 * Boston, MA 02110-1301, USA. | |
18 * | |
19 */ | |
20 | |
21 #include "config.h" | |
22 | |
23 #ifdef SKIP_STATIC_CONSTRUCTORS_ON_GCC | |
24 #define ATOMICSTRING_HIDE_GLOBALS 1 | |
25 #endif | |
26 | |
27 #include "AtomicString.h" | |
28 | |
29 #include "StaticConstructors.h" | |
30 #include "StringHash.h" | |
31 #include <kjs/identifier.h> | |
32 #include <wtf/HashSet.h> | |
33 | |
34 #if USE(JSC) | |
35 using KJS::Identifier; | |
36 using KJS::UString; | |
37 #endif | |
38 | |
39 namespace WebCore { | |
40 | |
41 static HashSet<StringImpl*>* stringTable; | |
42 | |
43 struct CStringTranslator { | |
44 static unsigned hash(const char* c) | |
45 { | |
46 return StringImpl::computeHash(c); | |
47 } | |
48 | |
49 static bool equal(StringImpl* r, const char* s) | |
50 { | |
51 int length = r->length(); | |
52 const UChar* d = r->characters(); | |
53 for (int i = 0; i != length; ++i) { | |
54 unsigned char c = s[i]; | |
55 if (d[i] != c) | |
56 return false; | |
57 } | |
58 return s[length] == 0; | |
59 } | |
60 | |
61 static void translate(StringImpl*& location, const char* const& c, unsigned
hash) | |
62 { | |
63 location = new StringImpl(c, strlen(c), hash); | |
64 } | |
65 }; | |
66 | |
67 bool operator==(const AtomicString& a, const char* b) | |
68 { | |
69 StringImpl* impl = a.impl(); | |
70 if ((!impl || !impl->characters()) && !b) | |
71 return true; | |
72 if ((!impl || !impl->characters()) || !b) | |
73 return false; | |
74 return CStringTranslator::equal(impl, b); | |
75 } | |
76 | |
77 PassRefPtr<StringImpl> AtomicString::add(const char* c) | |
78 { | |
79 if (!c) | |
80 return 0; | |
81 if (!*c) | |
82 return StringImpl::empty(); | |
83 pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<cons
t char*, CStringTranslator>(c); | |
84 if (!addResult.second) | |
85 return *addResult.first; | |
86 return adoptRef(*addResult.first); | |
87 } | |
88 | |
89 struct UCharBuffer { | |
90 const UChar* s; | |
91 unsigned length; | |
92 }; | |
93 | |
94 static inline bool equal(StringImpl* string, const UChar* characters, unsigned l
ength) | |
95 { | |
96 if (string->length() != length) | |
97 return false; | |
98 | |
99 #if PLATFORM(ARM) | |
100 const UChar* stringCharacters = string->characters(); | |
101 for (unsigned i = 0; i != length; ++i) { | |
102 if (*stringCharacters++ != *characters++) | |
103 return false; | |
104 } | |
105 return true; | |
106 #else | |
107 /* Do it 4-bytes-at-a-time on architectures where it's safe */ | |
108 | |
109 const uint32_t* stringCharacters = reinterpret_cast<const uint32_t*>(string-
>characters()); | |
110 const uint32_t* bufferCharacters = reinterpret_cast<const uint32_t*>(charact
ers); | |
111 | |
112 unsigned halfLength = length >> 1; | |
113 for (unsigned i = 0; i != halfLength; ++i) { | |
114 if (*stringCharacters++ != *bufferCharacters++) | |
115 return false; | |
116 } | |
117 | |
118 if (length & 1 && *reinterpret_cast<const uint16_t*>(stringCharacters) != *
reinterpret_cast<const uint16_t*>(bufferCharacters)) | |
119 return false; | |
120 | |
121 return true; | |
122 #endif | |
123 } | |
124 | |
125 struct UCharBufferTranslator { | |
126 static unsigned hash(const UCharBuffer& buf) | |
127 { | |
128 return StringImpl::computeHash(buf.s, buf.length); | |
129 } | |
130 | |
131 static bool equal(StringImpl* const& str, const UCharBuffer& buf) | |
132 { | |
133 return WebCore::equal(str, buf.s, buf.length); | |
134 } | |
135 | |
136 static void translate(StringImpl*& location, const UCharBuffer& buf, unsigne
d hash) | |
137 { | |
138 location = new StringImpl(buf.s, buf.length, hash); | |
139 } | |
140 }; | |
141 | |
142 struct HashAndCharacters { | |
143 unsigned hash; | |
144 const UChar* characters; | |
145 unsigned length; | |
146 }; | |
147 | |
148 struct HashAndCharactersTranslator { | |
149 static unsigned hash(const HashAndCharacters& buffer) | |
150 { | |
151 ASSERT(buffer.hash == StringImpl::computeHash(buffer.characters, buffer.
length)); | |
152 return buffer.hash; | |
153 } | |
154 | |
155 static bool equal(StringImpl* const& string, const HashAndCharacters& buffer
) | |
156 { | |
157 return WebCore::equal(string, buffer.characters, buffer.length); | |
158 } | |
159 | |
160 static void translate(StringImpl*& location, const HashAndCharacters& buffer
, unsigned hash) | |
161 { | |
162 location = new StringImpl(buffer.characters, buffer.length, hash); | |
163 } | |
164 }; | |
165 | |
166 PassRefPtr<StringImpl> AtomicString::add(const UChar* s, int length) | |
167 { | |
168 if (!s) | |
169 return 0; | |
170 | |
171 if (length == 0) | |
172 return StringImpl::empty(); | |
173 | |
174 UCharBuffer buf = { s, length }; | |
175 pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<UCha
rBuffer, UCharBufferTranslator>(buf); | |
176 if (!addResult.second) | |
177 return *addResult.first; | |
178 return adoptRef(*addResult.first); | |
179 } | |
180 | |
181 PassRefPtr<StringImpl> AtomicString::add(const UChar* s) | |
182 { | |
183 if (!s) | |
184 return 0; | |
185 | |
186 int length = 0; | |
187 while (s[length] != UChar(0)) | |
188 length++; | |
189 | |
190 if (length == 0) | |
191 return StringImpl::empty(); | |
192 | |
193 UCharBuffer buf = {s, length}; | |
194 pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<UCha
rBuffer, UCharBufferTranslator>(buf); | |
195 if (!addResult.second) | |
196 return *addResult.first; | |
197 return adoptRef(*addResult.first); | |
198 } | |
199 | |
200 PassRefPtr<StringImpl> AtomicString::add(StringImpl* r) | |
201 { | |
202 if (!r || r->m_inTable) | |
203 return r; | |
204 | |
205 if (r->length() == 0) | |
206 return StringImpl::empty(); | |
207 | |
208 StringImpl* result = *stringTable->add(r).first; | |
209 if (result == r) | |
210 r->m_inTable = true; | |
211 return result; | |
212 } | |
213 | |
214 void AtomicString::remove(StringImpl* r) | |
215 { | |
216 stringTable->remove(r); | |
217 } | |
218 | |
219 #if USE(JSC) | |
220 PassRefPtr<StringImpl> AtomicString::add(const KJS::Identifier& identifier) | |
221 { | |
222 if (identifier.isNull()) | |
223 return 0; | |
224 | |
225 UString::Rep* string = identifier.ustring().rep(); | |
226 unsigned length = string->size(); | |
227 if (!length) | |
228 return StringImpl::empty(); | |
229 | |
230 HashAndCharacters buffer = { string->computedHash(), string->data(), length
}; | |
231 pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<Hash
AndCharacters, HashAndCharactersTranslator>(buffer); | |
232 if (!addResult.second) | |
233 return *addResult.first; | |
234 return adoptRef(*addResult.first); | |
235 } | |
236 | |
237 PassRefPtr<StringImpl> AtomicString::add(const KJS::UString& ustring) | |
238 { | |
239 if (ustring.isNull()) | |
240 return 0; | |
241 | |
242 UString::Rep* string = ustring.rep(); | |
243 unsigned length = string->size(); | |
244 if (!length) | |
245 return StringImpl::empty(); | |
246 | |
247 HashAndCharacters buffer = { string->hash(), string->data(), length }; | |
248 pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<Hash
AndCharacters, HashAndCharactersTranslator>(buffer); | |
249 if (!addResult.second) | |
250 return *addResult.first; | |
251 return adoptRef(*addResult.first); | |
252 } | |
253 | |
254 AtomicStringImpl* AtomicString::find(const KJS::Identifier& identifier) | |
255 { | |
256 if (identifier.isNull()) | |
257 return 0; | |
258 | |
259 UString::Rep* string = identifier.ustring().rep(); | |
260 unsigned length = string->size(); | |
261 if (!length) | |
262 return static_cast<AtomicStringImpl*>(StringImpl::empty()); | |
263 | |
264 HashAndCharacters buffer = { string->computedHash(), string->data(), length
}; | |
265 HashSet<StringImpl*>::iterator iterator = stringTable->find<HashAndCharacter
s, HashAndCharactersTranslator>(buffer); | |
266 if (iterator == stringTable->end()) | |
267 return 0; | |
268 return static_cast<AtomicStringImpl*>(*iterator); | |
269 } | |
270 | |
271 AtomicString::operator UString() const | |
272 { | |
273 return m_string; | |
274 } | |
275 #endif | |
276 | |
277 DEFINE_GLOBAL(AtomicString, nullAtom) | |
278 DEFINE_GLOBAL(AtomicString, emptyAtom, "") | |
279 DEFINE_GLOBAL(AtomicString, textAtom, "#text") | |
280 DEFINE_GLOBAL(AtomicString, commentAtom, "#comment") | |
281 DEFINE_GLOBAL(AtomicString, starAtom, "*") | |
282 | |
283 void AtomicString::init() | |
284 { | |
285 static bool initialized; | |
286 if (!initialized) { | |
287 stringTable = new HashSet<StringImpl*>; | |
288 | |
289 // Use placement new to initialize the globals. | |
290 new ((void*)&nullAtom) AtomicString; | |
291 new ((void*)&emptyAtom) AtomicString(""); | |
292 new ((void*)&textAtom) AtomicString("#text"); | |
293 new ((void*)&commentAtom) AtomicString("#comment"); | |
294 new ((void*)&starAtom) AtomicString("*"); | |
295 | |
296 initialized = true; | |
297 } | |
298 } | |
299 | |
300 } | |
OLD | NEW |