| 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, |
| 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 |
| 310 |
| 305 struct value_type { | 311 struct value_type { |
| 306 Key* first; | 312 Key* first; |
| 307 Value* second; | 313 Value* second; |
| 308 }; | 314 }; |
| 309 | 315 |
| 310 class Iterator { | 316 class Iterator { |
| 311 public: | 317 public: |
| 312 Iterator& operator++() { | 318 Iterator& operator++() { |
| 313 entry_ = map_->Next(entry_); | 319 entry_ = map_->Next(entry_); |
| 314 return *this; | 320 return *this; |
| 315 } | 321 } |
| 316 | 322 |
| 317 value_type* operator->() { return reinterpret_cast<value_type*>(entry_); } | 323 value_type* operator->() { return reinterpret_cast<value_type*>(entry_); } |
| 318 bool operator!=(const Iterator& other) { return entry_ != other.entry_; } | 324 bool operator!=(const Iterator& other) { return entry_ != other.entry_; } |
| 319 | 325 |
| 320 private: | 326 private: |
| 321 Iterator(const TemplateHashMapImpl<AllocationPolicy>* map, | 327 Iterator(const TemplateHashMapImpl<AllocationPolicy>* map, |
| 322 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry) : | 328 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry) : |
| 323 map_(map), entry_(entry) { } | 329 map_(map), entry_(entry) { } |
| 324 | 330 |
| 325 const TemplateHashMapImpl<AllocationPolicy>* map_; | 331 const TemplateHashMapImpl<AllocationPolicy>* map_; |
| 326 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry_; | 332 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry_; |
| 327 | 333 |
| 328 friend class TemplateHashMap; | 334 friend class TemplateHashMap; |
| 329 }; | 335 }; |
| 330 | 336 |
| 331 TemplateHashMap( | 337 TemplateHashMap( |
| 332 typename TemplateHashMapImpl<AllocationPolicy>::MatchFun match) | 338 typename TemplateHashMapImpl<AllocationPolicy>::MatchFun match, |
| 333 : TemplateHashMapImpl<AllocationPolicy>(match) { } | 339 AllocationPolicy allocator = AllocationPolicy()) |
| 340 : TemplateHashMapImpl<AllocationPolicy>(match, 8, allocator) { } |
| 334 | 341 |
| 335 Iterator begin() const { return Iterator(this, this->Start()); } | 342 Iterator begin() const { return Iterator(this, this->Start()); } |
| 336 Iterator end() const { return Iterator(this, NULL); } | 343 Iterator end() const { return Iterator(this, NULL); } |
| 337 Iterator find(Key* key, bool insert = false) { | 344 Iterator find(Key* key, bool insert = false) { |
| 338 return Iterator(this, this->Lookup(key, key->Hash(), insert)); | 345 return Iterator(this, this->Lookup(key, key->Hash(), insert)); |
| 339 } | 346 } |
| 340 }; | 347 }; |
| 341 | 348 |
| 342 } } // namespace v8::internal | 349 } } // namespace v8::internal |
| 343 | 350 |
| 344 #endif // V8_HASHMAP_H_ | 351 #endif // V8_HASHMAP_H_ |
| OLD | NEW |