Teuchos Package Browser (Single Doxygen Collection)  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Teuchos_Hashtable.hpp
Go to the documentation of this file.
00001 // @HEADER
00002 // ***********************************************************************
00003 //
00004 //                    Teuchos: Common Tools Package
00005 //                 Copyright (2004) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ***********************************************************************
00040 // @HEADER
00041 
00042 #ifndef TEUCHOS_HASHTABLE_H
00043 #define TEUCHOS_HASHTABLE_H
00044 
00049 #include "Teuchos_ConfigDefs.hpp"
00050 #include "Teuchos_Array.hpp"
00051 #include "Teuchos_HashUtils.hpp"
00052 
00053 namespace Teuchos
00054 {
00055   using std::string;
00056 
00060   template<class Key, class Value> class HashPair
00061     {
00062     public:
00064       inline HashPair() : key_(), value_() {;}
00066       inline HashPair(const Key& key, const Value& value)
00067         : key_(key), value_(value) {;}
00068 
00070       Key key_;
00072       Value value_;
00073     };
00074 
00080   template<class Key, class Value> class Hashtable
00081     {
00082     public:
00083 
00085       inline Hashtable(int capacity=101, double rehashDensity = 0.8);
00086 
00088       inline bool containsKey(const Key& key) const ;
00089 
00091       inline const Value& get(const Key& key) const ;
00092 
00094       inline void put(const Key& key, const Value& value);
00095 
00097       inline void remove(const Key& key);
00098 
00100       inline int size() const {return count_;}
00101 
00103       inline void arrayify(Array<Key>& keys, Array<Value>& values) const ;
00104 
00106       inline double avgDegeneracy() const {return avgDegeneracy_;}
00107 
00109       inline double density() const {return ((double)count_)/((double) capacity_);}
00110 
00112       inline void setRehashDensity(double rehashDensity);
00113 
00115       inline std::string toString() const ;
00116 
00117     private:
00118 
00119       inline void rehash();
00120       inline int nextPrime(int newCap) const ;
00121       inline void accumulateAvgFill(int n) const ;
00122 
00123 
00124       Array<Array<HashPair<Key, Value> > > data_;
00125       int count_;
00126       int capacity_;
00127       mutable Value mostRecentValue_;
00128       mutable Key mostRecentKey_;
00129 
00130       mutable size_t nHits_;
00131       mutable double avgDegeneracy_;
00132       double rehashDensity_;
00133     };
00134 
00135   template<class Key, class Value>
00136   std::string toString(const Hashtable<Key, Value>& h);
00137 
00141   template<class Key, class Value>
00142   std::ostream& operator<<(std::ostream& os, const Hashtable<Key, Value>& h);
00143 
00144   template<class Key, class Value> inline
00145     Hashtable<Key, Value>::Hashtable(int capacity, double rehashDensity):
00146     data_(),
00147     count_(0),
00148     capacity_(HashUtils::nextPrime(capacity)),
00149     nHits_(0),
00150     avgDegeneracy_(0),
00151     rehashDensity_(rehashDensity)
00152     {
00153       data_.resize(capacity_);
00154     }
00155 
00156   template<class Key, class Value> inline
00157     bool Hashtable<Key, Value>::containsKey(const Key& key) const
00158     {
00159       const Array<HashPair<Key, Value> >& candidates
00160         = data_[hashCode(key) % capacity_];
00161 
00162       for (int i=0; i<candidates.length(); i++)
00163         {
00164           const HashPair<Key, Value>& c = candidates[i];
00165           if (c.key_ == key)
00166             {
00167               //          (Key&) mostRecentKey_ = key;
00168               //(Value&) mostRecentValue_ = c.value_;
00169               return true;
00170             }
00171         }
00172       return false;
00173     }
00174 
00175   template<class Key, class Value> inline
00176     void Hashtable<Key, Value>::put(const Key& key, const Value& value)
00177     {
00178       int index = hashCode(key) % capacity_;
00179 
00180       Array<HashPair<Key, Value> >& local = data_[index];
00181 
00182       // check for duplicate key
00183       for (int i=0; i<local.length(); i++)
00184         {
00185           if (local[i].key_ == key)
00186             {
00187               local[i].value_ = value;
00188               return;
00189             }
00190         }
00191 
00192       // no duplicate key, so increment element count by one.
00193       count_++;
00194 
00195       // check for need to resize.
00196       if ((double) count_ > rehashDensity_ * (double) capacity_)
00197         {
00198           capacity_ = HashUtils::nextPrime(capacity_+1);
00199           rehash();
00200           // recaluate index
00201           index = hashCode(key) % capacity_;
00202         }
00203 
00204       data_[index].append(HashPair<Key, Value>(key, value));
00205     }
00206 
00207 
00208 
00209   template<class Key, class Value> inline
00210     void Hashtable<Key, Value>::rehash()
00211     {
00212       Array<Array<HashPair<Key, Value> > > tmp(capacity_);
00213 
00214       for (int i=0; i<data_.length(); i++)
00215         {
00216           for (int j=0; j<data_[i].length(); j++)
00217             {
00218               int newIndex = hashCode(data_[i][j].key_) % capacity_;
00219               tmp[newIndex].append(data_[i][j]);
00220             }
00221         }
00222 
00223       data_ = tmp;
00224     }
00225 
00226 
00227   template<class Key, class Value> inline
00228     void Hashtable<Key, Value>::arrayify(Array<Key>& keys, Array<Value>& values) const
00229     {
00230       keys.reserve(size());
00231       values.reserve(size());
00232 
00233       for (int i=0; i<data_.length(); i++)
00234         {
00235           for (int j=0; j<data_[i].length(); j++)
00236             {
00237               keys.append(data_[i][j].key_);
00238               values.append(data_[i][j].value_);
00239             }
00240         }
00241     }
00242 
00243   template<class Key, class Value>  inline
00244   std::string Hashtable<Key, Value>::toString() const
00245   {
00246     Array<Key> keys;
00247     Array<Value> values;
00248     arrayify(keys, values);
00249 
00250     std::string rtn = "[";
00251     for (int i=0; i<keys.length(); i++)
00252       {
00253         rtn += "{" + Teuchos::toString(keys[i]) + ", " + Teuchos::toString(values[i])
00254           + "}";
00255         if (i < keys.length()-1) rtn += ", ";
00256       }
00257     rtn += "]";
00258 
00259     return rtn;
00260   }
00261 
00262   template<class Key, class Value>  inline
00263     std::string toString(const Hashtable<Key, Value>& h)
00264     {
00265       Array<Key> keys;
00266       Array<Value> values;
00267       h.arrayify(keys, values);
00268 
00269       std::string rtn = "[";
00270       for (int i=0; i<keys.length(); i++)
00271         {
00272           rtn += "{" + Teuchos::toString(keys[i]) + ", " + Teuchos::toString(values[i])
00273             + "}";
00274           if (i < keys.length()-1) rtn += ", ";
00275         }
00276       rtn += "]";
00277 
00278       return rtn;
00279     }
00280 
00281   template<class Key, class Value> inline
00282     const Value& Hashtable<Key, Value>::get(const Key& key) const
00283     {
00284       TEUCHOS_TEST_FOR_EXCEPTION(!containsKey(key),
00285                          std::runtime_error,
00286                          "Hashtable<Key, Value>::get: key "
00287                          << Teuchos::toString(key)
00288                          << " not found in Hashtable"
00289                          << toString());
00290 
00291       const Array<HashPair<Key, Value> >& candidates
00292         = data_[hashCode(key) % capacity_];
00293 
00294       accumulateAvgFill(candidates.length());
00295 
00296       for (int i=0; i<candidates.length(); i++)
00297         {
00298           const HashPair<Key, Value>& c = candidates[i];
00299           if (c.key_ == key)
00300             {
00301               return c.value_;
00302             }
00303         }
00304       return mostRecentValue_;
00305     }
00306 
00307 
00308   template<class Key, class Value> inline
00309     void Hashtable<Key, Value>::remove(const Key& key)
00310     {
00311       TEUCHOS_TEST_FOR_EXCEPTION(!containsKey(key),
00312                          std::runtime_error,
00313                          "Hashtable<Key, Value>::remove: key "
00314                          << Teuchos::toString(key)
00315                          << " not found in Hashtable"
00316                          << toString());
00317 
00318       count_--;
00319       int h = hashCode(key) % capacity_;
00320       const Array<HashPair<Key, Value> >& candidates = data_[h];
00321 
00322       for (int i=0; i<candidates.length(); i++)
00323         {
00324           const HashPair<Key, Value>& c = candidates[i];
00325           if (c.key_ == key)
00326             {
00327               data_[h].remove(i);
00328               break;
00329             }
00330         }
00331     }
00332 
00333   template<class Key, class Value> inline
00334   void Hashtable<Key, Value>::accumulateAvgFill(int n) const
00335   {
00336     avgDegeneracy_ = ((double) nHits_)/(nHits_ + 1.0) * avgDegeneracy_ + ((double) n)/(nHits_ + 1.0);
00337     nHits_++;
00338     }
00339 
00340   template<class Key, class Value>  inline
00341     std::ostream& operator<<(std::ostream& os, const Hashtable<Key, Value>& h)
00342     {
00343       return os << toString(h);
00344     }
00345 
00346 
00347 }
00348 
00349 #endif // TEUCHOS_HASHTABLE_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines