Skip to content

Commit

Permalink
[dart2js] Separate Iterables for Map.{keys,values,entries}
Browse files Browse the repository at this point in the history
The default `MapBase.entries` and `MapBase.values` maps over the keys and does lookups. It is faster to scan the data like `get keys`.

This is essentially the dart2js version of 23a98d808c0

Change-Id: I03894efda459d9a4f7f07c4c79524ba5e4d925cb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/399027
Reviewed-by: Mayank Patke <fishythefish@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
  • Loading branch information
rakudrama authored and Commit Queue committed Dec 10, 2024
1 parent a279ee1 commit 0c527e1
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 18 deletions.
12 changes: 6 additions & 6 deletions pkg/compiler/test/inference/data/map_tracer_keys.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ test1() {
theMap
/*update: Dictionary([exact=JsLinkedHashMap], key: [exact=JSString], value: [null|exact=JSNumNotInt], map: {a: [exact=JSNumNotInt], b: [exact=JSNumNotInt], c: [exact=JSNumNotInt], d: [null|exact=JSNumNotInt]})*/
['d'] = 5.5;
/*iterator: [exact=LinkedHashMapKeyIterable]*/
/*iterator: [exact=LinkedHashMapKeysIterable]*/
/*current: [exact=LinkedHashMapKeyIterator]*/
/*moveNext: [exact=LinkedHashMapKeyIterator]*/
for (var key in theMap.
Expand Down Expand Up @@ -60,7 +60,7 @@ test2() {
theMap
/*update: Map([exact=JsLinkedHashMap], key: [exact=JSString], value: [null|exact=JSNumNotInt])*/
[aList2] = 5.5;
/*iterator: [exact=LinkedHashMapKeyIterable]*/
/*iterator: [exact=LinkedHashMapKeysIterable]*/
/*current: [exact=LinkedHashMapKeyIterator]*/
/*moveNext: [exact=LinkedHashMapKeyIterator]*/
for (var key in theMap.
Expand Down Expand Up @@ -91,7 +91,7 @@ test3() {
theMap
/*update: Dictionary([exact=JsLinkedHashMap], key: [exact=JSString], value: Union(null, [exact=JSExtendableArray], [exact=JSNumNotInt]), map: {a: [exact=JSNumNotInt], b: [exact=JSNumNotInt], c: [exact=JSNumNotInt], d: Container([null|exact=JSExtendableArray], element: [exact=JSUInt31], length: 1)})*/
['d'] = aList3;
/*iterator: [exact=LinkedHashMapKeyIterable]*/
/*iterator: [exact=LinkedHashMapKeysIterable]*/
/*current: [exact=LinkedHashMapKeyIterator]*/
/*moveNext: [exact=LinkedHashMapKeyIterator]*/
for (var key in theMap.
Expand Down Expand Up @@ -119,7 +119,7 @@ consume4(
/*member: test4:[null]*/
test4() {
var theMap = {'a': 2.2, 'b': 3.3, 'c': 4.4, 'd': 5.5};
/*iterator: [exact=LinkedHashMapKeyIterable]*/
/*iterator: [exact=LinkedHashMapKeysIterable]*/
/*current: [exact=LinkedHashMapKeyIterator]*/
/*moveNext: [exact=LinkedHashMapKeyIterator]*/
for (var key in theMap.
Expand Down Expand Up @@ -147,7 +147,7 @@ consume5(
/*member: test5:[null]*/
test5() {
var theMap = {'a': 2.2, 'b': 3.3, 'c': 4.4, aList5: 5.5};
/*iterator: [exact=LinkedHashMapKeyIterable]*/
/*iterator: [exact=LinkedHashMapKeysIterable]*/
/*current: [exact=LinkedHashMapKeyIterator]*/
/*moveNext: [exact=LinkedHashMapKeyIterator]*/
for (var key in theMap.
Expand All @@ -174,7 +174,7 @@ consume6(
/*member: test6:[null]*/
test6() {
var theMap = {'a': 2.2, 'b': 3.3, 'c': 4.4, 'd': aList6};
/*iterator: [exact=LinkedHashMapKeyIterable]*/
/*iterator: [exact=LinkedHashMapKeysIterable]*/
/*current: [exact=LinkedHashMapKeyIterator]*/
/*moveNext: [exact=LinkedHashMapKeyIterator]*/
for (var key in theMap.
Expand Down
117 changes: 105 additions & 12 deletions sdk/lib/_internal/js_runtime/lib/linked_hash_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,11 @@ class JsLinkedHashMap<K, V> extends MapBase<K, V>
bool get isEmpty => _length == 0;
bool get isNotEmpty => !isEmpty;

Iterable<K> get keys {
return LinkedHashMapKeyIterable<K>(this);
}
Iterable<K> get keys => LinkedHashMapKeysIterable<K>(this);

Iterable<V> get values {
return MappedIterable<K, V>(keys, (each) => this[each] as V);
}
Iterable<V> get values => LinkedHashMapValuesIterable<V>(this);

Iterable<MapEntry<K, V>> get entries => LinkedHashMapEntriesIterable(this);

bool containsKey(Object? key) {
if (_isStringKey(key)) {
Expand Down Expand Up @@ -339,13 +337,13 @@ class LinkedHashMapCell {
LinkedHashMapCell(this.hashMapCellKey, this.hashMapCellValue);
}

class LinkedHashMapKeyIterable<E> extends EfficientLengthIterable<E>
class LinkedHashMapKeysIterable<E> extends EfficientLengthIterable<E>
implements HideEfficientLengthIterable<E> {
final JsLinkedHashMap _map;
LinkedHashMapKeyIterable(this._map);
LinkedHashMapKeysIterable(this._map);

int get length => _map._length;
bool get isEmpty => _map._length == 0;
bool get isEmpty => _map.isEmpty;

Iterator<E> get iterator {
return LinkedHashMapKeyIterator<E>(_map, _map._modifications);
Expand Down Expand Up @@ -374,9 +372,8 @@ class LinkedHashMapKeyIterator<E> implements Iterator<E> {
LinkedHashMapCell? _cell;
E? _current;

LinkedHashMapKeyIterator(this._map, this._modifications) {
_cell = _map._first;
}
LinkedHashMapKeyIterator(this._map, this._modifications)
: _cell = _map._first;

@pragma('dart2js:as:trust')
E get current => _current as E;
Expand All @@ -397,6 +394,102 @@ class LinkedHashMapKeyIterator<E> implements Iterator<E> {
}
}

class LinkedHashMapValuesIterable<E> extends EfficientLengthIterable<E>
implements HideEfficientLengthIterable<E> {
final JsLinkedHashMap _map;
LinkedHashMapValuesIterable(this._map);

int get length => _map._length;
bool get isEmpty => _map.isEmpty;

Iterator<E> get iterator {
return LinkedHashMapValueIterator<E>(_map, _map._modifications);
}

void forEach(void f(E element)) {
LinkedHashMapCell? cell = _map._first;
int modifications = _map._modifications;
while (cell != null) {
f(JS('', '#', cell.hashMapCellValue));
if (modifications != _map._modifications) {
throw ConcurrentModificationError(_map);
}
cell = cell._next;
}
}
}

class LinkedHashMapValueIterator<E> implements Iterator<E> {
final JsLinkedHashMap _map;
final int _modifications;
LinkedHashMapCell? _cell;
E? _current;

LinkedHashMapValueIterator(this._map, this._modifications)
: _cell = _map._first;

@pragma('dart2js:as:trust')
E get current => _current as E;

bool moveNext() {
if (_modifications != _map._modifications) {
throw ConcurrentModificationError(_map);
}
var cell = _cell;
if (cell == null) {
_current = null;
return false;
} else {
_current = JS('', '#', cell.hashMapCellValue);
_cell = cell._next;
return true;
}
}
}

class LinkedHashMapEntriesIterable<K, V>
extends EfficientLengthIterable<MapEntry<K, V>>
implements HideEfficientLengthIterable<MapEntry<K, V>> {
final JsLinkedHashMap _map;
LinkedHashMapEntriesIterable(this._map);

int get length => _map._length;
bool get isEmpty => _map.isEmpty;

Iterator<MapEntry<K, V>> get iterator {
return LinkedHashMapEntryIterator<K, V>(_map, _map._modifications);
}
}

class LinkedHashMapEntryIterator<K, V> implements Iterator<MapEntry<K, V>> {
final JsLinkedHashMap _map;
final int _modifications;
LinkedHashMapCell? _cell;
MapEntry<K, V>? _current;

LinkedHashMapEntryIterator(this._map, this._modifications)
: _cell = _map._first;

MapEntry<K, V> get current => _current!;

bool moveNext() {
if (_modifications != _map._modifications) {
throw ConcurrentModificationError(_map);
}
var cell = _cell;
if (cell == null) {
_current = null;
return false;
} else {
final K key = JS('', '#', cell.hashMapCellKey);
final V value = JS('', '#', cell.hashMapCellValue);
_current = MapEntry(key, value);
_cell = cell._next;
return true;
}
}
}

base class JsIdentityLinkedHashMap<K, V> extends JsLinkedHashMap<K, V> {
JsIdentityLinkedHashMap();

Expand Down

0 comments on commit 0c527e1

Please sign in to comment.