/src/mozilla-central/xpcom/ds/nsAtom.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef nsAtom_h |
8 | | #define nsAtom_h |
9 | | |
10 | | #include "nsISupportsImpl.h" |
11 | | #include "nsString.h" |
12 | | #include "mozilla/UniquePtr.h" |
13 | | |
14 | | namespace mozilla { |
15 | | struct AtomsSizes; |
16 | | } |
17 | | |
18 | | class nsStaticAtom; |
19 | | class nsDynamicAtom; |
20 | | |
21 | | // This class encompasses both static and dynamic atoms. |
22 | | // |
23 | | // - In places where static and dynamic atoms can be used, use RefPtr<nsAtom>. |
24 | | // This is by far the most common case. (The exception to this is the HTML5 |
25 | | // parser, which does its own weird thing, and uses non-refcounted dynamic |
26 | | // atoms.) |
27 | | // |
28 | | // - In places where only static atoms can appear, use nsStaticAtom* to avoid |
29 | | // unnecessary refcounting. This is a moderately common case. |
30 | | // |
31 | | // - In places where only dynamic atoms can appear, it doesn't matter much |
32 | | // whether you use RefPtr<nsAtom> or RefPtr<nsDynamicAtom>. This is an |
33 | | // extremely rare case. |
34 | | // |
35 | | class nsAtom |
36 | | { |
37 | | public: |
38 | | void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, |
39 | | mozilla::AtomsSizes& aSizes) const; |
40 | | |
41 | | // Dynamic HTML5 atoms are just like vanilla dynamic atoms, but we disallow |
42 | | // various operations, the most important of which is AddRef/Release. |
43 | | // XXX: we'd like to get rid of dynamic HTML5 atoms. See bug 1392185 for |
44 | | // details. |
45 | | enum class AtomKind : uint8_t { |
46 | | Static = 0, |
47 | | DynamicNormal = 1, |
48 | | DynamicHTML5 = 2, |
49 | | }; |
50 | | |
51 | | bool Equals(char16ptr_t aString, uint32_t aLength) const |
52 | 411 | { |
53 | 411 | return mLength == aLength && |
54 | 411 | memcmp(GetUTF16String(), aString, mLength * sizeof(char16_t)) == 0; |
55 | 411 | } |
56 | | |
57 | | bool Equals(const nsAString& aString) const |
58 | | { |
59 | | return Equals(aString.BeginReading(), aString.Length()); |
60 | | } |
61 | | |
62 | 229k | AtomKind Kind() const { return static_cast<AtomKind>(mKind); } |
63 | | |
64 | 229k | bool IsStatic() const { return Kind() == AtomKind::Static; } |
65 | | bool IsDynamic() const |
66 | 0 | { |
67 | 0 | return Kind() == AtomKind::DynamicNormal || |
68 | 0 | Kind() == AtomKind::DynamicHTML5; |
69 | 0 | } |
70 | | bool IsDynamicHTML5() const |
71 | | { |
72 | | return Kind() == AtomKind::DynamicHTML5; |
73 | | } |
74 | | |
75 | | const nsStaticAtom* AsStatic() const; |
76 | | const nsDynamicAtom* AsDynamic() const; |
77 | | nsDynamicAtom* AsDynamic(); |
78 | | |
79 | | char16ptr_t GetUTF16String() const; |
80 | | |
81 | 211k | uint32_t GetLength() const { return mLength; } |
82 | | |
83 | | operator mozilla::Span<const char16_t>() const |
84 | | { |
85 | | return mozilla::MakeSpan(static_cast<const char16_t*>(GetUTF16String()), GetLength()); |
86 | | } |
87 | | |
88 | | void ToString(nsAString& aString) const; |
89 | | void ToUTF8String(nsACString& aString) const; |
90 | | |
91 | | // A hashcode that is better distributed than the actual atom pointer, for |
92 | | // use in situations that need a well-distributed hashcode. It's called hash() |
93 | | // rather than Hash() so we can use mozilla::BloomFilter<N, nsAtom>, because |
94 | | // BloomFilter requires elements to implement a function called hash(). |
95 | | // |
96 | | uint32_t hash() const |
97 | 6.98k | { |
98 | 6.98k | MOZ_ASSERT(!IsDynamicHTML5()); |
99 | 6.98k | return mHash; |
100 | 6.98k | } |
101 | | |
102 | | // We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting |
103 | | // of this type is special. |
104 | | MozExternalRefCountType AddRef(); |
105 | | MozExternalRefCountType Release(); |
106 | | |
107 | | typedef mozilla::TrueType HasThreadSafeRefCnt; |
108 | | |
109 | | protected: |
110 | | // Used by nsStaticAtom. |
111 | | constexpr nsAtom(const char16_t* aStr, uint32_t aLength, uint32_t aHash) |
112 | | : mLength(aLength) |
113 | | , mKind(static_cast<uint32_t>(nsAtom::AtomKind::Static)) |
114 | | , mHash(aHash) |
115 | | {} |
116 | | |
117 | | // Used by nsDynamicAtom. |
118 | | nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash) |
119 | | : mLength(aString.Length()) |
120 | | , mKind(static_cast<uint32_t>(aKind)) |
121 | | , mHash(aHash) |
122 | 37 | { |
123 | 37 | MOZ_ASSERT(aKind == AtomKind::DynamicNormal || |
124 | 37 | aKind == AtomKind::DynamicHTML5); |
125 | 37 | } |
126 | | |
127 | | ~nsAtom() = default; |
128 | | |
129 | | const uint32_t mLength:30; |
130 | | const uint32_t mKind:2; // nsAtom::AtomKind |
131 | | const uint32_t mHash; |
132 | | }; |
133 | | |
134 | | // This class would be |final| if it wasn't for nsICSSAnonBoxPseudo and |
135 | | // nsICSSPseudoElement, which are trivial subclasses used to ensure only |
136 | | // certain static atoms are passed to certain functions. |
137 | | class nsStaticAtom : public nsAtom |
138 | | { |
139 | | public: |
140 | | // These are deleted so it's impossible to RefPtr<nsStaticAtom>. Raw |
141 | | // nsStaticAtom pointers should be used instead. |
142 | | MozExternalRefCountType AddRef() = delete; |
143 | | MozExternalRefCountType Release() = delete; |
144 | | |
145 | | // The static atom's precomputed hash value is an argument here, but it |
146 | | // must be the same as would be computed by mozilla::HashString(aStr), |
147 | | // which is what we use when atomizing strings. We compute this hash in |
148 | | // Atom.py and assert in nsAtomTable::RegisterStaticAtoms that the two |
149 | | // hashes match. |
150 | | constexpr nsStaticAtom(const char16_t* aStr, uint32_t aLength, |
151 | | uint32_t aHash, uint32_t aStringOffset) |
152 | | : nsAtom(aStr, aLength, aHash) |
153 | | , mStringOffset(aStringOffset) |
154 | | {} |
155 | | |
156 | | const char16_t* String() const |
157 | 205k | { |
158 | 205k | return reinterpret_cast<const char16_t*>(uintptr_t(this) - mStringOffset); |
159 | 205k | } |
160 | | |
161 | | already_AddRefed<nsAtom> ToAddRefed() { |
162 | | return already_AddRefed<nsAtom>(static_cast<nsAtom*>(this)); |
163 | | } |
164 | | |
165 | | private: |
166 | | // This is an offset to the string chars, which must be at a lower address in |
167 | | // memory. |
168 | | uint32_t mStringOffset; |
169 | | }; |
170 | | |
171 | | class nsDynamicAtom : public nsAtom |
172 | | { |
173 | | public: |
174 | | // We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting |
175 | | // of this type is special. |
176 | | MozExternalRefCountType AddRef(); |
177 | | MozExternalRefCountType Release(); |
178 | | |
179 | | const char16_t* String() const |
180 | 5.81k | { |
181 | 5.81k | return reinterpret_cast<const char16_t*>(this + 1); |
182 | 5.81k | } |
183 | | |
184 | | static nsDynamicAtom* FromChars(char16_t* chars) |
185 | | { |
186 | | return reinterpret_cast<nsDynamicAtom*>(chars) - 1; |
187 | | } |
188 | | |
189 | | private: |
190 | | friend class nsAtomTable; |
191 | | friend class nsAtomSubTable; |
192 | | // XXX: we'd like to remove nsHtml5AtomEntry. See bug 1392185. |
193 | | friend class nsHtml5AtomEntry; |
194 | | |
195 | | // These shouldn't be used directly, even by friend classes. The |
196 | | // Create()/Destroy() methods use them. |
197 | | static nsDynamicAtom* CreateInner(const nsAString& aString, uint32_t aHash); |
198 | | nsDynamicAtom(const nsAString& aString, uint32_t aHash); |
199 | 0 | ~nsDynamicAtom() {} |
200 | | |
201 | | // Creation/destruction is done by friend classes. The first Create() is for |
202 | | // dynamic normal atoms, the second is for dynamic HTML5 atoms. |
203 | | static nsDynamicAtom* Create(const nsAString& aString, uint32_t aHash); |
204 | | static nsDynamicAtom* Create(const nsAString& aString); |
205 | | static void Destroy(nsDynamicAtom* aAtom); |
206 | | |
207 | | mozilla::ThreadSafeAutoRefCnt mRefCnt; |
208 | | |
209 | | // The atom's chars are stored at the end of the struct. |
210 | | }; |
211 | | |
212 | | // The four forms of NS_Atomize (for use with |RefPtr<nsAtom>|) return the |
213 | | // atom for the string given. At any given time there will always be one atom |
214 | | // representing a given string. Atoms are intended to make string comparison |
215 | | // cheaper by simplifying it to pointer equality. A pointer to the atom that |
216 | | // does not own a reference is not guaranteed to be valid. |
217 | | |
218 | | // Find an atom that matches the given UTF-8 string. The string is assumed to |
219 | | // be zero terminated. Never returns null. |
220 | | already_AddRefed<nsAtom> NS_Atomize(const char* aUTF8String); |
221 | | |
222 | | // Find an atom that matches the given UTF-8 string. Never returns null. |
223 | | already_AddRefed<nsAtom> NS_Atomize(const nsACString& aUTF8String); |
224 | | |
225 | | // Find an atom that matches the given UTF-16 string. The string is assumed to |
226 | | // be zero terminated. Never returns null. |
227 | | already_AddRefed<nsAtom> NS_Atomize(const char16_t* aUTF16String); |
228 | | |
229 | | // Find an atom that matches the given UTF-16 string. Never returns null. |
230 | | already_AddRefed<nsAtom> NS_Atomize(const nsAString& aUTF16String); |
231 | | |
232 | | // An optimized version of the method above for the main thread. |
233 | | already_AddRefed<nsAtom> NS_AtomizeMainThread(const nsAString& aUTF16String); |
234 | | |
235 | | // Return a count of the total number of atoms currently alive in the system. |
236 | | // |
237 | | // Note that the result is imprecise and racy if other threads are currently |
238 | | // operating on atoms. It's also slow, since it triggers a GC before counting. |
239 | | // Currently this function is only used in tests, which should probably remain |
240 | | // the case. |
241 | | nsrefcnt NS_GetNumberOfAtoms(); |
242 | | |
243 | | // Return a pointer for a static atom for the string or null if there's no |
244 | | // static atom for this string. |
245 | | nsStaticAtom* NS_GetStaticAtom(const nsAString& aUTF16String); |
246 | | |
247 | | class nsAtomString : public nsString |
248 | | { |
249 | | public: |
250 | | explicit nsAtomString(const nsAtom* aAtom) { aAtom->ToString(*this); } |
251 | | }; |
252 | | |
253 | | class nsAtomCString : public nsCString |
254 | | { |
255 | | public: |
256 | | explicit nsAtomCString(nsAtom* aAtom) { aAtom->ToUTF8String(*this); } |
257 | | }; |
258 | | |
259 | | class nsDependentAtomString : public nsDependentString |
260 | | { |
261 | | public: |
262 | | explicit nsDependentAtomString(const nsAtom* aAtom) |
263 | | : nsDependentString(aAtom->GetUTF16String(), aAtom->GetLength()) |
264 | 204k | {} |
265 | | }; |
266 | | |
267 | | // Checks if the ascii chars in a given atom are already lowercase. |
268 | | // If they are, no-op. Otherwise, converts all the ascii uppercase |
269 | | // chars to lowercase and atomizes, storing the result in the inout |
270 | | // param. |
271 | | void ToLowerCaseASCII(RefPtr<nsAtom>& aAtom); |
272 | | |
273 | | #endif // nsAtom_h |