1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 * This Original Code has been modified by IBM Corporation.
6 * Modifications made by IBM described herein are
7 * Copyright (c) International Business Machines
10 * Modifications to Mozilla code or documentation
11 * identified per MPL Section 3.3
13 * Date Modified by Description of modification
14 * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2
20 #include "nsHashtable.h"
21 #include "nsReadableUtils.h"
22 #include "nsIObjectInputStream.h"
23 #include "nsIObjectOutputStream.h"
25 #include "mozilla/HashFunctions.h"
27 using namespace mozilla
;
29 struct HTEntry
: PLDHashEntryHdr
40 matchKeyEntry(PLDHashTable
*, const PLDHashEntryHdr
* entry
,
43 const HTEntry
* hashEntry
=
44 static_cast<const HTEntry
*>(entry
);
46 if (hashEntry
->key
== key
)
49 const nsHashKey
* otherKey
= reinterpret_cast<const nsHashKey
*>(key
);
50 return otherKey
->Equals(hashEntry
->key
);
54 hashKey(PLDHashTable
* table
, const void* key
)
56 const nsHashKey
* hashKey
= static_cast<const nsHashKey
*>(key
);
58 return hashKey
->HashCode();
62 clearHashEntry(PLDHashTable
* table
, PLDHashEntryHdr
* entry
)
64 HTEntry
* hashEntry
= static_cast<HTEntry
*>(entry
);
66 // leave it up to the nsHashKey destructor to free the "value"
67 delete hashEntry
->key
;
68 hashEntry
->key
= nullptr;
69 hashEntry
->value
= nullptr; // probably not necessary, but for
74 static const PLDHashTableOps hashtableOps
= {
79 PL_DHashMoveEntryStub
,
87 // Enumerator callback
90 struct _HashEnumerateArgs
{
91 nsHashtableEnumFunc fn
;
95 static PLDHashOperator
96 hashEnumerate(PLDHashTable
* table
, PLDHashEntryHdr
* hdr
, uint32_t i
, void *arg
)
98 _HashEnumerateArgs
* thunk
= (_HashEnumerateArgs
*)arg
;
99 HTEntry
* entry
= static_cast<HTEntry
*>(hdr
);
101 if (thunk
->fn(entry
->key
, entry
->value
, thunk
->arg
))
102 return PL_DHASH_NEXT
;
103 return PL_DHASH_STOP
;
110 nsHashKey::~nsHashKey(void)
112 MOZ_COUNT_DTOR(nsHashKey
);
116 nsHashKey::Write(nsIObjectOutputStream
* aStream
) const
118 NS_NOTREACHED("oops");
119 return NS_ERROR_NOT_IMPLEMENTED
;
122 nsHashtable::nsHashtable(uint32_t aInitSize
, bool threadSafe
)
123 : mLock(NULL
), mEnumerating(false)
125 MOZ_COUNT_CTOR(nsHashtable
);
127 bool result
= PL_DHashTableInit(&mHashtable
, &hashtableOps
, nullptr,
128 sizeof(HTEntry
), aInitSize
);
130 NS_ASSERTION(result
, "Hashtable failed to initialize");
132 // make sure we detect this later
134 mHashtable
.ops
= nullptr;
137 mLock
= PR_NewLock();
139 // Cannot create a lock. If running on a multiprocessing system
140 // we are sure to die.
141 PR_ASSERT(mLock
!= NULL
);
147 nsHashtable::~nsHashtable() {
148 MOZ_COUNT_DTOR(nsHashtable
);
150 PL_DHashTableFinish(&mHashtable
);
151 if (mLock
) PR_DestroyLock(mLock
);
154 bool nsHashtable::Exists(nsHashKey
*aKey
)
156 if (mLock
) PR_Lock(mLock
);
158 if (!mHashtable
.ops
) {
159 if (mLock
) PR_Unlock(mLock
);
163 PLDHashEntryHdr
*entry
=
164 PL_DHashTableOperate(&mHashtable
, aKey
, PL_DHASH_LOOKUP
);
166 bool exists
= PL_DHASH_ENTRY_IS_BUSY(entry
);
168 if (mLock
) PR_Unlock(mLock
);
173 void *nsHashtable::Put(nsHashKey
*aKey
, void *aData
)
177 if (!mHashtable
.ops
) return nullptr;
179 if (mLock
) PR_Lock(mLock
);
181 // shouldn't be adding an item during enumeration
182 PR_ASSERT(!mEnumerating
);
185 static_cast<HTEntry
*>
186 (PL_DHashTableOperate(&mHashtable
, aKey
, PL_DHASH_ADD
));
188 if (entry
) { // don't return early, or you'll be locked!
190 // existing entry, need to boot the old value
192 entry
->value
= aData
;
194 // new entry (leave res == null)
195 entry
->key
= aKey
->Clone();
196 entry
->value
= aData
;
200 if (mLock
) PR_Unlock(mLock
);
205 void *nsHashtable::Get(nsHashKey
*aKey
)
207 if (!mHashtable
.ops
) return nullptr;
209 if (mLock
) PR_Lock(mLock
);
212 static_cast<HTEntry
*>
213 (PL_DHashTableOperate(&mHashtable
, aKey
, PL_DHASH_LOOKUP
));
214 void *ret
= PL_DHASH_ENTRY_IS_BUSY(entry
) ? entry
->value
: nullptr;
216 if (mLock
) PR_Unlock(mLock
);
221 void *nsHashtable::Remove(nsHashKey
*aKey
)
223 if (!mHashtable
.ops
) return nullptr;
225 if (mLock
) PR_Lock(mLock
);
227 // shouldn't be adding an item during enumeration
228 PR_ASSERT(!mEnumerating
);
231 // need to see if the entry is actually there, in order to get the
232 // old value for the result
234 static_cast<HTEntry
*>
235 (PL_DHashTableOperate(&mHashtable
, aKey
, PL_DHASH_LOOKUP
));
238 if (PL_DHASH_ENTRY_IS_FREE(entry
)) {
239 // value wasn't in the table anyway
243 PL_DHashTableRawRemove(&mHashtable
, entry
);
246 if (mLock
) PR_Unlock(mLock
);
251 // XXX This method was called _hashEnumerateCopy, but it didn't copy the element!
252 // I don't know how this was supposed to work since the elements are neither copied
254 static PLDHashOperator
255 hashEnumerateShare(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
256 uint32_t i
, void *arg
)
258 nsHashtable
*newHashtable
= (nsHashtable
*)arg
;
259 HTEntry
* entry
= static_cast<HTEntry
*>(hdr
);
261 newHashtable
->Put(entry
->key
, entry
->value
);
262 return PL_DHASH_NEXT
;
265 nsHashtable
* nsHashtable::Clone()
267 if (!mHashtable
.ops
) return nullptr;
269 bool threadSafe
= (mLock
!= nullptr);
270 nsHashtable
*newHashTable
= new nsHashtable(mHashtable
.entryCount
, threadSafe
);
272 PL_DHashTableEnumerate(&mHashtable
, hashEnumerateShare
, newHashTable
);
276 void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc
, void* aClosure
)
278 if (!mHashtable
.ops
) return;
280 bool wasEnumerating
= mEnumerating
;
282 _HashEnumerateArgs thunk
;
283 thunk
.fn
= aEnumFunc
;
284 thunk
.arg
= aClosure
;
285 PL_DHashTableEnumerate(&mHashtable
, hashEnumerate
, &thunk
);
286 mEnumerating
= wasEnumerating
;
289 static PLDHashOperator
290 hashEnumerateRemove(PLDHashTable
*, PLDHashEntryHdr
* hdr
, uint32_t i
, void *arg
)
292 HTEntry
* entry
= static_cast<HTEntry
*>(hdr
);
293 _HashEnumerateArgs
* thunk
= (_HashEnumerateArgs
*)arg
;
295 return thunk
->fn(entry
->key
, entry
->value
, thunk
->arg
)
299 return PL_DHASH_REMOVE
;
302 void nsHashtable::Reset() {
306 void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc
, void* aClosure
)
308 if (!mHashtable
.ops
) return;
310 _HashEnumerateArgs thunk
, *thunkp
;
315 thunk
.fn
= destroyFunc
;
316 thunk
.arg
= aClosure
;
318 PL_DHashTableEnumerate(&mHashtable
, hashEnumerateRemove
, thunkp
);
321 // nsISerializable helpers
323 nsHashtable::nsHashtable(nsIObjectInputStream
* aStream
,
324 nsHashtableReadEntryFunc aReadEntryFunc
,
325 nsHashtableFreeEntryFunc aFreeEntryFunc
,
330 MOZ_COUNT_CTOR(nsHashtable
);
333 nsresult rv
= aStream
->ReadBoolean(&threadSafe
);
334 if (NS_SUCCEEDED(rv
)) {
336 mLock
= PR_NewLock();
338 rv
= NS_ERROR_OUT_OF_MEMORY
;
341 if (NS_SUCCEEDED(rv
)) {
343 rv
= aStream
->Read32(&count
);
345 if (NS_SUCCEEDED(rv
)) {
347 PL_DHashTableInit(&mHashtable
, &hashtableOps
,
348 nullptr, sizeof(HTEntry
), count
);
350 mHashtable
.ops
= nullptr;
351 rv
= NS_ERROR_OUT_OF_MEMORY
;
353 for (uint32_t i
= 0; i
< count
; i
++) {
357 rv
= aReadEntryFunc(aStream
, &key
, &data
);
358 if (NS_SUCCEEDED(rv
)) {
361 // XXXbe must we clone key? can't we hand off
362 aFreeEntryFunc(aStream
, key
, nullptr);
372 struct WriteEntryArgs
{
373 nsIObjectOutputStream
* mStream
;
374 nsHashtableWriteDataFunc mWriteDataFunc
;
379 WriteEntry(nsHashKey
*aKey
, void *aData
, void* aClosure
)
381 WriteEntryArgs
* args
= (WriteEntryArgs
*) aClosure
;
382 nsIObjectOutputStream
* stream
= args
->mStream
;
384 nsresult rv
= aKey
->Write(stream
);
385 if (NS_SUCCEEDED(rv
))
386 rv
= args
->mWriteDataFunc(stream
, aData
);
393 nsHashtable::Write(nsIObjectOutputStream
* aStream
,
394 nsHashtableWriteDataFunc aWriteDataFunc
) const
397 return NS_ERROR_OUT_OF_MEMORY
;
398 bool threadSafe
= (mLock
!= nullptr);
399 nsresult rv
= aStream
->WriteBoolean(threadSafe
);
400 if (NS_FAILED(rv
)) return rv
;
402 // Write the entry count first, so we know how many key/value pairs to read.
403 uint32_t count
= mHashtable
.entryCount
;
404 rv
= aStream
->Write32(count
);
405 if (NS_FAILED(rv
)) return rv
;
407 // Write all key/value pairs in the table.
408 WriteEntryArgs args
= {aStream
, aWriteDataFunc
};
409 const_cast<nsHashtable
*>(this)->Enumerate(WriteEntry
, (void*) &args
);
413 ////////////////////////////////////////////////////////////////////////////////
415 nsISupportsKey::nsISupportsKey(nsIObjectInputStream
* aStream
, nsresult
*aResult
)
419 nsresult rv
= aStream
->ReadBoolean(&nonnull
);
420 if (NS_SUCCEEDED(rv
) && nonnull
)
421 rv
= aStream
->ReadObject(true, &mKey
);
426 nsISupportsKey::Write(nsIObjectOutputStream
* aStream
) const
428 bool nonnull
= (mKey
!= nullptr);
429 nsresult rv
= aStream
->WriteBoolean(nonnull
);
430 if (NS_SUCCEEDED(rv
) && nonnull
)
431 rv
= aStream
->WriteObject(mKey
, true);
436 // We need to free mStr if the object is passed with mOwnership as OWN. As the
437 // destructor here is freeing mStr in that case, mStr is NOT getting leaked here.
439 nsCStringKey::nsCStringKey(const nsCStringKey
& aKey
)
440 : mStr(aKey
.mStr
), mStrLen(aKey
.mStrLen
), mOwnership(aKey
.mOwnership
)
442 if (mOwnership
!= NEVER_OWN
) {
443 uint32_t len
= mStrLen
* sizeof(char);
444 char* str
= reinterpret_cast<char*>(nsMemory::Alloc(len
+ sizeof(char)));
446 // Pray we don't dangle!
447 mOwnership
= NEVER_OWN
;
449 // Use memcpy in case there are embedded NULs.
450 memcpy(str
, mStr
, len
);
457 mKeyType
= CStringKey
;
459 MOZ_COUNT_CTOR(nsCStringKey
);
462 nsCStringKey::nsCStringKey(const nsAFlatCString
& str
)
463 : mStr(const_cast<char*>(str
.get())),
464 mStrLen(str
.Length()),
465 mOwnership(OWN_CLONE
)
467 NS_ASSERTION(mStr
, "null string key");
469 mKeyType
= CStringKey
;
471 MOZ_COUNT_CTOR(nsCStringKey
);
474 nsCStringKey::nsCStringKey(const nsACString
& str
)
475 : mStr(ToNewCString(str
)),
476 mStrLen(str
.Length()),
479 NS_ASSERTION(mStr
, "null string key");
481 mKeyType
= CStringKey
;
483 MOZ_COUNT_CTOR(nsCStringKey
);
486 nsCStringKey::nsCStringKey(const char* str
, int32_t strLen
, Ownership own
)
487 : mStr((char*)str
), mStrLen(strLen
), mOwnership(own
)
489 NS_ASSERTION(mStr
, "null string key");
490 if (mStrLen
== uint32_t(-1))
491 mStrLen
= strlen(str
);
493 mKeyType
= CStringKey
;
495 MOZ_COUNT_CTOR(nsCStringKey
);
498 nsCStringKey::~nsCStringKey(void)
500 if (mOwnership
== OWN
)
501 nsMemory::Free(mStr
);
502 MOZ_COUNT_DTOR(nsCStringKey
);
506 nsCStringKey::HashCode(void) const
508 return HashString(mStr
, mStrLen
);
512 nsCStringKey::Equals(const nsHashKey
* aKey
) const
514 NS_ASSERTION(aKey
->GetKeyType() == CStringKey
, "mismatched key types");
515 nsCStringKey
* other
= (nsCStringKey
*)aKey
;
516 NS_ASSERTION(mStrLen
!= uint32_t(-1), "never called HashCode");
517 NS_ASSERTION(other
->mStrLen
!= uint32_t(-1), "never called HashCode");
518 if (mStrLen
!= other
->mStrLen
)
520 return memcmp(mStr
, other
->mStr
, mStrLen
* sizeof(char)) == 0;
524 nsCStringKey::Clone() const
526 if (mOwnership
== NEVER_OWN
)
527 return new nsCStringKey(mStr
, mStrLen
, NEVER_OWN
);
529 // Since this might hold binary data OR a string, we ensure that the
530 // clone string is zero terminated, but don't assume that the source
531 // string was so terminated.
533 uint32_t len
= mStrLen
* sizeof(char);
534 char* str
= (char*)nsMemory::Alloc(len
+ sizeof(char));
537 memcpy(str
, mStr
, len
);
539 return new nsCStringKey(str
, mStrLen
, OWN
);
542 nsCStringKey::nsCStringKey(nsIObjectInputStream
* aStream
, nsresult
*aResult
)
543 : mStr(nullptr), mStrLen(0), mOwnership(OWN
)
546 nsresult rv
= aStream
->ReadCString(str
);
547 mStr
= ToNewCString(str
);
548 if (NS_SUCCEEDED(rv
))
549 mStrLen
= str
.Length();
551 MOZ_COUNT_CTOR(nsCStringKey
);
555 nsCStringKey::Write(nsIObjectOutputStream
* aStream
) const
557 return aStream
->WriteStringZ(mStr
);
560 ////////////////////////////////////////////////////////////////////////////////
563 // We need to free mStr if the object is passed with mOwnership as OWN. As the
564 // destructor here is freeing mStr in that case, mStr is NOT getting leaked here.
566 nsStringKey::nsStringKey(const nsStringKey
& aKey
)
567 : mStr(aKey
.mStr
), mStrLen(aKey
.mStrLen
), mOwnership(aKey
.mOwnership
)
569 if (mOwnership
!= NEVER_OWN
) {
570 uint32_t len
= mStrLen
* sizeof(PRUnichar
);
571 PRUnichar
* str
= reinterpret_cast<PRUnichar
*>(nsMemory::Alloc(len
+ sizeof(PRUnichar
)));
573 // Pray we don't dangle!
574 mOwnership
= NEVER_OWN
;
576 // Use memcpy in case there are embedded NULs.
577 memcpy(str
, mStr
, len
);
584 mKeyType
= StringKey
;
586 MOZ_COUNT_CTOR(nsStringKey
);
589 nsStringKey::nsStringKey(const nsAFlatString
& str
)
590 : mStr(const_cast<PRUnichar
*>(str
.get())),
591 mStrLen(str
.Length()),
592 mOwnership(OWN_CLONE
)
594 NS_ASSERTION(mStr
, "null string key");
596 mKeyType
= StringKey
;
598 MOZ_COUNT_CTOR(nsStringKey
);
601 nsStringKey::nsStringKey(const nsAString
& str
)
602 : mStr(ToNewUnicode(str
)),
603 mStrLen(str
.Length()),
606 NS_ASSERTION(mStr
, "null string key");
608 mKeyType
= StringKey
;
610 MOZ_COUNT_CTOR(nsStringKey
);
613 nsStringKey::nsStringKey(const PRUnichar
* str
, int32_t strLen
, Ownership own
)
614 : mStr((PRUnichar
*)str
), mStrLen(strLen
), mOwnership(own
)
616 NS_ASSERTION(mStr
, "null string key");
617 if (mStrLen
== uint32_t(-1))
618 mStrLen
= NS_strlen(str
);
620 mKeyType
= StringKey
;
622 MOZ_COUNT_CTOR(nsStringKey
);
625 nsStringKey::~nsStringKey(void)
627 if (mOwnership
== OWN
)
628 nsMemory::Free(mStr
);
629 MOZ_COUNT_DTOR(nsStringKey
);
633 nsStringKey::HashCode(void) const
635 return HashString(mStr
, mStrLen
);
639 nsStringKey::Equals(const nsHashKey
* aKey
) const
641 NS_ASSERTION(aKey
->GetKeyType() == StringKey
, "mismatched key types");
642 nsStringKey
* other
= (nsStringKey
*)aKey
;
643 NS_ASSERTION(mStrLen
!= uint32_t(-1), "never called HashCode");
644 NS_ASSERTION(other
->mStrLen
!= uint32_t(-1), "never called HashCode");
645 if (mStrLen
!= other
->mStrLen
)
647 return memcmp(mStr
, other
->mStr
, mStrLen
* sizeof(PRUnichar
)) == 0;
651 nsStringKey::Clone() const
653 if (mOwnership
== NEVER_OWN
)
654 return new nsStringKey(mStr
, mStrLen
, NEVER_OWN
);
656 uint32_t len
= (mStrLen
+1) * sizeof(PRUnichar
);
657 PRUnichar
* str
= (PRUnichar
*)nsMemory::Alloc(len
);
660 memcpy(str
, mStr
, len
);
661 return new nsStringKey(str
, mStrLen
, OWN
);
664 nsStringKey::nsStringKey(nsIObjectInputStream
* aStream
, nsresult
*aResult
)
665 : mStr(nullptr), mStrLen(0), mOwnership(OWN
)
668 nsresult rv
= aStream
->ReadString(str
);
669 mStr
= ToNewUnicode(str
);
670 if (NS_SUCCEEDED(rv
))
671 mStrLen
= str
.Length();
673 MOZ_COUNT_CTOR(nsStringKey
);
677 nsStringKey::Write(nsIObjectOutputStream
* aStream
) const
679 return aStream
->WriteWStringZ(mStr
);
682 ////////////////////////////////////////////////////////////////////////////////
683 // nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
686 nsObjectHashtable::nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun
,
687 void* cloneElementClosure
,
688 nsHashtableEnumFunc destroyElementFun
,
689 void* destroyElementClosure
,
690 uint32_t aSize
, bool threadSafe
)
691 : nsHashtable(aSize
, threadSafe
),
692 mCloneElementFun(cloneElementFun
),
693 mCloneElementClosure(cloneElementClosure
),
694 mDestroyElementFun(destroyElementFun
),
695 mDestroyElementClosure(destroyElementClosure
)
699 nsObjectHashtable::~nsObjectHashtable()
706 nsObjectHashtable::CopyElement(PLDHashTable
* table
,
707 PLDHashEntryHdr
* hdr
,
708 uint32_t i
, void *arg
)
710 nsObjectHashtable
*newHashtable
= (nsObjectHashtable
*)arg
;
711 HTEntry
*entry
= static_cast<HTEntry
*>(hdr
);
714 newHashtable
->mCloneElementFun(entry
->key
, entry
->value
,
715 newHashtable
->mCloneElementClosure
);
716 if (newElement
== nullptr)
717 return PL_DHASH_STOP
;
718 newHashtable
->Put(entry
->key
, newElement
);
719 return PL_DHASH_NEXT
;
723 nsObjectHashtable::Clone()
725 if (!mHashtable
.ops
) return nullptr;
727 bool threadSafe
= false;
730 nsObjectHashtable
* newHashTable
=
731 new nsObjectHashtable(mCloneElementFun
, mCloneElementClosure
,
732 mDestroyElementFun
, mDestroyElementClosure
,
733 mHashtable
.entryCount
, threadSafe
);
735 PL_DHashTableEnumerate(&mHashtable
, CopyElement
, newHashTable
);
740 nsObjectHashtable::Reset()
742 nsHashtable::Reset(mDestroyElementFun
, mDestroyElementClosure
);
746 nsObjectHashtable::RemoveAndDelete(nsHashKey
*aKey
)
748 void *value
= Remove(aKey
);
749 if (value
&& mDestroyElementFun
)
750 return !!(*mDestroyElementFun
)(aKey
, value
, mDestroyElementClosure
);
754 ////////////////////////////////////////////////////////////////////////////////
755 // nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
758 nsSupportsHashtable::ReleaseElement(nsHashKey
*aKey
, void *aData
, void* aClosure
)
760 nsISupports
* element
= static_cast<nsISupports
*>(aData
);
761 NS_IF_RELEASE(element
);
765 nsSupportsHashtable::~nsSupportsHashtable()
767 Enumerate(ReleaseElement
, nullptr);
770 // Return true if we overwrote something
773 nsSupportsHashtable::Put(nsHashKey
*aKey
, nsISupports
* aData
, nsISupports
**value
)
776 void *prev
= nsHashtable::Put(aKey
, aData
);
777 nsISupports
*old
= reinterpret_cast<nsISupports
*>(prev
);
778 if (value
) // pass own the ownership to the caller
780 else // the caller doesn't care, we do
782 return prev
!= nullptr;
786 nsSupportsHashtable::Get(nsHashKey
*aKey
)
788 void* data
= nsHashtable::Get(aKey
);
791 nsISupports
* element
= reinterpret_cast<nsISupports
*>(data
);
792 NS_IF_ADDREF(element
);
796 // Return true if we found something (useful for checks)
799 nsSupportsHashtable::Remove(nsHashKey
*aKey
, nsISupports
**value
)
801 void* data
= nsHashtable::Remove(aKey
);
802 nsISupports
* element
= static_cast<nsISupports
*>(data
);
803 if (value
) // caller wants it
805 else // caller doesn't care, we do
806 NS_IF_RELEASE(element
);
807 return data
!= nullptr;
811 nsSupportsHashtable::EnumerateCopy(PLDHashTable
*,
812 PLDHashEntryHdr
* hdr
,
813 uint32_t i
, void *arg
)
815 nsHashtable
*newHashtable
= (nsHashtable
*)arg
;
816 HTEntry
* entry
= static_cast<HTEntry
*>(hdr
);
818 nsISupports
* element
= static_cast<nsISupports
*>(entry
->value
);
819 NS_IF_ADDREF(element
);
820 newHashtable
->Put(entry
->key
, entry
->value
);
821 return PL_DHASH_NEXT
;
825 nsSupportsHashtable::Clone()
827 if (!mHashtable
.ops
) return nullptr;
829 bool threadSafe
= (mLock
!= nullptr);
830 nsSupportsHashtable
* newHashTable
=
831 new nsSupportsHashtable(mHashtable
.entryCount
, threadSafe
);
833 PL_DHashTableEnumerate(&mHashtable
, EnumerateCopy
, newHashTable
);
838 nsSupportsHashtable::Reset()
840 Enumerate(ReleaseElement
, nullptr);
841 nsHashtable::Reset();
844 ////////////////////////////////////////////////////////////////////////////////