| 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. | |
| 9 // TODO(koda): Remove these dependencies before using in production. | |
| 10 #include <map> | |
| 11 #include <vector> | |
| 12 | |
| 13 #include "platform/assert.h" | 8 #include "platform/assert.h" |
| 14 #include "vm/object.h" | 9 #include "vm/object.h" |
| 15 | 10 |
| 16 namespace dart { | 11 namespace dart { |
| 17 | 12 |
| 18 // OVERVIEW: | 13 // OVERVIEW: |
| 19 // | 14 // |
| 20 // Hash maps and hash sets all use RawArray as backing storage. At the lowest | 15 // Hash maps and hash sets all use RawArray as backing storage. At the lowest |
| 21 // level is a generic open-addressing table that supports deletion. | 16 // level is a generic open-addressing table that supports deletion. |
| 22 // - HashTable | 17 // - HashTable |
| 23 // The next layer provides ordering and iteration functionality: | 18 // The next layer provides ordering and iteration functionality: |
| 24 // - UnorderedHashTable | 19 // - UnorderedHashTable |
| 25 // - EnumIndexHashTable | |
| 26 // - LinkedListHashTable (TODO(koda): Implement.) | 20 // - LinkedListHashTable (TODO(koda): Implement.) |
| 27 // The utility class HashTables handles growth and conversion (e.g., converting | 21 // The utility class HashTables handles growth and conversion. |
| 28 // a compact EnumIndexHashTable to an iteration-efficient LinkedListHashTable). | |
| 29 // The next layer fixes the payload size and provides a natural interface: | 22 // The next layer fixes the payload size and provides a natural interface: |
| 30 // - HashMap | 23 // - HashMap |
| 31 // - HashSet | 24 // - HashSet |
| 32 // Combining either of these with an iteration strategy, we get the templates | 25 // Combining either of these with an iteration strategy, we get the templates |
| 33 // intended for use outside this file: | 26 // intended for use outside this file: |
| 34 // - UnorderedHashMap | 27 // - UnorderedHashMap |
| 35 // - EnumIndexHashMap | |
| 36 // - LinkedListHashMap | 28 // - LinkedListHashMap |
| 37 // - UnorderedHashSet | 29 // - UnorderedHashSet |
| 38 // - EnumIndexHashSet | |
| 39 // - LinkedListHashSet | 30 // - LinkedListHashSet |
| 40 // Each of these can be finally specialized with KeyTraits to support any set of | 31 // Each of these can be finally specialized with KeyTraits to support any set of |
| 41 // lookup key types (e.g., look up a char* in a set of String objects), and | 32 // lookup key types (e.g., look up a char* in a set of String objects), and |
| 42 // any equality and hash code computation. | 33 // any equality and hash code computation. |
| 43 // | 34 // |
| 44 // The classes all wrap an Array handle, and methods like HashSet::Insert can | 35 // The classes all wrap an Array handle, and methods like HashSet::Insert can |
| 45 // trigger growth into a new RawArray, updating the handle. Debug mode asserts | 36 // trigger growth into a new RawArray, updating the handle. Debug mode asserts |
| 46 // that 'Release' was called once to access the final array before destruction. | 37 // that 'Release' was called once to access the final array before destruction. |
| 47 // NOTE: The handle returned by 'Release' is cleared by ~HashTable. | 38 // NOTE: The handle returned by 'Release' is cleared by ~HashTable. |
| 48 // | 39 // |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 | 419 |
| 429 private: | 420 private: |
| 430 const UnorderedHashTable* table_; | 421 const UnorderedHashTable* table_; |
| 431 intptr_t entry_; | 422 intptr_t entry_; |
| 432 }; | 423 }; |
| 433 | 424 |
| 434 // No extra book-keeping needed for Initialize, InsertKey, DeleteEntry. | 425 // No extra book-keeping needed for Initialize, InsertKey, DeleteEntry. |
| 435 }; | 426 }; |
| 436 | 427 |
| 437 | 428 |
| 438 // Table with insertion order, using one payload component for the enumeration | |
| 439 // index, and one metadata element for the next enumeration index. | |
| 440 template<typename KeyTraits, intptr_t kUserPayloadSize> | |
| 441 class EnumIndexHashTable | |
| 442 : public HashTable<KeyTraits, kUserPayloadSize + 1, 1> { | |
| 443 public: | |
| 444 typedef HashTable<KeyTraits, kUserPayloadSize + 1, 1> BaseTable; | |
| 445 static const intptr_t kPayloadSize = kUserPayloadSize; | |
| 446 static const intptr_t kNextEnumIndex = BaseTable::kMetaDataIndex; | |
| 447 EnumIndexHashTable(Object* key, Smi* value, Array* data) | |
| 448 : BaseTable(key, value, data) {} | |
| 449 EnumIndexHashTable(Zone* zone, RawArray* data) | |
| 450 : BaseTable(zone, data) {} | |
| 451 explicit EnumIndexHashTable(RawArray* data) | |
| 452 : BaseTable(Thread::Current()->zone(), data) {} | |
| 453 // Note: Does not check for concurrent modification. | |
| 454 class Iterator { | |
| 455 public: | |
| 456 explicit Iterator(const EnumIndexHashTable* table) : index_(-1) { | |
| 457 // TODO(koda): Use GrowableArray after adding stateful comparator support. | |
| 458 std::map<intptr_t, intptr_t> enum_to_entry; | |
| 459 for (intptr_t i = 0; i < table->NumEntries(); ++i) { | |
| 460 if (table->IsOccupied(i)) { | |
| 461 intptr_t enum_index = | |
| 462 table->GetSmiValueAt(table->PayloadIndex(i, kPayloadSize)); | |
| 463 enum_to_entry[enum_index] = i; | |
| 464 } | |
| 465 } | |
| 466 for (std::map<intptr_t, intptr_t>::iterator it = enum_to_entry.begin(); | |
| 467 it != enum_to_entry.end(); | |
| 468 ++it) { | |
| 469 entries_.push_back(it->second); | |
| 470 } | |
| 471 } | |
| 472 bool MoveNext() { | |
| 473 if (index_ < (static_cast<intptr_t>(entries_.size() - 1))) { | |
| 474 index_++; | |
| 475 return true; | |
| 476 } | |
| 477 return false; | |
| 478 } | |
| 479 intptr_t Current() { | |
| 480 return entries_[index_]; | |
| 481 } | |
| 482 | |
| 483 private: | |
| 484 intptr_t index_; | |
| 485 std::vector<intptr_t> entries_; | |
| 486 }; | |
| 487 | |
| 488 void Initialize() const { | |
| 489 BaseTable::Initialize(); | |
| 490 BaseTable::SetSmiValueAt(kNextEnumIndex, 0); | |
| 491 } | |
| 492 | |
| 493 void InsertKey(intptr_t entry, const Object& key) const { | |
| 494 BaseTable::InsertKey(entry, key); | |
| 495 BaseTable::SmiHandle() = | |
| 496 Smi::New(BaseTable::GetSmiValueAt(kNextEnumIndex)); | |
| 497 BaseTable::UpdatePayload(entry, kPayloadSize, BaseTable::SmiHandle()); | |
| 498 // TODO(koda): Handle possible Smi overflow from repeated insert/delete. | |
| 499 BaseTable::AdjustSmiValueAt(kNextEnumIndex, 1); | |
| 500 } | |
| 501 | |
| 502 // No extra book-keeping needed for DeleteEntry. | |
| 503 }; | |
| 504 | |
| 505 | |
| 506 class HashTables : public AllStatic { | 429 class HashTables : public AllStatic { |
| 507 public: | 430 public: |
| 508 // Allocates and initializes a table. | 431 // Allocates and initializes a table. |
| 509 template<typename Table> | 432 template<typename Table> |
| 510 static RawArray* New(intptr_t initial_capacity, | 433 static RawArray* New(intptr_t initial_capacity, |
| 511 Heap::Space space = Heap::kNew) { | 434 Heap::Space space = Heap::kNew) { |
| 512 Table table(Thread::Current()->zone(), Array::New( | 435 Table table(Thread::Current()->zone(), Array::New( |
| 513 Table::ArrayLengthForNumOccupied(initial_capacity), space)); | 436 Table::ArrayLengthForNumOccupied(initial_capacity), space)); |
| 514 table.Initialize(); | 437 table.Initialize(); |
| 515 return table.Release().raw(); | 438 return table.Release().raw(); |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 680 public: | 603 public: |
| 681 typedef HashMap<UnorderedHashTable<KeyTraits, 1> > BaseMap; | 604 typedef HashMap<UnorderedHashTable<KeyTraits, 1> > BaseMap; |
| 682 explicit UnorderedHashMap(RawArray* data) | 605 explicit UnorderedHashMap(RawArray* data) |
| 683 : BaseMap(Thread::Current()->zone(), data) {} | 606 : BaseMap(Thread::Current()->zone(), data) {} |
| 684 UnorderedHashMap(Zone* zone, RawArray* data) : BaseMap(zone, data) {} | 607 UnorderedHashMap(Zone* zone, RawArray* data) : BaseMap(zone, data) {} |
| 685 UnorderedHashMap(Object* key, Smi* value, Array* data) | 608 UnorderedHashMap(Object* key, Smi* value, Array* data) |
| 686 : BaseMap(key, value, data) {} | 609 : BaseMap(key, value, data) {} |
| 687 }; | 610 }; |
| 688 | 611 |
| 689 | 612 |
| 690 template<typename KeyTraits> | |
| 691 class EnumIndexHashMap : public HashMap<EnumIndexHashTable<KeyTraits, 1> > { | |
| 692 public: | |
| 693 typedef HashMap<EnumIndexHashTable<KeyTraits, 1> > BaseMap; | |
| 694 explicit EnumIndexHashMap(RawArray* data) | |
| 695 : BaseMap(Thread::Current()->zone(), data) {} | |
| 696 EnumIndexHashMap(Zone* zone, RawArray* data) : BaseMap(zone, data) {} | |
| 697 EnumIndexHashMap(Object* key, Smi* value, Array* data) | |
| 698 : BaseMap(key, value, data) {} | |
| 699 }; | |
| 700 | |
| 701 | |
| 702 template<typename BaseIterTable> | 613 template<typename BaseIterTable> |
| 703 class HashSet : public BaseIterTable { | 614 class HashSet : public BaseIterTable { |
| 704 public: | 615 public: |
| 705 explicit HashSet(RawArray* data) | 616 explicit HashSet(RawArray* data) |
| 706 : BaseIterTable(Thread::Current()->zone(), data) {} | 617 : BaseIterTable(Thread::Current()->zone(), data) {} |
| 707 HashSet(Zone* zone, RawArray* data) : BaseIterTable(zone, data) {} | 618 HashSet(Zone* zone, RawArray* data) : BaseIterTable(zone, data) {} |
| 708 HashSet(Object* key, Smi* value, Array* data) | 619 HashSet(Object* key, Smi* value, Array* data) |
| 709 : BaseIterTable(key, value, data) {} | 620 : BaseIterTable(key, value, data) {} |
| 710 bool Insert(const Object& key) { | 621 bool Insert(const Object& key) { |
| 711 EnsureCapacity(); | 622 EnsureCapacity(); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 784 typedef HashSet<UnorderedHashTable<KeyTraits, 0> > BaseSet; | 695 typedef HashSet<UnorderedHashTable<KeyTraits, 0> > BaseSet; |
| 785 explicit UnorderedHashSet(RawArray* data) | 696 explicit UnorderedHashSet(RawArray* data) |
| 786 : BaseSet(Thread::Current()->zone(), data) { | 697 : BaseSet(Thread::Current()->zone(), data) { |
| 787 ASSERT(data != Array::null()); | 698 ASSERT(data != Array::null()); |
| 788 } | 699 } |
| 789 UnorderedHashSet(Zone* zone, RawArray* data) : BaseSet(zone, data) {} | 700 UnorderedHashSet(Zone* zone, RawArray* data) : BaseSet(zone, data) {} |
| 790 UnorderedHashSet(Object* key, Smi* value, Array* data) | 701 UnorderedHashSet(Object* key, Smi* value, Array* data) |
| 791 : BaseSet(key, value, data) {} | 702 : BaseSet(key, value, data) {} |
| 792 }; | 703 }; |
| 793 | 704 |
| 794 | |
| 795 template<typename KeyTraits> | |
| 796 class EnumIndexHashSet : public HashSet<EnumIndexHashTable<KeyTraits, 0> > { | |
| 797 public: | |
| 798 typedef HashSet<EnumIndexHashTable<KeyTraits, 0> > BaseSet; | |
| 799 explicit EnumIndexHashSet(RawArray* data) | |
| 800 : BaseSet(Thread::Current()->zone(), data) {} | |
| 801 EnumIndexHashSet(Zone* zone, RawArray* data) : BaseSet(zone, data) {} | |
| 802 EnumIndexHashSet(Object* key, Smi* value, Array* data) | |
| 803 : BaseSet(key, value, data) {} | |
| 804 }; | |
| 805 | |
| 806 } // namespace dart | 705 } // namespace dart |
| 807 | 706 |
| 808 #endif // VM_HASH_TABLE_H_ | 707 #endif // VM_HASH_TABLE_H_ |
| OLD | NEW |