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 blink { 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 void ref() 59 { 60 if (m_isStatic) 61 return; 62 RefCounted<QualifiedNameImpl>::ref(); 63 } 64 65 void deref() 66 { 67 if (m_isStatic) 68 return; 69 RefCounted<QualifiedNameImpl>::deref(); 70 } 71 72 // We rely on StringHasher's hashMemory clearing out the top 8 bits when 73 // doing hashing and use one of the bits for the m_isStatic value. 74 mutable unsigned m_existingHash : 24; 75 unsigned m_isStatic : 1; 76 const AtomicString m_prefix; 77 const AtomicString m_localName; 78 const AtomicString m_namespace; 79 mutable AtomicString m_localNameUpper; 80 81 private: 82 QualifiedNameImpl(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI, bool isStatic) 83 : m_existingHash(0) 84 , m_isStatic(isStatic) 85 , m_prefix(prefix) 86 , m_localName(localName) 87 , m_namespace(namespaceURI) 88 89 { 90 ASSERT(!namespaceURI.isEmpty() || namespaceURI.isNull()); 91 } 92 }; 93 94 QualifiedName(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI); 95 ~QualifiedName(); 96 97 QualifiedName(const QualifiedName& other) : m_impl(other.m_impl) { } 98 const QualifiedName& operator=(const QualifiedName& other) { m_impl = other.m_impl; return *this; } 99 100 // Hash table deleted values, which are only constructed and never copied or destroyed. 101 QualifiedName(WTF::HashTableDeletedValueType) : m_impl(WTF::HashTableDeletedValue) { } 102 bool isHashTableDeletedValue() const { return m_impl.isHashTableDeletedValue(); } 103 104 bool operator==(const QualifiedName& other) const { return m_impl == other.m_impl; } 105 bool operator!=(const QualifiedName& other) const { return !(*this == other); } 106 107 bool matches(const QualifiedName& other) const { return m_impl == other.m_impl || (localName() == other.localName() && namespaceURI() == other.namespaceURI()); } 108 109 bool matchesPossiblyIgnoringCase(const QualifiedName& other, bool shouldIgnoreCase) const { return m_impl == other.m_impl || (equalPossiblyIgnoringCase(localName(), other.localName(), shouldIgnoreCase) && namespaceURI() == other.namespaceURI()); } 110 111 bool hasPrefix() const { return m_impl->m_prefix != nullAtom; } 112 void setPrefix(const AtomicString& prefix) { *this = QualifiedName(prefix, localName(), namespaceURI()); } 113 114 const AtomicString& prefix() const { return m_impl->m_prefix; } 115 const AtomicString& localName() const { return m_impl->m_localName; } 116 const AtomicString& namespaceURI() const { return m_impl->m_namespace; } 117 118 // Uppercased localName, cached for efficiency 119 const AtomicString& localNameUpper() const; 120 121 String toString() const; 122 123 QualifiedNameImpl* impl() const { return m_impl.get(); } 124 125 // Init routine for globals 126 static void init(); 127 128 static const QualifiedName& null(); 129 130 // The below methods are only for creating static global QNames that need no ref counting. 131 static void createStatic(void* targetAddress, StringImpl* name); 132 static void createStatic(void* targetAddress, StringImpl* name, const AtomicString& nameNamespace); 133 134 private: 135 // This constructor is used only to create global/static QNames that don't require any ref counting. 136 QualifiedName(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI, bool isStatic); 137 138 RefPtr<QualifiedNameImpl> m_impl; 139 }; 140 141 extern const QualifiedName& anyName; 142 inline const QualifiedName& anyQName() { return anyName; } 143 144 inline bool operator==(const AtomicString& a, const QualifiedName& q) { return a == q.localName(); } 145 inline bool operator!=(const AtomicString& a, const QualifiedName& q) { return a != q.localName(); } 146 inline bool operator==(const QualifiedName& q, const AtomicString& a) { return a == q.localName(); } 147 inline bool operator!=(const QualifiedName& q, const AtomicString& a) { return a != q.localName(); } 148 149 inline unsigned hashComponents(const QualifiedNameComponents& buf) 150 { 151 return StringHasher::hashMemory<sizeof(QualifiedNameComponents)>(&buf); 152 } 153 154 struct QualifiedNameHash { 155 static unsigned hash(const QualifiedName& name) { return hash(name.impl()); } 156 157 static unsigned hash(const QualifiedName::QualifiedNameImpl* name) 158 { 159 if (!name->m_existingHash) 160 name->m_existingHash = name->computeHash(); 161 return name->m_existingHash; 162 } 163 164 static bool equal(const QualifiedName& a, const QualifiedName& b) { return a == b; } 165 static bool equal(const QualifiedName::QualifiedNameImpl* a, const QualifiedName::QualifiedNameImpl* b) { return a == b; } 166 167 static const bool safeToCompareToEmptyOrDeleted = false; 168 }; 169 170 } // namespace blink 171 172 namespace WTF { 173 174 template<typename T> struct DefaultHash; 175 176 template<> struct DefaultHash<blink::QualifiedName> { 177 typedef blink::QualifiedNameHash Hash; 178 }; 179 180 template<> struct HashTraits<blink::QualifiedName> : SimpleClassHashTraits<blink::QualifiedName> { 181 static const bool emptyValueIsZero = false; 182 static blink::QualifiedName emptyValue() { return blink::QualifiedName::null(); } 183 }; 184 } 185 186 #endif 187