8c5014569d941d841d72313ed2c13c6e2dfd3370
[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_STRING_API static Ref<SymbolImpl> createNullSymbol();
54     WTF_EXPORT_STRING_API 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     // The pointer to the owner string should be immediately following after the StringImpl layout,
120     // since we would like to align the layout of SymbolImpl to the one of BufferSubstring StringImpl.
121     StringImpl* m_owner;
122     unsigned m_hashForSymbol;
123     Flags m_flags { s_flagDefault };
124 };
125 static_assert(sizeof(SymbolImpl) == sizeof(SymbolImpl::StaticSymbolImpl), "");
126
127 class PrivateSymbolImpl : public SymbolImpl {
128 public:
129     WTF_EXPORT_STRING_API static Ref<PrivateSymbolImpl> createNullSymbol();
130     WTF_EXPORT_STRING_API static Ref<PrivateSymbolImpl> create(StringImpl& rep);
131
132 private:
133     PrivateSymbolImpl(const LChar* characters, unsigned length, Ref<StringImpl>&& base)
134         : SymbolImpl(characters, length, WTFMove(base), s_flagIsPrivate)
135     {
136     }
137
138     PrivateSymbolImpl(const UChar* characters, unsigned length, Ref<StringImpl>&& base)
139         : SymbolImpl(characters, length, WTFMove(base), s_flagIsPrivate)
140     {
141     }
142
143     PrivateSymbolImpl()
144         : SymbolImpl(s_flagIsPrivate)
145     {
146     }
147 };
148
149 class RegisteredSymbolImpl : public SymbolImpl {
150 private:
151     friend class StringImpl;
152     friend class SymbolImpl;
153     friend class SymbolRegistry;
154
155     SymbolRegistry* symbolRegistry() const { return m_symbolRegistry; }
156     void clearSymbolRegistry() { m_symbolRegistry = nullptr; }
157
158     static Ref<RegisteredSymbolImpl> create(StringImpl& rep, SymbolRegistry&);
159
160     RegisteredSymbolImpl(const LChar* characters, unsigned length, Ref<StringImpl>&& base, SymbolRegistry& registry)
161         : SymbolImpl(characters, length, WTFMove(base), s_flagIsRegistered)
162         , m_symbolRegistry(&registry)
163     {
164     }
165
166     RegisteredSymbolImpl(const UChar* characters, unsigned length, Ref<StringImpl>&& base, SymbolRegistry& registry)
167         : SymbolImpl(characters, length, WTFMove(base), s_flagIsRegistered)
168         , m_symbolRegistry(&registry)
169     {
170     }
171
172     SymbolRegistry* m_symbolRegistry;
173 };
174
175 inline unsigned StringImpl::symbolAwareHash() const
176 {
177     if (isSymbol())
178         return static_cast<const SymbolImpl*>(this)->hashForSymbol();
179     return hash();
180 }
181
182 inline unsigned StringImpl::existingSymbolAwareHash() const
183 {
184     if (isSymbol())
185         return static_cast<const SymbolImpl*>(this)->hashForSymbol();
186     return existingHash();
187 }
188
189 inline SymbolRegistry* SymbolImpl::symbolRegistry() const
190 {
191     if (isRegistered())
192         return static_cast<const RegisteredSymbolImpl*>(this)->symbolRegistry();
193     return nullptr;
194 }
195
196 inline RegisteredSymbolImpl* SymbolImpl::asRegisteredSymbolImpl()
197 {
198     ASSERT(isRegistered());
199     return static_cast<RegisteredSymbolImpl*>(this);
200 }
201
202 #if !ASSERT_DISABLED
203 // SymbolImpls created from StaticStringImpl will ASSERT
204 // in the generic ValueCheck<T>::checkConsistency
205 // as they are not allocated by fastMalloc.
206 // We don't currently have any way to detect that case
207 // so we ignore the consistency check for all SymbolImpls*.
208 template<> struct
209 ValueCheck<SymbolImpl*> {
210     static void checkConsistency(const SymbolImpl*) { }
211 };
212
213 template<> struct
214 ValueCheck<const SymbolImpl*> {
215     static void checkConsistency(const SymbolImpl*) { }
216 };
217 #endif
218
219 } // namespace WTF
220
221 using WTF::SymbolImpl;
222 using WTF::PrivateSymbolImpl;
223 using WTF::RegisteredSymbolImpl;