# 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   inline CHashTableSlotT() : m_pFirst(NULL) {}
    00025
    00027   inline void Clear() {m_pFirst = NULL;}
    00028
    00030   inline 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   inline 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   inline 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   inline 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   inline 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   inline CHashTableT() : m_num_items(0)
    00154   {
    00155   }
    00156
    00157 protected:
    00159   inline 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   inline static int CalcHash(const Titem_& item) {return CalcHash(item.GetKey());}
    00172
    00173 public:
    00175   inline int Count() const {return m_num_items;}
    00176
    00178   inline 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 */