Bug 1860492 - Change file name in test @ toolkit/components/antitracking/test/browser...
[gecko.git] / xpcom / ds / nsAtom.h
blobaa416e81ef49e583d7bdb419a17014f36e38fd00
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/. */
7 #ifndef nsAtom_h
8 #define nsAtom_h
10 #include <type_traits>
12 #include "mozilla/Atomics.h"
13 #include "mozilla/Char16.h"
14 #include "mozilla/MemoryReporting.h"
15 #include "nsISupports.h"
16 #include "nsString.h"
18 namespace mozilla {
19 struct AtomsSizes;
20 } // namespace mozilla
22 class nsStaticAtom;
23 class nsDynamicAtom;
25 // This class encompasses both static and dynamic atoms.
27 // - In places where static and dynamic atoms can be used, use RefPtr<nsAtom>.
28 // This is by far the most common case.
30 // - In places where only static atoms can appear, use nsStaticAtom* to avoid
31 // unnecessary refcounting. This is a moderately common case.
33 // - In places where only dynamic atoms can appear, it doesn't matter much
34 // whether you use RefPtr<nsAtom> or RefPtr<nsDynamicAtom>. This is an
35 // extremely rare case.
37 class nsAtom {
38 public:
39 void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
40 mozilla::AtomsSizes& aSizes) const;
42 bool Equals(char16ptr_t aString, uint32_t aLength) const {
43 return mLength == aLength &&
44 memcmp(GetUTF16String(), aString, mLength * sizeof(char16_t)) == 0;
47 bool Equals(const nsAString& aString) const {
48 return Equals(aString.BeginReading(), aString.Length());
51 bool IsStatic() const { return mIsStatic; }
52 bool IsDynamic() const { return !IsStatic(); }
54 inline const nsStaticAtom* AsStatic() const;
55 inline const nsDynamicAtom* AsDynamic() const;
56 inline nsDynamicAtom* AsDynamic();
58 char16ptr_t GetUTF16String() const;
60 uint32_t GetLength() const { return mLength; }
62 operator mozilla::Span<const char16_t>() const {
63 // Explicitly specify template argument here to avoid instantiating
64 // Span<char16_t> first and then implicitly converting to Span<const
65 // char16_t>
66 return mozilla::Span<const char16_t>{GetUTF16String(), GetLength()};
69 void ToString(nsAString& aString) const;
70 void ToUTF8String(nsACString& aString) const;
72 // A hashcode that is better distributed than the actual atom pointer, for
73 // use in situations that need a well-distributed hashcode. It's called hash()
74 // rather than Hash() so we can use mozilla::BloomFilter<N, nsAtom>, because
75 // BloomFilter requires elements to implement a function called hash().
77 uint32_t hash() const { return mHash; }
79 // This function returns true if ToLowercaseASCII would return the string
80 // unchanged.
81 bool IsAsciiLowercase() const { return mIsAsciiLowercase; }
83 // This function returns true if this is the empty atom. This is exactly
84 // equivalent to `this == nsGkAtoms::_empty`, but it's a bit less foot-gunny,
85 // since we also have `nsGkAtoms::empty`.
87 // Defined in nsGkAtoms.h
88 inline bool IsEmpty() const;
90 // We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting
91 // of this type is special.
92 inline MozExternalRefCountType AddRef();
93 inline MozExternalRefCountType Release();
95 using HasThreadSafeRefCnt = std::true_type;
97 protected:
98 constexpr nsAtom(uint32_t aLength, bool aIsStatic, uint32_t aHash,
99 bool aIsAsciiLowercase)
100 : mLength(aLength),
101 mIsStatic(aIsStatic),
102 mIsAsciiLowercase(aIsAsciiLowercase),
103 mHash(aHash) {}
105 ~nsAtom() = default;
107 const uint32_t mLength : 30;
108 const uint32_t mIsStatic : 1;
109 const uint32_t mIsAsciiLowercase : 1;
110 const uint32_t mHash;
113 // This class would be |final| if it wasn't for nsCSSAnonBoxPseudoStaticAtom
114 // and nsCSSPseudoElementStaticAtom, which are trivial subclasses used to
115 // ensure only certain static atoms are passed to certain functions.
116 class nsStaticAtom : public nsAtom {
117 public:
118 // These are deleted so it's impossible to RefPtr<nsStaticAtom>. Raw
119 // nsStaticAtom pointers should be used instead.
120 MozExternalRefCountType AddRef() = delete;
121 MozExternalRefCountType Release() = delete;
123 // The static atom's precomputed hash value is an argument here, but it
124 // must be the same as would be computed by mozilla::HashString(aStr),
125 // which is what we use when atomizing strings. We compute this hash in
126 // Atom.py and assert in nsAtomTable::RegisterStaticAtoms that the two
127 // hashes match.
128 constexpr nsStaticAtom(uint32_t aLength, uint32_t aHash,
129 uint32_t aStringOffset, bool aIsAsciiLowercase)
130 : nsAtom(aLength, /* aIsStatic = */ true, aHash, aIsAsciiLowercase),
131 mStringOffset(aStringOffset) {}
133 const char16_t* String() const {
134 return reinterpret_cast<const char16_t*>(uintptr_t(this) - mStringOffset);
137 already_AddRefed<nsAtom> ToAddRefed() {
138 return already_AddRefed<nsAtom>(static_cast<nsAtom*>(this));
141 private:
142 // This is an offset to the string chars, which must be at a lower address in
143 // memory.
144 uint32_t mStringOffset;
147 class nsDynamicAtom : public nsAtom {
148 public:
149 // We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting
150 // of this type is special.
151 MozExternalRefCountType AddRef() {
152 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");
153 nsrefcnt count = ++mRefCnt;
154 if (count == 1) {
155 gUnusedAtomCount--;
157 return count;
160 MozExternalRefCountType Release() {
161 #ifdef DEBUG
162 // We set a lower GC threshold for atoms in debug builds so that we exercise
163 // the GC machinery more often.
164 static const int32_t kAtomGCThreshold = 20;
165 #else
166 static const int32_t kAtomGCThreshold = 10000;
167 #endif
169 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
170 nsrefcnt count = --mRefCnt;
171 if (count == 0) {
172 if (++gUnusedAtomCount >= kAtomGCThreshold) {
173 GCAtomTable();
177 return count;
180 nsStringBuffer* StringBuffer() const { return mStringBuffer; }
182 const char16_t* String() const {
183 return reinterpret_cast<const char16_t*>(mStringBuffer->Data());
186 private:
187 friend class nsAtomTable;
188 friend class nsAtomSubTable;
189 friend int32_t NS_GetUnusedAtomCount();
191 static mozilla::Atomic<int32_t, mozilla::ReleaseAcquire> gUnusedAtomCount;
192 static void GCAtomTable();
194 // These shouldn't be used directly, even by friend classes. The
195 // Create()/Destroy() methods use them.
196 nsDynamicAtom(already_AddRefed<nsStringBuffer>, uint32_t aLength,
197 uint32_t aHash, bool aIsAsciiLowercase);
198 ~nsDynamicAtom() = default;
200 static nsDynamicAtom* Create(const nsAString& aString, uint32_t aHash);
201 static void Destroy(nsDynamicAtom* aAtom);
203 mozilla::ThreadSafeAutoRefCnt mRefCnt;
204 RefPtr<nsStringBuffer> mStringBuffer;
207 const nsStaticAtom* nsAtom::AsStatic() const {
208 MOZ_ASSERT(IsStatic());
209 return static_cast<const nsStaticAtom*>(this);
212 const nsDynamicAtom* nsAtom::AsDynamic() const {
213 MOZ_ASSERT(IsDynamic());
214 return static_cast<const nsDynamicAtom*>(this);
217 nsDynamicAtom* nsAtom::AsDynamic() {
218 MOZ_ASSERT(IsDynamic());
219 return static_cast<nsDynamicAtom*>(this);
222 MozExternalRefCountType nsAtom::AddRef() {
223 return IsStatic() ? 2 : AsDynamic()->AddRef();
226 MozExternalRefCountType nsAtom::Release() {
227 return IsStatic() ? 1 : AsDynamic()->Release();
230 // The four forms of NS_Atomize (for use with |RefPtr<nsAtom>|) return the
231 // atom for the string given. At any given time there will always be one atom
232 // representing a given string. Atoms are intended to make string comparison
233 // cheaper by simplifying it to pointer equality. A pointer to the atom that
234 // does not own a reference is not guaranteed to be valid.
236 // Find an atom that matches the given UTF-8 string. The string is assumed to
237 // be zero terminated. Never returns null.
238 already_AddRefed<nsAtom> NS_Atomize(const char* aUTF8String);
240 // Find an atom that matches the given UTF-8 string. Never returns null.
241 already_AddRefed<nsAtom> NS_Atomize(const nsACString& aUTF8String);
243 // Find an atom that matches the given UTF-16 string. The string is assumed to
244 // be zero terminated. Never returns null.
245 already_AddRefed<nsAtom> NS_Atomize(const char16_t* aUTF16String);
247 // Find an atom that matches the given UTF-16 string. Never returns null.
248 already_AddRefed<nsAtom> NS_Atomize(const nsAString& aUTF16String);
250 // Find an atom that matches the given UTF-16 string, with a known
251 // already-computed hash via mozilla::HashString. Never returns null.
252 already_AddRefed<nsAtom> NS_Atomize(const nsAString& aUTF16String,
253 uint32_t aKnownHash);
255 // An optimized version of the method above for the main thread.
256 already_AddRefed<nsAtom> NS_AtomizeMainThread(const nsAString& aUTF16String);
258 // Return a count of the total number of atoms currently alive in the system.
260 // Note that the result is imprecise and racy if other threads are currently
261 // operating on atoms. It's also slow, since it triggers a GC before counting.
262 // Currently this function is only used in tests, which should probably remain
263 // the case.
264 nsrefcnt NS_GetNumberOfAtoms();
266 // Return a pointer for a static atom for the string or null if there's no
267 // static atom for this string.
268 nsStaticAtom* NS_GetStaticAtom(const nsAString& aUTF16String);
270 class nsAtomString : public nsString {
271 public:
272 explicit nsAtomString(const nsAtom* aAtom) { aAtom->ToString(*this); }
275 class nsAtomCString : public nsCString {
276 public:
277 explicit nsAtomCString(const nsAtom* aAtom) { aAtom->ToUTF8String(*this); }
280 class nsAutoAtomCString : public nsAutoCString {
281 public:
282 explicit nsAutoAtomCString(const nsAtom* aAtom) {
283 aAtom->ToUTF8String(*this);
287 class nsDependentAtomString : public nsDependentString {
288 public:
289 explicit nsDependentAtomString(const nsAtom* aAtom)
290 : nsDependentString(aAtom->GetUTF16String(), aAtom->GetLength()) {}
293 // Checks if the ascii chars in a given atom are already lowercase.
294 // If they are, no-op. Otherwise, converts all the ascii uppercase
295 // chars to lowercase and atomizes, storing the result in the inout
296 // param.
297 void ToLowerCaseASCII(RefPtr<nsAtom>& aAtom);
299 #endif // nsAtom_h