Home | History | Annotate | Download | only in ADT
      1 //===- HashBase.tcc -------------------------------------------------------===//
      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 
     10 //===--------------------------------------------------------------------===//
     11 // internal non-member functions
     12 inline static unsigned int compute_bucket_count(unsigned int pNumOfBuckets)
     13 {
     14   static const unsigned int bucket_size[] =
     15   {
     16     1, 3, 17, 37, 67, 97, 197, 419, 977, 2593, 4099, 8209, 12289,
     17     16411, 20483, 32771, 49157, 65537, 98317, 131101, 196613
     18   };
     19 
     20   const unsigned int buckets_count =
     21       sizeof(bucket_size) / sizeof(bucket_size[0]);
     22   unsigned int idx = 0;
     23   do {
     24     if (pNumOfBuckets < bucket_size[idx]) {
     25       return bucket_size[idx];
     26     }
     27     ++idx;
     28   } while(idx < buckets_count);
     29 
     30   return (pNumOfBuckets+131101); // rare case. increase constantly
     31 }
     32 
     33 //===--------------------------------------------------------------------===//
     34 // template implementation of HashBucket
     35 template<typename DataType>
     36 typename HashBucket<DataType>::entry_type*
     37 HashBucket<DataType>::getEmptyBucket()
     38 {
     39   static entry_type* empty_bucket = reinterpret_cast<entry_type*>(0x0);
     40   return empty_bucket;
     41 }
     42 
     43 template<typename DataType>
     44 typename HashBucket<DataType>::entry_type*
     45 HashBucket<DataType>::getTombstone()
     46 {
     47   static entry_type* tombstone = reinterpret_cast<entry_type*>(0x1);
     48   return tombstone;
     49 }
     50 
     51 //===--------------------------------------------------------------------===//
     52 // template implementation of HashTableImpl
     53 template<typename HashEntryTy,
     54          typename HashFunctionTy>
     55 HashTableImpl<HashEntryTy, HashFunctionTy>::HashTableImpl()
     56   : m_Buckets(0),
     57     m_NumOfBuckets(0),
     58     m_NumOfEntries(0),
     59     m_NumOfTombstones(0),
     60     m_Hasher() {
     61 }
     62 
     63 template<typename HashEntryTy,
     64          typename HashFunctionTy>
     65 HashTableImpl<HashEntryTy, HashFunctionTy>::HashTableImpl(
     66   unsigned int pInitSize)
     67   : m_Hasher() {
     68   if (pInitSize) {
     69     init(pInitSize);
     70     return;
     71   }
     72 
     73   m_Buckets = 0;
     74   m_NumOfBuckets = 0;
     75   m_NumOfEntries = 0;
     76   m_NumOfTombstones = 0;
     77 }
     78 
     79 template<typename HashEntryTy,
     80          typename HashFunctionTy>
     81 HashTableImpl<HashEntryTy, HashFunctionTy>::~HashTableImpl()
     82 {
     83   clear();
     84 }
     85 
     86 /// empty - check if the hash table is empty
     87 template<typename HashEntryTy,
     88          typename HashFunctionTy>
     89 bool HashTableImpl<HashEntryTy, HashFunctionTy>::empty() const
     90 {
     91   return (0 == m_NumOfEntries);
     92 }
     93 
     94 /// init - initialize the hash table.
     95 template<typename HashEntryTy,
     96          typename HashFunctionTy>
     97 void HashTableImpl<HashEntryTy, HashFunctionTy>::init(unsigned int pInitSize)
     98 {
     99   m_NumOfBuckets = pInitSize? compute_bucket_count(pInitSize): NumOfInitBuckets;
    100 
    101   m_NumOfEntries = 0;
    102   m_NumOfTombstones = 0;
    103 
    104   /** calloc also set bucket.Item = bucket_type::getEmptyStone() **/
    105   m_Buckets = (bucket_type*)calloc(m_NumOfBuckets, sizeof(bucket_type));
    106 }
    107 
    108 /// clear - clear the hash table.
    109 template<typename HashEntryTy,
    110          typename HashFunctionTy>
    111 void HashTableImpl<HashEntryTy, HashFunctionTy>::clear()
    112 {
    113   free(m_Buckets);
    114 
    115   m_Buckets = 0;
    116   m_NumOfBuckets = 0;
    117   m_NumOfEntries = 0;
    118   m_NumOfTombstones = 0;
    119 }
    120 
    121 /// lookUpBucketFor - look up the bucket whose key is pKey
    122 template<typename HashEntryTy,
    123          typename HashFunctionTy>
    124 unsigned int
    125 HashTableImpl<HashEntryTy, HashFunctionTy>::lookUpBucketFor(
    126   const typename HashTableImpl<HashEntryTy, HashFunctionTy>::key_type& pKey)
    127 {
    128   if (0 == m_NumOfBuckets) {
    129     // NumOfBuckets is changed after init(pInitSize)
    130     init(NumOfInitBuckets);
    131   }
    132 
    133   unsigned int full_hash = m_Hasher(pKey);
    134   unsigned int index = full_hash % m_NumOfBuckets;
    135 
    136   const unsigned int probe = 1;
    137   int firstTombstone = -1;
    138 
    139   // linear probing
    140   while(true) {
    141     bucket_type& bucket = m_Buckets[index];
    142     // If we found an empty bucket, this key isn't in the table yet, return it.
    143     if (bucket_type::getEmptyBucket() == bucket.Entry) {
    144       if (-1 != firstTombstone) {
    145         m_Buckets[firstTombstone].FullHashValue = full_hash;
    146         return firstTombstone;
    147       }
    148 
    149       bucket.FullHashValue = full_hash;
    150       return index;
    151     }
    152 
    153     if (bucket_type::getTombstone() == bucket.Entry) {
    154       if (-1 == firstTombstone) {
    155         firstTombstone = index;
    156       }
    157     }
    158     else if (bucket.FullHashValue == full_hash) {
    159       if (bucket.Entry->compare(pKey)) {
    160         return index;
    161       }
    162     }
    163 
    164     index += probe;
    165     if (index == m_NumOfBuckets)
    166       index = 0;
    167   }
    168 }
    169 
    170 template<typename HashEntryTy,
    171          typename HashFunctionTy>
    172 int
    173 HashTableImpl<HashEntryTy, HashFunctionTy>::findKey(
    174   const typename HashTableImpl<HashEntryTy, HashFunctionTy>::key_type& pKey) const
    175 {
    176   if (0 == m_NumOfBuckets)
    177     return -1;
    178 
    179   unsigned int full_hash = m_Hasher(pKey);
    180   unsigned int index = full_hash % m_NumOfBuckets;
    181 
    182   const unsigned int probe = 1;
    183   // linear probing
    184   while (true) {
    185     bucket_type &bucket = m_Buckets[index];
    186 
    187     if (bucket_type::getEmptyBucket() == bucket.Entry)
    188       return -1;
    189 
    190     if (bucket_type::getTombstone() == bucket.Entry) {
    191       // Ignore tombstones.
    192     }
    193     else if (full_hash == bucket.FullHashValue) {
    194       // get string, compare, if match, return index
    195       if (bucket.Entry->compare(pKey))
    196         return index;
    197     }
    198     index += probe;
    199     if (index == m_NumOfBuckets)
    200       index = 0;
    201   }
    202 }
    203 
    204 template<typename HashEntryTy,
    205          typename HashFunctionTy>
    206 void HashTableImpl<HashEntryTy, HashFunctionTy>::mayRehash()
    207 {
    208 
    209   unsigned int new_size;
    210   // If the hash table is now more than 3/4 full, or if fewer than 1/8 of
    211   // the buckets are empty (meaning that many are filled with tombstones),
    212   // grow/rehash the table.
    213   if ((m_NumOfEntries<<2) > m_NumOfBuckets*3)
    214     new_size = compute_bucket_count(m_NumOfBuckets);
    215   else if (((m_NumOfBuckets-(m_NumOfEntries+m_NumOfTombstones))<<3) < m_NumOfBuckets)
    216     new_size = m_NumOfBuckets;
    217   else
    218     return;
    219 
    220   doRehash(new_size);
    221 }
    222 
    223 template<typename HashEntryTy,
    224          typename HashFunctionTy>
    225 void HashTableImpl<HashEntryTy, HashFunctionTy>::doRehash(unsigned int pNewSize)
    226 {
    227   bucket_type* new_table = (bucket_type*)calloc(pNewSize, sizeof(bucket_type));
    228 
    229   // Rehash all the items into their new buckets.  Luckily :) we already have
    230   // the hash values available, so we don't have to recall hash function again.
    231   for (bucket_type *IB = m_Buckets, *E = m_Buckets+m_NumOfBuckets; IB != E; ++IB) {
    232     if (IB->Entry != bucket_type::getEmptyBucket() &&
    233         IB->Entry != bucket_type::getTombstone()) {
    234       // Fast case, bucket available.
    235       unsigned full_hash = IB->FullHashValue;
    236       unsigned new_bucket = full_hash % pNewSize;
    237       if (bucket_type::getEmptyBucket() == new_table[new_bucket].Entry) {
    238         new_table[new_bucket].Entry = IB->Entry;
    239         new_table[new_bucket].FullHashValue = full_hash;
    240         continue;
    241       }
    242 
    243       // Otherwise probe for a spot.
    244       const unsigned int probe = 1;
    245       do {
    246         new_bucket += probe;
    247         if (new_bucket == pNewSize)
    248           new_bucket = 0;
    249       } while (new_table[new_bucket].Entry != bucket_type::getEmptyBucket());
    250 
    251       // Finally found a slot.  Fill it in.
    252       new_table[new_bucket].Entry = IB->Entry;
    253       new_table[new_bucket].FullHashValue = full_hash;
    254     }
    255   }
    256 
    257   free(m_Buckets);
    258 
    259   m_Buckets = new_table;
    260   m_NumOfBuckets = pNewSize;
    261   m_NumOfTombstones = 0;
    262 }
    263 
    264