Bug 1734063 [wpt PR 31107] - [GridNG] Fix rounding of distributed free space to flexi...
[gecko.git] / xpcom / ds / nsAtom.h
blob240e9ffcb0c27ce8a4012f75cfc87e664b65af3c
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;
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 // Used by nsStaticAtom.
99 constexpr nsAtom(uint32_t aLength, uint32_t aHash, bool aIsAsciiLowercase)
100 : mLength(aLength),
101 mIsStatic(true),
102 mIsAsciiLowercase(aIsAsciiLowercase),
103 mHash(aHash) {}
105 // Used by nsDynamicAtom.
106 nsAtom(const nsAString& aString, uint32_t aHash, bool aIsAsciiLowercase)
107 : mLength(aString.Length()),
108 mIsStatic(false),
109 mIsAsciiLowercase(aIsAsciiLowercase),
110 mHash(aHash) {}
112 ~nsAtom() = default;
114 const uint32_t mLength : 30;
115 const uint32_t mIsStatic : 1;
116 const uint32_t mIsAsciiLowercase : 1;
117 const uint32_t mHash;
120 // This class would be |final| if it wasn't for nsCSSAnonBoxPseudoStaticAtom
121 // and nsCSSPseudoElementStaticAtom, which are trivial subclasses used to
122 // ensure only certain static atoms are passed to certain functions.
123 class nsStaticAtom : public nsAtom {
124 public:
125 // These are deleted so it's impossible to RefPtr<nsStaticAtom>. Raw
126 // nsStaticAtom pointers should be used instead.
127 MozExternalRefCountType AddRef() = delete;
128 MozExternalRefCountType Release() = delete;
130 // The static atom's precomputed hash value is an argument here, but it
131 // must be the same as would be computed by mozilla::HashString(aStr),
132 // which is what we use when atomizing strings. We compute this hash in
133 // Atom.py and assert in nsAtomTable::RegisterStaticAtoms that the two
134 // hashes match.
135 constexpr nsStaticAtom(uint32_t aLength, uint32_t aHash,
136 uint32_t aStringOffset, bool aIsAsciiLowercase)
137 : nsAtom(aLength, aHash, aIsAsciiLowercase),
138 mStringOffset(aStringOffset) {}
140 const char16_t* String() const {
141 return reinterpret_cast<const char16_t*>(uintptr_t(this) - mStringOffset);
144 already_AddRefed<nsAtom> ToAddRefed() {
145 return already_AddRefed<nsAtom>(static_cast<nsAtom*>(this));
148 private:
149 // This is an offset to the string chars, which must be at a lower address in
150 // memory.
151 uint32_t mStringOffset;
154 class nsDynamicAtom : public nsAtom {
155 public:
156 // We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting
157 // of this type is special.
158 MozExternalRefCountType AddRef() {
159 MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt");
160 nsrefcnt count = ++mRefCnt;
161 if (count == 1) {
162 gUnusedAtomCount--;
164 return count;
167 MozExternalRefCountType Release() {
168 #ifdef DEBUG
169 // We set a lower GC threshold for atoms in debug builds so that we exercise
170 // the GC machinery more often.
171 static const int32_t kAtomGCThreshold = 20;
172 #else
173 static const int32_t kAtomGCThreshold = 10000;
174 #endif
176 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release");
177 nsrefcnt count = --mRefCnt;
178 if (count == 0) {
179 if (++gUnusedAtomCount >= kAtomGCThreshold) {
180 GCAtomTable();
184 return count;
187 const char16_t* String() const {
188 return reinterpret_cast<const char16_t*>(this + 1);
191 static nsDynamicAtom* FromChars(char16_t* chars) {
192 return reinterpret_cast<nsDynamicAtom*>(chars) - 1;
195 private:
196 friend class nsAtomTable;
197 friend class nsAtomSubTable;
198 friend int32_t NS_GetUnusedAtomCount();
200 static mozilla::Atomic<int32_t, mozilla::ReleaseAcquire> gUnusedAtomCount;
201 static void GCAtomTable();
203 // These shouldn't be used directly, even by friend classes. The
204 // Create()/Destroy() methods use them.
205 nsDynamicAtom(const nsAString& aString, uint32_t aHash,
206 bool aIsAsciiLowercase);
207 ~nsDynamicAtom() = default;
209 static nsDynamicAtom* Create(const nsAString& aString, uint32_t aHash);
210 static void Destroy(nsDynamicAtom* aAtom);
212 mozilla::ThreadSafeAutoRefCnt mRefCnt;
214 // The atom's chars are stored at the end of the struct.
217 const nsStaticAtom* nsAtom::AsStatic() const {
218 MOZ_ASSERT(IsStatic());
219 return static_cast<const nsStaticAtom*>(this);
222 const nsDynamicAtom* nsAtom::AsDynamic() const {
223 MOZ_ASSERT(IsDynamic());
224 return static_cast<const nsDynamicAtom*>(this);
227 nsDynamicAtom* nsAtom::AsDynamic() {
228 MOZ_ASSERT(IsDynamic());
229 return static_cast<nsDynamicAtom*>(this);
232 MozExternalRefCountType nsAtom::AddRef() {
233 return IsStatic() ? 2 : AsDynamic()->AddRef();
236 MozExternalRefCountType nsAtom::Release() {
237 return IsStatic() ? 1 : AsDynamic()->Release();
240 // The four forms of NS_Atomize (for use with |RefPtr<nsAtom>|) return the
241 // atom for the string given. At any given time there will always be one atom
242 // representing a given string. Atoms are intended to make string comparison
243 // cheaper by simplifying it to pointer equality. A pointer to the atom that
244 // does not own a reference is not guaranteed to be valid.
246 // Find an atom that matches the given UTF-8 string. The string is assumed to
247 // be zero terminated. Never returns null.
248 already_AddRefed<nsAtom> NS_Atomize(const char* aUTF8String);
250 // Find an atom that matches the given UTF-8 string. Never returns null.
251 already_AddRefed<nsAtom> NS_Atomize(const nsACString& aUTF8String);
253 // Find an atom that matches the given UTF-16 string. The string is assumed to
254 // be zero terminated. Never returns null.
255 already_AddRefed<nsAtom> NS_Atomize(const char16_t* aUTF16String);
257 // Find an atom that matches the given UTF-16 string. Never returns null.
258 already_AddRefed<nsAtom> NS_Atomize(const nsAString& aUTF16String);
260 // An optimized version of the method above for the main thread.
261 already_AddRefed<nsAtom> NS_AtomizeMainThread(const nsAString& aUTF16String);
263 // Return a count of the total number of atoms currently alive in the system.
265 // Note that the result is imprecise and racy if other threads are currently
266 // operating on atoms. It's also slow, since it triggers a GC before counting.
267 // Currently this function is only used in tests, which should probably remain
268 // the case.
269 nsrefcnt NS_GetNumberOfAtoms();
271 // Return a pointer for a static atom for the string or null if there's no
272 // static atom for this string.
273 nsStaticAtom* NS_GetStaticAtom(const nsAString& aUTF16String);
275 class nsAtomString : public nsString {
276 public:
277 explicit nsAtomString(const nsAtom* aAtom) { aAtom->ToString(*this); }
280 class nsAtomCString : public nsCString {
281 public:
282 explicit nsAtomCString(const nsAtom* aAtom) { aAtom->ToUTF8String(*this); }
285 class nsDependentAtomString : public nsDependentString {
286 public:
287 explicit nsDependentAtomString(const nsAtom* aAtom)
288 : nsDependentString(aAtom->GetUTF16String(), aAtom->GetLength()) {}
291 // Checks if the ascii chars in a given atom are already lowercase.
292 // If they are, no-op. Otherwise, converts all the ascii uppercase
293 // chars to lowercase and atomizes, storing the result in the inout
294 // param.
295 void ToLowerCaseASCII(RefPtr<nsAtom>& aAtom);
297 #endif // nsAtom_h