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 24 matching lines...) Expand all Loading... | |
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 // initial_capacity is the size of the initial hash map; | 43 // initial_capacity is the size of the initial hash map; |
44 // it must be a power of 2 (and thus must not be 0). | 44 // it must be a power of 2 (and thus must not be 0). |
45 TemplateHashMapImpl(MatchFun match, uint32_t initial_capacity = 8); | 45 TemplateHashMapImpl(MatchFun match, uint32_t capacity = 8, |
danno
2012/06/04 10:46:46
Turn default value into a constant so that you can
sanjoy
2012/06/04 11:05:42
Done.
| |
46 AllocationPolicy allocator = AllocationPolicy()); | |
46 | 47 |
47 ~TemplateHashMapImpl(); | 48 ~TemplateHashMapImpl(); |
48 | 49 |
49 // HashMap entries are (key, value, hash) triplets. | 50 // HashMap entries are (key, value, hash) triplets. |
50 // Some clients may not need to use the value slot | 51 // Some clients may not need to use the value slot |
51 // (e.g. implementers of sets, where the key is the value). | 52 // (e.g. implementers of sets, where the key is the value). |
52 struct Entry { | 53 struct Entry { |
53 void* key; | 54 void* key; |
54 void* value; | 55 void* value; |
55 uint32_t hash; // the full hash value for key | 56 uint32_t hash; // the full hash value for key |
56 }; | 57 }; |
57 | 58 |
58 // If an entry with matching key is found, Lookup() | 59 // If an entry with matching key is found, Lookup() |
59 // returns that entry. If no matching entry is found, | 60 // returns that entry. If no matching entry is found, |
60 // but insert is set, a new entry is inserted with | 61 // but insert is set, a new entry is inserted with |
61 // corresponding key, key hash, and NULL value. | 62 // corresponding key, key hash, and NULL value. |
62 // Otherwise, NULL is returned. | 63 // Otherwise, NULL is returned. |
63 Entry* Lookup(void* key, uint32_t hash, bool insert); | 64 Entry* Lookup(void* key, uint32_t hash, bool insert, |
65 AllocationPolicy allocator = AllocationPolicy()); | |
64 | 66 |
65 // Removes the entry with matching key. | 67 // Removes the entry with matching key. |
66 // It returns the value of the deleted entry | 68 // It returns the value of the deleted entry |
67 // or null if there is no value for such key. | 69 // or null if there is no value for such key. |
68 void* Remove(void* key, uint32_t hash); | 70 void* Remove(void* key, uint32_t hash); |
69 | 71 |
70 // Empties the hash map (occupancy() == 0). | 72 // Empties the hash map (occupancy() == 0). |
71 void Clear(); | 73 void Clear(); |
72 | 74 |
73 // The number of (non-empty) entries in the table. | 75 // The number of (non-empty) entries in the table. |
(...skipping 16 matching lines...) Expand all Loading... | |
90 Entry* Next(Entry* p) const; | 92 Entry* Next(Entry* p) const; |
91 | 93 |
92 private: | 94 private: |
93 MatchFun match_; | 95 MatchFun match_; |
94 Entry* map_; | 96 Entry* map_; |
95 uint32_t capacity_; | 97 uint32_t capacity_; |
96 uint32_t occupancy_; | 98 uint32_t occupancy_; |
97 | 99 |
98 Entry* map_end() const { return map_ + capacity_; } | 100 Entry* map_end() const { return map_ + capacity_; } |
99 Entry* Probe(void* key, uint32_t hash); | 101 Entry* Probe(void* key, uint32_t hash); |
100 void Initialize(uint32_t capacity); | 102 void Initialize(uint32_t capacity, AllocationPolicy allocator); |
101 void Resize(); | 103 void Resize(AllocationPolicy allocator); |
102 }; | 104 }; |
103 | 105 |
104 typedef TemplateHashMapImpl<FreeStoreAllocationPolicy> HashMap; | 106 typedef TemplateHashMapImpl<FreeStoreAllocationPolicy> HashMap; |
105 | 107 |
106 template<class P> | 108 template<class AllocationPolicy> |
107 TemplateHashMapImpl<P>::TemplateHashMapImpl(MatchFun match, | 109 TemplateHashMapImpl<AllocationPolicy>::TemplateHashMapImpl( |
108 uint32_t initial_capacity) { | 110 MatchFun match, uint32_t initial_capacity, AllocationPolicy allocator) { |
109 match_ = match; | 111 match_ = match; |
110 Initialize(initial_capacity); | 112 Initialize(initial_capacity, allocator); |
111 } | 113 } |
112 | 114 |
113 | 115 |
114 template<class P> | 116 template<class AllocationPolicy> |
115 TemplateHashMapImpl<P>::~TemplateHashMapImpl() { | 117 TemplateHashMapImpl<AllocationPolicy>::~TemplateHashMapImpl() { |
116 P::Delete(map_); | 118 AllocationPolicy::Delete(map_); |
117 } | 119 } |
118 | 120 |
119 | 121 |
120 template<class P> | 122 template<class AllocationPolicy> |
121 typename TemplateHashMapImpl<P>::Entry* TemplateHashMapImpl<P>::Lookup( | 123 typename TemplateHashMapImpl<AllocationPolicy>::Entry* |
122 void* key, uint32_t hash, bool insert) { | 124 TemplateHashMapImpl<AllocationPolicy>::Lookup( |
125 void* key, uint32_t hash, bool insert, AllocationPolicy allocator) { | |
123 // Find a matching entry. | 126 // Find a matching entry. |
124 Entry* p = Probe(key, hash); | 127 Entry* p = Probe(key, hash); |
125 if (p->key != NULL) { | 128 if (p->key != NULL) { |
126 return p; | 129 return p; |
127 } | 130 } |
128 | 131 |
129 // No entry found; insert one if necessary. | 132 // No entry found; insert one if necessary. |
130 if (insert) { | 133 if (insert) { |
131 p->key = key; | 134 p->key = key; |
132 p->value = NULL; | 135 p->value = NULL; |
133 p->hash = hash; | 136 p->hash = hash; |
134 occupancy_++; | 137 occupancy_++; |
135 | 138 |
136 // Grow the map if we reached >= 80% occupancy. | 139 // Grow the map if we reached >= 80% occupancy. |
137 if (occupancy_ + occupancy_/4 >= capacity_) { | 140 if (occupancy_ + occupancy_/4 >= capacity_) { |
138 Resize(); | 141 Resize(allocator); |
139 p = Probe(key, hash); | 142 p = Probe(key, hash); |
140 } | 143 } |
141 | 144 |
142 return p; | 145 return p; |
143 } | 146 } |
144 | 147 |
145 // No entry found and none inserted. | 148 // No entry found and none inserted. |
146 return NULL; | 149 return NULL; |
147 } | 150 } |
148 | 151 |
149 | 152 |
150 template<class P> | 153 template<class AllocationPolicy> |
151 void* TemplateHashMapImpl<P>::Remove(void* key, uint32_t hash) { | 154 void* TemplateHashMapImpl<AllocationPolicy>::Remove(void* key, uint32_t hash) { |
152 // Lookup the entry for the key to remove. | 155 // Lookup the entry for the key to remove. |
153 Entry* p = Probe(key, hash); | 156 Entry* p = Probe(key, hash); |
154 if (p->key == NULL) { | 157 if (p->key == NULL) { |
155 // Key not found nothing to remove. | 158 // Key not found nothing to remove. |
156 return NULL; | 159 return NULL; |
157 } | 160 } |
158 | 161 |
159 void* value = p->value; | 162 void* value = p->value; |
160 // To remove an entry we need to ensure that it does not create an empty | 163 // 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 | 164 // 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 } | 205 } |
203 } | 206 } |
204 | 207 |
205 // Clear the entry which is allowed to en emptied. | 208 // Clear the entry which is allowed to en emptied. |
206 p->key = NULL; | 209 p->key = NULL; |
207 occupancy_--; | 210 occupancy_--; |
208 return value; | 211 return value; |
209 } | 212 } |
210 | 213 |
211 | 214 |
212 template<class P> | 215 template<class AllocationPolicy> |
213 void TemplateHashMapImpl<P>::Clear() { | 216 void TemplateHashMapImpl<AllocationPolicy>::Clear() { |
214 // Mark all entries as empty. | 217 // Mark all entries as empty. |
215 const Entry* end = map_end(); | 218 const Entry* end = map_end(); |
216 for (Entry* p = map_; p < end; p++) { | 219 for (Entry* p = map_; p < end; p++) { |
217 p->key = NULL; | 220 p->key = NULL; |
218 } | 221 } |
219 occupancy_ = 0; | 222 occupancy_ = 0; |
220 } | 223 } |
221 | 224 |
222 | 225 |
223 template<class P> | 226 template<class AllocationPolicy> |
224 typename TemplateHashMapImpl<P>::Entry* TemplateHashMapImpl<P>::Start() const { | 227 typename TemplateHashMapImpl<AllocationPolicy>::Entry* |
228 TemplateHashMapImpl<AllocationPolicy>::Start() const { | |
225 return Next(map_ - 1); | 229 return Next(map_ - 1); |
226 } | 230 } |
227 | 231 |
228 | 232 |
229 template<class P> | 233 template<class AllocationPolicy> |
230 typename TemplateHashMapImpl<P>::Entry* TemplateHashMapImpl<P>::Next(Entry* p) | 234 typename TemplateHashMapImpl<AllocationPolicy>::Entry* |
231 const { | 235 TemplateHashMapImpl<AllocationPolicy>::Next(Entry* p) const { |
232 const Entry* end = map_end(); | 236 const Entry* end = map_end(); |
233 ASSERT(map_ - 1 <= p && p < end); | 237 ASSERT(map_ - 1 <= p && p < end); |
234 for (p++; p < end; p++) { | 238 for (p++; p < end; p++) { |
235 if (p->key != NULL) { | 239 if (p->key != NULL) { |
236 return p; | 240 return p; |
237 } | 241 } |
238 } | 242 } |
239 return NULL; | 243 return NULL; |
240 } | 244 } |
241 | 245 |
242 | 246 |
243 template<class P> | 247 template<class AllocationPolicy> |
244 typename TemplateHashMapImpl<P>::Entry* TemplateHashMapImpl<P>::Probe(void* key, | 248 typename TemplateHashMapImpl<AllocationPolicy>::Entry* |
245 uint32_t hash) { | 249 TemplateHashMapImpl<AllocationPolicy>::Probe(void* key, uint32_t hash) { |
246 ASSERT(key != NULL); | 250 ASSERT(key != NULL); |
247 | 251 |
248 ASSERT(IsPowerOf2(capacity_)); | 252 ASSERT(IsPowerOf2(capacity_)); |
249 Entry* p = map_ + (hash & (capacity_ - 1)); | 253 Entry* p = map_ + (hash & (capacity_ - 1)); |
250 const Entry* end = map_end(); | 254 const Entry* end = map_end(); |
251 ASSERT(map_ <= p && p < end); | 255 ASSERT(map_ <= p && p < end); |
252 | 256 |
253 ASSERT(occupancy_ < capacity_); // Guarantees loop termination. | 257 ASSERT(occupancy_ < capacity_); // Guarantees loop termination. |
254 while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) { | 258 while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) { |
255 p++; | 259 p++; |
256 if (p >= end) { | 260 if (p >= end) { |
257 p = map_; | 261 p = map_; |
258 } | 262 } |
259 } | 263 } |
260 | 264 |
261 return p; | 265 return p; |
262 } | 266 } |
263 | 267 |
264 | 268 |
265 template<class P> | 269 template<class AllocationPolicy> |
266 void TemplateHashMapImpl<P>::Initialize(uint32_t capacity) { | 270 void TemplateHashMapImpl<AllocationPolicy>::Initialize( |
271 uint32_t capacity, AllocationPolicy allocator) { | |
267 ASSERT(IsPowerOf2(capacity)); | 272 ASSERT(IsPowerOf2(capacity)); |
268 map_ = reinterpret_cast<Entry*>(P::New(capacity * sizeof(Entry))); | 273 map_ = reinterpret_cast<Entry*>(allocator.New(capacity * sizeof(Entry))); |
269 if (map_ == NULL) { | 274 if (map_ == NULL) { |
270 v8::internal::FatalProcessOutOfMemory("HashMap::Initialize"); | 275 v8::internal::FatalProcessOutOfMemory("HashMap::Initialize"); |
271 return; | 276 return; |
272 } | 277 } |
273 capacity_ = capacity; | 278 capacity_ = capacity; |
274 Clear(); | 279 Clear(); |
275 } | 280 } |
276 | 281 |
277 | 282 |
278 template<class P> | 283 template<class AllocationPolicy> |
279 void TemplateHashMapImpl<P>::Resize() { | 284 void TemplateHashMapImpl<AllocationPolicy>::Resize(AllocationPolicy allocator) { |
280 Entry* map = map_; | 285 Entry* map = map_; |
281 uint32_t n = occupancy_; | 286 uint32_t n = occupancy_; |
282 | 287 |
283 // Allocate larger map. | 288 // Allocate larger map. |
284 Initialize(capacity_ * 2); | 289 Initialize(capacity_ * 2, allocator); |
285 | 290 |
286 // Rehash all current entries. | 291 // Rehash all current entries. |
287 for (Entry* p = map; n > 0; p++) { | 292 for (Entry* p = map; n > 0; p++) { |
288 if (p->key != NULL) { | 293 if (p->key != NULL) { |
289 Lookup(p->key, p->hash, true)->value = p->value; | 294 Lookup(p->key, p->hash, true)->value = p->value; |
290 n--; | 295 n--; |
291 } | 296 } |
292 } | 297 } |
293 | 298 |
294 // Delete old map. | 299 // Delete old map. |
295 P::Delete(map); | 300 AllocationPolicy::Delete(map); |
296 } | 301 } |
297 | 302 |
298 | 303 |
299 // A hash map for pointer keys and values with an STL-like interface. | 304 // A hash map for pointer keys and values with an STL-like interface. |
300 template<class Key, class Value, class AllocationPolicy> | 305 template<class Key, class Value, class AllocationPolicy> |
301 class TemplateHashMap: private TemplateHashMapImpl<AllocationPolicy> { | 306 class TemplateHashMap: private TemplateHashMapImpl<AllocationPolicy> { |
302 public: | 307 public: |
303 STATIC_ASSERT(sizeof(Key*) == sizeof(void*)); // NOLINT | 308 STATIC_ASSERT(sizeof(Key*) == sizeof(void*)); // NOLINT |
304 STATIC_ASSERT(sizeof(Value*) == sizeof(void*)); // NOLINT | 309 STATIC_ASSERT(sizeof(Value*) == sizeof(void*)); // NOLINT |
305 struct value_type { | 310 struct value_type { |
(...skipping 16 matching lines...) Expand all Loading... | |
322 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry) : | 327 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry) : |
323 map_(map), entry_(entry) { } | 328 map_(map), entry_(entry) { } |
324 | 329 |
325 const TemplateHashMapImpl<AllocationPolicy>* map_; | 330 const TemplateHashMapImpl<AllocationPolicy>* map_; |
326 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry_; | 331 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry_; |
327 | 332 |
328 friend class TemplateHashMap; | 333 friend class TemplateHashMap; |
329 }; | 334 }; |
330 | 335 |
331 TemplateHashMap( | 336 TemplateHashMap( |
332 typename TemplateHashMapImpl<AllocationPolicy>::MatchFun match) | 337 typename TemplateHashMapImpl<AllocationPolicy>::MatchFun match, |
333 : TemplateHashMapImpl<AllocationPolicy>(match) { } | 338 AllocationPolicy allocator = AllocationPolicy()) |
339 : TemplateHashMapImpl<AllocationPolicy>(match, 8, allocator) { } | |
danno
2012/06/04 10:46:46
As discussed above, use constant for this.
sanjoy
2012/06/04 11:05:42
Done.
| |
334 | 340 |
335 Iterator begin() const { return Iterator(this, this->Start()); } | 341 Iterator begin() const { return Iterator(this, this->Start()); } |
336 Iterator end() const { return Iterator(this, NULL); } | 342 Iterator end() const { return Iterator(this, NULL); } |
337 Iterator find(Key* key, bool insert = false) { | 343 Iterator find(Key* key, bool insert = false) { |
338 return Iterator(this, this->Lookup(key, key->Hash(), insert)); | 344 return Iterator(this, this->Lookup(key, key->Hash(), insert)); |
339 } | 345 } |
340 }; | 346 }; |
341 | 347 |
342 } } // namespace v8::internal | 348 } } // namespace v8::internal |
343 | 349 |
344 #endif // V8_HASHMAP_H_ | 350 #endif // V8_HASHMAP_H_ |
OLD | NEW |