bug 812562 - click-to-play: reshow notification for blocklisted plugins r=jaws
[gecko.git] / xpcom / ds / nsHashtable.cpp
blob0ca643f857656238721cbde049cd1232a1e8bc54
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 "prmem.h"
19 #include "prlog.h"
20 #include "nsHashtable.h"
21 #include "nsReadableUtils.h"
22 #include "nsIObjectInputStream.h"
23 #include "nsIObjectOutputStream.h"
24 #include "nsCRT.h"
25 #include "mozilla/HashFunctions.h"
27 using namespace mozilla;
29 struct HTEntry : PLDHashEntryHdr
31 nsHashKey* key;
32 void* value;
36 // Key operations
39 static bool
40 matchKeyEntry(PLDHashTable*, const PLDHashEntryHdr* entry,
41 const void* key)
43 const HTEntry* hashEntry =
44 static_cast<const HTEntry*>(entry);
46 if (hashEntry->key == key)
47 return true;
49 const nsHashKey* otherKey = reinterpret_cast<const nsHashKey*>(key);
50 return otherKey->Equals(hashEntry->key);
53 static PLDHashNumber
54 hashKey(PLDHashTable* table, const void* key)
56 const nsHashKey* hashKey = static_cast<const nsHashKey*>(key);
58 return hashKey->HashCode();
61 static void
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
70 // sanity's sake
74 static const PLDHashTableOps hashtableOps = {
75 PL_DHashAllocTable,
76 PL_DHashFreeTable,
77 hashKey,
78 matchKeyEntry,
79 PL_DHashMoveEntryStub,
80 clearHashEntry,
81 PL_DHashFinalizeStub,
82 nullptr,
87 // Enumerator callback
90 struct _HashEnumerateArgs {
91 nsHashtableEnumFunc fn;
92 void* arg;
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;
107 // HashKey
110 nsHashKey::~nsHashKey(void)
112 MOZ_COUNT_DTOR(nsHashKey);
115 nsresult
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
133 if (!result)
134 mHashtable.ops = nullptr;
136 if (threadSafe) {
137 mLock = PR_NewLock();
138 if (mLock == NULL) {
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);
149 if (mHashtable.ops)
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);
160 return false;
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);
170 return exists;
173 void *nsHashtable::Put(nsHashKey *aKey, void *aData)
175 void *res = NULL;
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);
184 HTEntry* entry =
185 static_cast<HTEntry*>
186 (PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_ADD));
188 if (entry) { // don't return early, or you'll be locked!
189 if (entry->key) {
190 // existing entry, need to boot the old value
191 res = entry->value;
192 entry->value = aData;
193 } else {
194 // new entry (leave res == null)
195 entry->key = aKey->Clone();
196 entry->value = aData;
200 if (mLock) PR_Unlock(mLock);
202 return res;
205 void *nsHashtable::Get(nsHashKey *aKey)
207 if (!mHashtable.ops) return nullptr;
209 if (mLock) PR_Lock(mLock);
211 HTEntry* entry =
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);
218 return ret;
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
233 HTEntry* entry =
234 static_cast<HTEntry*>
235 (PL_DHashTableOperate(&mHashtable, aKey, PL_DHASH_LOOKUP));
236 void *res;
238 if (PL_DHASH_ENTRY_IS_FREE(entry)) {
239 // value wasn't in the table anyway
240 res = nullptr;
241 } else {
242 res = entry->value;
243 PL_DHashTableRawRemove(&mHashtable, entry);
246 if (mLock) PR_Unlock(mLock);
248 return res;
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
253 // nor refcounted.
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);
273 return newHashTable;
276 void nsHashtable::Enumerate(nsHashtableEnumFunc aEnumFunc, void* aClosure)
278 if (!mHashtable.ops) return;
280 bool wasEnumerating = mEnumerating;
281 mEnumerating = true;
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;
294 if (thunk) {
295 return thunk->fn(entry->key, entry->value, thunk->arg)
296 ? PL_DHASH_REMOVE
297 : PL_DHASH_STOP;
299 return PL_DHASH_REMOVE;
302 void nsHashtable::Reset() {
303 Reset(NULL);
306 void nsHashtable::Reset(nsHashtableEnumFunc destroyFunc, void* aClosure)
308 if (!mHashtable.ops) return;
310 _HashEnumerateArgs thunk, *thunkp;
311 if (!destroyFunc) {
312 thunkp = nullptr;
313 } else {
314 thunkp = &thunk;
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,
326 nsresult *aRetVal)
327 : mLock(nullptr),
328 mEnumerating(false)
330 MOZ_COUNT_CTOR(nsHashtable);
332 bool threadSafe;
333 nsresult rv = aStream->ReadBoolean(&threadSafe);
334 if (NS_SUCCEEDED(rv)) {
335 if (threadSafe) {
336 mLock = PR_NewLock();
337 if (!mLock)
338 rv = NS_ERROR_OUT_OF_MEMORY;
341 if (NS_SUCCEEDED(rv)) {
342 uint32_t count;
343 rv = aStream->Read32(&count);
345 if (NS_SUCCEEDED(rv)) {
346 bool status =
347 PL_DHashTableInit(&mHashtable, &hashtableOps,
348 nullptr, sizeof(HTEntry), count);
349 if (!status) {
350 mHashtable.ops = nullptr;
351 rv = NS_ERROR_OUT_OF_MEMORY;
352 } else {
353 for (uint32_t i = 0; i < count; i++) {
354 nsHashKey* key;
355 void *data;
357 rv = aReadEntryFunc(aStream, &key, &data);
358 if (NS_SUCCEEDED(rv)) {
359 Put(key, data);
361 // XXXbe must we clone key? can't we hand off
362 aFreeEntryFunc(aStream, key, nullptr);
369 *aRetVal = rv;
372 struct WriteEntryArgs {
373 nsIObjectOutputStream* mStream;
374 nsHashtableWriteDataFunc mWriteDataFunc;
375 nsresult mRetVal;
378 static bool
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);
388 args->mRetVal = rv;
389 return true;
392 nsresult
393 nsHashtable::Write(nsIObjectOutputStream* aStream,
394 nsHashtableWriteDataFunc aWriteDataFunc) const
396 if (!mHashtable.ops)
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);
410 return args.mRetVal;
413 ////////////////////////////////////////////////////////////////////////////////
415 nsISupportsKey::nsISupportsKey(nsIObjectInputStream* aStream, nsresult *aResult)
416 : mKey(nullptr)
418 bool nonnull;
419 nsresult rv = aStream->ReadBoolean(&nonnull);
420 if (NS_SUCCEEDED(rv) && nonnull)
421 rv = aStream->ReadObject(true, &mKey);
422 *aResult = rv;
425 nsresult
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);
432 return rv;
435 // Copy Constructor
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)));
445 if (!str) {
446 // Pray we don't dangle!
447 mOwnership = NEVER_OWN;
448 } else {
449 // Use memcpy in case there are embedded NULs.
450 memcpy(str, mStr, len);
451 str[mStrLen] = '\0';
452 mStr = str;
453 mOwnership = OWN;
456 #ifdef DEBUG
457 mKeyType = CStringKey;
458 #endif
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");
468 #ifdef DEBUG
469 mKeyType = CStringKey;
470 #endif
471 MOZ_COUNT_CTOR(nsCStringKey);
474 nsCStringKey::nsCStringKey(const nsACString& str)
475 : mStr(ToNewCString(str)),
476 mStrLen(str.Length()),
477 mOwnership(OWN)
479 NS_ASSERTION(mStr, "null string key");
480 #ifdef DEBUG
481 mKeyType = CStringKey;
482 #endif
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);
492 #ifdef DEBUG
493 mKeyType = CStringKey;
494 #endif
495 MOZ_COUNT_CTOR(nsCStringKey);
498 nsCStringKey::~nsCStringKey(void)
500 if (mOwnership == OWN)
501 nsMemory::Free(mStr);
502 MOZ_COUNT_DTOR(nsCStringKey);
505 uint32_t
506 nsCStringKey::HashCode(void) const
508 return HashString(mStr, mStrLen);
511 bool
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)
519 return false;
520 return memcmp(mStr, other->mStr, mStrLen * sizeof(char)) == 0;
523 nsHashKey*
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));
535 if (str == NULL)
536 return NULL;
537 memcpy(str, mStr, len);
538 str[len] = 0;
539 return new nsCStringKey(str, mStrLen, OWN);
542 nsCStringKey::nsCStringKey(nsIObjectInputStream* aStream, nsresult *aResult)
543 : mStr(nullptr), mStrLen(0), mOwnership(OWN)
545 nsAutoCString str;
546 nsresult rv = aStream->ReadCString(str);
547 mStr = ToNewCString(str);
548 if (NS_SUCCEEDED(rv))
549 mStrLen = str.Length();
550 *aResult = rv;
551 MOZ_COUNT_CTOR(nsCStringKey);
554 nsresult
555 nsCStringKey::Write(nsIObjectOutputStream* aStream) const
557 return aStream->WriteStringZ(mStr);
560 ////////////////////////////////////////////////////////////////////////////////
562 // Copy Constructor
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)));
572 if (!str) {
573 // Pray we don't dangle!
574 mOwnership = NEVER_OWN;
575 } else {
576 // Use memcpy in case there are embedded NULs.
577 memcpy(str, mStr, len);
578 str[mStrLen] = 0;
579 mStr = str;
580 mOwnership = OWN;
583 #ifdef DEBUG
584 mKeyType = StringKey;
585 #endif
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");
595 #ifdef DEBUG
596 mKeyType = StringKey;
597 #endif
598 MOZ_COUNT_CTOR(nsStringKey);
601 nsStringKey::nsStringKey(const nsAString& str)
602 : mStr(ToNewUnicode(str)),
603 mStrLen(str.Length()),
604 mOwnership(OWN)
606 NS_ASSERTION(mStr, "null string key");
607 #ifdef DEBUG
608 mKeyType = StringKey;
609 #endif
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);
619 #ifdef DEBUG
620 mKeyType = StringKey;
621 #endif
622 MOZ_COUNT_CTOR(nsStringKey);
625 nsStringKey::~nsStringKey(void)
627 if (mOwnership == OWN)
628 nsMemory::Free(mStr);
629 MOZ_COUNT_DTOR(nsStringKey);
632 uint32_t
633 nsStringKey::HashCode(void) const
635 return HashString(mStr, mStrLen);
638 bool
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)
646 return false;
647 return memcmp(mStr, other->mStr, mStrLen * sizeof(PRUnichar)) == 0;
650 nsHashKey*
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);
658 if (str == NULL)
659 return NULL;
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)
667 nsAutoString str;
668 nsresult rv = aStream->ReadString(str);
669 mStr = ToNewUnicode(str);
670 if (NS_SUCCEEDED(rv))
671 mStrLen = str.Length();
672 *aResult = rv;
673 MOZ_COUNT_CTOR(nsStringKey);
676 nsresult
677 nsStringKey::Write(nsIObjectOutputStream* aStream) const
679 return aStream->WriteWStringZ(mStr);
682 ////////////////////////////////////////////////////////////////////////////////
683 // nsObjectHashtable: an nsHashtable where the elements are C++ objects to be
684 // deleted
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()
701 Reset();
705 PLDHashOperator
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);
713 void* newElement =
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;
722 nsHashtable*
723 nsObjectHashtable::Clone()
725 if (!mHashtable.ops) return nullptr;
727 bool threadSafe = false;
728 if (mLock)
729 threadSafe = true;
730 nsObjectHashtable* newHashTable =
731 new nsObjectHashtable(mCloneElementFun, mCloneElementClosure,
732 mDestroyElementFun, mDestroyElementClosure,
733 mHashtable.entryCount, threadSafe);
735 PL_DHashTableEnumerate(&mHashtable, CopyElement, newHashTable);
736 return newHashTable;
739 void
740 nsObjectHashtable::Reset()
742 nsHashtable::Reset(mDestroyElementFun, mDestroyElementClosure);
745 bool
746 nsObjectHashtable::RemoveAndDelete(nsHashKey *aKey)
748 void *value = Remove(aKey);
749 if (value && mDestroyElementFun)
750 return !!(*mDestroyElementFun)(aKey, value, mDestroyElementClosure);
751 return false;
754 ////////////////////////////////////////////////////////////////////////////////
755 // nsSupportsHashtable: an nsHashtable where the elements are nsISupports*
757 bool
758 nsSupportsHashtable::ReleaseElement(nsHashKey *aKey, void *aData, void* aClosure)
760 nsISupports* element = static_cast<nsISupports*>(aData);
761 NS_IF_RELEASE(element);
762 return true;
765 nsSupportsHashtable::~nsSupportsHashtable()
767 Enumerate(ReleaseElement, nullptr);
770 // Return true if we overwrote something
772 bool
773 nsSupportsHashtable::Put(nsHashKey *aKey, nsISupports* aData, nsISupports **value)
775 NS_IF_ADDREF(aData);
776 void *prev = nsHashtable::Put(aKey, aData);
777 nsISupports *old = reinterpret_cast<nsISupports *>(prev);
778 if (value) // pass own the ownership to the caller
779 *value = old;
780 else // the caller doesn't care, we do
781 NS_IF_RELEASE(old);
782 return prev != nullptr;
785 nsISupports *
786 nsSupportsHashtable::Get(nsHashKey *aKey)
788 void* data = nsHashtable::Get(aKey);
789 if (!data)
790 return nullptr;
791 nsISupports* element = reinterpret_cast<nsISupports*>(data);
792 NS_IF_ADDREF(element);
793 return element;
796 // Return true if we found something (useful for checks)
798 bool
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
804 *value = element;
805 else // caller doesn't care, we do
806 NS_IF_RELEASE(element);
807 return data != nullptr;
810 PLDHashOperator
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;
824 nsHashtable*
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);
834 return newHashTable;
837 void
838 nsSupportsHashtable::Reset()
840 Enumerate(ReleaseElement, nullptr);
841 nsHashtable::Reset();
844 ////////////////////////////////////////////////////////////////////////////////