hash_list.h

Go to the documentation of this file.
00001 #ifndef hash_list_h_included
00002 #define hash_list_h_included
00003 
00004 
00005 //
00006 // Copyright 2002, Lowell Boggs Jr.
00007 //
00008 // This file or directory, containing source code for a computer program,
00009 // is Copyrighted by Lowell Boggs, Jr.  987 Regency Drive, Lewisville
00010 // TX (USA), 75067.  You may use, copy, modify, and distribute this
00011 // source file without charge or obligation so long as you agree to
00012 // the following:
00013 //
00014 //  1.  You must indemnify Lowell Boggs against any and all financial
00015 //      obligations caused by its use, misuse, function, or malfunction.
00016 //      Further, you acknowledge that there is no warranty of any kind,
00017 //      whatsoever.
00018 //
00019 //  2.  You agree not to attempt to patent any portion of this original
00020 //      work -- though you may attempt to patent your own extensions to
00021 //      it if you so choose.
00022 //
00023 //  3.  You keep this copyright notice with the file and all copies
00024 //      of the file and do not change it anyway except language translation.
00025 //
00026 // You are responsible for enforcing your own compliance with these
00027 // conditions and may not use this source file if you cannot agree to the
00028 // above terms and conditions.
00029 
00030 
00031 
00032 
00033 #include <list>
00034 #include <vector>
00035 #include <utility>
00036 #include <cxxtls/hashers.h>
00037 
00038 namespace cxxtls
00039 {
00040 
00044 
00045 
00046 template<class Key, class Value, class Hash=Hasher<Key> >
00047 class hash_list
00048 //
00122 {
00123   Value empty_value_;  
00124 
00125 
00126 public:
00127 
00128   typedef hash_list<Key,Value,Hash>   self;
00129 
00130   typedef typename std::pair<Key,Value> mapped_type;
00134 
00135   struct value_type
00140     //
00141   {
00142     value_type *bucket_next_;  
00143 
00144     mapped_type data_;         
00145 
00146     value_type(value_type* bn, Key const &k, Value const &v)
00147     : bucket_next_(bn),
00148       data_(k,v)
00149     {
00156     }
00157 
00158   };
00159 
00160   typedef std::list<value_type>    List;    
00161   typedef std::vector<value_type*> Vector;  
00162 
00163   typedef typename List::iterator        iterator;        
00164   typedef typename List::const_iterator  const_iterator;  
00165 
00166 private:
00167 
00168   size_t size_;                      
00169   size_t average_chain_length_;      
00170   List   list_;                      
00171   Vector ht_;                        
00172   Hash hash;                         
00173 
00174 public:
00175 
00176   hash_list(int chain_length=10)
00177   :  size_(0),
00178      average_chain_length_(chain_length),
00179      ht_(10)
00180 
00183   {
00184      typename Vector::iterator first = ht_.begin();
00185      typename Vector::iterator last = ht_.end();
00186 
00187      while(first != last)
00188      {
00189         *first = 0;
00190         ++first;
00191      }
00192 
00193   }
00194 
00195   ~hash_list()
00197   {
00198   }
00199 
00200   size_t size() const { return size_; }  
00201 
00202   iterator begin() { return list_.begin(); } 
00203   iterator end()   { return list_.end();   } 
00204 
00205   const_iterator begin() const { return list_.begin(); } 
00206   const_iterator end()   const { return list_.end();   } 
00207 
00208   iterator insert(mapped_type const &data)
00217   //
00218   {
00219        list_.push_back( value_type(0, data.first, data.second) );
00220 
00221        iterator last = end();
00222 
00223        --last;
00224 
00225 
00226        value_type *p = & (*last);
00227 
00228        int hash_code = hash(data.first);
00229 
00230        hash_code %= ht_.size();
00231 
00232        last->bucket_next_ = ht_[hash_code];
00233 
00234        ht_[hash_code] = p;
00235 
00236        ++size_;
00237 
00238        if(size_ / ht_.size() > average_chain_length_)
00239        {
00240          resize();
00241        }
00242 
00243        return last;
00244   }
00245 
00246   void erase(iterator location)
00247    
00248     
00249 
00250 
00251 
00252 
00253 
00254 
00255   {
00256     value_type *p = &(*location);
00257 
00258     int bucket =  hash(p->data_.first) % ht_.size();
00259 
00260     if(ht_[bucket] == p)
00261     {
00262        // erasing first item in the bucket
00263 
00264        ht_[bucket] = p->bucket_next_;
00265 
00266     }
00267     else
00268     {
00269        // unlink the guy from inside the bucket's chain somewhere
00270 
00271        value_type *scan = ht_[bucket];
00272 
00273        while(scan->bucket_next_)
00274        {
00275          if(scan->bucket_next_ == p)
00276          {
00277            scan->bucket_next_ = p->bucket_next_;
00278            break;
00279          }
00280 
00281          scan = scan->bucket_next_;
00282 
00283        }
00284 
00285     }
00286 
00287     list_.erase(location);
00288 
00289     --size_;
00290 
00291   }
00292 
00293   iterator find(Key const &key)
00294     
00295     
00296 
00297     
00298   {
00299     int hash_code = hash(key);
00300 
00301     hash_code %= ht_.size();
00302 
00303     value_type* scan = ht_[hash_code];
00304 
00305     while(scan)
00306     {
00307        if(scan->data_.first == key)
00308        {
00309 
00310           // this code assumes that the value_type object is
00311           // encased in a list_node which looks like this
00312           //
00313           //   list_node* next_;
00314           //   list_node* prev_;
00315           //   value_type v_;
00316           //
00317           // And that you can thus subtract 2 * sizeof list_node*
00318           // from the address of the value type to get the address
00319           // of the node type.
00320           //
00321           // It further assumes that an iterator is just a pointer
00322           // to a list_node.
00323           //
00324           // There will have to be #if's for this logic on
00325           // each platform.
00326 
00327           iterator rv;
00328 
00329           char *p = (char*)scan;
00330 
00331           p -= 2 * sizeof(void*);
00332 
00333           char **x = (char **)&rv;
00334 
00335           x[0] = p;
00336 
00337           return rv;
00338        }
00339 
00340        scan = scan->bucket_next_;
00341     }
00342 
00343     return end();
00344 
00345   }
00346 
00347   const_iterator find( Key const &index ) const
00350   {
00351      self * me = (self*)(this);  // unconstify
00352 
00353      return me->find(index);
00354 
00355   }
00356 
00357 
00358   Value const &operator[] (Key const &index) const
00359     
00367     //
00368   {
00369     const_iterator rv = find(index);
00370 
00371     if(rv == end())
00372       return empty_value_;
00373 
00374     return rv->data_.second;
00375   }
00376 
00377   struct index_helper
00378     //
00435   {
00436      typedef hash_list<Key, Value, Hash> HL;      
00437      Key const&                            key_;  
00438      HL*                                   list_; 
00439 
00440      index_helper(Key const& k, HL *l)
00441      : key_(k),
00442        list_(l)
00443      {
00445      }
00446 
00447      operator Value const &()
00448         //
00456      {
00457         iterator ptr = list_->find(key_);
00458         
00459         if(ptr == list_->end())
00460           return list_->empty_value_;
00461 
00462         return ptr->data_.second;
00463         
00464      }
00465 
00466 
00467      Value const &operator=( Value const &r )
00468         //
00475      {
00476 
00477         iterator ptr = list_->find(key_);
00478         
00479         if(ptr != list_->end())
00480         {
00481            list_->erase(ptr);
00482         }
00483         
00484         list_->insert( mapped_type(key_,r) );
00485         
00486         return r;
00487         
00488 
00489      }
00490 
00491 
00492   };
00493 
00494   friend class index_helper;
00495 
00496 
00497   index_helper operator [] (Key const &index)
00500   {
00501     // see the index_helper struct above for an explaination of
00502     // how this works
00503 
00504     return index_helper(index,this);
00505   }
00506 
00507 
00508 
00509 private:
00510 
00511   void resize()
00512   {
00516 
00517     int new_size = size_ / average_chain_length_;
00518 
00519     if(new_size < 10)
00520       new_size = 10;
00521 
00522     Vector new_table( new_size );
00523 
00524     while(new_table.size() != (unsigned)(new_size))
00525     {
00526       new_table.push_back(0);
00527     }
00528 
00529     ht_.swap(new_table);
00530 
00531     // now the hash table is larger but empty and the
00532     // bucket_next_ links in list_ are all wrong --
00533     // rebuild them all from scratch
00534 
00535     typename List::iterator f = list_.begin();
00536     typename List::iterator l = list_.end();
00537 
00538     while(f != l)
00539     {
00540       value_type *cur = &(*f);
00541 
00542       int hash_code = hash(cur->data_.first);
00543 
00544       hash_code %= ht_.size();
00545 
00546       cur->bucket_next_ = ht_[hash_code];
00547 
00548       ht_[hash_code] = cur;
00549 
00550       ++f;
00551     }
00552 
00553     // done!
00554   }
00555 };
00556 } // namespace cxxtls
00557 #endif
Generated on Wed Feb 29 22:50:04 2012 for CXXUtilities by  doxygen 1.6.3