Chromium Code Reviews| 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 // The reason we write our own hash map instead of using unordered_map in STL, | 5 // The reason we write our own hash map instead of using unordered_map in STL, |
| 6 // is that STL containers use a mutex pool on debug build, which will lead to | 6 // is that STL containers use a mutex pool on debug build, which will lead to |
| 7 // deadlock when we are using async signal handler. | 7 // deadlock when we are using async signal handler. |
| 8 | 8 |
| 9 #ifndef V8_BASE_HASHMAP_H_ | 9 #ifndef V8_BASE_HASHMAP_H_ |
| 10 #define V8_BASE_HASHMAP_H_ | 10 #define V8_BASE_HASHMAP_H_ |
| 11 | 11 |
| 12 #include <stdlib.h> | 12 #include <stdlib.h> |
| 13 | 13 |
| 14 #include "src/base/bits.h" | 14 #include "src/base/bits.h" |
| 15 #include "src/base/hashmap-entry.h" | |
| 15 #include "src/base/logging.h" | 16 #include "src/base/logging.h" |
| 16 | 17 |
| 17 namespace v8 { | 18 namespace v8 { |
| 18 namespace base { | 19 namespace base { |
| 19 | 20 |
| 20 class DefaultAllocationPolicy { | 21 class DefaultAllocationPolicy { |
| 21 public: | 22 public: |
| 22 V8_INLINE void* New(size_t size) { return malloc(size); } | 23 V8_INLINE void* New(size_t size) { return malloc(size); } |
| 23 V8_INLINE static void Delete(void* p) { free(p); } | 24 V8_INLINE static void Delete(void* p) { free(p); } |
| 24 }; | 25 }; |
| 25 | 26 |
| 26 template <class AllocationPolicy> | 27 // Metaprogramming helper to allow pointer keys to be passed by value and |
| 28 // non-pointer keys by const reference. | |
| 29 template <typename Key> | |
| 30 struct MatchFunHelper; | |
| 31 | |
| 32 template <typename Key, typename Value, class AllocationPolicy> | |
| 27 class TemplateHashMapImpl { | 33 class TemplateHashMapImpl { |
| 28 public: | 34 public: |
| 29 typedef bool (*MatchFun)(void* key1, void* key2); | 35 typedef typename MatchFunHelper<Key>::Fun MatchFun; |
| 36 typedef TemplateHashMapEntry<Key, Value> Entry; | |
| 30 | 37 |
| 31 // The default capacity. This is used by the call sites which want | 38 // The default capacity. This is used by the call sites which want |
| 32 // to pass in a non-default AllocationPolicy but want to use the | 39 // to pass in a non-default AllocationPolicy but want to use the |
| 33 // default value of capacity specified by the implementation. | 40 // default value of capacity specified by the implementation. |
| 34 static const uint32_t kDefaultHashMapCapacity = 8; | 41 static const uint32_t kDefaultHashMapCapacity = 8; |
| 35 | 42 |
| 36 // initial_capacity is the size of the initial hash map; | 43 // initial_capacity is the size of the initial hash map; |
| 37 // 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). |
| 38 TemplateHashMapImpl(MatchFun match, | 45 TemplateHashMapImpl(MatchFun match, |
| 39 uint32_t capacity = kDefaultHashMapCapacity, | 46 uint32_t capacity = kDefaultHashMapCapacity, |
| 40 AllocationPolicy allocator = AllocationPolicy()); | 47 AllocationPolicy allocator = AllocationPolicy()); |
| 41 | 48 |
| 42 ~TemplateHashMapImpl(); | 49 ~TemplateHashMapImpl(); |
| 43 | 50 |
| 44 // HashMap entries are (key, value, hash) triplets. | |
| 45 // Some clients may not need to use the value slot | |
| 46 // (e.g. implementers of sets, where the key is the value). | |
| 47 struct Entry { | |
| 48 void* key; | |
| 49 void* value; | |
| 50 uint32_t hash; // The full hash value for key | |
| 51 }; | |
| 52 | |
| 53 // If an entry with matching key is found, returns that entry. | 51 // If an entry with matching key is found, returns that entry. |
| 54 // Otherwise, NULL is returned. | 52 // Otherwise, nullptr is returned. |
| 55 Entry* Lookup(void* key, uint32_t hash) const; | 53 Entry* Lookup(const Key& key, uint32_t hash) const; |
| 56 | 54 |
| 57 // If an entry with matching key is found, returns that entry. | 55 // If an entry with matching key is found, returns that entry. |
| 58 // If no matching entry is found, a new entry is inserted with | 56 // If no matching entry is found, a new entry is inserted with |
| 59 // corresponding key, key hash, and NULL value. | 57 // corresponding key, key hash, and default initialized value. |
| 60 Entry* LookupOrInsert(void* key, uint32_t hash, | 58 Entry* LookupOrInsert(const Key& key, uint32_t hash, |
| 61 AllocationPolicy allocator = AllocationPolicy()); | 59 AllocationPolicy allocator = AllocationPolicy()); |
| 62 | 60 |
| 63 Entry* InsertNew(void* key, uint32_t hash, | 61 Entry* InsertNew(const Key& key, uint32_t hash, |
| 64 AllocationPolicy allocator = AllocationPolicy()); | 62 AllocationPolicy allocator = AllocationPolicy()); |
| 65 | 63 |
| 66 // Removes the entry with matching key. | 64 // Removes the entry with matching key. |
| 67 // It returns the value of the deleted entry | 65 // It returns the value of the deleted entry |
| 68 // or null if there is no value for such key. | 66 // or null if there is no value for such key. |
| 69 void* Remove(void* key, uint32_t hash); | 67 Value Remove(const Key& key, uint32_t hash); |
| 70 | 68 |
| 71 // Empties the hash map (occupancy() == 0). | 69 // Empties the hash map (occupancy() == 0). |
| 72 void Clear(); | 70 void Clear(); |
| 73 | 71 |
| 74 // The number of (non-empty) entries in the table. | 72 // The number of (non-empty) entries in the table. |
| 75 uint32_t occupancy() const { return occupancy_; } | 73 uint32_t occupancy() const { return occupancy_; } |
| 76 | 74 |
| 77 // The capacity of the table. The implementation | 75 // The capacity of the table. The implementation |
| 78 // makes sure that occupancy is at most 80% of | 76 // makes sure that occupancy is at most 80% of |
| 79 // the table capacity. | 77 // the table capacity. |
| 80 uint32_t capacity() const { return capacity_; } | 78 uint32_t capacity() const { return capacity_; } |
| 81 | 79 |
| 82 // Iteration | 80 // Iteration |
| 83 // | 81 // |
| 84 // for (Entry* p = map.Start(); p != NULL; p = map.Next(p)) { | 82 // for (Entry* p = map.Start(); p != nullptr; p = map.Next(p)) { |
| 85 // ... | 83 // ... |
| 86 // } | 84 // } |
| 87 // | 85 // |
| 88 // If entries are inserted during iteration, the effect of | 86 // If entries are inserted during iteration, the effect of |
| 89 // calling Next() is undefined. | 87 // calling Next() is undefined. |
| 90 Entry* Start() const; | 88 Entry* Start() const; |
| 91 Entry* Next(Entry* p) const; | 89 Entry* Next(Entry* p) const; |
| 92 | 90 |
| 93 // Some match functions defined for convenience. | 91 // Some match functions defined for convenience. |
| 94 static bool PointersMatch(void* key1, void* key2) { return key1 == key2; } | 92 static bool PointersMatch(typename MatchFunHelper<Key>::KeyRef key1, |
|
rmcilroy
2016/09/19 10:32:07
Hmm, this isn't really PointersMatch unless Key is
Leszek Swirski
2016/09/19 10:45:33
Added a TODO because I want to move the matcher fu
| |
| 93 typename MatchFunHelper<Key>::KeyRef key2) { | |
| 94 return key1 == key2; | |
| 95 } | |
| 95 | 96 |
| 96 private: | 97 private: |
| 97 MatchFun match_; | 98 MatchFun match_; |
| 98 Entry* map_; | 99 Entry* map_; |
| 99 uint32_t capacity_; | 100 uint32_t capacity_; |
| 100 uint32_t occupancy_; | 101 uint32_t occupancy_; |
| 101 | 102 |
| 102 Entry* map_end() const { return map_ + capacity_; } | 103 Entry* map_end() const { return map_ + capacity_; } |
| 103 Entry* Probe(void* key, uint32_t hash) const; | 104 Entry* Probe(const Key& key, uint32_t hash) const; |
| 104 void Initialize(uint32_t capacity, AllocationPolicy allocator); | 105 void Initialize(uint32_t capacity, AllocationPolicy allocator); |
| 105 void Resize(AllocationPolicy allocator); | 106 void Resize(AllocationPolicy allocator); |
| 106 }; | 107 }; |
| 107 | 108 |
| 108 typedef TemplateHashMapImpl<DefaultAllocationPolicy> HashMap; | 109 template <typename Key> |
| 110 struct MatchFunHelper { | |
| 111 typedef const Key& KeyRef; | |
| 112 typedef bool (*Fun)(KeyRef key1, KeyRef key2); | |
| 113 }; | |
| 109 | 114 |
| 110 template <class AllocationPolicy> | 115 template <typename Key> |
| 111 TemplateHashMapImpl<AllocationPolicy>::TemplateHashMapImpl( | 116 struct MatchFunHelper<Key*> { |
| 117 typedef Key* KeyRef; | |
| 118 typedef bool (*Fun)(KeyRef key1, KeyRef key2); | |
| 119 }; | |
| 120 | |
| 121 typedef TemplateHashMapImpl<void*, void*, DefaultAllocationPolicy> HashMap; | |
| 122 | |
| 123 template <typename Key, typename Value, class AllocationPolicy> | |
| 124 TemplateHashMapImpl<Key, Value, AllocationPolicy>::TemplateHashMapImpl( | |
| 112 MatchFun match, uint32_t initial_capacity, AllocationPolicy allocator) { | 125 MatchFun match, uint32_t initial_capacity, AllocationPolicy allocator) { |
| 113 match_ = match; | 126 match_ = match; |
| 114 Initialize(initial_capacity, allocator); | 127 Initialize(initial_capacity, allocator); |
| 115 } | 128 } |
| 116 | 129 |
| 117 template <class AllocationPolicy> | 130 template <typename Key, typename Value, class AllocationPolicy> |
| 118 TemplateHashMapImpl<AllocationPolicy>::~TemplateHashMapImpl() { | 131 TemplateHashMapImpl<Key, Value, AllocationPolicy>::~TemplateHashMapImpl() { |
| 119 AllocationPolicy::Delete(map_); | 132 AllocationPolicy::Delete(map_); |
| 120 } | 133 } |
| 121 | 134 |
| 122 template <class AllocationPolicy> | 135 template <typename Key, typename Value, class AllocationPolicy> |
| 123 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | 136 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 124 TemplateHashMapImpl<AllocationPolicy>::Lookup(void* key, uint32_t hash) const { | 137 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Lookup(const Key& key, |
| 138 uint32_t hash) const { | |
| 125 Entry* p = Probe(key, hash); | 139 Entry* p = Probe(key, hash); |
| 126 return p->key != NULL ? p : NULL; | 140 return p->exists() ? p : nullptr; |
| 127 } | 141 } |
| 128 | 142 |
| 129 template <class AllocationPolicy> | 143 template <typename Key, typename Value, class AllocationPolicy> |
| 130 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | 144 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 131 TemplateHashMapImpl<AllocationPolicy>::LookupOrInsert( | 145 TemplateHashMapImpl<Key, Value, AllocationPolicy>::LookupOrInsert( |
| 132 void* key, uint32_t hash, AllocationPolicy allocator) { | 146 const Key& key, uint32_t hash, AllocationPolicy allocator) { |
| 133 // Find a matching entry. | 147 // Find a matching entry. |
| 134 Entry* p = Probe(key, hash); | 148 Entry* p = Probe(key, hash); |
| 135 if (p->key != NULL) { | 149 if (p->exists()) { |
| 136 return p; | 150 return p; |
| 137 } | 151 } |
| 138 | 152 |
| 139 return InsertNew(key, hash, allocator); | 153 return InsertNew(key, hash, allocator); |
| 140 } | 154 } |
| 141 | 155 |
| 142 template <class AllocationPolicy> | 156 template <typename Key, typename Value, class AllocationPolicy> |
| 143 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | 157 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 144 TemplateHashMapImpl<AllocationPolicy>::InsertNew(void* key, uint32_t hash, | 158 TemplateHashMapImpl<Key, Value, AllocationPolicy>::InsertNew( |
| 145 AllocationPolicy allocator) { | 159 const Key& key, uint32_t hash, AllocationPolicy allocator) { |
| 146 // Find a matching entry. | 160 // Find a matching entry. |
| 147 Entry* p = Probe(key, hash); | 161 Entry* p = Probe(key, hash); |
| 148 DCHECK(p->key == NULL); | 162 DCHECK(!p->exists()); |
| 149 | 163 |
| 150 // No entry found; insert one. | 164 // No entry found; insert one. |
| 151 p->key = key; | 165 new (p) Entry(key, Value(), hash); |
|
rmcilroy
2016/09/19 10:32:07
Could you add a comment that this is in-placement
Leszek Swirski
2016/09/19 10:45:33
Done.
| |
| 152 p->value = NULL; | |
| 153 p->hash = hash; | |
| 154 occupancy_++; | 166 occupancy_++; |
| 155 | 167 |
| 156 // Grow the map if we reached >= 80% occupancy. | 168 // Grow the map if we reached >= 80% occupancy. |
| 157 if (occupancy_ + occupancy_ / 4 >= capacity_) { | 169 if (occupancy_ + occupancy_ / 4 >= capacity_) { |
| 158 Resize(allocator); | 170 Resize(allocator); |
| 159 p = Probe(key, hash); | 171 p = Probe(key, hash); |
| 160 } | 172 } |
| 161 | 173 |
| 162 return p; | 174 return p; |
| 163 } | 175 } |
| 164 | 176 |
| 165 template <class AllocationPolicy> | 177 template <typename Key, typename Value, class AllocationPolicy> |
| 166 void* TemplateHashMapImpl<AllocationPolicy>::Remove(void* key, uint32_t hash) { | 178 Value TemplateHashMapImpl<Key, Value, AllocationPolicy>::Remove(const Key& key, |
| 179 uint32_t hash) { | |
| 167 // Lookup the entry for the key to remove. | 180 // Lookup the entry for the key to remove. |
| 168 Entry* p = Probe(key, hash); | 181 Entry* p = Probe(key, hash); |
| 169 if (p->key == NULL) { | 182 if (!p->exists()) { |
| 170 // Key not found nothing to remove. | 183 // Key not found nothing to remove. |
| 171 return NULL; | 184 return nullptr; |
| 172 } | 185 } |
| 173 | 186 |
| 174 void* value = p->value; | 187 Value value = p->value; |
| 175 // To remove an entry we need to ensure that it does not create an empty | 188 // To remove an entry we need to ensure that it does not create an empty |
| 176 // entry that will cause the search for another entry to stop too soon. If all | 189 // entry that will cause the search for another entry to stop too soon. If all |
| 177 // the entries between the entry to remove and the next empty slot have their | 190 // the entries between the entry to remove and the next empty slot have their |
| 178 // initial position inside this interval, clearing the entry to remove will | 191 // initial position inside this interval, clearing the entry to remove will |
| 179 // not break the search. If, while searching for the next empty entry, an | 192 // not break the search. If, while searching for the next empty entry, an |
| 180 // entry is encountered which does not have its initial position between the | 193 // entry is encountered which does not have its initial position between the |
| 181 // entry to remove and the position looked at, then this entry can be moved to | 194 // entry to remove and the position looked at, then this entry can be moved to |
| 182 // the place of the entry to remove without breaking the search for it. The | 195 // the place of the entry to remove without breaking the search for it. The |
| 183 // entry made vacant by this move is now the entry to remove and the process | 196 // entry made vacant by this move is now the entry to remove and the process |
| 184 // starts over. | 197 // starts over. |
| 185 // Algorithm from http://en.wikipedia.org/wiki/Open_addressing. | 198 // Algorithm from http://en.wikipedia.org/wiki/Open_addressing. |
| 186 | 199 |
| 187 // This guarantees loop termination as there is at least one empty entry so | 200 // This guarantees loop termination as there is at least one empty entry so |
| 188 // eventually the removed entry will have an empty entry after it. | 201 // eventually the removed entry will have an empty entry after it. |
| 189 DCHECK(occupancy_ < capacity_); | 202 DCHECK(occupancy_ < capacity_); |
| 190 | 203 |
| 191 // p is the candidate entry to clear. q is used to scan forwards. | 204 // p is the candidate entry to clear. q is used to scan forwards. |
| 192 Entry* q = p; // Start at the entry to remove. | 205 Entry* q = p; // Start at the entry to remove. |
| 193 while (true) { | 206 while (true) { |
| 194 // Move q to the next entry. | 207 // Move q to the next entry. |
| 195 q = q + 1; | 208 q = q + 1; |
| 196 if (q == map_end()) { | 209 if (q == map_end()) { |
| 197 q = map_; | 210 q = map_; |
| 198 } | 211 } |
| 199 | 212 |
| 200 // All entries between p and q have their initial position between p and q | 213 // All entries between p and q have their initial position between p and q |
| 201 // and the entry p can be cleared without breaking the search for these | 214 // and the entry p can be cleared without breaking the search for these |
| 202 // entries. | 215 // entries. |
| 203 if (q->key == NULL) { | 216 if (!q->exists()) { |
| 204 break; | 217 break; |
| 205 } | 218 } |
| 206 | 219 |
| 207 // Find the initial position for the entry at position q. | 220 // Find the initial position for the entry at position q. |
| 208 Entry* r = map_ + (q->hash & (capacity_ - 1)); | 221 Entry* r = map_ + (q->hash & (capacity_ - 1)); |
| 209 | 222 |
| 210 // If the entry at position q has its initial position outside the range | 223 // If the entry at position q has its initial position outside the range |
| 211 // between p and q it can be moved forward to position p and will still be | 224 // between p and q it can be moved forward to position p and will still be |
| 212 // found. There is now a new candidate entry for clearing. | 225 // found. There is now a new candidate entry for clearing. |
| 213 if ((q > p && (r <= p || r > q)) || (q < p && (r <= p && r > q))) { | 226 if ((q > p && (r <= p || r > q)) || (q < p && (r <= p && r > q))) { |
| 214 *p = *q; | 227 *p = *q; |
| 215 p = q; | 228 p = q; |
| 216 } | 229 } |
| 217 } | 230 } |
| 218 | 231 |
| 219 // Clear the entry which is allowed to en emptied. | 232 // Clear the entry which is allowed to en emptied. |
| 220 p->key = NULL; | 233 p->clear(); |
| 221 occupancy_--; | 234 occupancy_--; |
| 222 return value; | 235 return value; |
| 223 } | 236 } |
| 224 | 237 |
| 225 template <class AllocationPolicy> | 238 template <typename Key, typename Value, class AllocationPolicy> |
| 226 void TemplateHashMapImpl<AllocationPolicy>::Clear() { | 239 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Clear() { |
| 227 // Mark all entries as empty. | 240 // Mark all entries as empty. |
| 228 const Entry* end = map_end(); | 241 const Entry* end = map_end(); |
| 229 for (Entry* p = map_; p < end; p++) { | 242 for (Entry* p = map_; p < end; p++) { |
| 230 p->key = NULL; | 243 p->clear(); |
| 231 } | 244 } |
| 232 occupancy_ = 0; | 245 occupancy_ = 0; |
| 233 } | 246 } |
| 234 | 247 |
| 235 template <class AllocationPolicy> | 248 template <typename Key, typename Value, class AllocationPolicy> |
| 236 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | 249 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 237 TemplateHashMapImpl<AllocationPolicy>::Start() const { | 250 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Start() const { |
| 238 return Next(map_ - 1); | 251 return Next(map_ - 1); |
| 239 } | 252 } |
| 240 | 253 |
| 241 template <class AllocationPolicy> | 254 template <typename Key, typename Value, class AllocationPolicy> |
| 242 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | 255 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 243 TemplateHashMapImpl<AllocationPolicy>::Next(Entry* p) const { | 256 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Next(Entry* p) const { |
| 244 const Entry* end = map_end(); | 257 const Entry* end = map_end(); |
| 245 DCHECK(map_ - 1 <= p && p < end); | 258 DCHECK(map_ - 1 <= p && p < end); |
| 246 for (p++; p < end; p++) { | 259 for (p++; p < end; p++) { |
| 247 if (p->key != NULL) { | 260 if (p->exists()) { |
| 248 return p; | 261 return p; |
| 249 } | 262 } |
| 250 } | 263 } |
| 251 return NULL; | 264 return nullptr; |
| 252 } | 265 } |
| 253 | 266 |
| 254 template <class AllocationPolicy> | 267 template <typename Key, typename Value, class AllocationPolicy> |
| 255 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | 268 typename TemplateHashMapImpl<Key, Value, AllocationPolicy>::Entry* |
| 256 TemplateHashMapImpl<AllocationPolicy>::Probe(void* key, uint32_t hash) const { | 269 TemplateHashMapImpl<Key, Value, AllocationPolicy>::Probe(const Key& key, |
| 257 DCHECK(key != NULL); | 270 uint32_t hash) const { |
| 258 | |
| 259 DCHECK(base::bits::IsPowerOfTwo32(capacity_)); | 271 DCHECK(base::bits::IsPowerOfTwo32(capacity_)); |
| 260 Entry* p = map_ + (hash & (capacity_ - 1)); | 272 Entry* p = map_ + (hash & (capacity_ - 1)); |
| 261 const Entry* end = map_end(); | 273 const Entry* end = map_end(); |
| 262 DCHECK(map_ <= p && p < end); | 274 DCHECK(map_ <= p && p < end); |
| 263 | 275 |
| 264 DCHECK(occupancy_ < capacity_); // Guarantees loop termination. | 276 DCHECK(occupancy_ < capacity_); // Guarantees loop termination. |
| 265 while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) { | 277 while (p->exists() && (hash != p->hash || !match_(key, p->key))) { |
| 266 p++; | 278 p++; |
| 267 if (p >= end) { | 279 if (p >= end) { |
| 268 p = map_; | 280 p = map_; |
| 269 } | 281 } |
| 270 } | 282 } |
| 271 | 283 |
| 272 return p; | 284 return p; |
| 273 } | 285 } |
| 274 | 286 |
| 275 template <class AllocationPolicy> | 287 template <typename Key, typename Value, class AllocationPolicy> |
| 276 void TemplateHashMapImpl<AllocationPolicy>::Initialize( | 288 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Initialize( |
| 277 uint32_t capacity, AllocationPolicy allocator) { | 289 uint32_t capacity, AllocationPolicy allocator) { |
| 278 DCHECK(base::bits::IsPowerOfTwo32(capacity)); | 290 DCHECK(base::bits::IsPowerOfTwo32(capacity)); |
| 279 map_ = reinterpret_cast<Entry*>(allocator.New(capacity * sizeof(Entry))); | 291 map_ = reinterpret_cast<Entry*>(allocator.New(capacity * sizeof(Entry))); |
| 280 if (map_ == NULL) { | 292 if (map_ == nullptr) { |
| 281 FATAL("Out of memory: HashMap::Initialize"); | 293 FATAL("Out of memory: HashMap::Initialize"); |
| 282 return; | 294 return; |
| 283 } | 295 } |
| 284 capacity_ = capacity; | 296 capacity_ = capacity; |
| 285 Clear(); | 297 Clear(); |
| 286 } | 298 } |
| 287 | 299 |
| 288 template <class AllocationPolicy> | 300 template <typename Key, typename Value, class AllocationPolicy> |
| 289 void TemplateHashMapImpl<AllocationPolicy>::Resize(AllocationPolicy allocator) { | 301 void TemplateHashMapImpl<Key, Value, AllocationPolicy>::Resize( |
| 302 AllocationPolicy allocator) { | |
| 290 Entry* map = map_; | 303 Entry* map = map_; |
| 291 uint32_t n = occupancy_; | 304 uint32_t n = occupancy_; |
| 292 | 305 |
| 293 // Allocate larger map. | 306 // Allocate larger map. |
| 294 Initialize(capacity_ * 2, allocator); | 307 Initialize(capacity_ * 2, allocator); |
| 295 | 308 |
| 296 // Rehash all current entries. | 309 // Rehash all current entries. |
| 297 for (Entry* p = map; n > 0; p++) { | 310 for (Entry* p = map; n > 0; p++) { |
| 298 if (p->key != NULL) { | 311 if (p->exists()) { |
| 299 Entry* entry = LookupOrInsert(p->key, p->hash, allocator); | 312 Entry* entry = LookupOrInsert(p->key, p->hash, allocator); |
| 300 entry->value = p->value; | 313 entry->value = p->value; |
| 301 n--; | 314 n--; |
| 302 } | 315 } |
| 303 } | 316 } |
| 304 | 317 |
| 305 // Delete old map. | 318 // Delete old map. |
| 306 AllocationPolicy::Delete(map); | 319 AllocationPolicy::Delete(map); |
| 307 } | 320 } |
| 308 | 321 |
| 309 // A hash map for pointer keys and values with an STL-like interface. | 322 // A hash map for pointer keys and values with an STL-like interface. |
| 310 template <class Key, class Value, class AllocationPolicy> | 323 template <class Key, class Value, class AllocationPolicy> |
| 311 class TemplateHashMap : private TemplateHashMapImpl<AllocationPolicy> { | 324 class TemplateHashMap |
| 325 : private TemplateHashMapImpl<void*, void*, AllocationPolicy> { | |
| 312 public: | 326 public: |
| 313 STATIC_ASSERT(sizeof(Key*) == sizeof(void*)); // NOLINT | 327 STATIC_ASSERT(sizeof(Key*) == sizeof(void*)); // NOLINT |
| 314 STATIC_ASSERT(sizeof(Value*) == sizeof(void*)); // NOLINT | 328 STATIC_ASSERT(sizeof(Value*) == sizeof(void*)); // NOLINT |
| 315 struct value_type { | 329 struct value_type { |
| 316 Key* first; | 330 Key* first; |
| 317 Value* second; | 331 Value* second; |
| 318 }; | 332 }; |
| 319 | 333 |
| 320 class Iterator { | 334 class Iterator { |
| 321 public: | 335 public: |
| 322 Iterator& operator++() { | 336 Iterator& operator++() { |
| 323 entry_ = map_->Next(entry_); | 337 entry_ = map_->Next(entry_); |
| 324 return *this; | 338 return *this; |
| 325 } | 339 } |
| 326 | 340 |
| 327 value_type* operator->() { return reinterpret_cast<value_type*>(entry_); } | 341 value_type* operator->() { return reinterpret_cast<value_type*>(entry_); } |
| 328 bool operator!=(const Iterator& other) { return entry_ != other.entry_; } | 342 bool operator!=(const Iterator& other) { return entry_ != other.entry_; } |
| 329 | 343 |
| 330 private: | 344 private: |
| 331 Iterator(const TemplateHashMapImpl<AllocationPolicy>* map, | 345 Iterator(const TemplateHashMapImpl<void*, void*, AllocationPolicy>* map, |
| 332 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry) | 346 typename TemplateHashMapImpl<void*, void*, |
| 347 AllocationPolicy>::Entry* entry) | |
| 333 : map_(map), entry_(entry) {} | 348 : map_(map), entry_(entry) {} |
| 334 | 349 |
| 335 const TemplateHashMapImpl<AllocationPolicy>* map_; | 350 const TemplateHashMapImpl<void*, void*, AllocationPolicy>* map_; |
| 336 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry_; | 351 typename TemplateHashMapImpl<void*, void*, AllocationPolicy>::Entry* entry_; |
| 337 | 352 |
| 338 friend class TemplateHashMap; | 353 friend class TemplateHashMap; |
| 339 }; | 354 }; |
| 340 | 355 |
| 341 TemplateHashMap( | 356 TemplateHashMap(typename TemplateHashMapImpl< |
| 342 typename TemplateHashMapImpl<AllocationPolicy>::MatchFun match, | 357 void*, void*, AllocationPolicy>::MatchFun match, |
| 343 AllocationPolicy allocator = AllocationPolicy()) | 358 AllocationPolicy allocator = AllocationPolicy()) |
| 344 : TemplateHashMapImpl<AllocationPolicy>( | 359 : TemplateHashMapImpl<void*, void*, AllocationPolicy>( |
| 345 match, | 360 match, |
| 346 TemplateHashMapImpl<AllocationPolicy>::kDefaultHashMapCapacity, | 361 TemplateHashMapImpl<void*, void*, |
| 362 AllocationPolicy>::kDefaultHashMapCapacity, | |
| 347 allocator) {} | 363 allocator) {} |
| 348 | 364 |
| 349 Iterator begin() const { return Iterator(this, this->Start()); } | 365 Iterator begin() const { return Iterator(this, this->Start()); } |
| 350 Iterator end() const { return Iterator(this, NULL); } | 366 Iterator end() const { return Iterator(this, nullptr); } |
| 351 Iterator find(Key* key, bool insert = false, | 367 Iterator find(Key* key, bool insert = false, |
| 352 AllocationPolicy allocator = AllocationPolicy()) { | 368 AllocationPolicy allocator = AllocationPolicy()) { |
| 353 if (insert) { | 369 if (insert) { |
| 354 return Iterator(this, this->LookupOrInsert(key, key->Hash(), allocator)); | 370 return Iterator(this, this->LookupOrInsert(key, key->Hash(), allocator)); |
| 355 } | 371 } |
| 356 return Iterator(this, this->Lookup(key, key->Hash())); | 372 return Iterator(this, this->Lookup(key, key->Hash())); |
| 357 } | 373 } |
| 358 }; | 374 }; |
| 359 | 375 |
| 360 } // namespace base | 376 } // namespace base |
| 361 } // namespace v8 | 377 } // namespace v8 |
| 362 | 378 |
| 363 #endif // V8_BASE_HASHMAP_H_ | 379 #endif // V8_BASE_HASHMAP_H_ |
| OLD | NEW |