Bug 959405 - Please update the Buri Moz-central, 1.3, 1.2 with the latest blobs from...
[gecko.git] / xpcom / ds / nsHashtable.cpp
blobf0f2a4ba8914f6dc1a8b0d4c71b4e15c5fee4a1f
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
8 * Corporation, 2000
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
17 #include <string.h>
18 #include "prlog.h"
19 #include "prlock.h"
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
30 nsHashKey* key;
31 void* value;
35 // Key operations
38 static bool
39 matchKeyEntry(PLDHashTable*, const PLDHashEntryHdr* entry,
40 const void* key)
42 const HTEntry* hashEntry =
43 static_cast<const HTEntry*>(entry);
45 if (hashEntry->key == key)
46 return true;
48 const nsHashKey* otherKey = reinterpret_cast<const nsHashKey*>(key);
49 return otherKey->Equals(hashEntry->key);
52 static PLDHashNumber
53 hashKey(PLDHashTable* table, const void* key)
55 const nsHashKey* hashKey = static_cast<const nsHashKey*>(key);
57 return hashKey->HashCode();
60 static void
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
69 // sanity's sake
73 static const PLDHashTableOps hashtableOps = {
74 PL_DHashAllocTable,
75 PL_DHashFreeTable,
76 hashKey,
77 matchKeyEntry,
78 PL_DHashMoveEntryStub,
79 clearHashEntry,
80 PL_DHashFinalizeStub,
81 nullptr,
86 // Enumerator callback
89 struct _HashEnumerateArgs {
90 nsHashtableEnumFunc fn;
91 void* arg;
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;
106 // HashKey
109 nsHashKey::~nsHashKey(void)
111 MOZ_COUNT_DTOR(nsHashKey);
114 nsresult
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
132 if (!result)
133 mHashtable.ops = nullptr;
135 if (threadSafe) {
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);
148 if (mHashtable.ops)
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);
159 return false;
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);
169 return exists;
172 void *nsHashtable::Put(nsHashKey *aKey, void *aData)
174 void *res = nullptr;
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);
183 HTEntry* entry =
184 static_cast<HTEntry*>
185 (PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_ADD));
187 if (entry) { // don't return early, or you'll be locked!
188 if (entry->key) {
189 // existing entry, need to boot the old value
190 res = entry->value;
191 entry->value = aData;
192 } else {
193 // new entry (leave res == null)
194 entry->key = aKey->Clone();
195 entry->value = aData;
199 if (mLock) PR_Unlock(mLock);
201 return res;
204 void *nsHashtable::Get(nsHashKey *aKey)
206 if (!mHashtable.ops) return nullptr;
208 if (mLock) PR_Lock(mLock);
210 HTEntry* entry =
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);
217 return ret;
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
232 HTEntry* entry =
233 static_cast<HTEntry*>
234 (PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP));
235 void *res;
237 if (PL_DHASH_ENTRY_IS_FREE(entry)) {
238 // value wasn't in the table anyway
239 res = nullptr;
240 } else {
241 res = entry->value;
242 PL_DHashTableRawRemove(&mHashtable, entry);
245 if (mLock) PR_Unlock(mLock);
247 return res;
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
252 // nor refcounted.
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);
272 return newHashTable;
275 void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* aClosure)
277 if (!mHashtable.ops) return;
279 bool wasEnumerating = mEnumerating;
280 mEnumerating = true;
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;
293 if (thunk) {
294 return thunk->fn(entry->key, entry->value, thunk->arg)
295 ? PL_DHASH_REMOVE
296 : PL_DHASH_STOP;
298 return PL_DHASH_REMOVE;
301 void nsHashtable::Reset() {
302 Reset(nullptr);
305 void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc, void* aClosure)
307 if (!mHashtable.ops) return;
309 _HashEnumerateArgs thunk, *thunkp;
310 if (!destroyFunc) {
311 thunkp = nullptr;
312 } else {
313 thunkp = &thunk;
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,
325 nsresult *aRetVal)
326 : mLock(nullptr),
327 mEnumerating(false)
329 MOZ_COUNT_CTOR(nsHashtable);
331 bool threadSafe;
332 nsresult rv = aStream->ReadBoolean(&threadSafe);
333 if (NS_SUCCEEDED(rv)) {
334 if (threadSafe) {
335 mLock = PR_NewLock();
336 if (!mLock)
337 rv = NS_ERROR_OUT_OF_MEMORY;
340 if (NS_SUCCEEDED(rv)) {
341 uint32_t count;
342 rv = aStream->Read32(&count);
344 if (NS_SUCCEEDED(rv)) {
345 bool status =
346 PL_DHashTableInit(&mHashtable, &hashtableOps,
347 nullptr, sizeof(HTEntry), count);
348 if (!status) {
349 mHashtable.ops = nullptr;
350 rv = NS_ERROR_OUT_OF_MEMORY;
351 } else {
352 for (uint32_t i = 0; i < count; i++) {
353 nsHashKey* key;
354 void *data;
356 rv = aReadEntryFunc(aStream, &key, &data);
357 if (NS_SUCCEEDED(rv)) {
358 Put(key, data);
360 // XXXbe must we clone key? can't we hand off
361 aFreeEntryFunc(aStream, key, nullptr);
368 *aRetVal = rv;
371 struct WriteEntryArgs {
372 nsIObjectOutputStream* mStream;
373 nsHashtableWriteDataFunc mWriteDataFunc;
374 nsresult mRetVal;
377 static bool
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);
387 args->mRetVal = rv;
388 return true;
391 nsresult
392 nsHashtable::Write(nsIObjectOutputStream* aStream,
393 nsHashtableWriteDataFunc aWriteDataFunc) const
395 if (!mHashtable.ops)
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);
409 return args.mRetVal;
412 ////////////////////////////////////////////////////////////////////////////////
414 nsISupportsKey::nsISupportsKey(nsIObjectInputStream* aStream, nsresult *aResult)
415 : mKey(nullptr)
417 bool nonnull;
418 nsresult rv = aStream->ReadBoolean(&nonnull);
419 if (NS_SUCCEEDED(rv) && nonnull)
420 rv = aStream->ReadObject(true, &mKey);
421 *aResult = rv;
424 nsresult
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);
431 return rv;
434 // Copy Constructor
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)));
444 if (!str) {
445 // Pray we don't dangle!
446 mOwnership = NEVER_OWN;
447 } else {
448 // Use memcpy in case there are embedded NULs.
449 memcpy(str, mStr, len);
450 str[mStrLen] = '\0';
451 mStr = str;
452 mOwnership = OWN;
455 #ifdef DEBUG
456 mKeyType = CStringKey;
457 #endif
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");
467 #ifdef DEBUG
468 mKeyType = CStringKey;
469 #endif
470 MOZ_COUNT_CTOR(nsCStringKey);
473 nsCStringKey::nsCStringKey(const nsACString& str)
474 : mStr(ToNewCString(str)),
475 mStrLen(str.Length()),
476 mOwnership(OWN)
478 NS_ASSERTION(mStr, "null string key");
479 #ifdef DEBUG
480 mKeyType = CStringKey;
481 #endif
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);
491 #ifdef DEBUG
492 mKeyType = CStringKey;
493 #endif
494 MOZ_COUNT_CTOR(nsCStringKey);
497 nsCStringKey::~nsCStringKey(void)
499 if (mOwnership == OWN)
500 nsMemory::Free(mStr);
501 MOZ_COUNT_DTOR(nsCStringKey);
504 uint32_t
505 nsCStringKey::HashCode(void) const
507 return HashString(mStr, mStrLen);
510 bool
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)
518 return false;
519 return memcmp(mStr, other->mStr, mStrLen * sizeof(char)) == 0;
522 nsHashKey*
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));
534 if (str == nullptr)
535 return nullptr;
536 memcpy(str, mStr, len);
537 str[len] = 0;
538 return new nsCStringKey(str, mStrLen, OWN);
541 nsCStringKey::nsCStringKey(nsIObjectInputStream* aStream, nsresult *aResult)
542 : mStr(nullptr), mStrLen(0), mOwnership(OWN)
544 nsAutoCString str;
545 nsresult rv = aStream->ReadCString(str);
546 mStr = ToNewCString(str);
547 if (NS_SUCCEEDED(rv))
548 mStrLen = str.Length();
549 *aResult = rv;
550 MOZ_COUNT_CTOR(nsCStringKey);
553 nsresult
554 nsCStringKey::Write(nsIObjectOutputStream* aStream) const
556 return aStream->WriteStringZ(mStr);
559 ////////////////////////////////////////////////////////////////////////////////
561 // Copy Constructor
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)));
571 if (!str) {
572 // Pray we don't dangle!
573 mOwnership = NEVER_OWN;
574 } else {
575 // Use memcpy in case there are embedded NULs.
576 memcpy(str, mStr, len);
577 str[mStrLen] = 0;
578 mStr = str;
579 mOwnership = OWN;
582 #ifdef DEBUG
583 mKeyType = StringKey;
584 #endif
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");
594 #ifdef DEBUG
595 mKeyType = StringKey;
596 #endif
597 MOZ_COUNT_CTOR(nsStringKey);
600 nsStringKey::nsStringKey(const nsAString& str)
601 : mStr(ToNewUnicode(str)),
602 mStrLen(str.Length()),
603 mOwnership(OWN)
605 NS_ASSERTION(mStr, "null string key");
606 #ifdef DEBUG
607 mKeyType = StringKey;
608 #endif
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);
618 #ifdef DEBUG
619 mKeyType = StringKey;
620 #endif
621 MOZ_COUNT_CTOR(nsStringKey);
624 nsStringKey::~nsStringKey(void)
626 if (mOwnership == OWN)
627 nsMemory::Free(mStr);
628 MOZ_COUNT_DTOR(nsStringKey);
631 uint32_t
632 nsStringKey::HashCode(void) const
634 return HashString(mStr, mStrLen);
637 bool
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)
645 return false;
646 return memcmp(mStr, other->mStr, mStrLen * sizeof(char16_t)) == 0;
649 nsHashKey*
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);
657 if (str == nullptr)
658 return nullptr;
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)
666 nsAutoString str;
667 nsresult rv = aStream->ReadString(str);
668 mStr = ToNewUnicode(str);
669 if (NS_SUCCEEDED(rv))
670 mStrLen = str.Length();
671 *aResult = rv;
672 MOZ_COUNT_CTOR(nsStringKey);
675 nsresult
676 nsStringKey::Write(nsIObjectOutputStream* aStream) const
678 return aStream->WriteWStringZ(mStr);
681 ////////////////////////////////////////////////////////////////////////////////
682 // nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
683 // deleted
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()
700 Reset();
704 PLDHashOperator
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);
712 void* newElement =
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;
721 nsHashtable*
722 nsObjectHashtable::Clone()
724 if (!mHashtable.ops) return nullptr;
726 bool threadSafe = false;
727 if (mLock)
728 threadSafe = true;
729 nsObjectHashtable* newHashTable =
730 new nsObjectHashtable(mCloneElementFun, mCloneElementClosure,
731 mDestroyElementFun, mDestroyElementClosure,
732 mHashtable.entryCount, threadSafe);
734 PL_DHashTableEnumerate(&mHashtable, CopyElement, newHashTable);
735 return newHashTable;
738 void
739 nsObjectHashtable::Reset()
741 nsHashtable::Reset(mDestroyElementFun, mDestroyElementClosure);
744 bool
745 nsObjectHashtable::RemoveAndDelete(nsHashKey *aKey)
747 void *value = Remove(aKey);
748 if (value && mDestroyElementFun)
749 return !!(*mDestroyElementFun)(aKey, value, mDestroyElementClosure);
750 return false;
753 ////////////////////////////////////////////////////////////////////////////////
754 // nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
756 bool
757 nsSupportsHashtable::ReleaseElement(nsHashKey *aKey, void *aData, void* aClosure)
759 nsISupports* element = static_cast<nsISupports*>(aData);
760 NS_IF_RELEASE(element);
761 return true;
764 nsSupportsHashtable::~nsSupportsHashtable()
766 Enumerate(ReleaseElement, nullptr);
769 // Return true if we overwrote something
771 bool
772 nsSupportsHashtable::Put(nsHashKey *aKey, nsISupports* aData, nsISupports **value)
774 NS_IF_ADDREF(aData);
775 void *prev = nsHashtable::Put(aKey, aData);
776 nsISupports *old = reinterpret_cast<nsISupports *>(prev);
777 if (value) // pass own the ownership to the caller
778 *value = old;
779 else // the caller doesn't care, we do
780 NS_IF_RELEASE(old);
781 return prev != nullptr;
784 nsISupports *
785 nsSupportsHashtable::Get(nsHashKey *aKey)
787 void* data = nsHashtable::Get(aKey);
788 if (!data)
789 return nullptr;
790 nsISupports* element = reinterpret_cast<nsISupports*>(data);
791 NS_IF_ADDREF(element);
792 return element;
795 // Return true if we found something (useful for checks)
797 bool
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
803 *value = element;
804 else // caller doesn't care, we do
805 NS_IF_RELEASE(element);
806 return data != nullptr;
809 PLDHashOperator
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;
823 nsHashtable*
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);
833 return newHashTable;
836 void
837 nsSupportsHashtable::Reset()
839 Enumerate(ReleaseElement, nullptr);
840 nsHashtable::Reset();
843 ////////////////////////////////////////////////////////////////////////////////