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 #ifndef V8_HASHMAP_H_ | 5 // This file is ported from src/hashmap.h |
|
Yang
2016/05/25 08:29:39
I wonder whether it makes sense to move src/hashma
| |
| 6 #define V8_HASHMAP_H_ | |
| 7 | 6 |
| 8 #include "src/allocation.h" | 7 #ifndef V8_LIBSAMPLER_HASHMAP_H_ |
| 8 #define V8_LIBSAMPLER_HASHMAP_H_ | |
| 9 | |
| 9 #include "src/base/bits.h" | 10 #include "src/base/bits.h" |
| 10 #include "src/base/logging.h" | 11 #include "src/base/logging.h" |
| 11 #include "src/utils.h" | 12 #include "src/libsampler/utils.h" |
| 12 | 13 |
| 13 namespace v8 { | 14 namespace v8 { |
| 14 namespace internal { | 15 namespace sampler { |
| 15 | 16 |
| 16 template<class AllocationPolicy> | 17 class HashMapImpl { |
| 17 class TemplateHashMapImpl { | |
| 18 public: | 18 public: |
| 19 typedef bool (*MatchFun) (void* key1, void* key2); | 19 typedef bool (*MatchFun) (void* key1, void* key2); |
| 20 | 20 |
| 21 // The default capacity. This is used by the call sites which want | 21 // The default capacity. |
| 22 // to pass in a non-default AllocationPolicy but want to use the | |
| 23 // default value of capacity specified by the implementation. | |
| 24 static const uint32_t kDefaultHashMapCapacity = 8; | 22 static const uint32_t kDefaultHashMapCapacity = 8; |
| 25 | 23 |
| 26 // initial_capacity is the size of the initial hash map; | 24 // initial_capacity is the size of the initial hash map; |
| 27 // it must be a power of 2 (and thus must not be 0). | 25 // it must be a power of 2 (and thus must not be 0). |
| 28 TemplateHashMapImpl(MatchFun match, | 26 HashMapImpl(MatchFun match, |
| 29 uint32_t capacity = kDefaultHashMapCapacity, | 27 uint32_t capacity = kDefaultHashMapCapacity); |
| 30 AllocationPolicy allocator = AllocationPolicy()); | |
| 31 | 28 |
| 32 ~TemplateHashMapImpl(); | 29 ~HashMapImpl(); |
| 33 | 30 |
| 34 // HashMap entries are (key, value, hash) triplets. | 31 // HashMap entries are (key, value, hash) triplets. |
| 35 // Some clients may not need to use the value slot | 32 // Some clients may not need to use the value slot |
| 36 // (e.g. implementers of sets, where the key is the value). | 33 // (e.g. implementers of sets, where the key is the value). |
| 37 struct Entry { | 34 struct Entry { |
| 38 void* key; | 35 void* key; |
| 39 void* value; | 36 void* value; |
| 40 uint32_t hash; // The full hash value for key | 37 uint32_t hash; // The full hash value for key |
| 41 int order; // If you never remove entries this is the insertion order. | 38 int order; // If you never remove entries this is the insertion order. |
| 42 }; | 39 }; |
| 43 | 40 |
| 44 // If an entry with matching key is found, returns that entry. | 41 // If an entry with matching key is found, returns that entry. |
| 45 // Otherwise, NULL is returned. | 42 // Otherwise, NULL is returned. |
| 46 Entry* Lookup(void* key, uint32_t hash) const; | 43 Entry* Lookup(void* key, uint32_t hash) const; |
| 47 | 44 |
| 48 // If an entry with matching key is found, returns that entry. | 45 // If an entry with matching key is found, returns that entry. |
| 49 // If no matching entry is found, a new entry is inserted with | 46 // If no matching entry is found, a new entry is inserted with |
| 50 // corresponding key, key hash, and NULL value. | 47 // corresponding key, key hash, and NULL value. |
| 51 Entry* LookupOrInsert(void* key, uint32_t hash, | 48 Entry* LookupOrInsert(void* key, uint32_t hash); |
| 52 AllocationPolicy allocator = AllocationPolicy()); | |
| 53 | 49 |
| 54 // Removes the entry with matching key. | 50 // Removes the entry with matching key. |
| 55 // It returns the value of the deleted entry | 51 // It returns the value of the deleted entry |
| 56 // or null if there is no value for such key. | 52 // or null if there is no value for such key. |
| 57 void* Remove(void* key, uint32_t hash); | 53 void* Remove(void* key, uint32_t hash); |
| 58 | 54 |
| 59 // Empties the hash map (occupancy() == 0). | 55 // Empties the hash map (occupancy() == 0). |
| 60 void Clear(); | 56 void Clear(); |
| 61 | 57 |
| 62 // The number of (non-empty) entries in the table. | 58 // The number of (non-empty) entries in the table. |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 84 } | 80 } |
| 85 | 81 |
| 86 private: | 82 private: |
| 87 MatchFun match_; | 83 MatchFun match_; |
| 88 Entry* map_; | 84 Entry* map_; |
| 89 uint32_t capacity_; | 85 uint32_t capacity_; |
| 90 uint32_t occupancy_; | 86 uint32_t occupancy_; |
| 91 | 87 |
| 92 Entry* map_end() const { return map_ + capacity_; } | 88 Entry* map_end() const { return map_ + capacity_; } |
| 93 Entry* Probe(void* key, uint32_t hash) const; | 89 Entry* Probe(void* key, uint32_t hash) const; |
| 94 void Initialize(uint32_t capacity, AllocationPolicy allocator); | 90 void Initialize(uint32_t capacity); |
| 95 void Resize(AllocationPolicy allocator); | 91 void Resize(); |
| 96 }; | 92 }; |
| 97 | 93 |
| 98 typedef TemplateHashMapImpl<FreeStoreAllocationPolicy> HashMap; | 94 typedef HashMapImpl HashMap; |
| 99 | 95 |
| 100 template<class AllocationPolicy> | 96 HashMapImpl::HashMapImpl(MatchFun match, uint32_t initial_capacity) { |
| 101 TemplateHashMapImpl<AllocationPolicy>::TemplateHashMapImpl( | |
| 102 MatchFun match, uint32_t initial_capacity, AllocationPolicy allocator) { | |
| 103 match_ = match; | 97 match_ = match; |
| 104 Initialize(initial_capacity, allocator); | 98 Initialize(initial_capacity); |
| 105 } | 99 } |
| 106 | 100 |
| 107 | 101 |
| 108 template<class AllocationPolicy> | 102 HashMapImpl::~HashMapImpl() { |
| 109 TemplateHashMapImpl<AllocationPolicy>::~TemplateHashMapImpl() { | 103 Malloced::Delete(map_); |
| 110 AllocationPolicy::Delete(map_); | |
| 111 } | 104 } |
| 112 | 105 |
| 113 | 106 |
| 114 template <class AllocationPolicy> | 107 HashMapImpl::Entry* HashMapImpl::Lookup(void* key, uint32_t hash) const { |
| 115 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | |
| 116 TemplateHashMapImpl<AllocationPolicy>::Lookup(void* key, uint32_t hash) const { | |
| 117 Entry* p = Probe(key, hash); | 108 Entry* p = Probe(key, hash); |
| 118 return p->key != NULL ? p : NULL; | 109 return p->key != NULL ? p : NULL; |
| 119 } | 110 } |
| 120 | 111 |
| 121 | 112 |
| 122 template <class AllocationPolicy> | 113 HashMapImpl::Entry* HashMapImpl::LookupOrInsert(void* key, uint32_t hash) { |
| 123 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | |
| 124 TemplateHashMapImpl<AllocationPolicy>::LookupOrInsert( | |
| 125 void* key, uint32_t hash, AllocationPolicy allocator) { | |
| 126 // Find a matching entry. | 114 // Find a matching entry. |
| 127 Entry* p = Probe(key, hash); | 115 Entry* p = Probe(key, hash); |
| 128 if (p->key != NULL) { | 116 if (p->key != NULL) { |
| 129 return p; | 117 return p; |
| 130 } | 118 } |
| 131 | 119 |
| 132 // No entry found; insert one. | 120 // No entry found; insert one. |
| 133 p->key = key; | 121 p->key = key; |
| 134 p->value = NULL; | 122 p->value = NULL; |
| 135 p->hash = hash; | 123 p->hash = hash; |
| 136 p->order = occupancy_; | 124 p->order = occupancy_; |
| 137 occupancy_++; | 125 occupancy_++; |
| 138 | 126 |
| 139 // Grow the map if we reached >= 80% occupancy. | 127 // Grow the map if we reached >= 80% occupancy. |
| 140 if (occupancy_ + occupancy_ / 4 >= capacity_) { | 128 if (occupancy_ + occupancy_ / 4 >= capacity_) { |
| 141 Resize(allocator); | 129 Resize(); |
| 142 p = Probe(key, hash); | 130 p = Probe(key, hash); |
| 143 } | 131 } |
| 144 | 132 |
| 145 return p; | 133 return p; |
| 146 } | 134 } |
| 147 | 135 |
| 148 | 136 |
| 149 template<class AllocationPolicy> | 137 void* HashMapImpl::Remove(void* key, uint32_t hash) { |
| 150 void* TemplateHashMapImpl<AllocationPolicy>::Remove(void* key, uint32_t hash) { | |
| 151 // Lookup the entry for the key to remove. | 138 // Lookup the entry for the key to remove. |
| 152 Entry* p = Probe(key, hash); | 139 Entry* p = Probe(key, hash); |
| 153 if (p->key == NULL) { | 140 if (p->key == NULL) { |
| 154 // Key not found nothing to remove. | 141 // Key not found nothing to remove. |
| 155 return NULL; | 142 return NULL; |
| 156 } | 143 } |
| 157 | 144 |
| 158 void* value = p->value; | 145 void* value = p->value; |
| 159 // To remove an entry we need to ensure that it does not create an empty | 146 // To remove an entry we need to ensure that it does not create an empty |
| 160 // entry that will cause the search for another entry to stop too soon. If all | 147 // 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... | |
| 201 } | 188 } |
| 202 } | 189 } |
| 203 | 190 |
| 204 // Clear the entry which is allowed to en emptied. | 191 // Clear the entry which is allowed to en emptied. |
| 205 p->key = NULL; | 192 p->key = NULL; |
| 206 occupancy_--; | 193 occupancy_--; |
| 207 return value; | 194 return value; |
| 208 } | 195 } |
| 209 | 196 |
| 210 | 197 |
| 211 template<class AllocationPolicy> | 198 void HashMapImpl::Clear() { |
| 212 void TemplateHashMapImpl<AllocationPolicy>::Clear() { | |
| 213 // Mark all entries as empty. | 199 // Mark all entries as empty. |
| 214 const Entry* end = map_end(); | 200 const Entry* end = map_end(); |
| 215 for (Entry* p = map_; p < end; p++) { | 201 for (Entry* p = map_; p < end; p++) { |
| 216 p->key = NULL; | 202 p->key = NULL; |
| 217 } | 203 } |
| 218 occupancy_ = 0; | 204 occupancy_ = 0; |
| 219 } | 205 } |
| 220 | 206 |
| 221 | 207 |
| 222 template<class AllocationPolicy> | 208 HashMapImpl::Entry* HashMapImpl::Start() const { |
| 223 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | |
| 224 TemplateHashMapImpl<AllocationPolicy>::Start() const { | |
| 225 return Next(map_ - 1); | 209 return Next(map_ - 1); |
| 226 } | 210 } |
| 227 | 211 |
| 228 | 212 |
| 229 template<class AllocationPolicy> | 213 HashMapImpl::Entry* HashMapImpl::Next(Entry* p) const { |
| 230 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | |
| 231 TemplateHashMapImpl<AllocationPolicy>::Next(Entry* p) const { | |
| 232 const Entry* end = map_end(); | 214 const Entry* end = map_end(); |
| 233 DCHECK(map_ - 1 <= p && p < end); | 215 DCHECK(map_ - 1 <= p && p < end); |
| 234 for (p++; p < end; p++) { | 216 for (p++; p < end; p++) { |
| 235 if (p->key != NULL) { | 217 if (p->key != NULL) { |
| 236 return p; | 218 return p; |
| 237 } | 219 } |
| 238 } | 220 } |
| 239 return NULL; | 221 return NULL; |
| 240 } | 222 } |
| 241 | 223 |
| 242 | 224 |
| 243 template <class AllocationPolicy> | 225 HashMapImpl::Entry* HashMapImpl::Probe(void* key, uint32_t hash) const { |
| 244 typename TemplateHashMapImpl<AllocationPolicy>::Entry* | |
| 245 TemplateHashMapImpl<AllocationPolicy>::Probe(void* key, uint32_t hash) const { | |
| 246 DCHECK(key != NULL); | 226 DCHECK(key != NULL); |
| 247 | 227 |
| 248 DCHECK(base::bits::IsPowerOfTwo32(capacity_)); | 228 DCHECK(base::bits::IsPowerOfTwo32(capacity_)); |
| 249 Entry* p = map_ + (hash & (capacity_ - 1)); | 229 Entry* p = map_ + (hash & (capacity_ - 1)); |
| 250 const Entry* end = map_end(); | 230 const Entry* end = map_end(); |
| 251 DCHECK(map_ <= p && p < end); | 231 DCHECK(map_ <= p && p < end); |
| 252 | 232 |
| 253 DCHECK(occupancy_ < capacity_); // Guarantees loop termination. | 233 DCHECK(occupancy_ < capacity_); // Guarantees loop termination. |
| 254 while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) { | 234 while (p->key != NULL && (hash != p->hash || !match_(key, p->key))) { |
| 255 p++; | 235 p++; |
| 256 if (p >= end) { | 236 if (p >= end) { |
| 257 p = map_; | 237 p = map_; |
| 258 } | 238 } |
| 259 } | 239 } |
| 260 | 240 |
| 261 return p; | 241 return p; |
| 262 } | 242 } |
| 263 | 243 |
| 264 | 244 |
| 265 template<class AllocationPolicy> | 245 void HashMapImpl::Initialize(uint32_t capacity) { |
| 266 void TemplateHashMapImpl<AllocationPolicy>::Initialize( | |
| 267 uint32_t capacity, AllocationPolicy allocator) { | |
| 268 DCHECK(base::bits::IsPowerOfTwo32(capacity)); | 246 DCHECK(base::bits::IsPowerOfTwo32(capacity)); |
| 269 map_ = reinterpret_cast<Entry*>(allocator.New(capacity * sizeof(Entry))); | 247 map_ = reinterpret_cast<Entry*>(Malloced::New(capacity * sizeof(Entry))); |
| 270 if (map_ == NULL) { | 248 CHECK(map_ != NULL); |
| 271 v8::internal::FatalProcessOutOfMemory("HashMap::Initialize"); | |
| 272 return; | |
| 273 } | |
| 274 capacity_ = capacity; | 249 capacity_ = capacity; |
| 275 Clear(); | 250 Clear(); |
| 276 } | 251 } |
| 277 | 252 |
| 278 | 253 |
| 279 template<class AllocationPolicy> | 254 void HashMapImpl::Resize() { |
| 280 void TemplateHashMapImpl<AllocationPolicy>::Resize(AllocationPolicy allocator) { | |
| 281 Entry* map = map_; | 255 Entry* map = map_; |
| 282 uint32_t n = occupancy_; | 256 uint32_t n = occupancy_; |
| 283 | 257 |
| 284 // Allocate larger map. | 258 // Allocate larger map. |
| 285 Initialize(capacity_ * 2, allocator); | 259 Initialize(capacity_ * 2); |
| 286 | 260 |
| 287 // Rehash all current entries. | 261 // Rehash all current entries. |
| 288 for (Entry* p = map; n > 0; p++) { | 262 for (Entry* p = map; n > 0; p++) { |
| 289 if (p->key != NULL) { | 263 if (p->key != NULL) { |
| 290 Entry* entry = LookupOrInsert(p->key, p->hash, allocator); | 264 Entry* entry = LookupOrInsert(p->key, p->hash); |
| 291 entry->value = p->value; | 265 entry->value = p->value; |
| 292 entry->order = p->order; | 266 entry->order = p->order; |
| 293 n--; | 267 n--; |
| 294 } | 268 } |
| 295 } | 269 } |
| 296 | 270 |
| 297 // Delete old map. | 271 // Delete old map. |
| 298 AllocationPolicy::Delete(map); | 272 Malloced::Delete(map); |
| 299 } | 273 } |
| 300 | 274 |
| 301 | 275 } // namespace sampler |
| 302 // A hash map for pointer keys and values with an STL-like interface. | |
| 303 template<class Key, class Value, class AllocationPolicy> | |
| 304 class TemplateHashMap: private TemplateHashMapImpl<AllocationPolicy> { | |
| 305 public: | |
| 306 STATIC_ASSERT(sizeof(Key*) == sizeof(void*)); // NOLINT | |
| 307 STATIC_ASSERT(sizeof(Value*) == sizeof(void*)); // NOLINT | |
| 308 struct value_type { | |
| 309 Key* first; | |
| 310 Value* second; | |
| 311 }; | |
| 312 | |
| 313 class Iterator { | |
| 314 public: | |
| 315 Iterator& operator++() { | |
| 316 entry_ = map_->Next(entry_); | |
| 317 return *this; | |
| 318 } | |
| 319 | |
| 320 value_type* operator->() { return reinterpret_cast<value_type*>(entry_); } | |
| 321 bool operator!=(const Iterator& other) { return entry_ != other.entry_; } | |
| 322 | |
| 323 private: | |
| 324 Iterator(const TemplateHashMapImpl<AllocationPolicy>* map, | |
| 325 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry) : | |
| 326 map_(map), entry_(entry) { } | |
| 327 | |
| 328 const TemplateHashMapImpl<AllocationPolicy>* map_; | |
| 329 typename TemplateHashMapImpl<AllocationPolicy>::Entry* entry_; | |
| 330 | |
| 331 friend class TemplateHashMap; | |
| 332 }; | |
| 333 | |
| 334 TemplateHashMap( | |
| 335 typename TemplateHashMapImpl<AllocationPolicy>::MatchFun match, | |
| 336 AllocationPolicy allocator = AllocationPolicy()) | |
| 337 : TemplateHashMapImpl<AllocationPolicy>( | |
| 338 match, | |
| 339 TemplateHashMapImpl<AllocationPolicy>::kDefaultHashMapCapacity, | |
| 340 allocator) { } | |
| 341 | |
| 342 Iterator begin() const { return Iterator(this, this->Start()); } | |
| 343 Iterator end() const { return Iterator(this, NULL); } | |
| 344 Iterator find(Key* key, bool insert = false, | |
| 345 AllocationPolicy allocator = AllocationPolicy()) { | |
| 346 if (insert) { | |
| 347 return Iterator(this, this->LookupOrInsert(key, key->Hash(), allocator)); | |
| 348 } | |
| 349 return Iterator(this, this->Lookup(key, key->Hash())); | |
| 350 } | |
| 351 }; | |
| 352 | |
| 353 } // namespace internal | |
| 354 } // namespace v8 | 276 } // namespace v8 |
| 355 | 277 |
| 356 #endif // V8_HASHMAP_H_ | 278 #endif // V8_LIBSAMPLER_HASHMAP_H_ |
| OLD | NEW |