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 |