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 VM_HASH_TABLE_H_ | 5 #ifndef VM_HASH_TABLE_H_ |
6 #define VM_HASH_TABLE_H_ | 6 #define VM_HASH_TABLE_H_ |
7 | 7 |
8 // Temporarily used when sorting the indices in EnumIndexHashTable. | 8 // Temporarily used when sorting the indices in EnumIndexHashTable. |
9 // TODO(koda): Remove these dependencies before using in production. | 9 // TODO(koda): Remove these dependencies before using in production. |
10 #include <map> | 10 #include <map> |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 // | 71 // |
72 // Parameters | 72 // Parameters |
73 // KeyTraits: defines static methods | 73 // KeyTraits: defines static methods |
74 // bool IsMatch(const Key& key, const Object& obj) and | 74 // bool IsMatch(const Key& key, const Object& obj) and |
75 // uword Hash(const Key& key) for any number of desired lookup key types. | 75 // uword Hash(const Key& key) for any number of desired lookup key types. |
76 // kPayloadSize: number of components of the payload in each entry. | 76 // kPayloadSize: number of components of the payload in each entry. |
77 // kMetaDataSize: number of elements reserved (e.g., for iteration order data). | 77 // kMetaDataSize: number of elements reserved (e.g., for iteration order data). |
78 template<typename KeyTraits, intptr_t kPayloadSize, intptr_t kMetaDataSize> | 78 template<typename KeyTraits, intptr_t kPayloadSize, intptr_t kMetaDataSize> |
79 class HashTable : public ValueObject { | 79 class HashTable : public ValueObject { |
80 public: | 80 public: |
| 81 typedef KeyTraits Traits; |
81 explicit HashTable(Array& data) : data_(data) {} | 82 explicit HashTable(Array& data) : data_(data) {} |
82 | 83 |
83 RawArray* Release() { | 84 RawArray* Release() { |
84 ASSERT(!data_.IsNull()); | 85 ASSERT(!data_.IsNull()); |
85 RawArray* array = data_.raw(); | 86 RawArray* array = data_.raw(); |
86 data_ = Array::null(); | 87 data_ = Array::null(); |
87 return array; | 88 return array; |
88 } | 89 } |
89 | 90 |
90 ~HashTable() { | 91 ~HashTable() { |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 } | 377 } |
377 | 378 |
378 // No extra book-keeping needed for DeleteEntry. | 379 // No extra book-keeping needed for DeleteEntry. |
379 }; | 380 }; |
380 | 381 |
381 | 382 |
382 class HashTables : public AllStatic { | 383 class HashTables : public AllStatic { |
383 public: | 384 public: |
384 // Allocates and initializes a table. | 385 // Allocates and initializes a table. |
385 template<typename Table> | 386 template<typename Table> |
386 static RawArray* New(intptr_t initial_capacity) { | 387 static RawArray* New(intptr_t initial_capacity, |
| 388 Heap::Space space = Heap::kNew) { |
387 Table table(Array::Handle(Array::New( | 389 Table table(Array::Handle(Array::New( |
388 Table::ArrayLengthForNumOccupied(initial_capacity)))); | 390 Table::ArrayLengthForNumOccupied(initial_capacity), space))); |
389 table.Initialize(); | 391 table.Initialize(); |
390 return table.Release(); | 392 return table.Release(); |
391 } | 393 } |
392 | 394 |
393 // Clears 'to' and inserts all elements from 'from', in iteration order. | 395 // Clears 'to' and inserts all elements from 'from', in iteration order. |
394 // The tables must have the same user payload size. | 396 // The tables must have the same user payload size. |
395 template<typename From, typename To> | 397 template<typename From, typename To> |
396 static void Copy(const From& from, const To& to) { | 398 static void Copy(const From& from, const To& to) { |
397 COMPILE_ASSERT(From::kPayloadSize == To::kPayloadSize); | 399 COMPILE_ASSERT(From::kPayloadSize == To::kPayloadSize); |
398 to.Initialize(); | 400 to.Initialize(); |
(...skipping 17 matching lines...) Expand all Loading... |
416 | 418 |
417 template<typename Table> | 419 template<typename Table> |
418 static void EnsureLoadFactor(double low, double high, const Table& table) { | 420 static void EnsureLoadFactor(double low, double high, const Table& table) { |
419 double current = (1 + table.NumOccupied() + table.NumDeleted()) / | 421 double current = (1 + table.NumOccupied() + table.NumDeleted()) / |
420 static_cast<double>(table.NumEntries()); | 422 static_cast<double>(table.NumEntries()); |
421 if (low <= current && current < high) { | 423 if (low <= current && current < high) { |
422 return; | 424 return; |
423 } | 425 } |
424 double target = (low + high) / 2.0; | 426 double target = (low + high) / 2.0; |
425 intptr_t new_capacity = (1 + table.NumOccupied()) / target; | 427 intptr_t new_capacity = (1 + table.NumOccupied()) / target; |
426 Table new_table(Array::Handle(New<Table>(new_capacity))); | 428 Table new_table(Array::Handle(New<Table>( |
| 429 new_capacity, |
| 430 table.data_.IsOld() ? Heap::kOld : Heap::kNew))); |
427 Copy(table, new_table); | 431 Copy(table, new_table); |
428 table.data_ = new_table.Release(); | 432 table.data_ = new_table.Release(); |
429 } | 433 } |
430 | 434 |
431 // Serializes a table by concatenating its entries as an array. | 435 // Serializes a table by concatenating its entries as an array. |
432 template<typename Table> | 436 template<typename Table> |
433 static RawArray* ToArray(const Table& table, bool include_payload) { | 437 static RawArray* ToArray(const Table& table, bool include_payload) { |
434 const intptr_t entry_size = include_payload ? (1 + Table::kPayloadSize) : 1; | 438 const intptr_t entry_size = include_payload ? (1 + Table::kPayloadSize) : 1; |
435 Array& result = Array::Handle(Array::New(table.NumOccupied() * entry_size)); | 439 Array& result = Array::Handle(Array::New(table.NumOccupied() * entry_size)); |
436 typename Table::Iterator it(&table); | 440 typename Table::Iterator it(&table); |
(...skipping 21 matching lines...) Expand all Loading... |
458 explicit HashMap(Array& data) : BaseIterTable(data) {} | 462 explicit HashMap(Array& data) : BaseIterTable(data) {} |
459 template<typename Key> | 463 template<typename Key> |
460 RawObject* GetOrNull(const Key& key, bool* present = NULL) const { | 464 RawObject* GetOrNull(const Key& key, bool* present = NULL) const { |
461 intptr_t entry = BaseIterTable::FindKey(key); | 465 intptr_t entry = BaseIterTable::FindKey(key); |
462 if (present != NULL) { | 466 if (present != NULL) { |
463 *present = (entry != -1); | 467 *present = (entry != -1); |
464 } | 468 } |
465 return (entry == -1) ? Object::null() : BaseIterTable::GetPayload(entry, 0); | 469 return (entry == -1) ? Object::null() : BaseIterTable::GetPayload(entry, 0); |
466 } | 470 } |
467 bool UpdateOrInsert(const Object& key, const Object& value) const { | 471 bool UpdateOrInsert(const Object& key, const Object& value) const { |
468 HashTables::EnsureLoadFactor(0.0, 0.75, *this); | 472 EnsureCapacity(); |
469 intptr_t entry = -1; | 473 intptr_t entry = -1; |
470 bool present = BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry); | 474 bool present = BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry); |
471 if (!present) { | 475 if (!present) { |
472 BaseIterTable::InsertKey(entry, key); | 476 BaseIterTable::InsertKey(entry, key); |
473 } | 477 } |
474 BaseIterTable::UpdatePayload(entry, 0, value); | 478 BaseIterTable::UpdatePayload(entry, 0, value); |
475 return present; | 479 return present; |
476 } | 480 } |
477 // Update the value of an existing key. Note that 'key' need not be an Object. | 481 // Update the value of an existing key. Note that 'key' need not be an Object. |
478 template<typename Key> | 482 template<typename Key> |
479 void UpdateValue(const Key& key, const Object& value) const { | 483 void UpdateValue(const Key& key, const Object& value) const { |
480 intptr_t entry = BaseIterTable::FindKey(key); | 484 intptr_t entry = BaseIterTable::FindKey(key); |
481 ASSERT(entry != -1); | 485 ASSERT(entry != -1); |
482 BaseIterTable::UpdatePayload(entry, 0, value); | 486 BaseIterTable::UpdatePayload(entry, 0, value); |
483 } | 487 } |
| 488 // If 'key' is not present, maps it to 'value_if_absent'. Returns the final |
| 489 // value in the map. |
| 490 RawObject* InsertOrGetValue(const Object& key, |
| 491 const Object& value_if_absent) const { |
| 492 EnsureCapacity(); |
| 493 intptr_t entry = -1; |
| 494 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { |
| 495 BaseIterTable::InsertKey(entry, key); |
| 496 BaseIterTable::UpdatePayload(entry, 0, value_if_absent); |
| 497 return value_if_absent.raw(); |
| 498 } else { |
| 499 return BaseIterTable::GetPayload(entry, 0); |
| 500 } |
| 501 } |
| 502 // Like InsertOrGetValue, but calls NewKey to allocate a key object if needed. |
| 503 template<typename Key> |
| 504 RawObject* InsertNewOrGetValue(const Key& key, |
| 505 const Object& value_if_absent) const { |
| 506 EnsureCapacity(); |
| 507 intptr_t entry = -1; |
| 508 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { |
| 509 Object& new_key = Object::Handle( |
| 510 BaseIterTable::BaseTable::Traits::NewKey(key)); |
| 511 BaseIterTable::InsertKey(entry, new_key); |
| 512 BaseIterTable::UpdatePayload(entry, 0, value_if_absent); |
| 513 return value_if_absent.raw(); |
| 514 } else { |
| 515 return BaseIterTable::GetPayload(entry, 0); |
| 516 } |
| 517 } |
484 | 518 |
485 template<typename Key> | 519 template<typename Key> |
486 bool Remove(const Key& key) const { | 520 bool Remove(const Key& key) const { |
487 intptr_t entry = BaseIterTable::FindKey(key); | 521 intptr_t entry = BaseIterTable::FindKey(key); |
488 if (entry == -1) { | 522 if (entry == -1) { |
489 return false; | 523 return false; |
490 } else { | 524 } else { |
491 BaseIterTable::DeleteEntry(entry); | 525 BaseIterTable::DeleteEntry(entry); |
492 return true; | 526 return true; |
493 } | 527 } |
494 } | 528 } |
| 529 |
| 530 protected: |
| 531 void EnsureCapacity() const { |
| 532 static const double kMaxLoadFactor = 0.75; |
| 533 HashTables::EnsureLoadFactor(0.0, kMaxLoadFactor, *this); |
| 534 } |
495 }; | 535 }; |
496 | 536 |
497 | 537 |
498 template<typename KeyTraits> | 538 template<typename KeyTraits> |
499 class UnorderedHashMap : public HashMap<UnorderedHashTable<KeyTraits, 1> > { | 539 class UnorderedHashMap : public HashMap<UnorderedHashTable<KeyTraits, 1> > { |
500 public: | 540 public: |
501 typedef HashMap<UnorderedHashTable<KeyTraits, 1> > BaseMap; | 541 typedef HashMap<UnorderedHashTable<KeyTraits, 1> > BaseMap; |
502 explicit UnorderedHashMap(Array& data) : BaseMap(data) {} | 542 explicit UnorderedHashMap(Array& data) : BaseMap(data) {} |
503 }; | 543 }; |
504 | 544 |
505 | 545 |
506 template<typename KeyTraits> | 546 template<typename KeyTraits> |
507 class EnumIndexHashMap : public HashMap<EnumIndexHashTable<KeyTraits, 1> > { | 547 class EnumIndexHashMap : public HashMap<EnumIndexHashTable<KeyTraits, 1> > { |
508 public: | 548 public: |
509 typedef HashMap<EnumIndexHashTable<KeyTraits, 1> > BaseMap; | 549 typedef HashMap<EnumIndexHashTable<KeyTraits, 1> > BaseMap; |
510 explicit EnumIndexHashMap(Array& data) : BaseMap(data) {} | 550 explicit EnumIndexHashMap(Array& data) : BaseMap(data) {} |
511 }; | 551 }; |
512 | 552 |
513 | 553 |
514 template<typename BaseIterTable> | 554 template<typename BaseIterTable> |
515 class HashSet : public BaseIterTable { | 555 class HashSet : public BaseIterTable { |
516 public: | 556 public: |
517 explicit HashSet(Array& data) : BaseIterTable(data) {} | 557 explicit HashSet(Array& data) : BaseIterTable(data) {} |
518 bool Insert(const Object& key) { | 558 bool Insert(const Object& key) { |
519 HashTables::EnsureLoadFactor(0.0, 0.75, *this); | 559 EnsureCapacity(); |
520 intptr_t entry = -1; | 560 intptr_t entry = -1; |
521 bool present = BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry); | 561 bool present = BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry); |
522 if (!present) { | 562 if (!present) { |
523 BaseIterTable::InsertKey(entry, key); | 563 BaseIterTable::InsertKey(entry, key); |
524 } | 564 } |
525 return present; | 565 return present; |
526 } | 566 } |
| 567 |
| 568 // If 'key' is not present, insert and return it. Else, return the existing |
| 569 // key in the set (useful for canonicalization). |
| 570 RawObject* InsertOrGet(const Object& key) const { |
| 571 EnsureCapacity(); |
| 572 intptr_t entry = -1; |
| 573 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { |
| 574 BaseIterTable::InsertKey(entry, key); |
| 575 return key.raw(); |
| 576 } else { |
| 577 return BaseIterTable::GetPayload(entry, 0); |
| 578 } |
| 579 } |
| 580 |
| 581 // Like InsertOrGet, but calls NewKey to allocate a key object if needed. |
| 582 template<typename Key> |
| 583 RawObject* InsertNewOrGet(const Key& key) const { |
| 584 EnsureCapacity(); |
| 585 intptr_t entry = -1; |
| 586 if (!BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry)) { |
| 587 Object& new_key = Object::Handle( |
| 588 BaseIterTable::BaseTable::Traits::NewKey(key)); |
| 589 BaseIterTable::InsertKey(entry, new_key); |
| 590 return new_key.raw(); |
| 591 } else { |
| 592 return BaseIterTable::GetKey(entry); |
| 593 } |
| 594 } |
| 595 |
| 596 template<typename Key> |
| 597 RawObject* GetOrNull(const Key& key, bool* present = NULL) const { |
| 598 intptr_t entry = BaseIterTable::FindKey(key); |
| 599 if (present != NULL) { |
| 600 *present = (entry != -1); |
| 601 } |
| 602 return (entry == -1) ? Object::null() : BaseIterTable::GetKey(entry); |
| 603 } |
| 604 |
527 template<typename Key> | 605 template<typename Key> |
528 bool Remove(const Key& key) const { | 606 bool Remove(const Key& key) const { |
529 intptr_t entry = BaseIterTable::FindKey(key); | 607 intptr_t entry = BaseIterTable::FindKey(key); |
530 if (entry == -1) { | 608 if (entry == -1) { |
531 return false; | 609 return false; |
532 } else { | 610 } else { |
533 BaseIterTable::DeleteEntry(entry); | 611 BaseIterTable::DeleteEntry(entry); |
534 return true; | 612 return true; |
535 } | 613 } |
536 } | 614 } |
| 615 |
| 616 protected: |
| 617 void EnsureCapacity() const { |
| 618 static const double kMaxLoadFactor = 0.75; |
| 619 HashTables::EnsureLoadFactor(0.0, kMaxLoadFactor, *this); |
| 620 } |
537 }; | 621 }; |
538 | 622 |
539 | 623 |
540 template<typename KeyTraits> | 624 template<typename KeyTraits> |
541 class UnorderedHashSet : public HashSet<UnorderedHashTable<KeyTraits, 0> > { | 625 class UnorderedHashSet : public HashSet<UnorderedHashTable<KeyTraits, 0> > { |
542 public: | 626 public: |
543 typedef HashSet<UnorderedHashTable<KeyTraits, 0> > BaseSet; | 627 typedef HashSet<UnorderedHashTable<KeyTraits, 0> > BaseSet; |
544 explicit UnorderedHashSet(Array& data) : BaseSet(data) {} | 628 explicit UnorderedHashSet(Array& data) : BaseSet(data) {} |
545 }; | 629 }; |
546 | 630 |
547 | 631 |
548 template<typename KeyTraits> | 632 template<typename KeyTraits> |
549 class EnumIndexHashSet : public HashSet<EnumIndexHashTable<KeyTraits, 0> > { | 633 class EnumIndexHashSet : public HashSet<EnumIndexHashTable<KeyTraits, 0> > { |
550 public: | 634 public: |
551 typedef HashSet<EnumIndexHashTable<KeyTraits, 0> > BaseSet; | 635 typedef HashSet<EnumIndexHashTable<KeyTraits, 0> > BaseSet; |
552 explicit EnumIndexHashSet(Array& data) : BaseSet(data) {} | 636 explicit EnumIndexHashSet(Array& data) : BaseSet(data) {} |
553 }; | 637 }; |
554 | 638 |
555 } // namespace dart | 639 } // namespace dart |
556 | 640 |
557 #endif // VM_HASH_TABLE_H_ | 641 #endif // VM_HASH_TABLE_H_ |
OLD | NEW |