OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // The reason we write our own hash map instead of using unordered_map in STL, | 5 // The reason we write our own hash map instead of using unordered_map in STL, |
6 // is that STL containers use a mutex pool on debug build, which will lead to | 6 // is that STL containers use a mutex pool on debug build, which will lead to |
7 // deadlock when we are using async signal handler. | 7 // deadlock when we are using async signal handler. |
8 | 8 |
9 #ifndef V8_BASE_HASHMAP_H_ | 9 #ifndef V8_BASE_HASHMAP_H_ |
10 #define V8_BASE_HASHMAP_H_ | 10 #define V8_BASE_HASHMAP_H_ |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 | 77 |
78 // Iteration | 78 // Iteration |
79 // | 79 // |
80 // for (Entry* p = map.Start(); p != nullptr; p = map.Next(p)) { | 80 // for (Entry* p = map.Start(); p != nullptr; p = map.Next(p)) { |
81 // ... | 81 // ... |
82 // } | 82 // } |
83 // | 83 // |
84 // If entries are inserted during iteration, the effect of | 84 // If entries are inserted during iteration, the effect of |
85 // calling Next() is undefined. | 85 // calling Next() is undefined. |
86 Entry* Start() const; | 86 Entry* Start() const; |
87 Entry* Next(Entry* p) const; | 87 Entry* Next(Entry* entry) const; |
88 | 88 |
89 // Some match functions defined for convenience. | 89 // Some match functions defined for convenience. |
90 // TODO(leszeks): This isn't really matching pointers, so the name doesn't | 90 // TODO(leszeks): This isn't really matching pointers, so the name doesn't |
91 // really make sense, but we should remove this entirely and template the map | 91 // really make sense, but we should remove this entirely and template the map |
92 // on the matching function. | 92 // on the matching function. |
93 static bool PointersMatch(typename MatchFunHelper<Key>::KeyRef key1, | 93 static bool PointersMatch(typename MatchFunHelper<Key>::KeyRef key1, |
94 typename MatchFunHelper<Key>::KeyRef key2) { | 94 typename MatchFunHelper<Key>::KeyRef key2) { |
95 return key1 == key2; | 95 return key1 == key2; |
96 } | 96 } |
97 | 97 |
98 private: | 98 private: |
99 MatchFun match_; | 99 MatchFun match_; |
100 Entry* map_; | 100 Entry* map_; |
101 uint32_t capacity_; | 101 uint32_t capacity_; |
102 uint32_t occupancy_; | 102 uint32_t occupancy_; |
103 AllocationPolicy allocator_; | 103 AllocationPolicy allocator_; |
104 | 104 |
105 Entry* map_end() const { return map_ + capacity_; } | 105 Entry* map_end() const { return map_ + capacity_; } |
106 Entry* Probe(const Key& key, uint32_t hash) const; | 106 Entry* Probe(const Key& key, uint32_t hash) const; |
| 107 Entry* FillEmptyEntry(Entry* entry, const Key& key, const Value& value, |
| 108 uint32_t hash); |
107 void Initialize(uint32_t capacity); | 109 void Initialize(uint32_t capacity); |
108 void Resize(); | 110 void Resize(); |
109 }; | 111 }; |
110 | 112 |
111 template <typename Key> | 113 template <typename Key> |
112 struct MatchFunHelper { | 114 struct MatchFunHelper { |
113 typedef const Key& KeyRef; | 115 typedef const Key& KeyRef; |
114 typedef bool (*Fun)(KeyRef key1, KeyRef key2); | 116 typedef bool (*Fun)(KeyRef key1, KeyRef key2); |
115 }; | 117 }; |
116 | 118 |
(...skipping 15 matching lines...) Expand all Loading... |
132 | 134 |
133 template <typename Key, typename Value, class AllocationPolicy> | 135 template <typename Key, typename Value, class AllocationPolicy> |
134 TemplateHashMapImpl<Key, Value, AllocationPolicy>::~TemplateHashMapImpl() { | 136 TemplateHashMapImpl<Key, Value, AllocationPolicy>::~TemplateHashMapImpl() { |
135 allocator_.Delete(map_); | 137 allocator_.Delete(map_); |
136 } | 138 } |
137 | 139 |
138 template <typename Key, typename Value, class AllocationPolicy> | 140 template <typename Key, typename Value, class AllocationPolicy> |
139 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* | 141 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
140 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Lookup(const Key& key, | 142 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Lookup(const Key& key, |
141 uint32_t hash) const { | 143 uint32_t hash) const { |
142 Entry* p = Probe(key, hash); | 144 Entry* entry = Probe(key, hash); |
143 return p->exists() ? p : nullptr; | 145 return entry->exists() ? entry : nullptr; |
144 } | 146 } |
145 | 147 |
146 template <typename Key, typename Value, class AllocationPolicy> | 148 template <typename Key, typename Value, class AllocationPolicy> |
147 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* | 149 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
148 TemplateHashMapImpl<Key, Value, AllocationPolicy>::LookupOrInsert( | 150 TemplateHashMapImpl<Key, Value, AllocationPolicy>::LookupOrInsert( |
149 const Key& key, uint32_t hash) { | 151 const Key& key, uint32_t hash) { |
150 // Find a matching entry. | 152 // Find a matching entry. |
151 Entry* p = Probe(key, hash); | 153 Entry* entry = Probe(key, hash); |
152 if (p->exists()) { | 154 if (entry->exists()) { |
153 return p; | 155 return entry; |
154 } | 156 } |
155 | 157 |
156 return InsertNew(key, hash); | 158 return FillEmptyEntry(entry, key, Value(), hash); |
157 } | 159 } |
158 | 160 |
159 template <typename Key, typename Value, class AllocationPolicy> | 161 template <typename Key, typename Value, class AllocationPolicy> |
160 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* | 162 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
161 TemplateHashMapImpl<Key, Value, AllocationPolicy>::InsertNew(const Key& key, | 163 TemplateHashMapImpl<Key, Value, AllocationPolicy>::InsertNew(const Key& key, |
162 uint32_t hash) { | 164 uint32_t hash) { |
163 // Find a matching entry. | 165 Entry* entry = Probe(key, hash); |
164 Entry* p = Probe(key, hash); | 166 return FillEmptyEntry(entry, key, Value(), hash); |
165 DCHECK(!p->exists()); | |
166 | |
167 // No entry found; construct one in-place in the empty slot using placement | |
168 // new. | |
169 new (p) Entry(key, Value(), hash); | |
170 occupancy_++; | |
171 | |
172 // Grow the map if we reached >= 80% occupancy. | |
173 if (occupancy_ + occupancy_ / 4 >= capacity_) { | |
174 Resize(); | |
175 p = Probe(key, hash); | |
176 } | |
177 | |
178 return p; | |
179 } | 167 } |
180 | 168 |
181 template <typename Key, typename Value, class AllocationPolicy> | 169 template <typename Key, typename Value, class AllocationPolicy> |
182 Value TemplateHashMapImpl<Key, Value, AllocationPolicy>::Remove(const Key& key, | 170 Value TemplateHashMapImpl<Key, Value, AllocationPolicy>::Remove(const Key& key, |
183 uint32_t hash) { | 171 uint32_t hash) { |
184 // Lookup the entry for the key to remove. | 172 // Lookup the entry for the key to remove. |
185 Entry* p = Probe(key, hash); | 173 Entry* p = Probe(key, hash); |
186 if (!p->exists()) { | 174 if (!p->exists()) { |
187 // Key not found nothing to remove. | 175 // Key not found nothing to remove. |
188 return nullptr; | 176 return nullptr; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 // Clear the entry which is allowed to en emptied. | 224 // Clear the entry which is allowed to en emptied. |
237 p->clear(); | 225 p->clear(); |
238 occupancy_--; | 226 occupancy_--; |
239 return value; | 227 return value; |
240 } | 228 } |
241 | 229 |
242 template <typename Key, typename Value, class AllocationPolicy> | 230 template <typename Key, typename Value, class AllocationPolicy> |
243 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Clear() { | 231 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Clear() { |
244 // Mark all entries as empty. | 232 // Mark all entries as empty. |
245 const Entry* end = map_end(); | 233 const Entry* end = map_end(); |
246 for (Entry* p = map_; p < end; p++) { | 234 for (Entry* entry = map_; entry < end; entry++) { |
247 p->clear(); | 235 entry->clear(); |
248 } | 236 } |
249 occupancy_ = 0; | 237 occupancy_ = 0; |
250 } | 238 } |
251 | 239 |
252 template <typename Key, typename Value, class AllocationPolicy> | 240 template <typename Key, typename Value, class AllocationPolicy> |
253 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* | 241 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
254 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Start() const { | 242 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Start() const { |
255 return Next(map_ - 1); | 243 return Next(map_ - 1); |
256 } | 244 } |
257 | 245 |
258 template <typename Key, typename Value, class AllocationPolicy> | 246 template <typename Key, typename Value, class AllocationPolicy> |
259 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* | 247 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
260 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Next(Entry* p) const { | 248 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Next(Entry* entry) const { |
261 const Entry* end = map_end(); | 249 const Entry* end = map_end(); |
262 DCHECK(map_ - 1 <= p && p < end); | 250 DCHECK(map_ - 1 <= entry && entry < end); |
263 for (p++; p < end; p++) { | 251 for (entry++; entry < end; entry++) { |
264 if (p->exists()) { | 252 if (entry->exists()) { |
265 return p; | 253 return entry; |
266 } | 254 } |
267 } | 255 } |
268 return nullptr; | 256 return nullptr; |
269 } | 257 } |
270 | 258 |
271 template <typename Key, typename Value, class AllocationPolicy> | 259 template <typename Key, typename Value, class AllocationPolicy> |
272 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* | 260 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
273 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Probe(const Key& key, | 261 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Probe(const Key& key, |
274 uint32_t hash) const { | 262 uint32_t hash) const { |
275 DCHECK(base::bits::IsPowerOfTwo32(capacity_)); | 263 DCHECK(base::bits::IsPowerOfTwo32(capacity_)); |
276 Entry* p = map_ + (hash & (capacity_ - 1)); | 264 Entry* entry = map_ + (hash & (capacity_ - 1)); |
277 const Entry* end = map_end(); | 265 const Entry* end = map_end(); |
278 DCHECK(map_ <= p && p < end); | 266 DCHECK(map_ <= entry && entry < end); |
279 | 267 |
280 DCHECK(occupancy_ < capacity_); // Guarantees loop termination. | 268 DCHECK(occupancy_ < capacity_); // Guarantees loop termination. |
281 while (p->exists() && (hash != p->hash || !match_(key, p->key))) { | 269 while (entry->exists() && (hash != entry->hash || !match_(key, entry->key))) { |
282 p++; | 270 entry++; |
283 if (p >= end) { | 271 if (entry >= end) { |
284 p = map_; | 272 entry = map_; |
285 } | 273 } |
286 } | 274 } |
287 | 275 |
288 return p; | 276 return entry; |
289 } | 277 } |
290 | 278 |
291 template <typename Key, typename Value, class AllocationPolicy> | 279 template <typename Key, typename Value, class AllocationPolicy> |
| 280 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 281 TemplateHashMapImpl<Key, Value, AllocationPolicy>::FillEmptyEntry( |
| 282 Entry* entry, const Key& key, const Value& value, uint32_t hash) { |
| 283 DCHECK(!entry->exists()); |
| 284 |
| 285 new (entry) Entry(key, value, hash); |
| 286 occupancy_++; |
| 287 |
| 288 // Grow the map if we reached >= 80% occupancy. |
| 289 if (occupancy_ + occupancy_ / 4 >= capacity_) { |
| 290 Resize(); |
| 291 entry = Probe(key, hash); |
| 292 } |
| 293 |
| 294 return entry; |
| 295 } |
| 296 |
| 297 template <typename Key, typename Value, class AllocationPolicy> |
292 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Initialize( | 298 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Initialize( |
293 uint32_t capacity) { | 299 uint32_t capacity) { |
294 DCHECK(base::bits::IsPowerOfTwo32(capacity)); | 300 DCHECK(base::bits::IsPowerOfTwo32(capacity)); |
295 map_ = reinterpret_cast<Entry*>(allocator_.New(capacity * sizeof(Entry))); | 301 map_ = reinterpret_cast<Entry*>(allocator_.New(capacity * sizeof(Entry))); |
296 if (map_ == nullptr) { | 302 if (map_ == nullptr) { |
297 FATAL("Out of memory: HashMap::Initialize"); | 303 FATAL("Out of memory: HashMap::Initialize"); |
298 return; | 304 return; |
299 } | 305 } |
300 capacity_ = capacity; | 306 capacity_ = capacity; |
301 Clear(); | 307 Clear(); |
302 } | 308 } |
303 | 309 |
304 template <typename Key, typename Value, class AllocationPolicy> | 310 template <typename Key, typename Value, class AllocationPolicy> |
305 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Resize() { | 311 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Resize() { |
306 Entry* map = map_; | 312 Entry* map = map_; |
307 uint32_t n = occupancy_; | 313 uint32_t n = occupancy_; |
308 | 314 |
309 // Allocate larger map. | 315 // Allocate larger map. |
310 Initialize(capacity_ * 2); | 316 Initialize(capacity_ * 2); |
311 | 317 |
312 // Rehash all current entries. | 318 // Rehash all current entries. |
313 for (Entry* p = map; n > 0; p++) { | 319 for (Entry* entry = map; n > 0; entry++) { |
314 if (p->exists()) { | 320 if (entry->exists()) { |
315 Entry* entry = LookupOrInsert(p->key, p->hash); | 321 Entry* new_entry = Probe(entry->key, entry->hash); |
316 entry->value = p->value; | 322 new_entry = |
| 323 FillEmptyEntry(new_entry, entry->key, entry->value, entry->hash); |
317 n--; | 324 n--; |
318 } | 325 } |
319 } | 326 } |
320 | 327 |
321 // Delete old map. | 328 // Delete old map. |
322 allocator_.Delete(map); | 329 allocator_.Delete(map); |
323 } | 330 } |
324 | 331 |
325 // A hash map for pointer keys and values with an STL-like interface. | 332 // A hash map for pointer keys and values with an STL-like interface. |
326 template <class Key, class Value, class AllocationPolicy> | 333 template <class Key, class Value, class AllocationPolicy> |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
372 return Iterator(this, this->LookupOrInsert(key, key->Hash())); | 379 return Iterator(this, this->LookupOrInsert(key, key->Hash())); |
373 } | 380 } |
374 return Iterator(this, this->Lookup(key, key->Hash())); | 381 return Iterator(this, this->Lookup(key, key->Hash())); |
375 } | 382 } |
376 }; | 383 }; |
377 | 384 |
378 } // namespace base | 385 } // namespace base |
379 } // namespace v8 | 386 } // namespace v8 |
380 | 387 |
381 #endif // V8_BASE_HASHMAP_H_ | 388 #endif // V8_BASE_HASHMAP_H_ |
OLD | NEW |