File indexing completed on 2024-04-28 11:38:27

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 }