OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_TABLE_H_ | 5 #ifndef RUNTIME_VM_HASH_TABLE_H_ |
6 #define RUNTIME_VM_HASH_TABLE_H_ | 6 #define RUNTIME_VM_HASH_TABLE_H_ |
7 | 7 |
8 #include "platform/assert.h" | 8 #include "platform/assert.h" |
9 #include "vm/object.h" | 9 #include "vm/object.h" |
10 | 10 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 // The header tracks the number of entries in each state. | 65 // The header tracks the number of entries in each state. |
66 // Any object except Object::sentinel() and Object::transition_sentinel() | 66 // Any object except Object::sentinel() and Object::transition_sentinel() |
67 // may be stored as a key. Any object may be stored in a payload. | 67 // may be stored as a key. Any object may be stored in a payload. |
68 // | 68 // |
69 // Parameters | 69 // Parameters |
70 // KeyTraits: defines static methods | 70 // KeyTraits: defines static methods |
71 // bool IsMatch(const Key& key, const Object& obj) and | 71 // bool IsMatch(const Key& key, const Object& obj) and |
72 // uword Hash(const Key& key) for any number of desired lookup key types. | 72 // uword Hash(const Key& key) for any number of desired lookup key types. |
73 // kPayloadSize: number of components of the payload in each entry. | 73 // kPayloadSize: number of components of the payload in each entry. |
74 // kMetaDataSize: number of elements reserved (e.g., for iteration order data). | 74 // kMetaDataSize: number of elements reserved (e.g., for iteration order data). |
75 template<typename KeyTraits, intptr_t kPayloadSize, intptr_t kMetaDataSize> | 75 template <typename KeyTraits, intptr_t kPayloadSize, intptr_t kMetaDataSize> |
76 class HashTable : public ValueObject { | 76 class HashTable : public ValueObject { |
77 public: | 77 public: |
78 typedef KeyTraits Traits; | 78 typedef KeyTraits Traits; |
79 // Uses the passed in handles for all handle operations. | 79 // Uses the passed in handles for all handle operations. |
80 // 'Release' must be called at the end to obtain the final table | 80 // 'Release' must be called at the end to obtain the final table |
81 // after potential growth/shrinkage. | 81 // after potential growth/shrinkage. |
82 HashTable(Object* key, Smi* index, Array* data) | 82 HashTable(Object* key, Smi* index, Array* data) |
83 : key_handle_(key), | 83 : key_handle_(key), |
84 smi_handle_(index), | 84 smi_handle_(index), |
85 data_(data), | 85 data_(data), |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
120 return kFirstKeyIndex + (kEntrySize * num_entries); | 120 return kFirstKeyIndex + (kEntrySize * num_entries); |
121 } | 121 } |
122 | 122 |
123 // Initializes an empty table. | 123 // Initializes an empty table. |
124 void Initialize() const { | 124 void Initialize() const { |
125 ASSERT(data_->Length() >= ArrayLengthForNumOccupied(0)); | 125 ASSERT(data_->Length() >= ArrayLengthForNumOccupied(0)); |
126 *smi_handle_ = Smi::New(0); | 126 *smi_handle_ = Smi::New(0); |
127 data_->SetAt(kOccupiedEntriesIndex, *smi_handle_); | 127 data_->SetAt(kOccupiedEntriesIndex, *smi_handle_); |
128 data_->SetAt(kDeletedEntriesIndex, *smi_handle_); | 128 data_->SetAt(kDeletedEntriesIndex, *smi_handle_); |
129 | 129 |
130 NOT_IN_PRODUCT( | 130 #if !defined(PRODUCT) |
131 data_->SetAt(kNumGrowsIndex, *smi_handle_); | 131 data_->SetAt(kNumGrowsIndex, *smi_handle_); |
132 data_->SetAt(kNumLT5LookupsIndex, *smi_handle_); | 132 data_->SetAt(kNumLT5LookupsIndex, *smi_handle_); |
133 data_->SetAt(kNumLT25LookupsIndex, *smi_handle_); | 133 data_->SetAt(kNumLT25LookupsIndex, *smi_handle_); |
134 data_->SetAt(kNumGT25LookupsIndex, *smi_handle_); | 134 data_->SetAt(kNumGT25LookupsIndex, *smi_handle_); |
135 ) // !PRODUCT | 135 #endif // !defined(PRODUCT) |
136 | 136 |
137 for (intptr_t i = kHeaderSize; i < data_->Length(); ++i) { | 137 for (intptr_t i = kHeaderSize; i < data_->Length(); ++i) { |
138 data_->SetAt(i, Object::sentinel()); | 138 data_->SetAt(i, Object::sentinel()); |
139 } | 139 } |
140 } | 140 } |
141 | 141 |
142 // Returns whether 'key' matches any key in the table. | 142 // Returns whether 'key' matches any key in the table. |
143 template<typename Key> | 143 template <typename Key> |
144 bool ContainsKey(const Key& key) const { | 144 bool ContainsKey(const Key& key) const { |
145 return FindKey(key) != -1; | 145 return FindKey(key) != -1; |
146 } | 146 } |
147 | 147 |
148 // Returns the entry that matches 'key', or -1 if none exists. | 148 // Returns the entry that matches 'key', or -1 if none exists. |
149 template<typename Key> | 149 template <typename Key> |
150 intptr_t FindKey(const Key& key) const { | 150 intptr_t FindKey(const Key& key) const { |
151 const intptr_t num_entries = NumEntries(); | 151 const intptr_t num_entries = NumEntries(); |
152 ASSERT(NumOccupied() < num_entries); | 152 ASSERT(NumOccupied() < num_entries); |
153 // TODO(koda): Add salt. | 153 // TODO(koda): Add salt. |
154 NOT_IN_PRODUCT(intptr_t collisions = 0;) | 154 NOT_IN_PRODUCT(intptr_t collisions = 0;) |
155 uword hash = KeyTraits::Hash(key); | 155 uword hash = KeyTraits::Hash(key); |
156 intptr_t probe = hash % num_entries; | 156 intptr_t probe = hash % num_entries; |
157 // TODO(koda): Consider quadratic probing. | 157 // TODO(koda): Consider quadratic probing. |
158 while (true) { | 158 while (true) { |
159 if (IsUnused(probe)) { | 159 if (IsUnused(probe)) { |
(...skipping 12 matching lines...) Expand all Loading... |
172 probe = (probe == num_entries) ? 0 : probe; | 172 probe = (probe == num_entries) ? 0 : probe; |
173 } | 173 } |
174 UNREACHABLE(); | 174 UNREACHABLE(); |
175 return -1; | 175 return -1; |
176 } | 176 } |
177 | 177 |
178 // Sets *entry to either: | 178 // Sets *entry to either: |
179 // - an occupied entry matching 'key', and returns true, or | 179 // - an occupied entry matching 'key', and returns true, or |
180 // - an unused/deleted entry where a matching key may be inserted, | 180 // - an unused/deleted entry where a matching key may be inserted, |
181 // and returns false. | 181 // and returns false. |
182 template<typename Key> | 182 template <typename Key> |
183 bool FindKeyOrDeletedOrUnused(const Key& key, intptr_t* entry) const { | 183 bool FindKeyOrDeletedOrUnused(const Key& key, intptr_t* entry) const { |
184 const intptr_t num_entries = NumEntries(); | 184 const intptr_t num_entries = NumEntries(); |
185 ASSERT(entry != NULL); | 185 ASSERT(entry != NULL); |
186 ASSERT(NumOccupied() < num_entries); | 186 ASSERT(NumOccupied() < num_entries); |
187 NOT_IN_PRODUCT(intptr_t collisions = 0;) | 187 NOT_IN_PRODUCT(intptr_t collisions = 0;) |
188 uword hash = KeyTraits::Hash(key); | 188 uword hash = KeyTraits::Hash(key); |
189 intptr_t probe = hash % num_entries; | 189 intptr_t probe = hash % num_entries; |
190 intptr_t deleted = -1; | 190 intptr_t deleted = -1; |
191 // TODO(koda): Consider quadratic probing. | 191 // TODO(koda): Consider quadratic probing. |
192 while (true) { | 192 while (true) { |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 InternalSetKey(entry, Object::transition_sentinel()); | 264 InternalSetKey(entry, Object::transition_sentinel()); |
265 AdjustSmiValueAt(kOccupiedEntriesIndex, -1); | 265 AdjustSmiValueAt(kOccupiedEntriesIndex, -1); |
266 AdjustSmiValueAt(kDeletedEntriesIndex, 1); | 266 AdjustSmiValueAt(kDeletedEntriesIndex, 1); |
267 } | 267 } |
268 intptr_t NumEntries() const { | 268 intptr_t NumEntries() const { |
269 return (data_->Length() - kFirstKeyIndex) / kEntrySize; | 269 return (data_->Length() - kFirstKeyIndex) / kEntrySize; |
270 } | 270 } |
271 intptr_t NumUnused() const { | 271 intptr_t NumUnused() const { |
272 return NumEntries() - NumOccupied() - NumDeleted(); | 272 return NumEntries() - NumOccupied() - NumDeleted(); |
273 } | 273 } |
274 intptr_t NumOccupied() const { | 274 intptr_t NumOccupied() const { return GetSmiValueAt(kOccupiedEntriesIndex); } |
275 return GetSmiValueAt(kOccupiedEntriesIndex); | 275 intptr_t NumDeleted() const { return GetSmiValueAt(kDeletedEntriesIndex); } |
276 } | 276 Object& KeyHandle() const { return *key_handle_; } |
277 intptr_t NumDeleted() const { | 277 Smi& SmiHandle() const { return *smi_handle_; } |
278 return GetSmiValueAt(kDeletedEntriesIndex); | |
279 } | |
280 Object& KeyHandle() const { | |
281 return *key_handle_; | |
282 } | |
283 Smi& SmiHandle() const { | |
284 return *smi_handle_; | |
285 } | |
286 | 278 |
287 NOT_IN_PRODUCT( | 279 #if !defined(PRODUCT) |
288 intptr_t NumGrows() const { | 280 intptr_t NumGrows() const { return GetSmiValueAt(kNumGrowsIndex); } |
289 return GetSmiValueAt(kNumGrowsIndex); | |
290 } | |
291 intptr_t NumLT5Collisions() const { | 281 intptr_t NumLT5Collisions() const { |
292 return GetSmiValueAt(kNumLT5LookupsIndex); | 282 return GetSmiValueAt(kNumLT5LookupsIndex); |
293 } | 283 } |
294 intptr_t NumLT25Collisions() const { | 284 intptr_t NumLT25Collisions() const { |
295 return GetSmiValueAt(kNumLT25LookupsIndex); | 285 return GetSmiValueAt(kNumLT25LookupsIndex); |
296 } | 286 } |
297 intptr_t NumGT25Collisions() const { | 287 intptr_t NumGT25Collisions() const { |
298 return GetSmiValueAt(kNumGT25LookupsIndex); | 288 return GetSmiValueAt(kNumGT25LookupsIndex); |
299 } | 289 } |
300 void UpdateGrowth() const { | 290 void UpdateGrowth() const { AdjustSmiValueAt(kNumGrowsIndex, 1); } |
301 AdjustSmiValueAt(kNumGrowsIndex, 1); | |
302 } | |
303 void UpdateCollisions(intptr_t collisions) const { | 291 void UpdateCollisions(intptr_t collisions) const { |
304 if (data_->raw()->IsVMHeapObject()) { | 292 if (data_->raw()->IsVMHeapObject()) { |
305 return; | 293 return; |
306 } | 294 } |
307 if (collisions < 5) { | 295 if (collisions < 5) { |
308 AdjustSmiValueAt(kNumLT5LookupsIndex, 1); | 296 AdjustSmiValueAt(kNumLT5LookupsIndex, 1); |
309 } else if (collisions < 25) { | 297 } else if (collisions < 25) { |
310 AdjustSmiValueAt(kNumLT25LookupsIndex, 1); | 298 AdjustSmiValueAt(kNumLT25LookupsIndex, 1); |
311 } else { | 299 } else { |
312 AdjustSmiValueAt(kNumGT25LookupsIndex, 1); | 300 AdjustSmiValueAt(kNumGT25LookupsIndex, 1); |
313 } | 301 } |
314 } | 302 } |
315 void PrintStats() const { | 303 void PrintStats() const { |
316 if (!KeyTraits::ReportStats()) { | 304 if (!KeyTraits::ReportStats()) { |
317 return; | 305 return; |
318 } | 306 } |
| 307 // clang-format off |
319 OS::Print("Stats for %s table :\n" | 308 OS::Print("Stats for %s table :\n" |
320 " Size of table = %" Pd ",Number of Occupied entries = %" Pd "\n" | 309 " Size of table = %" Pd ",Number of Occupied entries = %" Pd "\n" |
321 " Number of Grows = %" Pd "\n" | 310 " Number of Grows = %" Pd "\n" |
322 " Number of look ups with < 5 collisions = %" Pd "\n" | 311 " Number of look ups with < 5 collisions = %" Pd "\n" |
323 " Number of look ups with < 25 collisions = %" Pd "\n" | 312 " Number of look ups with < 25 collisions = %" Pd "\n" |
324 " Number of look ups with > 25 collisions = %" Pd "\n", | 313 " Number of look ups with > 25 collisions = %" Pd "\n", |
325 KeyTraits::Name(), | 314 KeyTraits::Name(), |
326 NumEntries(), NumOccupied(), | 315 NumEntries(), NumOccupied(), |
327 NumGrows(), | 316 NumGrows(), |
328 NumLT5Collisions(), NumLT25Collisions(), NumGT25Collisions()); | 317 NumLT5Collisions(), NumLT25Collisions(), NumGT25Collisions()); |
| 318 // clang-format on |
329 } | 319 } |
330 ) // !PRODUCT | 320 #endif // !PRODUCT |
331 | 321 |
332 protected: | 322 protected: |
333 static const intptr_t kOccupiedEntriesIndex = 0; | 323 static const intptr_t kOccupiedEntriesIndex = 0; |
334 static const intptr_t kDeletedEntriesIndex = 1; | 324 static const intptr_t kDeletedEntriesIndex = 1; |
335 #if defined(PRODUCT) | 325 #if defined(PRODUCT) |
336 static const intptr_t kHeaderSize = kDeletedEntriesIndex + 1; | 326 static const intptr_t kHeaderSize = kDeletedEntriesIndex + 1; |
337 #else | 327 #else |
338 static const intptr_t kNumGrowsIndex = 2; | 328 static const intptr_t kNumGrowsIndex = 2; |
339 static const intptr_t kNumLT5LookupsIndex = 3; | 329 static const intptr_t kNumLT5LookupsIndex = 3; |
340 static const intptr_t kNumLT25LookupsIndex = 4; | 330 static const intptr_t kNumLT25LookupsIndex = 4; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 Smi* smi_handle_; | 372 Smi* smi_handle_; |
383 // Exactly one of these is non-NULL, depending on whether Release was called. | 373 // Exactly one of these is non-NULL, depending on whether Release was called. |
384 Array* data_; | 374 Array* data_; |
385 Array* released_data_; | 375 Array* released_data_; |
386 | 376 |
387 friend class HashTables; | 377 friend class HashTables; |
388 }; | 378 }; |
389 | 379 |
390 | 380 |
391 // Table with unspecified iteration order. No payload overhead or metadata. | 381 // Table with unspecified iteration order. No payload overhead or metadata. |
392 template<typename KeyTraits, intptr_t kUserPayloadSize> | 382 template <typename KeyTraits, intptr_t kUserPayloadSize> |
393 class UnorderedHashTable : public HashTable<KeyTraits, kUserPayloadSize, 0> { | 383 class UnorderedHashTable : public HashTable<KeyTraits, kUserPayloadSize, 0> { |
394 public: | 384 public: |
395 typedef HashTable<KeyTraits, kUserPayloadSize, 0> BaseTable; | 385 typedef HashTable<KeyTraits, kUserPayloadSize, 0> BaseTable; |
396 static const intptr_t kPayloadSize = kUserPayloadSize; | 386 static const intptr_t kPayloadSize = kUserPayloadSize; |
397 explicit UnorderedHashTable(RawArray* data) | 387 explicit UnorderedHashTable(RawArray* data) |
398 : BaseTable(Thread::Current()->zone(), data) {} | 388 : BaseTable(Thread::Current()->zone(), data) {} |
399 UnorderedHashTable(Zone* zone, RawArray* data) : BaseTable(zone, data) {} | 389 UnorderedHashTable(Zone* zone, RawArray* data) : BaseTable(zone, data) {} |
400 UnorderedHashTable(Object* key, Smi* value, Array* data) | 390 UnorderedHashTable(Object* key, Smi* value, Array* data) |
401 : BaseTable(key, value, data) {} | 391 : BaseTable(key, value, data) {} |
402 // Note: Does not check for concurrent modification. | 392 // Note: Does not check for concurrent modification. |
403 class Iterator { | 393 class Iterator { |
404 public: | 394 public: |
405 explicit Iterator(const UnorderedHashTable* table) | 395 explicit Iterator(const UnorderedHashTable* table) |
406 : table_(table), entry_(-1) {} | 396 : table_(table), entry_(-1) {} |
407 bool MoveNext() { | 397 bool MoveNext() { |
408 while (entry_ < (table_->NumEntries() - 1)) { | 398 while (entry_ < (table_->NumEntries() - 1)) { |
409 ++entry_; | 399 ++entry_; |
410 if (table_->IsOccupied(entry_)) { | 400 if (table_->IsOccupied(entry_)) { |
411 return true; | 401 return true; |
412 } | 402 } |
413 } | 403 } |
414 return false; | 404 return false; |
415 } | 405 } |
416 intptr_t Current() { | 406 intptr_t Current() { return entry_; } |
417 return entry_; | |
418 } | |
419 | 407 |
420 private: | 408 private: |
421 const UnorderedHashTable* table_; | 409 const UnorderedHashTable* table_; |
422 intptr_t entry_; | 410 intptr_t entry_; |
423 }; | 411 }; |
424 | 412 |
425 // No extra book-keeping needed for Initialize, InsertKey, DeleteEntry. | 413 // No extra book-keeping needed for Initialize, InsertKey, DeleteEntry. |
426 }; | 414 }; |
427 | 415 |
428 | 416 |
429 class HashTables : public AllStatic { | 417 class HashTables : public AllStatic { |
430 public: | 418 public: |
431 // Allocates and initializes a table. | 419 // Allocates and initializes a table. |
432 template<typename Table> | 420 template <typename Table> |
433 static RawArray* New(intptr_t initial_capacity, | 421 static RawArray* New(intptr_t initial_capacity, |
434 Heap::Space space = Heap::kNew) { | 422 Heap::Space space = Heap::kNew) { |
435 Table table(Thread::Current()->zone(), Array::New( | 423 Table table( |
436 Table::ArrayLengthForNumOccupied(initial_capacity), space)); | 424 Thread::Current()->zone(), |
| 425 Array::New(Table::ArrayLengthForNumOccupied(initial_capacity), space)); |
437 table.Initialize(); | 426 table.Initialize(); |
438 return table.Release().raw(); | 427 return table.Release().raw(); |
439 } | 428 } |
440 | 429 |
441 template<typename Table> | 430 template <typename Table> |
442 static RawArray* New(const Array& array) { | 431 static RawArray* New(const Array& array) { |
443 Table table(Thread::Current()->zone(), array.raw()); | 432 Table table(Thread::Current()->zone(), array.raw()); |
444 table.Initialize(); | 433 table.Initialize(); |
445 return table.Release().raw(); | 434 return table.Release().raw(); |
446 } | 435 } |
447 | 436 |
448 // Clears 'to' and inserts all elements from 'from', in iteration order. | 437 // Clears 'to' and inserts all elements from 'from', in iteration order. |
449 // The tables must have the same user payload size. | 438 // The tables must have the same user payload size. |
450 template<typename From, typename To> | 439 template <typename From, typename To> |
451 static void Copy(const From& from, const To& to) { | 440 static void Copy(const From& from, const To& to) { |
452 COMPILE_ASSERT(From::kPayloadSize == To::kPayloadSize); | 441 COMPILE_ASSERT(From::kPayloadSize == To::kPayloadSize); |
453 to.Initialize(); | 442 to.Initialize(); |
454 ASSERT(from.NumOccupied() < to.NumEntries()); | 443 ASSERT(from.NumOccupied() < to.NumEntries()); |
455 typename From::Iterator it(&from); | 444 typename From::Iterator it(&from); |
456 Object& obj = Object::Handle(); | 445 Object& obj = Object::Handle(); |
457 while (it.MoveNext()) { | 446 while (it.MoveNext()) { |
458 intptr_t from_entry = it.Current(); | 447 intptr_t from_entry = it.Current(); |
459 obj = from.GetKey(from_entry); | 448 obj = from.GetKey(from_entry); |
460 intptr_t to_entry = -1; | 449 intptr_t to_entry = -1; |
461 const Object& key = obj; | 450 const Object& key = obj; |
462 bool present = to.FindKeyOrDeletedOrUnused(key, &to_entry); | 451 bool present = to.FindKeyOrDeletedOrUnused(key, &to_entry); |
463 ASSERT(!present); | 452 ASSERT(!present); |
464 to.InsertKey(to_entry, obj); | 453 to.InsertKey(to_entry, obj); |
465 for (intptr_t i = 0; i < From::kPayloadSize; ++i) { | 454 for (intptr_t i = 0; i < From::kPayloadSize; ++i) { |
466 obj = from.GetPayload(from_entry, i); | 455 obj = from.GetPayload(from_entry, i); |
467 to.UpdatePayload(to_entry, i, obj); | 456 to.UpdatePayload(to_entry, i, obj); |
468 } | 457 } |
469 } | 458 } |
470 } | 459 } |
471 | 460 |
472 template<typename Table> | 461 template <typename Table> |
473 static void EnsureLoadFactor(double low, double high, const Table& table) { | 462 static void EnsureLoadFactor(double low, double high, const Table& table) { |
474 double current = (1 + table.NumOccupied() + table.NumDeleted()) / | 463 double current = (1 + table.NumOccupied() + table.NumDeleted()) / |
475 static_cast<double>(table.NumEntries()); | 464 static_cast<double>(table.NumEntries()); |
476 if (low <= current && current < high) { | 465 if (low <= current && current < high) { |
477 return; | 466 return; |
478 } | 467 } |
479 double target = (low + high) / 2.0; | 468 double target = (low + high) / 2.0; |
480 intptr_t new_capacity = (1 + table.NumOccupied()) / target; | 469 intptr_t new_capacity = (1 + table.NumOccupied()) / target; |
481 Table new_table(New<Table>( | 470 Table new_table(New<Table>(new_capacity, |
482 new_capacity, | 471 table.data_->IsOld() ? Heap::kOld : Heap::kNew)); |
483 table.data_->IsOld() ? Heap::kOld : Heap::kNew)); | |
484 Copy(table, new_table); | 472 Copy(table, new_table); |
485 *table.data_ = new_table.Release().raw(); | 473 *table.data_ = new_table.Release().raw(); |
486 NOT_IN_PRODUCT(table.UpdateGrowth(); table.PrintStats();) | 474 NOT_IN_PRODUCT(table.UpdateGrowth(); table.PrintStats();) |
487 } | 475 } |
488 | 476 |
489 // Serializes a table by concatenating its entries as an array. | 477 // Serializes a table by concatenating its entries as an array. |
490 template<typename Table> | 478 template <typename Table> |
491 static RawArray* ToArray(const Table& table, bool include_payload) { | 479 static RawArray* ToArray(const Table& table, bool include_payload) { |
492 const intptr_t entry_size = include_payload ? (1 + Table::kPayloadSize) : 1; | 480 const intptr_t entry_size = include_payload ? (1 + Table::kPayloadSize) : 1; |
493 Array& result = Array::Handle(Array::New(table.NumOccupied() * entry_size)); | 481 Array& result = Array::Handle(Array::New(table.NumOccupied() * entry_size)); |
494 typename Table::Iterator it(&table); | 482 typename Table::Iterator it(&table); |
495 Object& obj = Object::Handle(); | 483 Object& obj = Object::Handle(); |
496 intptr_t result_index = 0; | 484 intptr_t result_index = 0; |
497 while (it.MoveNext()) { | 485 while (it.MoveNext()) { |
498 intptr_t entry = it.Current(); | 486 intptr_t entry = it.Current(); |
499 obj = table.GetKey(entry); | 487 obj = table.GetKey(entry); |
500 result.SetAt(result_index++, obj); | 488 result.SetAt(result_index++, obj); |
501 if (include_payload) { | 489 if (include_payload) { |
502 for (intptr_t i = 0; i < Table::kPayloadSize; ++i) { | 490 for (intptr_t i = 0; i < Table::kPayloadSize; ++i) { |
503 obj = table.GetPayload(entry, i); | 491 obj = table.GetPayload(entry, i); |
504 result.SetAt(result_index++, obj); | 492 result.SetAt(result_index++, obj); |
505 } | 493 } |
506 } | 494 } |
507 } | 495 } |
508 return result.raw(); | 496 return result.raw(); |
509 } | 497 } |
510 }; | 498 }; |
511 | 499 |
512 | 500 |
513 template<typename BaseIterTable> | 501 template <typename BaseIterTable> |
514 class HashMap : public BaseIterTable { | 502 class HashMap : public BaseIterTable { |
515 public: | 503 public: |
516 explicit HashMap(RawArray* data) | 504 explicit HashMap(RawArray* data) |
517 : BaseIterTable(Thread::Current()->zone(), data) {} | 505 : BaseIterTable(Thread::Current()->zone(), data) {} |
518 HashMap(Zone* zone, RawArray* data) : BaseIterTable(zone, data) {} | 506 HashMap(Zone* zone, RawArray* data) : BaseIterTable(zone, data) {} |
519 HashMap(Object* key, Smi* value, Array* data) | 507 HashMap(Object* key, Smi* value, Array* data) |
520 : BaseIterTable(key, value, data) {} | 508 : BaseIterTable(key, value, data) {} |
521 template<typename Key> | 509 template <typename Key> |
522 RawObject* GetOrNull(const Key& key, bool* present = NULL) const { | 510 RawObject* GetOrNull(const Key& key, bool* present = NULL) const { |
523 intptr_t entry = BaseIterTable::FindKey(key); | 511 intptr_t entry = BaseIterTable::FindKey(key); |
524 if (present != NULL) { | 512 if (present != NULL) { |
525 *present = (entry != -1); | 513 *present = (entry != -1); |
526 } | 514 } |
527 return (entry == -1) ? Object::null() : BaseIterTable::GetPayload(entry, 0); | 515 return (entry == -1) ? Object::null() : BaseIterTable::GetPayload(entry, 0); |
528 } | 516 } |
529 bool UpdateOrInsert(const Object& key, const Object& value) const { | 517 bool UpdateOrInsert(const Object& key, const Object& value) const { |
530 EnsureCapacity(); | 518 EnsureCapacity(); |
531 intptr_t entry = -1; | 519 intptr_t entry = -1; |
532 bool present = BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry); | 520 bool present = BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry); |
533 if (!present) { | 521 if (!present) { |
534 BaseIterTable::InsertKey(entry, key); | 522 BaseIterTable::InsertKey(entry, key); |
535 } | 523 } |
536 BaseIterTable::UpdatePayload(entry, 0, value); | 524 BaseIterTable::UpdatePayload(entry, 0, value); |
537 return present; | 525 return present; |
538 } | 526 } |
539 // Update the value of an existing key. Note that 'key' need not be an Object. | 527 // Update the value of an existing key. Note that 'key' need not be an Object. |
540 template<typename Key> | 528 template <typename Key> |
541 void UpdateValue(const Key& key, const Object& value) const { | 529 void UpdateValue(const Key& key, const Object& value) const { |
542 intptr_t entry = BaseIterTable::FindKey(key); | 530 intptr_t entry = BaseIterTable::FindKey(key); |
543 ASSERT(entry != -1); | 531 ASSERT(entry != -1); |
544 BaseIterTable::UpdatePayload(entry, 0, value); | 532 BaseIterTable::UpdatePayload(entry, 0, value); |
545 } | 533 } |
546 // If 'key' is not present, maps it to 'value_if_absent'. Returns the final | 534 // If 'key' is not present, maps it to 'value_if_absent'. Returns the final |
547 // value in the map. | 535 // value in the map. |
548 RawObject* InsertOrGetValue(const Object& key, | 536 RawObject* InsertOrGetValue(const Object& key, |
549 const Object& value_if_absent) const { | 537 const Object& value_if_absent) const { |
550 EnsureCapacity(); | 538 EnsureCapacity(); |
551 intptr_t entry = -1; | 539 intptr_t entry = -1; |
552 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { | 540 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { |
553 BaseIterTable::InsertKey(entry, key); | 541 BaseIterTable::InsertKey(entry, key); |
554 BaseIterTable::UpdatePayload(entry, 0, value_if_absent); | 542 BaseIterTable::UpdatePayload(entry, 0, value_if_absent); |
555 return value_if_absent.raw(); | 543 return value_if_absent.raw(); |
556 } else { | 544 } else { |
557 return BaseIterTable::GetPayload(entry, 0); | 545 return BaseIterTable::GetPayload(entry, 0); |
558 } | 546 } |
559 } | 547 } |
560 // Like InsertOrGetValue, but calls NewKey to allocate a key object if needed. | 548 // Like InsertOrGetValue, but calls NewKey to allocate a key object if needed. |
561 template<typename Key> | 549 template <typename Key> |
562 RawObject* InsertNewOrGetValue(const Key& key, | 550 RawObject* InsertNewOrGetValue(const Key& key, |
563 const Object& value_if_absent) const { | 551 const Object& value_if_absent) const { |
564 EnsureCapacity(); | 552 EnsureCapacity(); |
565 intptr_t entry = -1; | 553 intptr_t entry = -1; |
566 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { | 554 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { |
567 BaseIterTable::KeyHandle() = | 555 BaseIterTable::KeyHandle() = |
568 BaseIterTable::BaseTable::Traits::NewKey(key); | 556 BaseIterTable::BaseTable::Traits::NewKey(key); |
569 BaseIterTable::InsertKey(entry, BaseIterTable::KeyHandle()); | 557 BaseIterTable::InsertKey(entry, BaseIterTable::KeyHandle()); |
570 BaseIterTable::UpdatePayload(entry, 0, value_if_absent); | 558 BaseIterTable::UpdatePayload(entry, 0, value_if_absent); |
571 return value_if_absent.raw(); | 559 return value_if_absent.raw(); |
572 } else { | 560 } else { |
573 return BaseIterTable::GetPayload(entry, 0); | 561 return BaseIterTable::GetPayload(entry, 0); |
574 } | 562 } |
575 } | 563 } |
576 | 564 |
577 template<typename Key> | 565 template <typename Key> |
578 bool Remove(const Key& key) const { | 566 bool Remove(const Key& key) const { |
579 intptr_t entry = BaseIterTable::FindKey(key); | 567 intptr_t entry = BaseIterTable::FindKey(key); |
580 if (entry == -1) { | 568 if (entry == -1) { |
581 return false; | 569 return false; |
582 } else { | 570 } else { |
583 BaseIterTable::DeleteEntry(entry); | 571 BaseIterTable::DeleteEntry(entry); |
584 return true; | 572 return true; |
585 } | 573 } |
586 } | 574 } |
587 | 575 |
588 void Clear() const { | 576 void Clear() const { BaseIterTable::Initialize(); } |
589 BaseIterTable::Initialize(); | |
590 } | |
591 | 577 |
592 protected: | 578 protected: |
593 void EnsureCapacity() const { | 579 void EnsureCapacity() const { |
594 static const double kMaxLoadFactor = 0.75; | 580 static const double kMaxLoadFactor = 0.75; |
595 // We currently never shrink. | 581 // We currently never shrink. |
596 HashTables::EnsureLoadFactor(0.0, kMaxLoadFactor, *this); | 582 HashTables::EnsureLoadFactor(0.0, kMaxLoadFactor, *this); |
597 } | 583 } |
598 }; | 584 }; |
599 | 585 |
600 | 586 |
601 template<typename KeyTraits> | 587 template <typename KeyTraits> |
602 class UnorderedHashMap : public HashMap<UnorderedHashTable<KeyTraits, 1> > { | 588 class UnorderedHashMap : public HashMap<UnorderedHashTable<KeyTraits, 1> > { |
603 public: | 589 public: |
604 typedef HashMap<UnorderedHashTable<KeyTraits, 1> > BaseMap; | 590 typedef HashMap<UnorderedHashTable<KeyTraits, 1> > BaseMap; |
605 explicit UnorderedHashMap(RawArray* data) | 591 explicit UnorderedHashMap(RawArray* data) |
606 : BaseMap(Thread::Current()->zone(), data) {} | 592 : BaseMap(Thread::Current()->zone(), data) {} |
607 UnorderedHashMap(Zone* zone, RawArray* data) : BaseMap(zone, data) {} | 593 UnorderedHashMap(Zone* zone, RawArray* data) : BaseMap(zone, data) {} |
608 UnorderedHashMap(Object* key, Smi* value, Array* data) | 594 UnorderedHashMap(Object* key, Smi* value, Array* data) |
609 : BaseMap(key, value, data) {} | 595 : BaseMap(key, value, data) {} |
610 }; | 596 }; |
611 | 597 |
612 | 598 |
613 template<typename BaseIterTable> | 599 template <typename BaseIterTable> |
614 class HashSet : public BaseIterTable { | 600 class HashSet : public BaseIterTable { |
615 public: | 601 public: |
616 explicit HashSet(RawArray* data) | 602 explicit HashSet(RawArray* data) |
617 : BaseIterTable(Thread::Current()->zone(), data) {} | 603 : BaseIterTable(Thread::Current()->zone(), data) {} |
618 HashSet(Zone* zone, RawArray* data) : BaseIterTable(zone, data) {} | 604 HashSet(Zone* zone, RawArray* data) : BaseIterTable(zone, data) {} |
619 HashSet(Object* key, Smi* value, Array* data) | 605 HashSet(Object* key, Smi* value, Array* data) |
620 : BaseIterTable(key, value, data) {} | 606 : BaseIterTable(key, value, data) {} |
621 bool Insert(const Object& key) { | 607 bool Insert(const Object& key) { |
622 EnsureCapacity(); | 608 EnsureCapacity(); |
623 intptr_t entry = -1; | 609 intptr_t entry = -1; |
(...skipping 11 matching lines...) Expand all Loading... |
635 intptr_t entry = -1; | 621 intptr_t entry = -1; |
636 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { | 622 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { |
637 BaseIterTable::InsertKey(entry, key); | 623 BaseIterTable::InsertKey(entry, key); |
638 return key.raw(); | 624 return key.raw(); |
639 } else { | 625 } else { |
640 return BaseIterTable::GetKey(entry); | 626 return BaseIterTable::GetKey(entry); |
641 } | 627 } |
642 } | 628 } |
643 | 629 |
644 // Like InsertOrGet, but calls NewKey to allocate a key object if needed. | 630 // Like InsertOrGet, but calls NewKey to allocate a key object if needed. |
645 template<typename Key> | 631 template <typename Key> |
646 RawObject* InsertNewOrGet(const Key& key) const { | 632 RawObject* InsertNewOrGet(const Key& key) const { |
647 EnsureCapacity(); | 633 EnsureCapacity(); |
648 intptr_t entry = -1; | 634 intptr_t entry = -1; |
649 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { | 635 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { |
650 BaseIterTable::KeyHandle() = | 636 BaseIterTable::KeyHandle() = |
651 BaseIterTable::BaseTable::Traits::NewKey(key); | 637 BaseIterTable::BaseTable::Traits::NewKey(key); |
652 BaseIterTable::InsertKey(entry, BaseIterTable::KeyHandle()); | 638 BaseIterTable::InsertKey(entry, BaseIterTable::KeyHandle()); |
653 return BaseIterTable::KeyHandle().raw(); | 639 return BaseIterTable::KeyHandle().raw(); |
654 } else { | 640 } else { |
655 return BaseIterTable::GetKey(entry); | 641 return BaseIterTable::GetKey(entry); |
656 } | 642 } |
657 } | 643 } |
658 | 644 |
659 template<typename Key> | 645 template <typename Key> |
660 RawObject* GetOrNull(const Key& key, bool* present = NULL) const { | 646 RawObject* GetOrNull(const Key& key, bool* present = NULL) const { |
661 intptr_t entry = BaseIterTable::FindKey(key); | 647 intptr_t entry = BaseIterTable::FindKey(key); |
662 if (present != NULL) { | 648 if (present != NULL) { |
663 *present = (entry != -1); | 649 *present = (entry != -1); |
664 } | 650 } |
665 return (entry == -1) ? Object::null() : BaseIterTable::GetKey(entry); | 651 return (entry == -1) ? Object::null() : BaseIterTable::GetKey(entry); |
666 } | 652 } |
667 | 653 |
668 template<typename Key> | 654 template <typename Key> |
669 bool Remove(const Key& key) const { | 655 bool Remove(const Key& key) const { |
670 intptr_t entry = BaseIterTable::FindKey(key); | 656 intptr_t entry = BaseIterTable::FindKey(key); |
671 if (entry == -1) { | 657 if (entry == -1) { |
672 return false; | 658 return false; |
673 } else { | 659 } else { |
674 BaseIterTable::DeleteEntry(entry); | 660 BaseIterTable::DeleteEntry(entry); |
675 return true; | 661 return true; |
676 } | 662 } |
677 } | 663 } |
678 | 664 |
679 void Clear() const { | 665 void Clear() const { BaseIterTable::Initialize(); } |
680 BaseIterTable::Initialize(); | |
681 } | |
682 | 666 |
683 protected: | 667 protected: |
684 void EnsureCapacity() const { | 668 void EnsureCapacity() const { |
685 static const double kMaxLoadFactor = 0.75; | 669 static const double kMaxLoadFactor = 0.75; |
686 // We currently never shrink. | 670 // We currently never shrink. |
687 HashTables::EnsureLoadFactor(0.0, kMaxLoadFactor, *this); | 671 HashTables::EnsureLoadFactor(0.0, kMaxLoadFactor, *this); |
688 } | 672 } |
689 }; | 673 }; |
690 | 674 |
691 | 675 |
692 template<typename KeyTraits> | 676 template <typename KeyTraits> |
693 class UnorderedHashSet : public HashSet<UnorderedHashTable<KeyTraits, 0> > { | 677 class UnorderedHashSet : public HashSet<UnorderedHashTable<KeyTraits, 0> > { |
694 public: | 678 public: |
695 typedef HashSet<UnorderedHashTable<KeyTraits, 0> > BaseSet; | 679 typedef HashSet<UnorderedHashTable<KeyTraits, 0> > BaseSet; |
696 explicit UnorderedHashSet(RawArray* data) | 680 explicit UnorderedHashSet(RawArray* data) |
697 : BaseSet(Thread::Current()->zone(), data) { | 681 : BaseSet(Thread::Current()->zone(), data) { |
698 ASSERT(data != Array::null()); | 682 ASSERT(data != Array::null()); |
699 } | 683 } |
700 UnorderedHashSet(Zone* zone, RawArray* data) : BaseSet(zone, data) {} | 684 UnorderedHashSet(Zone* zone, RawArray* data) : BaseSet(zone, data) {} |
701 UnorderedHashSet(Object* key, Smi* value, Array* data) | 685 UnorderedHashSet(Object* key, Smi* value, Array* data) |
702 : BaseSet(key, value, data) {} | 686 : BaseSet(key, value, data) {} |
703 }; | 687 }; |
704 | 688 |
705 } // namespace dart | 689 } // namespace dart |
706 | 690 |
707 #endif // RUNTIME_VM_HASH_TABLE_H_ | 691 #endif // RUNTIME_VM_HASH_TABLE_H_ |
OLD | NEW |