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 #ifndef V8_HASHMAP_H_ | 5 // This file is ported from src/hashmap.h |
Yang
2016/05/25 08:29:39
I wonder whether it makes sense to move src/hashma
| |
6 #define V8_HASHMAP_H_ | |
7 | 6 |
8 #include "src/allocation.h" | 7 #ifndef V8_LIBSAMPLER_HASHMAP_H_ |
8 #define V8_LIBSAMPLER_HASHMAP_H_ | |
9 | |
9 #include "src/base/bits.h" | 10 #include "src/base/bits.h" |
10 #include "src/base/logging.h" | 11 #include "src/base/logging.h" |
11 #include "src/utils.h" | 12 #include "src/libsampler/utils.h" |
12 | 13 |
13 namespace v8 { | 14 namespace v8 { |
14 namespace internal { | 15 namespace sampler { |
15 | 16 |
16 template<class AllocationPolicy> | 17 class HashMapImpl { |
17 class TemplateHashMapImpl { | |
18 public: | 18 public: |
19 typedef bool (*MatchFun) (void* key1, void* key2); | 19 typedef bool (*MatchFun) (void* key1, void* key2); |
20 | 20 |
21 // The default capacity. This is used by the call sites which want | 21 // The default capacity. |
22 // to pass in a non-default AllocationPolicy but want to use the | |
23 // default value of capacity specified by the implementation. | |
24 static const uint32_t kDefaultHashMapCapacity = 8; | 22 static const uint32_t kDefaultHashMapCapacity = 8; |
25 | 23 |
26 // initial_capacity is the size of the initial hash map; | 24 // initial_capacity is the size of the initial hash map; |
27 // it must be a power of 2 (and thus must not be 0). | 25 // it must be a power of 2 (and thus must not be 0). |
28 TemplateHashMapImpl(MatchFun match, | 26 HashMapImpl(MatchFun match, |
29 uint32_t capacity = kDefaultHashMapCapacity, | 27 uint32_t capacity = kDefaultHashMapCapacity); |
30 AllocationPolicy allocator = AllocationPolicy()); | |
31 | 28 |
32 ~TemplateHashMapImpl(); | 29 ~HashMapImpl(); |
33 | 30 |
34 // HashMap entries are (key, value, hash) triplets. | 31 // HashMap entries are (key, value, hash) triplets. |
35 // Some clients may not need to use the value slot | 32 // Some clients may not need to use the value slot |
36 // (e.g. implementers of sets, where the key is the value). | 33 // (e.g. implementers of sets, where the key is the value). |
37 struct Entry { | 34 struct Entry { |
38 void* key; | 35 void* key; |
39 void* value; | 36 void* value; |
40 uint32_t hash; // The full hash value for key | 37 uint32_t hash; // The full hash value for key |
41 int order; // If you never remove entries this is the insertion order. | 38 int order; // If you never remove entries this is the insertion order. |
42 }; | 39 }; |
43 | 40 |
44 // If an entry with matching key is found, returns that entry. | 41 // If an entry with matching key is found, returns that entry. |
45 // Otherwise, NULL is returned. | 42 // Otherwise, NULL is returned. |
46 Entry* Lookup(void* key, uint32_t hash) const; | 43 Entry* Lookup(void* key, uint32_t hash) const; |
47 | 44 |
48 // If an entry with matching key is found, returns that entry. | 45 // If an entry with matching key is found, returns that entry. |
49 // If no matching entry is found, a new entry is inserted with | 46 // If no matching entry is found, a new entry is inserted with |
50 // corresponding key, key hash, and NULL value. | 47 // corresponding key, key hash, and NULL value. |
51 Entry* LookupOrInsert(void* key, uint32_t hash, | 48 Entry* LookupOrInsert(void* key, uint32_t hash); |
52 AllocationPolicy allocator = AllocationPolicy()); | |
53 | 49 |
54 // Removes the entry with matching key. | 50 // Removes the entry with matching key. |
55 // It returns the value of the deleted entry | 51 // It returns the value of the deleted entry |
56 // or null if there is no value for such key. | 52 // or null if there is no value for such key. |
57 void* Remove(void* key, uint32_t hash); | 53 void* Remove(void* key, uint32_t hash); |
58 | 54 |
59 // Empties the hash map (occupancy() == 0). | 55 // Empties the hash map (occupancy() == 0). |
60 void Clear(); | 56 void Clear(); |
61 | 57 |
62 // The number of (non-empty) entries in the table. | 58 // The number of (non-empty) entries in the table. |
(...skipping 21 matching lines...) Expand all Loading... | |
84 } | 80 } |
85 | 81 |
86 private: | 82 private: |
87 MatchFun match_; | 83 MatchFun match_; |
88 Entry* map_; | 84 Entry* map_; |
89 uint32_t capacity_; | 85 uint32_t capacity_; |
90 uint32_t occupancy_; | 86 uint32_t occupancy_; |
91 | 87 |
92 Entry* map_end() const { return map_ + capacity_; } | 88 Entry* map_end() const { return map_ + capacity_; } |
93 Entry* Probe(void* key, uint32_t hash) const; | 89 Entry* Probe(void* key, uint32_t hash) const; |
94 void Initialize(uint32_t capacity, AllocationPolicy allocator); | 90 void Initialize(uint32_t capacity); |
95 void Resize(AllocationPolicy allocator); | 91 void Resize(); |
96 }; | 92 }; |
97 | 93 |
98 typedef TemplateHashMapImpl<FreeStoreAllocationPolicy> HashMap; | 94 typedef HashMapImpl HashMap; |
99 | 95 |
100 template<class AllocationPolicy> | 96 HashMapImpl::HashMapImpl(MatchFun match, uint32_t initial_capacity) { |
101 TemplateHashMapImpl<AllocationPolicy>::TemplateHashMapImpl( | |
102 MatchFun match, uint32_t initial_capacity, AllocationPolicy allocator) { | |
103 match_ = match; | 97 match_ = match; |
104 Initialize(initial_capacity, allocator); | 98 Initialize(initial_capacity); |
105 } | 99 } |
106 | 100 |
107 | 101 |
108 template<class AllocationPolicy> | 102 HashMapImpl::~HashMapImpl() { |
109 TemplateHashMapImpl<AllocationPolicy>::~TemplateHashMapImpl() { | 103 Malloced::Delete(map_); |
110 AllocationPolicy::Delete(map_); | |
111 } | 104 } |
112 | 105 |
113 | 106 |
114 template <class AllocationPolicy> | 107 HashMapImpl::Entry* HashMapImpl::Lookup(void* key, uint32_t hash) const { |
115 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | |
116 TemplateHashMapImpl<AllocationPolicy>::Lookup(void* key, uint32_t hash) const { | |
117 Entry* p = Probe(key, hash); | 108 Entry* p = Probe(key, hash); |
118 return p->key != NULL ? p : NULL; | 109 return p->key != NULL ? p : NULL; |
119 } | 110 } |
120 | 111 |
121 | 112 |
122 template <class AllocationPolicy> | 113 HashMapImpl::Entry* HashMapImpl::LookupOrInsert(void* key, uint32_t hash) { |
123 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | |
124 TemplateHashMapImpl<AllocationPolicy>::LookupOrInsert( | |
125 void* key, uint32_t hash, AllocationPolicy allocator) { | |
126 // Find a matching entry. | 114 // Find a matching entry. |
127 Entry* p = Probe(key, hash); | 115 Entry* p = Probe(key, hash); |
128 if (p->key != NULL) { | 116 if (p->key != NULL) { |
129 return p; | 117 return p; |
130 } | 118 } |
131 | 119 |
132 // No entry found; insert one. | 120 // No entry found; insert one. |
133 p->key = key; | 121 p->key = key; |
134 p->value = NULL; | 122 p->value = NULL; |
135 p->hash = hash; | 123 p->hash = hash; |
136 p->order = occupancy_; | 124 p->order = occupancy_; |
137 occupancy_++; | 125 occupancy_++; |
138 | 126 |
139 // Grow the map if we reached >= 80% occupancy. | 127 // Grow the map if we reached >= 80% occupancy. |
140 if (occupancy_ + occupancy_ / 4 >= capacity_) { | 128 if (occupancy_ + occupancy_ / 4 >= capacity_) { |
141 Resize(allocator); | 129 Resize(); |
142 p = Probe(key, hash); | 130 p = Probe(key, hash); |
143 } | 131 } |
144 | 132 |
145 return p; | 133 return p; |
146 } | 134 } |
147 | 135 |
148 | 136 |
149 template<class AllocationPolicy> | 137 void* HashMapImpl::Remove(void* key, uint32_t hash) { |
150 void* TemplateHashMapImpl<AllocationPolicy>::Remove(void* key, uint32_t hash) { | |
151 // Lookup the entry for the key to remove. | 138 // Lookup the entry for the key to remove. |
152 Entry* p = Probe(key, hash); | 139 Entry* p = Probe(key, hash); |
153 if (p->key == NULL) { | 140 if (p->key == NULL) { |
154 // Key not found nothing to remove. | 141 // Key not found nothing to remove. |
155 return NULL; | 142 return NULL; |
156 } | 143 } |
157 | 144 |
158 void* value = p->value; | 145 void* value = p->value; |
159 // To remove an entry we need to ensure that it does not create an empty | 146 // To remove an entry we need to ensure that it does not create an empty |
160 // entry that will cause the search for another entry to stop too soon. If all | 147 // entry that will cause the search for another entry to stop too soon. If all |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
201 } | 188 } |
202 } | 189 } |
203 | 190 |
204 // Clear the entry which is allowed to en emptied. | 191 // Clear the entry which is allowed to en emptied. |
205 p->key = NULL; | 192 p->key = NULL; |
206 occupancy_--; | 193 occupancy_--; |
207 return value; | 194 return value; |
208 } | 195 } |
209 | 196 |
210 | 197 |
211 template<class AllocationPolicy> | 198 void HashMapImpl::Clear() { |
212 void TemplateHashMapImpl<AllocationPolicy>::Clear() { | |
213 // Mark all entries as empty. | 199 // Mark all entries as empty. |
214 const Entry* end = map_end(); | 200 const Entry* end = map_end(); |
215 for (Entry* p = map_; p < end; p++) { | 201 for (Entry* p = map_; p < end; p++) { |
216 p->key = NULL; | 202 p->key = NULL; |
217 } | 203 } |
218 occupancy_ = 0; | 204 occupancy_ = 0; |
219 } | 205 } |
220 | 206 |
221 | 207 |
222 template<class AllocationPolicy> | 208 HashMapImpl::Entry* HashMapImpl::Start() const { |
223 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | |
224 TemplateHashMapImpl<AllocationPolicy>::Start() const { | |
225 return Next(map_ - 1); | 209 return Next(map_ - 1); |
226 } | 210 } |
227 | 211 |
228 | 212 |
229 template<class AllocationPolicy> | 213 HashMapImpl::Entry* HashMapImpl::Next(Entry* p) const { |
230 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | |
231 TemplateHashMapImpl<AllocationPolicy>::Next(Entry* p) const { | |
232 const Entry* end = map_end(); | 214 const Entry* end = map_end(); |
233 DCHECK(map_ - 1 <= p && p < end); | 215 DCHECK(map_ - 1 <= p && p < end); |
234 for (p++; p < end; p++) { | 216 for (p++; p < end; p++) { |
235 if (p->key != NULL) { | 217 if (p->key != NULL) { |
236 return p; | 218 return p; |
237 } | 219 } |
238 } | 220 } |
239 return NULL; | 221 return NULL; |
240 } | 222 } |
241 | 223 |
242 | 224 |
243 template <class AllocationPolicy> | 225 HashMapImpl::Entry* HashMapImpl::Probe(void* key, uint32_t hash) const { |
244 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | |
245 TemplateHashMapImpl<AllocationPolicy>::Probe(void* key, uint32_t hash) const { | |
246 DCHECK(key != NULL); | 226 DCHECK(key != NULL); |
247 | 227 |
248 DCHECK(base::bits::IsPowerOfTwo32(capacity_)); | 228 DCHECK(base::bits::IsPowerOfTwo32(capacity_)); |
249 Entry* p = map_ + (hash & (capacity_ - 1)); | 229 Entry* p = map_ + (hash & (capacity_ - 1)); |
250 const Entry* end = map_end(); | 230 const Entry* end = map_end(); |
251 DCHECK(map_ <= p && p < end); | 231 DCHECK(map_ <= p && p < end); |
252 | 232 |
253 DCHECK(occupancy_ < capacity_); // Guarantees loop termination. | 233 DCHECK(occupancy_ < capacity_); // Guarantees loop termination. |
254 while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) { | 234 while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) { |
255 p++; | 235 p++; |
256 if (p >= end) { | 236 if (p >= end) { |
257 p = map_; | 237 p = map_; |
258 } | 238 } |
259 } | 239 } |
260 | 240 |
261 return p; | 241 return p; |
262 } | 242 } |
263 | 243 |
264 | 244 |
265 template<class AllocationPolicy> | 245 void HashMapImpl::Initialize(uint32_t capacity) { |
266 void TemplateHashMapImpl<AllocationPolicy>::Initialize( | |
267 uint32_t capacity, AllocationPolicy allocator) { | |
268 DCHECK(base::bits::IsPowerOfTwo32(capacity)); | 246 DCHECK(base::bits::IsPowerOfTwo32(capacity)); |
269 map_ = reinterpret_cast<Entry*>(allocator.New(capacity * sizeof(Entry))); | 247 map_ = reinterpret_cast<Entry*>(Malloced::New(capacity * sizeof(Entry))); |
270 if (map_ == NULL) { | 248 CHECK(map_ != NULL); |
271 v8::internal::FatalProcessOutOfMemory("HashMap::Initialize"); | |
272 return; | |
273 } | |
274 capacity_ = capacity; | 249 capacity_ = capacity; |
275 Clear(); | 250 Clear(); |
276 } | 251 } |
277 | 252 |
278 | 253 |
279 template<class AllocationPolicy> | 254 void HashMapImpl::Resize() { |
280 void TemplateHashMapImpl<AllocationPolicy>::Resize(AllocationPolicy allocator) { | |
281 Entry* map = map_; | 255 Entry* map = map_; |
282 uint32_t n = occupancy_; | 256 uint32_t n = occupancy_; |
283 | 257 |
284 // Allocate larger map. | 258 // Allocate larger map. |
285 Initialize(capacity_ * 2, allocator); | 259 Initialize(capacity_ * 2); |
286 | 260 |
287 // Rehash all current entries. | 261 // Rehash all current entries. |
288 for (Entry* p = map; n > 0; p++) { | 262 for (Entry* p = map; n > 0; p++) { |
289 if (p->key != NULL) { | 263 if (p->key != NULL) { |
290 Entry* entry = LookupOrInsert(p->key, p->hash, allocator); | 264 Entry* entry = LookupOrInsert(p->key, p->hash); |
291 entry->value = p->value; | 265 entry->value = p->value; |
292 entry->order = p->order; | 266 entry->order = p->order; |
293 n--; | 267 n--; |
294 } | 268 } |
295 } | 269 } |
296 | 270 |
297 // Delete old map. | 271 // Delete old map. |
298 AllocationPolicy::Delete(map); | 272 Malloced::Delete(map); |
299 } | 273 } |
300 | 274 |
301 | 275 } // namespace sampler |
302 // A hash map for pointer keys and values with an STL-like interface. | |
303 template<class Key, class Value, class AllocationPolicy> | |
304 class TemplateHashMap: private TemplateHashMapImpl<AllocationPolicy> { | |
305 public: | |
306 STATIC_ASSERT(sizeof(Key*) == sizeof(void*)); // NOLINT | |
307 STATIC_ASSERT(sizeof(Value*) == sizeof(void*)); // NOLINT | |
308 struct value_type { | |
309 Key* first; | |
310 Value* second; | |
311 }; | |
312 | |
313 class Iterator { | |
314 public: | |
315 Iterator& operator++() { | |
316 entry_ = map_->Next(entry_); | |
317 return *this; | |
318 } | |
319 | |
320 value_type* operator->() { return reinterpret_cast<value_type*>(entry_); } | |
321 bool operator!=(const Iterator& other) { return entry_ != other.entry_; } | |
322 | |
323 private: | |
324 Iterator(const TemplateHashMapImpl<AllocationPolicy>* map, | |
325 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry) : | |
326 map_(map), entry_(entry) { } | |
327 | |
328 const TemplateHashMapImpl<AllocationPolicy>* map_; | |
329 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry_; | |
330 | |
331 friend class TemplateHashMap; | |
332 }; | |
333 | |
334 TemplateHashMap( | |
335 typename TemplateHashMapImpl<AllocationPolicy>::MatchFun match, | |
336 AllocationPolicy allocator = AllocationPolicy()) | |
337 : TemplateHashMapImpl<AllocationPolicy>( | |
338 match, | |
339 TemplateHashMapImpl<AllocationPolicy>::kDefaultHashMapCapacity, | |
340 allocator) { } | |
341 | |
342 Iterator begin() const { return Iterator(this, this->Start()); } | |
343 Iterator end() const { return Iterator(this, NULL); } | |
344 Iterator find(Key* key, bool insert = false, | |
345 AllocationPolicy allocator = AllocationPolicy()) { | |
346 if (insert) { | |
347 return Iterator(this, this->LookupOrInsert(key, key->Hash(), allocator)); | |
348 } | |
349 return Iterator(this, this->Lookup(key, key->Hash())); | |
350 } | |
351 }; | |
352 | |
353 } // namespace internal | |
354 } // namespace v8 | 276 } // namespace v8 |
355 | 277 |
356 #endif // V8_HASHMAP_H_ | 278 #endif // V8_LIBSAMPLER_HASHMAP_H_ |
OLD | NEW |