| 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>( |
| 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 |