e082e1e9c1fc5cec583250efb585bbb25faa29e4
[WebKit-https.git] / Source / WTF / wtf / text / SymbolImpl.h
1 /*
2  * Copyright (C) 2015-2016 Yusuke Suzuki <utatane.tea@gmail.com>.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #include <wtf/text/UniquedStringImpl.h>
29
30 namespace WTF {
31
32 class RegisteredSymbolImpl;
33
34 // SymbolImpl is used to represent the symbol string impl.
35 // It is uniqued string impl, but is not registered in Atomic String tables, so it's not atomic.
36 class SymbolImpl : public UniquedStringImpl {
37 public:
38     using Flags = unsigned;
39     static constexpr Flags s_flagDefault = 0u;
40     static constexpr Flags s_flagIsNullSymbol = 0b001u;
41     static constexpr Flags s_flagIsRegistered = 0b010u;
42     static constexpr Flags s_flagIsPrivate = 0b100u;
43
44     unsigned hashForSymbol() const { return m_hashForSymbol; }
45     bool isNullSymbol() const { return m_flags & s_flagIsNullSymbol; }
46     bool isRegistered() const { return m_flags & s_flagIsRegistered; }
47     bool isPrivate() const { return m_flags & s_flagIsPrivate; }
48
49     SymbolRegistry* symbolRegistry() const;
50
51     RegisteredSymbolImpl* asRegisteredSymbolImpl();
52
53     WTF_EXPORT_PRIVATE static Ref<SymbolImpl> createNullSymbol();
54     WTF_EXPORT_PRIVATE static Ref<SymbolImpl> create(StringImpl& rep);
55
56     class StaticSymbolImpl : private StringImplShape {
57         WTF_MAKE_NONCOPYABLE(StaticSymbolImpl);
58     public:
59         template<unsigned characterCount>
60         constexpr StaticSymbolImpl(const char (&characters)[characterCount], Flags flags = s_flagDefault)
61             : StringImplShape(s_refCountFlagIsStaticString, characterCount - 1, characters,
62                 s_hashFlag8BitBuffer | s_hashFlagDidReportCost | StringSymbol | BufferInternal | (StringHasher::computeLiteralHashAndMaskTop8Bits(characters) << s_flagCount), ConstructWithConstExpr)
63             , m_hashForSymbol(StringHasher::computeLiteralHashAndMaskTop8Bits(characters) << s_flagCount)
64             , m_flags(flags)
65         {
66         }
67
68         template<unsigned characterCount>
69         constexpr StaticSymbolImpl(const char16_t (&characters)[characterCount], Flags flags = s_flagDefault)
70             : StringImplShape(s_refCountFlagIsStaticString, characterCount - 1, characters,
71                 s_hashFlagDidReportCost | StringSymbol | BufferInternal | (StringHasher::computeLiteralHashAndMaskTop8Bits(characters) << s_flagCount), ConstructWithConstExpr)
72             , m_hashForSymbol(StringHasher::computeLiteralHashAndMaskTop8Bits(characters) << s_flagCount)
73             , m_flags(flags)
74         {
75         }
76
77         operator SymbolImpl&()
78         {
79             return *reinterpret_cast<SymbolImpl*>(this);
80         }
81
82         StringImpl* m_owner { nullptr }; // We do not make StaticSymbolImpl BufferSubstring. Thus we can make this nullptr.
83         unsigned m_hashForSymbol;
84         Flags m_flags;
85     };
86
87 protected:
88     WTF_EXPORT_PRIVATE static unsigned nextHashForSymbol();
89
90     friend class StringImpl;
91
92     SymbolImpl(const LChar* characters, unsigned length, Ref<StringImpl>&& base, Flags flags = s_flagDefault)
93         : UniquedStringImpl(CreateSymbol, characters, length)
94         , m_owner(&base.leakRef())
95         , m_hashForSymbol(nextHashForSymbol())
96         , m_flags(flags)
97     {
98         ASSERT(StringImpl::tailOffset<StringImpl*>() == OBJECT_OFFSETOF(SymbolImpl, m_owner));
99     }
100
101     SymbolImpl(const UChar* characters, unsigned length, Ref<StringImpl>&& base, Flags flags = s_flagDefault)
102         : UniquedStringImpl(CreateSymbol, characters, length)
103         , m_owner(&base.leakRef())
104         , m_hashForSymbol(nextHashForSymbol())
105         , m_flags(flags)
106     {
107         ASSERT(StringImpl::tailOffset<StringImpl*>() == OBJECT_OFFSETOF(SymbolImpl, m_owner));
108     }
109
110     SymbolImpl(Flags flags = s_flagDefault)
111         : UniquedStringImpl(CreateSymbol)
112         , m_owner(StringImpl::empty())
113         , m_hashForSymbol(nextHashForSymbol())
114         , m_flags(flags | s_flagIsNullSymbol)
115     {
116         ASSERT(StringImpl::tailOffset<StringImpl*>() == OBJECT_OFFSETOF(SymbolImpl, m_owner));
117     }
118
119     ~SymbolImpl()
120     {
121         if (m_owner != StringImpl::empty())
122             m_owner->deref();
123         m_owner = nullptr;
124     }
125
126     // The pointer to the owner string should be immediately following after the StringImpl layout,
127     // since we would like to align the layout of SymbolImpl to the one of BufferSubstring StringImpl.
128     StringImpl* m_owner;
129     unsigned m_hashForSymbol;
130     Flags m_flags { s_flagDefault };
131 };
132 static_assert(sizeof(SymbolImpl) == sizeof(SymbolImpl::StaticSymbolImpl), "");
133
134 class PrivateSymbolImpl : public SymbolImpl {
135 public:
136     WTF_EXPORT_PRIVATE static Ref<PrivateSymbolImpl> createNullSymbol();
137     WTF_EXPORT_PRIVATE static Ref<PrivateSymbolImpl> create(StringImpl& rep);
138
139 private:
140     PrivateSymbolImpl(const LChar* characters, unsigned length, Ref<StringImpl>&& base)
141         : SymbolImpl(characters, length, WTFMove(base), s_flagIsPrivate)
142     {
143     }
144
145     PrivateSymbolImpl(const UChar* characters, unsigned length, Ref<StringImpl>&& base)
146         : SymbolImpl(characters, length, WTFMove(base), s_flagIsPrivate)
147     {
148     }
149
150     PrivateSymbolImpl()
151         : SymbolImpl(s_flagIsPrivate)
152     {
153     }
154 };
155
156 class RegisteredSymbolImpl : public SymbolImpl {
157 private:
158     friend class StringImpl;
159     friend class SymbolImpl;
160     friend class SymbolRegistry;
161
162     SymbolRegistry* symbolRegistry() const { return m_symbolRegistry; }
163     void clearSymbolRegistry() { m_symbolRegistry = nullptr; }
164
165     static Ref<RegisteredSymbolImpl> create(StringImpl& rep, SymbolRegistry&);
166
167     RegisteredSymbolImpl(const LChar* characters, unsigned length, Ref<StringImpl>&& base, SymbolRegistry& registry)
168         : SymbolImpl(characters, length, WTFMove(base), s_flagIsRegistered)
169         , m_symbolRegistry(&registry)
170     {
171     }
172
173     RegisteredSymbolImpl(const UChar* characters, unsigned length, Ref<StringImpl>&& base, SymbolRegistry& registry)
174         : SymbolImpl(characters, length, WTFMove(base), s_flagIsRegistered)
175         , m_symbolRegistry(&registry)
176     {
177     }
178
179     SymbolRegistry* m_symbolRegistry;
180 };
181
182 inline unsigned StringImpl::symbolAwareHash() const
183 {
184     if (isSymbol())
185         return static_cast<const SymbolImpl*>(this)->hashForSymbol();
186     return hash();
187 }
188
189 inline unsigned StringImpl::existingSymbolAwareHash() const
190 {
191     if (isSymbol())
192         return static_cast<const SymbolImpl*>(this)->hashForSymbol();
193     return existingHash();
194 }
195
196 inline SymbolRegistry* SymbolImpl::symbolRegistry() const
197 {
198     if (isRegistered())
199         return static_cast<const RegisteredSymbolImpl*>(this)->symbolRegistry();
200     return nullptr;
201 }
202
203 inline RegisteredSymbolImpl* SymbolImpl::asRegisteredSymbolImpl()
204 {
205     ASSERT(isRegistered());
206     return static_cast<RegisteredSymbolImpl*>(this);
207 }
208
209 #if !ASSERT_DISABLED
210 // SymbolImpls created from StaticStringImpl will ASSERT
211 // in the generic ValueCheck<T>::checkConsistency
212 // as they are not allocated by fastMalloc.
213 // We don't currently have any way to detect that case
214 // so we ignore the consistency check for all SymbolImpls*.
215 template<> struct
216 ValueCheck<SymbolImpl*> {
217     static void checkConsistency(const SymbolImpl*) { }
218 };
219
220 template<> struct
221 ValueCheck<const SymbolImpl*> {
222     static void checkConsistency(const SymbolImpl*) { }
223 };
224 #endif
225
226 } // namespace WTF
227
228 using WTF::SymbolImpl;
229 using WTF::PrivateSymbolImpl;
230 using WTF::RegisteredSymbolImpl;