/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is C++ hashtable templates. * * The Initial Developer of the Original Code is * Benjamin Smedberg. * Portions created by the Initial Developer are Copyright (C) 2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef nsTHashtable_h__ #define nsTHashtable_h__ #include "nscore.h" #include "pldhash.h" #include "nsDebug.h" #include NEW_H // helper function for nsTHashtable::Clear() PR_EXTERN(PLDHashOperator) PR_CALLBACK PL_DHashStubEnumRemove(PLDHashTable *table, PLDHashEntryHdr *entry, PRUint32 ordinal, void *userArg); /** * a base class for templated hashtables. * * Clients will rarely need to use this class directly. Check the derived * classes first, to see if they will meet your needs. * * @param EntryType the templated entry-type class that is managed by the * hashtable. EntryType must extend the following declaration, * and must not declare any virtual functions or derive from classes * with virtual functions. Any vtable pointer would break the * PLDHashTable code. *
   class EntryType : public PLDHashEntryHdr
 *   {
 *   public: or friend nsTHashtable;
 *     // KeyType is what we use when Get()ing or Put()ing this entry
 *     // this should either be a simple datatype (PRUint32, nsISupports*) or
 *     // a const reference (const nsAString&)
 *     typedef something KeyType;
 *     // KeyTypePointer is the pointer-version of KeyType, because pldhash.h
 *     // requires keys to cast to const void*
 *     typedef const something* KeyTypePointer;
 *
 *     EntryType(KeyTypePointer aKey);
 *
 *     // the copy constructor must be defined, even if AllowMemMove() == true
 *     // or you will cause link errors!
 *     EntryType(const EntryType& aEnt);
 *
 *     // the destructor must be defined... or you will cause link errors!
 *     ~EntryType();
 *
 *     // return the key of this entry
 *     const KeyTypePointer GetKeyPointer() const;
 *
 *     // KeyEquals(): does this entry match this key?
 *     PRBool KeyEquals(KeyTypePointer aKey) const;
 *
 *     // KeyToPointer(): Convert KeyType to KeyTypePointer
 *     static KeyTypePointer KeyToPointer(KeyType aKey);
 *
 *     // HashKey(): calculate the hash number
 *     static PLDHashNumber HashKey(KeyTypePointer aKey);
 *
 *     // ALLOW_MEMMOVE can we move this class with memmove(), or do we have
 *     // to use the copy constructor?
 *     enum { ALLOW_MEMMOVE = PR_(TRUE or FALSE) };
 *   }
* * @see nsInterfaceHashtable * @see nsDataHashtable * @see nsClassHashtable * @author "Benjamin Smedberg " */ template class nsTHashtable { public: /** * A dummy constructor; you must call Init() before using this class. */ nsTHashtable(); /** * destructor, cleans up and deallocates */ ~nsTHashtable(); /** * Initialize the table. This function must be called before any other * class operations. This can fail due to OOM conditions. * @param initSize the initial number of buckets in the hashtable, default 16 * @return PR_TRUE if the class was initialized properly. */ PRBool Init(PRUint32 initSize = PL_DHASH_MIN_SIZE); /** * Check whether the table has been initialized. This can be useful for static hashtables. * @return the initialization state of the class. */ PRBool IsInitialized() const { return mTable.entrySize; } /** * KeyType is typedef'ed for ease of use. */ typedef typename EntryType::KeyType KeyType; /** * KeyTypePointer is typedef'ed for ease of use. */ typedef typename EntryType::KeyTypePointer KeyTypePointer; /** * Return the number of entries in the table. * @return number of entries */ PRUint32 Count() const { return mTable.entryCount; } /** * Get the entry associated with a key. * @param aKey the key to retrieve * @return pointer to the entry class, if the key exists; nsnull if the * key doesn't exist */ EntryType* GetEntry(KeyType aKey) const { NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); EntryType* entry = NS_REINTERPRET_CAST(EntryType*, PL_DHashTableOperate( NS_CONST_CAST(PLDHashTable*,&mTable), EntryType::KeyToPointer(aKey), PL_DHASH_LOOKUP)); return PL_DHASH_ENTRY_IS_BUSY(entry) ? entry : nsnull; } /** * Get the entry associated with a key, or create a new entry, * @param aKey the key to retrieve * @return pointer to the entry class retreived; nsnull only if memory can't be allocated */ EntryType* PutEntry(KeyType aKey) { NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); return NS_STATIC_CAST(EntryType*, PL_DHashTableOperate( &mTable, EntryType::KeyToPointer(aKey), PL_DHASH_ADD)); } /** * Remove the entry associated with a key. * @param aKey of the entry to remove */ void RemoveEntry(KeyType aKey) { NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); PL_DHashTableOperate(&mTable, EntryType::KeyToPointer(aKey), PL_DHASH_REMOVE); } /** * Remove the entry associated with a key, but don't resize the hashtable. * This is a low-level method, and is not recommended unless you know what * you're doing and you need the extra performance. This method can be used * during enumeration, while RemoveEntry() cannot. * @param aEntry the entry-pointer to remove (obtained from GetEntry or * the enumerator */ void RawRemoveEntry(EntryType* aEntry) { PL_DHashTableRawRemove(&mTable, aEntry); } /** * client must provide an Enumerator function for * EnumerateEntries * @param aEntry the entry being enumerated * @param userArg passed unchanged from EnumerateEntries * @return combination of flags * @link PLDHashOperator::PL_DHASH_NEXT PL_DHASH_NEXT @endlink , * @link PLDHashOperator::PL_DHASH_STOP PL_DHASH_STOP @endlink , * @link PLDHashOperator::PL_DHASH_REMOVE PL_DHASH_REMOVE @endlink */ typedef PLDHashOperator (*PR_CALLBACK Enumerator)(EntryType* aEntry, void* userArg); /** * Enumerate all the entries of the function. * @param enumFunc the Enumerator function to call * @param userArg a pointer to pass to the * Enumerator function * @return the number of entries actually enumerated */ PRUint32 EnumerateEntries(Enumerator enumFunc, void* userArg) { NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); s_EnumArgs args = { enumFunc, userArg }; return PL_DHashTableEnumerate(&mTable, s_EnumStub, &args); } /** * remove all entries, return hashtable to "pristine" state ;) */ void Clear() { NS_ASSERTION(mTable.entrySize, "nsTHashtable was not initialized properly."); PL_DHashTableEnumerate(&mTable, PL_DHashStubEnumRemove, nsnull); } protected: PLDHashTable mTable; static const void* PR_CALLBACK s_GetKey(PLDHashTable *table, PLDHashEntryHdr *entry); static PLDHashNumber PR_CALLBACK s_HashKey(PLDHashTable *table, const void *key); static PRBool PR_CALLBACK s_MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry, const void *key); static void PR_CALLBACK s_CopyEntry(PLDHashTable *table, const PLDHashEntryHdr *from, PLDHashEntryHdr *to); static void PR_CALLBACK s_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry); static PRBool PR_CALLBACK s_InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, const void *key); /** * passed internally during enumeration. Allocated on the stack. * * @param userFunc the Enumerator function passed to * EnumerateEntries by the client * @param userArg the userArg passed unaltered */ struct s_EnumArgs { Enumerator userFunc; void* userArg; }; static PLDHashOperator PR_CALLBACK s_EnumStub(PLDHashTable *table, PLDHashEntryHdr *entry, PRUint32 number, void *arg); private: // copy constructor, not implemented nsTHashtable(nsTHashtable& toCopy); // assignment operator, not implemented nsTHashtable& operator= (nsTHashtable& toEqual); }; // // template definitions // template nsTHashtable::nsTHashtable() { // entrySize is our "I'm initialized" indicator mTable.entrySize = 0; } template nsTHashtable::~nsTHashtable() { if (mTable.entrySize) PL_DHashTableFinish(&mTable); } template PRBool nsTHashtable::Init(PRUint32 initSize) { if (mTable.entrySize) { NS_ERROR("nsTHashtable::Init() should not be called twice."); return PR_TRUE; } static PLDHashTableOps sOps = { ::PL_DHashAllocTable, ::PL_DHashFreeTable, s_GetKey, s_HashKey, s_MatchEntry, ::PL_DHashMoveEntryStub, s_ClearEntry, ::PL_DHashFinalizeStub, s_InitEntry }; if (!EntryType::ALLOW_MEMMOVE) { sOps.moveEntry = s_CopyEntry; } if (!PL_DHashTableInit(&mTable, &sOps, nsnull, sizeof(EntryType), initSize)) { // if failed, reset "flag" mTable.entrySize = 0; return PR_FALSE; } return PR_TRUE; } // static definitions template const void* nsTHashtable::s_GetKey(PLDHashTable *table, PLDHashEntryHdr *entry) { return ((EntryType*) entry)->GetKeyPointer(); } template PLDHashNumber nsTHashtable::s_HashKey(PLDHashTable *table, const void *key) { return EntryType::HashKey(NS_REINTERPRET_CAST(const KeyTypePointer, key)); } template PRBool nsTHashtable::s_MatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry, const void *key) { return ((const EntryType*) entry)->KeyEquals( NS_REINTERPRET_CAST(const KeyTypePointer, key)); } template void nsTHashtable::s_CopyEntry(PLDHashTable *table, const PLDHashEntryHdr *from, PLDHashEntryHdr *to) { EntryType* fromEntry = NS_CONST_CAST(EntryType*, NS_REINTERPRET_CAST(const EntryType*, from)); new(to) EntryType(*fromEntry); fromEntry->~EntryType(); } template void nsTHashtable::s_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) { NS_REINTERPRET_CAST(EntryType*,entry)->~EntryType(); } template PRBool nsTHashtable::s_InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, const void *key) { new(entry) EntryType(NS_REINTERPRET_CAST(KeyTypePointer,key)); return PR_TRUE; } template PLDHashOperator nsTHashtable::s_EnumStub(PLDHashTable *table, PLDHashEntryHdr *entry, PRUint32 number, void *arg) { // dereferences the function-pointer to the user's enumeration function return (* NS_REINTERPRET_CAST(s_EnumArgs*,arg)->userFunc)( NS_REINTERPRET_CAST(EntryType*,entry), NS_REINTERPRET_CAST(s_EnumArgs*,arg)->userArg); } #endif // nsTHashtable_h__