GEL  2
GEL is a library for Geometry and Linear Algebra
/Users/jab/Documents/Teaching/02585/GEL2_and_demos/GEL/src/Util/HashTable.h
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations