csutil/hash.h
00001 /* 00002 Copyright (C) 2003 by Mat Sutcliffe <oktal@gmx.co.uk> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Lesser General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public 00015 License along with this library; if not, write to the Free 00016 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 */ 00018 00019 #ifndef __CS_UTIL_HASH_H__ 00020 #define __CS_UTIL_HASH_H__ 00021 00022 #include "csextern.h" 00023 #include "array.h" 00024 00031 CS_CSUTIL_EXPORT unsigned int csHashCompute (char const*); 00032 00039 CS_CSUTIL_EXPORT unsigned int csHashCompute (char const*, size_t length); 00040 00044 template <class T> 00045 class csIntegralHashKeyHandler 00046 { 00047 public: 00048 static unsigned int ComputeHash (const T& key) 00049 { 00050 #if (_MSC_VER >= 1300) 00051 /* 00052 VC7 with 64bit warnings complains about a pointer truncation when T is 00053 a pointer. This isn't serious (as csHash<> does not rely on the hash of 00054 a key alone to retrieve a value). The __w64 causes VC7 to not emit that 00055 warning (on 32bit compilers at least). 00056 */ 00057 return (unsigned int __w64)key; 00058 #else 00059 return (unsigned int)key; 00060 #endif 00061 } 00062 00063 static bool CompareKeys (const T& key1, const T& key2) 00064 { 00065 return (key1 == key2); 00066 } 00067 }; 00068 00073 template <class T, class K = unsigned int, 00074 class KeyHandler = csIntegralHashKeyHandler<K> > 00075 class csHash 00076 { 00077 protected: 00078 struct Element 00079 { 00080 const K key; 00081 T value; 00082 00083 Element (const K& key0, const T &value0) : key (key0), value (value0) {} 00084 Element (const Element &other) : key (other.key), value (other.value) {} 00085 }; 00086 csArray< csArray<Element> > Elements; 00087 00088 int Modulo; 00089 00090 private: 00091 int InitModulo; 00092 int GrowRate; 00093 int MaxSize; 00094 int Size; 00095 00096 void Grow () 00097 { 00098 static const int Primes[] = 00099 { 00100 53, 97, 193, 389, 769, 00101 1543, 3079, 6151, 12289, 24593, 00102 49157, 98317, 196613, 393241, 786433, 00103 1572869, 3145739, 6291469, 12582917, 25165843, 00104 50331653, 100663319, 201326611, 402653189, 805306457, 00105 1610612741, 0 00106 }; 00107 00108 const int *p; 00109 int elen = Elements.Length (); 00110 for (p = Primes; *p && *p <= elen; p++) ; 00111 Modulo = *p; 00112 CS_ASSERT (Modulo); 00113 00114 Elements.SetLength (Modulo); 00115 00116 for (int i = 0; i < elen; i++) 00117 { 00118 csArray<Element>& src = Elements[i]; 00119 int slen = src.Length (); 00120 for (int j = slen - 1; j >= 0; j--) 00121 { 00122 const Element& srcElem = src[j]; 00123 csArray<Element>& dst = 00124 Elements.Get (KeyHandler::ComputeHash (srcElem.key) % Modulo); 00125 if (&src != &dst) 00126 { 00127 dst.Push (srcElem); 00128 src.DeleteIndex (j); 00129 } 00130 } 00131 } 00132 } 00133 00134 public: 00148 csHash (int size = 257, int grow_rate = 64, int max_size = 20000) 00149 : Elements (size), Modulo (size), InitModulo (size), 00150 GrowRate (grow_rate), MaxSize (max_size), Size (0) 00151 { 00152 Elements.SetLength (size, csArray<Element> (0, 8)); 00153 } 00154 00156 csHash (const csHash<T> &o) : Elements (o.Elements), 00157 Modulo (o.Modulo), InitModulo (o.InitModulo), 00158 GrowRate (o.GrowRate), MaxSize (o.MaxSize), Size (o.Size) {} 00159 00161 void Put (const K& key, const T &value) 00162 { 00163 csArray<Element> &values = 00164 Elements[KeyHandler::ComputeHash (key) % Modulo]; 00165 values.Push (Element (key, value)); 00166 Size++; 00167 if (values.Length () > Elements.Length () / GrowRate 00168 && Elements.Length () < MaxSize) Grow (); 00169 } 00170 00172 csArray<T> GetAll (const K& key) const 00173 { 00174 const csArray<Element> &values = 00175 Elements[KeyHandler::ComputeHash (key) % Modulo]; 00176 csArray<T> ret (values.Length () / 2); 00177 const int len = values.Length (); 00178 for (int i = 0; i < len; ++i) 00179 { 00180 const Element& v = values[i]; 00181 if (KeyHandler::CompareKeys (v.key, key)) 00182 ret.Push (v.value); 00183 } 00184 return ret; 00185 } 00186 00188 void PutFirst (const K& key, const T &value) 00189 { 00190 csArray<Element> &values = 00191 Elements[KeyHandler::ComputeHash (key) % Modulo]; 00192 const int len = values.Length (); 00193 for (int i = 0; i < len; ++i) 00194 { 00195 Element& v = values[i]; 00196 if (KeyHandler::CompareKeys (v.key, key)) 00197 { 00198 v.value = value; 00199 return; 00200 } 00201 } 00202 00203 values.Push (Element (key, value)); 00204 Size++; 00205 if (values.Length () > Elements.Length () / GrowRate 00206 && Elements.Length () < MaxSize) Grow (); 00207 } 00208 00210 bool In (const K& key) const 00211 { 00212 const csArray<Element> &values = 00213 Elements[KeyHandler::ComputeHash (key) % Modulo]; 00214 const int len = values.Length (); 00215 for (int i = 0; i < len; ++i) 00216 if (KeyHandler::CompareKeys (values[i].key, key)) 00217 return true; 00218 00219 return false; 00220 } 00221 00226 const T* GetElementPointer (const K& key) const 00227 { 00228 const csArray<Element> &values = 00229 Elements[KeyHandler::ComputeHash (key) % Modulo]; 00230 const int len = values.Length (); 00231 for (int i = 0; i < len; ++i) 00232 { 00233 const Element& v = values[i]; 00234 if (KeyHandler::CompareKeys (v.key, key)) 00235 return &v.value; 00236 } 00237 00238 return 0; 00239 } 00240 00245 T* GetElementPointer (const K& key) 00246 { 00247 csArray<Element> &values = 00248 Elements[KeyHandler::ComputeHash (key) % Modulo]; 00249 const int len = values.Length (); 00250 for (int i = 0; i < len; ++i) 00251 { 00252 Element& v = values[i]; 00253 if (KeyHandler::CompareKeys (v.key, key)) 00254 return &v.value; 00255 } 00256 00257 return 0; 00258 } 00259 00264 const T& Get (const K& key, const T& fallback) const 00265 { 00266 const csArray<Element> &values = 00267 Elements[KeyHandler::ComputeHash (key) % Modulo]; 00268 const int len = values.Length (); 00269 for (int i = 0; i < len; ++i) 00270 { 00271 const Element& v = values[i]; 00272 if (KeyHandler::CompareKeys (v.key, key)) 00273 return v.value; 00274 } 00275 00276 return fallback; 00277 } 00278 00283 T& Get (const K& key, T& fallback) 00284 { 00285 csArray<Element> &values = 00286 Elements[KeyHandler::ComputeHash (key) % Modulo]; 00287 const int len = values.Length (); 00288 for (int i = 0; i < len; ++i) 00289 { 00290 Element& v = values[i]; 00291 if (KeyHandler::CompareKeys (v.key, key)) 00292 return v.value; 00293 } 00294 00295 return fallback; 00296 } 00297 00299 void DeleteAll () 00300 { 00301 Elements.SetLength (Modulo = InitModulo); 00302 int elen = Elements.Length (); 00303 for (int i = 0; i < elen; i++) 00304 Elements[i].Empty (); 00305 Size = 0; 00306 } 00307 00309 bool DeleteAll (const K& key) 00310 { 00311 bool ret = false; 00312 csArray<Element> &values = 00313 Elements[KeyHandler::ComputeHash (key) % Modulo]; 00314 for (int i = values.Length () - 1; i >= 0; i--) 00315 if (KeyHandler::CompareKeys (values[i].key, key)) 00316 { 00317 values.DeleteIndex (i); 00318 ret = true; 00319 Size--; 00320 } 00321 return ret; 00322 } 00323 00325 bool Delete (const K& key, const T &value) 00326 { 00327 bool ret = false; 00328 csArray<Element> &values = 00329 Elements[KeyHandler::ComputeHash (key) % Modulo]; 00330 for (int i = values.Length () - 1; i >= 0; i--) 00331 if (KeyHandler::CompareKeys (values[i].key, key) && 00332 (values[i].value == value)) 00333 { 00334 values.DeleteIndex (i); 00335 ret = true; 00336 Size--; 00337 } 00338 return ret; 00339 } 00340 00342 int GetSize () const 00343 { 00344 return Size; 00345 } 00346 00348 class Iterator 00349 { 00350 private: 00351 const csHash<T, K, KeyHandler>* hash; 00352 const K key; 00353 int bucket, size, element; 00354 00355 void Seek () 00356 { 00357 while ((element < size) && 00358 ! KeyHandler::CompareKeys (hash->Elements[bucket][element].key, key)) 00359 element++; 00360 } 00361 00362 protected: 00363 Iterator (const csHash<T, K, KeyHandler>* hash0, const K& key0) : 00364 hash(hash0), 00365 key(key0), 00366 bucket(KeyHandler::ComputeHash(key) % hash->Modulo), 00367 size(hash->Elements[bucket].Length ()) 00368 { Reset (); } 00369 00370 friend class csHash; 00371 public: 00373 Iterator (const Iterator &o) : 00374 hash (o.hash), 00375 key(o.key), 00376 bucket(o.bucket), 00377 size(o.size), 00378 element(o.element) {} 00379 00381 Iterator& operator=(const Iterator& o) 00382 { 00383 hash = o.hash; 00384 key = o.key; 00385 bucket = o.bucket; 00386 size = o.size; 00387 element = o.element; 00388 return *this; 00389 } 00390 00392 bool HasNext () const 00393 { 00394 return element < size; 00395 } 00396 00398 const T& Next () 00399 { 00400 const T &ret = hash->Elements[bucket][element].value; 00401 element++; 00402 Seek (); 00403 return ret; 00404 } 00405 00407 void Reset () { element = 0; Seek (); } 00408 }; 00409 friend class Iterator; 00410 00412 class GlobalIterator 00413 { 00414 private: 00415 const csHash<T, K, KeyHandler> *hash; 00416 int bucket, size, element; 00417 00418 void Zero () { bucket = element = 0; } 00419 void Init () { size = hash->Elements[bucket].Length (); } 00420 00421 void FindItem () 00422 { 00423 if (element >= size) 00424 { 00425 while (++bucket < hash->Elements.Length ()) 00426 { 00427 Init (); 00428 if (size != 0) 00429 { 00430 element = 0; 00431 break; 00432 } 00433 } 00434 } 00435 } 00436 00437 protected: 00438 GlobalIterator (const csHash<T, K, KeyHandler> *hash0) : hash (hash0) 00439 { 00440 Zero (); 00441 Init (); 00442 FindItem (); 00443 } 00444 00445 friend class csHash; 00446 public: 00448 GlobalIterator (const Iterator &o) : 00449 hash (o.hash), 00450 bucket (o.bucket), 00451 size (o.size), 00452 element (o.element) {} 00453 00455 GlobalIterator& operator=(const GlobalIterator& o) 00456 { 00457 hash = o.hash; 00458 bucket = o.bucket; 00459 size = o.size; 00460 element = o.element; 00461 return *this; 00462 } 00463 00465 bool HasNext () const 00466 { 00467 if (hash->Elements.Length () == 0) return false; 00468 return element < size || bucket < hash->Elements.Length (); 00469 } 00470 00472 void Advance () 00473 { 00474 element++; 00475 FindItem (); 00476 } 00477 00479 const T& NextNoAdvance () 00480 { 00481 return hash->Elements[bucket][element].value; 00482 } 00483 00485 const T& Next () 00486 { 00487 const T &ret = NextNoAdvance (); 00488 Advance (); 00489 return ret; 00490 } 00491 00492 const T& NextNoAdvance (K &key) 00493 { 00494 key = hash->Elements[bucket][element].key; 00495 return NextNoAdvance (); 00496 } 00497 00499 const T& Next (K &key) 00500 { 00501 key = hash->Elements[bucket][element].key; 00502 return Next (); 00503 } 00504 00506 void Reset () { Zero (); Init (); FindItem (); } 00507 }; 00508 friend class GlobalIterator; 00509 00512 void DeleteElement (GlobalIterator& iterator) 00513 { 00514 Elements[iterator.bucket].DeleteIndex(iterator.element); 00515 Size--; 00516 iterator.size--; 00517 iterator.FindItem (); 00518 } 00519 00526 Iterator GetIterator (const K& key) const 00527 { 00528 return Iterator (this, key); 00529 } 00530 00536 GlobalIterator GetIterator () const 00537 { 00538 return GlobalIterator (this); 00539 } 00540 }; 00541 00547 template <class T, class KeyHandler = csIntegralHashKeyHandler<T> > 00548 class csSet 00549 { 00550 private: 00551 csHash<T, T, KeyHandler> map; 00552 00553 public: 00555 class Iterator : public csHash<T, T, KeyHandler>::Iterator 00556 { 00557 protected: 00558 Iterator () {} 00559 public: 00560 }; 00562 class GlobalIterator : public csHash<T, T, KeyHandler>::GlobalIterator 00563 { 00564 protected: 00565 GlobalIterator () {} 00566 GlobalIterator (const csSet<T, KeyHandler> *set0) : 00567 csHash<T, T, KeyHandler>::GlobalIterator(&set0->map) 00568 { } 00569 00570 public: 00571 friend class csSet; 00572 }; 00573 friend class GlobalIterator; 00574 00579 csSet (int size = 257, int grow_rate = 64, int max_size = 20000) 00580 : map (size, grow_rate, max_size) 00581 { 00582 } 00583 00588 void Add (const T& object) 00589 { 00590 if (In (object)) return; 00591 AddNoTest (object); 00592 } 00593 00600 void AddNoTest (const T& object) 00601 { 00602 map.Put (object, object); 00603 } 00604 00608 bool In (const T& object) const 00609 { 00610 return map.In (object); 00611 } 00612 00616 void DeleteAll () 00617 { 00618 map.DeleteAll (); 00619 } 00620 00626 bool Delete (const T& object) 00627 { 00628 return map.Delete (object, object); 00629 } 00630 00632 int GetSize () const 00633 { 00634 return map.GetSize (); 00635 } 00636 00638 csHash<T, T, KeyHandler>* GetHash () { return ↦ } 00639 00645 GlobalIterator GetIterator () const 00646 { 00647 return GlobalIterator(this); 00648 } 00649 }; 00650 00651 00652 #endif
Generated for Crystal Space by doxygen 1.2.18
