2 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
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.
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.
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.
21 #ifdef AVOID_STATIC_CONSTRUCTORS
22 #define ATOMICSTRING_HIDE_GLOBALS 1
25 #include "AtomicString.h"
27 //#include "StaticConstructors.h"
28 #include "StringHash.h"
29 //#include <kjs/identifier.h>
30 #include <wtf/HashSet.h>
32 //using KJS::Identifier;
37 static HashSet
<DOMStringImpl
*>* stringTable
;
39 struct CStringTranslator
{
40 static unsigned hash(const char* c
)
42 return DOMStringImpl::computeHash(c
);
45 static bool equal(DOMStringImpl
* r
, const char* s
)
47 int length
= r
->length();
48 const QChar
* d
= r
->unicode();
49 for (int i
= 0; i
!= length
; ++i
) {
50 unsigned char c
= s
[i
];
54 return s
[length
] == 0;
57 static void translate(DOMStringImpl
*& location
, const char* const& c
, unsigned hash
)
59 location
= new DOMStringImpl(c
, strlen(c
), hash
);
63 bool operator==(const AtomicString
& a
, const char* b
)
65 DOMStringImpl
* impl
= a
.impl();
66 if ((!impl
|| !impl
->unicode()) && !b
)
68 if ((!impl
|| !impl
->unicode()) || !b
)
70 return CStringTranslator::equal(impl
, b
);
73 DOMStringImpl
* AtomicString::add(const char* c
)
78 return DOMStringImpl::empty();
80 std::pair
<HashSet
<DOMStringImpl
*>::iterator
, bool> addResult
= stringTable
->add
<const char*, CStringTranslator
>(c
);
81 if (!addResult
.second
)
82 return *addResult
.first
;
83 return *addResult
.first
;
91 static inline bool equal(DOMStringImpl
* string
, const QChar
* characters
, unsigned length
)
93 if (string
->length() != length
)
96 /* Do it 4-bytes-at-a-time on architectures where it's safe */
98 const uint32_t* stringCharacters
= reinterpret_cast<const uint32_t*>(string
->unicode());
99 const uint32_t* bufferCharacters
= reinterpret_cast<const uint32_t*>(characters
);
101 unsigned halfLength
= length
>> 1;
102 for (unsigned i
= 0; i
!= halfLength
; ++i
) {
103 if (*stringCharacters
++ != *bufferCharacters
++)
107 if (length
& 1 && *reinterpret_cast<const uint16_t*>(stringCharacters
) != *reinterpret_cast<const uint16_t*>(bufferCharacters
))
113 struct UCharBufferTranslator
{
114 static unsigned hash(const UCharBuffer
& buf
)
116 return DOMStringImpl::computeHash(buf
.s
, buf
.length
);
119 static bool equal(DOMStringImpl
* const& str
, const UCharBuffer
& buf
)
121 return khtml::equal(str
, buf
.s
, buf
.length
);
124 static void translate(DOMStringImpl
*& location
, const UCharBuffer
& buf
, unsigned hash
)
126 location
= new DOMStringImpl(buf
.s
, buf
.length
, hash
);
130 struct HashAndCharacters
{
132 const QChar
* characters
;
136 struct HashAndCharactersTranslator
{
137 static unsigned hash(const HashAndCharacters
& buffer
)
139 ASSERT(buffer
.hash
== DOMStringImpl::computeHash(buffer
.characters
, buffer
.length
));
143 static bool equal(DOMStringImpl
* const& string
, const HashAndCharacters
& buffer
)
145 return khtml::equal(string
, buffer
.characters
, buffer
.length
);
148 static void translate(DOMStringImpl
*& location
, const HashAndCharacters
& buffer
, unsigned hash
)
150 location
= new DOMStringImpl(buffer
.characters
, buffer
.length
, hash
);
154 DOMStringImpl
* AtomicString::add(const QChar
* s
, int length
)
160 return DOMStringImpl::empty();
163 UCharBuffer buf
= { s
, length
};
164 std::pair
<HashSet
<DOMStringImpl
*>::iterator
, bool> addResult
= stringTable
->add
<UCharBuffer
, UCharBufferTranslator
>(buf
);
165 if (!addResult
.second
)
166 return *addResult
.first
;
167 return *addResult
.first
;
170 DOMStringImpl
* AtomicString::add(const QChar
* s
)
176 while (s
[length
] != QChar(0))
180 return DOMStringImpl::empty();
183 UCharBuffer buf
= {s
, length
};
184 std::pair
<HashSet
<DOMStringImpl
*>::iterator
, bool> addResult
= stringTable
->add
<UCharBuffer
, UCharBufferTranslator
>(buf
);
185 if (!addResult
.second
)
186 return *addResult
.first
;
187 return *addResult
.first
;
190 DOMStringImpl
* AtomicString::add(DOMStringImpl
* r
)
192 if (!r
|| r
->m_inTable
)
195 if (r
->length() == 0)
196 return DOMStringImpl::empty();
199 DOMStringImpl
* result
= *stringTable
->add(r
).first
;
205 void AtomicString::remove(DOMStringImpl
* r
)
207 stringTable
->remove(r
);
210 /*DOMStringImpl* AtomicString::add(const KJS::Identifier& identifier)
212 if (identifier.isNull())
215 UString::Rep* string = identifier.ustring().rep();
216 unsigned length = string->size();
218 return StringImpl::empty();
220 HashAndCharacters buffer = { string->computedHash(), string->data(), length };
221 pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<HashAndCharacters, HashAndCharactersTranslator>(buffer);
222 if (!addResult.second)
223 return *addResult.first;
224 return adoptRef(*addResult.first);
227 PassRefPtr<StringImpl> AtomicString::add(const KJS::UString& ustring)
229 if (ustring.isNull())
232 UString::Rep* string = ustring.rep();
233 unsigned length = string->size();
235 return StringImpl::empty();
237 HashAndCharacters buffer = { string->hash(), string->data(), length };
238 pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<HashAndCharacters, HashAndCharactersTranslator>(buffer);
239 if (!addResult.second)
240 return *addResult.first;
241 return adoptRef(*addResult.first);
244 AtomicStringImpl* AtomicString::find(const KJS::Identifier& identifier)
246 if (identifier.isNull())
249 UString::Rep* string = identifier.ustring().rep();
250 unsigned length = string->size();
252 return static_cast<AtomicStringImpl*>(StringImpl::empty());
254 HashAndCharacters buffer = { string->computedHash(), string->data(), length };
255 HashSet<StringImpl*>::iterator iterator = stringTable->find<HashAndCharacters, HashAndCharactersTranslator>(buffer);
256 if (iterator == stringTable->end())
258 return static_cast<AtomicStringImpl*>(*iterator);
261 AtomicString::operator UString() const
266 #define DEFINE_GLOBAL(type, name, ...) \
269 DEFINE_GLOBAL(AtomicString
, nullAtom
)
270 DEFINE_GLOBAL(AtomicString
, emptyAtom
, "")
271 DEFINE_GLOBAL(AtomicString
, textAtom
, "#text")
272 DEFINE_GLOBAL(AtomicString
, commentAtom
, "#comment")
273 DEFINE_GLOBAL(AtomicString
, starAtom
, "*")
275 void AtomicString::init()
277 static bool initialized
;
279 stringTable
= new HashSet
<DOMStringImpl
*>;
281 // Use placement new to initialize the globals.
282 /*new ((void*)&nullAtom) AtomicString;
283 new ((void*)&emptyAtom) AtomicString("");
284 new ((void*)&textAtom) AtomicString("#text");
285 new ((void*)&commentAtom) AtomicString("#comment");
286 new ((void*)&starAtom) AtomicString("*");*/