Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages
hash.h
Go to the documentation of this file.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 00026 #include "csextern.h" 00027 #include "csutil/array.h" 00028 #include "csutil/comparator.h" 00029 00030 00040 CS_CRYSTALSPACE_EXPORT unsigned int csHashCompute (char const*); 00041 00048 CS_CRYSTALSPACE_EXPORT unsigned int csHashCompute (char const*, size_t length); 00049 00054 template <class T> 00055 class csHashComputer 00056 { 00057 public: 00059 static uint ComputeHash (const T& key) 00060 { 00061 return key.GetHash(); 00062 } 00063 }; 00064 00069 template <class T> 00070 class csHashComputerIntegral 00071 { 00072 public: 00074 static uint ComputeHash (const T& key) 00075 { 00076 return (uintptr_t)key; 00077 } 00078 }; 00079 00081 00084 CS_SPECIALIZE_TEMPLATE 00085 class csHashComputer<void*> : public csHashComputerIntegral<void*> {}; 00086 00087 CS_SPECIALIZE_TEMPLATE 00088 class csHashComputer<int> : public csHashComputerIntegral<int> {}; 00089 CS_SPECIALIZE_TEMPLATE 00090 class csHashComputer<unsigned int> : 00091 public csHashComputerIntegral<unsigned int> {}; 00092 00093 CS_SPECIALIZE_TEMPLATE 00094 class csHashComputer<long> : public csHashComputerIntegral<long> {}; 00095 CS_SPECIALIZE_TEMPLATE 00096 class csHashComputer<unsigned long> : 00097 public csHashComputerIntegral<unsigned long> {}; 00098 00099 CS_SPECIALIZE_TEMPLATE 00100 class csHashComputer<longlong> : 00101 public csHashComputerIntegral<longlong> {}; 00102 CS_SPECIALIZE_TEMPLATE 00103 class csHashComputer<ulonglong> : 00104 public csHashComputerIntegral<ulonglong> {}; 00105 00106 CS_SPECIALIZE_TEMPLATE 00107 class csHashComputer<float> 00108 { 00109 public: 00111 static uint ComputeHash (float key) 00112 { 00113 union 00114 { 00115 float f; 00116 uint u; 00117 } float2uint; 00118 float2uint.f = key; 00119 return float2uint.u; 00120 } 00121 }; 00122 CS_SPECIALIZE_TEMPLATE 00123 class csHashComputer<double> 00124 { 00125 public: 00127 static uint ComputeHash (double key) 00128 { 00129 union 00130 { 00131 double f; 00132 uint u; 00133 } double2uint; 00134 double2uint.f = key; 00135 return double2uint.u; 00136 } 00137 }; 00139 00143 template <typename T> 00144 class csPtrKey 00145 { 00146 T* ptr; 00147 public: 00148 csPtrKey () : ptr(0) {} 00149 csPtrKey (T* ptr) : ptr(ptr) {} 00150 csPtrKey (csPtrKey const& other) : ptr (other.ptr) {} 00151 00152 uint GetHash () const { return (uintptr_t)ptr; } 00153 inline friend bool operator < (const csPtrKey& r1, const csPtrKey& r2) 00154 { return r1.ptr < r2.ptr; } 00155 operator T* () const 00156 { return ptr; } 00157 T* operator -> () const 00158 { return ptr; } 00159 csPtrKey& operator = (csPtrKey const& other) 00160 { ptr = other.ptr; return *this; } 00161 }; 00162 00172 template <class T> 00173 class csHashComputerString 00174 { 00175 public: 00176 static uint ComputeHash (const T& key) 00177 { 00178 return csHashCompute ((const char*)key); 00179 } 00180 }; 00181 00185 CS_SPECIALIZE_TEMPLATE 00186 class csHashComputer<const char*> : public csHashComputerString<const char*> {}; 00187 00197 template <class T> 00198 class csHashComputerStruct 00199 { 00200 public: 00201 static uint ComputeHash (const T& key) 00202 { 00203 return csHashCompute ((char*)&key, sizeof (T)); 00204 } 00205 }; 00206 00212 class csStrKey 00213 { 00214 private: 00215 char* str; 00216 00217 public: 00218 csStrKey () { str = 0; } 00219 csStrKey (const char* s) { str = csStrNew (s); } 00220 csStrKey (const csStrKey& c) { str = csStrNew (c.str); } 00221 ~csStrKey () { delete[] str; } 00222 csStrKey& operator=(const csStrKey& o) 00223 { 00224 delete[] str; str = csStrNew (o.str); 00225 return *this; 00226 } 00227 operator const char* () const { return str; } 00228 uint GetHash() const { return csHashCompute (str); } 00229 }; 00230 00234 CS_SPECIALIZE_TEMPLATE 00235 class csComparator<csStrKey, csStrKey> : public csComparatorString<csStrKey> {}; 00236 00246 template <class T, class K = unsigned int> 00247 class csHash 00248 { 00249 protected: 00250 struct Element 00251 { 00252 const K key; 00253 T value; 00254 00255 Element (const K& key0, const T &value0) : key (key0), value (value0) {} 00256 Element (const Element &other) : key (other.key), value (other.value) {} 00257 }; 00258 csArray< csArray<Element> > Elements; 00259 00260 size_t Modulo; 00261 00262 private: 00263 size_t InitModulo; 00264 size_t GrowRate; 00265 size_t MaxSize; 00266 size_t Size; 00267 00268 void Grow () 00269 { 00270 static const size_t Primes[] = 00271 { 00272 53, 97, 193, 389, 769, 00273 1543, 3079, 6151, 12289, 24593, 00274 49157, 98317, 196613, 393241, 786433, 00275 1572869, 3145739, 6291469, 12582917, 25165843, 00276 50331653, 100663319, 201326611, 402653189, 805306457, 00277 1610612741, 0 00278 }; 00279 00280 const size_t *p; 00281 size_t elen = Elements.Length (); 00282 for (p = Primes; *p && *p <= elen; p++) ; 00283 Modulo = *p; 00284 CS_ASSERT (Modulo); 00285 00286 Elements.SetLength(Modulo, csArray<Element>(0, MIN(Modulo / GrowRate, 8))); 00287 00288 for (size_t i = 0; i < elen; i++) 00289 { 00290 csArray<Element>& src = Elements[i]; 00291 size_t slen = src.Length (); 00292 for (size_t j = slen; j > 0; j--) 00293 { 00294 const Element& srcElem = src[j - 1]; 00295 csArray<Element>& dst = 00296 Elements.Get (csHashComputer<K>::ComputeHash (srcElem.key) % Modulo); 00297 if (&src != &dst) 00298 { 00299 dst.Push (srcElem); 00300 src.DeleteIndex (j - 1); 00301 } 00302 } 00303 } 00304 } 00305 00306 public: 00321 csHash (size_t size = 23, size_t grow_rate = 5, size_t max_size = 20000) 00322 : Elements (size), Modulo (size), InitModulo (size), 00323 GrowRate (MIN (grow_rate, size)), MaxSize (max_size), Size (0) 00324 { 00325 Elements.SetLength (size, csArray<Element> (0, MIN (size / GrowRate, 8))); 00326 } 00327 00329 csHash (const csHash<T> &o) : Elements (o.Elements), 00330 Modulo (o.Modulo), InitModulo (o.InitModulo), 00331 GrowRate (o.GrowRate), MaxSize (o.MaxSize), Size (o.Size) {} 00332 00340 void Put (const K& key, const T &value) 00341 { 00342 csArray<Element> &values = 00343 Elements[csHashComputer<K>::ComputeHash (key) % Modulo]; 00344 values.Push (Element (key, value)); 00345 Size++; 00346 if (values.Length () > Elements.Length () / GrowRate 00347 && Elements.Length () < MaxSize) Grow (); 00348 } 00349 00351 csArray<T> GetAll (const K& key) const 00352 { 00353 const csArray<Element> &values = 00354 Elements[csHashComputer<K>::ComputeHash (key) % Modulo]; 00355 csArray<T> ret (values.Length () / 2); 00356 const size_t len = values.Length (); 00357 for (size_t i = 0; i < len; ++i) 00358 { 00359 const Element& v = values[i]; 00360 if (csComparator<K, K>::Compare (v.key, key) == 0) 00361 ret.Push (v.value); 00362 } 00363 return ret; 00364 } 00365 00367 void PutUnique (const K& key, const T &value) 00368 { 00369 csArray<Element> &values = 00370 Elements[csHashComputer<K>::ComputeHash (key) % Modulo]; 00371 const size_t len = values.Length (); 00372 for (size_t i = 0; i < len; ++i) 00373 { 00374 Element& v = values[i]; 00375 if (csComparator<K, K>::Compare (v.key, key) == 0) 00376 { 00377 v.value = value; 00378 return; 00379 } 00380 } 00381 00382 values.Push (Element (key, value)); 00383 Size++; 00384 if (values.Length () > Elements.Length () / GrowRate 00385 && Elements.Length () < MaxSize) Grow (); 00386 } 00387 00392 CS_DEPRECATED_METHOD void PutFirst (const K& key, const T &value) 00393 { 00394 PutUnique(key, value); 00395 } 00396 00398 bool Contains (const K& key) const 00399 { 00400 const csArray<Element> &values = 00401 Elements[csHashComputer<K>::ComputeHash (key) % Modulo]; 00402 const size_t len = values.Length (); 00403 for (size_t i = 0; i < len; ++i) 00404 if (csComparator<K, K>::Compare (values[i].key, key) == 0) 00405 return true; 00406 return false; 00407 } 00408 00414 bool In (const K& key) const 00415 { return Contains(key); } 00416 00421 const T* GetElementPointer (const K& key) const 00422 { 00423 const csArray<Element> &values = 00424 Elements[csHashComputer<K>::ComputeHash (key) % Modulo]; 00425 const size_t len = values.Length (); 00426 for (size_t i = 0; i < len; ++i) 00427 { 00428 const Element& v = values[i]; 00429 if (csComparator<K, K>::Compare (v.key, key) == 0) 00430 return &v.value; 00431 } 00432 00433 return 0; 00434 } 00435 00440 T* GetElementPointer (const K& key) 00441 { 00442 csArray<Element> &values = 00443 Elements[csHashComputer<K>::ComputeHash (key) % Modulo]; 00444 const size_t len = values.Length (); 00445 for (size_t i = 0; i < len; ++i) 00446 { 00447 Element& v = values[i]; 00448 if (csComparator<K, K>::Compare (v.key, key) == 0) 00449 return &v.value; 00450 } 00451 00452 return 0; 00453 } 00454 00459 const T& Get (const K& key, const T& fallback) const 00460 { 00461 const csArray<Element> &values = 00462 Elements[csHashComputer<K>::ComputeHash (key) % Modulo]; 00463 const size_t len = values.Length (); 00464 for (size_t i = 0; i < len; ++i) 00465 { 00466 const Element& v = values[i]; 00467 if (csComparator<K, K>::Compare (v.key, key) == 0) 00468 return v.value; 00469 } 00470 00471 return fallback; 00472 } 00473 00478 T& Get (const K& key, T& fallback) 00479 { 00480 csArray<Element> &values = 00481 Elements[csHashComputer<K>::ComputeHash (key) % Modulo]; 00482 const size_t len = values.Length (); 00483 for (size_t i = 0; i < len; ++i) 00484 { 00485 Element& v = values[i]; 00486 if (csComparator<K, K>::Compare (v.key, key) == 0) 00487 return v.value; 00488 } 00489 00490 return fallback; 00491 } 00492 00494 void DeleteAll () 00495 { 00496 Elements.SetLength (Modulo = InitModulo); 00497 size_t elen = Elements.Length (); 00498 for (size_t i = 0; i < elen; i++) 00499 Elements[i].Empty (); 00500 Size = 0; 00501 } 00502 00504 void Empty() { DeleteAll(); } 00505 00507 bool DeleteAll (const K& key) 00508 { 00509 bool ret = false; 00510 csArray<Element> &values = 00511 Elements[csHashComputer<K>::ComputeHash (key) % Modulo]; 00512 for (size_t i = values.Length (); i > 0; i--) 00513 { 00514 const size_t idx = i - 1; 00515 if (csComparator<K, K>::Compare (values[idx].key, key) == 0) 00516 { 00517 values.DeleteIndexFast (idx); 00518 ret = true; 00519 Size--; 00520 } 00521 } 00522 return ret; 00523 } 00524 00526 bool Delete (const K& key, const T &value) 00527 { 00528 bool ret = false; 00529 csArray<Element> &values = 00530 Elements[csHashComputer<K>::ComputeHash (key) % Modulo]; 00531 for (size_t i = values.Length (); i > 0; i--) 00532 { 00533 const size_t idx = i - 1; 00534 if ((csComparator<K, K>::Compare (values[idx].key, key) == 0) && 00535 (values[idx].value == value)) 00536 { 00537 values.DeleteIndexFast (idx); 00538 ret = true; 00539 Size--; 00540 } 00541 } 00542 return ret; 00543 } 00544 00546 size_t GetSize () const 00547 { 00548 return Size; 00549 } 00550 00556 bool IsEmpty() const 00557 { 00558 return GetSize() == 0; 00559 } 00560 00562 class Iterator 00563 { 00564 private: 00565 const csHash<T, K>* hash; 00566 const K key; 00567 size_t bucket, size, element; 00568 00569 void Seek () 00570 { 00571 while ((element < size) && 00572 (csComparator<K, K>::Compare (hash->Elements[bucket][element].key, 00573 key) != 0)) 00574 element++; 00575 } 00576 00577 protected: 00578 Iterator (const csHash<T, K>* hash0, const K& key0) : 00579 hash(hash0), 00580 key(key0), 00581 bucket(csHashComputer<K>::ComputeHash (key) % hash->Modulo), 00582 size(hash->Elements[bucket].Length ()) 00583 { Reset (); } 00584 00585 friend class csHash<T, K>; 00586 public: 00588 Iterator (const Iterator &o) : 00589 hash (o.hash), 00590 key(o.key), 00591 bucket(o.bucket), 00592 size(o.size), 00593 element(o.element) {} 00594 00596 Iterator& operator=(const Iterator& o) 00597 { 00598 hash = o.hash; 00599 key = o.key; 00600 bucket = o.bucket; 00601 size = o.size; 00602 element = o.element; 00603 return *this; 00604 } 00605 00607 bool HasNext () const 00608 { 00609 return element < size; 00610 } 00611 00613 const T& Next () 00614 { 00615 const T &ret = hash->Elements[bucket][element].value; 00616 element++; 00617 Seek (); 00618 return ret; 00619 } 00620 00622 void Reset () { element = 0; Seek (); } 00623 }; 00624 friend class Iterator; 00625 00627 class GlobalIterator 00628 { 00629 private: 00630 const csHash<T, K> *hash; 00631 size_t bucket, size, element; 00632 00633 void Zero () { bucket = element = 0; } 00634 void Init () { size = hash->Elements[bucket].Length (); } 00635 00636 void FindItem () 00637 { 00638 if (element >= size) 00639 { 00640 while (++bucket < hash->Elements.Length ()) 00641 { 00642 Init (); 00643 if (size != 0) 00644 { 00645 element = 0; 00646 break; 00647 } 00648 } 00649 } 00650 } 00651 00652 protected: 00653 GlobalIterator (const csHash<T, K> *hash0) : hash (hash0) 00654 { 00655 Zero (); 00656 Init (); 00657 FindItem (); 00658 } 00659 00660 friend class csHash<T, K>; 00661 public: 00663 GlobalIterator (const Iterator &o) : 00664 hash (o.hash), 00665 bucket (o.bucket), 00666 size (o.size), 00667 element (o.element) {} 00668 00670 GlobalIterator& operator=(const GlobalIterator& o) 00671 { 00672 hash = o.hash; 00673 bucket = o.bucket; 00674 size = o.size; 00675 element = o.element; 00676 return *this; 00677 } 00678 00680 bool HasNext () const 00681 { 00682 if (hash->Elements.Length () == 0) return false; 00683 return element < size || bucket < hash->Elements.Length (); 00684 } 00685 00687 void Advance () 00688 { 00689 element++; 00690 FindItem (); 00691 } 00692 00694 const T& NextNoAdvance () 00695 { 00696 return hash->Elements[bucket][element].value; 00697 } 00698 00700 const T& Next () 00701 { 00702 const T &ret = NextNoAdvance (); 00703 Advance (); 00704 return ret; 00705 } 00706 00708 const T& NextNoAdvance (K &key) 00709 { 00710 key = hash->Elements[bucket][element].key; 00711 return NextNoAdvance (); 00712 } 00713 00715 const T& Next (K &key) 00716 { 00717 key = hash->Elements[bucket][element].key; 00718 return Next (); 00719 } 00720 00722 void Reset () { Zero (); Init (); FindItem (); } 00723 }; 00724 friend class GlobalIterator; 00725 00728 void DeleteElement (GlobalIterator& iterator) 00729 { 00730 Elements[iterator.bucket].DeleteIndex(iterator.element); 00731 Size--; 00732 iterator.size--; 00733 iterator.FindItem (); 00734 } 00735 00742 Iterator GetIterator (const K& key) const 00743 { 00744 return Iterator (this, key); 00745 } 00746 00752 GlobalIterator GetIterator () const 00753 { 00754 return GlobalIterator (this); 00755 } 00756 }; 00757 00760 #endif
Generated for Crystal Space by doxygen 1.4.4