KUDr@5633: /* $Id$ */ KUDr@5633: belugas@6481: /** @file hashtable.hpp */ belugas@6481: KUDr@5633: #ifndef HASHTABLE_HPP KUDr@5633: #define HASHTABLE_HPP KUDr@5633: KUDr@5633: template KUDr@5633: struct CHashTableSlotT KUDr@5633: { KUDr@5633: typedef typename Titem_::Key Key; // make Titem_::Key a property of HashTable KUDr@5633: KUDr@5633: Titem_* m_pFirst; KUDr@5633: KUDr@5633: CHashTableSlotT() : m_pFirst(NULL) {} KUDr@5633: KUDr@5633: /** hash table slot helper - clears the slot by simple forgetting its items */ KUDr@5633: FORCEINLINE void Clear() {m_pFirst = NULL;} KUDr@5633: KUDr@5633: /** hash table slot helper - linear search for item with given key through the given blob - const version */ KUDr@5633: FORCEINLINE const Titem_* Find(const Key& key) const KUDr@5633: { KUDr@5633: for (const Titem_* pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) { KUDr@5633: if (pItem->GetKey() == key) { KUDr@5633: // we have found the item, return it KUDr@5633: return pItem; KUDr@5633: } KUDr@5633: } KUDr@5633: return NULL; KUDr@5633: } KUDr@5633: KUDr@5633: /** hash table slot helper - linear search for item with given key through the given blob - non-const version */ KUDr@5633: FORCEINLINE Titem_* Find(const Key& key) KUDr@5633: { KUDr@5633: for (Titem_* pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) { KUDr@5633: if (pItem->GetKey() == key) { KUDr@5633: // we have found the item, return it KUDr@5633: return pItem; KUDr@5633: } KUDr@5633: } KUDr@5633: return NULL; KUDr@5633: } KUDr@5633: KUDr@5633: /** hash table slot helper - add new item to the slot */ KUDr@5633: FORCEINLINE void Attach(Titem_& new_item) KUDr@5633: { KUDr@5633: assert(new_item.GetHashNext() == NULL); KUDr@5633: new_item.SetHashNext(m_pFirst); KUDr@5633: m_pFirst = &new_item; KUDr@5633: } KUDr@5633: KUDr@5633: /** hash table slot helper - remove item from a slot */ KUDr@5633: FORCEINLINE bool Detach(Titem_& item_to_remove) KUDr@5633: { KUDr@5633: if (m_pFirst == &item_to_remove) { KUDr@5633: m_pFirst = item_to_remove.GetHashNext(); KUDr@5633: item_to_remove.SetHashNext(NULL); KUDr@5633: return true; KUDr@5633: } KUDr@5633: Titem_* pItem = m_pFirst; KUDr@5633: while (true) { KUDr@5633: if (pItem == NULL) { KUDr@5633: return false; KUDr@5633: } KUDr@5633: Titem_* pNextItem = pItem->GetHashNext(); KUDr@5633: if (pNextItem == &item_to_remove) break; KUDr@5633: pItem = pNextItem; KUDr@5633: } KUDr@5633: pItem->SetHashNext(item_to_remove.GetHashNext()); KUDr@5633: item_to_remove.SetHashNext(NULL); KUDr@5633: return true; KUDr@5633: } KUDr@5633: KUDr@5633: /** hash table slot helper - remove and return item from a slot */ KUDr@5633: FORCEINLINE Titem_* Detach(const Key& key) KUDr@5633: { KUDr@5633: // do we have any items? KUDr@5633: if (m_pFirst == NULL) { KUDr@5633: return NULL; KUDr@5633: } KUDr@5633: // is it our first item? KUDr@5633: if (m_pFirst->GetKey() == key) { KUDr@5633: Titem_& ret_item = *m_pFirst; KUDr@5633: m_pFirst = m_pFirst->GetHashNext(); KUDr@5633: ret_item.SetHashNext(NULL); KUDr@5633: return &ret_item; KUDr@5633: } KUDr@5633: // find it in the following items KUDr@5633: Titem_* pPrev = m_pFirst; KUDr@5633: for (Titem_* pItem = m_pFirst->GetHashNext(); pItem != NULL; pPrev = pItem, pItem = pItem->GetHashNext()) { KUDr@5633: if (pItem->GetKey() == key) { KUDr@5633: // we have found the item, unlink and return it KUDr@5633: pPrev->SetHashNext(pItem->GetHashNext()); KUDr@5633: pItem->SetHashNext(NULL); KUDr@5633: return pItem; KUDr@5633: } KUDr@5633: } KUDr@5633: return NULL; KUDr@5633: } KUDr@5633: }; KUDr@5633: belugas@6481: /** class CHashTableT - simple hash table KUDr@5633: * of pointers allocated elsewhere. KUDr@5633: * KUDr@5633: * Supports: Add/Find/Remove of Titems. KUDr@5633: * KUDr@5633: * Your Titem must meet some extra requirements to be CHashTableT KUDr@5633: * compliant: KUDr@5633: * - its constructor/destructor (if any) must be public KUDr@5633: * - if the copying of item requires an extra resource management, KUDr@5633: * you must define also copy constructor KUDr@5633: * - must support nested type (struct, class or typedef) Titem::Key KUDr@5633: * that defines the type of key class for that item KUDr@5633: * - must support public method: KUDr@5633: * const Key& GetKey() const; // return the item's key object KUDr@5633: * KUDr@5633: * In addition, the Titem::Key class must support: KUDr@5633: * - public method that calculates key's hash: KUDr@5633: * int CalcHash() const; KUDr@5633: * - public 'equality' operator to compare the key with another one KUDr@5633: * bool operator == (const Key& other) const; KUDr@5633: */ KUDr@5633: template KUDr@5633: class CHashTableT { KUDr@5633: public: KUDr@5633: typedef Titem_ Titem; // make Titem_ visible from outside of class KUDr@5633: typedef typename Titem_::Key Tkey; // make Titem_::Key a property of HashTable KUDr@5633: static const int Thash_bits = Thash_bits_; // publish num of hash bits KUDr@5633: static const int Tcapacity = 1 << Thash_bits; // and num of slots 2^bits KUDr@5633: KUDr@5633: protected: KUDr@5633: /** each slot contains pointer to the first item in the list, KUDr@5633: * Titem contains pointer to the next item - GetHashNext(), SetHashNext() */ KUDr@5633: typedef CHashTableSlotT Slot; KUDr@5633: KUDr@5633: Slot* m_slots; // here we store our data (array of blobs) KUDr@5633: int m_num_items; // item counter KUDr@5633: KUDr@5633: public: KUDr@5633: // default constructor KUDr@5633: FORCEINLINE CHashTableT() KUDr@5633: { KUDr@5633: // construct all slots KUDr@5633: m_slots = new Slot[Tcapacity]; KUDr@5633: m_num_items = 0; KUDr@5633: } KUDr@5633: KUDr@5633: ~CHashTableT() {delete [] m_slots; m_num_items = 0; m_slots = NULL;} KUDr@5633: KUDr@5633: protected: KUDr@5633: /** static helper - return hash for the given key modulo number of slots */ KUDr@5633: FORCEINLINE static int CalcHash(const Tkey& key) KUDr@5633: { KUDr@5633: int32 hash = key.CalcHash(); KUDr@5633: if ((8 * Thash_bits) < 32) hash ^= hash >> (min(8 * Thash_bits, 31)); KUDr@5633: if ((4 * Thash_bits) < 32) hash ^= hash >> (min(4 * Thash_bits, 31)); KUDr@5633: if ((2 * Thash_bits) < 32) hash ^= hash >> (min(2 * Thash_bits, 31)); KUDr@5633: if ((1 * Thash_bits) < 32) hash ^= hash >> (min(1 * Thash_bits, 31)); KUDr@5633: hash &= (1 << Thash_bits) - 1; KUDr@5633: return hash; KUDr@5633: } KUDr@5633: KUDr@5633: /** static helper - return hash for the given item modulo number of slots */ KUDr@5633: FORCEINLINE static int CalcHash(const Titem_& item) {return CalcHash(item.GetKey());} KUDr@5633: KUDr@5633: public: KUDr@5633: /** item count */ KUDr@5633: FORCEINLINE int Count() const {return m_num_items;} KUDr@5633: KUDr@5633: /** simple clear - forget all items - used by CSegmentCostCacheT.Flush() */ KUDr@5633: FORCEINLINE void Clear() const {for (int i = 0; i < Tcapacity; i++) m_slots[i].Clear();} KUDr@5633: KUDr@5633: /** const item search */ KUDr@5633: const Titem_* Find(const Tkey& key) const KUDr@5633: { KUDr@5633: int hash = CalcHash(key); KUDr@5633: const Slot& slot = m_slots[hash]; KUDr@5633: const Titem_* item = slot.Find(key); KUDr@5633: return item; KUDr@5633: } KUDr@5633: KUDr@5633: /** non-const item search */ KUDr@5633: Titem_* Find(const Tkey& key) KUDr@5633: { KUDr@5633: int hash = CalcHash(key); KUDr@5633: Slot& slot = m_slots[hash]; KUDr@5633: Titem_* item = slot.Find(key); KUDr@5633: return item; KUDr@5633: } KUDr@5633: KUDr@5633: /** non-const item search & optional removal (if found) */ KUDr@5633: Titem_* TryPop(const Tkey& key) KUDr@5633: { KUDr@5633: int hash = CalcHash(key); KUDr@5633: Slot& slot = m_slots[hash]; KUDr@5633: Titem_* item = slot.Detach(key); KUDr@5633: if (item != NULL) { KUDr@5633: m_num_items--; KUDr@5633: } KUDr@5633: return item; KUDr@5633: } KUDr@5633: KUDr@5633: /** non-const item search & removal */ KUDr@5633: Titem_& Pop(const Tkey& key) KUDr@5633: { KUDr@5633: Titem_* item = TryPop(key); KUDr@5633: assert(item != NULL); KUDr@5633: return *item; KUDr@5633: } KUDr@5633: KUDr@5633: /** non-const item search & optional removal (if found) */ KUDr@5633: bool TryPop(Titem_& item) KUDr@5633: { KUDr@5633: const Tkey& key = item.GetKey(); KUDr@5633: int hash = CalcHash(key); KUDr@5633: Slot& slot = m_slots[hash]; KUDr@5633: bool ret = slot.Detach(item); KUDr@5633: if (ret) { KUDr@5633: m_num_items--; KUDr@5633: } KUDr@5633: return ret; KUDr@5633: } KUDr@5633: KUDr@5633: /** non-const item search & removal */ KUDr@5633: void Pop(Titem_& item) KUDr@5633: { KUDr@5633: bool ret = TryPop(item); KUDr@5633: assert(ret); KUDr@5633: } KUDr@5633: KUDr@5633: /** add one item - copy it from the given item */ KUDr@5633: void Push(Titem_& new_item) KUDr@5633: { KUDr@5633: int hash = CalcHash(new_item); KUDr@5633: Slot& slot = m_slots[hash]; KUDr@5633: assert(slot.Find(new_item.GetKey()) == NULL); KUDr@5633: slot.Attach(new_item); KUDr@5633: m_num_items++; KUDr@5633: } KUDr@5633: }; KUDr@5633: KUDr@5633: #endif /* HASHTABLE_HPP */