1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is C++ hashtable templates.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Benjamin Smedberg.
19 : * Portions created by the Initial Developer are Copyright (C) 2002
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef nsBaseHashtable_h__
39 : #define nsBaseHashtable_h__
40 :
41 : #include "nsTHashtable.h"
42 : #include "prlock.h"
43 : #include "nsDebug.h"
44 :
45 : template<class KeyClass,class DataType,class UserDataType>
46 : class nsBaseHashtable; // forward declaration
47 :
48 : /**
49 : * the private nsTHashtable::EntryType class used by nsBaseHashtable
50 : * @see nsTHashtable for the specification of this class
51 : * @see nsBaseHashtable for template parameters
52 : */
53 : template<class KeyClass,class DataType>
54 : class nsBaseHashtableET : public KeyClass
55 : {
56 : public:
57 : DataType mData;
58 : friend class nsTHashtable< nsBaseHashtableET<KeyClass,DataType> >;
59 :
60 : private:
61 : typedef typename KeyClass::KeyType KeyType;
62 : typedef typename KeyClass::KeyTypePointer KeyTypePointer;
63 :
64 : nsBaseHashtableET(KeyTypePointer aKey);
65 : nsBaseHashtableET(nsBaseHashtableET<KeyClass,DataType>& toCopy);
66 : ~nsBaseHashtableET();
67 : };
68 :
69 : /**
70 : * templated hashtable for simple data types
71 : * This class manages simple data types that do not need construction or
72 : * destruction.
73 : *
74 : * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h
75 : * for a complete specification.
76 : * @param DataType the datatype stored in the hashtable,
77 : * for example, PRUint32 or nsCOMPtr. If UserDataType is not the same,
78 : * DataType must implicitly cast to UserDataType
79 : * @param UserDataType the user sees, for example PRUint32 or nsISupports*
80 : */
81 : template<class KeyClass,class DataType,class UserDataType>
82 : class nsBaseHashtable :
83 : protected nsTHashtable< nsBaseHashtableET<KeyClass,DataType> >
84 8 : {
85 : public:
86 : typedef typename KeyClass::KeyType KeyType;
87 : typedef nsBaseHashtableET<KeyClass,DataType> EntryType;
88 :
89 : // default constructor+destructor are fine
90 :
91 : /**
92 : * Initialize the object.
93 : * @param initSize the initial number of buckets in the hashtable,
94 : * default 16
95 : * locking on all class methods
96 : * @return true if the object was initialized properly.
97 : */
98 1222 : bool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE)
99 1222 : { return nsTHashtable<EntryType>::Init(initSize); }
100 :
101 : /**
102 : * Check whether the table has been initialized.
103 : * This function is especially useful for static hashtables.
104 : * @return true if the table has been initialized.
105 : */
106 : bool IsInitialized() const { return !!this->mTable.entrySize; }
107 :
108 : /**
109 : * Return the number of entries in the table.
110 : * @return number of entries
111 : */
112 : PRUint32 Count() const
113 : { return nsTHashtable<EntryType>::Count(); }
114 :
115 : /**
116 : * retrieve the value for a key.
117 : * @param aKey the key to retreive
118 : * @param pData data associated with this key will be placed at this
119 : * pointer. If you only need to check if the key exists, pData
120 : * may be null.
121 : * @return true if the key exists. If key does not exist, pData is not
122 : * modified.
123 : */
124 0 : bool Get(KeyType aKey, UserDataType* pData NS_OUTPARAM) const
125 : {
126 0 : EntryType* ent = this->GetEntry(aKey);
127 :
128 0 : if (!ent)
129 0 : return false;
130 :
131 0 : if (pData)
132 0 : *pData = ent->mData;
133 :
134 0 : return true;
135 : }
136 :
137 : /**
138 : * For pointer types, get the value, returning nsnull if the entry is not
139 : * present in the table.
140 : *
141 : * @param aKey the key to retrieve
142 : * @return The found value, or nsnull if no entry was found with the given key.
143 : * @note If nsnull values are stored in the table, it is not possible to
144 : * distinguish between a nsnull value and a missing entry.
145 : */
146 : UserDataType Get(KeyType aKey) const
147 : {
148 : EntryType* ent = this->GetEntry(aKey);
149 : if (!ent)
150 : return nsnull;
151 :
152 : return ent->mData;
153 : }
154 :
155 : /**
156 : * put a new value for the associated key
157 : * @param aKey the key to put
158 : * @param aData the new data
159 : * @return always true, unless memory allocation failed
160 : */
161 1533 : bool Put(KeyType aKey, UserDataType aData)
162 : {
163 1533 : EntryType* ent = this->PutEntry(aKey);
164 :
165 1533 : if (!ent)
166 0 : return false;
167 :
168 1533 : ent->mData = aData;
169 :
170 1533 : return true;
171 : }
172 :
173 : /**
174 : * remove the data for the associated key
175 : * @param aKey the key to remove from the hashtable
176 : */
177 1 : void Remove(KeyType aKey) { this->RemoveEntry(aKey); }
178 :
179 : /**
180 : * function type provided by the application for enumeration.
181 : * @param aKey the key being enumerated
182 : * @param aData data being enumerated
183 : * @parm userArg passed unchanged from Enumerate
184 : * @return either
185 : * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink or
186 : * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink
187 : */
188 : typedef PLDHashOperator
189 : (* EnumReadFunction)(KeyType aKey,
190 : UserDataType aData,
191 : void* userArg);
192 :
193 : /**
194 : * enumerate entries in the hashtable, without allowing changes
195 : * @param enumFunc enumeration callback
196 : * @param userArg passed unchanged to the EnumReadFunction
197 : */
198 27 : PRUint32 EnumerateRead(EnumReadFunction enumFunc, void* userArg) const
199 : {
200 27 : NS_ASSERTION(this->mTable.entrySize,
201 : "nsBaseHashtable was not initialized properly.");
202 :
203 27 : s_EnumReadArgs enumData = { enumFunc, userArg };
204 : return PL_DHashTableEnumerate(const_cast<PLDHashTable*>(&this->mTable),
205 : s_EnumReadStub,
206 27 : &enumData);
207 : }
208 :
209 : /**
210 : * function type provided by the application for enumeration.
211 : * @param aKey the key being enumerated
212 : * @param aData Reference to data being enumerated, may be altered. e.g. for
213 : * nsInterfaceHashtable this is an nsCOMPtr reference...
214 : * @parm userArg passed unchanged from Enumerate
215 : * @return bitflag combination of
216 : * @link PLDHashOperator::PL_DHASH_REMOVE @endlink,
217 : * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink, or
218 : * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink
219 : */
220 : typedef PLDHashOperator
221 : (* EnumFunction)(KeyType aKey,
222 : DataType& aData,
223 : void* userArg);
224 :
225 : /**
226 : * enumerate entries in the hashtable, allowing changes. This
227 : * functions write-locks the hashtable.
228 : * @param enumFunc enumeration callback
229 : * @param userArg passed unchanged to the EnumFunction
230 : */
231 : PRUint32 Enumerate(EnumFunction enumFunc, void* userArg)
232 : {
233 : NS_ASSERTION(this->mTable.entrySize,
234 : "nsBaseHashtable was not initialized properly.");
235 :
236 : s_EnumArgs enumData = { enumFunc, userArg };
237 : return PL_DHashTableEnumerate(&this->mTable,
238 : s_EnumStub,
239 : &enumData);
240 : }
241 :
242 : /**
243 : * reset the hashtable, removing all entries
244 : */
245 385 : void Clear() { nsTHashtable<EntryType>::Clear(); }
246 :
247 : /**
248 : * client must provide a SizeOfEntryExcludingThisFun function for
249 : * SizeOfExcludingThis.
250 : * @param aKey the key being enumerated
251 : * @param aData Reference to data being enumerated.
252 : * @param mallocSizeOf the function used to measure heap-allocated blocks
253 : * @param userArg passed unchanged from SizeOf{In,Ex}cludingThis
254 : * @return summed size of the things pointed to by the entries
255 : */
256 : typedef size_t
257 : (* SizeOfEntryExcludingThisFun)(KeyType aKey,
258 : const DataType &aData,
259 : nsMallocSizeOfFun mallocSizeOf,
260 : void* userArg);
261 :
262 : /**
263 : * Measure the size of the table's entry storage, and if
264 : * |sizeOfEntryExcludingThis| is non-nsnull, measure the size of things pointed
265 : * to by entries.
266 : *
267 : * @param sizeOfEntryExcludingThis the
268 : * <code>SizeOfEntryExcludingThisFun</code> function to call
269 : * @param mallocSizeOf the function used to measure heap-allocated blocks
270 : * @param userArg a pointer to pass to the
271 : * <code>SizeOfEntryExcludingThisFun</code> function
272 : * @return the summed size of all the entries
273 : */
274 : size_t SizeOfExcludingThis(SizeOfEntryExcludingThisFun sizeOfEntryExcludingThis,
275 : nsMallocSizeOfFun mallocSizeOf, void *userArg = nsnull)
276 : {
277 : if (IsInitialized()) {
278 : s_SizeOfArgs args = { sizeOfEntryExcludingThis, userArg };
279 : return PL_DHashTableSizeOfExcludingThis(&this->mTable,
280 : s_SizeOfStub,
281 : mallocSizeOf,
282 : &args);
283 : }
284 : return 0;
285 : }
286 :
287 : protected:
288 : /**
289 : * used internally during EnumerateRead. Allocated on the stack.
290 : * @param func the enumerator passed to EnumerateRead
291 : * @param userArg the userArg passed to EnumerateRead
292 : */
293 : struct s_EnumReadArgs
294 : {
295 : EnumReadFunction func;
296 : void* userArg;
297 : };
298 :
299 : static PLDHashOperator s_EnumReadStub(PLDHashTable *table,
300 : PLDHashEntryHdr *hdr,
301 : PRUint32 number,
302 : void *arg);
303 :
304 : struct s_EnumArgs
305 : {
306 : EnumFunction func;
307 : void* userArg;
308 : };
309 :
310 : static PLDHashOperator s_EnumStub(PLDHashTable *table,
311 : PLDHashEntryHdr *hdr,
312 : PRUint32 number,
313 : void *arg);
314 :
315 : struct s_SizeOfArgs
316 : {
317 : SizeOfEntryExcludingThisFun func;
318 : void* userArg;
319 : };
320 :
321 : static size_t s_SizeOfStub(PLDHashEntryHdr *entry,
322 : nsMallocSizeOfFun mallocSizeOf,
323 : void *arg);
324 : };
325 :
326 : /**
327 : * This class is a thread-safe version of nsBaseHashtable.
328 : */
329 : template<class KeyClass,class DataType,class UserDataType>
330 : class nsBaseHashtableMT :
331 : protected nsBaseHashtable<KeyClass,DataType,UserDataType>
332 : {
333 : public:
334 : typedef typename
335 : nsBaseHashtable<KeyClass,DataType,UserDataType>::EntryType EntryType;
336 : typedef typename
337 : nsBaseHashtable<KeyClass,DataType,UserDataType>::KeyType KeyType;
338 : typedef typename
339 : nsBaseHashtable<KeyClass,DataType,UserDataType>::EnumFunction EnumFunction;
340 : typedef typename
341 : nsBaseHashtable<KeyClass,DataType,UserDataType>::EnumReadFunction EnumReadFunction;
342 :
343 : nsBaseHashtableMT() : mLock(nsnull) { }
344 : ~nsBaseHashtableMT();
345 :
346 : bool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE);
347 : bool IsInitialized() const { return mLock != nsnull; }
348 : PRUint32 Count() const;
349 : bool Get(KeyType aKey, UserDataType* pData) const;
350 : bool Put(KeyType aKey, UserDataType aData);
351 : void Remove(KeyType aKey);
352 :
353 : PRUint32 EnumerateRead(EnumReadFunction enumFunc, void* userArg) const;
354 : PRUint32 Enumerate(EnumFunction enumFunc, void* userArg);
355 : void Clear();
356 :
357 : protected:
358 : PRLock* mLock;
359 : };
360 :
361 :
362 : //
363 : // nsBaseHashtableET definitions
364 : //
365 :
366 : template<class KeyClass,class DataType>
367 1541 : nsBaseHashtableET<KeyClass,DataType>::nsBaseHashtableET(KeyTypePointer aKey) :
368 1541 : KeyClass(aKey)
369 1541 : { }
370 :
371 : template<class KeyClass,class DataType>
372 : nsBaseHashtableET<KeyClass,DataType>::nsBaseHashtableET
373 : (nsBaseHashtableET<KeyClass,DataType>& toCopy) :
374 : KeyClass(toCopy),
375 : mData(toCopy.mData)
376 : { }
377 :
378 : template<class KeyClass,class DataType>
379 1541 : nsBaseHashtableET<KeyClass,DataType>::~nsBaseHashtableET()
380 1541 : { }
381 :
382 :
383 : //
384 : // nsBaseHashtable definitions
385 : //
386 :
387 : template<class KeyClass,class DataType,class UserDataType>
388 : PLDHashOperator
389 31 : nsBaseHashtable<KeyClass,DataType,UserDataType>::s_EnumReadStub
390 : (PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number, void* arg)
391 : {
392 31 : EntryType* ent = static_cast<EntryType*>(hdr);
393 31 : s_EnumReadArgs* eargs = (s_EnumReadArgs*) arg;
394 :
395 31 : PLDHashOperator res = (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg);
396 :
397 31 : NS_ASSERTION( !(res & PL_DHASH_REMOVE ),
398 : "PL_DHASH_REMOVE return during const enumeration; ignoring.");
399 :
400 31 : if (res & PL_DHASH_STOP)
401 0 : return PL_DHASH_STOP;
402 :
403 31 : return PL_DHASH_NEXT;
404 : }
405 :
406 : template<class KeyClass,class DataType,class UserDataType>
407 : PLDHashOperator
408 : nsBaseHashtable<KeyClass,DataType,UserDataType>::s_EnumStub
409 : (PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number, void* arg)
410 : {
411 : EntryType* ent = static_cast<EntryType*>(hdr);
412 : s_EnumArgs* eargs = (s_EnumArgs*) arg;
413 :
414 : return (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg);
415 : }
416 :
417 : template<class KeyClass,class DataType,class UserDataType>
418 : size_t
419 : nsBaseHashtable<KeyClass,DataType,UserDataType>::s_SizeOfStub
420 : (PLDHashEntryHdr *hdr, nsMallocSizeOfFun mallocSizeOf, void *arg)
421 : {
422 : EntryType* ent = static_cast<EntryType*>(hdr);
423 : s_SizeOfArgs* eargs = static_cast<s_SizeOfArgs*>(arg);
424 :
425 : return (eargs->func)(ent->GetKey(), ent->mData, mallocSizeOf, eargs->userArg);
426 : }
427 :
428 : //
429 : // nsBaseHashtableMT definitions
430 : //
431 :
432 : template<class KeyClass,class DataType,class UserDataType>
433 : nsBaseHashtableMT<KeyClass,DataType,UserDataType>::~nsBaseHashtableMT()
434 : {
435 : if (this->mLock)
436 : PR_DestroyLock(this->mLock);
437 : }
438 :
439 : template<class KeyClass,class DataType,class UserDataType>
440 : bool
441 : nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Init(PRUint32 initSize)
442 : {
443 : if (!nsTHashtable<EntryType>::IsInitialized() && !nsTHashtable<EntryType>::Init(initSize))
444 : return false;
445 :
446 : this->mLock = PR_NewLock();
447 : NS_ASSERTION(this->mLock, "Error creating lock during nsBaseHashtableL::Init()");
448 :
449 : return (this->mLock != nsnull);
450 : }
451 :
452 : template<class KeyClass,class DataType,class UserDataType>
453 : PRUint32
454 : nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Count() const
455 : {
456 : PR_Lock(this->mLock);
457 : PRUint32 count = nsTHashtable<EntryType>::Count();
458 : PR_Unlock(this->mLock);
459 :
460 : return count;
461 : }
462 :
463 : template<class KeyClass,class DataType,class UserDataType>
464 : bool
465 : nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Get(KeyType aKey,
466 : UserDataType* pData) const
467 : {
468 : PR_Lock(this->mLock);
469 : bool res =
470 : nsBaseHashtable<KeyClass,DataType,UserDataType>::Get(aKey, pData);
471 : PR_Unlock(this->mLock);
472 :
473 : return res;
474 : }
475 :
476 : template<class KeyClass,class DataType,class UserDataType>
477 : bool
478 : nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Put(KeyType aKey,
479 : UserDataType aData)
480 : {
481 : PR_Lock(this->mLock);
482 : bool res =
483 : nsBaseHashtable<KeyClass,DataType,UserDataType>::Put(aKey, aData);
484 : PR_Unlock(this->mLock);
485 :
486 : return res;
487 : }
488 :
489 : template<class KeyClass,class DataType,class UserDataType>
490 : void
491 : nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Remove(KeyType aKey)
492 : {
493 : PR_Lock(this->mLock);
494 : nsBaseHashtable<KeyClass,DataType,UserDataType>::Remove(aKey);
495 : PR_Unlock(this->mLock);
496 : }
497 :
498 : template<class KeyClass,class DataType,class UserDataType>
499 : PRUint32
500 : nsBaseHashtableMT<KeyClass,DataType,UserDataType>::EnumerateRead
501 : (EnumReadFunction fEnumCall, void* userArg) const
502 : {
503 : PR_Lock(this->mLock);
504 : PRUint32 count =
505 : nsBaseHashtable<KeyClass,DataType,UserDataType>::EnumerateRead(fEnumCall, userArg);
506 : PR_Unlock(this->mLock);
507 :
508 : return count;
509 : }
510 :
511 : template<class KeyClass,class DataType,class UserDataType>
512 : PRUint32
513 : nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Enumerate
514 : (EnumFunction fEnumCall, void* userArg)
515 : {
516 : PR_Lock(this->mLock);
517 : PRUint32 count =
518 : nsBaseHashtable<KeyClass,DataType,UserDataType>::Enumerate(fEnumCall, userArg);
519 : PR_Unlock(this->mLock);
520 :
521 : return count;
522 : }
523 :
524 : template<class KeyClass,class DataType,class UserDataType>
525 : void
526 : nsBaseHashtableMT<KeyClass,DataType,UserDataType>::Clear()
527 : {
528 : PR_Lock(this->mLock);
529 : nsBaseHashtable<KeyClass,DataType,UserDataType>::Clear();
530 : PR_Unlock(this->mLock);
531 : }
532 :
533 : #endif // nsBaseHashtable_h__
|