OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 22 matching lines...) Expand all Loading... | |
33 #include "utils.h" | 33 #include "utils.h" |
34 | 34 |
35 namespace v8 { | 35 namespace v8 { |
36 namespace internal { | 36 namespace internal { |
37 | 37 |
38 template<class AllocationPolicy> | 38 template<class AllocationPolicy> |
39 class TemplateHashMapImpl { | 39 class TemplateHashMapImpl { |
40 public: | 40 public: |
41 typedef bool (*MatchFun) (void* key1, void* key2); | 41 typedef bool (*MatchFun) (void* key1, void* key2); |
42 | 42 |
43 // The default capacity. This is used by the call sites which want | |
44 // to pass in a non-default AllocationPolicy but want to use the | |
45 // default value of capacity specified by the implementation. | |
46 static const uint32_t kDefaultHashMapCapacity = 8; | |
47 | |
43 // initial_capacity is the size of the initial hash map; | 48 // initial_capacity is the size of the initial hash map; |
44 // it must be a power of 2 (and thus must not be 0). | 49 // it must be a power of 2 (and thus must not be 0). |
45 TemplateHashMapImpl(MatchFun match, uint32_t initial_capacity = 8); | 50 TemplateHashMapImpl(MatchFun match, |
51 uint32_t capacity = kDefaultHashMapCapacity, | |
52 AllocationPolicy allocator = AllocationPolicy()); | |
46 | 53 |
47 ~TemplateHashMapImpl(); | 54 ~TemplateHashMapImpl(); |
48 | 55 |
49 // HashMap entries are (key, value, hash) triplets. | 56 // HashMap entries are (key, value, hash) triplets. |
50 // Some clients may not need to use the value slot | 57 // Some clients may not need to use the value slot |
51 // (e.g. implementers of sets, where the key is the value). | 58 // (e.g. implementers of sets, where the key is the value). |
52 struct Entry { | 59 struct Entry { |
53 void* key; | 60 void* key; |
54 void* value; | 61 void* value; |
55 uint32_t hash; // the full hash value for key | 62 uint32_t hash; // the full hash value for key |
56 }; | 63 }; |
57 | 64 |
58 // If an entry with matching key is found, Lookup() | 65 // If an entry with matching key is found, Lookup() |
59 // returns that entry. If no matching entry is found, | 66 // returns that entry. If no matching entry is found, |
60 // but insert is set, a new entry is inserted with | 67 // but insert is set, a new entry is inserted with |
61 // corresponding key, key hash, and NULL value. | 68 // corresponding key, key hash, and NULL value. |
62 // Otherwise, NULL is returned. | 69 // Otherwise, NULL is returned. |
63 Entry* Lookup(void* key, uint32_t hash, bool insert); | 70 Entry* Lookup(void* key, uint32_t hash, bool insert, |
71 AllocationPolicy allocator = AllocationPolicy()); | |
64 | 72 |
65 // Removes the entry with matching key. | 73 // Removes the entry with matching key. |
66 // It returns the value of the deleted entry | 74 // It returns the value of the deleted entry |
67 // or null if there is no value for such key. | 75 // or null if there is no value for such key. |
68 void* Remove(void* key, uint32_t hash); | 76 void* Remove(void* key, uint32_t hash); |
69 | 77 |
70 // Empties the hash map (occupancy() == 0). | 78 // Empties the hash map (occupancy() == 0). |
71 void Clear(); | 79 void Clear(); |
72 | 80 |
73 // The number of (non-empty) entries in the table. | 81 // The number of (non-empty) entries in the table. |
(...skipping 16 matching lines...) Expand all Loading... | |
90 Entry* Next(Entry* p) const; | 98 Entry* Next(Entry* p) const; |
91 | 99 |
92 private: | 100 private: |
93 MatchFun match_; | 101 MatchFun match_; |
94 Entry* map_; | 102 Entry* map_; |
95 uint32_t capacity_; | 103 uint32_t capacity_; |
96 uint32_t occupancy_; | 104 uint32_t occupancy_; |
97 | 105 |
98 Entry* map_end() const { return map_ + capacity_; } | 106 Entry* map_end() const { return map_ + capacity_; } |
99 Entry* Probe(void* key, uint32_t hash); | 107 Entry* Probe(void* key, uint32_t hash); |
100 void Initialize(uint32_t capacity); | 108 void Initialize(uint32_t capacity, AllocationPolicy allocator); |
101 void Resize(); | 109 void Resize(AllocationPolicy allocator); |
102 }; | 110 }; |
103 | 111 |
104 typedef TemplateHashMapImpl<FreeStoreAllocationPolicy> HashMap; | 112 typedef TemplateHashMapImpl<FreeStoreAllocationPolicy> HashMap; |
105 | 113 |
106 template<class P> | 114 template<class AllocationPolicy> |
107 TemplateHashMapImpl<P>::TemplateHashMapImpl(MatchFun match, | 115 TemplateHashMapImpl<AllocationPolicy>::TemplateHashMapImpl( |
108 uint32_t initial_capacity) { | 116 MatchFun match, uint32_t initial_capacity, AllocationPolicy allocator) { |
109 match_ = match; | 117 match_ = match; |
110 Initialize(initial_capacity); | 118 Initialize(initial_capacity, allocator); |
111 } | 119 } |
112 | 120 |
113 | 121 |
114 template<class P> | 122 template<class AllocationPolicy> |
115 TemplateHashMapImpl<P>::~TemplateHashMapImpl() { | 123 TemplateHashMapImpl<AllocationPolicy>::~TemplateHashMapImpl() { |
116 P::Delete(map_); | 124 AllocationPolicy::Delete(map_); |
117 } | 125 } |
118 | 126 |
119 | 127 |
120 template<class P> | 128 template<class AllocationPolicy> |
121 typename TemplateHashMapImpl<P>::Entry* TemplateHashMapImpl<P>::Lookup( | 129 typename TemplateHashMapImpl<AllocationPolicy>::Entry* |
122 void* key, uint32_t hash, bool insert) { | 130 TemplateHashMapImpl<AllocationPolicy>::Lookup( |
131 void* key, uint32_t hash, bool insert, AllocationPolicy allocator) { | |
123 // Find a matching entry. | 132 // Find a matching entry. |
124 Entry* p = Probe(key, hash); | 133 Entry* p = Probe(key, hash); |
125 if (p->key != NULL) { | 134 if (p->key != NULL) { |
126 return p; | 135 return p; |
127 } | 136 } |
128 | 137 |
129 // No entry found; insert one if necessary. | 138 // No entry found; insert one if necessary. |
130 if (insert) { | 139 if (insert) { |
131 p->key = key; | 140 p->key = key; |
132 p->value = NULL; | 141 p->value = NULL; |
133 p->hash = hash; | 142 p->hash = hash; |
134 occupancy_++; | 143 occupancy_++; |
135 | 144 |
136 // Grow the map if we reached >= 80% occupancy. | 145 // Grow the map if we reached >= 80% occupancy. |
137 if (occupancy_ + occupancy_/4 >= capacity_) { | 146 if (occupancy_ + occupancy_/4 >= capacity_) { |
138 Resize(); | 147 Resize(allocator); |
139 p = Probe(key, hash); | 148 p = Probe(key, hash); |
140 } | 149 } |
141 | 150 |
142 return p; | 151 return p; |
143 } | 152 } |
144 | 153 |
145 // No entry found and none inserted. | 154 // No entry found and none inserted. |
146 return NULL; | 155 return NULL; |
147 } | 156 } |
148 | 157 |
149 | 158 |
150 template<class P> | 159 template<class AllocationPolicy> |
151 void* TemplateHashMapImpl<P>::Remove(void* key, uint32_t hash) { | 160 void* TemplateHashMapImpl<AllocationPolicy>::Remove(void* key, uint32_t hash) { |
152 // Lookup the entry for the key to remove. | 161 // Lookup the entry for the key to remove. |
153 Entry* p = Probe(key, hash); | 162 Entry* p = Probe(key, hash); |
154 if (p->key == NULL) { | 163 if (p->key == NULL) { |
155 // Key not found nothing to remove. | 164 // Key not found nothing to remove. |
156 return NULL; | 165 return NULL; |
157 } | 166 } |
158 | 167 |
159 void* value = p->value; | 168 void* value = p->value; |
160 // To remove an entry we need to ensure that it does not create an empty | 169 // To remove an entry we need to ensure that it does not create an empty |
161 // entry that will cause the search for another entry to stop too soon. If all | 170 // 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... | |
202 } | 211 } |
203 } | 212 } |
204 | 213 |
205 // Clear the entry which is allowed to en emptied. | 214 // Clear the entry which is allowed to en emptied. |
206 p->key = NULL; | 215 p->key = NULL; |
207 occupancy_--; | 216 occupancy_--; |
208 return value; | 217 return value; |
209 } | 218 } |
210 | 219 |
211 | 220 |
212 template<class P> | 221 template<class AllocationPolicy> |
213 void TemplateHashMapImpl<P>::Clear() { | 222 void TemplateHashMapImpl<AllocationPolicy>::Clear() { |
214 // Mark all entries as empty. | 223 // Mark all entries as empty. |
215 const Entry* end = map_end(); | 224 const Entry* end = map_end(); |
216 for (Entry* p = map_; p < end; p++) { | 225 for (Entry* p = map_; p < end; p++) { |
217 p->key = NULL; | 226 p->key = NULL; |
218 } | 227 } |
219 occupancy_ = 0; | 228 occupancy_ = 0; |
220 } | 229 } |
221 | 230 |
222 | 231 |
223 template<class P> | 232 template<class AllocationPolicy> |
224 typename TemplateHashMapImpl<P>::Entry* TemplateHashMapImpl<P>::Start() const { | 233 typename TemplateHashMapImpl<AllocationPolicy>::Entry* |
234 TemplateHashMapImpl<AllocationPolicy>::Start() const { | |
225 return Next(map_ - 1); | 235 return Next(map_ - 1); |
226 } | 236 } |
227 | 237 |
228 | 238 |
229 template<class P> | 239 template<class AllocationPolicy> |
230 typename TemplateHashMapImpl<P>::Entry* TemplateHashMapImpl<P>::Next(Entry* p) | 240 typename TemplateHashMapImpl<AllocationPolicy>::Entry* |
231 const { | 241 TemplateHashMapImpl<AllocationPolicy>::Next(Entry* p) const { |
232 const Entry* end = map_end(); | 242 const Entry* end = map_end(); |
233 ASSERT(map_ - 1 <= p && p < end); | 243 ASSERT(map_ - 1 <= p && p < end); |
234 for (p++; p < end; p++) { | 244 for (p++; p < end; p++) { |
235 if (p->key != NULL) { | 245 if (p->key != NULL) { |
236 return p; | 246 return p; |
237 } | 247 } |
238 } | 248 } |
239 return NULL; | 249 return NULL; |
240 } | 250 } |
241 | 251 |
242 | 252 |
243 template<class P> | 253 template<class AllocationPolicy> |
244 typename TemplateHashMapImpl<P>::Entry* TemplateHashMapImpl<P>::Probe(void* key, | 254 typename TemplateHashMapImpl<AllocationPolicy>::Entry* |
245 uint32_t hash) { | 255 TemplateHashMapImpl<AllocationPolicy>::Probe(void* key, uint32_t hash) { |
246 ASSERT(key != NULL); | 256 ASSERT(key != NULL); |
247 | 257 |
248 ASSERT(IsPowerOf2(capacity_)); | 258 ASSERT(IsPowerOf2(capacity_)); |
249 Entry* p = map_ + (hash & (capacity_ - 1)); | 259 Entry* p = map_ + (hash & (capacity_ - 1)); |
250 const Entry* end = map_end(); | 260 const Entry* end = map_end(); |
251 ASSERT(map_ <= p && p < end); | 261 ASSERT(map_ <= p && p < end); |
252 | 262 |
253 ASSERT(occupancy_ < capacity_); // Guarantees loop termination. | 263 ASSERT(occupancy_ < capacity_); // Guarantees loop termination. |
254 while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) { | 264 while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) { |
255 p++; | 265 p++; |
256 if (p >= end) { | 266 if (p >= end) { |
257 p = map_; | 267 p = map_; |
258 } | 268 } |
259 } | 269 } |
260 | 270 |
261 return p; | 271 return p; |
262 } | 272 } |
263 | 273 |
264 | 274 |
265 template<class P> | 275 template<class AllocationPolicy> |
266 void TemplateHashMapImpl<P>::Initialize(uint32_t capacity) { | 276 void TemplateHashMapImpl<AllocationPolicy>::Initialize( |
277 uint32_t capacity, AllocationPolicy allocator) { | |
267 ASSERT(IsPowerOf2(capacity)); | 278 ASSERT(IsPowerOf2(capacity)); |
268 map_ = reinterpret_cast<Entry*>(P::New(capacity * sizeof(Entry))); | 279 map_ = reinterpret_cast<Entry*>(allocator.New(capacity * sizeof(Entry))); |
269 if (map_ == NULL) { | 280 if (map_ == NULL) { |
270 v8::internal::FatalProcessOutOfMemory("HashMap::Initialize"); | 281 v8::internal::FatalProcessOutOfMemory("HashMap::Initialize"); |
271 return; | 282 return; |
272 } | 283 } |
273 capacity_ = capacity; | 284 capacity_ = capacity; |
274 Clear(); | 285 Clear(); |
275 } | 286 } |
276 | 287 |
277 | 288 |
278 template<class P> | 289 template<class AllocationPolicy> |
279 void TemplateHashMapImpl<P>::Resize() { | 290 void TemplateHashMapImpl<AllocationPolicy>::Resize(AllocationPolicy allocator) { |
280 Entry* map = map_; | 291 Entry* map = map_; |
281 uint32_t n = occupancy_; | 292 uint32_t n = occupancy_; |
282 | 293 |
283 // Allocate larger map. | 294 // Allocate larger map. |
284 Initialize(capacity_ * 2); | 295 Initialize(capacity_ * 2, allocator); |
285 | 296 |
286 // Rehash all current entries. | 297 // Rehash all current entries. |
287 for (Entry* p = map; n > 0; p++) { | 298 for (Entry* p = map; n > 0; p++) { |
288 if (p->key != NULL) { | 299 if (p->key != NULL) { |
289 Lookup(p->key, p->hash, true)->value = p->value; | 300 Lookup(p->key, p->hash, true)->value = p->value; |
290 n--; | 301 n--; |
291 } | 302 } |
292 } | 303 } |
293 | 304 |
294 // Delete old map. | 305 // Delete old map. |
295 P::Delete(map); | 306 AllocationPolicy::Delete(map); |
296 } | 307 } |
297 | 308 |
298 | 309 |
299 // A hash map for pointer keys and values with an STL-like interface. | 310 // A hash map for pointer keys and values with an STL-like interface. |
300 template<class Key, class Value, class AllocationPolicy> | 311 template<class Key, class Value, class AllocationPolicy> |
301 class TemplateHashMap: private TemplateHashMapImpl<AllocationPolicy> { | 312 class TemplateHashMap: private TemplateHashMapImpl<AllocationPolicy> { |
302 public: | 313 public: |
303 STATIC_ASSERT(sizeof(Key*) == sizeof(void*)); // NOLINT | 314 STATIC_ASSERT(sizeof(Key*) == sizeof(void*)); // NOLINT |
304 STATIC_ASSERT(sizeof(Value*) == sizeof(void*)); // NOLINT | 315 STATIC_ASSERT(sizeof(Value*) == sizeof(void*)); // NOLINT |
305 struct value_type { | 316 struct value_type { |
(...skipping 16 matching lines...) Expand all Loading... | |
322 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry) : | 333 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry) : |
323 map_(map), entry_(entry) { } | 334 map_(map), entry_(entry) { } |
324 | 335 |
325 const TemplateHashMapImpl<AllocationPolicy>* map_; | 336 const TemplateHashMapImpl<AllocationPolicy>* map_; |
326 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry_; | 337 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry_; |
327 | 338 |
328 friend class TemplateHashMap; | 339 friend class TemplateHashMap; |
329 }; | 340 }; |
330 | 341 |
331 TemplateHashMap( | 342 TemplateHashMap( |
332 typename TemplateHashMapImpl<AllocationPolicy>::MatchFun match) | 343 typename TemplateHashMapImpl<AllocationPolicy>::MatchFun match, |
333 : TemplateHashMapImpl<AllocationPolicy>(match) { } | 344 AllocationPolicy allocator = AllocationPolicy()) |
345 : TemplateHashMapImpl<AllocationPolicy>( | |
danno
2012/06/04 13:46:17
nit: two space indent from beginning of line here,
sanjoy
2012/06/04 13:58:53
Fixed.
| |
346 match, | |
347 TemplateHashMapImpl<AllocationPolicy>::kDefaultHashMapCapacity, | |
348 allocator) { } | |
334 | 349 |
335 Iterator begin() const { return Iterator(this, this->Start()); } | 350 Iterator begin() const { return Iterator(this, this->Start()); } |
336 Iterator end() const { return Iterator(this, NULL); } | 351 Iterator end() const { return Iterator(this, NULL); } |
337 Iterator find(Key* key, bool insert = false) { | 352 Iterator find(Key* key, bool insert = false) { |
338 return Iterator(this, this->Lookup(key, key->Hash(), insert)); | 353 return Iterator(this, this->Lookup(key, key->Hash(), insert)); |
339 } | 354 } |
340 }; | 355 }; |
341 | 356 |
342 } } // namespace v8::internal | 357 } } // namespace v8::internal |
343 | 358 |
344 #endif // V8_HASHMAP_H_ | 359 #endif // V8_HASHMAP_H_ |
OLD | NEW |