From f2e5e604fb671a1b86a942ea9bb480c03b5efa9d Mon Sep 17 00:00:00 2001 From: KUDr Date: Sat, 13 Jan 2007 13:33:36 +0000 Subject: (svn r8092) -Codechange: header files with miscellaneous template classes (smart pointers, blob, array, hashtable, etc.) moved from src/yapf to src/misc as they can now be used anywhere. --- src/misc/hashtable.hpp | 240 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 240 insertions(+) create mode 100644 src/misc/hashtable.hpp (limited to 'src/misc/hashtable.hpp') diff --git a/src/misc/hashtable.hpp b/src/misc/hashtable.hpp new file mode 100644 index 000000000..c6b52e50a --- /dev/null +++ b/src/misc/hashtable.hpp @@ -0,0 +1,240 @@ +/* $Id$ */ + +#ifndef HASHTABLE_HPP +#define HASHTABLE_HPP + +template +struct CHashTableSlotT +{ + typedef typename Titem_::Key Key; // make Titem_::Key a property of HashTable + + Titem_* m_pFirst; + + CHashTableSlotT() : m_pFirst(NULL) {} + + /** hash table slot helper - clears the slot by simple forgetting its items */ + FORCEINLINE void Clear() {m_pFirst = NULL;} + + /** hash table slot helper - linear search for item with given key through the given blob - const version */ + FORCEINLINE const Titem_* Find(const Key& key) const + { + for (const Titem_* pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) { + if (pItem->GetKey() == key) { + // we have found the item, return it + return pItem; + } + } + return NULL; + } + + /** hash table slot helper - linear search for item with given key through the given blob - non-const version */ + FORCEINLINE Titem_* Find(const Key& key) + { + for (Titem_* pItem = m_pFirst; pItem != NULL; pItem = pItem->GetHashNext()) { + if (pItem->GetKey() == key) { + // we have found the item, return it + return pItem; + } + } + return NULL; + } + + /** hash table slot helper - add new item to the slot */ + FORCEINLINE void Attach(Titem_& new_item) + { + assert(new_item.GetHashNext() == NULL); + new_item.SetHashNext(m_pFirst); + m_pFirst = &new_item; + } + + /** hash table slot helper - remove item from a slot */ + FORCEINLINE bool Detach(Titem_& item_to_remove) + { + if (m_pFirst == &item_to_remove) { + m_pFirst = item_to_remove.GetHashNext(); + item_to_remove.SetHashNext(NULL); + return true; + } + Titem_* pItem = m_pFirst; + while (true) { + if (pItem == NULL) { + return false; + } + Titem_* pNextItem = pItem->GetHashNext(); + if (pNextItem == &item_to_remove) break; + pItem = pNextItem; + } + pItem->SetHashNext(item_to_remove.GetHashNext()); + item_to_remove.SetHashNext(NULL); + return true; + } + + /** hash table slot helper - remove and return item from a slot */ + FORCEINLINE Titem_* Detach(const Key& key) + { + // do we have any items? + if (m_pFirst == NULL) { + return NULL; + } + // is it our first item? + if (m_pFirst->GetKey() == key) { + Titem_& ret_item = *m_pFirst; + m_pFirst = m_pFirst->GetHashNext(); + ret_item.SetHashNext(NULL); + return &ret_item; + } + // find it in the following items + Titem_* pPrev = m_pFirst; + for (Titem_* pItem = m_pFirst->GetHashNext(); pItem != NULL; pPrev = pItem, pItem = pItem->GetHashNext()) { + if (pItem->GetKey() == key) { + // we have found the item, unlink and return it + pPrev->SetHashNext(pItem->GetHashNext()); + pItem->SetHashNext(NULL); + return pItem; + } + } + return NULL; + } +}; + +/** @class CHashTableT - simple hash table + * of pointers allocated elsewhere. + * + * Supports: Add/Find/Remove of Titems. + * + * Your Titem must meet some extra requirements to be CHashTableT + * compliant: + * - its constructor/destructor (if any) must be public + * - if the copying of item requires an extra resource management, + * you must define also copy constructor + * - must support nested type (struct, class or typedef) Titem::Key + * that defines the type of key class for that item + * - must support public method: + * const Key& GetKey() const; // return the item's key object + * + * In addition, the Titem::Key class must support: + * - public method that calculates key's hash: + * int CalcHash() const; + * - public 'equality' operator to compare the key with another one + * bool operator == (const Key& other) const; + */ +template +class CHashTableT { +public: + typedef Titem_ Titem; // make Titem_ visible from outside of class + typedef typename Titem_::Key Tkey; // make Titem_::Key a property of HashTable + static const int Thash_bits = Thash_bits_; // publish num of hash bits + static const int Tcapacity = 1 << Thash_bits; // and num of slots 2^bits + +protected: + /** each slot contains pointer to the first item in the list, + * Titem contains pointer to the next item - GetHashNext(), SetHashNext() */ + typedef CHashTableSlotT Slot; + + Slot* m_slots; // here we store our data (array of blobs) + int m_num_items; // item counter + +public: + // default constructor + FORCEINLINE CHashTableT() + { + // construct all slots + m_slots = new Slot[Tcapacity]; + m_num_items = 0; + } + + ~CHashTableT() {delete [] m_slots; m_num_items = 0; m_slots = NULL;} + +protected: + /** static helper - return hash for the given key modulo number of slots */ + FORCEINLINE static int CalcHash(const Tkey& key) + { + int32 hash = key.CalcHash(); + if ((8 * Thash_bits) < 32) hash ^= hash >> (min(8 * Thash_bits, 31)); + if ((4 * Thash_bits) < 32) hash ^= hash >> (min(4 * Thash_bits, 31)); + if ((2 * Thash_bits) < 32) hash ^= hash >> (min(2 * Thash_bits, 31)); + if ((1 * Thash_bits) < 32) hash ^= hash >> (min(1 * Thash_bits, 31)); + hash &= (1 << Thash_bits) - 1; + return hash; + } + + /** static helper - return hash for the given item modulo number of slots */ + FORCEINLINE static int CalcHash(const Titem_& item) {return CalcHash(item.GetKey());} + +public: + /** item count */ + FORCEINLINE int Count() const {return m_num_items;} + + /** simple clear - forget all items - used by CSegmentCostCacheT.Flush() */ + FORCEINLINE void Clear() const {for (int i = 0; i < Tcapacity; i++) m_slots[i].Clear();} + + /** const item search */ + const Titem_* Find(const Tkey& key) const + { + int hash = CalcHash(key); + const Slot& slot = m_slots[hash]; + const Titem_* item = slot.Find(key); + return item; + } + + /** non-const item search */ + Titem_* Find(const Tkey& key) + { + int hash = CalcHash(key); + Slot& slot = m_slots[hash]; + Titem_* item = slot.Find(key); + return item; + } + + /** non-const item search & optional removal (if found) */ + Titem_* TryPop(const Tkey& key) + { + int hash = CalcHash(key); + Slot& slot = m_slots[hash]; + Titem_* item = slot.Detach(key); + if (item != NULL) { + m_num_items--; + } + return item; + } + + /** non-const item search & removal */ + Titem_& Pop(const Tkey& key) + { + Titem_* item = TryPop(key); + assert(item != NULL); + return *item; + } + + /** non-const item search & optional removal (if found) */ + bool TryPop(Titem_& item) + { + const Tkey& key = item.GetKey(); + int hash = CalcHash(key); + Slot& slot = m_slots[hash]; + bool ret = slot.Detach(item); + if (ret) { + m_num_items--; + } + return ret; + } + + /** non-const item search & removal */ + void Pop(Titem_& item) + { + bool ret = TryPop(item); + assert(ret); + } + + /** add one item - copy it from the given item */ + void Push(Titem_& new_item) + { + int hash = CalcHash(new_item); + Slot& slot = m_slots[hash]; + assert(slot.Find(new_item.GetKey()) == NULL); + slot.Attach(new_item); + m_num_items++; + } +}; + +#endif /* HASHTABLE_HPP */ -- cgit v1.2.3-54-g00ecf