//===- HashIterator.h -----------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef MCLD_HASH_ITERATOR_H
#define MCLD_HASH_ITERATOR_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <cstddef>
namespace mcld {
/** \class ChainIteratorBase
* \brief ChaintIteratorBase follows the HashEntryTy with the same hash value.
*/
template<typename HashTableImplTy>
class ChainIteratorBase
{
public:
typedef HashTableImplTy hash_table;
typedef typename HashTableImplTy::key_type key_type;
typedef typename HashTableImplTy::entry_type entry_type;
typedef typename HashTableImplTy::bucket_type bucket_type;
public:
ChainIteratorBase()
: m_pHashTable(0), m_Index(0), m_HashValue(0), m_EndIndex(0)
{ }
ChainIteratorBase(HashTableImplTy* pTable, const key_type& pKey)
: m_pHashTable(pTable)
{
m_HashValue = pTable->hash()(pKey);
m_EndIndex = m_Index = m_HashValue % m_pHashTable->m_NumOfBuckets;
const unsigned int probe = 1;
while(true) {
bucket_type &bucket = m_pHashTable->m_Buckets[m_Index];
if (bucket_type::getTombstone() == bucket.Entry) {
// Ignore tombstones.
}
else if (m_HashValue == bucket.FullHashValue) {
if (bucket.Entry->compare(pKey)) {
m_EndIndex = m_Index;
break;
}
}
m_Index += probe;
if (m_Index == m_pHashTable->m_NumOfBuckets)
m_Index = 0;
// doesn't exist
if (m_EndIndex == m_Index) {
reset();
break;
}
}
}
ChainIteratorBase(const ChainIteratorBase& pCopy)
: m_pHashTable(pCopy.m_pHashTable),
m_Index(pCopy.m_Index),
m_HashValue(pCopy.m_HashValue),
m_EndIndex(pCopy.m_EndIndex)
{ }
ChainIteratorBase& assign(const ChainIteratorBase& pCopy) {
m_pHashTable = pCopy.m_pHashTable;
m_Index = pCopy.m_Index;
m_HashValue = pCopy.m_HashValue;
m_EndIndex = pCopy.m_EndIndex;
return *this;
}
inline bucket_type* getBucket() {
if (0 == m_pHashTable)
return 0;
return &(m_pHashTable->m_Buckets[m_Index]);
}
inline const bucket_type* getBucket() const {
if (0 == m_pHashTable)
return 0;
return &(m_pHashTable->m_Buckets[m_Index]);
}
inline entry_type* getEntry() {
if (0 == m_pHashTable)
return 0;
return m_pHashTable->m_Buckets[m_Index].Entry;
}
inline const entry_type* getEntry() const {
if (0 == m_pHashTable)
return 0;
return m_pHashTable->m_Buckets[m_Index].Entry;
}
inline void reset() {
m_pHashTable = 0;
m_Index = 0;
m_EndIndex = 0;
m_HashValue = 0;
}
inline void advance() {
if (0 == m_pHashTable)
return;
const unsigned int probe = 1;
while(true) {
m_Index += probe;
if (m_Index == m_pHashTable->m_NumOfBuckets)
m_Index = 0;
// reach end()
if (m_Index == m_EndIndex) {
reset();
return;
}
bucket_type &bucket = m_pHashTable->m_Buckets[m_Index];
if (bucket_type::getTombstone() == bucket.Entry ||
bucket_type::getEmptyBucket() == bucket.Entry) {
// Ignore tombstones.
}
else if (m_HashValue == bucket.FullHashValue) {
return;
}
}
}
bool operator==(const ChainIteratorBase& pCopy) const {
if (m_pHashTable == pCopy.m_pHashTable) {
if (0 == m_pHashTable)
return true;
return ((m_HashValue == pCopy.m_HashValue) &&
(m_EndIndex == pCopy.m_EndIndex) &&
(m_Index == pCopy.m_Index));
}
return false;
}
bool operator!=(const ChainIteratorBase& pCopy) const
{ return !(*this == pCopy); }
private:
HashTableImplTy* m_pHashTable;
unsigned int m_Index;
unsigned int m_HashValue;
unsigned int m_EndIndex;
};
/** \class EntryIteratorBase
* \brief EntryIteratorBase walks over hash table by the natural layout of the
* buckets
*/
template<typename HashTableImplTy>
class EntryIteratorBase
{
public:
typedef HashTableImplTy hash_table;
typedef typename HashTableImplTy::key_type key_type;
typedef typename HashTableImplTy::entry_type entry_type;
typedef typename HashTableImplTy::bucket_type bucket_type;
public:
EntryIteratorBase()
: m_pHashTable(0), m_Index(0)
{ }
EntryIteratorBase(HashTableImplTy* pTable,
unsigned int pIndex)
: m_pHashTable(pTable), m_Index(pIndex)
{ }
EntryIteratorBase(const EntryIteratorBase& pCopy)
: m_pHashTable(pCopy.m_pHashTable), m_Index(pCopy.m_Index)
{ }
EntryIteratorBase& assign(const EntryIteratorBase& pCopy) {
m_pHashTable = pCopy.m_pHashTable;
m_Index = pCopy.m_Index;
return *this;
}
inline bucket_type* getBucket() {
if (0 == m_pHashTable)
return 0;
return &(m_pHashTable->m_Buckets[m_Index]);
}
inline const bucket_type* getBucket() const {
if (0 == m_pHashTable)
return 0;
return &(m_pHashTable->m_Buckets[m_Index]);
}
inline entry_type* getEntry() {
if (0 == m_pHashTable)
return 0;
return m_pHashTable->m_Buckets[m_Index].Entry;
}
inline const entry_type* getEntry() const {
if (0 == m_pHashTable)
return 0;
return m_pHashTable->m_Buckets[m_Index].Entry;
}
inline void reset() {
m_pHashTable = 0;
m_Index = 0;
}
inline void advance() {
if (0 == m_pHashTable)
return;
do {
++m_Index;
if (m_pHashTable->m_NumOfBuckets == m_Index) { // to the end
reset();
return;
}
} while(bucket_type::getEmptyBucket() == m_pHashTable->m_Buckets[m_Index].Entry ||
bucket_type::getTombstone() == m_pHashTable->m_Buckets[m_Index].Entry);
}
bool operator==(const EntryIteratorBase& pCopy) const
{ return ((m_pHashTable == pCopy.m_pHashTable) &&
(m_Index == pCopy.m_Index)); }
bool operator!=(const EntryIteratorBase& pCopy) const
{ return !(*this == pCopy); }
private:
HashTableImplTy* m_pHashTable;
unsigned int m_Index;
};
/** \class HashIterator
* \brief HashIterator provides a policy-based iterator.
*
* HashTable has two kinds of iterators. One is used to traverse buckets
* with the same hash value; the other is used to traverse all entries of the
* hash table.
*
* HashIterator is a template policy-based iterator, which can change its
* behavior by change the template argument IteratorBase. HashTable defines
* above two iterators by defining HashIterators with different IteratorBase.
*/
template<typename IteratorBase,
typename Traits>
class HashIterator : public IteratorBase
{
public:
typedef Traits traits;
typedef typename traits::pointer pointer;
typedef typename traits::reference reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef IteratorBase Base;
typedef HashIterator<IteratorBase,
Traits> Self;
typedef typename traits::nonconst_traits nonconst_traits;
typedef HashIterator<IteratorBase,
nonconst_traits> iterator;
typedef typename traits::const_traits const_traits;
typedef HashIterator<IteratorBase,
const_traits> const_iterator;
typedef std::forward_iterator_tag iterator_category;
public:
HashIterator()
: IteratorBase()
{ }
/// HashIterator - constructor for EntryIterator
HashIterator(typename IteratorBase::hash_table* pTable, unsigned int pIndex)
: IteratorBase(pTable, pIndex)
{ }
/// HashIterator - constructor for ChainIterator
explicit HashIterator(typename IteratorBase::hash_table* pTable,
const typename IteratorBase::key_type& pKey,
int)
: IteratorBase(pTable, pKey)
{ }
HashIterator(const HashIterator& pCopy)
: IteratorBase(pCopy)
{ }
~HashIterator()
{ }
HashIterator& operator=(const HashIterator& pCopy) {
IteratorBase::assign(pCopy);
return *this;
}
// ----- operators ----- //
Self& operator++() {
this->Base::advance();
return *this;
}
Self operator++(int) {
Self tmp = *this;
this->Base::advance();
return tmp;
}
};
} // namespace of mcld
#endif