@@ -185,6 +185,27 @@ abstract class _HashBase implements _HashVMBase {
185185 ! identical (_data, oldData) || (_checkSum != oldCheckSum);
186186
187187 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+ }
188209}
189210
190211class _OperatorEqualsAndHashCode {
@@ -233,6 +254,16 @@ class _InternalLinkedHashMap<K, V> extends _HashVMBase
233254 _usedData = 0 ;
234255 _deletedKeys = 0 ;
235256 }
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+ }
236267}
237268
238269// This is essentially the same class as _InternalLinkedHashMap, but it does
@@ -531,7 +562,7 @@ abstract class _LinkedHashMapMixin<K, V> implements _HashBase {
531562 return false ;
532563 }
533564
534- void forEach (void f (K key, V value)) {
565+ void forEach (void action (K key, V value)) {
535566 final data = _data;
536567 final checkSum = _checkSum;
537568 final len = _usedData;
@@ -540,7 +571,7 @@ abstract class _LinkedHashMapMixin<K, V> implements _HashBase {
540571 if (_HashBase ._isDeleted (data, current)) continue ;
541572 final key = internal.unsafeCast <K >(current);
542573 final value = internal.unsafeCast <V >(data[offset + 1 ]);
543- f (key, value);
574+ action (key, value);
544575 if (_isModifiedSince (data, checkSum)) {
545576 throw ConcurrentModificationError (this );
546577 }
@@ -561,6 +592,16 @@ class _CompactLinkedIdentityHashMap<K, V> extends _HashFieldBase
561592 _IdenticalAndIdentityHashCode
562593 implements LinkedHashMap <K , V > {
563594 _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+ }
564605}
565606
566607class _CompactLinkedCustomHashMap <K , V > extends _HashFieldBase
@@ -832,6 +873,16 @@ class _CompactLinkedHashSet<E> extends _HashVMBase
832873 // is not required by the spec. (For instance, always using an identity set
833874 // would be technically correct, albeit surprising.)
834875 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+ }
835886}
836887
837888@pragma ("vm:entry-point" )
@@ -924,6 +975,16 @@ class _CompactLinkedIdentityHashSet<E> extends _HashFieldBase
924975 static Set <R > _newEmpty <R >() => new _CompactLinkedIdentityHashSet <R >();
925976
926977 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+ }
927988}
928989
929990class _CompactLinkedCustomHashSet <E > extends _HashFieldBase
0 commit comments