File indexing completed on 2024-10-13 09:32:59
0001 /* 0002 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Library General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Library General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Library General Public License 0015 * along with this library; see the file COPYING.LIB. If not, write to 0016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 * 0019 */ 0020 0021 #ifdef AVOID_STATIC_CONSTRUCTORS 0022 #define ATOMICSTRING_HIDE_GLOBALS 1 0023 #endif 0024 0025 #include "AtomicString.h" 0026 0027 //#include "StaticConstructors.h" 0028 #include "StringHash.h" 0029 //#include <kjs/identifier.h> 0030 #include <wtf/HashSet.h> 0031 0032 //using KJS::Identifier; 0033 //using KJS::UString; 0034 0035 namespace khtml 0036 { 0037 0038 static HashSet<DOMStringImpl *> *stringTable; 0039 0040 struct CStringTranslator { 0041 static unsigned hash(const char *c) 0042 { 0043 return DOMStringImpl::computeHash(c); 0044 } 0045 0046 static bool equal(DOMStringImpl *r, const char *s) 0047 { 0048 int length = r->length(); 0049 const QChar *d = r->unicode(); 0050 for (int i = 0; i != length; ++i) { 0051 unsigned char c = s[i]; 0052 if (d[i] != c) { 0053 return false; 0054 } 0055 } 0056 return s[length] == 0; 0057 } 0058 0059 static void translate(DOMStringImpl *&location, const char *const &c, unsigned hash) 0060 { 0061 location = new DOMStringImpl(c, strlen(c), hash); 0062 } 0063 }; 0064 0065 bool operator==(const AtomicString &a, const char *b) 0066 { 0067 DOMStringImpl *impl = a.impl(); 0068 if ((!impl || !impl->unicode()) && !b) { 0069 return true; 0070 } 0071 if ((!impl || !impl->unicode()) || !b) { 0072 return false; 0073 } 0074 return CStringTranslator::equal(impl, b); 0075 } 0076 0077 DOMStringImpl *AtomicString::add(const char *c) 0078 { 0079 if (!c) { 0080 return nullptr; 0081 } 0082 if (!*c) { 0083 return DOMStringImpl::empty(); 0084 } 0085 init(); 0086 std::pair<HashSet<DOMStringImpl *>::iterator, bool> addResult = stringTable->add<const char *, CStringTranslator>(c); 0087 if (!addResult.second) { 0088 return *addResult.first; 0089 } 0090 return *addResult.first; 0091 } 0092 0093 struct UCharBuffer { 0094 const QChar *s; 0095 unsigned length; 0096 }; 0097 0098 static inline bool equal(DOMStringImpl *string, const QChar *characters, unsigned length) 0099 { 0100 if (string->length() != length) { 0101 return false; 0102 } 0103 0104 /* Do it 4-bytes-at-a-time on architectures where it's safe */ 0105 0106 const uint32_t *stringCharacters = reinterpret_cast<const uint32_t *>(string->unicode()); 0107 const uint32_t *bufferCharacters = reinterpret_cast<const uint32_t *>(characters); 0108 0109 unsigned halfLength = length >> 1; 0110 for (unsigned i = 0; i != halfLength; ++i) { 0111 if (*stringCharacters++ != *bufferCharacters++) { 0112 return false; 0113 } 0114 } 0115 0116 if (length & 1 && *reinterpret_cast<const uint16_t *>(stringCharacters) != *reinterpret_cast<const uint16_t *>(bufferCharacters)) { 0117 return false; 0118 } 0119 0120 return true; 0121 } 0122 0123 struct UCharBufferTranslator { 0124 static unsigned hash(const UCharBuffer &buf) 0125 { 0126 return DOMStringImpl::computeHash(buf.s, buf.length); 0127 } 0128 0129 static bool equal(DOMStringImpl *const &str, const UCharBuffer &buf) 0130 { 0131 return khtml::equal(str, buf.s, buf.length); 0132 } 0133 0134 static void translate(DOMStringImpl *&location, const UCharBuffer &buf, unsigned hash) 0135 { 0136 location = new DOMStringImpl(buf.s, buf.length, hash); 0137 } 0138 }; 0139 0140 struct HashAndCharacters { 0141 unsigned hash; 0142 const QChar *characters; 0143 unsigned length; 0144 }; 0145 0146 struct HashAndCharactersTranslator { 0147 static unsigned hash(const HashAndCharacters &buffer) 0148 { 0149 ASSERT(buffer.hash == DOMStringImpl::computeHash(buffer.characters, buffer.length)); 0150 return buffer.hash; 0151 } 0152 0153 static bool equal(DOMStringImpl *const &string, const HashAndCharacters &buffer) 0154 { 0155 return khtml::equal(string, buffer.characters, buffer.length); 0156 } 0157 0158 static void translate(DOMStringImpl *&location, const HashAndCharacters &buffer, unsigned hash) 0159 { 0160 location = new DOMStringImpl(buffer.characters, buffer.length, hash); 0161 } 0162 }; 0163 0164 DOMStringImpl *AtomicString::add(const QChar *s, int length) 0165 { 0166 if (!s) { 0167 return nullptr; 0168 } 0169 0170 if (length == 0) { 0171 return DOMStringImpl::empty(); 0172 } 0173 0174 init(); 0175 UCharBuffer buf = { s, static_cast<uint>(length) }; 0176 std::pair<HashSet<DOMStringImpl *>::iterator, bool> addResult = stringTable->add<UCharBuffer, UCharBufferTranslator>(buf); 0177 if (!addResult.second) { 0178 return *addResult.first; 0179 } 0180 return *addResult.first; 0181 } 0182 0183 DOMStringImpl *AtomicString::add(const QChar *s) 0184 { 0185 if (!s) { 0186 return nullptr; 0187 } 0188 0189 int length = 0; 0190 while (s[length] != QChar(0)) { 0191 length++; 0192 } 0193 0194 if (length == 0) { 0195 return DOMStringImpl::empty(); 0196 } 0197 0198 init(); 0199 UCharBuffer buf = {s, static_cast<uint>(length)}; 0200 std::pair<HashSet<DOMStringImpl *>::iterator, bool> addResult = stringTable->add<UCharBuffer, UCharBufferTranslator>(buf); 0201 if (!addResult.second) { 0202 return *addResult.first; 0203 } 0204 return *addResult.first; 0205 } 0206 0207 DOMStringImpl *AtomicString::add(DOMStringImpl *r) 0208 { 0209 if (!r || r->m_inTable) { 0210 return r; 0211 } 0212 0213 if (r->length() == 0) { 0214 return DOMStringImpl::empty(); 0215 } 0216 0217 init(); 0218 DOMStringImpl *result = *stringTable->add(r).first; 0219 if (result == r) { 0220 r->m_inTable = true; 0221 } 0222 return result; 0223 } 0224 0225 void AtomicString::remove(DOMStringImpl *r) 0226 { 0227 stringTable->remove(r); 0228 } 0229 0230 /*DOMStringImpl* AtomicString::add(const KJS::Identifier& identifier) 0231 { 0232 if (identifier.isNull()) 0233 return 0; 0234 0235 UString::Rep* string = identifier.ustring().rep(); 0236 unsigned length = string->size(); 0237 if (!length) 0238 return StringImpl::empty(); 0239 0240 HashAndCharacters buffer = { string->computedHash(), string->data(), length }; 0241 pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<HashAndCharacters, HashAndCharactersTranslator>(buffer); 0242 if (!addResult.second) 0243 return *addResult.first; 0244 return adoptRef(*addResult.first); 0245 } 0246 0247 PassRefPtr<StringImpl> AtomicString::add(const KJS::UString& ustring) 0248 { 0249 if (ustring.isNull()) 0250 return 0; 0251 0252 UString::Rep* string = ustring.rep(); 0253 unsigned length = string->size(); 0254 if (!length) 0255 return StringImpl::empty(); 0256 0257 HashAndCharacters buffer = { string->hash(), string->data(), length }; 0258 pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<HashAndCharacters, HashAndCharactersTranslator>(buffer); 0259 if (!addResult.second) 0260 return *addResult.first; 0261 return adoptRef(*addResult.first); 0262 } 0263 0264 AtomicStringImpl* AtomicString::find(const KJS::Identifier& identifier) 0265 { 0266 if (identifier.isNull()) 0267 return 0; 0268 0269 UString::Rep* string = identifier.ustring().rep(); 0270 unsigned length = string->size(); 0271 if (!length) 0272 return static_cast<AtomicStringImpl*>(StringImpl::empty()); 0273 0274 HashAndCharacters buffer = { string->computedHash(), string->data(), length }; 0275 HashSet<StringImpl*>::iterator iterator = stringTable->find<HashAndCharacters, HashAndCharactersTranslator>(buffer); 0276 if (iterator == stringTable->end()) 0277 return 0; 0278 return static_cast<AtomicStringImpl*>(*iterator); 0279 } 0280 0281 AtomicString::operator UString() const 0282 { 0283 return m_string; 0284 }*/ 0285 0286 #define DEFINE_GLOBAL(type, name, ...) \ 0287 const type name; 0288 0289 DEFINE_GLOBAL(AtomicString, nullAtom) 0290 DEFINE_GLOBAL(AtomicString, emptyAtom, "") 0291 DEFINE_GLOBAL(AtomicString, textAtom, "#text") 0292 DEFINE_GLOBAL(AtomicString, commentAtom, "#comment") 0293 DEFINE_GLOBAL(AtomicString, starAtom, "*") 0294 0295 void AtomicString::init() 0296 { 0297 static bool initialized; 0298 if (!initialized) { 0299 stringTable = new HashSet<DOMStringImpl *>; 0300 0301 // Use placement new to initialize the globals. 0302 /*new ((void*)&nullAtom) AtomicString; 0303 new ((void*)&emptyAtom) AtomicString(""); 0304 new ((void*)&textAtom) AtomicString("#text"); 0305 new ((void*)&commentAtom) AtomicString("#comment"); 0306 new ((void*)&starAtom) AtomicString("*");*/ 0307 0308 initialized = true; 0309 } 0310 } 0311 0312 }