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