| 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 |