Home | History | Annotate | Download | only in ADT
      1 //===- HashIterator.h -----------------------------------------------------===//
      2 //
      3 //                     The MCLinker Project
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 #ifndef MCLD_HASH_ITERATOR_H
     10 #define MCLD_HASH_ITERATOR_H
     11 #ifdef ENABLE_UNITTEST
     12 #include <gtest.h>
     13 #endif
     14 
     15 #include <cstddef>
     16 
     17 namespace mcld {
     18 
     19 /** \class ChainIteratorBase
     20  *  \brief ChaintIteratorBase follows the HashEntryTy with the same hash value.
     21  */
     22 template<typename HashTableImplTy>
     23 class ChainIteratorBase
     24 {
     25 public:
     26   typedef HashTableImplTy hash_table;
     27   typedef typename HashTableImplTy::key_type key_type;
     28   typedef typename HashTableImplTy::entry_type entry_type;
     29   typedef typename HashTableImplTy::bucket_type bucket_type;
     30 
     31 public:
     32   ChainIteratorBase()
     33   : m_pHashTable(0), m_Index(0), m_HashValue(0), m_EndIndex(0)
     34   { }
     35 
     36   ChainIteratorBase(HashTableImplTy* pTable, const key_type& pKey)
     37   : m_pHashTable(pTable)
     38   {
     39     m_HashValue = pTable->hash()(pKey);
     40     m_EndIndex = m_Index = m_HashValue % m_pHashTable->m_NumOfBuckets;
     41     const unsigned int probe = 1;
     42     while(true) {
     43       bucket_type &bucket = m_pHashTable->m_Buckets[m_Index];
     44       if (bucket_type::getTombstone() == bucket.Entry) {
     45         // Ignore tombstones.
     46       }
     47       else if (m_HashValue == bucket.FullHashValue) {
     48         if (bucket.Entry->compare(pKey)) {
     49           m_EndIndex = m_Index;
     50           break;
     51         }
     52       }
     53       m_Index += probe;
     54       if (m_Index == m_pHashTable->m_NumOfBuckets)
     55         m_Index = 0;
     56       // doesn't exist
     57       if (m_EndIndex == m_Index) {
     58         reset();
     59         break;
     60       }
     61     }
     62   }
     63 
     64   ChainIteratorBase(const ChainIteratorBase& pCopy)
     65   : m_pHashTable(pCopy.m_pHashTable),
     66     m_Index(pCopy.m_Index),
     67     m_HashValue(pCopy.m_HashValue),
     68     m_EndIndex(pCopy.m_EndIndex)
     69   { }
     70 
     71   ChainIteratorBase& assign(const ChainIteratorBase& pCopy) {
     72     m_pHashTable = pCopy.m_pHashTable;
     73     m_Index = pCopy.m_Index;
     74     m_HashValue = pCopy.m_HashValue;
     75     m_EndIndex = pCopy.m_EndIndex;
     76     return *this;
     77   }
     78 
     79   inline bucket_type* getBucket() {
     80     if (0 == m_pHashTable)
     81       return 0;
     82     return &(m_pHashTable->m_Buckets[m_Index]);
     83   }
     84 
     85   inline const bucket_type* getBucket() const {
     86     if (0 == m_pHashTable)
     87       return 0;
     88     return &(m_pHashTable->m_Buckets[m_Index]);
     89   }
     90 
     91   inline entry_type* getEntry() {
     92     if (0 == m_pHashTable)
     93       return 0;
     94     return m_pHashTable->m_Buckets[m_Index].Entry;
     95   }
     96 
     97   inline const entry_type* getEntry() const {
     98     if (0 == m_pHashTable)
     99       return 0;
    100     return m_pHashTable->m_Buckets[m_Index].Entry;
    101   }
    102 
    103   inline void reset() {
    104     m_pHashTable = 0;
    105     m_Index = 0;
    106     m_EndIndex = 0;
    107     m_HashValue = 0;
    108   }
    109 
    110   inline void advance() {
    111     if (0 == m_pHashTable)
    112       return;
    113     const unsigned int probe = 1;
    114     while(true) {
    115       m_Index += probe;
    116       if (m_Index == m_pHashTable->m_NumOfBuckets)
    117         m_Index = 0;
    118       // reach end()
    119       if (m_Index == m_EndIndex) {
    120         reset();
    121         return;
    122       }
    123 
    124       bucket_type &bucket = m_pHashTable->m_Buckets[m_Index];
    125 
    126       if (bucket_type::getTombstone() == bucket.Entry ||
    127           bucket_type::getEmptyBucket() == bucket.Entry) {
    128         // Ignore tombstones.
    129       }
    130       else if (m_HashValue == bucket.FullHashValue) {
    131         return;
    132       }
    133     }
    134   }
    135 
    136   bool operator==(const ChainIteratorBase& pCopy) const {
    137     if (m_pHashTable == pCopy.m_pHashTable) {
    138       if (0 == m_pHashTable)
    139         return true;
    140       return ((m_HashValue == pCopy.m_HashValue) &&
    141               (m_EndIndex == pCopy.m_EndIndex) &&
    142               (m_Index == pCopy.m_Index));
    143     }
    144     return false;
    145   }
    146 
    147   bool operator!=(const ChainIteratorBase& pCopy) const
    148   { return !(*this == pCopy); }
    149 
    150 private:
    151   HashTableImplTy* m_pHashTable;
    152   unsigned int m_Index;
    153   unsigned int m_HashValue;
    154   unsigned int m_EndIndex;
    155 };
    156 
    157 /** \class EntryIteratorBase
    158  *  \brief EntryIteratorBase walks over hash table by the natural layout of the
    159  *  buckets
    160  */
    161 template<typename HashTableImplTy>
    162 class EntryIteratorBase
    163 {
    164 public:
    165   typedef HashTableImplTy hash_table;
    166   typedef typename HashTableImplTy::key_type key_type;
    167   typedef typename HashTableImplTy::entry_type entry_type;
    168   typedef typename HashTableImplTy::bucket_type bucket_type;
    169 
    170 public:
    171   EntryIteratorBase()
    172   : m_pHashTable(0), m_Index(0)
    173   { }
    174 
    175   EntryIteratorBase(HashTableImplTy* pTable,
    176                    unsigned int pIndex)
    177   : m_pHashTable(pTable), m_Index(pIndex)
    178   { }
    179 
    180   EntryIteratorBase(const EntryIteratorBase& pCopy)
    181   : m_pHashTable(pCopy.m_pHashTable), m_Index(pCopy.m_Index)
    182   { }
    183 
    184   EntryIteratorBase& assign(const EntryIteratorBase& pCopy) {
    185     m_pHashTable = pCopy.m_pHashTable;
    186     m_Index = pCopy.m_Index;
    187     return *this;
    188   }
    189 
    190   inline bucket_type* getBucket() {
    191     if (0 == m_pHashTable)
    192       return 0;
    193     return &(m_pHashTable->m_Buckets[m_Index]);
    194   }
    195 
    196   inline const bucket_type* getBucket() const {
    197     if (0 == m_pHashTable)
    198       return 0;
    199     return &(m_pHashTable->m_Buckets[m_Index]);
    200   }
    201 
    202   inline entry_type* getEntry() {
    203     if (0 == m_pHashTable)
    204       return 0;
    205     return m_pHashTable->m_Buckets[m_Index].Entry;
    206   }
    207 
    208   inline const entry_type* getEntry() const {
    209     if (0 == m_pHashTable)
    210       return 0;
    211     return m_pHashTable->m_Buckets[m_Index].Entry;
    212   }
    213 
    214   inline void reset() {
    215     m_pHashTable = 0;
    216     m_Index = 0;
    217   }
    218 
    219   inline void advance() {
    220     if (0 == m_pHashTable)
    221       return;
    222     do {
    223       ++m_Index;
    224       if (m_pHashTable->m_NumOfBuckets == m_Index) { // to the end
    225         reset();
    226         return;
    227       }
    228     } while(bucket_type::getEmptyBucket() == m_pHashTable->m_Buckets[m_Index].Entry ||
    229             bucket_type::getTombstone() == m_pHashTable->m_Buckets[m_Index].Entry);
    230   }
    231 
    232   bool operator==(const EntryIteratorBase& pCopy) const
    233   { return ((m_pHashTable == pCopy.m_pHashTable) &&
    234             (m_Index == pCopy.m_Index)); }
    235 
    236   bool operator!=(const EntryIteratorBase& pCopy) const
    237   { return !(*this == pCopy); }
    238 
    239 private:
    240   HashTableImplTy* m_pHashTable;
    241   unsigned int m_Index;
    242 
    243 };
    244 
    245 /** \class HashIterator
    246  *  \brief HashIterator provides a policy-based iterator.
    247  *
    248  *  HashTable has two kinds of iterators. One is used to traverse buckets
    249  *  with the same hash value; the other is used to traverse all entries of the
    250  *  hash table.
    251  *
    252  *  HashIterator is a template policy-based iterator, which can change its
    253  *  behavior by change the template argument IteratorBase. HashTable defines
    254  *  above two iterators by defining HashIterators with different IteratorBase.
    255  */
    256 template<typename IteratorBase,
    257          typename Traits>
    258 class HashIterator : public IteratorBase
    259 {
    260 public:
    261   typedef Traits                     traits;
    262   typedef typename traits::pointer   pointer;
    263   typedef typename traits::reference reference;
    264   typedef size_t                     size_type;
    265   typedef ptrdiff_t                  difference_type;
    266   typedef IteratorBase               Base;
    267 
    268   typedef HashIterator<IteratorBase,
    269                        Traits>             Self;
    270 
    271   typedef typename traits::nonconst_traits nonconst_traits;
    272   typedef HashIterator<IteratorBase,
    273                        nonconst_traits>    iterator;
    274 
    275   typedef typename traits::const_traits    const_traits;
    276   typedef HashIterator<IteratorBase,
    277                        const_traits>       const_iterator;
    278   typedef std::forward_iterator_tag        iterator_category;
    279 
    280 public:
    281   HashIterator()
    282   : IteratorBase()
    283   { }
    284 
    285   /// HashIterator - constructor for EntryIterator
    286   HashIterator(typename IteratorBase::hash_table* pTable, unsigned int pIndex)
    287   : IteratorBase(pTable, pIndex)
    288   { }
    289 
    290   /// HashIterator - constructor for ChainIterator
    291   explicit HashIterator(typename IteratorBase::hash_table* pTable,
    292                         const typename IteratorBase::key_type& pKey,
    293                         int)
    294   : IteratorBase(pTable, pKey)
    295   { }
    296 
    297   HashIterator(const HashIterator& pCopy)
    298   : IteratorBase(pCopy)
    299   { }
    300 
    301   ~HashIterator()
    302   { }
    303 
    304   HashIterator& operator=(const HashIterator& pCopy) {
    305     IteratorBase::assign(pCopy);
    306     return *this;
    307   }
    308 
    309   // -----  operators  ----- //
    310   Self& operator++() {
    311     this->Base::advance();
    312     return *this;
    313   }
    314 
    315   Self operator++(int) {
    316     Self tmp = *this;
    317     this->Base::advance();
    318     return tmp;
    319   }
    320 };
    321 
    322 } // namespace of mcld
    323 
    324 #endif
    325 
    326