00001
00002 #ifndef GAUDIKERNEL_HASHTABLE_H
00003 #define GAUDIKERNEL_HASHTABLE_H
00004
00005 #include <list>
00006 #include <vector>
00007 #include <functional>
00008
00009 template <class T> class HashTableHasher : public std::unary_function<const T&,size_t> {
00010 public:
00011 size_t operator()(const T& key) {
00012 size_t f = size_t(key)>>4;
00013 const unsigned char* s = (const unsigned char*)&f;
00014 return (((((((0^*s++)<<1)^*s++)<<1)^*s++)<<1)^*s++);
00015 }
00016 };
00017
00042 template < class K, class E, class H=HashTableHasher< K > >
00043 class HashTable {
00044 public:
00045
00048 template<class KK, class EE> class TableEntry {
00049 friend class HashTable<KK,EE,H>;
00050 private:
00052 TableEntry* chain;
00053 public:
00055 KK first;
00057 EE second;
00059 TableEntry() : chain(0) {
00060 }
00062 TableEntry(const TableEntry& copy)
00063 : chain(copy.chain), first(copy.first), second(copy.second) {
00064 }
00066 TableEntry(const KK& k, const EE& e,TableEntry* c)
00067 : chain(c), first(k), second(e) {
00068 }
00070 bool operator==(const TableEntry& copy) const {
00071 return copy.first == first;
00072 }
00074 TableEntry& operator=(const TableEntry& copy) {
00075 first = copy.first;
00076 second = copy.second;
00077 chain = copy.chain;
00078 return *this;
00079 }
00080 };
00081 typedef HashTable<K,E,H> table_type;
00082 typedef H hash_type;
00083 typedef TableEntry<K, E> value_type;
00084 typedef std::list< value_type > container_type;
00085 typedef container_type::iterator iterator;
00086 typedef container_type::const_iterator const_iterator;
00087 protected:
00089 int m_size;
00091 int m_incr;
00093 std::vector<value_type*> m_vec;
00095 container_type m_con;
00097 hash_type m_hash;
00098 protected:
00100 void rehash(int new_size) {
00101 m_vec.clear();
00102 m_vec.insert(m_vec.begin(), new_size, (value_type*)0);
00103 for ( container_type::iterator i = m_con.begin(); i != m_con.end(); i++ ) {
00104 size_t h = m_hash((*i).first)%m_vec.size();
00105 (*i).chain = m_vec[h];
00106 m_vec[h] = &(*i);
00107 }
00108 }
00110 value_type* find(size_t idx, const K& key ) {
00111 for (value_type* e = m_vec[idx]; e != 0; e = e->chain) {
00112 if ( e->first == key ) {
00113 return e;
00114 }
00115 }
00116 return 0;
00117 }
00118 void remove(value_type* e) {
00119 m_con.remove(*e);
00120 m_size--;
00121 }
00122 public:
00124 HashTable(int length = 16, int incr = 2) : m_size(0), m_incr(incr) {
00125 reserve(length);
00126 }
00128 virtual ~HashTable() {
00129 clear();
00130 }
00132 iterator begin() {
00133 return m_con.begin();
00134 }
00136 const_iterator begin() const {
00137 return m_con.begin();
00138 }
00140 iterator end() {
00141 return m_con.end();
00142 }
00144 const_iterator end() const {
00145 return m_con.end();
00146 }
00148 void clear() {
00149 m_con.erase(m_con.begin(), m_con.end());
00150 m_vec.erase(m_vec.begin(), m_vec.end());
00151 }
00153 long size() const {
00154 return m_size;
00155 }
00157 void reserve(int len) {
00158 if ( int(m_vec.size()) < len ) rehash(len);
00159 }
00161 bool insert(const K& first, const E& second) {
00162 size_t h = m_hash(first)%m_vec.size();
00163 value_type* val = find(h, first);
00164 if ( !val ) {
00165 if ( ++m_size == int(m_vec.size()) ) {
00166 rehash(m_vec.size()*m_incr);
00167 h = m_hash(first)%m_vec.size();
00168 }
00169 m_con.insert(m_con.end(), value_type(first, second, m_vec[h]));
00170 m_vec[h] = &m_con.back();
00171 return true;
00172 }
00173 return false;
00174 }
00176 value_type* find(const K& first) {
00177 return find(m_hash(first)%m_vec.size(), first);
00178 }
00180 const value_type* find(const K& first) const {
00181 table_type* thisPtr = const_cast<table_type*>(this);
00182 return thisPtr->find(m_hash(first)%m_vec.size(), first);
00183 }
00185 void remove(const K& first) {
00186 size_t h = m_hash(first)%m_vec.size();
00187 if (0 != m_vec[h]) {
00188 value_type *prev, *e = m_vec[h];
00189 if ( e->first == first ) {
00190 m_vec[h] = e->chain;
00191 remove(e);
00192 return;
00193 }
00194 do {
00195 prev = e;
00196 e = e->chain;
00197 } while ( 0 != e && e->first != first);
00198 if ( 0 != e ) {
00199 prev->chain = e->chain;
00200 remove(e);
00201 }
00202 }
00203 }
00204 };
00205
00206 #endif // GAUDI_KERNEL_HASHTABLE_H