Shinya Kitaoka 810553
#pragma once
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifndef TCG_HASH_H
Toshihiro Shimizu 890ddd
#define TCG_HASH_H
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tcg includes
Toshihiro Shimizu 890ddd
#include "list.h"
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace tcg {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Toshihiro Shimizu 890ddd
  The hash class implements a hash map using tcg lists
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
template <typename &)="" (*)(const="" hash_functor="size_t" k="" k,="" t,="" typename=""></typename>
Shinya Kitaoka 120a6e
class hash {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  typedef K key_type;
Shinya Kitaoka 120a6e
  typedef T value_type;
Shinya Kitaoka 120a6e
  typedef Hash_functor hash_type;
Toshihiro Shimizu 890ddd
Grillo d28d00
  struct BucketNode;
Grillo d28d00
  typedef typename tcg::list<bucketnode>::size_t size_t;</bucketnode>
Grillo d28d00
  typedef typename tcg::list<bucketnode>::iterator iterator;</bucketnode>
Grillo d28d00
  typedef typename tcg::list<bucketnode>::const_iterator const_iterator;</bucketnode>
Grillo d28d00
Shinya Kitaoka 120a6e
  struct BucketNode {
Shinya Kitaoka 120a6e
    K m_key;
Shinya Kitaoka 120a6e
    T m_val;
Shinya Kitaoka 120a6e
    size_t m_next;
Shinya Kitaoka 120a6e
    size_t m_prev;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    BucketNode(const K &key, const T &val)
Shinya Kitaoka 120a6e
        : m_key(key), m_val(val), m_next(-1), m_prev(-1) {}
Shinya Kitaoka 120a6e
    BucketNode(const std::pair<k, t=""> &pair)</k,>
Shinya Kitaoka 120a6e
        : m_key(pair.first), m_val(pair.second), m_next(-1), m_prev(-1) {}
Shinya Kitaoka 120a6e
    ~BucketNode() {}
Shinya Kitaoka 120a6e
  };
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  std::vector<size_t> m_bucketsIdx;</size_t>
Shinya Kitaoka 120a6e
  tcg::list<bucketnode> m_items;</bucketnode>
Shinya Kitaoka 120a6e
  Hash_functor m_hash;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  bool createItem(const K &key, const T &val) {
Shinya Kitaoka 120a6e
    m_items.push_back(BucketNode(key, val));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    size_t itemsCount = m_items.size(), bucketsCount = m_bucketsIdx.size();
Shinya Kitaoka 120a6e
    if (itemsCount > bucketsCount) {
Shinya Kitaoka 120a6e
      do
Shinya Kitaoka 120a6e
        bucketsCount =
Shinya Kitaoka 120a6e
            2 * bucketsCount + 1;  // Please, note that 2n here would be moronic
Shinya Kitaoka 120a6e
      while (itemsCount > bucketsCount);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      rehash(bucketsCount);
Shinya Kitaoka 120a6e
      return true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  size_t touchKey(const K &key, const T &val = T()) {
Shinya Kitaoka 120a6e
    size_t hashValue = m_hash(key) % m_bucketsIdx.size();
Shinya Kitaoka 120a6e
    size_t bucketIdx = m_bucketsIdx[hashValue];
Shinya Kitaoka 120a6e
    size_t oldIdx    = _neg;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (bucketIdx == _neg) {
Shinya Kitaoka 120a6e
      // A new bucket is created
Shinya Kitaoka 120a6e
      bool rehashed = createItem(key, val);
Shinya Kitaoka 120a6e
      bucketIdx     = m_items.last().m_idx;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (!rehashed)
Shinya Kitaoka 120a6e
        // Need to manually update the stored bucket index
Shinya Kitaoka 120a6e
        m_bucketsIdx[hashValue] = bucketIdx;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      return bucketIdx;
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      // Bucket exists - search key in it
Shinya Kitaoka 120a6e
      for (; bucketIdx != _neg && m_items[bucketIdx].m_key != key;
Shinya Kitaoka 120a6e
           oldIdx = bucketIdx, bucketIdx = m_items[bucketIdx].m_next)
Shinya Kitaoka 120a6e
        ;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (bucketIdx == _neg) {
Shinya Kitaoka 120a6e
      // Key was not found - create an item and insert it
Shinya Kitaoka 120a6e
      bool rehashed = createItem(key, val);
Shinya Kitaoka 120a6e
      bucketIdx     = m_items.last().m_idx;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (!rehashed && oldIdx != _neg) {
Shinya Kitaoka 120a6e
        // Need to relink manually
Shinya Kitaoka 120a6e
        m_items[oldIdx].m_next    = bucketIdx;
Shinya Kitaoka 120a6e
        m_items[bucketIdx].m_prev = oldIdx;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    return bucketIdx;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  // NOTE: The defaulted 89 is a *good* initial buckets size when expanding by
Shinya Kitaoka 120a6e
  // the (2n+1) rule.
Shinya Kitaoka 120a6e
  // See http://www.concentric.net/~ttwang/tech/hashsize.htm for details
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  hash(const Hash_functor &func = Hash_functor(), size_t bucketsCount = 89)
Shinya Kitaoka 120a6e
      : m_bucketsIdx(bucketsCount, _neg), m_hash(func) {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  template <typename forit=""></typename>
Shinya Kitaoka 120a6e
  hash(ForIt begin, ForIt end, const Hash_functor &func = Hash_functor(),
Shinya Kitaoka 120a6e
       size_t bucketsCount = 89)
Shinya Kitaoka 120a6e
      : m_items(begin, end), m_hash(func) {
Shinya Kitaoka 120a6e
    for (size_t nCount = m_items.nodesCount(); bucketsCount < nCount;
Shinya Kitaoka 120a6e
         bucketsCount  = 2 * bucketsCount + 1)
Shinya Kitaoka 120a6e
      ;
Shinya Kitaoka 120a6e
    rehash(bucketsCount);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //! Constructs from a range of (index, value) item pairs
Shinya Kitaoka 120a6e
  template <typename bidit=""></typename>
Shinya Kitaoka 120a6e
  hash(BidIt begin, BidIt end, size_t nodesCount,
Shinya Kitaoka 120a6e
       const Hash_functor &func = Hash_functor(), size_t bucketsCount = 89)
Shinya Kitaoka 120a6e
      : m_items(begin, end, nodesCount), m_hash(func) {
Shinya Kitaoka 120a6e
    for (size_t nCount = m_items.nodesCount(); bucketsCount < nCount;
Shinya Kitaoka 120a6e
         bucketsCount  = 2 * bucketsCount + 1)
Shinya Kitaoka 120a6e
      ;
Shinya Kitaoka 120a6e
    rehash(bucketsCount);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void rehash(size_t newSize) {
Shinya Kitaoka 120a6e
    m_bucketsIdx.clear();
Shinya Kitaoka 120a6e
    m_bucketsIdx.resize(newSize, _neg);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    size_t bucketIdx;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    iterator it, iEnd = end();
Shinya Kitaoka 120a6e
    for (it = begin(); it != iEnd; ++it) {
Shinya Kitaoka 120a6e
      bucketIdx   = m_hash(it->m_key) % newSize;
Shinya Kitaoka 120a6e
      size_t &idx = m_bucketsIdx[bucketIdx];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      it->m_next = idx;
Shinya Kitaoka 120a6e
      it->m_prev = _neg;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
      if (idx != _neg) m_items[idx].m_prev = it.m_idx;
Shinya Kitaoka 120a6e
      idx                                  = it.m_idx;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  size_t size() const { return m_items.size(); }
Shinya Kitaoka 120a6e
  bool empty() { return size() == 0; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  void clear() {
Shinya Kitaoka 120a6e
    m_items.clear();
Shinya Kitaoka 120a6e
    m_bucketsIdx.clear();
Shinya Kitaoka 120a6e
    m_bucketsIdx.resize(1, _neg);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  iterator begin() { return m_items.begin(); }
Shinya Kitaoka 120a6e
  iterator last() { return m_items.last(); }
Shinya Kitaoka 120a6e
  iterator end() { return m_items.end(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const_iterator begin() const { return m_items.begin(); }
Shinya Kitaoka 120a6e
  const_iterator last() const { return m_items.last(); }
Shinya Kitaoka 120a6e
  const_iterator end() const { return m_items.end(); }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  iterator find(const K &key) {
Shinya Kitaoka 120a6e
    size_t hashValue = m_hash(key) % m_bucketsIdx.size();
Shinya Kitaoka 120a6e
    size_t bucketIdx = m_bucketsIdx[hashValue];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (bucketIdx == _neg) return end();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    for (; bucketIdx != _neg && m_items[bucketIdx].m_key != key;
Shinya Kitaoka 120a6e
         bucketIdx = m_items[bucketIdx].m_next)
Shinya Kitaoka 120a6e
      ;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    return bucketIdx == _neg ? end() : iterator(&m_items, bucketIdx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  const_iterator find(const K &key) const {
Shinya Kitaoka 120a6e
    return const_iterator(&m_items, const_cast<hash *="">(this)->find(key).m_idx);</hash>
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  iterator insert(const K &key, const T &val) {
Shinya Kitaoka 120a6e
    size_t idx         = touchKey(key);
Shinya Kitaoka 120a6e
    m_items[idx].m_val = val;
Shinya Kitaoka 120a6e
    return iterator(&m_items, idx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //!\warning Assignment of the kind hash_map[i1] = hash_map[i2] are DANGEROUS!
Shinya Kitaoka 38fd86
  //! The
Shinya Kitaoka 120a6e
  //! reference returned on the right may be INVALIDATED if the first key is
Shinya Kitaoka 120a6e
  //! inserted!
Shinya Kitaoka 120a6e
  T &operator[](const K &key) { return m_items[touchKey(key)].m_val; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //!\warning The same remark of operator[] applies here!
Shinya Kitaoka 120a6e
  T &touch(const K &key, const T &val) {
Shinya Kitaoka 120a6e
    return m_items[touchKey(key, val)].m_val;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  iterator insert(const std::pair<k, t=""> &pair) {</k,>
Shinya Kitaoka 120a6e
    return insert(pair.first, pair.second);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void erase(iterator it) {
Shinya Kitaoka 120a6e
    BucketNode &node                                     = *it;
Shinya Kitaoka 120a6e
    if (node.m_next != _neg) m_items[node.m_next].m_prev = node.m_prev;
Shinya Kitaoka 120a6e
    if (node.m_prev != _neg)
Shinya Kitaoka 120a6e
      m_items[node.m_prev].m_next = node.m_next;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      m_bucketsIdx[m_hash(node.m_key) % m_bucketsIdx.size()] = _neg;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_items.erase(it);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void erase(const K &key) {
Shinya Kitaoka 120a6e
    iterator it = find(key);
Shinya Kitaoka 120a6e
    if (it != end()) erase(it);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  friend void swap(hash &a, hash &b) {
Shinya Kitaoka 120a6e
    using std::swap;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    a.m_bucketsIdx.swap(b.m_bucketsIdx);
Shinya Kitaoka 120a6e
    swap(a.m_items, b.m_items);
Shinya Kitaoka 120a6e
    swap(a.m_hash, b.m_hash);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const tcg::list<bucketnode> &items() const { return m_items; }</bucketnode>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const std::vector<size_t> &buckets() const { return m_bucketsIdx; }</size_t>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //--------------------------------------------------------------------------
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const Hash_functor &hashFunctor() const { return m_hash; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  //! Remember to rehash() if the hash functor changes
Shinya Kitaoka 120a6e
  Hash_functor &hashFunctor() { return m_hash; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace tcg
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
#endif  // TCG_HASH_H