| 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 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 // Parameters | 78 // Parameters |
| 79 // KeyTraits: defines static methods | 79 // KeyTraits: defines static methods |
| 80 // bool IsMatch(const Key& key, const Object& obj) and | 80 // bool IsMatch(const Key& key, const Object& obj) and |
| 81 // uword Hash(const Key& key) for any number of desired lookup key types. | 81 // uword Hash(const Key& key) for any number of desired lookup key types. |
| 82 // kPayloadSize: number of components of the payload in each entry. | 82 // kPayloadSize: number of components of the payload in each entry. |
| 83 // kMetaDataSize: number of elements reserved (e.g., for iteration order data). | 83 // kMetaDataSize: number of elements reserved (e.g., for iteration order data). |
| 84 template<typename KeyTraits, intptr_t kPayloadSize, intptr_t kMetaDataSize> | 84 template<typename KeyTraits, intptr_t kPayloadSize, intptr_t kMetaDataSize> |
| 85 class HashTable : public ValueObject { | 85 class HashTable : public ValueObject { |
| 86 public: | 86 public: |
| 87 typedef KeyTraits Traits; | 87 typedef KeyTraits Traits; |
| 88 // Uses the passed in handles for all handle operations. |
| 89 // 'Release' must be called at the end to obtain the final table |
| 90 // after potential growth/shrinkage. |
| 91 HashTable(Object* key, Smi* index, Array* data) |
| 92 : key_handle_(key), |
| 93 smi_handle_(index), |
| 94 data_(data), |
| 95 released_data_(NULL) {} |
| 88 // Uses 'zone' for handle allocation. 'Release' must be called at the end | 96 // Uses 'zone' for handle allocation. 'Release' must be called at the end |
| 89 // to obtain the final table after potential growth/shrinkage. | 97 // to obtain the final table after potential growth/shrinkage. |
| 90 HashTable(Zone* zone, RawArray* data) | 98 HashTable(Zone* zone, RawArray* data) |
| 91 : zone_(zone), | 99 : key_handle_(&Object::Handle(zone)), |
| 92 key_handle_(Object::Handle(zone_)), | 100 smi_handle_(&Smi::Handle(zone)), |
| 93 smi_handle_(Smi::Handle(zone_)), | 101 data_(&Array::Handle(zone, data)), |
| 94 data_(&Array::Handle(zone_, data)), | |
| 95 released_data_(NULL) {} | 102 released_data_(NULL) {} |
| 96 // Like above, except uses current zone. | |
| 97 explicit HashTable(RawArray* data) | |
| 98 : zone_(Thread::Current()->zone()), | |
| 99 key_handle_(Object::Handle(zone_)), | |
| 100 smi_handle_(Smi::Handle(zone_)), | |
| 101 data_(&Array::Handle(zone_, data)), | |
| 102 released_data_(NULL) { | |
| 103 ASSERT(!data_->IsNull()); | |
| 104 } | |
| 105 | 103 |
| 106 // Returns the final table. The handle is cleared when this HashTable is | 104 // Returns the final table. The handle is cleared when this HashTable is |
| 107 // destroyed. | 105 // destroyed. |
| 108 Array& Release() { | 106 Array& Release() { |
| 109 ASSERT(data_ != NULL); | 107 ASSERT(data_ != NULL); |
| 110 ASSERT(released_data_ == NULL); | 108 ASSERT(released_data_ == NULL); |
| 111 // Ensure that no methods are called after 'Release'. | 109 // Ensure that no methods are called after 'Release'. |
| 112 released_data_ = data_; | 110 released_data_ = data_; |
| 113 data_ = NULL; | 111 data_ = NULL; |
| 114 return *released_data_; | 112 return *released_data_; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 127 static intptr_t ArrayLengthForNumOccupied(intptr_t num_occupied) { | 125 static intptr_t ArrayLengthForNumOccupied(intptr_t num_occupied) { |
| 128 // The current invariant requires at least one unoccupied entry. | 126 // The current invariant requires at least one unoccupied entry. |
| 129 // TODO(koda): Adjust if moving to quadratic probing. | 127 // TODO(koda): Adjust if moving to quadratic probing. |
| 130 intptr_t num_entries = num_occupied + 1; | 128 intptr_t num_entries = num_occupied + 1; |
| 131 return kFirstKeyIndex + (kEntrySize * num_entries); | 129 return kFirstKeyIndex + (kEntrySize * num_entries); |
| 132 } | 130 } |
| 133 | 131 |
| 134 // Initializes an empty table. | 132 // Initializes an empty table. |
| 135 void Initialize() const { | 133 void Initialize() const { |
| 136 ASSERT(data_->Length() >= ArrayLengthForNumOccupied(0)); | 134 ASSERT(data_->Length() >= ArrayLengthForNumOccupied(0)); |
| 137 smi_handle_ = Smi::New(0); | 135 *smi_handle_ = Smi::New(0); |
| 138 data_->SetAt(kOccupiedEntriesIndex, smi_handle_); | 136 data_->SetAt(kOccupiedEntriesIndex, *smi_handle_); |
| 139 data_->SetAt(kDeletedEntriesIndex, smi_handle_); | 137 data_->SetAt(kDeletedEntriesIndex, *smi_handle_); |
| 140 | 138 |
| 141 NOT_IN_PRODUCT( | 139 NOT_IN_PRODUCT( |
| 142 data_->SetAt(kNumGrowsIndex, smi_handle_); | 140 data_->SetAt(kNumGrowsIndex, *smi_handle_); |
| 143 data_->SetAt(kNumLT5LookupsIndex, smi_handle_); | 141 data_->SetAt(kNumLT5LookupsIndex, *smi_handle_); |
| 144 data_->SetAt(kNumLT25LookupsIndex, smi_handle_); | 142 data_->SetAt(kNumLT25LookupsIndex, *smi_handle_); |
| 145 data_->SetAt(kNumGT25LookupsIndex, smi_handle_); | 143 data_->SetAt(kNumGT25LookupsIndex, *smi_handle_); |
| 146 ) // !PRODUCT | 144 ) // !PRODUCT |
| 147 | 145 |
| 148 for (intptr_t i = kHeaderSize; i < data_->Length(); ++i) { | 146 for (intptr_t i = kHeaderSize; i < data_->Length(); ++i) { |
| 149 data_->SetAt(i, Object::sentinel()); | 147 data_->SetAt(i, Object::sentinel()); |
| 150 } | 148 } |
| 151 } | 149 } |
| 152 | 150 |
| 153 // Returns whether 'key' matches any key in the table. | 151 // Returns whether 'key' matches any key in the table. |
| 154 template<typename Key> | 152 template<typename Key> |
| 155 bool ContainsKey(const Key& key) const { | 153 bool ContainsKey(const Key& key) const { |
| 156 return FindKey(key) != -1; | 154 return FindKey(key) != -1; |
| 157 } | 155 } |
| 158 | 156 |
| 159 // Returns the entry that matches 'key', or -1 if none exists. | 157 // Returns the entry that matches 'key', or -1 if none exists. |
| 160 template<typename Key> | 158 template<typename Key> |
| 161 intptr_t FindKey(const Key& key) const { | 159 intptr_t FindKey(const Key& key) const { |
| 162 const intptr_t num_entries = NumEntries(); | 160 const intptr_t num_entries = NumEntries(); |
| 163 ASSERT(NumOccupied() < num_entries); | 161 ASSERT(NumOccupied() < num_entries); |
| 164 // TODO(koda): Add salt. | 162 // TODO(koda): Add salt. |
| 165 NOT_IN_PRODUCT(intptr_t collisions = 0;) | 163 NOT_IN_PRODUCT(intptr_t collisions = 0;) |
| 166 uword hash = KeyTraits::Hash(key); | 164 uword hash = KeyTraits::Hash(key); |
| 167 intptr_t probe = hash % num_entries; | 165 intptr_t probe = hash % num_entries; |
| 168 // TODO(koda): Consider quadratic probing. | 166 // TODO(koda): Consider quadratic probing. |
| 169 while (true) { | 167 while (true) { |
| 170 if (IsUnused(probe)) { | 168 if (IsUnused(probe)) { |
| 171 NOT_IN_PRODUCT(UpdateCollisions(collisions);) | 169 NOT_IN_PRODUCT(UpdateCollisions(collisions);) |
| 172 return -1; | 170 return -1; |
| 173 } else if (!IsDeleted(probe)) { | 171 } else if (!IsDeleted(probe)) { |
| 174 key_handle_ = GetKey(probe); | 172 *key_handle_ = GetKey(probe); |
| 175 if (KeyTraits::IsMatch(key, key_handle_)) { | 173 if (KeyTraits::IsMatch(key, *key_handle_)) { |
| 176 NOT_IN_PRODUCT(UpdateCollisions(collisions);) | 174 NOT_IN_PRODUCT(UpdateCollisions(collisions);) |
| 177 return probe; | 175 return probe; |
| 178 } | 176 } |
| 179 NOT_IN_PRODUCT(collisions += 1;) | 177 NOT_IN_PRODUCT(collisions += 1;) |
| 180 } | 178 } |
| 181 // Advance probe. | 179 // Advance probe. |
| 182 probe++; | 180 probe++; |
| 183 probe = (probe == num_entries) ? 0 : probe; | 181 probe = (probe == num_entries) ? 0 : probe; |
| 184 } | 182 } |
| 185 UNREACHABLE(); | 183 UNREACHABLE(); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 203 while (true) { | 201 while (true) { |
| 204 if (IsUnused(probe)) { | 202 if (IsUnused(probe)) { |
| 205 *entry = (deleted != -1) ? deleted : probe; | 203 *entry = (deleted != -1) ? deleted : probe; |
| 206 NOT_IN_PRODUCT(UpdateCollisions(collisions);) | 204 NOT_IN_PRODUCT(UpdateCollisions(collisions);) |
| 207 return false; | 205 return false; |
| 208 } else if (IsDeleted(probe)) { | 206 } else if (IsDeleted(probe)) { |
| 209 if (deleted == -1) { | 207 if (deleted == -1) { |
| 210 deleted = probe; | 208 deleted = probe; |
| 211 } | 209 } |
| 212 } else { | 210 } else { |
| 213 key_handle_ = GetKey(probe); | 211 *key_handle_ = GetKey(probe); |
| 214 if (KeyTraits::IsMatch(key, key_handle_)) { | 212 if (KeyTraits::IsMatch(key, *key_handle_)) { |
| 215 *entry = probe; | 213 *entry = probe; |
| 216 NOT_IN_PRODUCT(UpdateCollisions(collisions);) | 214 NOT_IN_PRODUCT(UpdateCollisions(collisions);) |
| 217 return true; | 215 return true; |
| 218 } | 216 } |
| 219 NOT_IN_PRODUCT(collisions += 1;) | 217 NOT_IN_PRODUCT(collisions += 1;) |
| 220 } | 218 } |
| 221 // Advance probe. | 219 // Advance probe. |
| 222 probe++; | 220 probe++; |
| 223 probe = (probe == num_entries) ? 0 : probe; | 221 probe = (probe == num_entries) ? 0 : probe; |
| 224 } | 222 } |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 intptr_t NumUnused() const { | 280 intptr_t NumUnused() const { |
| 283 return NumEntries() - NumOccupied() - NumDeleted(); | 281 return NumEntries() - NumOccupied() - NumDeleted(); |
| 284 } | 282 } |
| 285 intptr_t NumOccupied() const { | 283 intptr_t NumOccupied() const { |
| 286 return GetSmiValueAt(kOccupiedEntriesIndex); | 284 return GetSmiValueAt(kOccupiedEntriesIndex); |
| 287 } | 285 } |
| 288 intptr_t NumDeleted() const { | 286 intptr_t NumDeleted() const { |
| 289 return GetSmiValueAt(kDeletedEntriesIndex); | 287 return GetSmiValueAt(kDeletedEntriesIndex); |
| 290 } | 288 } |
| 291 Object& KeyHandle() const { | 289 Object& KeyHandle() const { |
| 292 return key_handle_; | 290 return *key_handle_; |
| 293 } | 291 } |
| 294 Smi& SmiHandle() const { | 292 Smi& SmiHandle() const { |
| 295 return smi_handle_; | 293 return *smi_handle_; |
| 296 } | 294 } |
| 297 | 295 |
| 298 NOT_IN_PRODUCT( | 296 NOT_IN_PRODUCT( |
| 299 intptr_t NumGrows() const { | 297 intptr_t NumGrows() const { |
| 300 return GetSmiValueAt(kNumGrowsIndex); | 298 return GetSmiValueAt(kNumGrowsIndex); |
| 301 } | 299 } |
| 302 intptr_t NumLT5Collisions() const { | 300 intptr_t NumLT5Collisions() const { |
| 303 return GetSmiValueAt(kNumLT5LookupsIndex); | 301 return GetSmiValueAt(kNumLT5LookupsIndex); |
| 304 } | 302 } |
| 305 intptr_t NumLT25Collisions() const { | 303 intptr_t NumLT25Collisions() const { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 RawObject* InternalGetKey(intptr_t entry) const { | 367 RawObject* InternalGetKey(intptr_t entry) const { |
| 370 return data_->At(KeyIndex(entry)); | 368 return data_->At(KeyIndex(entry)); |
| 371 } | 369 } |
| 372 | 370 |
| 373 void InternalSetKey(intptr_t entry, const Object& key) const { | 371 void InternalSetKey(intptr_t entry, const Object& key) const { |
| 374 data_->SetAt(KeyIndex(entry), key); | 372 data_->SetAt(KeyIndex(entry), key); |
| 375 } | 373 } |
| 376 | 374 |
| 377 intptr_t GetSmiValueAt(intptr_t index) const { | 375 intptr_t GetSmiValueAt(intptr_t index) const { |
| 378 ASSERT(!data_->IsNull()); | 376 ASSERT(!data_->IsNull()); |
| 379 ASSERT(Object::Handle(zone(), data_->At(index)).IsSmi()); | 377 ASSERT(!data_->At(index)->IsHeapObject()); |
| 380 return Smi::Value(Smi::RawCast(data_->At(index))); | 378 return Smi::Value(Smi::RawCast(data_->At(index))); |
| 381 } | 379 } |
| 382 | 380 |
| 383 void SetSmiValueAt(intptr_t index, intptr_t value) const { | 381 void SetSmiValueAt(intptr_t index, intptr_t value) const { |
| 384 smi_handle_ = Smi::New(value); | 382 *smi_handle_ = Smi::New(value); |
| 385 data_->SetAt(index, smi_handle_); | 383 data_->SetAt(index, *smi_handle_); |
| 386 } | 384 } |
| 387 | 385 |
| 388 void AdjustSmiValueAt(intptr_t index, intptr_t delta) const { | 386 void AdjustSmiValueAt(intptr_t index, intptr_t delta) const { |
| 389 SetSmiValueAt(index, (GetSmiValueAt(index) + delta)); | 387 SetSmiValueAt(index, (GetSmiValueAt(index) + delta)); |
| 390 } | 388 } |
| 391 | 389 |
| 392 Zone* zone() const { return zone_; } | 390 Object* key_handle_; |
| 393 | 391 Smi* smi_handle_; |
| 394 Zone* zone_; | |
| 395 Object& key_handle_; | |
| 396 Smi& smi_handle_; | |
| 397 // Exactly one of these is non-NULL, depending on whether Release was called. | 392 // Exactly one of these is non-NULL, depending on whether Release was called. |
| 398 Array* data_; | 393 Array* data_; |
| 399 Array* released_data_; | 394 Array* released_data_; |
| 400 | 395 |
| 401 friend class HashTables; | 396 friend class HashTables; |
| 402 }; | 397 }; |
| 403 | 398 |
| 404 | 399 |
| 405 // Table with unspecified iteration order. No payload overhead or metadata. | 400 // Table with unspecified iteration order. No payload overhead or metadata. |
| 406 template<typename KeyTraits, intptr_t kUserPayloadSize> | 401 template<typename KeyTraits, intptr_t kUserPayloadSize> |
| 407 class UnorderedHashTable : public HashTable<KeyTraits, kUserPayloadSize, 0> { | 402 class UnorderedHashTable : public HashTable<KeyTraits, kUserPayloadSize, 0> { |
| 408 public: | 403 public: |
| 409 typedef HashTable<KeyTraits, kUserPayloadSize, 0> BaseTable; | 404 typedef HashTable<KeyTraits, kUserPayloadSize, 0> BaseTable; |
| 410 static const intptr_t kPayloadSize = kUserPayloadSize; | 405 static const intptr_t kPayloadSize = kUserPayloadSize; |
| 411 explicit UnorderedHashTable(RawArray* data) : BaseTable(data) {} | 406 explicit UnorderedHashTable(RawArray* data) |
| 412 UnorderedHashTable(Zone* zone, RawArray* data) | 407 : BaseTable(Thread::Current()->zone(), data) {} |
| 413 : BaseTable(zone, data) {} | 408 UnorderedHashTable(Zone* zone, RawArray* data) : BaseTable(zone, data) {} |
| 409 UnorderedHashTable(Object* key, Smi* value, Array* data) |
| 410 : BaseTable(key, value, data) {} |
| 414 // Note: Does not check for concurrent modification. | 411 // Note: Does not check for concurrent modification. |
| 415 class Iterator { | 412 class Iterator { |
| 416 public: | 413 public: |
| 417 explicit Iterator(const UnorderedHashTable* table) | 414 explicit Iterator(const UnorderedHashTable* table) |
| 418 : table_(table), entry_(-1) {} | 415 : table_(table), entry_(-1) {} |
| 419 bool MoveNext() { | 416 bool MoveNext() { |
| 420 while (entry_ < (table_->NumEntries() - 1)) { | 417 while (entry_ < (table_->NumEntries() - 1)) { |
| 421 ++entry_; | 418 ++entry_; |
| 422 if (table_->IsOccupied(entry_)) { | 419 if (table_->IsOccupied(entry_)) { |
| 423 return true; | 420 return true; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 440 | 437 |
| 441 // Table with insertion order, using one payload component for the enumeration | 438 // Table with insertion order, using one payload component for the enumeration |
| 442 // index, and one metadata element for the next enumeration index. | 439 // index, and one metadata element for the next enumeration index. |
| 443 template<typename KeyTraits, intptr_t kUserPayloadSize> | 440 template<typename KeyTraits, intptr_t kUserPayloadSize> |
| 444 class EnumIndexHashTable | 441 class EnumIndexHashTable |
| 445 : public HashTable<KeyTraits, kUserPayloadSize + 1, 1> { | 442 : public HashTable<KeyTraits, kUserPayloadSize + 1, 1> { |
| 446 public: | 443 public: |
| 447 typedef HashTable<KeyTraits, kUserPayloadSize + 1, 1> BaseTable; | 444 typedef HashTable<KeyTraits, kUserPayloadSize + 1, 1> BaseTable; |
| 448 static const intptr_t kPayloadSize = kUserPayloadSize; | 445 static const intptr_t kPayloadSize = kUserPayloadSize; |
| 449 static const intptr_t kNextEnumIndex = BaseTable::kMetaDataIndex; | 446 static const intptr_t kNextEnumIndex = BaseTable::kMetaDataIndex; |
| 447 EnumIndexHashTable(Object* key, Smi* value, Array* data) |
| 448 : BaseTable(key, value, data) {} |
| 450 EnumIndexHashTable(Zone* zone, RawArray* data) | 449 EnumIndexHashTable(Zone* zone, RawArray* data) |
| 451 : BaseTable(zone, data) {} | 450 : BaseTable(zone, data) {} |
| 452 explicit EnumIndexHashTable(RawArray* data) : BaseTable(data) {} | 451 explicit EnumIndexHashTable(RawArray* data) |
| 452 : BaseTable(Thread::Current()->zone(), data) {} |
| 453 // Note: Does not check for concurrent modification. | 453 // Note: Does not check for concurrent modification. |
| 454 class Iterator { | 454 class Iterator { |
| 455 public: | 455 public: |
| 456 explicit Iterator(const EnumIndexHashTable* table) : index_(-1) { | 456 explicit Iterator(const EnumIndexHashTable* table) : index_(-1) { |
| 457 // TODO(koda): Use GrowableArray after adding stateful comparator support. | 457 // TODO(koda): Use GrowableArray after adding stateful comparator support. |
| 458 std::map<intptr_t, intptr_t> enum_to_entry; | 458 std::map<intptr_t, intptr_t> enum_to_entry; |
| 459 for (intptr_t i = 0; i < table->NumEntries(); ++i) { | 459 for (intptr_t i = 0; i < table->NumEntries(); ++i) { |
| 460 if (table->IsOccupied(i)) { | 460 if (table->IsOccupied(i)) { |
| 461 intptr_t enum_index = | 461 intptr_t enum_index = |
| 462 table->GetSmiValueAt(table->PayloadIndex(i, kPayloadSize)); | 462 table->GetSmiValueAt(table->PayloadIndex(i, kPayloadSize)); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 502 // No extra book-keeping needed for DeleteEntry. | 502 // No extra book-keeping needed for DeleteEntry. |
| 503 }; | 503 }; |
| 504 | 504 |
| 505 | 505 |
| 506 class HashTables : public AllStatic { | 506 class HashTables : public AllStatic { |
| 507 public: | 507 public: |
| 508 // Allocates and initializes a table. | 508 // Allocates and initializes a table. |
| 509 template<typename Table> | 509 template<typename Table> |
| 510 static RawArray* New(intptr_t initial_capacity, | 510 static RawArray* New(intptr_t initial_capacity, |
| 511 Heap::Space space = Heap::kNew) { | 511 Heap::Space space = Heap::kNew) { |
| 512 Table table(Array::New( | 512 Table table(Thread::Current()->zone(), Array::New( |
| 513 Table::ArrayLengthForNumOccupied(initial_capacity), space)); | 513 Table::ArrayLengthForNumOccupied(initial_capacity), space)); |
| 514 table.Initialize(); | 514 table.Initialize(); |
| 515 return table.Release().raw(); | 515 return table.Release().raw(); |
| 516 } | 516 } |
| 517 | 517 |
| 518 template<typename Table> | 518 template<typename Table> |
| 519 static RawArray* New(const Array& array) { | 519 static RawArray* New(const Array& array) { |
| 520 Table table(array.raw()); | 520 Table table(Thread::Current()->zone(), array.raw()); |
| 521 table.Initialize(); | 521 table.Initialize(); |
| 522 return table.Release().raw(); | 522 return table.Release().raw(); |
| 523 } | 523 } |
| 524 | 524 |
| 525 // Clears 'to' and inserts all elements from 'from', in iteration order. | 525 // Clears 'to' and inserts all elements from 'from', in iteration order. |
| 526 // The tables must have the same user payload size. | 526 // The tables must have the same user payload size. |
| 527 template<typename From, typename To> | 527 template<typename From, typename To> |
| 528 static void Copy(const From& from, const To& to) { | 528 static void Copy(const From& from, const To& to) { |
| 529 COMPILE_ASSERT(From::kPayloadSize == To::kPayloadSize); | 529 COMPILE_ASSERT(From::kPayloadSize == To::kPayloadSize); |
| 530 to.Initialize(); | 530 to.Initialize(); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 583 } | 583 } |
| 584 } | 584 } |
| 585 return result.raw(); | 585 return result.raw(); |
| 586 } | 586 } |
| 587 }; | 587 }; |
| 588 | 588 |
| 589 | 589 |
| 590 template<typename BaseIterTable> | 590 template<typename BaseIterTable> |
| 591 class HashMap : public BaseIterTable { | 591 class HashMap : public BaseIterTable { |
| 592 public: | 592 public: |
| 593 explicit HashMap(RawArray* data) : BaseIterTable(data) {} | 593 explicit HashMap(RawArray* data) |
| 594 : BaseIterTable(Thread::Current()->zone(), data) {} |
| 594 HashMap(Zone* zone, RawArray* data) : BaseIterTable(zone, data) {} | 595 HashMap(Zone* zone, RawArray* data) : BaseIterTable(zone, data) {} |
| 596 HashMap(Object* key, Smi* value, Array* data) |
| 597 : BaseIterTable(key, value, data) {} |
| 595 template<typename Key> | 598 template<typename Key> |
| 596 RawObject* GetOrNull(const Key& key, bool* present = NULL) const { | 599 RawObject* GetOrNull(const Key& key, bool* present = NULL) const { |
| 597 intptr_t entry = BaseIterTable::FindKey(key); | 600 intptr_t entry = BaseIterTable::FindKey(key); |
| 598 if (present != NULL) { | 601 if (present != NULL) { |
| 599 *present = (entry != -1); | 602 *present = (entry != -1); |
| 600 } | 603 } |
| 601 return (entry == -1) ? Object::null() : BaseIterTable::GetPayload(entry, 0); | 604 return (entry == -1) ? Object::null() : BaseIterTable::GetPayload(entry, 0); |
| 602 } | 605 } |
| 603 bool UpdateOrInsert(const Object& key, const Object& value) const { | 606 bool UpdateOrInsert(const Object& key, const Object& value) const { |
| 604 EnsureCapacity(); | 607 EnsureCapacity(); |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 669 // We currently never shrink. | 672 // We currently never shrink. |
| 670 HashTables::EnsureLoadFactor(0.0, kMaxLoadFactor, *this); | 673 HashTables::EnsureLoadFactor(0.0, kMaxLoadFactor, *this); |
| 671 } | 674 } |
| 672 }; | 675 }; |
| 673 | 676 |
| 674 | 677 |
| 675 template<typename KeyTraits> | 678 template<typename KeyTraits> |
| 676 class UnorderedHashMap : public HashMap<UnorderedHashTable<KeyTraits, 1> > { | 679 class UnorderedHashMap : public HashMap<UnorderedHashTable<KeyTraits, 1> > { |
| 677 public: | 680 public: |
| 678 typedef HashMap<UnorderedHashTable<KeyTraits, 1> > BaseMap; | 681 typedef HashMap<UnorderedHashTable<KeyTraits, 1> > BaseMap; |
| 679 explicit UnorderedHashMap(RawArray* data) : BaseMap(data) {} | 682 explicit UnorderedHashMap(RawArray* data) |
| 683 : BaseMap(Thread::Current()->zone(), data) {} |
| 680 UnorderedHashMap(Zone* zone, RawArray* data) : BaseMap(zone, data) {} | 684 UnorderedHashMap(Zone* zone, RawArray* data) : BaseMap(zone, data) {} |
| 685 UnorderedHashMap(Object* key, Smi* value, Array* data) |
| 686 : BaseMap(key, value, data) {} |
| 681 }; | 687 }; |
| 682 | 688 |
| 683 | 689 |
| 684 template<typename KeyTraits> | 690 template<typename KeyTraits> |
| 685 class EnumIndexHashMap : public HashMap<EnumIndexHashTable<KeyTraits, 1> > { | 691 class EnumIndexHashMap : public HashMap<EnumIndexHashTable<KeyTraits, 1> > { |
| 686 public: | 692 public: |
| 687 typedef HashMap<EnumIndexHashTable<KeyTraits, 1> > BaseMap; | 693 typedef HashMap<EnumIndexHashTable<KeyTraits, 1> > BaseMap; |
| 688 explicit EnumIndexHashMap(RawArray* data) : BaseMap(data) {} | 694 explicit EnumIndexHashMap(RawArray* data) |
| 695 : BaseMap(Thread::Current()->zone(), data) {} |
| 689 EnumIndexHashMap(Zone* zone, RawArray* data) : BaseMap(zone, data) {} | 696 EnumIndexHashMap(Zone* zone, RawArray* data) : BaseMap(zone, data) {} |
| 697 EnumIndexHashMap(Object* key, Smi* value, Array* data) |
| 698 : BaseMap(key, value, data) {} |
| 690 }; | 699 }; |
| 691 | 700 |
| 692 | 701 |
| 693 template<typename BaseIterTable> | 702 template<typename BaseIterTable> |
| 694 class HashSet : public BaseIterTable { | 703 class HashSet : public BaseIterTable { |
| 695 public: | 704 public: |
| 696 explicit HashSet(RawArray* data) : BaseIterTable(data) {} | 705 explicit HashSet(RawArray* data) |
| 706 : BaseIterTable(Thread::Current()->zone(), data) {} |
| 697 HashSet(Zone* zone, RawArray* data) : BaseIterTable(zone, data) {} | 707 HashSet(Zone* zone, RawArray* data) : BaseIterTable(zone, data) {} |
| 708 HashSet(Object* key, Smi* value, Array* data) |
| 709 : BaseIterTable(key, value, data) {} |
| 698 bool Insert(const Object& key) { | 710 bool Insert(const Object& key) { |
| 699 EnsureCapacity(); | 711 EnsureCapacity(); |
| 700 intptr_t entry = -1; | 712 intptr_t entry = -1; |
| 701 bool present = BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry); | 713 bool present = BaseIterTable::FindKeyOrDeletedOrUnused(key, &entry); |
| 702 if (!present) { | 714 if (!present) { |
| 703 BaseIterTable::InsertKey(entry, key); | 715 BaseIterTable::InsertKey(entry, key); |
| 704 } | 716 } |
| 705 return present; | 717 return present; |
| 706 } | 718 } |
| 707 | 719 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 763 // We currently never shrink. | 775 // We currently never shrink. |
| 764 HashTables::EnsureLoadFactor(0.0, kMaxLoadFactor, *this); | 776 HashTables::EnsureLoadFactor(0.0, kMaxLoadFactor, *this); |
| 765 } | 777 } |
| 766 }; | 778 }; |
| 767 | 779 |
| 768 | 780 |
| 769 template<typename KeyTraits> | 781 template<typename KeyTraits> |
| 770 class UnorderedHashSet : public HashSet<UnorderedHashTable<KeyTraits, 0> > { | 782 class UnorderedHashSet : public HashSet<UnorderedHashTable<KeyTraits, 0> > { |
| 771 public: | 783 public: |
| 772 typedef HashSet<UnorderedHashTable<KeyTraits, 0> > BaseSet; | 784 typedef HashSet<UnorderedHashTable<KeyTraits, 0> > BaseSet; |
| 773 explicit UnorderedHashSet(RawArray* data) : BaseSet(data) { | 785 explicit UnorderedHashSet(RawArray* data) |
| 786 : BaseSet(Thread::Current()->zone(), data) { |
| 774 ASSERT(data != Array::null()); | 787 ASSERT(data != Array::null()); |
| 775 } | 788 } |
| 776 UnorderedHashSet(Zone* zone, RawArray* data) : BaseSet(zone, data) {} | 789 UnorderedHashSet(Zone* zone, RawArray* data) : BaseSet(zone, data) {} |
| 790 UnorderedHashSet(Object* key, Smi* value, Array* data) |
| 791 : BaseSet(key, value, data) {} |
| 777 }; | 792 }; |
| 778 | 793 |
| 779 | 794 |
| 780 template<typename KeyTraits> | 795 template<typename KeyTraits> |
| 781 class EnumIndexHashSet : public HashSet<EnumIndexHashTable<KeyTraits, 0> > { | 796 class EnumIndexHashSet : public HashSet<EnumIndexHashTable<KeyTraits, 0> > { |
| 782 public: | 797 public: |
| 783 typedef HashSet<EnumIndexHashTable<KeyTraits, 0> > BaseSet; | 798 typedef HashSet<EnumIndexHashTable<KeyTraits, 0> > BaseSet; |
| 784 explicit EnumIndexHashSet(RawArray* data) : BaseSet(data) {} | 799 explicit EnumIndexHashSet(RawArray* data) |
| 800 : BaseSet(Thread::Current()->zone(), data) {} |
| 785 EnumIndexHashSet(Zone* zone, RawArray* data) : BaseSet(zone, data) {} | 801 EnumIndexHashSet(Zone* zone, RawArray* data) : BaseSet(zone, data) {} |
| 802 EnumIndexHashSet(Object* key, Smi* value, Array* data) |
| 803 : BaseSet(key, value, data) {} |
| 786 }; | 804 }; |
| 787 | 805 |
| 788 } // namespace dart | 806 } // namespace dart |
| 789 | 807 |
| 790 #endif // VM_HASH_TABLE_H_ | 808 #endif // VM_HASH_TABLE_H_ |
| OLD | NEW |