@@ -154,6 +154,12 @@ final class HashMap[K, +V] private[immutable] (private[immutable] val rootNode:
154
154
}
155
155
}
156
156
157
+ override def transform [W ](f : (K , V ) => W ) = {
158
+ val transformed = rootNode.transform(f)
159
+ if (transformed eq rootNode) this .asInstanceOf [HashMap [K , W ]]
160
+ else new HashMap (transformed, cachedJavaKeySetHashCode)
161
+ }
162
+
157
163
override def filterImpl (pred : ((K , V )) => Boolean , flipped : Boolean ): HashMap [K , V ] = {
158
164
// This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
159
165
// in a minor release without breaking binary compatibility.
@@ -173,15 +179,6 @@ final class HashMap[K, +V] private[immutable] (private[immutable] val rootNode:
173
179
super .removeAll(keys)
174
180
}
175
181
176
- override def transform [W ](f : (K , V ) => W ): HashMap [K , W ] = {
177
- // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
178
- // in a minor release without breaking binary compatibility.
179
- //
180
- // In particular, `transform` could be optimized to traverse the trie node-by-node, swapping out the values of each
181
- // key with the result of applying `f`.
182
- super .transform(f)
183
- }
184
-
185
182
override def partition (p : ((K , V )) => Boolean ): (HashMap [K , V ], HashMap [K , V ]) = {
186
183
// This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
187
184
// in a minor release without breaking binary compatibility.
@@ -255,6 +252,7 @@ final class HashMap[K, +V] private[immutable] (private[immutable] val rootNode:
255
252
// checks.
256
253
super .span(p)
257
254
}
255
+
258
256
}
259
257
260
258
private [immutable] object MapNode {
@@ -303,6 +301,8 @@ private[immutable] sealed abstract class MapNode[K, +V] extends Node[MapNode[K,
303
301
304
302
def foreach [U ](f : ((K , V )) => U ): Unit
305
303
304
+ def transform [W ](f : (K , V ) => W ): MapNode [K , W ]
305
+
306
306
def copy (): MapNode [K , V ]
307
307
}
308
308
@@ -655,6 +655,44 @@ private final class BitmapIndexedMapNode[K, +V](
655
655
}
656
656
}
657
657
658
+ override def transform [W ](f : (K , V ) => W ): BitmapIndexedMapNode [K , W ] = {
659
+ var newContent : Array [Any ] = null
660
+ val _payloadArity = payloadArity
661
+ val _nodeArity = nodeArity
662
+ val newContentLength = content.length
663
+ var i = 0
664
+ while (i < _payloadArity) {
665
+ val key = getKey(i)
666
+ val value = getValue(i)
667
+ val newValue = f(key, value)
668
+ if (newContent eq null ) {
669
+ if (newValue.asInstanceOf [AnyRef ] ne value.asInstanceOf [AnyRef ]) {
670
+ newContent = content.clone()
671
+ newContent(TupleLength * i + 1 ) = newValue
672
+ }
673
+ } else {
674
+ newContent(TupleLength * i + 1 ) = newValue
675
+ }
676
+ i += 1
677
+ }
678
+
679
+ var j = 0
680
+ while (j < _nodeArity) {
681
+ val node = getNode(j)
682
+ val newNode = node.transform(f)
683
+ if (newContent eq null ) {
684
+ if (newNode ne node) {
685
+ newContent = content.clone()
686
+ newContent(newContentLength - j - 1 ) = newNode
687
+ }
688
+ } else
689
+ newContent(newContentLength - j - 1 ) = newNode
690
+ j += 1
691
+ }
692
+ if (newContent eq null ) this .asInstanceOf [BitmapIndexedMapNode [K , W ]]
693
+ else new BitmapIndexedMapNode [K , W ](dataMap, nodeMap, newContent, originalHashes, size)
694
+ }
695
+
658
696
override def equals (that : Any ): Boolean =
659
697
that match {
660
698
case node : BitmapIndexedMapNode [K , V ] =>
@@ -801,6 +839,21 @@ private final class HashCollisionMapNode[K, +V ](
801
839
802
840
def foreach [U ](f : ((K , V )) => U ): Unit = content.foreach(f)
803
841
842
+ override def transform [W ](f : (K , V ) => W ): HashCollisionMapNode [K , W ] = {
843
+ val newContent = Vector .newBuilder[(K , W )]
844
+ val contentIter = content.iterator
845
+ // true if any values have been transformed to a different value via `f`
846
+ var anyChanges = false
847
+ while (contentIter.hasNext) {
848
+ val (k, v) = contentIter.next()
849
+ val newValue = f(k, v)
850
+ newContent.addOne((k, newValue))
851
+ anyChanges ||= (v.asInstanceOf [AnyRef ] ne newValue.asInstanceOf [AnyRef ])
852
+ }
853
+ if (anyChanges) new HashCollisionMapNode (originalHash, hash, newContent.result())
854
+ else this .asInstanceOf [HashCollisionMapNode [K , W ]]
855
+ }
856
+
804
857
override def equals (that : Any ): Boolean =
805
858
that match {
806
859
case node : HashCollisionMapNode [K , V ] =>
0 commit comments