Index: runtime/vm/object.h |
diff --git a/runtime/vm/object.h b/runtime/vm/object.h |
index 1accd627c857483bc05cd8b3cf631d4b970ea748..1d16768ca97aac8a0dae99cc9c6ea114fc2a1cea 100644 |
--- a/runtime/vm/object.h |
+++ b/runtime/vm/object.h |
@@ -7233,6 +7233,56 @@ class LinkedHashMap : public Instance { |
return OFFSET_OF(RawLinkedHashMap, deleted_keys_); |
} |
+ intptr_t Length() const { |
+ intptr_t used = Smi::Value(raw_ptr()->used_data_); |
+ intptr_t deleted = Smi::Value(raw_ptr()->deleted_keys_); |
+ return (used >> 1) - deleted; |
+ } |
+ |
+ // This iterator differs somewhat from its Dart counterpart (_CompactIterator |
+ // in runtime/lib/compact_hash.dart): |
+ // - There are no checks for concurrent modifications. |
+ // - Accessing a key or value before the first call to MoveNext and after |
+ // MoveNext returns false will result in crashes. |
+ class Iterator : ValueObject { |
+ public: |
+ explicit Iterator(const LinkedHashMap& map) |
+ : map_(map), |
+ data_(Array::Handle(map.data())), |
+ scratch_(Object::Handle()), |
+ offset_(-2), |
+ length_(Smi::Value(map.used_data())) {} |
+ |
+ bool MoveNext() { |
+ while (true) { |
+ offset_ += 2; |
+ if (offset_ >= length_) { |
+ return false; |
+ } |
+ scratch_ = data_.At(offset_); |
+ if (scratch_.raw() != data_.raw()) { |
+ // Slot is not deleted (self-reference indicates deletion). |
+ return true; |
+ } |
+ } |
+ } |
+ |
+ RawObject* CurrentKey() const { |
+ return data_.At(offset_); |
+ } |
+ |
+ RawObject* CurrentValue() const { |
+ return data_.At(offset_ + 1); |
+ } |
+ |
+ private: |
+ const LinkedHashMap& map_; |
+ const Array& data_; |
+ Object& scratch_; |
+ intptr_t offset_; |
+ const intptr_t length_; |
+ }; |
+ |
private: |
FINAL_HEAP_OBJECT_IMPLEMENTATION(LinkedHashMap, Instance); |