michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsBaseHashtable_h__ michael@0: #define nsBaseHashtable_h__ michael@0: michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/Move.h" michael@0: #include "nsTHashtable.h" michael@0: #include "prlock.h" michael@0: #include "nsDebug.h" michael@0: michael@0: template michael@0: class nsBaseHashtable; // forward declaration michael@0: michael@0: /** michael@0: * the private nsTHashtable::EntryType class used by nsBaseHashtable michael@0: * @see nsTHashtable for the specification of this class michael@0: * @see nsBaseHashtable for template parameters michael@0: */ michael@0: template michael@0: class nsBaseHashtableET : public KeyClass michael@0: { michael@0: public: michael@0: DataType mData; michael@0: friend class nsTHashtable< nsBaseHashtableET >; michael@0: michael@0: private: michael@0: typedef typename KeyClass::KeyType KeyType; michael@0: typedef typename KeyClass::KeyTypePointer KeyTypePointer; michael@0: michael@0: nsBaseHashtableET(KeyTypePointer aKey); michael@0: nsBaseHashtableET(nsBaseHashtableET&& toMove); michael@0: ~nsBaseHashtableET(); michael@0: }; michael@0: michael@0: /** michael@0: * templated hashtable for simple data types michael@0: * This class manages simple data types that do not need construction or michael@0: * destruction. michael@0: * michael@0: * @param KeyClass a wrapper-class for the hashtable key, see nsHashKeys.h michael@0: * for a complete specification. michael@0: * @param DataType the datatype stored in the hashtable, michael@0: * for example, uint32_t or nsCOMPtr. If UserDataType is not the same, michael@0: * DataType must implicitly cast to UserDataType michael@0: * @param UserDataType the user sees, for example uint32_t or nsISupports* michael@0: */ michael@0: template michael@0: class nsBaseHashtable : michael@0: protected nsTHashtable< nsBaseHashtableET > michael@0: { michael@0: typedef mozilla::fallible_t fallible_t; michael@0: michael@0: public: michael@0: typedef typename KeyClass::KeyType KeyType; michael@0: typedef nsBaseHashtableET EntryType; michael@0: michael@0: using nsTHashtable::Contains; michael@0: michael@0: nsBaseHashtable() michael@0: { michael@0: } michael@0: explicit nsBaseHashtable(uint32_t aInitSize) michael@0: : nsTHashtable(aInitSize) michael@0: { michael@0: } michael@0: michael@0: /** michael@0: * Return the number of entries in the table. michael@0: * @return number of entries michael@0: */ michael@0: uint32_t Count() const michael@0: { return nsTHashtable::Count(); } michael@0: michael@0: /** michael@0: * retrieve the value for a key. michael@0: * @param aKey the key to retreive michael@0: * @param pData data associated with this key will be placed at this michael@0: * pointer. If you only need to check if the key exists, pData michael@0: * may be null. michael@0: * @return true if the key exists. If key does not exist, pData is not michael@0: * modified. michael@0: */ michael@0: bool Get(KeyType aKey, UserDataType* pData) const michael@0: { michael@0: EntryType* ent = this->GetEntry(aKey); michael@0: michael@0: if (!ent) michael@0: return false; michael@0: michael@0: if (pData) michael@0: *pData = ent->mData; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: /** michael@0: * For pointer types, get the value, returning nullptr if the entry is not michael@0: * present in the table. michael@0: * michael@0: * @param aKey the key to retrieve michael@0: * @return The found value, or nullptr if no entry was found with the given key. michael@0: * @note If nullptr values are stored in the table, it is not possible to michael@0: * distinguish between a nullptr value and a missing entry. michael@0: */ michael@0: UserDataType Get(KeyType aKey) const michael@0: { michael@0: EntryType* ent = this->GetEntry(aKey); michael@0: if (!ent) michael@0: return 0; michael@0: michael@0: return ent->mData; michael@0: } michael@0: michael@0: /** michael@0: * put a new value for the associated key michael@0: * @param aKey the key to put michael@0: * @param aData the new data michael@0: * @return always true, unless memory allocation failed michael@0: */ michael@0: void Put(KeyType aKey, const UserDataType& aData) michael@0: { michael@0: if (!Put(aKey, aData, fallible_t())) michael@0: NS_ABORT_OOM(this->mTable.entrySize * this->mTable.entryCount); michael@0: } michael@0: michael@0: bool Put(KeyType aKey, const UserDataType& aData, const fallible_t&) NS_WARN_UNUSED_RESULT michael@0: { michael@0: EntryType* ent = this->PutEntry(aKey); michael@0: michael@0: if (!ent) michael@0: return false; michael@0: michael@0: ent->mData = aData; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: /** michael@0: * remove the data for the associated key michael@0: * @param aKey the key to remove from the hashtable michael@0: */ michael@0: void Remove(KeyType aKey) { this->RemoveEntry(aKey); } michael@0: michael@0: /** michael@0: * function type provided by the application for enumeration. michael@0: * @param aKey the key being enumerated michael@0: * @param aData data being enumerated michael@0: * @parm userArg passed unchanged from Enumerate michael@0: * @return either michael@0: * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink or michael@0: * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink michael@0: */ michael@0: typedef PLDHashOperator michael@0: (* EnumReadFunction)(KeyType aKey, michael@0: UserDataType aData, michael@0: void* userArg); michael@0: michael@0: /** michael@0: * enumerate entries in the hashtable, without allowing changes michael@0: * @param enumFunc enumeration callback michael@0: * @param userArg passed unchanged to the EnumReadFunction michael@0: */ michael@0: uint32_t EnumerateRead(EnumReadFunction enumFunc, void* userArg) const michael@0: { michael@0: NS_ASSERTION(this->mTable.entrySize, michael@0: "nsBaseHashtable was not initialized properly."); michael@0: michael@0: s_EnumReadArgs enumData = { enumFunc, userArg }; michael@0: return PL_DHashTableEnumerate(const_cast(&this->mTable), michael@0: s_EnumReadStub, michael@0: &enumData); michael@0: } michael@0: michael@0: /** michael@0: * function type provided by the application for enumeration. michael@0: * @param aKey the key being enumerated michael@0: * @param aData Reference to data being enumerated, may be altered. e.g. for michael@0: * nsInterfaceHashtable this is an nsCOMPtr reference... michael@0: * @parm userArg passed unchanged from Enumerate michael@0: * @return bitflag combination of michael@0: * @link PLDHashOperator::PL_DHASH_REMOVE @endlink, michael@0: * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink, or michael@0: * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink michael@0: */ michael@0: typedef PLDHashOperator michael@0: (* EnumFunction)(KeyType aKey, michael@0: DataType& aData, michael@0: void* userArg); michael@0: michael@0: /** michael@0: * enumerate entries in the hashtable, allowing changes. This michael@0: * functions write-locks the hashtable. michael@0: * @param enumFunc enumeration callback michael@0: * @param userArg passed unchanged to the EnumFunction michael@0: */ michael@0: uint32_t Enumerate(EnumFunction enumFunc, void* userArg) michael@0: { michael@0: NS_ASSERTION(this->mTable.entrySize, michael@0: "nsBaseHashtable was not initialized properly."); michael@0: michael@0: s_EnumArgs enumData = { enumFunc, userArg }; michael@0: return PL_DHashTableEnumerate(&this->mTable, michael@0: s_EnumStub, michael@0: &enumData); michael@0: } michael@0: michael@0: /** michael@0: * reset the hashtable, removing all entries michael@0: */ michael@0: void Clear() { nsTHashtable::Clear(); } michael@0: michael@0: /** michael@0: * client must provide a SizeOfEntryExcludingThisFun function for michael@0: * SizeOfExcludingThis. michael@0: * @param aKey the key being enumerated michael@0: * @param aData Reference to data being enumerated. michael@0: * @param mallocSizeOf the function used to measure heap-allocated blocks michael@0: * @param userArg passed unchanged from SizeOf{In,Ex}cludingThis michael@0: * @return summed size of the things pointed to by the entries michael@0: */ michael@0: typedef size_t michael@0: (* SizeOfEntryExcludingThisFun)(KeyType aKey, michael@0: const DataType &aData, michael@0: mozilla::MallocSizeOf mallocSizeOf, michael@0: void* userArg); michael@0: michael@0: /** michael@0: * Measure the size of the table's entry storage and the table itself. michael@0: * If |sizeOfEntryExcludingThis| is non-nullptr, measure the size of things michael@0: * pointed to by entries. michael@0: * michael@0: * @param sizeOfEntryExcludingThis michael@0: * the SizeOfEntryExcludingThisFun function to call michael@0: * @param mallocSizeOf the function used to meeasure heap-allocated blocks michael@0: * @param userArg a point to pass to the michael@0: * SizeOfEntryExcludingThisFun function michael@0: * @return the summed size of the entries, the table, and the table's storage michael@0: */ michael@0: size_t SizeOfIncludingThis(SizeOfEntryExcludingThisFun sizeOfEntryExcludingThis, michael@0: mozilla::MallocSizeOf mallocSizeOf, void *userArg = nullptr) michael@0: { michael@0: return mallocSizeOf(this) + this->SizeOfExcludingThis(sizeOfEntryExcludingThis, michael@0: mallocSizeOf, userArg); michael@0: } michael@0: michael@0: /** michael@0: * Measure the size of the table's entry storage, and if michael@0: * |sizeOfEntryExcludingThis| is non-nullptr, measure the size of things pointed michael@0: * to by entries. michael@0: * michael@0: * @param sizeOfEntryExcludingThis the michael@0: * SizeOfEntryExcludingThisFun function to call michael@0: * @param mallocSizeOf the function used to measure heap-allocated blocks michael@0: * @param userArg a pointer to pass to the michael@0: * SizeOfEntryExcludingThisFun function michael@0: * @return the summed size of all the entries michael@0: */ michael@0: size_t SizeOfExcludingThis(SizeOfEntryExcludingThisFun sizeOfEntryExcludingThis, michael@0: mozilla::MallocSizeOf mallocSizeOf, void *userArg = nullptr) const michael@0: { michael@0: if (sizeOfEntryExcludingThis) { michael@0: s_SizeOfArgs args = { sizeOfEntryExcludingThis, userArg }; michael@0: return PL_DHashTableSizeOfExcludingThis(&this->mTable, s_SizeOfStub, michael@0: mallocSizeOf, &args); michael@0: } michael@0: return PL_DHashTableSizeOfExcludingThis(&this->mTable, nullptr, michael@0: mallocSizeOf); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: using nsTHashtable::MarkImmutable; michael@0: #endif michael@0: michael@0: protected: michael@0: /** michael@0: * used internally during EnumerateRead. Allocated on the stack. michael@0: * @param func the enumerator passed to EnumerateRead michael@0: * @param userArg the userArg passed to EnumerateRead michael@0: */ michael@0: struct s_EnumReadArgs michael@0: { michael@0: EnumReadFunction func; michael@0: void* userArg; michael@0: }; michael@0: michael@0: static PLDHashOperator s_EnumReadStub(PLDHashTable *table, michael@0: PLDHashEntryHdr *hdr, michael@0: uint32_t number, michael@0: void *arg); michael@0: michael@0: struct s_EnumArgs michael@0: { michael@0: EnumFunction func; michael@0: void* userArg; michael@0: }; michael@0: michael@0: static PLDHashOperator s_EnumStub(PLDHashTable *table, michael@0: PLDHashEntryHdr *hdr, michael@0: uint32_t number, michael@0: void *arg); michael@0: michael@0: struct s_SizeOfArgs michael@0: { michael@0: SizeOfEntryExcludingThisFun func; michael@0: void* userArg; michael@0: }; michael@0: michael@0: static size_t s_SizeOfStub(PLDHashEntryHdr *entry, michael@0: mozilla::MallocSizeOf mallocSizeOf, michael@0: void *arg); michael@0: }; michael@0: michael@0: class nsCycleCollectionTraversalCallback; michael@0: michael@0: struct MOZ_STACK_CLASS nsBaseHashtableCCTraversalData michael@0: { michael@0: nsBaseHashtableCCTraversalData(nsCycleCollectionTraversalCallback& aCallback, michael@0: const char* aName, michael@0: uint32_t aFlags) michael@0: : mCallback(aCallback), michael@0: mName(aName), michael@0: mFlags(aFlags) michael@0: { michael@0: } michael@0: michael@0: nsCycleCollectionTraversalCallback& mCallback; michael@0: const char* mName; michael@0: uint32_t mFlags; michael@0: michael@0: }; michael@0: michael@0: template michael@0: PLDHashOperator michael@0: ImplCycleCollectionTraverse_EnumFunc(K aKey, michael@0: T aData, michael@0: void* aUserData) michael@0: { michael@0: nsBaseHashtableCCTraversalData* userData = michael@0: static_cast(aUserData); michael@0: michael@0: CycleCollectionNoteChild(userData->mCallback, michael@0: aData, michael@0: userData->mName, michael@0: userData->mFlags); michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: // michael@0: // nsBaseHashtableET definitions michael@0: // michael@0: michael@0: template michael@0: nsBaseHashtableET::nsBaseHashtableET(KeyTypePointer aKey) : michael@0: KeyClass(aKey) michael@0: { } michael@0: michael@0: template michael@0: nsBaseHashtableET::nsBaseHashtableET michael@0: (nsBaseHashtableET&& toMove) : michael@0: KeyClass(mozilla::Move(toMove)), michael@0: mData(mozilla::Move(toMove.mData)) michael@0: { } michael@0: michael@0: template michael@0: nsBaseHashtableET::~nsBaseHashtableET() michael@0: { } michael@0: michael@0: michael@0: // michael@0: // nsBaseHashtable definitions michael@0: // michael@0: michael@0: template michael@0: PLDHashOperator michael@0: nsBaseHashtable::s_EnumReadStub michael@0: (PLDHashTable *table, PLDHashEntryHdr *hdr, uint32_t number, void* arg) michael@0: { michael@0: EntryType* ent = static_cast(hdr); michael@0: s_EnumReadArgs* eargs = (s_EnumReadArgs*) arg; michael@0: michael@0: PLDHashOperator res = (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg); michael@0: michael@0: NS_ASSERTION( !(res & PL_DHASH_REMOVE ), michael@0: "PL_DHASH_REMOVE return during const enumeration; ignoring."); michael@0: michael@0: if (res & PL_DHASH_STOP) michael@0: return PL_DHASH_STOP; michael@0: michael@0: return PL_DHASH_NEXT; michael@0: } michael@0: michael@0: template michael@0: PLDHashOperator michael@0: nsBaseHashtable::s_EnumStub michael@0: (PLDHashTable *table, PLDHashEntryHdr *hdr, uint32_t number, void* arg) michael@0: { michael@0: EntryType* ent = static_cast(hdr); michael@0: s_EnumArgs* eargs = (s_EnumArgs*) arg; michael@0: michael@0: return (eargs->func)(ent->GetKey(), ent->mData, eargs->userArg); michael@0: } michael@0: michael@0: template michael@0: size_t michael@0: nsBaseHashtable::s_SizeOfStub michael@0: (PLDHashEntryHdr *hdr, mozilla::MallocSizeOf mallocSizeOf, void *arg) michael@0: { michael@0: EntryType* ent = static_cast(hdr); michael@0: s_SizeOfArgs* eargs = static_cast(arg); michael@0: michael@0: return (eargs->func)(ent->GetKey(), ent->mData, mallocSizeOf, eargs->userArg); michael@0: } michael@0: michael@0: #endif // nsBaseHashtable_h__