|
1 /** |
|
2 * This file is part of the DOM implementation for KDE. |
|
3 * |
|
4 * Copyright (C) 2005, 2006 Apple Computer, Inc. |
|
5 * |
|
6 * This library is free software; you can redistribute it and/or |
|
7 * modify it under the terms of the GNU Library General Public |
|
8 * License as published by the Free Software Foundation; either |
|
9 * version 2 of the License, or (at your option) any later version. |
|
10 * |
|
11 * This library is distributed in the hope that it will be useful, |
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 * Library General Public License for more details. |
|
15 * |
|
16 * You should have received a copy of the GNU Library General Public License |
|
17 * along with this library; see the file COPYING.LIB. If not, write to |
|
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
19 * Boston, MA 02110-1301, USA. |
|
20 */ |
|
21 |
|
22 #include "config.h" |
|
23 |
|
24 #ifdef AVOID_STATIC_CONSTRUCTORS |
|
25 #define WEBCORE_QUALIFIEDNAME_HIDE_GLOBALS 1 |
|
26 #else |
|
27 #define QNAME_DEFAULT_CONSTRUCTOR |
|
28 #endif |
|
29 |
|
30 #include "QualifiedName.h" |
|
31 #include "StaticConstructors.h" |
|
32 #include <wtf/Assertions.h> |
|
33 #include <wtf/HashSet.h> |
|
34 |
|
35 namespace WebCore { |
|
36 |
|
37 struct QualifiedNameComponents { |
|
38 StringImpl* m_prefix; |
|
39 StringImpl* m_localName; |
|
40 StringImpl* m_namespace; |
|
41 }; |
|
42 |
|
43 // Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's |
|
44 static const unsigned PHI = 0x9e3779b9U; |
|
45 |
|
46 static inline unsigned hashComponents(const QualifiedNameComponents& buf) |
|
47 { |
|
48 ASSERT(sizeof(QualifiedNameComponents) % (sizeof(uint16_t) * 2) == 0); |
|
49 |
|
50 unsigned l = sizeof(QualifiedNameComponents) / (sizeof(uint16_t) * 2); |
|
51 const uint16_t* s = reinterpret_cast<const uint16_t*>(&buf); |
|
52 uint32_t hash = PHI; |
|
53 |
|
54 // Main loop |
|
55 for (; l > 0; l--) { |
|
56 hash += s[0]; |
|
57 uint32_t tmp = (s[1] << 11) ^ hash; |
|
58 hash = (hash << 16) ^ tmp; |
|
59 s += 2; |
|
60 hash += hash >> 11; |
|
61 } |
|
62 |
|
63 // Force "avalanching" of final 127 bits |
|
64 hash ^= hash << 3; |
|
65 hash += hash >> 5; |
|
66 hash ^= hash << 2; |
|
67 hash += hash >> 15; |
|
68 hash ^= hash << 10; |
|
69 |
|
70 // this avoids ever returning a hash code of 0, since that is used to |
|
71 // signal "hash not computed yet", using a value that is likely to be |
|
72 // effectively the same as 0 when the low bits are masked |
|
73 if (hash == 0) |
|
74 hash = 0x80000000; |
|
75 |
|
76 return hash; |
|
77 } |
|
78 |
|
79 struct QNameHash { |
|
80 static unsigned hash(const QualifiedName::QualifiedNameImpl* name) { |
|
81 QualifiedNameComponents c = { name->m_prefix.impl(), name->m_localName.impl(), name->m_namespace.impl() }; |
|
82 return hashComponents(c); |
|
83 } |
|
84 static bool equal(const QualifiedName::QualifiedNameImpl* a, const QualifiedName::QualifiedNameImpl* b) { return a == b; } |
|
85 }; |
|
86 |
|
87 typedef HashSet<QualifiedName::QualifiedNameImpl*, QNameHash> QNameSet; |
|
88 |
|
89 struct QNameComponentsTranslator { |
|
90 static unsigned hash(const QualifiedNameComponents& components) { |
|
91 return hashComponents(components); |
|
92 } |
|
93 static bool equal(QualifiedName::QualifiedNameImpl* name, const QualifiedNameComponents& c) { |
|
94 return c.m_prefix == name->m_prefix.impl() && c.m_localName == name->m_localName.impl() && c.m_namespace == name->m_namespace.impl(); |
|
95 } |
|
96 static void translate(QualifiedName::QualifiedNameImpl*& location, const QualifiedNameComponents& components, unsigned hash) { |
|
97 location = new QualifiedName::QualifiedNameImpl(components.m_prefix, components.m_localName, components.m_namespace); |
|
98 } |
|
99 }; |
|
100 |
|
101 static QNameSet* gNameCache; |
|
102 |
|
103 QualifiedName::QualifiedName(const AtomicString& p, const AtomicString& l, const AtomicString& n) |
|
104 : m_impl(0) |
|
105 { |
|
106 if (!gNameCache) |
|
107 gNameCache = new QNameSet; |
|
108 QualifiedNameComponents components = { p.impl(), l.impl(), n.impl() }; |
|
109 m_impl = *gNameCache->add<QualifiedNameComponents, QNameComponentsTranslator>(components).first; |
|
110 ref(); |
|
111 } |
|
112 |
|
113 QualifiedName::~QualifiedName() |
|
114 { |
|
115 deref(); |
|
116 } |
|
117 |
|
118 QualifiedName::QualifiedName(const QualifiedName& other) |
|
119 { |
|
120 m_impl = other.m_impl; |
|
121 ref(); |
|
122 } |
|
123 |
|
124 const QualifiedName& QualifiedName::operator=(const QualifiedName& other) |
|
125 { |
|
126 if (m_impl != other.m_impl) { |
|
127 deref(); |
|
128 m_impl = other.m_impl; |
|
129 ref(); |
|
130 } |
|
131 |
|
132 return *this; |
|
133 } |
|
134 |
|
135 void QualifiedName::deref() |
|
136 { |
|
137 #ifdef QNAME_DEFAULT_CONSTRUCTOR |
|
138 if (!m_impl) |
|
139 return; |
|
140 #endif |
|
141 |
|
142 if (m_impl->hasOneRef()) |
|
143 gNameCache->remove(m_impl); |
|
144 m_impl->deref(); |
|
145 } |
|
146 |
|
147 void QualifiedName::setPrefix(const AtomicString& prefix) |
|
148 { |
|
149 QualifiedName other(prefix, localName(), namespaceURI()); |
|
150 *this = other; |
|
151 } |
|
152 |
|
153 String QualifiedName::toString() const |
|
154 { |
|
155 String local = localName(); |
|
156 if (hasPrefix()) |
|
157 return prefix() + ":" + local; |
|
158 return local; |
|
159 } |
|
160 |
|
161 // Global init routines |
|
162 DEFINE_GLOBAL(QualifiedName, anyName, nullAtom, starAtom, starAtom) |
|
163 |
|
164 void QualifiedName::init() |
|
165 { |
|
166 static bool initialized; |
|
167 if (!initialized) { |
|
168 // Use placement new to initialize the globals. |
|
169 |
|
170 AtomicString::init(); |
|
171 new ((void*)&anyName) QualifiedName(nullAtom, starAtom, starAtom); |
|
172 initialized = true; |
|
173 } |
|
174 } |
|
175 |
|
176 } |