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
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.
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
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
52 #include "nsHashtable.h"
53 #include "nsReadableUtils.h"
54 #include "nsIObjectInputStream.h"
55 #include "nsIObjectOutputStream.h"
58 struct HTEntry
: PLDHashEntryHdr
68 PR_STATIC_CALLBACK(PRBool
)
69 matchKeyEntry(PLDHashTable
*, const PLDHashEntryHdr
* entry
,
72 const HTEntry
* hashEntry
=
73 static_cast<const HTEntry
*>(entry
);
75 if (hashEntry
->key
== key
)
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
103 static const PLDHashTableOps hashtableOps
= {
108 PL_DHashMoveEntryStub
,
110 PL_DHashFinalizeStub
,
116 // Enumerator callback
119 struct _HashEnumerateArgs
{
120 nsHashtableEnumFunc fn
;
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
;
143 nsHashKey::~nsHashKey(void)
145 MOZ_COUNT_DTOR(nsHashKey
);
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
167 mHashtable
.ops
= nsnull
;
170 mLock
= PR_NewLock();
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
);
183 PL_DHashTableFinish(&mHashtable
);
184 if (mLock
) PR_DestroyLock(mLock
);
187 PRBool
nsHashtable::Exists(nsHashKey
*aKey
)
189 if (mLock
) PR_Lock(mLock
);
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
);
204 void *nsHashtable::Put(nsHashKey
*aKey
, void *aData
)
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
);
216 static_cast<HTEntry
*>
217 (PL_DHashTableOperate(&mHashtable
, aKey
, PL_DHASH_ADD
));
219 if (entry
) { // don't return early, or you'll be locked!
221 // existing entry, need to boot the old value
223 entry
->value
= aData
;
225 // new entry (leave res == null)
226 entry
->key
= aKey
->Clone();
227 entry
->value
= aData
;
231 if (mLock
) PR_Unlock(mLock
);
236 void *nsHashtable::Get(nsHashKey
*aKey
)
238 if (!mHashtable
.ops
) return nsnull
;
240 if (mLock
) PR_Lock(mLock
);
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
);
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
265 static_cast<HTEntry
*>
266 (PL_DHashTableOperate(&mHashtable
, aKey
, PL_DHASH_LOOKUP
));
269 if (PL_DHASH_ENTRY_IS_FREE(entry
)) {
270 // value wasn't in the table anyway
274 PL_DHashTableRawRemove(&mHashtable
, entry
);
277 if (mLock
) PR_Unlock(mLock
);
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
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
);
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
;
326 return thunk
->fn(entry
->key
, entry
->value
, thunk
->arg
)
330 return PL_DHASH_REMOVE
;
333 void nsHashtable::Reset() {
337 void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc
, void* aClosure
)
339 if (!mHashtable
.ops
) return;
341 _HashEnumerateArgs thunk
, *thunkp
;
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
,
359 mEnumerating(PR_FALSE
)
361 MOZ_COUNT_CTOR(nsHashtable
);
364 nsresult rv
= aStream
->ReadBoolean(&threadSafe
);
365 if (NS_SUCCEEDED(rv
)) {
367 mLock
= PR_NewLock();
369 rv
= NS_ERROR_OUT_OF_MEMORY
;
372 if (NS_SUCCEEDED(rv
)) {
374 rv
= aStream
->Read32(&count
);
376 if (NS_SUCCEEDED(rv
)) {
378 PL_DHashTableInit(&mHashtable
, &hashtableOps
,
379 nsnull
, sizeof(HTEntry
), count
);
381 mHashtable
.ops
= nsnull
;
382 rv
= NS_ERROR_OUT_OF_MEMORY
;
384 for (PRUint32 i
= 0; i
< count
; i
++) {
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
);
394 // XXXbe must we clone key? can't we hand off
395 aFreeEntryFunc(aStream
, key
, nsnull
);
408 struct WriteEntryArgs
{
409 nsIObjectOutputStream
* mStream
;
410 nsHashtableWriteDataFunc mWriteDataFunc
;
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
);
429 nsHashtable::Write(nsIObjectOutputStream
* aStream
,
430 nsHashtableWriteDataFunc aWriteDataFunc
) const
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
);
449 ////////////////////////////////////////////////////////////////////////////////
451 nsISupportsKey::nsISupportsKey(nsIObjectInputStream
* aStream
, nsresult
*aResult
)
455 nsresult rv
= aStream
->ReadBoolean(&nonnull
);
456 if (NS_SUCCEEDED(rv
) && nonnull
)
457 rv
= aStream
->ReadObject(PR_TRUE
, &mKey
);
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
);
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 ////////////////////////////////////////////////////////////////////////////////
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)));
494 // Pray we don't dangle!
495 mOwnership
= NEVER_OWN
;
497 // Use memcpy in case there are embedded NULs.
498 memcpy(str
, mStr
, len
);
505 mKeyType
= CStringKey
;
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");
517 mKeyType
= CStringKey
;
519 MOZ_COUNT_CTOR(nsCStringKey
);
522 nsCStringKey::nsCStringKey(const nsACString
& str
)
523 : mStr(ToNewCString(str
)),
524 mStrLen(str
.Length()),
527 NS_ASSERTION(mStr
, "null string key");
529 mKeyType
= CStringKey
;
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
);
541 mKeyType
= CStringKey
;
543 MOZ_COUNT_CTOR(nsCStringKey
);
546 nsCStringKey::~nsCStringKey(void)
548 if (mOwnership
== OWN
)
549 nsMemory::Free(mStr
);
550 MOZ_COUNT_DTOR(nsCStringKey
);
554 nsCStringKey::HashCode(void) const
556 return nsCRT::HashCode(mStr
, (PRUint32
*)&mStrLen
);
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
)
568 return memcmp(mStr
, other
->mStr
, mStrLen
* sizeof(char)) == 0;
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));
585 memcpy(str
, mStr
, len
);
587 return new nsCStringKey(str
, mStrLen
, OWN
);
590 nsCStringKey::nsCStringKey(nsIObjectInputStream
* aStream
, nsresult
*aResult
)
591 : mStr(nsnull
), mStrLen(0), mOwnership(OWN
)
594 nsresult rv
= aStream
->ReadCString(str
);
595 mStr
= ToNewCString(str
);
596 if (NS_SUCCEEDED(rv
))
597 mStrLen
= str
.Length();
599 MOZ_COUNT_CTOR(nsCStringKey
);
603 nsCStringKey::Write(nsIObjectOutputStream
* aStream
) const
605 return aStream
->WriteStringZ(mStr
);
608 ////////////////////////////////////////////////////////////////////////////////
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
)));
621 // Pray we don't dangle!
622 mOwnership
= NEVER_OWN
;
624 // Use memcpy in case there are embedded NULs.
625 memcpy(str
, mStr
, len
);
632 mKeyType
= StringKey
;
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");
644 mKeyType
= StringKey
;
646 MOZ_COUNT_CTOR(nsStringKey
);
649 nsStringKey::nsStringKey(const nsAString
& str
)
650 : mStr(ToNewUnicode(str
)),
651 mStrLen(str
.Length()),
654 NS_ASSERTION(mStr
, "null string key");
656 mKeyType
= StringKey
;
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
);
668 mKeyType
= StringKey
;
670 MOZ_COUNT_CTOR(nsStringKey
);
673 nsStringKey::~nsStringKey(void)
675 if (mOwnership
== OWN
)
676 nsMemory::Free(mStr
);
677 MOZ_COUNT_DTOR(nsStringKey
);
681 nsStringKey::HashCode(void) const
683 return nsCRT::HashCode(mStr
, (PRUint32
*)&mStrLen
);
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
)
695 return memcmp(mStr
, other
->mStr
, mStrLen
* sizeof(PRUnichar
)) == 0;
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
);
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
)
716 nsresult rv
= aStream
->ReadString(str
);
717 mStr
= ToNewUnicode(str
);
718 if (NS_SUCCEEDED(rv
))
719 mStrLen
= str
.Length();
721 MOZ_COUNT_CTOR(nsStringKey
);
725 nsStringKey::Write(nsIObjectOutputStream
* aStream
) const
727 return aStream
->WriteWStringZ(mStr
);
730 ////////////////////////////////////////////////////////////////////////////////
731 // nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
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()
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
);
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
;
771 nsObjectHashtable::Clone()
773 if (!mHashtable
.ops
) return nsnull
;
775 PRBool threadSafe
= PR_FALSE
;
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
);
788 nsObjectHashtable::Reset()
790 nsHashtable::Reset(mDestroyElementFun
, mDestroyElementClosure
);
794 nsObjectHashtable::RemoveAndDelete(nsHashKey
*aKey
)
796 void *value
= Remove(aKey
);
797 if (value
&& mDestroyElementFun
)
798 return !!(*mDestroyElementFun
)(aKey
, value
, mDestroyElementClosure
);
802 ////////////////////////////////////////////////////////////////////////////////
803 // nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
806 nsSupportsHashtable::ReleaseElement(nsHashKey
*aKey
, void *aData
, void* aClosure
)
808 nsISupports
* element
= static_cast<nsISupports
*>(aData
);
809 NS_IF_RELEASE(element
);
813 nsSupportsHashtable::~nsSupportsHashtable()
815 Enumerate(ReleaseElement
, nsnull
);
818 // Return true if we overwrote something
821 nsSupportsHashtable::Put(nsHashKey
*aKey
, nsISupports
* aData
, nsISupports
**value
)
824 void *prev
= nsHashtable::Put(aKey
, aData
);
825 nsISupports
*old
= reinterpret_cast<nsISupports
*>(prev
);
826 if (value
) // pass own the ownership to the caller
828 else // the caller doesn't care, we do
830 return prev
!= nsnull
;
834 nsSupportsHashtable::Get(nsHashKey
*aKey
)
836 void* data
= nsHashtable::Get(aKey
);
839 nsISupports
* element
= reinterpret_cast<nsISupports
*>(data
);
840 NS_IF_ADDREF(element
);
844 // Return true if we found something (useful for checks)
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
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
;
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
);
886 nsSupportsHashtable::Reset()
888 Enumerate(ReleaseElement
, nsnull
);
889 nsHashtable::Reset();
892 ////////////////////////////////////////////////////////////////////////////////