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 "nsStringBuffer.h"
13 
14 namespace mozilla {
15 struct AtomsSizes;
16 }
17 
18 class nsAtom {
19  public:
20   void AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf,
21                               mozilla::AtomsSizes& aSizes) const;
22 
23   enum class AtomKind : uint8_t {
24     DynamicAtom = 0,
25     StaticAtom = 1,
26     HTML5Atom = 2,
27   };
28 
Equals(char16ptr_t aString,uint32_t aLength)29   bool Equals(char16ptr_t aString, uint32_t aLength) const {
30     return mLength == aLength &&
31            memcmp(mString, aString, mLength * sizeof(char16_t)) == 0;
32   }
33 
Equals(const nsAString & aString)34   bool Equals(const nsAString& aString) const {
35     return Equals(aString.BeginReading(), aString.Length());
36   }
37 
Kind()38   AtomKind Kind() const { return static_cast<AtomKind>(mKind); }
39 
IsDynamic()40   bool IsDynamic() const { return Kind() == AtomKind::DynamicAtom; }
IsHTML5()41   bool IsHTML5() const { return Kind() == AtomKind::HTML5Atom; }
IsStatic()42   bool IsStatic() const { return Kind() == AtomKind::StaticAtom; }
43 
GetUTF16String()44   char16ptr_t GetUTF16String() const { return mString; }
45 
GetLength()46   uint32_t GetLength() const { return mLength; }
47 
48   void ToString(nsAString& aString) const;
49   void ToUTF8String(nsACString& aString) const;
50 
51   // This is not valid for static atoms. The caller must *not* mutate the
52   // string buffer, otherwise all hell will break loose.
GetStringBuffer()53   nsStringBuffer* GetStringBuffer() const {
54     // See the comment on |mString|'s declaration.
55     MOZ_ASSERT(IsDynamic() || IsHTML5());
56     return nsStringBuffer::FromData(const_cast<char16_t*>(mString));
57   }
58 
59   // A hashcode that is better distributed than the actual atom pointer, for
60   // use in situations that need a well-distributed hashcode. It's called hash()
61   // rather than Hash() so we can use mozilla::BloomFilter<N, nsAtom>, because
62   // BloomFilter requires elements to implement a function called hash().
63   //
hash()64   uint32_t hash() const {
65     MOZ_ASSERT(!IsHTML5());
66     return mHash;
67   }
68 
69   // We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting
70   // of this type is special.
71   MozExternalRefCountType AddRef();
72   MozExternalRefCountType Release();
73 
74   typedef mozilla::TrueType HasThreadSafeRefCnt;
75 
76  private:
77   friend class nsAtomTable;
78   friend class nsAtomSubTable;
79   friend class nsHtml5AtomEntry;
80 
81  protected:
82   // Used by nsDynamicAtom and directly (by nsHtml5AtomEntry) for HTML5 atoms.
83   nsAtom(AtomKind aKind, const nsAString& aString, uint32_t aHash);
84 
85   // Used by nsStaticAtom.
86   nsAtom(const char16_t* aString, uint32_t aLength, uint32_t aHash);
87 
88   ~nsAtom();
89 
90   const uint32_t mLength : 30;
91   const uint32_t mKind : 2;  // nsAtom::AtomKind
92   const uint32_t mHash;
93   // WARNING! For static atoms, this is a pointer to a static char buffer. For
94   // non-static atoms it points to the chars in an nsStringBuffer. This means
95   // that nsStringBuffer::FromData(mString) calls are only valid for non-static
96   // atoms.
97   const char16_t* const mString;
98 };
99 
100 // A trivial subclass of nsAtom that can be used for known static atoms. The
101 // main advantage of this class is that it doesn't require refcounting, so you
102 // can use |nsStaticAtom*| in contrast with |RefPtr<nsAtom>|.
103 //
104 // This class would be |final| if it wasn't for nsICSSAnonBoxPseudo and
105 // nsICSSPseudoElement, which are trivial subclasses used to ensure only
106 // certain atoms are passed to certain functions.
107 class nsStaticAtom : public nsAtom {
108  public:
109   // These are deleted so it's impossible to RefPtr<nsStaticAtom>. Raw
110   // nsStaticAtom pointers should be used instead.
111   MozExternalRefCountType AddRef() = delete;
112   MozExternalRefCountType Release() = delete;
113 
ToAddRefed()114   already_AddRefed<nsAtom> ToAddRefed() {
115     return already_AddRefed<nsAtom>(static_cast<nsAtom*>(this));
116   }
117 
118  private:
119   friend class nsAtomTable;
120 
121   // Construction is done entirely by |friend|s.
nsStaticAtom(const char16_t * aString,uint32_t aLength,uint32_t aHash)122   nsStaticAtom(const char16_t* aString, uint32_t aLength, uint32_t aHash)
123       : nsAtom(aString, aLength, aHash) {}
124 };
125 
126 // The four forms of NS_Atomize (for use with |RefPtr<nsAtom>|) return the
127 // atom for the string given. At any given time there will always be one atom
128 // representing a given string. Atoms are intended to make string comparison
129 // cheaper by simplifying it to pointer equality. A pointer to the atom that
130 // does not own a reference is not guaranteed to be valid.
131 
132 // Find an atom that matches the given UTF-8 string. The string is assumed to
133 // be zero terminated. Never returns null.
134 already_AddRefed<nsAtom> NS_Atomize(const char* aUTF8String);
135 
136 // Find an atom that matches the given UTF-8 string. Never returns null.
137 already_AddRefed<nsAtom> NS_Atomize(const nsACString& aUTF8String);
138 
139 // Find an atom that matches the given UTF-16 string. The string is assumed to
140 // be zero terminated. Never returns null.
141 already_AddRefed<nsAtom> NS_Atomize(const char16_t* aUTF16String);
142 
143 // Find an atom that matches the given UTF-16 string. Never returns null.
144 already_AddRefed<nsAtom> NS_Atomize(const nsAString& aUTF16String);
145 
146 // An optimized version of the method above for the main thread.
147 already_AddRefed<nsAtom> NS_AtomizeMainThread(const nsAString& aUTF16String);
148 
149 // Return a count of the total number of atoms currently alive in the system.
150 //
151 // Note that the result is imprecise and racy if other threads are currently
152 // operating on atoms. It's also slow, since it triggers a GC before counting.
153 // Currently this function is only used in tests, which should probably remain
154 // the case.
155 nsrefcnt NS_GetNumberOfAtoms();
156 
157 // Return a pointer for a static atom for the string or null if there's no
158 // static atom for this string.
159 nsStaticAtom* NS_GetStaticAtom(const nsAString& aUTF16String);
160 
161 // Record that all static atoms have been inserted.
162 void NS_SetStaticAtomsDone();
163 
164 class nsAtomString : public nsString {
165  public:
nsAtomString(const nsAtom * aAtom)166   explicit nsAtomString(const nsAtom* aAtom) { aAtom->ToString(*this); }
167 };
168 
169 class nsAtomCString : public nsCString {
170  public:
nsAtomCString(nsAtom * aAtom)171   explicit nsAtomCString(nsAtom* aAtom) { aAtom->ToUTF8String(*this); }
172 };
173 
174 class nsDependentAtomString : public nsDependentString {
175  public:
nsDependentAtomString(const nsAtom * aAtom)176   explicit nsDependentAtomString(const nsAtom* aAtom)
177       : nsDependentString(aAtom->GetUTF16String(), aAtom->GetLength()) {}
178 };
179 
180 #endif  // nsAtom_h
181