topical media & game development

talk show tell print

professional-program-23-Hashmap-BasicHashmap-hashmap.c

? / professional-program-23-Hashmap-BasicHashmap-hashmap.c


  // Throws invalid_argument if numBuckets is non-positive
  template <typename T>
  DefaultHash<T>::DefaultHash(int numBuckets) throw (invalid_argument)
  {
    if (numBuckets <= 0) {
      throw (invalid_argument("numBuckets must be > 0"));
    }
    mNumBuckets = numBuckets;
  }
  
  // Uses the division method for hashing.
  // Treats the key as a sequence of bytes, sums the ASCII
  // values of the bytes, and mods the total by the number
  // of buckets.
  template <typename T>
  int DefaultHash<T>::hash(const T& key) const
  {
    int bytes = sizeof(key);
    unsigned long res = 0;
    for (int i = 0; i < bytes; ++i) {
      res += *((char*)&key + i);
    }
    return (res % mNumBuckets);
  }
  
  // Throws invalid_argument if numBuckets is non-positive
  DefaultHash<string>::DefaultHash(int numBuckets) throw (invalid_argument)
  {
    if (numBuckets <= 0) {
      throw (invalid_argument("numBuckets must be > 0"));
    }
    mNumBuckets = numBuckets;
  }
  
  // Uses the division method for hashing after summing the
  // ASCII values of all the characters in key.
  int DefaultHash<string>::hash(const string& key) const
  {
    int sum = 0;
  
    for (size_t i = 0; i < key.size(); i++) {
      sum += key[i];
    }
    return (sum % mNumBuckets);
  }
  
  // Construct mElems with the number of buckets.
  template <typename Key, typename T, typename Compare, typename Hash>
  hashmap<Key, T, Compare, Hash>::hashmap(
                                          const Compare& comp, const Hash& hash) throw(invalid_argument) :
    mSize(0), mComp(comp), mHash(hash)
  {
    if (mHash.numBuckets() <= 0) {
      throw (invalid_argument("Number of buckets must be positive"));
    }
    mElems = new vector<list<value_type> >(mHash.numBuckets());
  }
  
  template <typename Key, typename T, typename Compare, typename Hash>
  hashmap<Key, T, Compare, Hash>::~hashmap()
  {
    delete mElems;
  }
  
  template <typename Key, typename T, typename Compare, typename Hash>
  hashmap<Key, T, Compare, Hash>::hashmap(const hashmap<
                                          Key, T, Compare, Hash>& src) :
    mSize(src.mSize), mComp(src.mComp), mHash(src.mHash)
  {
    // Don't need to bother checking if numBuckets is positive, because
    // we know src checked.
  
    // Use the vector copy constructor
    mElems = new vector<list<value_type> >(*(src.mElems));
  }
  
  template <typename Key, typename T, typename Compare, typename Hash>
  hashmap<Key, T, Compare, Hash>& hashmap<Key, T, Compare, Hash>::operator=(
                                                                            const hashmap<Key, T, Compare, Hash>& rhs)
  {
    // check for self-assignment
    if (this != &rhs) {
      delete mElems;
      mSize = rhs.mSize;
      mComp = rhs.mComp;
      mHash = rhs.mHash;
      // Don't need to bother checking if numBuckets is positive, because
      // we know rhs checked
  
      // Use the vector copy constructor
      mElems = new vector<list<value_type> >(*(rhs.mElems));
    }
  }
  
  template <typename Key, typename T, typename Compare, typename Hash>
  typename list<pair<const Key, T> >::iterator
  hashmap<Key, T, Compare, Hash>::findElement(const key_type& x, int& bucket) const
  {
    // hash the key to get the bucket
    bucket = mHash.hash(x);
  
    // Look for the key in the bucket
    for (typename ListType::iterator it = (*mElems)[bucket].begin();
         it != (*mElems)[bucket].end(); ++it) {
      if (mComp(it->first, x)) {
        return (it);
      }
    }
    return ((*mElems)[bucket].end());
  }
  
  template <typename Key, typename T, typename Compare, typename Hash>
  typename hashmap<Key, T, Compare, Hash>::value_type*
  hashmap<Key, T, Compare, Hash>::find(const key_type& x)
  {
    int bucket;
    // Use the findElement() helper
    typename ListType::iterator it = findElement(x, bucket);
    if (it == (*mElems)[bucket].end()) {
      // we didn't find the element -- return NULL
      return (NULL);
    }
    // We found the element. Return a pointer to it.
    return (&(*it));
  }
  
  template <typename Key, typename T, typename Compare, typename Hash>
  T& hashmap<Key, T, Compare, Hash>::operator[] (const key_type& x)
  {
    // Try to find the element.
    // If it doesn't exist, add a new element.
    value_type* found = find(x);
    if (found == NULL) {
      insert(make_pair(x, T()));
      found = find(x);
    }
    return (found->second);
  }
  
  template <typename Key, typename T, typename Compare, typename Hash>
  void hashmap<Key, T, Compare, Hash>::insert(const value_type& x)
  {
    int bucket;
    // Try to find the element
    typename ListType::iterator it = findElement(x.first, bucket);
  
    if (it != (*mElems)[bucket].end()) {
      // The element already exists
      return;
    } else {
      // We didn't find the element, so insert a new one.
      mSize++;
      (*mElems)[bucket].insert((*mElems)[bucket].end(), x);
    }
  }
  
  template <typename Key, typename T, typename Compare, typename Hash>
  void
  hashmap<Key, T, Compare, Hash>::erase(const key_type& x)
  {
    int bucket;
  
    // First, try to find the element
    typename ListType::iterator it = findElement(x, bucket);
  
    if (it != (*mElems)[bucket].end()) {
      // The element already exists -- erase it
      (*mElems)[bucket].erase(it);
      mSize--;
    }
  }
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.