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/Forward.h>
25#include <wtf/HashTraits.h>
26#include <wtf/RefCounted.h>
27#include <wtf/text/AtomicString.h>
28
29namespace WebCore {
30
31struct QualifiedNameComponents {
32    StringImpl* m_prefix;
33    StringImpl* m_localName;
34    StringImpl* m_namespace;
35};
36
37class QualifiedName {
38    WTF_MAKE_FAST_ALLOCATED;
39public:
40    class QualifiedNameImpl : public RefCounted<QualifiedNameImpl> {
41    public:
42        static PassRef<QualifiedNameImpl> create(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI)
43        {
44            return adoptRef(*new QualifiedNameImpl(prefix, localName, namespaceURI));
45        }
46
47        ~QualifiedNameImpl();
48
49        unsigned computeHash() const;
50
51        mutable unsigned m_existingHash;
52        const AtomicString m_prefix;
53        const AtomicString m_localName;
54        const AtomicString m_namespace;
55        mutable AtomicString m_localNameUpper;
56
57#if ENABLE(CSS_SELECTOR_JIT)
58        static ptrdiff_t localNameMemoryOffset() { return OBJECT_OFFSETOF(QualifiedNameImpl, m_localName); }
59        static ptrdiff_t namespaceMemoryOffset() { return OBJECT_OFFSETOF(QualifiedNameImpl, m_namespace); }
60#endif // ENABLE(CSS_SELECTOR_JIT)
61
62    private:
63        QualifiedNameImpl(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI)
64            : m_existingHash(0)
65            , m_prefix(prefix)
66            , m_localName(localName)
67            , m_namespace(namespaceURI)
68        {
69            ASSERT(!namespaceURI.isEmpty() || namespaceURI.isNull());
70        }
71    };
72
73    QualifiedName(const AtomicString& prefix, const AtomicString& localName, const AtomicString& namespaceURI);
74    explicit QualifiedName(WTF::HashTableDeletedValueType) : m_impl(WTF::HashTableDeletedValue) { }
75    bool isHashTableDeletedValue() const { return m_impl.isHashTableDeletedValue(); }
76#ifdef QNAME_DEFAULT_CONSTRUCTOR
77    QualifiedName() { }
78#endif
79
80    QualifiedName(const QualifiedName& other) : m_impl(other.m_impl) { }
81    const QualifiedName& operator=(const QualifiedName& other) { m_impl = other.m_impl; return *this; }
82
83    bool operator==(const QualifiedName& other) const { return m_impl == other.m_impl; }
84    bool operator!=(const QualifiedName& other) const { return !(*this == other); }
85
86    bool matches(const QualifiedName& other) const { return m_impl == other.m_impl || (localName() == other.localName() && namespaceURI() == other.namespaceURI()); }
87
88    bool matchesIgnoringCaseForLocalName(const QualifiedName& other, bool shouldIgnoreCase) const { return m_impl == other.m_impl || (equalPossiblyIgnoringCase(localName(), other.localName(), shouldIgnoreCase) && namespaceURI() == other.namespaceURI()); }
89
90    bool hasPrefix() const { return m_impl->m_prefix != nullAtom; }
91    void setPrefix(const AtomicString& prefix) { *this = QualifiedName(prefix, localName(), namespaceURI()); }
92
93    const AtomicString& prefix() const { return m_impl->m_prefix; }
94    const AtomicString& localName() const { return m_impl->m_localName; }
95    const AtomicString& namespaceURI() const { return m_impl->m_namespace; }
96
97    // Uppercased localName, cached for efficiency
98    const AtomicString& localNameUpper() const;
99
100    String toString() const;
101
102    QualifiedNameImpl* impl() const { return m_impl.get(); }
103#if ENABLE(CSS_SELECTOR_JIT)
104    static ptrdiff_t implMemoryOffset() { return OBJECT_OFFSETOF(QualifiedName, m_impl); }
105#endif // ENABLE(CSS_SELECTOR_JIT)
106
107    // Init routine for globals
108    static void init();
109
110private:
111    static QualifiedNameImpl* hashTableDeletedValue() { return RefPtr<QualifiedNameImpl>::hashTableDeletedValue(); }
112
113    RefPtr<QualifiedNameImpl> m_impl;
114};
115
116#ifndef WEBCORE_QUALIFIEDNAME_HIDE_GLOBALS
117extern const QualifiedName anyName;
118inline const QualifiedName& anyQName() { return anyName; }
119#endif
120
121const QualifiedName& nullQName();
122
123inline bool operator==(const AtomicString& a, const QualifiedName& q) { return a == q.localName(); }
124inline bool operator!=(const AtomicString& a, const QualifiedName& q) { return a != q.localName(); }
125inline bool operator==(const QualifiedName& q, const AtomicString& a) { return a == q.localName(); }
126inline bool operator!=(const QualifiedName& q, const AtomicString& a) { return a != q.localName(); }
127
128inline unsigned hashComponents(const QualifiedNameComponents& buf)
129{
130    return StringHasher::hashMemory<sizeof(QualifiedNameComponents)>(&buf);
131}
132
133struct QualifiedNameHash {
134    static unsigned hash(const QualifiedName& name) { return hash(name.impl()); }
135
136    static unsigned hash(const QualifiedName::QualifiedNameImpl* name)
137    {
138        if (!name->m_existingHash)
139            name->m_existingHash = name->computeHash();
140        return name->m_existingHash;
141    }
142
143    static bool equal(const QualifiedName& a, const QualifiedName& b) { return a == b; }
144    static bool equal(const QualifiedName::QualifiedNameImpl* a, const QualifiedName::QualifiedNameImpl* b) { return a == b; }
145
146    static const bool safeToCompareToEmptyOrDeleted = false;
147};
148
149void createQualifiedName(void* targetAddress, StringImpl* name);
150void createQualifiedName(void* targetAddress, StringImpl* name, const AtomicString& nameNamespace);
151
152}
153
154namespace WTF {
155
156    template<typename T> struct DefaultHash;
157
158    template<> struct DefaultHash<WebCore::QualifiedName> {
159        typedef WebCore::QualifiedNameHash Hash;
160    };
161
162    template<> struct HashTraits<WebCore::QualifiedName> : SimpleClassHashTraits<WebCore::QualifiedName> {
163        static const bool emptyValueIsZero = false;
164        static WebCore::QualifiedName emptyValue() { return WebCore::nullQName(); }
165    };
166}
167
168#endif
169