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 #include "../core/math_func.hpp"
00016 
00017 template <class Titem_>
00018 struct CHashTableSlotT
00019 {
00020   typedef typename Titem_::Key Key;          // make Titem_::Key a property of HashTable
00021 
00022   Titem_ *m_pFirst;
00023 
00024   FORCEINLINE CHashTableSlotT() : m_pFirst(NULL) {}
00025 
00027   FORCEINLINE void Clear() {m_pFirst = NULL;}
00028 
00030   FORCEINLINE const Titem_ *Find(const Key& key) const
00031   {
00032     for (const Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) {
00033       if (pItem->GetKey() == key) {
00034         /* we have found the item, return it */
00035         return pItem;
00036       }
00037     }
00038     return NULL;
00039   }
00040 
00042   FORCEINLINE Titem_ *Find(const Key& key)
00043   {
00044     for (Titem_ *pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) {
00045       if (pItem->GetKey() == key) {
00046         /* we have found the item, return it */
00047         return pItem;
00048       }
00049     }
00050     return NULL;
00051   }
00052 
00054   FORCEINLINE void Attach(Titem_& new_item)
00055   {
00056     assert(new_item.GetHashNext() == NULL);
00057     new_item.SetHashNext(m_pFirst);
00058     m_pFirst = &new_item;
00059   }
00060 
00062   FORCEINLINE bool Detach(Titem_& item_to_remove)
00063   {
00064     if (m_pFirst == &item_to_remove) {
00065       m_pFirst = item_to_remove.GetHashNext();
00066       item_to_remove.SetHashNext(NULL);
00067       return true;
00068     }
00069     Titem_ *pItem = m_pFirst;
00070     for (;;) {
00071       if (pItem == NULL) {
00072         return false;
00073       }
00074       Titem_ *pNextItem = pItem->GetHashNext();
00075       if (pNextItem == &item_to_remove) break;
00076       pItem = pNextItem;
00077     }
00078     pItem->SetHashNext(item_to_remove.GetHashNext());
00079     item_to_remove.SetHashNext(NULL);
00080     return true;
00081   }
00082 
00084   FORCEINLINE Titem_ *Detach(const Key& key)
00085   {
00086     /* do we have any items? */
00087     if (m_pFirst == NULL) {
00088       return NULL;
00089     }
00090     /* is it our first item? */
00091     if (m_pFirst->GetKey() == key) {
00092       Titem_& ret_item = *m_pFirst;
00093       m_pFirst = m_pFirst->GetHashNext();
00094       ret_item.SetHashNext(NULL);
00095       return &ret_item;
00096     }
00097     /* find it in the following items */
00098     Titem_ *pPrev = m_pFirst;
00099     for (Titem_ *pItem = m_pFirst->GetHashNext(); pItem != NULL; pPrev = pItem, pItem = pItem->GetHashNext()) {
00100       if (pItem->GetKey() == key) {
00101         /* we have found the item, unlink and return it */
00102         pPrev->SetHashNext(pItem->GetHashNext());
00103         pItem->SetHashNext(NULL);
00104         return pItem;
00105       }
00106     }
00107     return NULL;
00108   }
00109 };
00110 
00133 template <class Titem_, int Thash_bits_>
00134 class CHashTableT {
00135 public:
00136   typedef Titem_ Titem;                         // make Titem_ visible from outside of class
00137   typedef typename Titem_::Key Tkey;            // make Titem_::Key a property of HashTable
00138   static const int Thash_bits = Thash_bits_;    // publish num of hash bits
00139   static const int Tcapacity = 1 << Thash_bits; // and num of slots 2^bits
00140 
00141 protected:
00146   typedef CHashTableSlotT<Titem_> Slot;
00147 
00148   Slot  m_slots[Tcapacity]; // here we store our data (array of blobs)
00149   int   m_num_items;        // item counter
00150 
00151 public:
00152   /* default constructor */
00153   FORCEINLINE CHashTableT() : m_num_items(0)
00154   {
00155   }
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() {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 Mon May 9 05:18:54 2011 for OpenTTD by  doxygen 1.6.1