/*************************************************************************/ /* File : XSHashTable.h */ /* Author : Aymeric Bard */ /* */ /* Virtools SDK */ /* Copyright (c) Virtools 2000, All Rights Reserved. */ /*************************************************************************/ #ifndef _XSHashTable_H_ #define _XSHashTable_H_ #include "XArray.h" #include "XHashFun.h" template class XSHashTable; #define STATUS_FREE 0 #define STATUS_OCCUPIED 1 #define STATUS_DELETED 2 template class XSHashTableEntry { typedef XSHashTableEntry* pEntry; public: XSHashTableEntry():m_Status(STATUS_FREE) {} XSHashTableEntry(const XSHashTableEntry& e) : m_Key(e.m_Key),m_Data(e.m_Data),m_Status(STATUS_OCCUPIED) {} ~XSHashTableEntry() {} void Set(const K& key, const T& data) { m_Key = key; m_Data = data; m_Status = STATUS_OCCUPIED; } K m_Key; T m_Data; int m_Status; }; /************************************************ Summary: Iterator on a hash table. Remarks: This iterator is the only way to iterate on elements in a hash table. The iteration will be in no specific order, not in the insertion order. Here is an example of how to use it: Example: XSHashTableIt it = hashtable.Begin(); while (it != hashtable.End()) { // access to the key it.GetKey(); // access to the element *it; // next element ++it; } ************************************************/ template , class Eq = XEqual > class XSHashTableIt { typedef XSHashTableEntry* pEntry; typedef XSHashTableIt tIterator; typedef XSHashTable* tTable; friend class XSHashTable; public: /************************************************ Summary: Default constructor of the iterator. ************************************************/ XSHashTableIt():m_Node(0),m_Table(0){} /************************************************ Summary: Copy constructor of the iterator. ************************************************/ XSHashTableIt(const tIterator& n):m_Node(n.m_Node),m_Table(n.m_Table){} /************************************************ Summary: Operator Equal of the iterator. ************************************************/ int operator==(const tIterator& it) const { return m_Node == it.m_Node; } /************************************************ Summary: Operator Equal of the iterator. ************************************************/ int operator!=(const tIterator& it) const { return m_Node != it.m_Node; } /************************************************ Summary: Returns a constant reference on the data pointed by the iterator. Remarks: The returned reference is constant, so you can't modify its value. Use the other * operator for this purpose. ************************************************/ const T& operator*() const { return (*m_Node).m_Data; } /************************************************ Summary: Returns a reference on the data pointed by the iterator. Remarks: The returned reference is not constant, so you can modify its value. ************************************************/ T& operator*() { return (*m_Node).m_Data; } /************************************************ Summary: Returns a pointer on a T object. ************************************************/ operator const T*() const { return &(m_Node->m_Data); } /************************************************ Summary: Returns a const reference on the key of the pointed entry. ************************************************/ const K& GetKey() const {return m_Node->m_Key;} /************************************************ Summary: Jumps to next entry in the hashtable. ************************************************/ tIterator& operator++() { // Prefixe ++m_Node; pEntry end = m_Table->m_Table.End(); while (m_Node != end) { // we're not at the end of the list yet if (m_Node->m_Status == STATUS_OCCUPIED) break; ++m_Node; } return *this; } /************************************************ Summary: Jumps to next entry in the hashtable. ************************************************/ tIterator operator++(int) { tIterator tmp = *this; ++*this; return tmp; } protected: XSHashTableIt(pEntry n,tTable t):m_Node(n),m_Table(t){} // The Current Node {secret} pEntry m_Node; // The Current Table {secret} tTable m_Table; }; /************************************************ Summary: Constant iterator on a hash table. Remarks: This iterator is the only way to iterate on elements in a constant hash table. The iteration will be in no specific order, not in the insertion order. Here is an example of how to use it: Example: void MyClass::MyMethod() const { XSHashTableConstIt it = m_Hashtable.Begin(); while (it != m_Hashtable.End()) { // access to the key it.GetKey(); // access to the element *it; // next element ++it; } } ************************************************/ template , class Eq = XEqual > class XSHashTableConstIt { typedef XSHashTableEntry* pEntry; typedef XSHashTableConstIt tConstIterator; typedef XSHashTableconst* tConstTable; friend class XSHashTable; public: /************************************************ Summary: Default constructor of the iterator. ************************************************/ XSHashTableConstIt():m_Node(0),m_Table(0){} /************************************************ Summary: Copy constructor of the iterator. ************************************************/ XSHashTableConstIt(const tConstIterator& n):m_Node(n.m_Node),m_Table(n.m_Table){} /************************************************ Summary: Operator Equal of the iterator. ************************************************/ int operator==(const tConstIterator& it) const { return m_Node == it.m_Node; } /************************************************ Summary: Operator Equal of the iterator. ************************************************/ int operator!=(const tConstIterator& it) const { return m_Node != it.m_Node; } /************************************************ Summary: Returns a constant reference on the data pointed by the iterator. Remarks: The returned reference is constant, so you can't modify its value. Use the other * operator for this purpose. ************************************************/ const T& operator*() const { return (*m_Node).m_Data; } /************************************************ Summary: Returns a pointer on a T object. ************************************************/ operator const T*() const { return &(m_Node->m_Data); } /************************************************ Summary: Returns a const reference on the key of the pointed entry. ************************************************/ const K& GetKey() const {return m_Node->m_Key;} /************************************************ Summary: Jumps to next entry in the hashtable. ************************************************/ tConstIterator& operator++() { // Prefixe ++m_Node; pEntry end = m_Table->m_Table.End(); while (m_Node != end) { // we're not at the end of the list yet if (m_Node->m_Status == STATUS_OCCUPIED) break; ++m_Node; } return *this; } /************************************************ Summary: Jumps to next entry in the hashtable. ************************************************/ tConstIterator operator++(int) { tConstIterator tmp = *this; ++*this; return tmp; } protected: XSHashTableConstIt(pEntry n,tConstTable t):m_Node(n),m_Table(t){} // The Current Node {secret} pEntry m_Node; // The Current Table {secret} tConstTable m_Table; }; /************************************************ Summary: Struct containing an iterator on an object inserted and a BOOL determining if it were really inserted (TRUE) or already there (FALSE). ************************************************/ template , class Eq = XEqual > class XSHashTablePair { public: XSHashTablePair(XSHashTableIt it,int n) : m_Iterator(it),m_New(n) {}; XSHashTableIt m_Iterator; BOOL m_New; }; /************************************************ Summary: Class representation of an Hash Table container. Remarks: T is the type of element to insert K is the type of the key H is the hash function to hash the key Several hash functions for basic types are already defined in XHashFun.h This implementation of the hash table uses Linked List in each bucket for element hashed to the same index, so there are memory allocation for each insertion. For a static implementation without dynamic allocation, look at XSHashTable. There is a m_LoadFactor member which allow the user to decide at which occupation the hash table must be extended and rehashed. ************************************************/ template , class Eq = XEqual > class XSHashTable { // Types typedef XSHashTable tTable; typedef XSHashTableEntry tEntry; typedef tEntry* pEntry; typedef XSHashTableIt tIterator; typedef XSHashTableConstIt tConstIterator; typedef XSHashTablePair tPair; // Friendship friend class XSHashTableIt; friend class XSHashTableConstIt; public: typedef XSHashTableIt Iterator; typedef XSHashTableConstIt ConstIterator; /************************************************ Summary: Constructors. Input Arguments: initialsize: The default number of buckets (should be a power of 2, otherwise will be converted.) l: Load Factor (see Class Description). a: hash table to copy. ************************************************/ XSHashTable(int initialsize = 8,float l = 0.75f) { int dec = -1; while (initialsize) { initialsize>>=1; dec++; } if (dec > -1) initialsize = 1<= m_Threshold) { // Yes Rehash(m_Table.Size()*2); return InsertUnique(key,o); } else { // No m_Table[index].Set(key,o); return tIterator(&m_Table[index],this); } } /************************************************ Summary: Removes an element. Input Arguments: key: key of the element to remove. it: iterator on the object to remove. Return Value: iterator on the lement next to the one just removed. ************************************************/ void Remove(const K& key) { int index = XFindPos( key ); if (m_Table[index].m_Status == STATUS_OCCUPIED) { m_Table[index].m_Status = STATUS_DELETED; --m_Count; } } tIterator Remove(const tIterator& it) { // may be not necessary pEntry e = it.m_Node; if (e == m_Table.End()) return it; if (e->m_Status == STATUS_OCCUPIED) { e->m_Status = STATUS_DELETED; --m_Count; } ++e; while (e != m_Table.End()) { // we're not at the end of the list yet if (e->m_Status == STATUS_OCCUPIED) break; ++e; } return tIterator(e,this); } /************************************************ Summary: Access to an hash table element. Input Arguments: key: key of the element to access. Return Value: a reference of the element found. Remarks: If no element correspond to the key, an exception. ************************************************/ T& operator [] (const K& key) { // Insert x as active int index = XFindPos( key ); if (m_Table[index].m_Status != STATUS_OCCUPIED) { // If the element was deleted, we remove an element if ((m_Table[index].m_Status != STATUS_DELETED)) { ++m_Occupation; ++m_Count; } else { ++m_Count; } m_Table[index].m_Status = STATUS_OCCUPIED; m_Table[index].m_Key = key; } // Test the rehash need if( m_Occupation < m_Threshold ) return m_Table[index].m_Data; Rehash(m_Table.Size()*2); return m_Table[XFindPos( key )].m_Data; } /************************************************ Summary: Access to an hash table element. Input Arguments: key: key of the element to access. Return Value: an iterator of the element found. End() if not found. ************************************************/ tIterator Find(const K& key) const { return tIterator(XFindIndex(key),this); } /************************************************ Summary: Access to an hash table element. Input Arguments: key: key of the element to access. Return Value: a pointer on the element found. NULL if not found. ************************************************/ T *FindPtr(const K& key) const { pEntry e = XFindIndex(key); if (e) return &e->m_Data; else return 0; } /************************************************ Summary: search for an hash table element. Input Arguments: key: key of the element to access. value: value to receive the element found value. Return Value: TRUE if the key was found, FALSE otherwise.. ************************************************/ BOOL LookUp(const K& key,T& value) const { pEntry e = XFindIndex(key); if (e) { value = e->m_Data; return TRUE; } else return FALSE; } /************************************************ Summary: test for the presence of a key. Input Arguments: key: key of the element to access. Return Value: TRUE if the key was found, FALSE otherwise.. ************************************************/ int IsHere(const K& key) const { return (int)XFindIndex(key); } /************************************************ Summary: Returns an iterator on the first element. Example: Typically, an algorithm iterating on an hash table looks like: XSHashTableIt it = h.Begin(); XSHashTableIt itend = h.End(); for(; it != itend; ++it) { // do something with *t } ************************************************/ tIterator Begin() { for(pEntry it = m_Table.Begin();it != m_Table.End();it++) { if (it->m_Status == STATUS_OCCUPIED) return tIterator(it,this); } return End(); } tConstIterator Begin() const { for(pEntry it = m_Table.Begin();it != m_Table.End();it++) { if (it->m_Status == STATUS_OCCUPIED) return tConstIterator(it,this); } return End(); } /************************************************ Summary: Returns an iterator out of the hash table. ************************************************/ tIterator End() { return tIterator(m_Table.End(),this); } /************************************************ Summary: Returns an iterator out of the hash table. ************************************************/ tConstIterator End() const { return tConstIterator(m_Table.End(),this); } /************************************************ Summary: Returns the index of the given key. Input Arguments: key: key of the element to find the index. ************************************************/ int Index(const K& key) const { H hashfun; return XIndex(hashfun(key),m_Table.Size()); } /************************************************ Summary: Returns the elements number. ************************************************/ int Size() const { return m_Count; } private: /// // Methods pEntry* GetFirstBucket() const {return m_Table.ConstBegin();} void Rehash(int size) { int oldsize = m_Table.Size(); m_Threshold = (int)(size * m_LoadFactor); // Temporary table XClassArray tmp; tmp.Resize(size); m_Table.Swap(tmp); m_Count = 0; m_Occupation = 0; for (int index = 0; index < oldsize; ++index) { pEntry first = &tmp[index]; if (first->m_Status == STATUS_OCCUPIED) { Insert(first->m_Key,first->m_Data,TRUE); } } } int XIndex(int key,int size) const { return key&(size-1); } void XCopy(const XSHashTable& a) { m_Table = a.m_Table; m_Occupation = a.m_Occupation; m_LoadFactor = a.m_LoadFactor; m_Count = a.m_Count; m_Threshold = a.m_Threshold; } pEntry XFindIndex(const K& key) const { int index = XFindPos( key ); if (index < 0) return NULL; pEntry e = &m_Table[index]; if (e->m_Status == STATUS_OCCUPIED) return e; else return NULL; } int XFindPos(const K& key) const { int index = Index(key); int oldindex = index; Eq eqaulFunc; while (m_Table[index].m_Status == STATUS_OCCUPIED) { if (eqaulFunc(m_Table[index].m_Key,key)) return index; ++index; // Compute ith probe if (index == m_Table.Size()) index=0; if (index == oldindex) return -1; } return index; } /// // Members // the hash table data XClassArray m_Table; // The entry count int m_Count; // The entry count int m_Occupation; // Rehashes the table when count exceeds this threshold. int m_Threshold; // The load factor for the hashtable. float m_LoadFactor; }; #endif