Bug 440351, update win32_buildPlatform for move from pacifica-vm to patrocles clones
[mozilla-1.9.git] / xpcom / ds / nsHashtable.cpp
blob4566000ff31d6224eb80d5114da6d90c9aca677e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or 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.
36 * ***** END LICENSE BLOCK *****
37 * This Original Code has been modified by IBM Corporation.
38 * Modifications made by IBM described herein are
39 * Copyright (c) International Business Machines
40 * Corporation, 2000
42 * Modifications to Mozilla code or documentation
43 * identified per MPL Section 3.3
45 * Date Modified by Description of modification
46 * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
49 #include <string.h>
50 #include "prmem.h"
51 #include "prlog.h"
52 #include "nsHashtable.h"
53 #include "nsReadableUtils.h"
54 #include "nsIObjectInputStream.h"
55 #include "nsIObjectOutputStream.h"
56 #include "nsCRT.h"
58 struct HTEntry : PLDHashEntryHdr
60 nsHashKey* key;
61 void* value;
65 // Key operations
68 PR_STATIC_CALLBACK(PRBool)
69 matchKeyEntry(PLDHashTable*, const PLDHashEntryHdr* entry,
70 const void* key)
72 const HTEntry* hashEntry =
73 static_cast<const HTEntry*>(entry);
75 if (hashEntry->key == key)
76 return PR_TRUE;
78 const nsHashKey* otherKey = reinterpret_cast<const nsHashKey*>(key);
79 return otherKey->Equals(hashEntry->key);
82 PR_STATIC_CALLBACK(PLDHashNumber)
83 hashKey(PLDHashTable* table, const void* key)
85 const nsHashKey* hashKey = static_cast<const nsHashKey*>(key);
87 return hashKey->HashCode();
90 PR_STATIC_CALLBACK(void)
91 clearHashEntry(PLDHashTable* table, PLDHashEntryHdr* entry)
93 HTEntry* hashEntry = static_cast<HTEntry*>(entry);
95 // leave it up to the nsHashKey destructor to free the "value"
96 delete hashEntry->key;
97 hashEntry->key = nsnull;
98 hashEntry->value = nsnull; // probably not necessary, but for
99 // sanity's sake
103 static const PLDHashTableOps hashtableOps = {
104 PL_DHashAllocTable,
105 PL_DHashFreeTable,
106 hashKey,
107 matchKeyEntry,
108 PL_DHashMoveEntryStub,
109 clearHashEntry,
110 PL_DHashFinalizeStub,
111 nsnull,
116 // Enumerator callback
119 struct _HashEnumerateArgs {
120 nsHashtableEnumFunc fn;
121 void* arg;
124 PR_STATIC_CALLBACK(PLDHashOperator)
125 hashEnumerate(PLDHashTable* table, PLDHashEntryHdr* hdr, PRUint32 i, void *arg)
127 _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
128 HTEntry* entry = static_cast<HTEntry*>(hdr);
130 switch (thunk->fn(entry->key, entry->value, thunk->arg)) {
131 case kHashEnumerateNext:
132 return PL_DHASH_NEXT;
133 case kHashEnumerateRemove:
134 return PL_DHASH_REMOVE;
136 return PL_DHASH_STOP;
140 // HashKey
143 nsHashKey::~nsHashKey(void)
145 MOZ_COUNT_DTOR(nsHashKey);
148 nsresult
149 nsHashKey::Write(nsIObjectOutputStream* aStream) const
151 NS_NOTREACHED("oops");
152 return NS_ERROR_NOT_IMPLEMENTED;
155 nsHashtable::nsHashtable(PRUint32 aInitSize, PRBool threadSafe)
156 : mLock(NULL), mEnumerating(PR_FALSE)
158 MOZ_COUNT_CTOR(nsHashtable);
160 PRBool result = PL_DHashTableInit(&mHashtable, &hashtableOps, nsnull,
161 sizeof(HTEntry), aInitSize);
163 NS_ASSERTION(result, "Hashtable failed to initialize");
165 // make sure we detect this later
166 if (!result)
167 mHashtable.ops = nsnull;
169 if (threadSafe) {
170 mLock = PR_NewLock();
171 if (mLock == NULL) {
172 // Cannot create a lock. If running on a multiprocessing system
173 // we are sure to die.
174 PR_ASSERT(mLock != NULL);
180 nsHashtable::~nsHashtable() {
181 MOZ_COUNT_DTOR(nsHashtable);
182 if (mHashtable.ops)
183 PL_DHashTableFinish(&mHashtable);
184 if (mLock) PR_DestroyLock(mLock);
187 PRBool nsHashtable::Exists(nsHashKey *aKey)
189 if (mLock) PR_Lock(mLock);
191 if (!mHashtable.ops)
192 return PR_FALSE;
194 PLDHashEntryHdr *entry =
195 PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP);
197 PRBool exists = PL_DHASH_ENTRY_IS_BUSY(entry);
199 if (mLock) PR_Unlock(mLock);
201 return exists;
204 void *nsHashtable::Put(nsHashKey *aKey, void *aData)
206 void *res = NULL;
208 if (!mHashtable.ops) return nsnull;
210 if (mLock) PR_Lock(mLock);
212 // shouldn't be adding an item during enumeration
213 PR_ASSERT(!mEnumerating);
215 HTEntry* entry =
216 static_cast<HTEntry*>
217 (PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_ADD));
219 if (entry) { // don't return early, or you'll be locked!
220 if (entry->key) {
221 // existing entry, need to boot the old value
222 res = entry->value;
223 entry->value = aData;
224 } else {
225 // new entry (leave res == null)
226 entry->key = aKey->Clone();
227 entry->value = aData;
231 if (mLock) PR_Unlock(mLock);
233 return res;
236 void *nsHashtable::Get(nsHashKey *aKey)
238 if (!mHashtable.ops) return nsnull;
240 if (mLock) PR_Lock(mLock);
242 HTEntry* entry =
243 static_cast<HTEntry*>
244 (PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP));
245 void *ret = PL_DHASH_ENTRY_IS_BUSY(entry) ? entry->value : nsnull;
247 if (mLock) PR_Unlock(mLock);
249 return ret;
252 void *nsHashtable::Remove(nsHashKey *aKey)
254 if (!mHashtable.ops) return nsnull;
256 if (mLock) PR_Lock(mLock);
258 // shouldn't be adding an item during enumeration
259 PR_ASSERT(!mEnumerating);
262 // need to see if the entry is actually there, in order to get the
263 // old value for the result
264 HTEntry* entry =
265 static_cast<HTEntry*>
266 (PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP));
267 void *res;
269 if (PL_DHASH_ENTRY_IS_FREE(entry)) {
270 // value wasn't in the table anyway
271 res = nsnull;
272 } else {
273 res = entry->value;
274 PL_DHashTableRawRemove(&mHashtable, entry);
277 if (mLock) PR_Unlock(mLock);
279 return res;
282 // XXX This method was called _hashEnumerateCopy, but it didn't copy the element!
283 // I don't know how this was supposed to work since the elements are neither copied
284 // nor refcounted.
285 PR_STATIC_CALLBACK(PLDHashOperator)
286 hashEnumerateShare(PLDHashTable *table, PLDHashEntryHdr *hdr,
287 PRUint32 i, void *arg)
289 nsHashtable *newHashtable = (nsHashtable *)arg;
290 HTEntry * entry = static_cast<HTEntry*>(hdr);
292 newHashtable->Put(entry->key, entry->value);
293 return PL_DHASH_NEXT;
296 nsHashtable * nsHashtable::Clone()
298 if (!mHashtable.ops) return nsnull;
300 PRBool threadSafe = (mLock != nsnull);
301 nsHashtable *newHashTable = new nsHashtable(mHashtable.entryCount, threadSafe);
303 PL_DHashTableEnumerate(&mHashtable, hashEnumerateShare, newHashTable);
304 return newHashTable;
307 void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* aClosure)
309 if (!mHashtable.ops) return;
311 PRBool wasEnumerating = mEnumerating;
312 mEnumerating = PR_TRUE;
313 _HashEnumerateArgs thunk;
314 thunk.fn = aEnumFunc;
315 thunk.arg = aClosure;
316 PL_DHashTableEnumerate(&mHashtable, hashEnumerate, &thunk);
317 mEnumerating = wasEnumerating;
320 PR_STATIC_CALLBACK(PLDHashOperator)
321 hashEnumerateRemove(PLDHashTable*, PLDHashEntryHdr* hdr, PRUint32 i, void *arg)
323 HTEntry* entry = static_cast<HTEntry*>(hdr);
324 _HashEnumerateArgs* thunk = (_HashEnumerateArgs*)arg;
325 if (thunk) {
326 return thunk->fn(entry->key, entry->value, thunk->arg)
327 ? PL_DHASH_REMOVE
328 : PL_DHASH_STOP;
330 return PL_DHASH_REMOVE;
333 void nsHashtable::Reset() {
334 Reset(NULL);
337 void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc, void* aClosure)
339 if (!mHashtable.ops) return;
341 _HashEnumerateArgs thunk, *thunkp;
342 if (!destroyFunc) {
343 thunkp = nsnull;
344 } else {
345 thunkp = &thunk;
346 thunk.fn = destroyFunc;
347 thunk.arg = aClosure;
349 PL_DHashTableEnumerate(&mHashtable, hashEnumerateRemove, thunkp);
352 // nsISerializable helpers
354 nsHashtable::nsHashtable(nsIObjectInputStream* aStream,
355 nsHashtableReadEntryFunc aReadEntryFunc,
356 nsHashtableFreeEntryFunc aFreeEntryFunc,
357 nsresult *aRetVal)
358 : mLock(nsnull),
359 mEnumerating(PR_FALSE)
361 MOZ_COUNT_CTOR(nsHashtable);
363 PRBool threadSafe;
364 nsresult rv = aStream->ReadBoolean(&threadSafe);
365 if (NS_SUCCEEDED(rv)) {
366 if (threadSafe) {
367 mLock = PR_NewLock();
368 if (!mLock)
369 rv = NS_ERROR_OUT_OF_MEMORY;
372 if (NS_SUCCEEDED(rv)) {
373 PRUint32 count;
374 rv = aStream->Read32(&count);
376 if (NS_SUCCEEDED(rv)) {
377 PRBool status =
378 PL_DHashTableInit(&mHashtable, &hashtableOps,
379 nsnull, sizeof(HTEntry), count);
380 if (!status) {
381 mHashtable.ops = nsnull;
382 rv = NS_ERROR_OUT_OF_MEMORY;
383 } else {
384 for (PRUint32 i = 0; i < count; i++) {
385 nsHashKey* key;
386 void *data;
388 rv = aReadEntryFunc(aStream, &key, &data);
389 if (NS_SUCCEEDED(rv)) {
390 if (!Put(key, data)) {
391 rv = NS_ERROR_OUT_OF_MEMORY;
392 aFreeEntryFunc(aStream, key, data);
393 } else {
394 // XXXbe must we clone key? can't we hand off
395 aFreeEntryFunc(aStream, key, nsnull);
397 if (NS_FAILED(rv))
398 break;
405 *aRetVal = rv;
408 struct WriteEntryArgs {
409 nsIObjectOutputStream* mStream;
410 nsHashtableWriteDataFunc mWriteDataFunc;
411 nsresult mRetVal;
414 PR_STATIC_CALLBACK(PRBool)
415 WriteEntry(nsHashKey *aKey, void *aData, void* aClosure)
417 WriteEntryArgs* args = (WriteEntryArgs*) aClosure;
418 nsIObjectOutputStream* stream = args->mStream;
420 nsresult rv = aKey->Write(stream);
421 if (NS_SUCCEEDED(rv))
422 rv = args->mWriteDataFunc(stream, aData);
424 args->mRetVal = rv;
425 return PR_TRUE;
428 nsresult
429 nsHashtable::Write(nsIObjectOutputStream* aStream,
430 nsHashtableWriteDataFunc aWriteDataFunc) const
432 if (!mHashtable.ops)
433 return NS_ERROR_OUT_OF_MEMORY;
434 PRBool threadSafe = (mLock != nsnull);
435 nsresult rv = aStream->WriteBoolean(threadSafe);
436 if (NS_FAILED(rv)) return rv;
438 // Write the entry count first, so we know how many key/value pairs to read.
439 PRUint32 count = mHashtable.entryCount;
440 rv = aStream->Write32(count);
441 if (NS_FAILED(rv)) return rv;
443 // Write all key/value pairs in the table.
444 WriteEntryArgs args = {aStream, aWriteDataFunc};
445 const_cast<nsHashtable*>(this)->Enumerate(WriteEntry, (void*) &args);
446 return args.mRetVal;
449 ////////////////////////////////////////////////////////////////////////////////
451 nsISupportsKey::nsISupportsKey(nsIObjectInputStream* aStream, nsresult *aResult)
452 : mKey(nsnull)
454 PRBool nonnull;
455 nsresult rv = aStream->ReadBoolean(&nonnull);
456 if (NS_SUCCEEDED(rv) && nonnull)
457 rv = aStream->ReadObject(PR_TRUE, &mKey);
458 *aResult = rv;
461 nsresult
462 nsISupportsKey::Write(nsIObjectOutputStream* aStream) const
464 PRBool nonnull = (mKey != nsnull);
465 nsresult rv = aStream->WriteBoolean(nonnull);
466 if (NS_SUCCEEDED(rv) && nonnull)
467 rv = aStream->WriteObject(mKey, PR_TRUE);
468 return rv;
471 nsIDKey::nsIDKey(nsIObjectInputStream* aStream, nsresult *aResult)
473 *aResult = aStream->ReadID(&mID);
476 nsresult nsIDKey::Write(nsIObjectOutputStream* aStream) const
478 return aStream->WriteID(mID);
481 ////////////////////////////////////////////////////////////////////////////////
483 // Copy Constructor
484 // We need to free mStr if the object is passed with mOwnership as OWN. As the
485 // destructor here is freeing mStr in that case, mStr is NOT getting leaked here.
487 nsCStringKey::nsCStringKey(const nsCStringKey& aKey)
488 : mStr(aKey.mStr), mStrLen(aKey.mStrLen), mOwnership(aKey.mOwnership)
490 if (mOwnership != NEVER_OWN) {
491 PRUint32 len = mStrLen * sizeof(char);
492 char* str = reinterpret_cast<char*>(nsMemory::Alloc(len + sizeof(char)));
493 if (!str) {
494 // Pray we don't dangle!
495 mOwnership = NEVER_OWN;
496 } else {
497 // Use memcpy in case there are embedded NULs.
498 memcpy(str, mStr, len);
499 str[mStrLen] = '\0';
500 mStr = str;
501 mOwnership = OWN;
504 #ifdef DEBUG
505 mKeyType = CStringKey;
506 #endif
507 MOZ_COUNT_CTOR(nsCStringKey);
510 nsCStringKey::nsCStringKey(const nsAFlatCString& str)
511 : mStr(const_cast<char*>(str.get())),
512 mStrLen(str.Length()),
513 mOwnership(OWN_CLONE)
515 NS_ASSERTION(mStr, "null string key");
516 #ifdef DEBUG
517 mKeyType = CStringKey;
518 #endif
519 MOZ_COUNT_CTOR(nsCStringKey);
522 nsCStringKey::nsCStringKey(const nsACString& str)
523 : mStr(ToNewCString(str)),
524 mStrLen(str.Length()),
525 mOwnership(OWN)
527 NS_ASSERTION(mStr, "null string key");
528 #ifdef DEBUG
529 mKeyType = CStringKey;
530 #endif
531 MOZ_COUNT_CTOR(nsCStringKey);
534 nsCStringKey::nsCStringKey(const char* str, PRInt32 strLen, Ownership own)
535 : mStr((char*)str), mStrLen(strLen), mOwnership(own)
537 NS_ASSERTION(mStr, "null string key");
538 if (mStrLen == PRUint32(-1))
539 mStrLen = strlen(str);
540 #ifdef DEBUG
541 mKeyType = CStringKey;
542 #endif
543 MOZ_COUNT_CTOR(nsCStringKey);
546 nsCStringKey::~nsCStringKey(void)
548 if (mOwnership == OWN)
549 nsMemory::Free(mStr);
550 MOZ_COUNT_DTOR(nsCStringKey);
553 PRUint32
554 nsCStringKey::HashCode(void) const
556 return nsCRT::HashCode(mStr, (PRUint32*)&mStrLen);
559 PRBool
560 nsCStringKey::Equals(const nsHashKey* aKey) const
562 NS_ASSERTION(aKey->GetKeyType() == CStringKey, "mismatched key types");
563 nsCStringKey* other = (nsCStringKey*)aKey;
564 NS_ASSERTION(mStrLen != PRUint32(-1), "never called HashCode");
565 NS_ASSERTION(other->mStrLen != PRUint32(-1), "never called HashCode");
566 if (mStrLen != other->mStrLen)
567 return PR_FALSE;
568 return memcmp(mStr, other->mStr, mStrLen * sizeof(char)) == 0;
571 nsHashKey*
572 nsCStringKey::Clone() const
574 if (mOwnership == NEVER_OWN)
575 return new nsCStringKey(mStr, mStrLen, NEVER_OWN);
577 // Since this might hold binary data OR a string, we ensure that the
578 // clone string is zero terminated, but don't assume that the source
579 // string was so terminated.
581 PRUint32 len = mStrLen * sizeof(char);
582 char* str = (char*)nsMemory::Alloc(len + sizeof(char));
583 if (str == NULL)
584 return NULL;
585 memcpy(str, mStr, len);
586 str[len] = 0;
587 return new nsCStringKey(str, mStrLen, OWN);
590 nsCStringKey::nsCStringKey(nsIObjectInputStream* aStream, nsresult *aResult)
591 : mStr(nsnull), mStrLen(0), mOwnership(OWN)
593 nsCAutoString str;
594 nsresult rv = aStream->ReadCString(str);
595 mStr = ToNewCString(str);
596 if (NS_SUCCEEDED(rv))
597 mStrLen = str.Length();
598 *aResult = rv;
599 MOZ_COUNT_CTOR(nsCStringKey);
602 nsresult
603 nsCStringKey::Write(nsIObjectOutputStream* aStream) const
605 return aStream->WriteStringZ(mStr);
608 ////////////////////////////////////////////////////////////////////////////////
610 // Copy Constructor
611 // We need to free mStr if the object is passed with mOwnership as OWN. As the
612 // destructor here is freeing mStr in that case, mStr is NOT getting leaked here.
614 nsStringKey::nsStringKey(const nsStringKey& aKey)
615 : mStr(aKey.mStr), mStrLen(aKey.mStrLen), mOwnership(aKey.mOwnership)
617 if (mOwnership != NEVER_OWN) {
618 PRUint32 len = mStrLen * sizeof(PRUnichar);
619 PRUnichar* str = reinterpret_cast<PRUnichar*>(nsMemory::Alloc(len + sizeof(PRUnichar)));
620 if (!str) {
621 // Pray we don't dangle!
622 mOwnership = NEVER_OWN;
623 } else {
624 // Use memcpy in case there are embedded NULs.
625 memcpy(str, mStr, len);
626 str[mStrLen] = 0;
627 mStr = str;
628 mOwnership = OWN;
631 #ifdef DEBUG
632 mKeyType = StringKey;
633 #endif
634 MOZ_COUNT_CTOR(nsStringKey);
637 nsStringKey::nsStringKey(const nsAFlatString& str)
638 : mStr(const_cast<PRUnichar*>(str.get())),
639 mStrLen(str.Length()),
640 mOwnership(OWN_CLONE)
642 NS_ASSERTION(mStr, "null string key");
643 #ifdef DEBUG
644 mKeyType = StringKey;
645 #endif
646 MOZ_COUNT_CTOR(nsStringKey);
649 nsStringKey::nsStringKey(const nsAString& str)
650 : mStr(ToNewUnicode(str)),
651 mStrLen(str.Length()),
652 mOwnership(OWN)
654 NS_ASSERTION(mStr, "null string key");
655 #ifdef DEBUG
656 mKeyType = StringKey;
657 #endif
658 MOZ_COUNT_CTOR(nsStringKey);
661 nsStringKey::nsStringKey(const PRUnichar* str, PRInt32 strLen, Ownership own)
662 : mStr((PRUnichar*)str), mStrLen(strLen), mOwnership(own)
664 NS_ASSERTION(mStr, "null string key");
665 if (mStrLen == PRUint32(-1))
666 mStrLen = nsCRT::strlen(str);
667 #ifdef DEBUG
668 mKeyType = StringKey;
669 #endif
670 MOZ_COUNT_CTOR(nsStringKey);
673 nsStringKey::~nsStringKey(void)
675 if (mOwnership == OWN)
676 nsMemory::Free(mStr);
677 MOZ_COUNT_DTOR(nsStringKey);
680 PRUint32
681 nsStringKey::HashCode(void) const
683 return nsCRT::HashCode(mStr, (PRUint32*)&mStrLen);
686 PRBool
687 nsStringKey::Equals(const nsHashKey* aKey) const
689 NS_ASSERTION(aKey->GetKeyType() == StringKey, "mismatched key types");
690 nsStringKey* other = (nsStringKey*)aKey;
691 NS_ASSERTION(mStrLen != PRUint32(-1), "never called HashCode");
692 NS_ASSERTION(other->mStrLen != PRUint32(-1), "never called HashCode");
693 if (mStrLen != other->mStrLen)
694 return PR_FALSE;
695 return memcmp(mStr, other->mStr, mStrLen * sizeof(PRUnichar)) == 0;
698 nsHashKey*
699 nsStringKey::Clone() const
701 if (mOwnership == NEVER_OWN)
702 return new nsStringKey(mStr, mStrLen, NEVER_OWN);
704 PRUint32 len = (mStrLen+1) * sizeof(PRUnichar);
705 PRUnichar* str = (PRUnichar*)nsMemory::Alloc(len);
706 if (str == NULL)
707 return NULL;
708 memcpy(str, mStr, len);
709 return new nsStringKey(str, mStrLen, OWN);
712 nsStringKey::nsStringKey(nsIObjectInputStream* aStream, nsresult *aResult)
713 : mStr(nsnull), mStrLen(0), mOwnership(OWN)
715 nsAutoString str;
716 nsresult rv = aStream->ReadString(str);
717 mStr = ToNewUnicode(str);
718 if (NS_SUCCEEDED(rv))
719 mStrLen = str.Length();
720 *aResult = rv;
721 MOZ_COUNT_CTOR(nsStringKey);
724 nsresult
725 nsStringKey::Write(nsIObjectOutputStream* aStream) const
727 return aStream->WriteWStringZ(mStr);
730 ////////////////////////////////////////////////////////////////////////////////
731 // nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
732 // deleted
734 nsObjectHashtable::nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun,
735 void* cloneElementClosure,
736 nsHashtableEnumFunc destroyElementFun,
737 void* destroyElementClosure,
738 PRUint32 aSize, PRBool threadSafe)
739 : nsHashtable(aSize, threadSafe),
740 mCloneElementFun(cloneElementFun),
741 mCloneElementClosure(cloneElementClosure),
742 mDestroyElementFun(destroyElementFun),
743 mDestroyElementClosure(destroyElementClosure)
747 nsObjectHashtable::~nsObjectHashtable()
749 Reset();
753 PLDHashOperator PR_CALLBACK
754 nsObjectHashtable::CopyElement(PLDHashTable* table,
755 PLDHashEntryHdr* hdr,
756 PRUint32 i, void *arg)
758 nsObjectHashtable *newHashtable = (nsObjectHashtable *)arg;
759 HTEntry *entry = static_cast<HTEntry*>(hdr);
761 void* newElement =
762 newHashtable->mCloneElementFun(entry->key, entry->value,
763 newHashtable->mCloneElementClosure);
764 if (newElement == nsnull)
765 return PL_DHASH_STOP;
766 newHashtable->Put(entry->key, newElement);
767 return PL_DHASH_NEXT;
770 nsHashtable*
771 nsObjectHashtable::Clone()
773 if (!mHashtable.ops) return nsnull;
775 PRBool threadSafe = PR_FALSE;
776 if (mLock)
777 threadSafe = PR_TRUE;
778 nsObjectHashtable* newHashTable =
779 new nsObjectHashtable(mCloneElementFun, mCloneElementClosure,
780 mDestroyElementFun, mDestroyElementClosure,
781 mHashtable.entryCount, threadSafe);
783 PL_DHashTableEnumerate(&mHashtable, CopyElement, newHashTable);
784 return newHashTable;
787 void
788 nsObjectHashtable::Reset()
790 nsHashtable::Reset(mDestroyElementFun, mDestroyElementClosure);
793 PRBool
794 nsObjectHashtable::RemoveAndDelete(nsHashKey *aKey)
796 void *value = Remove(aKey);
797 if (value && mDestroyElementFun)
798 return !!(*mDestroyElementFun)(aKey, value, mDestroyElementClosure);
799 return PR_FALSE;
802 ////////////////////////////////////////////////////////////////////////////////
803 // nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
805 PRBool PR_CALLBACK
806 nsSupportsHashtable::ReleaseElement(nsHashKey *aKey, void *aData, void* aClosure)
808 nsISupports* element = static_cast<nsISupports*>(aData);
809 NS_IF_RELEASE(element);
810 return PR_TRUE;
813 nsSupportsHashtable::~nsSupportsHashtable()
815 Enumerate(ReleaseElement, nsnull);
818 // Return true if we overwrote something
820 PRBool
821 nsSupportsHashtable::Put(nsHashKey *aKey, nsISupports* aData, nsISupports **value)
823 NS_IF_ADDREF(aData);
824 void *prev = nsHashtable::Put(aKey, aData);
825 nsISupports *old = reinterpret_cast<nsISupports *>(prev);
826 if (value) // pass own the ownership to the caller
827 *value = old;
828 else // the caller doesn't care, we do
829 NS_IF_RELEASE(old);
830 return prev != nsnull;
833 nsISupports *
834 nsSupportsHashtable::Get(nsHashKey *aKey)
836 void* data = nsHashtable::Get(aKey);
837 if (!data)
838 return nsnull;
839 nsISupports* element = reinterpret_cast<nsISupports*>(data);
840 NS_IF_ADDREF(element);
841 return element;
844 // Return true if we found something (useful for checks)
846 PRBool
847 nsSupportsHashtable::Remove(nsHashKey *aKey, nsISupports **value)
849 void* data = nsHashtable::Remove(aKey);
850 nsISupports* element = static_cast<nsISupports*>(data);
851 if (value) // caller wants it
852 *value = element;
853 else // caller doesn't care, we do
854 NS_IF_RELEASE(element);
855 return data != nsnull;
858 PLDHashOperator PR_CALLBACK
859 nsSupportsHashtable::EnumerateCopy(PLDHashTable*,
860 PLDHashEntryHdr* hdr,
861 PRUint32 i, void *arg)
863 nsHashtable *newHashtable = (nsHashtable *)arg;
864 HTEntry* entry = static_cast<HTEntry*>(hdr);
866 nsISupports* element = static_cast<nsISupports*>(entry->value);
867 NS_IF_ADDREF(element);
868 newHashtable->Put(entry->key, entry->value);
869 return PL_DHASH_NEXT;
872 nsHashtable*
873 nsSupportsHashtable::Clone()
875 if (!mHashtable.ops) return nsnull;
877 PRBool threadSafe = (mLock != nsnull);
878 nsSupportsHashtable* newHashTable =
879 new nsSupportsHashtable(mHashtable.entryCount, threadSafe);
881 PL_DHashTableEnumerate(&mHashtable, EnumerateCopy, newHashTable);
882 return newHashTable;
885 void
886 nsSupportsHashtable::Reset()
888 Enumerate(ReleaseElement, nsnull);
889 nsHashtable::Reset();
892 ////////////////////////////////////////////////////////////////////////////////