GEL
2
GEL is a library for Geometry and Linear Algebra
|
00001 #ifndef __UTIL_HASHTABLE_H 00002 #define __UTIL_HASHTABLE_H 00003 00004 #include "HashKey.h" 00005 00006 #include <functional> 00007 #include <iostream> 00008 00009 namespace Util 00010 { 00011 00012 namespace 00013 { 00014 const int HASH_EXPAND_LOAD = 80; 00015 }; 00016 00032 template<class KEY_T, class VAL_T> 00033 class HashTable 00034 { 00038 struct EntryType 00039 { 00040 // Hash key 00041 KEY_T key; 00042 00044 VAL_T val; 00045 00047 signed char ref; 00048 00049 public: 00050 EntryType(): ref(-1) {} 00051 }; 00052 00054 EntryType* table; 00055 00056 private: 00057 00059 int items; 00060 00062 int size; 00063 00065 void resize(int new_size); 00066 00070 bool find_entry_priv(const KEY_T&, int&) const; 00071 00072 public: 00073 00075 HashTable(): items(0), size(1) 00076 { 00077 table = new EntryType[size]; 00078 } 00079 00081 ~HashTable() { delete [] table; } 00082 00096 bool create_entry(const KEY_T&, const VAL_T&,int=0); 00097 00098 bool create_entry(const KEY_T& kv, VAL_T*& val, int incr=0); 00099 00100 00101 00107 bool remove_entry(const KEY_T&); 00108 00113 bool find_entry(const KEY_T&, VAL_T&) const; 00114 00123 bool decr_reference(const KEY_T&, VAL_T&, int=1); 00124 00125 00128 bool change_entry(const KEY_T&, const VAL_T&); 00129 00131 void print() const; 00132 00142 bool get_first(int& idx, KEY_T&,VAL_T& val,int&) const; 00143 00151 bool get_next(int& idx, KEY_T&,VAL_T& val,int&) const; 00152 00154 int integrate() const; 00155 00156 00158 int no_items() const {return items;} 00159 00161 bool empty() const {return items==0;} 00162 00164 int total_size() const {return sizeof(*this) + sizeof(EntryType)*size;} 00165 00167 static int entry_size() {return sizeof(EntryType);} 00168 00169 }; 00170 00171 00172 template<class KEY_T, class VAL_T> 00173 bool HashTable<KEY_T, VAL_T>::find_entry_priv(const KEY_T& kv, int& k) const 00174 { 00175 k = kv.hash(size); 00176 int fk = k; 00177 while(table[k].ref != -1) 00178 { 00179 if (table[k].key == kv) 00180 return (table[k].ref > 0) ? true : false; 00181 k = (k+1)&(size-1); 00182 if (k==fk) break; 00183 } 00184 return false; 00185 } 00186 00187 template<class KEY_T, class VAL_T> 00188 bool HashTable<KEY_T, VAL_T>::find_entry(const KEY_T& kv, VAL_T& val) const 00189 { 00190 int k; 00191 if(find_entry_priv(kv,k)) 00192 { 00193 val = table[k].val; 00194 return true; 00195 } 00196 return false; 00197 } 00198 00199 template<class KEY_T, class VAL_T> 00200 void HashTable<KEY_T, VAL_T>::resize(int new_size) 00201 { 00202 int j=0; 00203 EntryType* tmp_table = new EntryType[new_size]; 00204 for(int i=0; i<size;i++) 00205 if (table[i].ref >0) 00206 { 00207 j++; 00208 int k = table[i].key.hash(new_size); 00209 00210 while(tmp_table[k].ref != -1) 00211 k=(k+1)&(new_size-1); 00212 00213 tmp_table[k].key = table[i].key; 00214 tmp_table[k].val = table[i].val; 00215 tmp_table[k].ref = table[i].ref; 00216 } 00217 00218 delete table; 00219 table = tmp_table; 00220 size = new_size; 00221 } 00222 00223 template<class KEY_T, class VAL_T> 00224 bool HashTable<KEY_T, VAL_T>::create_entry(const KEY_T& kv, 00225 const VAL_T& val, 00226 int incr) 00227 { 00228 if (items*100 >= HASH_EXPAND_LOAD * size) 00229 resize(size*2); 00230 00231 int k; 00232 if(!find_entry_priv(kv,k)) 00233 { 00234 ++items; 00235 table[k].ref = (incr==0? 1: incr); 00236 table[k].key = kv; 00237 table[k].val = val; 00238 return true; 00239 } 00240 table[k].ref += incr; 00241 table[k].val = val; 00242 return false; 00243 } 00244 00245 template<class KEY_T, class VAL_T> 00246 bool HashTable<KEY_T, VAL_T>::create_entry(const KEY_T& kv, 00247 VAL_T*& val, 00248 int incr) 00249 { 00250 if (items*100 >= HASH_EXPAND_LOAD * size) 00251 resize(size*2); 00252 00253 int k; 00254 if(!find_entry_priv(kv,k)) 00255 { 00256 ++items; 00257 table[k].ref = (incr==0? 1: incr); 00258 table[k].key = kv; 00259 val = &table[k].val; 00260 return true; 00261 } 00262 table[k].ref += incr; 00263 val=&table[k].val; 00264 return false; 00265 } 00266 00267 00268 template<class KEY_T, class VAL_T> 00269 bool HashTable<KEY_T, VAL_T>::remove_entry(const KEY_T& kv) 00270 { 00271 int k; 00272 if(find_entry_priv(kv,k)) 00273 { 00274 table[k].ref = 0; 00275 --items; 00276 if(items*100 < (HASH_EXPAND_LOAD * size) / 2) 00277 resize(size/2); 00278 return true; 00279 } 00280 return false; 00281 } 00282 00283 00284 00285 template<class KEY_T, class VAL_T> 00286 bool HashTable<KEY_T, VAL_T>::decr_reference(const KEY_T& kv, 00287 VAL_T& val, 00288 int decr) 00289 { 00290 int k; 00291 if(find_entry_priv(kv,k)) 00292 { 00293 table[k].ref -= decr; 00294 val = table[k].val; 00295 if(table[k].ref == 0) 00296 { 00297 --items; 00298 if(items*100 < (HASH_EXPAND_LOAD * size) / 2) 00299 resize(size/2); 00300 } 00301 return true; 00302 } 00303 return false; 00304 } 00305 00306 template<class KEY_T, class VAL_T> 00307 bool HashTable<KEY_T, VAL_T>::change_entry(const KEY_T& kv, 00308 const VAL_T& val) 00309 { 00310 int k; 00311 if(find_entry_priv(kv,k)) 00312 { 00313 table[k].val = val; 00314 return true; 00315 } 00316 return false; 00317 } 00318 00319 00320 template<class KEY_T, class VAL_T> 00321 void HashTable<KEY_T, VAL_T>::print() const 00322 { 00323 std::cout << "Entry size " << sizeof(EntryType) << " bytes\n" 00324 << "Max number of items " << size << "\n" 00325 << "Number of items " << items << std::endl; 00326 } 00327 00328 template<class KEY_T, class VAL_T> 00329 int HashTable<KEY_T, VAL_T>::integrate() const 00330 { 00331 int integral =0; 00332 for(int i=0;i<size; i++) 00333 if(table[i].ref>0) integral += table[i].ref; 00334 return integral; 00335 } 00336 00337 template<class KEY_T, class VAL_T> 00338 bool HashTable<KEY_T, VAL_T>::get_first(int& idx, 00339 KEY_T& key, 00340 VAL_T& val, 00341 int& r) const 00342 { 00343 if(size==0) return false; 00344 00345 idx=0; 00346 while(table[idx].ref <= 0) 00347 { 00348 ++idx; 00349 if(idx==size) return false; 00350 } 00351 key = table[idx].key; 00352 val = table[idx].val; 00353 r = table[idx].ref; 00354 return true; 00355 } 00356 00357 template<class KEY_T, class VAL_T> 00358 bool HashTable<KEY_T, VAL_T>::get_next(int& idx, 00359 KEY_T& key, 00360 VAL_T& val, 00361 int& r) const 00362 { 00363 idx++; 00364 if(idx==size) return false; 00365 while(table[idx].ref <= 0) 00366 { 00367 ++idx; 00368 if(idx==size) return false; 00369 } 00370 key = table[idx].key; 00371 val = table[idx].val; 00372 r = table[idx].ref; 00373 return true; 00374 } 00375 00376 } 00377 00378 00379 #endif