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