00001 #ifndef MMANN_GLIBHASH_H
00002 #define MMANN_GLIBHASH_H
00003
00011
00012
00013 #include "CompareAlgorithms.h"
00014 #include "HashAlgorithms.h"
00015
00017 #define GLIB_HASH_TABLE_MIN_SIZE 11
00018
00019 #define GLIB_HASH_TABLE_MAX_SIZE 13845163
00020
00024 template <class Key>
00025 class GLIBHashNode
00026 {
00027 public:
00029 GLIBHashNode(Key* key, int Value, DeleteHashDataEnum DeleteHashData);
00030
00032 virtual ~GLIBHashNode();
00033
00035 Key* m_Key;
00036
00038 int m_Value;
00039
00041 GLIBHashNode<Key>* m_Next;
00042
00044 DeleteHashDataEnum m_DeleteHashData;
00045 };
00046
00047 template <class Key>
00048 GLIBHashNode<Key>::GLIBHashNode(Key* key, int Value, DeleteHashDataEnum DeleteHashData)
00049 {
00050 m_Key = key;
00051 m_Value = Value;
00052 m_Next = NULL;
00053 m_DeleteHashData = DeleteHashData;
00054 }
00055
00056 template <class Key>
00057 GLIBHashNode<Key>::~GLIBHashNode()
00058 {
00059 switch(m_DeleteHashData)
00060 {
00061 case NO_DELETE_HASH_ITEM:
00062 break;
00063 case DELETE_HASH_ITEM:
00064 delete m_Key;
00065 break;
00066 case DELETE_HASH_ITEM_ARRAY:
00067 delete [] m_Key;
00068 break;
00069 default:
00070
00071 assert(false);
00072 }
00073
00074 if (m_Next != NULL)
00075 delete m_Next;
00076 }
00077
00081 template <class Key, class ConfigData>
00082 class GLIBHash : public AGenericHash<Key, ConfigData>
00083 {
00084 public:
00086 GLIBHash(int SizeWanted, ACompareNodesAlgorithm<Key, ConfigData>* Compare,
00087 AHashAlgorithm<Key>* Hash, DeleteHashDataEnum DeleteHashData = NO_DELETE_HASH_ITEM);
00088
00090 virtual ~GLIBHash();
00091
00097 virtual Key* Insert(Key* key, bool OptimizeForCaching);
00098
00102 void Remove(Key* key);
00103
00108 int Lookup(Key* key);
00109
00116 bool LookupExtended(Key* LookupKey, Key** OriginalKey, int** Value);
00117
00119 void Freeze();
00120
00122 void Thaw();
00123
00125 void Resize();
00126
00131 void ForEach(AProcessHashAlgorithm<Key, ConfigData>* ProcessFunc, ConfigData* UserData);
00132
00137 unsigned int ForEachRemove(RemoveHashAlgorithm<Key, ConfigData>* RemoveFunc, ConfigData* configData);
00138
00140 int GetSize();
00141
00142 protected:
00147 void Insert(Key* key, int Value);
00148
00153 GLIBHashNode<Key>** LookupNode(Key* key);
00154
00155 private:
00157 unsigned int m_Frozen;
00158
00160 GLIBHashNode<Key> **m_Nodes;
00161 };
00162
00163 template <class Key, class ConfigData>
00164 GLIBHash<Key, ConfigData>::GLIBHash(int SizeWanted, ACompareNodesAlgorithm<Key, ConfigData>* Compare,
00165 AHashAlgorithm<Key>* Hash, DeleteHashDataEnum DeleteHashData) : AGenericHash<Key, ConfigData>(SizeWanted, Compare, Hash, DeleteHashData)
00166 {
00167 m_Frozen = 0;
00168 m_Nodes = new GLIBHashNode<Key>*[m_Size];
00169 for (int i = 0; i < m_Size; i++)
00170 m_Nodes[i] = NULL;
00171 }
00172
00173 template <class Key, class ConfigData>
00174 GLIBHash<Key, ConfigData>::~GLIBHash()
00175 {
00176 for (int i = 0;i<m_Size;i++)
00177 delete m_Nodes[i];
00178
00179 delete [] m_Nodes;
00180 }
00181
00182 template <class Key, class ConfigData>
00183 Key* GLIBHash<Key, ConfigData>::Insert(Key* key, bool OptimizeForCaching)
00184 {
00185 GLIBHashNode<Key> **Node = LookupNode(key);
00186
00187 if (*Node != NULL)
00188 return (*Node)->m_Key;
00189
00190 int HashValue = m_Hash->Hash(key);
00191 Insert(key, HashValue);
00192 return NULL;
00193 }
00194
00195 template <class Key,class ConfigData>
00196 void GLIBHash<Key, ConfigData>::Insert(Key* key, int Value)
00197 {
00198 GLIBHashNode<Key> **Node = LookupNode(key);
00199
00200 if (*Node != NULL)
00201 (*Node)->m_Value = Value;
00202
00203 *Node = new GLIBHashNode<Key>(key, Value, m_DeleteHashData);
00204 m_NumberOfElements++;
00205 if (!m_Frozen)
00206 Resize();
00207 }
00208
00209 template <class Key, class ConfigData>
00210 void GLIBHash<Key, ConfigData>::Remove(Key* key)
00211 {
00212 GLIBHashNode<Key> **Node = LookupNode(key),
00213 *DestroyNode;
00214
00215 if (*Node)
00216 {
00217 DestroyNode = *Node;
00218 (*Node) = DestroyNode->m_Next;
00219 delete DestroyNode;
00220 m_NumberOfElements--;
00221
00222 if (!m_Frozen)
00223 Resize();
00224 }
00225 }
00226
00227 template <class Key, class ConfigData>
00228 int GLIBHash<Key, ConfigData>::Lookup(Key* key)
00229 {
00230 GLIBHashNode<Key> *Node = LookupNode(key);
00231
00232 return Node ? Node->m_Value : 0;
00233 }
00234
00235 template <class Key, class ConfigData>
00236 bool GLIBHash<Key, ConfigData>::LookupExtended(Key* LookupKey, Key** OriginalKey, int** Value)
00237 {
00238 GLIBHashNode<Key> *Node = LookupNode(LookupKey);
00239
00240 if (Node)
00241 {
00242 if (OriginalKey)
00243 *OriginalKey = Node->m_Key;
00244 if (Value)
00245 *Value = Node->m_Value;
00246 return true;
00247 }
00248 else
00249 return false;
00250 }
00251
00252 template <class Key, class ConfigData>
00253 void GLIBHash<Key, ConfigData>::Freeze()
00254 {
00255 m_Frozen++;
00256 }
00257
00258 template <class Key, class ConfigData>
00259 void GLIBHash<Key, ConfigData>::Thaw()
00260 {
00261 if (m_Frozen)
00262 if (!(--m_Frozen))
00263 Resize();
00264 }
00265
00266 template <class Key, class ConfigData>
00267 void GLIBHash<Key, ConfigData>::Resize()
00268 {
00269 GLIBHashNode<Key> **NewNodes;
00270 GLIBHashNode<Key> *Node, *Next;
00271 float NodesPerList = (float)m_NumberOfElements/(float)m_Size;
00272 unsigned int HashValue;
00273 int NewSize = FindClosestPrime(m_NumberOfElements);
00274
00275 if ((NodesPerList > 0.3 || m_Size <= GLIB_HASH_TABLE_MIN_SIZE) &&
00276 (NodesPerList < 3.0 || m_Size >= GLIB_HASH_TABLE_MAX_SIZE))
00277 return;
00278
00279 if (NewSize == m_Size)
00280 return;
00281
00282 NewNodes = new GLIBHashNode<Key>*[NewSize];
00283
00284 for (int a = 0;a<NewSize;a++)
00285 NewNodes[a] = NULL;
00286
00287 for (int i = 0; i < m_Size; i++)
00288 for (Node = m_Nodes[i]; Node; Node = Next)
00289 {
00290 Next = Node->m_Next;
00291 HashValue = m_Hash->Hash(Node->m_Key) % NewSize;
00292 Node->m_Next = NewNodes[HashValue];
00293 NewNodes[HashValue] = Node;
00294 }
00295
00296 delete [] m_Nodes;
00297 m_Nodes = NewNodes;
00298 m_Size = NewSize;
00299 }
00300
00301 template <class Key, class ConfigData>
00302 void GLIBHash<Key, ConfigData>::ForEach(AProcessHashAlgorithm<Key, ConfigData>* ProcessFunc, ConfigData* UserData)
00303 {
00304 GLIBHashNode<Key> *Node;
00305
00306 for (int i = 0; i < m_Size; i++)
00307 for (Node = m_Nodes[i]; Node; Node = Node->m_Next)
00308 ProcessFunc->ProcessHash(Node->m_Key, Node->m_Value, UserData);
00309 }
00310
00311 template <class Key, class ConfigData>
00312 unsigned int GLIBHash<Key, ConfigData>::ForEachRemove(RemoveHashAlgorithm<Key, ConfigData>* RemoveFunc, ConfigData* configData)
00313 {
00314 GLIBHashNode<Key> *Node, *Previous;
00315 unsigned int Deleted = 0;
00316
00317 for (int i = 0; i < m_Size; i++)
00318 {
00319 Restart:
00320 Previous = NULL;
00321
00322 for (Node = m_Nodes[i]; Node; Previous = Node, Node = Node->m_Next)
00323 {
00324 if (RemoveFunc->ProcessHash(Node->m_Key, Node->m_Value, configData))
00325 {
00326 Deleted += 1;
00327 m_NumberOfElements -= 1;
00328
00329 if (Previous)
00330 {
00331 Previous->m_Next = Node->m_Next;
00332 delete Node;
00333 Node = Previous;
00334 }
00335 else
00336 {
00337 m_Nodes[i] = Node->m_Next;
00338 delete Node;
00339 goto Restart;
00340 }
00341 }
00342 }
00343 }
00344
00345 if (!m_Frozen)
00346 Resize();
00347
00348 return Deleted;
00349 }
00350
00351 template <class Key, class ConfigData>
00352 int GLIBHash<Key, ConfigData>::GetSize()
00353 {
00354 return m_NumberOfElements;
00355 }
00356
00357 template <class Key, class ConfigData>
00358 GLIBHashNode<Key>** GLIBHash<Key, ConfigData>::LookupNode(Key* key)
00359 {
00360 GLIBHashNode<Key> **Node;
00361
00362 Node = &m_Nodes[m_Hash->Hash(key) % m_Size];
00363
00364
00365
00366
00367
00368
00369 if (m_Compare)
00370 while (*Node && (m_Compare->Compare((*Node)->m_Key, key, NULL) != 0) )
00371 Node = &(*Node)->m_Next;
00372 else
00373 while (*Node && (*Node)->m_Key != key)
00374 Node = &(*Node)->m_Next;
00375
00376 return Node;
00377 }
00378
00379 #endif