hashtable.hpp

Go to the documentation of this file.
00001 /* $Id: hashtable.hpp 21594 2010-12-22 11:24:38Z alberth $ */
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     while (true) {
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;     // here we store our data (array of blobs)
00149   int   m_num_items; // item counter
00150 
00151 public:
00152   /* default constructor */
00153   FORCEINLINE CHashTableT()
00154   {
00155     /* construct all slots */
00156     m_slots = new Slot[Tcapacity];
00157     m_num_items = 0;
00158   }
00159 
00160   ~CHashTableT() {delete [] m_slots; m_num_items = 0; m_slots = NULL;}
00161 
00162 protected:
00164   FORCEINLINE static int CalcHash(const Tkey& key)
00165   {
00166     int32 hash = key.CalcHash();
00167     if ((8 * Thash_bits) < 32) hash ^= hash >> (min(8 * Thash_bits, 31));
00168     if ((4 * Thash_bits) < 32) hash ^= hash >> (min(4 * Thash_bits, 31));
00169     if ((2 * Thash_bits) < 32) hash ^= hash >> (min(2 * Thash_bits, 31));
00170     if ((1 * Thash_bits) < 32) hash ^= hash >> (min(1 * Thash_bits, 31));
00171     hash &= (1 << Thash_bits) - 1;
00172     return hash;
00173   }
00174 
00176   FORCEINLINE static int CalcHash(const Titem_& item) {return CalcHash(item.GetKey());}
00177 
00178 public:
00180   FORCEINLINE int Count() const {return m_num_items;}
00181 
00183   FORCEINLINE void Clear() const {for (int i = 0; i < Tcapacity; i++) m_slots[i].Clear();}
00184 
00186   const Titem_ *Find(const Tkey& key) const
00187   {
00188     int hash = CalcHash(key);
00189     const Slot& slot = m_slots[hash];
00190     const Titem_ *item = slot.Find(key);
00191     return item;
00192   }
00193 
00195   Titem_ *Find(const Tkey& key)
00196   {
00197     int hash = CalcHash(key);
00198     Slot& slot = m_slots[hash];
00199     Titem_ *item = slot.Find(key);
00200     return item;
00201   }
00202 
00204   Titem_ *TryPop(const Tkey& key)
00205   {
00206     int hash = CalcHash(key);
00207     Slot& slot = m_slots[hash];
00208     Titem_ *item = slot.Detach(key);
00209     if (item != NULL) {
00210       m_num_items--;
00211     }
00212     return item;
00213   }
00214 
00216   Titem_& Pop(const Tkey& key)
00217   {
00218     Titem_ *item = TryPop(key);
00219     assert(item != NULL);
00220     return *item;
00221   }
00222 
00224   bool TryPop(Titem_& item)
00225   {
00226     const Tkey& key = item.GetKey();
00227     int hash = CalcHash(key);
00228     Slot& slot = m_slots[hash];
00229     bool ret = slot.Detach(item);
00230     if (ret) {
00231       m_num_items--;
00232     }
00233     return ret;
00234   }
00235 
00237   void Pop(Titem_& item)
00238   {
00239     bool ret = TryPop(item);
00240     assert(ret);
00241   }
00242 
00244   void Push(Titem_& new_item)
00245   {
00246     int hash = CalcHash(new_item);
00247     Slot& slot = m_slots[hash];
00248     assert(slot.Find(new_item.GetKey()) == NULL);
00249     slot.Attach(new_item);
00250     m_num_items++;
00251   }
00252 };
00253 
00254 #endif /* HASHTABLE_HPP */

Generated on Fri Feb 4 20:53:41 2011 for OpenTTD by  doxygen 1.6.1