Main Page | Namespace List | Class Hierarchy | Class List | File List | Namespace Members | Class Members | File Members

CascadeHashTable.h

Go to the documentation of this file.
00001 //
00002 // CascadeHashTable.h - header file for class CascadeHashTable
00003 //
00004 // Copyright (c) 2002, Roku, LLC.  All rights reserved.
00005 //
00008 
00009 #ifndef _ROKU_INCLUDE_CASCADE_UTIL_CASCADEHASHTABLE_H
00010 #define _ROKU_INCLUDE_CASCADE_UTIL_CASCADEHASHTABLE_H
00011 
00012 #include <cascade/util/CascadeNewArray.h>
00013 #include <cascade/util/CascadeString.h>
00014 
00028 #undef CASSERT  /* temporary */
00029 #define CASSERT(x) do {} while (false) /* temporary */
00030 
00031 template <class KEY, class DATA>
00032 class CascadeHashTable : public CascadeObject
00033 {
00034 public:
00035     CascadeHashTable(u32 nInitialTableSize = kMinTableSize);
00036     virtual ~CascadeHashTable();
00037 
00038 public: // public functions dealing with entries
00039     bool SetAt(const KEY & key, const DATA & data);
00040         // SetAt() sets the entry identified by key to data
00041         // adding an entry for key if one doesn't already exist,
00042         // replacing the entry for key if it does
00043         // a copy is made of data
00044 
00045     bool GetAt(const KEY & key, DATA & dataToSet) const;
00046         // GetAt() sets dataToSet with the data for the key identified by key
00047         // returning true if successful, false if there is no entry at key
00048         // dataToSet is set with a copy of data
00049 
00050     u32 GetSize() const;
00051         // GetSize() gets the number of entries in the hash table
00052 
00053     bool RemoveAt(const KEY & key);
00054         // RemoveAt() removes the entry at key if it exists
00055 
00056     void RemoveAllEntries();
00057         // RemoveAllEntries() removes all entries from the hash table.
00058 
00059 public: // public functions dealing with enumeration
00060     typedef bool (EntryEnumProc)(const KEY & key, const DATA & data, void * pClientData);
00061     bool EnumerateEntries(EntryEnumProc * pEnumProc, void * pClientData) const;
00062         // EnumerateEntries() calls back pEnumProc once for each entry in the
00063         // hash table.  It is safe to call RemoveAt on the entry (and only
00064         // on the entry) passed into the pEnumProc.  EnumerateEntries() returns
00065         // true if the enumeration ran to completion, false if it was aborted.
00066 
00067 protected:
00068     enum { kMinTableSize = 8, kExpansionFactor = 3 };
00069 
00070 protected:
00071     class KeyDataPair
00072     {
00073     public:
00074         KeyDataPair(const KEY & key, const DATA & data, KeyDataPair * pNext) : m_key(key), m_data(data), m_pNext(pNext) { }
00075         ~KeyDataPair() { }
00076     public: 
00077         KEY m_key;
00078         DATA m_data;
00079         KeyDataPair * m_pNext;
00080     };
00081 
00082 protected:
00083     void ExpandTable();
00084 
00085 protected:
00086     u32 m_nSize;
00087     CascadeNewArray<KeyDataPair *> m_table;
00088 };
00089 
00091 // CascadeHashTable default template KeyHash and KeyCompare functions
00092 template <class KEY> inline u32 CascadeHashTable_KeyHash(const KEY & key)
00093 {
00094     // default hash: simple identity hash - give yourself a u32 casting operator to use it
00095     // e.g.  inline operator u32 () const { return (u32)this; }
00096     u32 nKey = (u32)key;
00097     return nKey >> 4;
00098 }
00099 
00100 template <class KEY> inline bool CascadeHashTable_KeyCompare(const KEY & key1, const KEY & key2)
00101 {
00102     // default hash key compare function: better have an operator ==
00103     return (key1 == key2);
00104 }
00105 
00107 // CascadeHashTable overloaded template KeyHash and KeyCompare functions for common key types
00108 #ifndef WIN32
00109 template <class KEY>
00110 #endif
00111 inline u32 CascadeHashTable_KeyHash(const CascadeString & string)
00112 {
00113     const char * pString = (const char *)string;
00114     u32 nHash = 0;
00115     while (*pString) { nHash *= 65599; nHash += *pString++; }
00116     return nHash;
00117 }
00118 
00119 #ifndef WIN32
00120 template <class KEY>
00121 #endif
00122 inline u32 CascadeHashTable_KeyHash(const char * pString)
00123 {
00124         u32 nHash = 0;
00125     while (*pString) { nHash *= 65599; nHash += *pString++; }
00126         return nHash;
00127 }
00128 
00129 #ifndef WIN32
00130 template <class KEY>
00131 #endif
00132 inline bool CascadeHashTable_KeyCompare(const char * pStringKey1, const char * pStringKey2)
00133 {
00134     int c = 0;
00135     while (! (c = *(u8 *)pStringKey1 - *(u8 *)pStringKey2) && *pStringKey2) ++pStringKey1, ++pStringKey2;
00136     return (c == 0);
00137 }
00138 
00140 // template class CascadeHashTable<KEY, DATA> implementation
00141 template <class KEY, class DATA>
00142 CascadeHashTable<KEY, DATA>::CascadeHashTable(u32 nInitialTableSize) :
00143     m_nSize(0),
00144     m_table(nInitialTableSize < kMinTableSize ? kMinTableSize : nInitialTableSize)
00145 {
00146     // constructor for m_table specifies initial mem size for array, must also
00147     // set the size (number of elements we want active) the array
00148     m_table.SetSize(nInitialTableSize < kMinTableSize ? kMinTableSize : nInitialTableSize);
00149     for (u32 i = 0; i < m_table.GetSize(); i++) m_table[i] = NULL;
00150 }
00151 
00152 template <class KEY, class DATA>
00153 CascadeHashTable<KEY, DATA>::~CascadeHashTable()
00154 {
00155   RemoveAllEntries();
00156 }
00157 
00158 // void CascadeHashTable::SetEntry(const KEY & key, const DATA & data);
00159 template <class KEY, class DATA>
00160 bool
00161 CascadeHashTable<KEY, DATA>::SetAt(const KEY & key, const DATA & data)
00162 {
00163     u32 nHash = CascadeHashTable_KeyHash<KEY>(key) % m_table.GetSize();
00164     KeyDataPair * pCurr = m_table[nHash];
00165     while (pCurr)
00166     {
00167         if (CascadeHashTable_KeyCompare<KEY>(key, pCurr->m_key))
00168         {
00169             pCurr->m_data = data;
00170             return true;
00171         }
00172         pCurr = pCurr->m_pNext;
00173     }
00174     m_table[nHash] = new KeyDataPair(key, data, m_table[nHash]);
00175     m_nSize++;
00176     if (m_nSize > (kExpansionFactor * m_table.GetSize())) ExpandTable();
00177     return true;
00178 }
00179 
00180 // bool CascadeHashTable::GetEntry(const KEY & key, DATA & dataToSet);
00181 template <class KEY, class DATA>
00182 bool
00183 CascadeHashTable<KEY, DATA>::GetAt(const KEY & key, DATA & dataToSet) const
00184 {
00185     KeyDataPair * pBucket = m_table[CascadeHashTable_KeyHash<KEY>(key) % m_table.GetSize()];
00186     while (pBucket)
00187     {
00188         if (CascadeHashTable_KeyCompare<KEY>(key, pBucket->m_key))
00189         {
00190             dataToSet = pBucket->m_data;
00191             return true;
00192         }
00193         pBucket = pBucket->m_pNext;
00194     }
00195     return false;
00196 }
00197 
00198 // u32 CascadeHashTable::GetSize();
00199 template <class KEY, class DATA>
00200 inline u32
00201 CascadeHashTable<KEY, DATA>::GetSize() const
00202 {
00203     return m_nSize;
00204 }
00205 
00206 // void CascadeHashTable::RemoveAt(const KEY & key);
00207 template <class KEY, class DATA>
00208 bool
00209 CascadeHashTable<KEY, DATA>::RemoveAt(const KEY & key)
00210 {
00211     u32 nHash = CascadeHashTable_KeyHash<KEY>(key) % m_table.GetSize();
00212     KeyDataPair * pCurr = m_table[nHash];
00213     KeyDataPair * pPrev = NULL;
00214     while (pCurr)
00215     {
00216         if (CascadeHashTable_KeyCompare<KEY>(key, pCurr->m_key))
00217         {
00218             if (pPrev) pPrev->m_pNext = pCurr->m_pNext;
00219             else m_table[nHash] = pCurr->m_pNext;
00220             delete pCurr;
00221             m_nSize--;
00222             return true;
00223         }
00224         pPrev = pCurr; pCurr = pCurr->m_pNext;
00225     }
00226     return false;
00227 }
00228 
00229 // void CascadeHashTable::RemoveAllEntries();
00230 template <class KEY, class DATA>
00231 void
00232 CascadeHashTable<KEY, DATA>::RemoveAllEntries()
00233 {
00234     u32 nSize = m_table.GetSize();
00235     for (u32 i = 0; i < nSize; i++)
00236     {
00237         KeyDataPair * pCurr = m_table[i];
00238         KeyDataPair * pDel;
00239         while (pCurr)
00240         {
00241             pDel = pCurr;
00242             pCurr = pCurr->m_pNext;
00243             delete pDel;
00244         }
00245         m_table[i] = NULL;
00246     }
00247     m_nSize = 0;
00248 }
00249 
00250 // bool CascadeHashTable::EnumerateEntries(EntryEnumProc * pEnumProc, void * pClientData);
00251 template <class KEY, class DATA>
00252 bool
00253 CascadeHashTable<KEY, DATA>::EnumerateEntries(EntryEnumProc * pEnumProc, void * pClientData) const
00254 {
00255     u32 nSize = m_table.GetSize();
00256     for (u32 i = 0; i < nSize; i++)
00257     {
00258         KeyDataPair * pCurr = m_table[i];
00259         KeyDataPair * pNext;
00260         while (pCurr)
00261         {
00262             pNext = pCurr->m_pNext;
00263             if (! (*pEnumProc)(pCurr->m_key, pCurr->m_data, pClientData)) return false;
00264             pCurr = pNext;
00265         }
00266     }
00267     return true;
00268 }
00269 
00270 // void CascadeHashTable::ExpandTable();
00271 template <class KEY, class DATA>
00272 void
00273 CascadeHashTable<KEY, DATA>::ExpandTable()
00274 {
00275     u32 nSizeOld = m_table.GetSize();
00276     u32 nSizeNew = 2 * nSizeOld;
00277     u32 nHashNew;
00278     m_table.SetSize(nSizeNew);
00279     for (u32 i = nSizeOld; i < nSizeNew; i++) m_table[i] = NULL;
00280 
00281     // rehash buckets from 0 to (nSizeOld-1)
00282     for (u32 nHashOld = 0; nHashOld < nSizeOld; nHashOld++)
00283     {
00284         KeyDataPair * pCurr = m_table[nHashOld];
00285         KeyDataPair * pPrev = NULL;
00286         while (pCurr)
00287         {
00288             nHashNew = CascadeHashTable_KeyHash<KEY>(pCurr->m_key) % nSizeNew;
00289             if (nHashNew == nHashOld)
00290             {
00291                 // hash staying the same
00292                 pPrev = pCurr;
00293                 pCurr = pCurr->m_pNext;
00294             }
00295             else
00296             {
00297                 // hash is in new slot, move it
00298                 CASSERT(nHashNew == (nHashOld * 2)); // must be nHashOld*2 since we doubled the table size and modded against the new size
00299                 if (pPrev)
00300                 {
00301                     pPrev->m_pNext = pCurr->m_pNext;
00302                     pCurr->m_pNext = m_table[nHashNew];
00303                     m_table[nHashNew] = pCurr;
00304                     pCurr = pPrev->m_pNext;
00305                 }
00306                 else
00307                 {
00308                     m_table[nHashOld] = pCurr->m_pNext;
00309                     pCurr->m_pNext = m_table[nHashNew];
00310                     m_table[nHashNew] = pCurr;
00311                     pCurr = m_table[nHashOld];
00312                 }
00313             }
00314         }
00315     }
00316 }
00317 
00318 #endif // #ifndef _ROKU_INCLUDE_CASCADE_UTIL_CASCADEHASHTABLE_H
00319 
00321 //  LOG
00323 //  07-Feb-04   dwoodward       created
00324 //  15-Mar-04   dwoodward   made overloaded KeyHash and KeyCompare functions
00325 //                          WIN32 friendly
00326 

Generated on Sun Jul 24 14:27:17 2005 for Cascade Library by  doxygen 1.4.1