00001
00002
00003
00004
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
00029 #define CASSERT(x) do {} while (false)
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:
00039 bool SetAt(const KEY & key, const DATA & data);
00040
00041
00042
00043
00044
00045 bool GetAt(const KEY & key, DATA & dataToSet) const;
00046
00047
00048
00049
00050 u32 GetSize() const;
00051
00052
00053 bool RemoveAt(const KEY & key);
00054
00055
00056 void RemoveAllEntries();
00057
00058
00059 public:
00060 typedef bool (EntryEnumProc)(const KEY & key, const DATA & data, void * pClientData);
00061 bool EnumerateEntries(EntryEnumProc * pEnumProc, void * pClientData) const;
00062
00063
00064
00065
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
00092 template <class KEY> inline u32 CascadeHashTable_KeyHash(const KEY & key)
00093 {
00094
00095
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
00103 return (key1 == key2);
00104 }
00105
00107
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
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
00147
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
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
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
00199 template <class KEY, class DATA>
00200 inline u32
00201 CascadeHashTable<KEY, DATA>::GetSize() const
00202 {
00203 return m_nSize;
00204 }
00205
00206
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
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
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
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
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
00292 pPrev = pCurr;
00293 pCurr = pCurr->m_pNext;
00294 }
00295 else
00296 {
00297
00298 CASSERT(nHashNew == (nHashOld * 2));
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
00323
00324
00325
00326