hash.h

Go to the documentation of this file.
00001 /****************************************************************************/
00002 /*                                                                          */
00003 /*  Copyright (c) 1994-2002                                                 */
00004 /*  Jeremy Levitt                                                           */
00005 /*                                                                          */
00006 /****************************************************************************/
00007 #ifndef _hash_h_
00008 #define _hash_h_
00009 
00010 #include <iostream>
00011 
00012 #ifndef NULL
00013 #define NULL 0
00014 #endif
00015 
00016 //#include <ext/stl_hash_fun.h>
00017 
00018 namespace CVCL {
00019 using std::pair;
00020 
00021 template <class _Key> 
00022         static size_t hash(_Key e) { return 1;}
00023 template <class _Key> 
00024         static size_t equal_to(_Key x, _Key y) { return x==y;}
00025         //static size_t mfun(Expr x, Expr y) { return x==y;}
00026 
00027 const int HASH_TABLE_SIZE = 1024;
00028 const int HASH_TABLE_GROW_THRESHOLD = 1;
00029 const int HASH_TABLE_GROW_FACTOR = 2;
00030 typedef void *void_pointer;
00031 
00032 template <class _Key, class _Data> class Hash_Table;
00033 template <class _Key, class _Data> class Hash_Entry;
00034 template <class _Key, class _Data> class Hash_Ptr;
00035 
00036 //iterator
00037 template <class _Key, class _Data>
00038 struct _Hashtable_iterator;
00039 
00040 template <class _Key, class _Data>
00041 struct _Hashtable_const_iterator;
00042 
00043 template <class _Key, class _Data>
00044 struct _Hashtable_iterator {
00045   typedef Hash_Table<_Key,_Data>
00046           _Hashtable;
00047   typedef _Hashtable_iterator<_Key, _Data>
00048           iterator;
00049   typedef _Hashtable_const_iterator<_Key, _Data>
00050           const_iterator;
00051   typedef Hash_Entry<_Key, _Data> _Node;
00052 
00053   //typedef forward_iterator_tag iterator_category;
00054   //typedef _Val value_type;
00055   //typedef ptrdiff_t difference_type;
00056   //typedef size_t size_type;
00057   typedef pair<const _Key,_Data>& reference;
00058   typedef pair<const _Key,_Data>* pointer;
00059 
00060   _Node* _M_cur;
00061   _Hashtable* _M_ht;
00062 
00063   _Hashtable_iterator(_Node* __n, _Hashtable* __tab) 
00064     : _M_cur(__n), _M_ht(__tab) {}
00065   _Hashtable_iterator() {}
00066   reference operator*() const { return _M_cur->Val(); }
00067   pointer operator->() const { return &(operator*()); }
00068   iterator& operator++(){
00069             //const _Node* _old = _M_cur;
00070                 _M_cur = _M_cur->Next();
00071                 //if (!_M_cur)
00072                 //      _M_cur = _old;
00073                 return *this;
00074   }
00075   //iterator operator++(int);
00076   bool operator==(const iterator& __it) const
00077     { return _M_cur == __it._M_cur; }
00078   bool operator!=(const iterator& __it) const
00079     { return _M_cur != __it._M_cur; }
00080 };
00081 
00082 
00083 template <class _Key, class _Data>
00084 struct _Hashtable_const_iterator {
00085   typedef Hash_Table<_Key,_Data>
00086           _Hashtable;
00087   typedef _Hashtable_iterator<_Key,_Data> iterator;
00088   typedef _Hashtable_const_iterator<_Key,_Data>
00089           const_iterator;
00090   typedef Hash_Entry<_Key,_Data> _Node;
00091 
00092   //typedef forward_iterator_tag iterator_category;
00093   //typedef _Val value_type;
00094   //typedef ptrdiff_t difference_type;
00095   //typedef size_t size_type;
00096   typedef const pair<const _Key,_Data>& reference;
00097   typedef const pair<const _Key,_Data>* pointer;
00098 
00099   const _Node* _M_cur;
00100   const _Hashtable* _M_ht;
00101 
00102   _Hashtable_const_iterator(const _Node* __n, const _Hashtable* __tab)
00103     : _M_cur(__n), _M_ht(__tab) {
00104                 //cout << "Hashtable_const_iterator. " << endl; 
00105         }
00106   _Hashtable_const_iterator() {}
00107   _Hashtable_const_iterator(const iterator& __it) 
00108     : _M_cur(__it._M_cur), _M_ht(__it._M_ht) {}
00109   reference operator*() const {
00110           //cout << "hashtable-const-iterator: * " << endl;
00111         pair<_Key,_Data> tmp(_M_cur->Val());
00112         //return _M_cur->Val(); 
00113         return tmp;
00114         }
00115   pointer operator->() const { //cout << "hashtable-const-iterator: -> " << endl;
00116           return &(operator*()); }
00117   const_iterator& operator++(){
00118             //const _Node* _old = _M_cur;
00119           //cout << "hashtable-const-iterator: ++ " << endl;
00120                 _M_cur = _M_cur->Next();
00121                 //if (!_M_cur)
00122                 //      _M_cur = _old;
00123                 return *this;
00124   }
00125   //const_iterator operator++(int);
00126   bool operator==(const const_iterator& __it) const 
00127     { //cout << "hashtable-const-iterator: == " << endl;
00128           return _M_cur == __it._M_cur; }
00129   bool operator!=(const const_iterator& __it) const 
00130     { //cout << "hashtable-const-iterator: != " << endl;
00131           return _M_cur != __it._M_cur; }
00132 };
00133 
00134 //end iterator
00135 
00136 /****************************************************************************/
00137 /*  class Hash_Entry                                                        */
00138 /****************************************************************************/
00139 template <class _Key, class _Data>
00140 class Hash_Entry {
00141         //friend class ExprMap;
00142 private:
00143   _Key _key;
00144   _Data _data;
00145   pair<const _Key,_Data> _val;
00146   Hash_Entry *_next;
00147   //Hash_Entry(const _Data &data):
00148   //_Key(0), _data(data), _next(NULL){}
00149   Hash_Entry(const _Key &key, const _Data &data) : 
00150   _key(key), _data(data), _val(make_pair(key,data)), _next(NULL) {}
00151   Hash_Entry(const Hash_Entry &rhs) : 
00152   _key(rhs._key), _data(rhs._data), _val(make_pair(rhs._key,rhs._data)), _next(NULL) {}
00153   ~Hash_Entry() {}
00154   friend class Hash_Table<_Key, _Data>;
00155   
00156 public:
00157   Hash_Entry* Next() const { return _next; } 
00158   _Key Key() const { return _key; }
00159   _Data& Data() { return _data; }
00160   pair<const _Key,_Data> Val() const {
00161           //cout << "hashtable-hashentry-val(): key " << _key << " , data: " << _data << endl;
00162                 pair<const _Key,_Data> val1 = make_pair(_key,_data);
00163           //cout << "key: " << val1.first << ", data: " << val1.second << endl;
00164           return val1;}
00165   bool operator==(const Hash_Entry he){
00166           if( (_key == he.Key()) && (_data == he.Data()))
00167                   return true;
00168           else
00169                   return false;
00170   }
00171   bool operator!=(const Hash_Entry he){
00172           if( (_key == he.Key()) && (_data == he.Data()))
00173                   return false;
00174           else
00175                   return true;
00176   }
00177 
00178   //IF_DEBUG(
00179     void Print();
00180   //)
00181 };
00182 
00183 
00184 /****************************************************************************/
00185 /*  class Hash_Table                                                        */
00186 /****************************************************************************/
00187 template <class _Key, class _Data>
00188 class Hash_Table {
00189         //friend class ExprMap;
00190 private:
00191   Hash_Entry<_Key, _Data> **_hashTbl;
00192   //int (*_hashFunc)(const _Key);               // must return a positive int
00193   size_t (*_hashFunc)(const _Key);
00194   //int (*_matchFunc)(const _Key, const _Key);  // return (k1==k2) ? 1 : 0
00195   size_t (*_matchFunc)(const _Key, const _Key);
00196   int _size;
00197   int _growThreshold;
00198   int _growFactor;
00199   int _numEntries;
00200   Hash_Entry<_Key, _Data>** Find_Hash_Entry(const _Key&) const;
00201   void Copy(const Hash_Table &rhs);
00202   void Resize(int size);
00203   void Destroy();
00204   friend class Hash_Ptr<_Key, _Data>;
00205   //friend class Expr;
00206 
00207 public:
00208         
00209         //Hash_Table(): _hashFunc(hash<_Key>), _matchFunc(equal_to<_Key>),
00210                 //_size(HASH_TABLE_SIZE),
00211                 //_growThreshold(HASH_TABLE_GROW_THRESHOLD), 
00212         //      _growFactor(HASH_TABLE_GROW_FACTOR), _numEntries(0)
00213         //{cout << "hashtable-hashtable():" << endl;}
00214         
00215   //Hash_Table(int (*hashFunction)(const _Key),
00216         //     int (*matchFunc)(const _Key, const _Key),
00217         Hash_Table(size_t (*hashFunction)(const _Key),
00218            size_t (*matchFunc)(const _Key, const _Key),
00219        int size = HASH_TABLE_SIZE, int threshold = HASH_TABLE_GROW_THRESHOLD,
00220        int factor = HASH_TABLE_GROW_FACTOR);
00221   Hash_Table(const Hash_Table &hash) { Copy(hash); }
00222   ~Hash_Table() { Destroy(); }
00223   int Insert(_Key key, _Data data);
00224   int Delete(_Key key);
00225   void clear();
00226   Hash_Table& operator= (const Hash_Table &rhs);
00227   _Data* Fetch(_Key key);
00228   _Data& operator[] (_Key key);
00229   //int Size() const { return _size; }
00230   //int NumEntries() const { return _numEntries; } //real size()
00231   size_t size() const { return _numEntries; }
00232   bool empty() const { return size() == 0; }
00233         void erase(_Key key);
00234         int count(_Key key) const;
00235         typedef _Hashtable_iterator<_Key, _Data>
00236           iterator;
00237         typedef _Hashtable_const_iterator<_Key, _Data>
00238           const_iterator;
00239         friend struct
00240                 _Hashtable_iterator<_Key, _Data>;
00241         friend struct
00242                 _Hashtable_const_iterator<_Key, _Data>;
00243         
00244 
00245   //IF_DEBUG(
00246     void Print();
00247   //)
00248  
00249         const_iterator begin() const{ 
00250       if (size()>0)
00251         return const_iterator(_hashTbl[0], this);
00252           else
00253                 return end();
00254         }
00255 
00256         const_iterator end() const{ return const_iterator(0, this); }
00257         const_iterator find(const _Key& key) const{
00258                 //cout << "hashtable-find e: " << key << endl;
00259                 return const_iterator(*Find_Hash_Entry(key), this);
00260         }
00261         template<class InputIterator>
00262                 void insert(InputIterator l, InputIterator r);
00263 };
00264 
00265 
00266 /****************************************************************************/
00267 /*  class Hash_Ptr                                                          */
00268 /****************************************************************************/
00269 template <class _Key, class _Data>
00270 class Hash_Ptr {
00271         //friend class ExprMap;
00272 private:
00273   Hash_Table<_Key, _Data> *_hash;
00274   int _index;
00275   Hash_Entry<_Key, _Data> *_hashEntry;
00276   void Set_Next_Hash_Entry();
00277   
00278 public:
00279   Hash_Ptr() : _hash(0), _index(0), _hashEntry(0) {}
00280   Hash_Ptr(Hash_Table<_Key, _Data> *hash) : 
00281   _hash(hash), _index(0), _hashEntry(hash->_hashTbl[0]) 
00282     { if (_hashEntry == NULL) Set_Next_Hash_Entry(); }
00283   Hash_Ptr(const Hash_Table<_Key, _Data> *hash) :
00284     _hash((Hash_Table<_Key, _Data>*)hash), _index(0),
00285     _hashEntry(hash->_hashTbl[0])
00286     { if (_hashEntry == NULL) Set_Next_Hash_Entry(); }
00287   Hash_Entry<_Key, _Data>* operator-> () { return _hashEntry; }
00288   Hash_Entry<_Key, _Data>& operator* () 
00289     { //ASSERT(_hashEntry);  
00290         return *_hashEntry; }
00291   operator void_pointer() const { return void_pointer(_hashEntry); }
00292   int Null() const { return _hashEntry == NULL; }
00293   void operator++ () { Set_Next_Hash_Entry(); }
00294   void Reset(Hash_Table<_Key, _Data> *hash)
00295     { *this = Hash_Ptr(hash); }
00296 };   
00297 
00298 
00299 /****************************************************************************/
00300 /*    Hash_Table::Hash_Table()                                              */
00301 /****************************************************************************/
00302 template <class _Key, class _Data>
00303 Hash_Table<_Key, _Data>::Hash_Table
00304 //(int (*hashFunc)(const _Key), int (*matchFunc)(const _Key, const _Key),
00305 (size_t (*hashFunc)(const _Key), size_t (*matchFunc)(const _Key, const _Key),
00306  int size, int threshold, int factor)
00307 : _hashFunc(hashFunc), _matchFunc(matchFunc), _size(size),
00308   _growThreshold(threshold), _growFactor(factor), _numEntries(0)
00309 {
00310   //ASSERT(_growFactor >= HASH_TABLE_GROW_FACTOR);
00311   //ASSERT(_growThreshold >= HASH_TABLE_GROW_THRESHOLD);
00312 
00313         //cout << "hashtable-hashtable(hfun, mfun):" << endl;
00314   _hashTbl = new Hash_Entry<_Key, _Data> *[_size];
00315   for(int i=0; i<_size; i++)
00316     _hashTbl[i] = NULL;
00317 }
00318 
00319 
00320 /****************************************************************************/
00321 /*    Hash_Table::Destroy()                                                 */
00322 /****************************************************************************/
00323 template <class _Key, class _Data>
00324 void Hash_Table<_Key, _Data>::Destroy()
00325 {
00326   for (int i=0; i<_size; i++) {
00327     Hash_Entry<_Key, _Data> *tmp = _hashTbl[i];
00328 
00329     while(tmp != NULL) {
00330       Hash_Entry<_Key, _Data> *next = tmp->_next;
00331       delete tmp;
00332       tmp = next;
00333     }
00334   }
00335 
00336   delete [] _hashTbl;
00337 }
00338 
00339 
00340 /****************************************************************************/
00341 /*    Hash_Table::Copy()                                                    */
00342 /****************************************************************************/
00343 template <class _Key, class _Data>
00344 void Hash_Table<_Key, _Data>::Copy(const Hash_Table<_Key, _Data> &rhs)
00345 {
00346   _hashFunc = rhs._hashFunc;
00347   _matchFunc = rhs._matchFunc;
00348   _numEntries = rhs._numEntries;
00349   _size = rhs._size;
00350   _growThreshold = rhs._growThreshold;
00351   _growFactor = rhs._growFactor;
00352   _hashTbl = new Hash_Entry<_Key, _Data> *[rhs._size];
00353 
00354   for (int i=0; i<rhs._size; i++) {
00355     Hash_Entry<_Key, _Data> *tmp = rhs._hashTbl[i];
00356     Hash_Entry<_Key, _Data> **copy = &(_hashTbl[i] = NULL);
00357 
00358     while(tmp != NULL) {
00359       *copy = new Hash_Entry<_Key, _Data>(*tmp);
00360       copy = &(*copy)->_next;
00361       tmp = tmp->_next;
00362     }
00363   }
00364 }
00365 
00366 
00367 /****************************************************************************/
00368 /*    Hash_Table::Resize()                                                  */
00369 /****************************************************************************/
00370 template <class _Key, class _Data>
00371 void Hash_Table<_Key, _Data>::Resize(int size)
00372 {
00373   Hash_Table<_Key, _Data> tmp(_hashFunc, _matchFunc, size);
00374 
00375   Hash_Ptr<_Key, _Data> ptr(this);
00376   for (;!ptr.Null(); ++ptr) {
00377     _Key key = ptr->Key();
00378     tmp.Insert(key, ptr->Data());
00379   }
00380 
00381   Destroy();
00382   Copy(tmp);
00383 }
00384 
00385 
00386 /****************************************************************************/
00387 /*   Hash_Table::operator=                                                  */
00388 /****************************************************************************/
00389 template <class _Key, class _Data>
00390 Hash_Table<_Key, _Data>& Hash_Table<_Key, _Data>::operator=
00391 (const Hash_Table<_Key, _Data> &rhs)
00392 {
00393   if (this != &rhs) {
00394     Destroy();
00395     Copy(rhs);
00396   }
00397 
00398   return *this;
00399 }
00400 
00401 
00402 /****************************************************************************/
00403 /*    Hash_Table::Find_Hash_Entry()                                         */
00404 /*                                                                          */
00405 /*    Return a pointer to the element if found, or a pointer to where       */
00406 /*    the element should be if not found.                                   */
00407 /****************************************************************************/
00408 template <class _Key, class _Data>
00409 Hash_Entry<_Key, _Data>** 
00410 Hash_Table<_Key, _Data>::Find_Hash_Entry(const _Key& key) const
00411 {
00412   int index = (*_hashFunc)(key) % _size;
00413   //cout << "hashtable-findHashEntry, index: " << index << endl;
00414 
00415   //ASSERT(index >=0);
00416   Hash_Entry<_Key, _Data>** link = &_hashTbl[index];  
00417   while (*link != NULL && !_matchFunc((*link)->_key, key))
00418     link = &((*link)->_next);
00419   return link;
00420 }
00421 
00422 
00423 /****************************************************************************/
00424 /*    Hash_Table::Insert()                                                  */
00425 /*                                                                          */
00426 /*    Return 0 if the element was successfully inserted                     */
00427 /*    Return 1 if insertion fails becuase an entry with the same key        */
00428 /*    is already present                                                    */
00429 /****************************************************************************/
00430 template <class _Key, class _Data>
00431 int Hash_Table<_Key, _Data>::Insert(_Key key, _Data data)
00432 {
00433   if (_numEntries>_size*_growThreshold)
00434     Resize(_size*_growFactor);
00435 
00436   Hash_Entry<_Key, _Data>* hash_entry = 
00437     new Hash_Entry<_Key, _Data>(key, data);
00438   Hash_Entry<_Key, _Data>** link = Find_Hash_Entry(key);
00439   
00440   if (*link != NULL) {
00441     delete hash_entry;
00442     return 1;
00443   }
00444   
00445   _numEntries++;
00446   *link = hash_entry;
00447   return 0;
00448 }
00449 
00450 template<class InputIterator>
00451 void insert(InputIterator l, InputIterator r) {
00452         for(; l!=r; ++l) {
00453                 Insert((*l).first, (*l).second);
00454         }       
00455 }
00456 
00457 /****************************************************************************/
00458 /*    Hash_Table::Delete()                                                  */
00459 /*                                                                          */
00460 /*    Return 0 if the element was successfully deleted and 1                */
00461 /*    if the deletion failed becuase the entry could not be found.          */
00462 /****************************************************************************/
00463 template <class _Key, class _Data>
00464 int Hash_Table<_Key, _Data>::Delete(_Key key)
00465 {
00466   Hash_Entry<_Key, _Data>** link = Find_Hash_Entry(key);
00467   Hash_Entry<_Key, _Data>* tmp;
00468   
00469   if (*link == NULL)
00470     return 1;
00471   
00472   _numEntries--;
00473   tmp = (*link);
00474   *link = (*link)->_next;
00475   delete tmp;
00476   return 0;
00477 }
00478 
00479 template <class _Key, class _Data>
00480 void Hash_Table<_Key, _Data>::erase(_Key key){
00481   Hash_Entry<_Key, _Data>** link = Find_Hash_Entry(key);
00482   Hash_Entry<_Key, _Data>* tmp;
00483   
00484   if (*link == NULL)
00485     return;
00486   
00487   _numEntries--;
00488   tmp = (*link);
00489   *link = (*link)->_next;
00490   delete tmp;
00491   return;
00492 }
00493 
00494 /****************************************************************************/
00495 /*    Hash_Table::clear()                                                   */
00496 /*                                                                          */
00497 /*    Delete all elements in the hash table.                                */
00498 /****************************************************************************/
00499 template <class _Key, class _Data>
00500 void Hash_Table<_Key, _Data>::clear()
00501 {
00502   for (int i=0; i<_size; i++) {
00503     Hash_Entry<_Key, _Data> *tmp = _hashTbl[i];
00504     _hashTbl[i] = NULL;
00505 
00506     while(tmp != NULL) {
00507       Hash_Entry<_Key, _Data> *next = tmp->_next;
00508       delete tmp;
00509       tmp = next;
00510     }
00511   }
00512   _numEntries = 0;
00513 }
00514 
00515 
00516 /****************************************************************************/
00517 /*    Hash_Table::Fetch()                                                   */
00518 /*                                                                          */
00519 /*    Return a pointer to the element if it was found, otherwise return     */
00520 /*    a NULL pointer.                                                       */
00521 /****************************************************************************/
00522 template <class _Key, class _Data>
00523 _Data* Hash_Table<_Key, _Data>::Fetch(_Key key)
00524 {
00525   Hash_Entry<_Key, _Data>** link = Find_Hash_Entry(key);
00526   return (*link) ? &(*link)->Data() : (_Data *)NULL;
00527 }
00528 
00529 template <class _Key, class _Data>
00530 int Hash_Table<_Key, _Data>::count(_Key key) const{
00531   Hash_Entry<_Key, _Data>** link = Find_Hash_Entry(key);
00532   return (*link) ? 1 : 0;
00533 }
00534 
00535 /****************************************************************************/
00536 /*    Hash_Table::operator[]                                                */
00537 /****************************************************************************/
00538 /*
00539 template <class _Key, class _Data>
00540 _Data& Hash_Table<_Key, _Data>::operator[] (_Key key)
00541 {
00542   _Data* result = Fetch(key);
00543   //ASSERT(result != NULL);
00544   return *result;
00545 }
00546 */
00547 
00548 template <class _Key, class _Data>
00549 _Data& Hash_Table<_Key, _Data>::operator[](_Key key)
00550 {
00551  _Data* result = Fetch(key);
00552  if (result) return *result;
00553  else {
00554    _Data data;
00555 
00556    if (_numEntries>_size*_growThreshold)
00557      Resize(_size*_growFactor);
00558 
00559    Hash_Entry<_Key, _Data>* hash_entry = 
00560      new Hash_Entry<_Key, _Data>(key, data);
00561 
00562    Hash_Entry<_Key, _Data>** link = Find_Hash_Entry(key);
00563   
00564    //ASSERT(*link != NULL);
00565 
00566    _numEntries++;
00567    *link = hash_entry;
00568    //cout << "hashtable [] 3: link" << *link << endl;
00569 
00570    return (hash_entry->Data());
00571  }
00572 }
00573 
00574 /****************************************************************************/
00575 /*    Hash_Ptr::Set_Next_Hash_Entry()                                       */
00576 /****************************************************************************/
00577 template <class _Key, class _Data>
00578 void Hash_Ptr<_Key, _Data>::Set_Next_Hash_Entry()
00579 {
00580   if (_hashEntry != NULL && _hashEntry->Next() != NULL) {
00581     _hashEntry = _hashEntry->Next();
00582     return;
00583   }
00584   
00585   while (++_index < _hash->_size)
00586     if (_hash->_hashTbl[_index] != NULL) {
00587       _hashEntry = _hash->_hashTbl[_index];
00588       return;
00589     }
00590   
00591   _hashEntry = NULL;
00592 }
00593 
00594 
00595 template <class _Key, class _Data>
00596 void HashUpdateIntData(Hash_Table<_Key, _Data>& t, _Key key, _Data i)
00597 {
00598   _Data *tmp = t.Fetch(key);
00599   if (tmp) *tmp = *tmp + i;
00600   else t.Insert(key, i);
00601 }
00602 
00603 
00604 #ifdef DEBUG
00605 /****************************************************************************/
00606 /*    Hash_Entry::operator<<                                                */
00607 /****************************************************************************/
00608 template <class _Key, class _Data>
00609 void Hash_Entry<_Key, _Data>::Print()
00610 { 
00611   std::cout << "key: \"" << Key() << "\" data: " << Data() << '\n';
00612 }
00613 
00614 
00615 /****************************************************************************/
00616 /*    Hash_Table::operator<<                                                */
00617 /****************************************************************************/
00618 template <class _Key, class _Data>
00619 void Hash_Table<_Key, _Data>::Print()
00620 { 
00621   for (Hash_Ptr<_Key, _Data> ptr(this); !ptr.Null(); ++ptr) 
00622     ptr->Print();
00623 }
00624 #endif
00625 
00626 } // end of namespace CVCL
00627 
00628 #endif /* _hash_h_ */

Generated on Thu Apr 13 16:57:31 2006 for CVC Lite by  doxygen 1.4.4