1/*
2 * Copyright (C) 2007-2014 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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 *
19 */
20
21#ifndef SpaceSplitString_h
22#define SpaceSplitString_h
23
24#include <wtf/MainThread.h>
25#include <wtf/text/AtomicString.h>
26
27namespace WebCore {
28
29class SpaceSplitStringData {
30    WTF_MAKE_NONCOPYABLE(SpaceSplitStringData);
31    WTF_MAKE_FAST_ALLOCATED;
32public:
33    static PassRefPtr<SpaceSplitStringData> create(const AtomicString&);
34
35    bool contains(const AtomicString& string)
36    {
37        const AtomicString* data = tokenArrayStart();
38        unsigned i = 0;
39        do {
40            if (data[i] == string)
41                return true;
42            ++i;
43        } while (i < m_size);
44        return false;
45    }
46
47    bool containsAll(SpaceSplitStringData&);
48
49    unsigned size() const { return m_size; }
50    static ptrdiff_t sizeMemoryOffset() { return OBJECT_OFFSETOF(SpaceSplitStringData, m_size); }
51
52    const AtomicString& operator[](unsigned i)
53    {
54        RELEASE_ASSERT(i < m_size);
55        return tokenArrayStart()[i];
56    }
57
58    void ref()
59    {
60        ASSERT(isMainThread());
61        ASSERT(m_refCount);
62        ++m_refCount;
63    }
64
65    void deref()
66    {
67        ASSERT(isMainThread());
68        ASSERT(m_refCount);
69        unsigned tempRefCount = m_refCount - 1;
70        if (!tempRefCount) {
71            destroy(this);
72            return;
73        }
74        m_refCount = tempRefCount;
75    }
76
77    static ptrdiff_t tokensMemoryOffset() { return sizeof(SpaceSplitStringData); }
78
79private:
80    static PassRefPtr<SpaceSplitStringData> create(const AtomicString&, unsigned tokenCount);
81    SpaceSplitStringData(const AtomicString& string, unsigned size)
82        : m_keyString(string)
83        , m_refCount(1)
84        , m_size(size)
85    {
86        ASSERT(!string.isEmpty());
87        ASSERT_WITH_MESSAGE(m_size, "SpaceSplitStringData should never be empty by definition. There is no difference between empty and null.");
88    }
89
90    ~SpaceSplitStringData() { }
91    static void destroy(SpaceSplitStringData*);
92
93    AtomicString* tokenArrayStart() { return reinterpret_cast<AtomicString*>(this + 1); }
94
95    AtomicString m_keyString;
96    unsigned m_refCount;
97    unsigned m_size;
98};
99
100class SpaceSplitString {
101public:
102    SpaceSplitString() { }
103    SpaceSplitString(const AtomicString& string, bool shouldFoldCase) { set(string, shouldFoldCase); }
104
105    bool operator!=(const SpaceSplitString& other) const { return m_data != other.m_data; }
106
107    void set(const AtomicString&, bool shouldFoldCase);
108    void clear() { m_data.clear(); }
109
110    bool contains(const AtomicString& string) const { return m_data && m_data->contains(string); }
111    bool containsAll(const SpaceSplitString& names) const { return !names.m_data || (m_data && m_data->containsAll(*names.m_data)); }
112
113    unsigned size() const { return m_data ? m_data->size() : 0; }
114    bool isEmpty() const { return !m_data; }
115    const AtomicString& operator[](unsigned i) const
116    {
117        ASSERT_WITH_SECURITY_IMPLICATION(m_data);
118        return (*m_data)[i];
119    }
120
121    static bool spaceSplitStringContainsValue(const String& spaceSplitString, const char* value, unsigned length, bool shouldFoldCase);
122    template<size_t length>
123    static bool spaceSplitStringContainsValue(const String& spaceSplitString, const char (&value)[length], bool shouldFoldCase)
124    {
125        return spaceSplitStringContainsValue(spaceSplitString, value, length - 1, shouldFoldCase);
126    }
127
128private:
129    RefPtr<SpaceSplitStringData> m_data;
130};
131
132} // namespace WebCore
133
134#endif // SpaceSplitString_h
135