@@ -185,6 +185,27 @@ abstract class _HashBase implements _HashVMBase {
185
185
! identical (_data, oldData) || (_checkSum != oldCheckSum);
186
186
187
187
int get length;
188
+
189
+ // If this collection has never had an insertion, and [other] is the same
190
+ // representation and has had no deletions, then adding the entries of [other]
191
+ // will end up building the same [_data] and [_index]. We can do this more
192
+ // efficiently by copying the Lists directly.
193
+ //
194
+ // Precondition: [this] and [other] must use the same hashcode and equality.
195
+ bool _quickCopy (_HashBase other) {
196
+ if (! identical (_index, _uninitializedIndex)) return false ;
197
+ if (other._usedData == 0 ) return true ; // [other] is empty, nothing to copy.
198
+ if (other._deletedKeys != 0 ) return false ;
199
+
200
+ assert (! identical (other._index, _uninitializedIndex));
201
+ assert (! identical (other._data, _uninitializedData));
202
+ _index = Uint32List .fromList (other._index);
203
+ _hashMask = other._hashMask;
204
+ _data = List .of (other._data, growable: false );
205
+ _usedData = other._usedData;
206
+ _deletedKeys = other._deletedKeys;
207
+ return true ;
208
+ }
188
209
}
189
210
190
211
class _OperatorEqualsAndHashCode {
@@ -233,6 +254,16 @@ class _InternalLinkedHashMap<K, V> extends _HashVMBase
233
254
_usedData = 0 ;
234
255
_deletedKeys = 0 ;
235
256
}
257
+
258
+ void addAll (Map <K , V > other) {
259
+ if (other is _InternalLinkedHashMap ) {
260
+ final otherBase = other as _InternalLinkedHashMap ; // manual promotion.
261
+ // If this map is empty we might be able to block-copy from [other].
262
+ if (isEmpty && _quickCopy (otherBase)) return ;
263
+ // TODO(48143): Pre-grow capacity if it will reduce rehashing.
264
+ }
265
+ super .addAll (other);
266
+ }
236
267
}
237
268
238
269
// This is essentially the same class as _InternalLinkedHashMap, but it does
@@ -531,7 +562,7 @@ abstract class _LinkedHashMapMixin<K, V> implements _HashBase {
531
562
return false ;
532
563
}
533
564
534
- void forEach (void f (K key, V value)) {
565
+ void forEach (void action (K key, V value)) {
535
566
final data = _data;
536
567
final checkSum = _checkSum;
537
568
final len = _usedData;
@@ -540,7 +571,7 @@ abstract class _LinkedHashMapMixin<K, V> implements _HashBase {
540
571
if (_HashBase ._isDeleted (data, current)) continue ;
541
572
final key = internal.unsafeCast <K >(current);
542
573
final value = internal.unsafeCast <V >(data[offset + 1 ]);
543
- f (key, value);
574
+ action (key, value);
544
575
if (_isModifiedSince (data, checkSum)) {
545
576
throw ConcurrentModificationError (this );
546
577
}
@@ -561,6 +592,16 @@ class _CompactLinkedIdentityHashMap<K, V> extends _HashFieldBase
561
592
_IdenticalAndIdentityHashCode
562
593
implements LinkedHashMap <K , V > {
563
594
_CompactLinkedIdentityHashMap () : super (_HashBase ._INITIAL_INDEX_SIZE );
595
+
596
+ void addAll (Map <K , V > other) {
597
+ if (other is _CompactLinkedIdentityHashMap ) {
598
+ final otherBase = other as _CompactLinkedIdentityHashMap ;
599
+ // If this map is empty we might be able to block-copy from [other].
600
+ if (isEmpty && _quickCopy (otherBase)) return ;
601
+ // TODO(48143): Pre-grow capacity if it will reduce rehashing.
602
+ }
603
+ super .addAll (other);
604
+ }
564
605
}
565
606
566
607
class _CompactLinkedCustomHashMap <K , V > extends _HashFieldBase
@@ -832,6 +873,16 @@ class _CompactLinkedHashSet<E> extends _HashVMBase
832
873
// is not required by the spec. (For instance, always using an identity set
833
874
// would be technically correct, albeit surprising.)
834
875
Set <E > toSet () => new _CompactLinkedHashSet <E >()..addAll (this );
876
+
877
+ void addAll (Iterable <E > other) {
878
+ if (other is _CompactLinkedHashSet ) {
879
+ final otherBase = other as _CompactLinkedHashSet ;
880
+ // If this set is empty we might be able to block-copy from [other].
881
+ if (isEmpty && _quickCopy (otherBase)) return ;
882
+ // TODO(48143): Pre-grow capacity if it will reduce rehashing.
883
+ }
884
+ super .addAll (other);
885
+ }
835
886
}
836
887
837
888
@pragma ("vm:entry-point" )
@@ -924,6 +975,16 @@ class _CompactLinkedIdentityHashSet<E> extends _HashFieldBase
924
975
static Set <R > _newEmpty <R >() => new _CompactLinkedIdentityHashSet <R >();
925
976
926
977
Set <R > cast <R >() => Set .castFrom <E , R >(this , newSet: _newEmpty);
978
+
979
+ void addAll (Iterable <E > other) {
980
+ if (other is _CompactLinkedIdentityHashSet ) {
981
+ final otherBase = other as _CompactLinkedIdentityHashSet ;
982
+ // If this set is empty we might be able to block-copy from [other].
983
+ if (isEmpty && _quickCopy (otherBase)) return ;
984
+ // TODO(48143): Pre-grow capacity if it will reduce rehashing.
985
+ }
986
+ super .addAll (other);
987
+ }
927
988
}
928
989
929
990
class _CompactLinkedCustomHashSet <E > extends _HashFieldBase
0 commit comments