1 /* 2 * Copyright (C) 2005, 2006, 2009 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 #ifndef QualifiedName_h 22 #define QualifiedName_h 23 24 #include "wtf/HashTableDeletedValueType.h" 25 #include "wtf/HashTraits.h" 26 #include "wtf/RefCounted.h" 27 #include "wtf/text/AtomicString.h" 28 29 namespace WebCore { 30 31 struct QualifiedNameComponents { 32 StringImpl* m_prefix; 33 StringImpl* m_localName; 34 StringImpl* m_namespace; 35 }; 36 37 // This struct is used to pass data between QualifiedName and the QNameTranslator. 38 // For hashing and equality only the QualifiedNameComponents fields are used. 39 struct QualifiedNameData { 40 QualifiedNameComponents m_components; 41 bool m_isStatic; 42 }; 43 44 class QualifiedName { 45 WTF_MAKE_FAST_ALLOCATED; 46 public: 47 class QualifiedNameImpl : public RefCounted<QualifiedNameImpl> { 48 public: 49 static PassRefPtr<QualifiedNameImpl> create(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI, bool isStatic) 50 { 51 return adoptRef(new QualifiedNameImpl(prefix, localName, namespaceURI, isStatic)); 52 } 53 54 ~QualifiedNameImpl(); 55 56 unsigned computeHash() const; 57 58 bool hasOneRef() const 59 { 60 return m_isStatic || RefCounted<QualifiedNameImpl>::hasOneRef(); 61 } 62 63 void ref() 64 { 65 if (m_isStatic) 66 return; 67 RefCounted<QualifiedNameImpl>::ref(); 68 } 69 70 void deref() 71 { 72 if (m_isStatic) 73 return; 74 RefCounted<QualifiedNameImpl>::deref(); 75 } 76 77 const AtomicString m_prefix; 78 const AtomicString m_localName; 79 const AtomicString m_namespace; 80 mutable AtomicString m_localNameUpper; 81 // We rely on StringHasher's hashMemory clearing out the top 8 bits when 82 // doing hashing and use one of the bits for the m_isStatic value. 83 mutable unsigned m_existingHash : 24; 84 unsigned m_isStatic : 1; 85 86 private: 87 QualifiedNameImpl(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI, bool isStatic) 88 : m_prefix(prefix) 89 , m_localName(localName) 90 , m_namespace(namespaceURI) 91 , m_existingHash(0) 92 , m_isStatic(isStatic) 93 94 { 95 ASSERT(!namespaceURI.isEmpty() || namespaceURI.isNull()); 96 } 97 }; 98 99 QualifiedName(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI); 100 ~QualifiedName(); 101 #ifdef QNAME_DEFAULT_CONSTRUCTOR 102 QualifiedName() { } 103 #endif 104 105 QualifiedName(const QualifiedName& other) : m_impl(other.m_impl) { } 106 const QualifiedName& operator=(const QualifiedName& other) { m_impl = other.m_impl; return *this; } 107 108 // Hash table deleted values, which are only constructed and never copied or destroyed. 109 QualifiedName(WTF::HashTableDeletedValueType) : m_impl(WTF::HashTableDeletedValue) { } 110 bool isHashTableDeletedValue() const { return m_impl.isHashTableDeletedValue(); } 111 112 bool operator==(const QualifiedName& other) const { return m_impl == other.m_impl; } 113 bool operator!=(const QualifiedName& other) const { return !(*this == other); } 114 115 bool matches(const QualifiedName& other) const { return m_impl == other.m_impl || (localName() == other.localName() && namespaceURI() == other.namespaceURI()); } 116 117 bool matchesPossiblyIgnoringCase(const QualifiedName& other, bool shouldIgnoreCase) const { return m_impl == other.m_impl || (equalPossiblyIgnoringCase(localName(), other.localName(), shouldIgnoreCase) && namespaceURI() == other.namespaceURI()); } 118 119 bool hasPrefix() const { return m_impl->m_prefix != nullAtom; } 120 void setPrefix(const AtomicString& prefix) { *this = QualifiedName(prefix, localName(), namespaceURI()); } 121 122 const AtomicString& prefix() const { return m_impl->m_prefix; } 123 const AtomicString& localName() const { return m_impl->m_localName; } 124 const AtomicString& namespaceURI() const { return m_impl->m_namespace; } 125 126 // Uppercased localName, cached for efficiency 127 const AtomicString& localNameUpper() const; 128 129 String toString() const; 130 131 QualifiedNameImpl* impl() const { return m_impl.get(); } 132 133 // Init routine for globals 134 static void init(); 135 136 static const QualifiedName& null(); 137 138 // The below methods are only for creating static global QNames that need no ref counting. 139 static void createStatic(void* targetAddress, StringImpl* name); 140 static void createStatic(void* targetAddress, StringImpl* name, const AtomicString& nameNamespace); 141 142 private: 143 // This constructor is used only to create global/static QNames that don't require any ref counting. 144 QualifiedName(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI, bool isStatic); 145 146 RefPtr<QualifiedNameImpl> m_impl; 147 }; 148 149 #ifndef WEBCORE_QUALIFIEDNAME_HIDE_GLOBALS 150 extern const QualifiedName anyName; 151 inline const QualifiedName& anyQName() { return anyName; } 152 #endif 153 154 inline bool operator==(const AtomicString& a, const QualifiedName& q) { return a == q.localName(); } 155 inline bool operator!=(const AtomicString& a, const QualifiedName& q) { return a != q.localName(); } 156 inline bool operator==(const QualifiedName& q, const AtomicString& a) { return a == q.localName(); } 157 inline bool operator!=(const QualifiedName& q, const AtomicString& a) { return a != q.localName(); } 158 159 inline unsigned hashComponents(const QualifiedNameComponents& buf) 160 { 161 return StringHasher::hashMemory<sizeof(QualifiedNameComponents)>(&buf); 162 } 163 164 struct QualifiedNameHash { 165 static unsigned hash(const QualifiedName& name) { return hash(name.impl()); } 166 167 static unsigned hash(const QualifiedName::QualifiedNameImpl* name) 168 { 169 if (!name->m_existingHash) 170 name->m_existingHash = name->computeHash(); 171 return name->m_existingHash; 172 } 173 174 static bool equal(const QualifiedName& a, const QualifiedName& b) { return a == b; } 175 static bool equal(const QualifiedName::QualifiedNameImpl* a, const QualifiedName::QualifiedNameImpl* b) { return a == b; } 176 177 static const bool safeToCompareToEmptyOrDeleted = false; 178 }; 179 180 } 181 182 namespace WTF { 183 184 template<typename T> struct DefaultHash; 185 186 template<> struct DefaultHash<WebCore::QualifiedName> { 187 typedef WebCore::QualifiedNameHash Hash; 188 }; 189 190 template<> struct HashTraits<WebCore::QualifiedName> : SimpleClassHashTraits<WebCore::QualifiedName> { 191 static const bool emptyValueIsZero = false; 192 static WebCore::QualifiedName emptyValue() { return WebCore::QualifiedName::null(); } 193 }; 194 } 195 196 #endif 197