//===- HashBase.h ---------------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef MCLD_ADT_HASHBASE_H
#define MCLD_ADT_HASHBASE_H
#include <llvm/ADT/StringRef.h>
#include <cstdlib>

namespace mcld {

/** forward declaration **/
template<typename HashTableImplTy>
class ChainIteratorBase;

template<typename HashTableImplTy>
class EntryIteratorBase;

/** \class HashBucket
 *  \brief HashBucket is an entry in the hash table.
 */
template<typename HashEntryTy>
class HashBucket
{
public:
  typedef HashEntryTy entry_type;

public:
  unsigned int FullHashValue;
  entry_type *Entry;

public:
  static entry_type* getEmptyBucket();
  static entry_type* getTombstone();

};

/** \class HashTableImpl
 *  \brief HashTableImpl is the base class of HashTable.
 *
 *  HashTableImpl uses open-addressing, linear probing hash table.
 *  linear probing hash table obviously has high performance when the
 *  load factor is less than 0.7.
 *  The drawback is that the number of the stored items can notbe more
 *  than the size of the hash table.
 *
 *  MCLinker tries to merge every things in the same HashEntry. It can
 *  keep every thing in the same cache line and improve the locality
 *  efficiently. HashTableImpl provides a template argument to change the
 *  definition of HashEntries.
 *
 *  HashEntryTy must provide getKey() and getKenLength() functions.
 *
 *  Different environments have different demands of HashFunctions. For
 *  example, on-device linkers needs a more light-weight hash function
 *  than static linkers. HashTableImpl also provides a template argument to
 *  change the hash functions.
 */
template<typename HashEntryTy,
         typename HashFunctionTy>
class HashTableImpl
{
private:
  static const unsigned int NumOfInitBuckets = 16;

public:
  typedef size_t size_type;
  typedef HashFunctionTy hasher;
  typedef HashEntryTy entry_type;
  typedef typename HashEntryTy::key_type key_type;
  typedef HashBucket<HashEntryTy> bucket_type;
  typedef HashTableImpl<HashEntryTy, HashFunctionTy> Self;


public:
  HashTableImpl();
  explicit HashTableImpl(unsigned int pInitSize);
  virtual ~HashTableImpl();

  // -----  observers  ----- //
  bool empty() const;

  size_t numOfBuckets() const
  { return m_NumOfBuckets; }

  size_t numOfEntries() const
  { return m_NumOfEntries; }

  hasher& hash()
  { return m_Hasher; }

  const hasher& hash() const
  { return m_Hasher; }

protected:
  /// initialize the hash table.
  void init(unsigned int pInitSize);

  void clear();

  /// lookUpBucketFor - search the index of bucket whose key is p>ey
  //  @return the index of the found bucket
  unsigned int lookUpBucketFor(const key_type& pKey);

  /// findKey - finds an element with key pKey
  //  return the index of the element, or -1 when the element does not exist.
  int findKey(const key_type& pKey) const;

  /// mayRehash - check the load_factor, compute the new size, and then doRehash
  void mayRehash();

  /// doRehash - re-new the hash table, and rehash all elements into the new buckets
  void doRehash(unsigned int pNewSize);

friend class ChainIteratorBase<Self>;
friend class ChainIteratorBase<const Self>;
friend class EntryIteratorBase<Self>;
friend class EntryIteratorBase<const Self>;
protected:
  // Array of Buckets
  bucket_type* m_Buckets;
  unsigned int m_NumOfBuckets;
  unsigned int m_NumOfEntries;
  unsigned int m_NumOfTombstones;
  hasher m_Hasher;

};

#include "HashBase.tcc"

} // namespace of mcld

#endif