hashtable.hpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #ifndef  HASHTABLE_HPP
00013 #define  HASHTABLE_HPP
00014 
00015 template <class Titem_>
00016 struct CHashTableSlotT
00017 {
00018   typedef typename Titem_::Key Key;          // make Titem_::Key a property of HashTable
00019 
00020   Titem_ *m_pFirst;
00021 
00022   FORCEINLINE CHashTableSlotT() : m_pFirst(NULL) {}
00023 
00025   FORCEINLINE void Clear() {m_pFirst = NULL;}
00026 
00028   FORCEINLINE const Titem_ *Find(const Key& key) const
00029   {
00030     for (const Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) {
00031       if (pItem->GetKey() == key) {
00032         /* we have found the item, return it */
00033         return pItem;
00034       }
00035     }
00036     return NULL;
00037   }
00038 
00040   FORCEINLINE Titem_ *Find(const Key& key)
00041   {
00042     for (Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) {
00043       if (pItem->GetKey() == key) {
00044         /* we have found the item, return it */
00045         return pItem;
00046       }
00047     }
00048     return NULL;
00049   }
00050 
00052   FORCEINLINE void Attach(Titem_& new_item)
00053   {
00054     assert(new_item.GetHashNext() == NULL);
00055     new_item.SetHashNext(m_pFirst);
00056     m_pFirst = &new_item;
00057   }
00058 
00060   FORCEINLINE bool Detach(Titem_& item_to_remove)
00061   {
00062     if (m_pFirst == &item_to_remove) {
00063       m_pFirst = item_to_remove.GetHashNext();
00064       item_to_remove.SetHashNext(NULL);
00065       return true;
00066     }
00067     Titem_ *pItem = m_pFirst;
00068     while (true) {
00069       if (pItem == NULL) {
00070         return false;
00071       }
00072       Titem_ *pNextItem = pItem->GetHashNext();
00073       if (pNextItem == &item_to_remove) break;
00074       pItem = pNextItem;
00075     }
00076     pItem->SetHashNext(item_to_remove.GetHashNext());
00077     item_to_remove.SetHashNext(NULL);
00078     return true;
00079   }
00080 
00082   FORCEINLINE Titem_ *Detach(const Key& key)
00083   {
00084     /* do we have any items? */
00085     if (m_pFirst == NULL) {
00086       return NULL;
00087     }
00088     /* is it our first item? */
00089     if (m_pFirst->GetKey() == key) {
00090       Titem_& ret_item = *m_pFirst;
00091       m_pFirst = m_pFirst->GetHashNext();
00092       ret_item.SetHashNext(NULL);
00093       return &ret_item;
00094     }
00095     /* find it in the following items */
00096     Titem_ *pPrev = m_pFirst;
00097     for (Titem_ *pItem = m_pFirst->GetHashNext(); pItem != NULL; pPrev = pItem, pItem = pItem->GetHashNext()) {
00098       if (pItem->GetKey() == key) {
00099         /* we have found the item, unlink and return it */
00100         pPrev->SetHashNext(pItem->GetHashNext());
00101         pItem->SetHashNext(NULL);
00102         return pItem;
00103       }
00104     }
00105     return NULL;
00106   }
00107 };
00108 
00130 template <class Titem_, int Thash_bits_>
00131 class CHashTableT {
00132 public:
00133   typedef Titem_ Titem;                         // make Titem_ visible from outside of class
00134   typedef typename Titem_::Key Tkey;            // make Titem_::Key a property of HashTable
00135   static const int Thash_bits = Thash_bits_;    // publish num of hash bits
00136   static const int Tcapacity = 1 << Thash_bits; // and num of slots 2^bits
00137 
00138 protected:
00141   typedef CHashTableSlotT<Titem_> Slot;
00142 
00143   Slot *m_slots;     // here we store our data (array of blobs)
00144   int   m_num_items; // item counter
00145 
00146 public:
00147   /* default constructor */
00148   FORCEINLINE CHashTableT()
00149   {
00150     /* construct all slots */
00151     m_slots = new Slot[Tcapacity];
00152     m_num_items = 0;
00153   }
00154 
00155   ~CHashTableT() {delete [] m_slots; m_num_items = 0; m_slots = NULL;}
00156 
00157 protected:
00159   FORCEINLINE static int CalcHash(const Tkey& key)
00160   {
00161     int32 hash = key.CalcHash();
00162     if ((8 * Thash_bits) < 32) hash ^= hash >> (min(8 * Thash_bits, 31));
00163     if ((4 * Thash_bits) < 32) hash ^= hash >> (min(4 * Thash_bits, 31));
00164     if ((2 * Thash_bits) < 32) hash ^= hash >> (min(2 * Thash_bits, 31));
00165     if ((1 * Thash_bits) < 32) hash ^= hash >> (min(1 * Thash_bits, 31));
00166     hash &= (1 << Thash_bits) - 1;
00167     return hash;
00168   }
00169 
00171   FORCEINLINE static int CalcHash(const Titem_& item) {return CalcHash(item.GetKey());}
00172 
00173 public:
00175   FORCEINLINE int Count() const {return m_num_items;}
00176 
00178   FORCEINLINE void Clear() const {for (int i = 0; i < Tcapacity; i++) m_slots[i].Clear();}
00179 
00181   const Titem_ *Find(const Tkey& key) const
00182   {
00183     int hash = CalcHash(key);
00184     const Slot& slot = m_slots[hash];
00185     const Titem_ *item = slot.Find(key);
00186     return item;
00187   }
00188 
00190   Titem_ *Find(const Tkey& key)
00191   {
00192     int hash = CalcHash(key);
00193     Slot& slot = m_slots[hash];
00194     Titem_ *item = slot.Find(key);
00195     return item;
00196   }
00197 
00199   Titem_ *TryPop(const Tkey& key)
00200   {
00201     int hash = CalcHash(key);
00202     Slot& slot = m_slots[hash];
00203     Titem_ *item = slot.Detach(key);
00204     if (item != NULL) {
00205       m_num_items--;
00206     }
00207     return item;
00208   }
00209 
00211   Titem_& Pop(const Tkey& key)
00212   {
00213     Titem_ *item = TryPop(key);
00214     assert(item != NULL);
00215     return *item;
00216   }
00217 
00219   bool TryPop(Titem_& item)
00220   {
00221     const Tkey& key = item.GetKey();
00222     int hash = CalcHash(key);
00223     Slot& slot = m_slots[hash];
00224     bool ret = slot.Detach(item);
00225     if (ret) {
00226       m_num_items--;
00227     }
00228     return ret;
00229   }
00230 
00232   void Pop(Titem_& item)
00233   {
00234     bool ret = TryPop(item);
00235     assert(ret);
00236   }
00237 
00239   void Push(Titem_& new_item)
00240   {
00241     int hash = CalcHash(new_item);
00242     Slot& slot = m_slots[hash];
00243     assert(slot.Find(new_item.GetKey()) == NULL);
00244     slot.Attach(new_item);
00245     m_num_items++;
00246   }
00247 };
00248 
00249 #endif /* HASHTABLE_HPP */

Generated on Wed Dec 30 20:40:03 2009 for OpenTTD by  doxygen 1.5.6