// @HEADER // *********************************************************************** // // Teuchos: Common Tools Package // Copyright (2004) Sandia Corporation // // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive // license for use of this work by or on behalf of the U.S. Government. // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // USA // Questions? Contact Michael A. Heroux (maherou@sandia.gov) // // *********************************************************************** // @HEADER #ifndef TEUCHOS_HASHTABLE_H #define TEUCHOS_HASHTABLE_H /*! \file Teuchos_Hashtable.hpp \brief Templated hashtable class */ #include "Teuchos_ConfigDefs.hpp" #include "Teuchos_Array.hpp" #include "Teuchos_HashUtils.hpp" namespace Teuchos { using std::string; /** \ingroup Containers * \brief Helper class for Teuchos::Hashtable, representing a single pair. */ template class HashPair { public: //! Empty constructor inline HashPair() : key_(), value_() {;} //! Basic constructor inline HashPair(const Key& key, const Value& value) : key_(key), value_(value) {;} //! Templated key variable Key key_; //! Templated value variable Value value_; }; /** \ingroup Containers \brief Templated hashtable class. @author Kevin Long */ template class Hashtable { public: //! Create an empty Hashtable inline Hashtable(int capacity=101, double rehashDensity = 0.8); //! Check for the presence of a key inline bool containsKey(const Key& key) const ; //! Get the value indexed by key inline const Value& get(const Key& key) const ; //! Put a new (key, value) pair in the table. inline void put(const Key& key, const Value& value); //! Remove from the table the element given by key. inline void remove(const Key& key); //! Get the number of elements in the table inline int size() const {return count_;} //! Get lists of keys and values in Array form inline void arrayify(Array& keys, Array& values) const ; //! Return the average degeneracy (average number of entries per hash code). inline double avgDegeneracy() const {return avgDegeneracy_;} //! Return the density of the hashtable (num entries / capacity) inline double density() const {return ((double)count_)/((double) capacity_);} //! Set the density at which to do a rehash inline void setRehashDensity(double rehashDensity); //! Write to a std::string inline std::string toString() const ; private: inline void rehash(); inline int nextPrime(int newCap) const ; inline void accumulateAvgFill(int n) const ; Array > > data_; int count_; int capacity_; mutable Value mostRecentValue_; mutable Key mostRecentKey_; mutable int nHits_; mutable double avgDegeneracy_; double rehashDensity_; }; template std::string toString(const Hashtable& h); /** \relates Hashtable \brief Write Hashtable to a stream */ template std::ostream& operator<<(std::ostream& os, const Hashtable& h); template inline Hashtable::Hashtable(int capacity, double rehashDensity) : data_(), count_(0), capacity_(HashUtils::nextPrime(capacity)), nHits_(0), avgDegeneracy_(0), rehashDensity_(rehashDensity) { data_.resize(capacity_); } template inline bool Hashtable::containsKey(const Key& key) const { const Array >& candidates = data_[hashCode(key) % capacity_]; for (int i=0; i& c = candidates[i]; if (c.key_ == key) { // (Key&) mostRecentKey_ = key; //(Value&) mostRecentValue_ = c.value_; return true; } } return false; } template inline void Hashtable::put(const Key& key, const Value& value) { int index = hashCode(key) % capacity_; Array >& local = data_[index]; // check for duplicate key for (int i=0; i rehashDensity_ * (double) capacity_) { capacity_ = HashUtils::nextPrime(capacity_+1); rehash(); // recaluate index index = hashCode(key) % capacity_; } data_[index].append(HashPair(key, value)); } template inline void Hashtable::rehash() { Array > > tmp(capacity_); for (int i=0; i inline void Hashtable::arrayify(Array& keys, Array& values) const { keys.reserve(size()); values.reserve(size()); for (int i=0; i inline std::string Hashtable::toString() const { Array keys; Array values; arrayify(keys, values); std::string rtn = "["; for (int i=0; i inline std::string toString(const Hashtable& h) { Array keys; Array values; h.arrayify(keys, values); std::string rtn = "["; for (int i=0; i inline const Value& Hashtable::get(const Key& key) const { TEST_FOR_EXCEPTION(!containsKey(key), std::runtime_error, "Hashtable::get: key " << Teuchos::toString(key) << " not found in Hashtable" << toString()); const Array >& candidates = data_[hashCode(key) % capacity_]; accumulateAvgFill(candidates.length()); for (int i=0; i& c = candidates[i]; if (c.key_ == key) { return c.value_; } } return mostRecentValue_; } template inline void Hashtable::remove(const Key& key) { TEST_FOR_EXCEPTION(!containsKey(key), std::runtime_error, "Hashtable::remove: key " << Teuchos::toString(key) << " not found in Hashtable" << toString()); count_--; int h = hashCode(key) % capacity_; const Array >& candidates = data_[h]; for (int i=0; i& c = candidates[i]; if (c.key_ == key) { data_[h].remove(i); break; } } } template inline void Hashtable::accumulateAvgFill(int n) const { avgDegeneracy_ = ((double) nHits_)/(nHits_ + 1.0) * avgDegeneracy_ + ((double) n)/(nHits_ + 1.0); nHits_++; } template inline std::ostream& operator<<(std::ostream& os, const Hashtable& h) { return os << toString(h); } } #endif // TEUCHOS_HASHTABLE_H