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 "nsIObjectInputStream.h"
22 #include "nsIObjectOutputStream.h"
23 #include "nsCRTGlue.h"
24 #include "mozilla/HashFunctions.h"
26 using namespace mozilla
;
28 struct HTEntry
: PLDHashEntryHdr
39 matchKeyEntry(PLDHashTable
*, const PLDHashEntryHdr
* entry
,
42 const HTEntry
* hashEntry
=
43 static_cast<const HTEntry
*>(entry
);
45 if (hashEntry
->key
== key
)
48 const nsHashKey
* otherKey
= reinterpret_cast<const nsHashKey
*>(key
);
49 return otherKey
->Equals(hashEntry
->key
);
53 hashKey(PLDHashTable
* table
, const void* key
)
55 const nsHashKey
* hashKey
= static_cast<const nsHashKey
*>(key
);
57 return hashKey
->HashCode();
61 clearHashEntry(PLDHashTable
* table
, PLDHashEntryHdr
* entry
)
63 HTEntry
* hashEntry
= static_cast<HTEntry
*>(entry
);
65 // leave it up to the nsHashKey destructor to free the "value"
66 delete hashEntry
->key
;
67 hashEntry
->key
= nullptr;
68 hashEntry
->value
= nullptr; // probably not necessary, but for
73 static const PLDHashTableOps hashtableOps
= {
78 PL_DHashMoveEntryStub
,
86 // Enumerator callback
89 struct _HashEnumerateArgs
{
90 nsHashtableEnumFunc fn
;
94 static PLDHashOperator
95 hashEnumerate(PLDHashTable
* table
, PLDHashEntryHdr
* hdr
, uint32_t i
, void *arg
)
97 _HashEnumerateArgs
* thunk
= (_HashEnumerateArgs
*)arg
;
98 HTEntry
* entry
= static_cast<HTEntry
*>(hdr
);
100 if (thunk
->fn(entry
->key
, entry
->value
, thunk
->arg
))
101 return PL_DHASH_NEXT
;
102 return PL_DHASH_STOP
;
109 nsHashKey::~nsHashKey(void)
111 MOZ_COUNT_DTOR(nsHashKey
);
115 nsHashKey::Write(nsIObjectOutputStream
* aStream
) const
117 NS_NOTREACHED("oops");
118 return NS_ERROR_NOT_IMPLEMENTED
;
121 nsHashtable::nsHashtable(uint32_t aInitSize
, bool threadSafe
)
122 : mLock(nullptr), mEnumerating(false)
124 MOZ_COUNT_CTOR(nsHashtable
);
126 bool result
= PL_DHashTableInit(&mHashtable
, &hashtableOps
, nullptr,
127 sizeof(HTEntry
), aInitSize
);
129 NS_ASSERTION(result
, "Hashtable failed to initialize");
131 // make sure we detect this later
133 mHashtable
.ops
= nullptr;
136 mLock
= PR_NewLock();
137 if (mLock
== nullptr) {
138 // Cannot create a lock. If running on a multiprocessing system
139 // we are sure to die.
140 PR_ASSERT(mLock
!= nullptr);
146 nsHashtable::~nsHashtable() {
147 MOZ_COUNT_DTOR(nsHashtable
);
149 PL_DHashTableFinish(&mHashtable
);
150 if (mLock
) PR_DestroyLock(mLock
);
153 bool nsHashtable::Exists(nsHashKey
*aKey
)
155 if (mLock
) PR_Lock(mLock
);
157 if (!mHashtable
.ops
) {
158 if (mLock
) PR_Unlock(mLock
);
162 PLDHashEntryHdr
*entry
=
163 PL_DHashTableOperate(&mHashtable
, aKey
, PL_DHASH_LOOKUP
);
165 bool exists
= PL_DHASH_ENTRY_IS_BUSY(entry
);
167 if (mLock
) PR_Unlock(mLock
);
172 void *nsHashtable::Put(nsHashKey
*aKey
, void *aData
)
176 if (!mHashtable
.ops
) return nullptr;
178 if (mLock
) PR_Lock(mLock
);
180 // shouldn't be adding an item during enumeration
181 PR_ASSERT(!mEnumerating
);
184 static_cast<HTEntry
*>
185 (PL_DHashTableOperate(&mHashtable
, aKey
, PL_DHASH_ADD
));
187 if (entry
) { // don't return early, or you'll be locked!
189 // existing entry, need to boot the old value
191 entry
->value
= aData
;
193 // new entry (leave res == null)
194 entry
->key
= aKey
->Clone();
195 entry
->value
= aData
;
199 if (mLock
) PR_Unlock(mLock
);
204 void *nsHashtable::Get(nsHashKey
*aKey
)
206 if (!mHashtable
.ops
) return nullptr;
208 if (mLock
) PR_Lock(mLock
);
211 static_cast<HTEntry
*>
212 (PL_DHashTableOperate(&mHashtable
, aKey
, PL_DHASH_LOOKUP
));
213 void *ret
= PL_DHASH_ENTRY_IS_BUSY(entry
) ? entry
->value
: nullptr;
215 if (mLock
) PR_Unlock(mLock
);
220 void *nsHashtable::Remove(nsHashKey
*aKey
)
222 if (!mHashtable
.ops
) return nullptr;
224 if (mLock
) PR_Lock(mLock
);
226 // shouldn't be adding an item during enumeration
227 PR_ASSERT(!mEnumerating
);
230 // need to see if the entry is actually there, in order to get the
231 // old value for the result
233 static_cast<HTEntry
*>
234 (PL_DHashTableOperate(&mHashtable
, aKey
, PL_DHASH_LOOKUP
));
237 if (PL_DHASH_ENTRY_IS_FREE(entry
)) {
238 // value wasn't in the table anyway
242 PL_DHashTableRawRemove(&mHashtable
, entry
);
245 if (mLock
) PR_Unlock(mLock
);
250 // XXX This method was called _hashEnumerateCopy, but it didn't copy the element!
251 // I don't know how this was supposed to work since the elements are neither copied
253 static PLDHashOperator
254 hashEnumerateShare(PLDHashTable
*table
, PLDHashEntryHdr
*hdr
,
255 uint32_t i
, void *arg
)
257 nsHashtable
*newHashtable
= (nsHashtable
*)arg
;
258 HTEntry
* entry
= static_cast<HTEntry
*>(hdr
);
260 newHashtable
->Put(entry
->key
, entry
->value
);
261 return PL_DHASH_NEXT
;
264 nsHashtable
* nsHashtable::Clone()
266 if (!mHashtable
.ops
) return nullptr;
268 bool threadSafe
= (mLock
!= nullptr);
269 nsHashtable
*newHashTable
= new nsHashtable(mHashtable
.entryCount
, threadSafe
);
271 PL_DHashTableEnumerate(&mHashtable
, hashEnumerateShare
, newHashTable
);
275 void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc
, void* aClosure
)
277 if (!mHashtable
.ops
) return;
279 bool wasEnumerating
= mEnumerating
;
281 _HashEnumerateArgs thunk
;
282 thunk
.fn
= aEnumFunc
;
283 thunk
.arg
= aClosure
;
284 PL_DHashTableEnumerate(&mHashtable
, hashEnumerate
, &thunk
);
285 mEnumerating
= wasEnumerating
;
288 static PLDHashOperator
289 hashEnumerateRemove(PLDHashTable
*, PLDHashEntryHdr
* hdr
, uint32_t i
, void *arg
)
291 HTEntry
* entry
= static_cast<HTEntry
*>(hdr
);
292 _HashEnumerateArgs
* thunk
= (_HashEnumerateArgs
*)arg
;
294 return thunk
->fn(entry
->key
, entry
->value
, thunk
->arg
)
298 return PL_DHASH_REMOVE
;
301 void nsHashtable::Reset() {
305 void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc
, void* aClosure
)
307 if (!mHashtable
.ops
) return;
309 _HashEnumerateArgs thunk
, *thunkp
;
314 thunk
.fn
= destroyFunc
;
315 thunk
.arg
= aClosure
;
317 PL_DHashTableEnumerate(&mHashtable
, hashEnumerateRemove
, thunkp
);
320 // nsISerializable helpers
322 nsHashtable::nsHashtable(nsIObjectInputStream
* aStream
,
323 nsHashtableReadEntryFunc aReadEntryFunc
,
324 nsHashtableFreeEntryFunc aFreeEntryFunc
,
329 MOZ_COUNT_CTOR(nsHashtable
);
332 nsresult rv
= aStream
->ReadBoolean(&threadSafe
);
333 if (NS_SUCCEEDED(rv
)) {
335 mLock
= PR_NewLock();
337 rv
= NS_ERROR_OUT_OF_MEMORY
;
340 if (NS_SUCCEEDED(rv
)) {
342 rv
= aStream
->Read32(&count
);
344 if (NS_SUCCEEDED(rv
)) {
346 PL_DHashTableInit(&mHashtable
, &hashtableOps
,
347 nullptr, sizeof(HTEntry
), count
);
349 mHashtable
.ops
= nullptr;
350 rv
= NS_ERROR_OUT_OF_MEMORY
;
352 for (uint32_t i
= 0; i
< count
; i
++) {
356 rv
= aReadEntryFunc(aStream
, &key
, &data
);
357 if (NS_SUCCEEDED(rv
)) {
360 // XXXbe must we clone key? can't we hand off
361 aFreeEntryFunc(aStream
, key
, nullptr);
371 struct WriteEntryArgs
{
372 nsIObjectOutputStream
* mStream
;
373 nsHashtableWriteDataFunc mWriteDataFunc
;
378 WriteEntry(nsHashKey
*aKey
, void *aData
, void* aClosure
)
380 WriteEntryArgs
* args
= (WriteEntryArgs
*) aClosure
;
381 nsIObjectOutputStream
* stream
= args
->mStream
;
383 nsresult rv
= aKey
->Write(stream
);
384 if (NS_SUCCEEDED(rv
))
385 rv
= args
->mWriteDataFunc(stream
, aData
);
392 nsHashtable::Write(nsIObjectOutputStream
* aStream
,
393 nsHashtableWriteDataFunc aWriteDataFunc
) const
396 return NS_ERROR_OUT_OF_MEMORY
;
397 bool threadSafe
= (mLock
!= nullptr);
398 nsresult rv
= aStream
->WriteBoolean(threadSafe
);
399 if (NS_FAILED(rv
)) return rv
;
401 // Write the entry count first, so we know how many key/value pairs to read.
402 uint32_t count
= mHashtable
.entryCount
;
403 rv
= aStream
->Write32(count
);
404 if (NS_FAILED(rv
)) return rv
;
406 // Write all key/value pairs in the table.
407 WriteEntryArgs args
= {aStream
, aWriteDataFunc
};
408 const_cast<nsHashtable
*>(this)->Enumerate(WriteEntry
, (void*) &args
);
412 ////////////////////////////////////////////////////////////////////////////////
414 nsISupportsKey::nsISupportsKey(nsIObjectInputStream
* aStream
, nsresult
*aResult
)
418 nsresult rv
= aStream
->ReadBoolean(&nonnull
);
419 if (NS_SUCCEEDED(rv
) && nonnull
)
420 rv
= aStream
->ReadObject(true, &mKey
);
425 nsISupportsKey::Write(nsIObjectOutputStream
* aStream
) const
427 bool nonnull
= (mKey
!= nullptr);
428 nsresult rv
= aStream
->WriteBoolean(nonnull
);
429 if (NS_SUCCEEDED(rv
) && nonnull
)
430 rv
= aStream
->WriteObject(mKey
, true);
435 // We need to free mStr if the object is passed with mOwnership as OWN. As the
436 // destructor here is freeing mStr in that case, mStr is NOT getting leaked here.
438 nsCStringKey::nsCStringKey(const nsCStringKey
& aKey
)
439 : mStr(aKey
.mStr
), mStrLen(aKey
.mStrLen
), mOwnership(aKey
.mOwnership
)
441 if (mOwnership
!= NEVER_OWN
) {
442 uint32_t len
= mStrLen
* sizeof(char);
443 char* str
= reinterpret_cast<char*>(nsMemory::Alloc(len
+ sizeof(char)));
445 // Pray we don't dangle!
446 mOwnership
= NEVER_OWN
;
448 // Use memcpy in case there are embedded NULs.
449 memcpy(str
, mStr
, len
);
456 mKeyType
= CStringKey
;
458 MOZ_COUNT_CTOR(nsCStringKey
);
461 nsCStringKey::nsCStringKey(const nsAFlatCString
& str
)
462 : mStr(const_cast<char*>(str
.get())),
463 mStrLen(str
.Length()),
464 mOwnership(OWN_CLONE
)
466 NS_ASSERTION(mStr
, "null string key");
468 mKeyType
= CStringKey
;
470 MOZ_COUNT_CTOR(nsCStringKey
);
473 nsCStringKey::nsCStringKey(const nsACString
& str
)
474 : mStr(ToNewCString(str
)),
475 mStrLen(str
.Length()),
478 NS_ASSERTION(mStr
, "null string key");
480 mKeyType
= CStringKey
;
482 MOZ_COUNT_CTOR(nsCStringKey
);
485 nsCStringKey::nsCStringKey(const char* str
, int32_t strLen
, Ownership own
)
486 : mStr((char*)str
), mStrLen(strLen
), mOwnership(own
)
488 NS_ASSERTION(mStr
, "null string key");
489 if (mStrLen
== uint32_t(-1))
490 mStrLen
= strlen(str
);
492 mKeyType
= CStringKey
;
494 MOZ_COUNT_CTOR(nsCStringKey
);
497 nsCStringKey::~nsCStringKey(void)
499 if (mOwnership
== OWN
)
500 nsMemory::Free(mStr
);
501 MOZ_COUNT_DTOR(nsCStringKey
);
505 nsCStringKey::HashCode(void) const
507 return HashString(mStr
, mStrLen
);
511 nsCStringKey::Equals(const nsHashKey
* aKey
) const
513 NS_ASSERTION(aKey
->GetKeyType() == CStringKey
, "mismatched key types");
514 nsCStringKey
* other
= (nsCStringKey
*)aKey
;
515 NS_ASSERTION(mStrLen
!= uint32_t(-1), "never called HashCode");
516 NS_ASSERTION(other
->mStrLen
!= uint32_t(-1), "never called HashCode");
517 if (mStrLen
!= other
->mStrLen
)
519 return memcmp(mStr
, other
->mStr
, mStrLen
* sizeof(char)) == 0;
523 nsCStringKey::Clone() const
525 if (mOwnership
== NEVER_OWN
)
526 return new nsCStringKey(mStr
, mStrLen
, NEVER_OWN
);
528 // Since this might hold binary data OR a string, we ensure that the
529 // clone string is zero terminated, but don't assume that the source
530 // string was so terminated.
532 uint32_t len
= mStrLen
* sizeof(char);
533 char* str
= (char*)nsMemory::Alloc(len
+ sizeof(char));
536 memcpy(str
, mStr
, len
);
538 return new nsCStringKey(str
, mStrLen
, OWN
);
541 nsCStringKey::nsCStringKey(nsIObjectInputStream
* aStream
, nsresult
*aResult
)
542 : mStr(nullptr), mStrLen(0), mOwnership(OWN
)
545 nsresult rv
= aStream
->ReadCString(str
);
546 mStr
= ToNewCString(str
);
547 if (NS_SUCCEEDED(rv
))
548 mStrLen
= str
.Length();
550 MOZ_COUNT_CTOR(nsCStringKey
);
554 nsCStringKey::Write(nsIObjectOutputStream
* aStream
) const
556 return aStream
->WriteStringZ(mStr
);
559 ////////////////////////////////////////////////////////////////////////////////
562 // We need to free mStr if the object is passed with mOwnership as OWN. As the
563 // destructor here is freeing mStr in that case, mStr is NOT getting leaked here.
565 nsStringKey::nsStringKey(const nsStringKey
& aKey
)
566 : mStr(aKey
.mStr
), mStrLen(aKey
.mStrLen
), mOwnership(aKey
.mOwnership
)
568 if (mOwnership
!= NEVER_OWN
) {
569 uint32_t len
= mStrLen
* sizeof(char16_t
);
570 char16_t
* str
= reinterpret_cast<char16_t
*>(nsMemory::Alloc(len
+ sizeof(char16_t
)));
572 // Pray we don't dangle!
573 mOwnership
= NEVER_OWN
;
575 // Use memcpy in case there are embedded NULs.
576 memcpy(str
, mStr
, len
);
583 mKeyType
= StringKey
;
585 MOZ_COUNT_CTOR(nsStringKey
);
588 nsStringKey::nsStringKey(const nsAFlatString
& str
)
589 : mStr((char16_t
*)str
.get()),
590 mStrLen(str
.Length()),
591 mOwnership(OWN_CLONE
)
593 NS_ASSERTION(mStr
, "null string key");
595 mKeyType
= StringKey
;
597 MOZ_COUNT_CTOR(nsStringKey
);
600 nsStringKey::nsStringKey(const nsAString
& str
)
601 : mStr(ToNewUnicode(str
)),
602 mStrLen(str
.Length()),
605 NS_ASSERTION(mStr
, "null string key");
607 mKeyType
= StringKey
;
609 MOZ_COUNT_CTOR(nsStringKey
);
612 nsStringKey::nsStringKey(const char16_t
* str
, int32_t strLen
, Ownership own
)
613 : mStr((char16_t
*)str
), mStrLen(strLen
), mOwnership(own
)
615 NS_ASSERTION(mStr
, "null string key");
616 if (mStrLen
== uint32_t(-1))
617 mStrLen
= NS_strlen(str
);
619 mKeyType
= StringKey
;
621 MOZ_COUNT_CTOR(nsStringKey
);
624 nsStringKey::~nsStringKey(void)
626 if (mOwnership
== OWN
)
627 nsMemory::Free(mStr
);
628 MOZ_COUNT_DTOR(nsStringKey
);
632 nsStringKey::HashCode(void) const
634 return HashString(mStr
, mStrLen
);
638 nsStringKey::Equals(const nsHashKey
* aKey
) const
640 NS_ASSERTION(aKey
->GetKeyType() == StringKey
, "mismatched key types");
641 nsStringKey
* other
= (nsStringKey
*)aKey
;
642 NS_ASSERTION(mStrLen
!= uint32_t(-1), "never called HashCode");
643 NS_ASSERTION(other
->mStrLen
!= uint32_t(-1), "never called HashCode");
644 if (mStrLen
!= other
->mStrLen
)
646 return memcmp(mStr
, other
->mStr
, mStrLen
* sizeof(char16_t
)) == 0;
650 nsStringKey::Clone() const
652 if (mOwnership
== NEVER_OWN
)
653 return new nsStringKey(mStr
, mStrLen
, NEVER_OWN
);
655 uint32_t len
= (mStrLen
+1) * sizeof(char16_t
);
656 char16_t
* str
= (char16_t
*)nsMemory::Alloc(len
);
659 memcpy(str
, mStr
, len
);
660 return new nsStringKey(str
, mStrLen
, OWN
);
663 nsStringKey::nsStringKey(nsIObjectInputStream
* aStream
, nsresult
*aResult
)
664 : mStr(nullptr), mStrLen(0), mOwnership(OWN
)
667 nsresult rv
= aStream
->ReadString(str
);
668 mStr
= ToNewUnicode(str
);
669 if (NS_SUCCEEDED(rv
))
670 mStrLen
= str
.Length();
672 MOZ_COUNT_CTOR(nsStringKey
);
676 nsStringKey::Write(nsIObjectOutputStream
* aStream
) const
678 return aStream
->WriteWStringZ(mStr
);
681 ////////////////////////////////////////////////////////////////////////////////
682 // nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
685 nsObjectHashtable::nsObjectHashtable(nsHashtableCloneElementFunc cloneElementFun
,
686 void* cloneElementClosure
,
687 nsHashtableEnumFunc destroyElementFun
,
688 void* destroyElementClosure
,
689 uint32_t aSize
, bool threadSafe
)
690 : nsHashtable(aSize
, threadSafe
),
691 mCloneElementFun(cloneElementFun
),
692 mCloneElementClosure(cloneElementClosure
),
693 mDestroyElementFun(destroyElementFun
),
694 mDestroyElementClosure(destroyElementClosure
)
698 nsObjectHashtable::~nsObjectHashtable()
705 nsObjectHashtable::CopyElement(PLDHashTable
* table
,
706 PLDHashEntryHdr
* hdr
,
707 uint32_t i
, void *arg
)
709 nsObjectHashtable
*newHashtable
= (nsObjectHashtable
*)arg
;
710 HTEntry
*entry
= static_cast<HTEntry
*>(hdr
);
713 newHashtable
->mCloneElementFun(entry
->key
, entry
->value
,
714 newHashtable
->mCloneElementClosure
);
715 if (newElement
== nullptr)
716 return PL_DHASH_STOP
;
717 newHashtable
->Put(entry
->key
, newElement
);
718 return PL_DHASH_NEXT
;
722 nsObjectHashtable::Clone()
724 if (!mHashtable
.ops
) return nullptr;
726 bool threadSafe
= false;
729 nsObjectHashtable
* newHashTable
=
730 new nsObjectHashtable(mCloneElementFun
, mCloneElementClosure
,
731 mDestroyElementFun
, mDestroyElementClosure
,
732 mHashtable
.entryCount
, threadSafe
);
734 PL_DHashTableEnumerate(&mHashtable
, CopyElement
, newHashTable
);
739 nsObjectHashtable::Reset()
741 nsHashtable::Reset(mDestroyElementFun
, mDestroyElementClosure
);
745 nsObjectHashtable::RemoveAndDelete(nsHashKey
*aKey
)
747 void *value
= Remove(aKey
);
748 if (value
&& mDestroyElementFun
)
749 return !!(*mDestroyElementFun
)(aKey
, value
, mDestroyElementClosure
);
753 ////////////////////////////////////////////////////////////////////////////////
754 // nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
757 nsSupportsHashtable::ReleaseElement(nsHashKey
*aKey
, void *aData
, void* aClosure
)
759 nsISupports
* element
= static_cast<nsISupports
*>(aData
);
760 NS_IF_RELEASE(element
);
764 nsSupportsHashtable::~nsSupportsHashtable()
766 Enumerate(ReleaseElement
, nullptr);
769 // Return true if we overwrote something
772 nsSupportsHashtable::Put(nsHashKey
*aKey
, nsISupports
* aData
, nsISupports
**value
)
775 void *prev
= nsHashtable::Put(aKey
, aData
);
776 nsISupports
*old
= reinterpret_cast<nsISupports
*>(prev
);
777 if (value
) // pass own the ownership to the caller
779 else // the caller doesn't care, we do
781 return prev
!= nullptr;
785 nsSupportsHashtable::Get(nsHashKey
*aKey
)
787 void* data
= nsHashtable::Get(aKey
);
790 nsISupports
* element
= reinterpret_cast<nsISupports
*>(data
);
791 NS_IF_ADDREF(element
);
795 // Return true if we found something (useful for checks)
798 nsSupportsHashtable::Remove(nsHashKey
*aKey
, nsISupports
**value
)
800 void* data
= nsHashtable::Remove(aKey
);
801 nsISupports
* element
= static_cast<nsISupports
*>(data
);
802 if (value
) // caller wants it
804 else // caller doesn't care, we do
805 NS_IF_RELEASE(element
);
806 return data
!= nullptr;
810 nsSupportsHashtable::EnumerateCopy(PLDHashTable
*,
811 PLDHashEntryHdr
* hdr
,
812 uint32_t i
, void *arg
)
814 nsHashtable
*newHashtable
= (nsHashtable
*)arg
;
815 HTEntry
* entry
= static_cast<HTEntry
*>(hdr
);
817 nsISupports
* element
= static_cast<nsISupports
*>(entry
->value
);
818 NS_IF_ADDREF(element
);
819 newHashtable
->Put(entry
->key
, entry
->value
);
820 return PL_DHASH_NEXT
;
824 nsSupportsHashtable::Clone()
826 if (!mHashtable
.ops
) return nullptr;
828 bool threadSafe
= (mLock
!= nullptr);
829 nsSupportsHashtable
* newHashTable
=
830 new nsSupportsHashtable(mHashtable
.entryCount
, threadSafe
);
832 PL_DHashTableEnumerate(&mHashtable
, EnumerateCopy
, newHashTable
);
837 nsSupportsHashtable::Reset()
839 Enumerate(ReleaseElement
, nullptr);
840 nsHashtable::Reset();
843 ////////////////////////////////////////////////////////////////////////////////