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 |