|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef nsBaseHashtable_h__ |
|
7 #define nsBaseHashtable_h__ |
|
8 |
|
9 #include "mozilla/MemoryReporting.h" |
|
10 #include "mozilla/Move.h" |
|
11 #include "nsTHashtable.h" |
|
12 #include "prlock.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 nsBaseHashtableET(KeyTypePointer aKey); |
|
35 nsBaseHashtableET(nsBaseHashtableET<KeyClass,DataType>&& toMove); |
|
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 |
|
63 nsBaseHashtable() |
|
64 { |
|
65 } |
|
66 explicit nsBaseHashtable(uint32_t aInitSize) |
|
67 : nsTHashtable<EntryType>(aInitSize) |
|
68 { |
|
69 } |
|
70 |
|
71 /** |
|
72 * Return the number of entries in the table. |
|
73 * @return number of entries |
|
74 */ |
|
75 uint32_t Count() const |
|
76 { return nsTHashtable<EntryType>::Count(); } |
|
77 |
|
78 /** |
|
79 * retrieve the value for a key. |
|
80 * @param aKey the key to retreive |
|
81 * @param pData data associated with this key will be placed at this |
|
82 * pointer. If you only need to check if the key exists, pData |
|
83 * may be null. |
|
84 * @return true if the key exists. If key does not exist, pData is not |
|
85 * modified. |
|
86 */ |
|
87 bool Get(KeyType aKey, UserDataType* pData) const |
|
88 { |
|
89 EntryType* ent = this->GetEntry(aKey); |
|
90 |
|
91 if (!ent) |
|
92 return false; |
|
93 |
|
94 if (pData) |
|
95 *pData = ent->mData; |
|
96 |
|
97 return true; |
|
98 } |
|
99 |
|
100 /** |
|
101 * For pointer types, get the value, returning nullptr if the entry is not |
|
102 * present in the table. |
|
103 * |
|
104 * @param aKey the key to retrieve |
|
105 * @return The found value, or nullptr if no entry was found with the given key. |
|
106 * @note If nullptr values are stored in the table, it is not possible to |
|
107 * distinguish between a nullptr value and a missing entry. |
|
108 */ |
|
109 UserDataType Get(KeyType aKey) const |
|
110 { |
|
111 EntryType* ent = this->GetEntry(aKey); |
|
112 if (!ent) |
|
113 return 0; |
|
114 |
|
115 return ent->mData; |
|
116 } |
|
117 |
|
118 /** |
|
119 * put a new value for the associated key |
|
120 * @param aKey the key to put |
|
121 * @param aData the new data |
|
122 * @return always true, unless memory allocation failed |
|
123 */ |
|
124 void Put(KeyType aKey, const UserDataType& aData) |
|
125 { |
|
126 if (!Put(aKey, aData, fallible_t())) |
|
127 NS_ABORT_OOM(this->mTable.entrySize * this->mTable.entryCount); |
|
128 } |
|
129 |
|
130 bool Put(KeyType aKey, const UserDataType& aData, const fallible_t&) NS_WARN_UNUSED_RESULT |
|
131 { |
|
132 EntryType* ent = this->PutEntry(aKey); |
|
133 |
|
134 if (!ent) |
|
135 return false; |
|
136 |
|
137 ent->mData = aData; |
|
138 |
|
139 return true; |
|
140 } |
|
141 |
|
142 /** |
|
143 * remove the data for the associated key |
|
144 * @param aKey the key to remove from the hashtable |
|
145 */ |
|
146 void Remove(KeyType aKey) { this->RemoveEntry(aKey); } |
|
147 |
|
148 /** |
|
149 * function type provided by the application for enumeration. |
|
150 * @param aKey the key being enumerated |
|
151 * @param aData data being enumerated |
|
152 * @parm userArg passed unchanged from Enumerate |
|
153 * @return either |
|
154 * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink or |
|
155 * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink |
|
156 */ |
|
157 typedef PLDHashOperator |
|
158 (* EnumReadFunction)(KeyType aKey, |
|
159 UserDataType aData, |
|
160 void* userArg); |
|
161 |
|
162 /** |
|
163 * enumerate entries in the hashtable, without allowing changes |
|
164 * @param enumFunc enumeration callback |
|
165 * @param userArg passed unchanged to the EnumReadFunction |
|
166 */ |
|
167 uint32_t EnumerateRead(EnumReadFunction enumFunc, void* userArg) const |
|
168 { |
|
169 NS_ASSERTION(this->mTable.entrySize, |
|
170 "nsBaseHashtable was not initialized properly."); |
|
171 |
|
172 s_EnumReadArgs enumData = { enumFunc, userArg }; |
|
173 return PL_DHashTableEnumerate(const_cast<PLDHashTable*>(&this->mTable), |
|
174 s_EnumReadStub, |
|
175 &enumData); |
|
176 } |
|
177 |
|
178 /** |
|
179 * function type provided by the application for enumeration. |
|
180 * @param aKey the key being enumerated |
|
181 * @param aData Reference to data being enumerated, may be altered. e.g. for |
|
182 * nsInterfaceHashtable this is an nsCOMPtr reference... |
|
183 * @parm userArg passed unchanged from Enumerate |
|
184 * @return bitflag combination of |
|
185 * @link PLDHashOperator::PL_DHASH_REMOVE @endlink, |
|
186 * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink, or |
|
187 * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink |
|
188 */ |
|
189 typedef PLDHashOperator |
|
190 (* EnumFunction)(KeyType aKey, |
|
191 DataType& aData, |
|
192 void* userArg); |
|
193 |
|
194 /** |
|
195 * enumerate entries in the hashtable, allowing changes. This |
|
196 * functions write-locks the hashtable. |
|
197 * @param enumFunc enumeration callback |
|
198 * @param userArg passed unchanged to the EnumFunction |
|
199 */ |
|
200 uint32_t Enumerate(EnumFunction enumFunc, void* userArg) |
|
201 { |
|
202 NS_ASSERTION(this->mTable.entrySize, |
|
203 "nsBaseHashtable was not initialized properly."); |
|
204 |
|
205 s_EnumArgs enumData = { enumFunc, userArg }; |
|
206 return PL_DHashTableEnumerate(&this->mTable, |
|
207 s_EnumStub, |
|
208 &enumData); |
|
209 } |
|
210 |
|
211 /** |
|
212 * reset the hashtable, removing all entries |
|
213 */ |
|
214 void Clear() { nsTHashtable<EntryType>::Clear(); } |
|
215 |
|
216 /** |
|
217 * client must provide a SizeOfEntryExcludingThisFun function for |
|
218 * SizeOfExcludingThis. |
|
219 * @param aKey the key being enumerated |
|
220 * @param aData Reference to data being enumerated. |
|
221 * @param mallocSizeOf the function used to measure heap-allocated blocks |
|
222 * @param userArg passed unchanged from SizeOf{In,Ex}cludingThis |
|
223 * @return summed size of the things pointed to by the entries |
|
224 */ |
|
225 typedef size_t |
|
226 (* SizeOfEntryExcludingThisFun)(KeyType aKey, |
|
227 const DataType &aData, |
|
228 mozilla::MallocSizeOf mallocSizeOf, |
|
229 void* userArg); |
|
230 |
|
231 /** |
|
232 * Measure the size of the table's entry storage and the table itself. |
|
233 * If |sizeOfEntryExcludingThis| is non-nullptr, measure the size of things |
|
234 * pointed to by entries. |
|
235 * |
|
236 * @param sizeOfEntryExcludingThis |
|
237 * the <code>SizeOfEntryExcludingThisFun</code> function to call |
|
238 * @param mallocSizeOf the function used to meeasure heap-allocated blocks |
|
239 * @param userArg a point to pass to the |
|
240 * <code>SizeOfEntryExcludingThisFun</code> function |
|
241 * @return the summed size of the entries, the table, and the table's storage |
|
242 */ |
|
243 size_t SizeOfIncludingThis(SizeOfEntryExcludingThisFun sizeOfEntryExcludingThis, |
|
244 mozilla::MallocSizeOf mallocSizeOf, void *userArg = nullptr) |
|
245 { |
|
246 return mallocSizeOf(this) + this->SizeOfExcludingThis(sizeOfEntryExcludingThis, |
|
247 mallocSizeOf, userArg); |
|
248 } |
|
249 |
|
250 /** |
|
251 * Measure the size of the table's entry storage, and if |
|
252 * |sizeOfEntryExcludingThis| is non-nullptr, measure the size of things pointed |
|
253 * to by entries. |
|
254 * |
|
255 * @param sizeOfEntryExcludingThis the |
|
256 * <code>SizeOfEntryExcludingThisFun</code> function to call |
|
257 * @param mallocSizeOf the function used to measure heap-allocated blocks |
|
258 * @param userArg a pointer to pass to the |
|
259 * <code>SizeOfEntryExcludingThisFun</code> function |
|
260 * @return the summed size of all the entries |
|
261 */ |
|
262 size_t SizeOfExcludingThis(SizeOfEntryExcludingThisFun sizeOfEntryExcludingThis, |
|
263 mozilla::MallocSizeOf mallocSizeOf, void *userArg = nullptr) const |
|
264 { |
|
265 if (sizeOfEntryExcludingThis) { |
|
266 s_SizeOfArgs args = { sizeOfEntryExcludingThis, userArg }; |
|
267 return PL_DHashTableSizeOfExcludingThis(&this->mTable, s_SizeOfStub, |
|
268 mallocSizeOf, &args); |
|
269 } |
|
270 return PL_DHashTableSizeOfExcludingThis(&this->mTable, nullptr, |
|
271 mallocSizeOf); |
|
272 } |
|
273 |
|
274 #ifdef DEBUG |
|
275 using nsTHashtable<EntryType>::MarkImmutable; |
|
276 #endif |
|
277 |
|
278 protected: |
|
279 /** |
|
280 * used internally during EnumerateRead. Allocated on the stack. |
|
281 * @param func the enumerator passed to EnumerateRead |
|
282 * @param userArg the userArg passed to EnumerateRead |
|
283 */ |
|
284 struct s_EnumReadArgs |
|
285 { |
|
286 EnumReadFunction func; |
|
287 void* userArg; |
|
288 }; |
|
289 |
|
290 static PLDHashOperator s_EnumReadStub(PLDHashTable *table, |
|
291 PLDHashEntryHdr *hdr, |
|
292 uint32_t number, |
|
293 void *arg); |
|
294 |
|
295 struct s_EnumArgs |
|
296 { |
|
297 EnumFunction func; |
|
298 void* userArg; |
|
299 }; |
|
300 |
|
301 static PLDHashOperator s_EnumStub(PLDHashTable *table, |
|
302 PLDHashEntryHdr *hdr, |
|
303 uint32_t number, |
|
304 void *arg); |
|
305 |
|
306 struct s_SizeOfArgs |
|
307 { |
|
308 SizeOfEntryExcludingThisFun func; |
|
309 void* userArg; |
|
310 }; |
|
311 |
|
312 static size_t s_SizeOfStub(PLDHashEntryHdr *entry, |
|
313 mozilla::MallocSizeOf mallocSizeOf, |
|
314 void *arg); |
|
315 }; |
|
316 |
|
317 class nsCycleCollectionTraversalCallback; |
|
318 |
|
319 struct MOZ_STACK_CLASS nsBaseHashtableCCTraversalData |
|
320 { |
|
321 nsBaseHashtableCCTraversalData(nsCycleCollectionTraversalCallback& aCallback, |
|
322 const char* aName, |
|
323 uint32_t aFlags) |
|
324 : mCallback(aCallback), |
|
325 mName(aName), |
|
326 mFlags(aFlags) |
|
327 { |
|
328 } |
|
329 |
|
330 nsCycleCollectionTraversalCallback& mCallback; |
|
331 const char* mName; |
|
332 uint32_t mFlags; |
|
333 |
|
334 }; |
|
335 |
|
336 template <typename K, typename T> |
|
337 PLDHashOperator |
|
338 ImplCycleCollectionTraverse_EnumFunc(K aKey, |
|
339 T aData, |
|
340 void* aUserData) |
|
341 { |
|
342 nsBaseHashtableCCTraversalData* userData = |
|
343 static_cast<nsBaseHashtableCCTraversalData*>(aUserData); |
|
344 |
|
345 CycleCollectionNoteChild(userData->mCallback, |
|
346 aData, |
|
347 userData->mName, |
|
348 userData->mFlags); |
|
349 return PL_DHASH_NEXT; |
|
350 } |
|
351 |
|
352 // |
|
353 // nsBaseHashtableET definitions |
|
354 // |
|
355 |
|
356 template<class KeyClass,class DataType> |
|
357 nsBaseHashtableET<KeyClass,DataType>::nsBaseHashtableET(KeyTypePointer aKey) : |
|
358 KeyClass(aKey) |
|
359 { } |
|
360 |
|
361 template<class KeyClass,class DataType> |
|
362 nsBaseHashtableET<KeyClass,DataType>::nsBaseHashtableET |
|
363 (nsBaseHashtableET<KeyClass,DataType>&& toMove) : |
|
364 KeyClass(mozilla::Move(toMove)), |
|
365 mData(mozilla::Move(toMove.mData)) |
|
366 { } |
|
367 |
|
368 template<class KeyClass,class DataType> |
|
369 nsBaseHashtableET<KeyClass,DataType>::~nsBaseHashtableET() |
|
370 { } |
|
371 |
|
372 |
|
373 // |
|
374 // nsBaseHashtable definitions |
|
375 // |
|
376 |
|
377 template<class KeyClass,class DataType,class UserDataType> |
|
378 PLDHashOperator |
|
379 nsBaseHashtable<KeyClass,DataType,UserDataType>::s_EnumReadStub |
|
380 (PLDHashTable *table, PLDHashEntryHdr *hdr, uint32_t number, void* arg) |
|
381 { |
|
382 EntryType* ent = static_cast<EntryType*>(hdr); |
|
383 s_EnumReadArgs* eargs = (s_EnumReadArgs*) arg; |
|
384 |
|
385 PLDHashOperator res = (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg); |
|
386 |
|
387 NS_ASSERTION( !(res & PL_DHASH_REMOVE ), |
|
388 "PL_DHASH_REMOVE return during const enumeration; ignoring."); |
|
389 |
|
390 if (res & PL_DHASH_STOP) |
|
391 return PL_DHASH_STOP; |
|
392 |
|
393 return PL_DHASH_NEXT; |
|
394 } |
|
395 |
|
396 template<class KeyClass,class DataType,class UserDataType> |
|
397 PLDHashOperator |
|
398 nsBaseHashtable<KeyClass,DataType,UserDataType>::s_EnumStub |
|
399 (PLDHashTable *table, PLDHashEntryHdr *hdr, uint32_t number, void* arg) |
|
400 { |
|
401 EntryType* ent = static_cast<EntryType*>(hdr); |
|
402 s_EnumArgs* eargs = (s_EnumArgs*) arg; |
|
403 |
|
404 return (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg); |
|
405 } |
|
406 |
|
407 template<class KeyClass,class DataType,class UserDataType> |
|
408 size_t |
|
409 nsBaseHashtable<KeyClass,DataType,UserDataType>::s_SizeOfStub |
|
410 (PLDHashEntryHdr *hdr, mozilla::MallocSizeOf mallocSizeOf, void *arg) |
|
411 { |
|
412 EntryType* ent = static_cast<EntryType*>(hdr); |
|
413 s_SizeOfArgs* eargs = static_cast<s_SizeOfArgs*>(arg); |
|
414 |
|
415 return (eargs->func)(ent->GetKey(), ent->mData, mallocSizeOf, eargs->userArg); |
|
416 } |
|
417 |
|
418 #endif // nsBaseHashtable_h__ |