| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef RUNTIME_VM_HASH_MAP_H_ | 5 #ifndef RUNTIME_VM_HASH_MAP_H_ |
| 6 #define RUNTIME_VM_HASH_MAP_H_ | 6 #define RUNTIME_VM_HASH_MAP_H_ |
| 7 | 7 |
| 8 #include "vm/growable_array.h" // For Malloc, EmptyBase | 8 #include "vm/growable_array.h" // For Malloc, EmptyBase |
| 9 #include "vm/zone.h" | 9 #include "vm/zone.h" |
| 10 | 10 |
| 11 namespace dart { | 11 namespace dart { |
| 12 | 12 |
| 13 template<typename KeyValueTrait, typename B, typename Allocator = Zone> | 13 template <typename KeyValueTrait, typename B, typename Allocator = Zone> |
| 14 class BaseDirectChainedHashMap : public B { | 14 class BaseDirectChainedHashMap : public B { |
| 15 public: | 15 public: |
| 16 explicit BaseDirectChainedHashMap(Allocator* allocator) | 16 explicit BaseDirectChainedHashMap(Allocator* allocator) |
| 17 : array_size_(0), | 17 : array_size_(0), |
| 18 lists_size_(0), | 18 lists_size_(0), |
| 19 count_(0), | 19 count_(0), |
| 20 array_(NULL), | 20 array_(NULL), |
| 21 lists_(NULL), | 21 lists_(NULL), |
| 22 free_list_head_(kNil), | 22 free_list_head_(kNil), |
| 23 allocator_(allocator) { | 23 allocator_(allocator) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 } | 64 } |
| 65 | 65 |
| 66 private: | 66 private: |
| 67 explicit Iterator(const BaseDirectChainedHashMap& map) | 67 explicit Iterator(const BaseDirectChainedHashMap& map) |
| 68 : map_(map), array_index_(0), list_index_(kNil) {} | 68 : map_(map), array_index_(0), list_index_(kNil) {} |
| 69 | 69 |
| 70 const BaseDirectChainedHashMap& map_; | 70 const BaseDirectChainedHashMap& map_; |
| 71 intptr_t array_index_; | 71 intptr_t array_index_; |
| 72 intptr_t list_index_; | 72 intptr_t list_index_; |
| 73 | 73 |
| 74 template<typename T, typename Bs, typename A> | 74 template <typename T, typename Bs, typename A> |
| 75 friend class BaseDirectChainedHashMap; | 75 friend class BaseDirectChainedHashMap; |
| 76 }; | 76 }; |
| 77 | 77 |
| 78 Iterator GetIterator() const { return Iterator(*this); } | 78 Iterator GetIterator() const { return Iterator(*this); } |
| 79 | 79 |
| 80 protected: | 80 protected: |
| 81 // A linked list of T values. Stored in arrays. | 81 // A linked list of T values. Stored in arrays. |
| 82 struct HashMapListElement { | 82 struct HashMapListElement { |
| 83 HashMapListElement() : kv(), next(kNil) { } | 83 HashMapListElement() : kv(), next(kNil) {} |
| 84 typename KeyValueTrait::Pair kv; | 84 typename KeyValueTrait::Pair kv; |
| 85 intptr_t next; // Index in the array of the next list element. | 85 intptr_t next; // Index in the array of the next list element. |
| 86 }; | 86 }; |
| 87 static const intptr_t kNil = -1; // The end of a linked list | 87 static const intptr_t kNil = -1; // The end of a linked list |
| 88 | 88 |
| 89 static void InitArray(HashMapListElement* array, intptr_t size) { | 89 static void InitArray(HashMapListElement* array, intptr_t size) { |
| 90 for (intptr_t i = 0; i < size; ++i) { | 90 for (intptr_t i = 0; i < size; ++i) { |
| 91 array[i] = HashMapListElement(); | 91 array[i] = HashMapListElement(); |
| 92 } | 92 } |
| 93 } | 93 } |
| 94 | 94 |
| 95 // Must be a power of 2. | 95 // Must be a power of 2. |
| 96 static const intptr_t kInitialSize = 16; | 96 static const intptr_t kInitialSize = 16; |
| 97 | 97 |
| 98 void Resize(intptr_t new_size); | 98 void Resize(intptr_t new_size); |
| 99 void ResizeLists(intptr_t new_size); | 99 void ResizeLists(intptr_t new_size); |
| 100 uword Bound(uword value) const { return value & (array_size_ - 1); } | 100 uword Bound(uword value) const { return value & (array_size_ - 1); } |
| 101 | 101 |
| 102 intptr_t array_size_; | 102 intptr_t array_size_; |
| 103 intptr_t lists_size_; | 103 intptr_t lists_size_; |
| 104 intptr_t count_; // The number of values stored in the HashMap. | 104 intptr_t count_; // The number of values stored in the HashMap. |
| 105 HashMapListElement* array_; // Primary store - contains the first value | 105 HashMapListElement* array_; // Primary store - contains the first value |
| 106 // with a given hash. Colliding elements are stored in linked lists. | 106 // with a given hash. Colliding elements are stored in linked lists. |
| 107 HashMapListElement* lists_; // The linked lists containing hash collisions. | 107 HashMapListElement* lists_; // The linked lists containing hash collisions. |
| 108 intptr_t free_list_head_; // Unused elements in lists_ are on the free list. | 108 intptr_t free_list_head_; // Unused elements in lists_ are on the free list. |
| 109 Allocator* allocator_; | 109 Allocator* allocator_; |
| 110 }; | 110 }; |
| 111 | 111 |
| 112 | 112 |
| 113 template<typename KeyValueTrait, typename B, typename Allocator> | 113 template <typename KeyValueTrait, typename B, typename Allocator> |
| 114 BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>:: | 114 BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::BaseDirectChainedHashMap( |
| 115 BaseDirectChainedHashMap(const BaseDirectChainedHashMap& other) | 115 const BaseDirectChainedHashMap& other) |
| 116 : B(), | 116 : B(), |
| 117 array_size_(other.array_size_), | 117 array_size_(other.array_size_), |
| 118 lists_size_(other.lists_size_), | 118 lists_size_(other.lists_size_), |
| 119 count_(other.count_), | 119 count_(other.count_), |
| 120 array_(other.allocator_->template Alloc<HashMapListElement>( | 120 array_(other.allocator_->template Alloc<HashMapListElement>( |
| 121 other.array_size_)), | 121 other.array_size_)), |
| 122 lists_(other.allocator_->template Alloc<HashMapListElement>( | 122 lists_(other.allocator_->template Alloc<HashMapListElement>( |
| 123 other.lists_size_)), | 123 other.lists_size_)), |
| 124 free_list_head_(other.free_list_head_), | 124 free_list_head_(other.free_list_head_), |
| 125 allocator_(other.allocator_) { | 125 allocator_(other.allocator_) { |
| 126 memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement)); | 126 memmove(array_, other.array_, array_size_ * sizeof(HashMapListElement)); |
| 127 memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement)); | 127 memmove(lists_, other.lists_, lists_size_ * sizeof(HashMapListElement)); |
| 128 } | 128 } |
| 129 | 129 |
| 130 | 130 |
| 131 template<typename KeyValueTrait, typename B, typename Allocator> | 131 template <typename KeyValueTrait, typename B, typename Allocator> |
| 132 typename KeyValueTrait::Pair* | 132 typename KeyValueTrait::Pair* |
| 133 BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>:: | 133 BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Lookup( |
| 134 Lookup(typename KeyValueTrait::Key key) const { | 134 typename KeyValueTrait::Key key) const { |
| 135 const typename KeyValueTrait::Value kNoValue = | 135 const typename KeyValueTrait::Value kNoValue = |
| 136 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); | 136 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); |
| 137 | 137 |
| 138 uword hash = static_cast<uword>(KeyValueTrait::Hashcode(key)); | 138 uword hash = static_cast<uword>(KeyValueTrait::Hashcode(key)); |
| 139 uword pos = Bound(hash); | 139 uword pos = Bound(hash); |
| 140 if (KeyValueTrait::ValueOf(array_[pos].kv) != kNoValue) { | 140 if (KeyValueTrait::ValueOf(array_[pos].kv) != kNoValue) { |
| 141 if (KeyValueTrait::IsKeyEqual(array_[pos].kv, key)) { | 141 if (KeyValueTrait::IsKeyEqual(array_[pos].kv, key)) { |
| 142 return &array_[pos].kv; | 142 return &array_[pos].kv; |
| 143 } | 143 } |
| 144 | 144 |
| 145 intptr_t next = array_[pos].next; | 145 intptr_t next = array_[pos].next; |
| 146 while (next != kNil) { | 146 while (next != kNil) { |
| 147 if (KeyValueTrait::IsKeyEqual(lists_[next].kv, key)) { | 147 if (KeyValueTrait::IsKeyEqual(lists_[next].kv, key)) { |
| 148 return &lists_[next].kv; | 148 return &lists_[next].kv; |
| 149 } | 149 } |
| 150 next = lists_[next].next; | 150 next = lists_[next].next; |
| 151 } | 151 } |
| 152 } | 152 } |
| 153 return NULL; | 153 return NULL; |
| 154 } | 154 } |
| 155 | 155 |
| 156 | 156 |
| 157 template<typename KeyValueTrait, typename B, typename Allocator> | 157 template <typename KeyValueTrait, typename B, typename Allocator> |
| 158 typename KeyValueTrait::Value | 158 typename KeyValueTrait::Value |
| 159 BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>:: | 159 BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::LookupValue( |
| 160 LookupValue(typename KeyValueTrait::Key key) const { | 160 typename KeyValueTrait::Key key) const { |
| 161 const typename KeyValueTrait::Value kNoValue = | 161 const typename KeyValueTrait::Value kNoValue = |
| 162 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); | 162 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); |
| 163 typename KeyValueTrait::Pair* pair = Lookup(key); | 163 typename KeyValueTrait::Pair* pair = Lookup(key); |
| 164 return (pair == NULL) ? kNoValue : KeyValueTrait::ValueOf(*pair); | 164 return (pair == NULL) ? kNoValue : KeyValueTrait::ValueOf(*pair); |
| 165 } | 165 } |
| 166 | 166 |
| 167 | 167 |
| 168 template<typename KeyValueTrait, typename B, typename Allocator> | 168 template <typename KeyValueTrait, typename B, typename Allocator> |
| 169 typename KeyValueTrait::Pair* | 169 typename KeyValueTrait::Pair* |
| 170 BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Iterator::Next() { | 170 BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Iterator::Next() { |
| 171 const typename KeyValueTrait::Value kNoValue = | 171 const typename KeyValueTrait::Value kNoValue = |
| 172 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); | 172 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); |
| 173 | 173 |
| 174 if (array_index_ < map_.array_size_) { | 174 if (array_index_ < map_.array_size_) { |
| 175 // If we're not in the middle of a list, find the next array slot. | 175 // If we're not in the middle of a list, find the next array slot. |
| 176 if (list_index_ == kNil) { | 176 if (list_index_ == kNil) { |
| 177 while (KeyValueTrait::ValueOf(map_.array_[array_index_].kv) == kNoValue && | 177 while (KeyValueTrait::ValueOf(map_.array_[array_index_].kv) == kNoValue && |
| 178 array_index_ < map_.array_size_) { | 178 array_index_ < map_.array_size_) { |
| 179 array_index_++; | 179 array_index_++; |
| 180 } | 180 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 193 // Otherwise, return the current lists_ entry, advancing list_index_. | 193 // Otherwise, return the current lists_ entry, advancing list_index_. |
| 194 intptr_t current = list_index_; | 194 intptr_t current = list_index_; |
| 195 list_index_ = map_.lists_[current].next; | 195 list_index_ = map_.lists_[current].next; |
| 196 return &map_.lists_[current].kv; | 196 return &map_.lists_[current].kv; |
| 197 } | 197 } |
| 198 | 198 |
| 199 return NULL; | 199 return NULL; |
| 200 } | 200 } |
| 201 | 201 |
| 202 | 202 |
| 203 template<typename KeyValueTrait, typename B, typename Allocator> | 203 template <typename KeyValueTrait, typename B, typename Allocator> |
| 204 void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Resize( | 204 void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Resize( |
| 205 intptr_t new_size) { | 205 intptr_t new_size) { |
| 206 const typename KeyValueTrait::Value kNoValue = | 206 const typename KeyValueTrait::Value kNoValue = |
| 207 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); | 207 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); |
| 208 | 208 |
| 209 ASSERT(new_size > count_); | 209 ASSERT(new_size > count_); |
| 210 // Hashing the values into the new array has no more collisions than in the | 210 // Hashing the values into the new array has no more collisions than in the |
| 211 // old hash map, so we can use the existing lists_ array, if we are careful. | 211 // old hash map, so we can use the existing lists_ array, if we are careful. |
| 212 | 212 |
| 213 // Make sure we have at least one free element. | 213 // Make sure we have at least one free element. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 243 Insert(old_array[i].kv); | 243 Insert(old_array[i].kv); |
| 244 } | 244 } |
| 245 } | 245 } |
| 246 } | 246 } |
| 247 USE(old_count); | 247 USE(old_count); |
| 248 ASSERT(count_ == old_count); | 248 ASSERT(count_ == old_count); |
| 249 allocator_->template Free<HashMapListElement>(old_array, old_size); | 249 allocator_->template Free<HashMapListElement>(old_array, old_size); |
| 250 } | 250 } |
| 251 | 251 |
| 252 | 252 |
| 253 template<typename KeyValueTrait, typename B, typename Allocator> | 253 template <typename KeyValueTrait, typename B, typename Allocator> |
| 254 void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::ResizeLists( | 254 void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::ResizeLists( |
| 255 intptr_t new_size) { | 255 intptr_t new_size) { |
| 256 ASSERT(new_size > lists_size_); | 256 ASSERT(new_size > lists_size_); |
| 257 | 257 |
| 258 HashMapListElement* new_lists = | 258 HashMapListElement* new_lists = |
| 259 allocator_->template Alloc<HashMapListElement>(new_size); | 259 allocator_->template Alloc<HashMapListElement>(new_size); |
| 260 InitArray(new_lists, new_size); | 260 InitArray(new_lists, new_size); |
| 261 | 261 |
| 262 HashMapListElement* old_lists = lists_; | 262 HashMapListElement* old_lists = lists_; |
| 263 intptr_t old_size = lists_size_; | 263 intptr_t old_size = lists_size_; |
| 264 | 264 |
| 265 lists_size_ = new_size; | 265 lists_size_ = new_size; |
| 266 lists_ = new_lists; | 266 lists_ = new_lists; |
| 267 | 267 |
| 268 if (old_lists != NULL) { | 268 if (old_lists != NULL) { |
| 269 memmove(lists_, old_lists, old_size * sizeof(HashMapListElement)); | 269 memmove(lists_, old_lists, old_size * sizeof(HashMapListElement)); |
| 270 } | 270 } |
| 271 for (intptr_t i = old_size; i < lists_size_; ++i) { | 271 for (intptr_t i = old_size; i < lists_size_; ++i) { |
| 272 lists_[i].next = free_list_head_; | 272 lists_[i].next = free_list_head_; |
| 273 free_list_head_ = i; | 273 free_list_head_ = i; |
| 274 } | 274 } |
| 275 allocator_->template Free<HashMapListElement>(old_lists, old_size); | 275 allocator_->template Free<HashMapListElement>(old_lists, old_size); |
| 276 } | 276 } |
| 277 | 277 |
| 278 | 278 |
| 279 template<typename KeyValueTrait, typename B, typename Allocator> | 279 template <typename KeyValueTrait, typename B, typename Allocator> |
| 280 void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>:: | 280 void BaseDirectChainedHashMap<KeyValueTrait, B, Allocator>::Insert( |
| 281 Insert(typename KeyValueTrait::Pair kv) { | 281 typename KeyValueTrait::Pair kv) { |
| 282 const typename KeyValueTrait::Value kNoValue = | 282 const typename KeyValueTrait::Value kNoValue = |
| 283 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); | 283 KeyValueTrait::ValueOf(typename KeyValueTrait::Pair()); |
| 284 | 284 |
| 285 ASSERT(KeyValueTrait::ValueOf(kv) != kNoValue); | 285 ASSERT(KeyValueTrait::ValueOf(kv) != kNoValue); |
| 286 // Resizing when half of the hashtable is filled up. | 286 // Resizing when half of the hashtable is filled up. |
| 287 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1); | 287 if (count_ >= array_size_ >> 1) Resize(array_size_ << 1); |
| 288 ASSERT(count_ < array_size_); | 288 ASSERT(count_ < array_size_); |
| 289 count_++; | 289 count_++; |
| 290 uword pos = Bound( | 290 uword pos = Bound( |
| 291 static_cast<uword>(KeyValueTrait::Hashcode(KeyValueTrait::KeyOf(kv)))); | 291 static_cast<uword>(KeyValueTrait::Hashcode(KeyValueTrait::KeyOf(kv)))); |
| 292 if (KeyValueTrait::ValueOf(array_[pos].kv) == kNoValue) { | 292 if (KeyValueTrait::ValueOf(array_[pos].kv) == kNoValue) { |
| 293 array_[pos].kv = kv; | 293 array_[pos].kv = kv; |
| 294 array_[pos].next = kNil; | 294 array_[pos].next = kNil; |
| 295 } else { | 295 } else { |
| 296 if (free_list_head_ == kNil) { | 296 if (free_list_head_ == kNil) { |
| 297 ResizeLists(lists_size_ << 1); | 297 ResizeLists(lists_size_ << 1); |
| 298 } | 298 } |
| 299 intptr_t new_element_pos = free_list_head_; | 299 intptr_t new_element_pos = free_list_head_; |
| 300 ASSERT(new_element_pos != kNil); | 300 ASSERT(new_element_pos != kNil); |
| 301 free_list_head_ = lists_[free_list_head_].next; | 301 free_list_head_ = lists_[free_list_head_].next; |
| 302 lists_[new_element_pos].kv = kv; | 302 lists_[new_element_pos].kv = kv; |
| 303 lists_[new_element_pos].next = array_[pos].next; | 303 lists_[new_element_pos].next = array_[pos].next; |
| 304 ASSERT(array_[pos].next == kNil || | 304 ASSERT(array_[pos].next == kNil || |
| 305 KeyValueTrait::ValueOf(lists_[array_[pos].next].kv) != kNoValue); | 305 KeyValueTrait::ValueOf(lists_[array_[pos].next].kv) != kNoValue); |
| 306 array_[pos].next = new_element_pos; | 306 array_[pos].next = new_element_pos; |
| 307 } | 307 } |
| 308 } | 308 } |
| 309 | 309 |
| 310 | 310 |
| 311 template<typename KeyValueTrait> | 311 template <typename KeyValueTrait> |
| 312 class DirectChainedHashMap | 312 class DirectChainedHashMap |
| 313 : public BaseDirectChainedHashMap<KeyValueTrait, ValueObject> { | 313 : public BaseDirectChainedHashMap<KeyValueTrait, ValueObject> { |
| 314 public: | 314 public: |
| 315 DirectChainedHashMap() : BaseDirectChainedHashMap<KeyValueTrait, ValueObject>( | 315 DirectChainedHashMap() |
| 316 ASSERT_NOTNULL(Thread::Current()->zone())) {} | 316 : BaseDirectChainedHashMap<KeyValueTrait, ValueObject>( |
| 317 ASSERT_NOTNULL(Thread::Current()->zone())) {} |
| 317 }; | 318 }; |
| 318 | 319 |
| 319 | 320 |
| 320 template<typename KeyValueTrait> | 321 template <typename KeyValueTrait> |
| 321 class MallocDirectChainedHashMap | 322 class MallocDirectChainedHashMap |
| 322 : public BaseDirectChainedHashMap<KeyValueTrait, EmptyBase, Malloc> { | 323 : public BaseDirectChainedHashMap<KeyValueTrait, EmptyBase, Malloc> { |
| 323 public: | 324 public: |
| 324 MallocDirectChainedHashMap() | 325 MallocDirectChainedHashMap() |
| 325 : BaseDirectChainedHashMap<KeyValueTrait, EmptyBase, Malloc>(NULL) {} | 326 : BaseDirectChainedHashMap<KeyValueTrait, EmptyBase, Malloc>(NULL) {} |
| 326 }; | 327 }; |
| 327 | 328 |
| 328 | 329 |
| 329 template<typename T> | 330 template <typename T> |
| 330 class PointerKeyValueTrait { | 331 class PointerKeyValueTrait { |
| 331 public: | 332 public: |
| 332 typedef T* Value; | 333 typedef T* Value; |
| 333 typedef T* Key; | 334 typedef T* Key; |
| 334 typedef T* Pair; | 335 typedef T* Pair; |
| 335 | 336 |
| 336 static Key KeyOf(Pair kv) { | 337 static Key KeyOf(Pair kv) { return kv; } |
| 337 return kv; | |
| 338 } | |
| 339 | 338 |
| 340 static Value ValueOf(Pair kv) { | 339 static Value ValueOf(Pair kv) { return kv; } |
| 341 return kv; | |
| 342 } | |
| 343 | 340 |
| 344 static inline intptr_t Hashcode(Key key) { | 341 static inline intptr_t Hashcode(Key key) { return key->Hashcode(); } |
| 345 return key->Hashcode(); | |
| 346 } | |
| 347 | 342 |
| 348 static inline bool IsKeyEqual(Pair kv, Key key) { | 343 static inline bool IsKeyEqual(Pair kv, Key key) { return kv->Equals(key); } |
| 349 return kv->Equals(key); | |
| 350 } | |
| 351 }; | 344 }; |
| 352 | 345 |
| 353 | 346 |
| 354 template<typename T> | 347 template <typename T> |
| 355 class NumbersKeyValueTrait { | 348 class NumbersKeyValueTrait { |
| 356 public: | 349 public: |
| 357 typedef T Value; | 350 typedef T Value; |
| 358 typedef intptr_t Key; | 351 typedef intptr_t Key; |
| 359 typedef T Pair; | 352 typedef T Pair; |
| 360 | 353 |
| 361 static intptr_t KeyOf(Pair kv) { return kv.first(); } | 354 static intptr_t KeyOf(Pair kv) { return kv.first(); } |
| 362 static T ValueOf(Pair kv) { return kv; } | 355 static T ValueOf(Pair kv) { return kv; } |
| 363 static inline intptr_t Hashcode(Key key) { return key; } | 356 static inline intptr_t Hashcode(Key key) { return key; } |
| 364 static inline bool IsKeyEqual(Pair kv, Key key) { return kv.first() == key; } | 357 static inline bool IsKeyEqual(Pair kv, Key key) { return kv.first() == key; } |
| 365 }; | 358 }; |
| 366 | 359 |
| 367 | 360 |
| 368 template<typename K, typename V> | 361 template <typename K, typename V> |
| 369 class RawPointerKeyValueTrait { | 362 class RawPointerKeyValueTrait { |
| 370 public: | 363 public: |
| 371 typedef K* Key; | 364 typedef K* Key; |
| 372 typedef V Value; | 365 typedef V Value; |
| 373 | 366 |
| 374 struct Pair { | 367 struct Pair { |
| 375 Key key; | 368 Key key; |
| 376 Value value; | 369 Value value; |
| 377 Pair() : key(NULL), value() {} | 370 Pair() : key(NULL), value() {} |
| 378 Pair(const Key key, const Value& value) : key(key), value(value) {} | 371 Pair(const Key key, const Value& value) : key(key), value(value) {} |
| 379 Pair(const Pair& other) : key(other.key), value(other.value) {} | 372 Pair(const Pair& other) : key(other.key), value(other.value) {} |
| 380 }; | 373 }; |
| 381 | 374 |
| 382 static Key KeyOf(Pair kv) { return kv.key; } | 375 static Key KeyOf(Pair kv) { return kv.key; } |
| 383 static Value ValueOf(Pair kv) { return kv.value; } | 376 static Value ValueOf(Pair kv) { return kv.value; } |
| 384 static intptr_t Hashcode(Key key) { return reinterpret_cast<intptr_t>(key); } | 377 static intptr_t Hashcode(Key key) { return reinterpret_cast<intptr_t>(key); } |
| 385 static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; } | 378 static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; } |
| 386 }; | 379 }; |
| 387 | 380 |
| 388 } // namespace dart | 381 } // namespace dart |
| 389 | 382 |
| 390 #endif // RUNTIME_VM_HASH_MAP_H_ | 383 #endif // RUNTIME_VM_HASH_MAP_H_ |
| OLD | NEW |