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 nsBaseHashtable_h__
8 #define nsBaseHashtable_h__
9 
10 #include "mozilla/MemoryReporting.h"
11 #include "mozilla/Move.h"
12 #include "nsTHashtable.h"
13 #include "nsDebug.h"
14 
15 template<class KeyClass, class DataType, class UserDataType>
16 class nsBaseHashtable; // forward declaration
17 
18 /**
19  * the private nsTHashtable::EntryType class used by nsBaseHashtable
20  * @see nsTHashtable for the specification of this class
21  * @see nsBaseHashtable for template parameters
22  */
23 template<class KeyClass, class DataType>
24 class nsBaseHashtableET : public KeyClass
25 {
26 public:
27   DataType mData;
28   friend class nsTHashtable<nsBaseHashtableET<KeyClass, DataType>>;
29 
30 private:
31   typedef typename KeyClass::KeyType KeyType;
32   typedef typename KeyClass::KeyTypePointer KeyTypePointer;
33 
34   explicit nsBaseHashtableET(KeyTypePointer aKey);
35   nsBaseHashtableET(nsBaseHashtableET<KeyClass, DataType>&& aToMove);
36   ~nsBaseHashtableET();
37 };
38 
39 /**
40  * templated hashtable for simple data types
41  * This class manages simple data types that do not need construction or
42  * destruction.
43  *
44  * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h
45  *   for a complete specification.
46  * @param DataType the datatype stored in the hashtable,
47  *   for example, uint32_t or nsCOMPtr.  If UserDataType is not the same,
48  *   DataType must implicitly cast to UserDataType
49  * @param UserDataType the user sees, for example uint32_t or nsISupports*
50  */
51 template<class KeyClass, class DataType, class UserDataType>
52 class nsBaseHashtable
53   : protected nsTHashtable<nsBaseHashtableET<KeyClass, DataType>>
54 {
55   typedef mozilla::fallible_t fallible_t;
56 
57 public:
58   typedef typename KeyClass::KeyType KeyType;
59   typedef nsBaseHashtableET<KeyClass, DataType> EntryType;
60 
61   using nsTHashtable<EntryType>::Contains;
62 
nsBaseHashtable()63   nsBaseHashtable() {}
nsBaseHashtable(uint32_t aInitLength)64   explicit nsBaseHashtable(uint32_t aInitLength)
65     : nsTHashtable<EntryType>(aInitLength)
66   {
67   }
68 
69   /**
70    * Return the number of entries in the table.
71    * @return    number of entries
72    */
Count()73   uint32_t Count() const { return nsTHashtable<EntryType>::Count(); }
74 
75   /**
76    * retrieve the value for a key.
77    * @param aKey the key to retreive
78    * @param aData data associated with this key will be placed at this
79    *   pointer.  If you only need to check if the key exists, aData
80    *   may be null.
81    * @return true if the key exists. If key does not exist, aData is not
82    *   modified.
83    */
Get(KeyType aKey,UserDataType * aData)84   bool Get(KeyType aKey, UserDataType* aData) const
85   {
86     EntryType* ent = this->GetEntry(aKey);
87     if (!ent) {
88       return false;
89     }
90 
91     if (aData) {
92       *aData = ent->mData;
93     }
94 
95     return true;
96   }
97 
98   /**
99    * Get the value, returning a zero-initialized POD or a default-initialized
100    * object if the entry is not present in the table.
101    *
102    * @param aKey the key to retrieve
103    * @return The found value, or UserDataType{} if no entry was found with the
104    *         given key.
105    * @note If zero/default-initialized values are stored in the table, it is
106    *       not possible to distinguish between such a value and a missing entry.
107    */
Get(KeyType aKey)108   UserDataType Get(KeyType aKey) const
109   {
110     EntryType* ent = this->GetEntry(aKey);
111     if (!ent) {
112       return UserDataType{};
113     }
114 
115     return ent->mData;
116   }
117 
118   /**
119    * Add key to the table if not already present, and return a reference to its
120    * value.  If key is not already in the table then the value is default
121    * constructed.
122    */
GetOrInsert(const KeyType & aKey)123   DataType& GetOrInsert(const KeyType& aKey)
124   {
125     EntryType* ent = this->GetEntry(aKey);
126     if (ent) {
127       return ent->mData;
128     }
129 
130     ent = this->PutEntry(aKey);
131     return ent->mData;
132   }
133 
134   /**
135    * put a new value for the associated key
136    * @param aKey the key to put
137    * @param aData the new data
138    * @return always true, unless memory allocation failed
139    */
Put(KeyType aKey,const UserDataType & aData)140   void Put(KeyType aKey, const UserDataType& aData)
141   {
142     if (!Put(aKey, aData, mozilla::fallible)) {
143       NS_ABORT_OOM(this->mTable.EntrySize() * this->mTable.EntryCount());
144     }
145   }
146 
Put(KeyType aKey,const UserDataType & aData,const fallible_t &)147   MOZ_MUST_USE bool Put(KeyType aKey, const UserDataType& aData,
148                         const fallible_t&)
149   {
150     EntryType* ent = this->PutEntry(aKey, mozilla::fallible);
151     if (!ent) {
152       return false;
153     }
154 
155     ent->mData = aData;
156 
157     return true;
158   }
159 
160   /**
161    * remove the data for the associated key
162    * @param aKey the key to remove from the hashtable
163    */
Remove(KeyType aKey)164   void Remove(KeyType aKey) { this->RemoveEntry(aKey); }
165 
166   // This is an iterator that also allows entry removal. Example usage:
167   //
168   //   for (auto iter = table.Iter(); !iter.Done(); iter.Next()) {
169   //     const KeyType key = iter.Key();
170   //     const UserDataType data = iter.UserData();
171   //     // or
172   //     const DataType& data = iter.Data();
173   //     // ... do stuff with |key| and/or |data| ...
174   //     // ... possibly call iter.Remove() once ...
175   //   }
176   //
177   class Iterator : public PLDHashTable::Iterator
178   {
179   public:
180     typedef PLDHashTable::Iterator Base;
181 
Iterator(nsBaseHashtable * aTable)182     explicit Iterator(nsBaseHashtable* aTable) : Base(&aTable->mTable) {}
Iterator(Iterator && aOther)183     Iterator(Iterator&& aOther) : Base(aOther.mTable) {}
~Iterator()184     ~Iterator() {}
185 
Key()186     KeyType Key() const { return static_cast<EntryType*>(Get())->GetKey(); }
UserData()187     UserDataType UserData() const
188     {
189       return static_cast<EntryType*>(Get())->mData;
190     }
Data()191     DataType& Data() const { return static_cast<EntryType*>(Get())->mData; }
192 
193   private:
194     Iterator() = delete;
195     Iterator(const Iterator&) = delete;
196     Iterator& operator=(const Iterator&) = delete;
197     Iterator& operator=(const Iterator&&) = delete;
198   };
199 
Iter()200   Iterator Iter() { return Iterator(this); }
201 
ConstIter()202   Iterator ConstIter() const
203   {
204     return Iterator(const_cast<nsBaseHashtable*>(this));
205   }
206 
207   /**
208    * reset the hashtable, removing all entries
209    */
Clear()210   void Clear() { nsTHashtable<EntryType>::Clear(); }
211 
212   /**
213    * Measure the size of the table's entry storage. The size of things pointed
214    * to by entries must be measured separately; hence the "Shallow" prefix.
215    *
216    * @param   aMallocSizeOf the function used to measure heap-allocated blocks
217    * @return  the summed size of the table's storage
218    */
ShallowSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)219   size_t ShallowSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
220   {
221     return this->mTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
222   }
223 
224   /**
225    * Like ShallowSizeOfExcludingThis, but includes sizeof(*this).
226    */
ShallowSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)227   size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
228   {
229     return aMallocSizeOf(this) + ShallowSizeOfExcludingThis(aMallocSizeOf);
230   }
231 
232   /**
233    * Swap the elements in this hashtable with the elements in aOther.
234    */
SwapElements(nsBaseHashtable & aOther)235   void SwapElements(nsBaseHashtable& aOther)
236   {
237     nsTHashtable<EntryType>::SwapElements(aOther);
238   }
239 
240 
241 #ifdef DEBUG
242   using nsTHashtable<EntryType>::MarkImmutable;
243 #endif
244 };
245 
246 //
247 // nsBaseHashtableET definitions
248 //
249 
250 template<class KeyClass, class DataType>
nsBaseHashtableET(KeyTypePointer aKey)251 nsBaseHashtableET<KeyClass, DataType>::nsBaseHashtableET(KeyTypePointer aKey)
252   : KeyClass(aKey)
253   , mData()
254 {
255 }
256 
257 template<class KeyClass, class DataType>
nsBaseHashtableET(nsBaseHashtableET<KeyClass,DataType> && aToMove)258 nsBaseHashtableET<KeyClass, DataType>::nsBaseHashtableET(
259       nsBaseHashtableET<KeyClass, DataType>&& aToMove)
260   : KeyClass(mozilla::Move(aToMove))
261   , mData(mozilla::Move(aToMove.mData))
262 {
263 }
264 
265 template<class KeyClass, class DataType>
~nsBaseHashtableET()266 nsBaseHashtableET<KeyClass, DataType>::~nsBaseHashtableET()
267 {
268 }
269 
270 #endif // nsBaseHashtable_h__
271