Skip to content

Commit 70ca7b5

Browse files
committed
[nomerge] HashMap#transform reuses structure
The keys in the resulting map are the same, so the internal structure will also be the same, and that can be used to avoid allocating tuples and going through `MapBuilder` and other such convolutions.
1 parent c003048 commit 70ca7b5

File tree

1 file changed

+32
-3
lines changed

1 file changed

+32
-3
lines changed

library/src/scala/collection/immutable/HashMap.scala

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,12 @@ sealed class HashMap[A, +B] extends AbstractMap[A, B]
153153
}
154154
override def values: scala.collection.Iterable[B] = new HashMapValues
155155

156+
override final def transform[W, That](f: (A, B) => W)(implicit bf: CanBuildFrom[HashMap[A, B], (A, W), That]): That =
157+
if ((bf eq Map.canBuildFrom) || (bf eq HashMap.canBuildFrom)) transformImpl(f).asInstanceOf[That]
158+
else super.transform(f)(bf)
156159

160+
/* `transform` specialized to return a HashMap */
161+
protected def transformImpl[W](f: (A, B) => W): HashMap[A, W] = HashMap.empty
157162
}
158163

159164
/** $factoryInfo
@@ -187,10 +192,12 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int {
187192
}
188193

189194
/** $mapCanBuildFromInfo */
190-
implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), HashMap[A, B]] = new MapCanBuildFrom[A, B]
195+
implicit def canBuildFrom[A, B]: CanBuildFrom[Coll, (A, B), HashMap[A, B]] =
196+
ReusableCBF.asInstanceOf[CanBuildFrom[Coll, (A, B), HashMap[A, B]]]
197+
private val ReusableCBF = new MapCanBuildFrom[Nothing, Nothing]
191198
def empty[A, B]: HashMap[A, B] = EmptyHashMap.asInstanceOf[HashMap[A, B]]
192199

193-
private object EmptyHashMap extends HashMap[Any, Nothing] {
200+
private object EmptyHashMap extends HashMap[Any, Nothing] {
194201
override def head: (Any, Nothing) = throw new NoSuchElementException("Empty Map")
195202
override def tail: HashMap[Any, Nothing] = throw new NoSuchElementException("Empty Map")
196203
}
@@ -268,7 +275,7 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int {
268275

269276
override def equals(that: Any): Boolean = {
270277
that match {
271-
case hm: HashMap1[_,_] =>
278+
case hm: HashMap1[_, _] =>
272279
(this eq hm) ||
273280
(hm.hash == hash && hm.key == key && hm.value == value)
274281
case _: HashMap[_, _] =>
@@ -277,6 +284,12 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int {
277284
super.equals(that)
278285
}
279286
}
287+
288+
protected override def transformImpl[W](f: (A, B) => W): HashMap[A, W] = {
289+
val value1 = f(key, value)
290+
if (value1.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef]) this.asInstanceOf[HashMap1[A, W]]
291+
else new HashMap1(key, hash, value1, null)
292+
}
280293
}
281294

282295
private[collection] class HashMapCollision1[A, +B](private[collection] val hash: Int, val kvs: ListMap[A, B @uV])
@@ -361,6 +374,9 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int {
361374
}
362375
}
363376

377+
protected override def transformImpl[W](f: (A, B) => W): HashMap[A, W] = {
378+
new HashMapCollision1[A, W](hash, kvs transform f)
379+
}
364380
}
365381

366382
@deprecatedInheritance("This class will be made final in a future release.", "2.12.2")
@@ -636,6 +652,19 @@ object HashMap extends ImmutableMapFactory[HashMap] with BitOperations.Int {
636652
}
637653
}
638654

655+
protected override def transformImpl[W](f: (A, B) => W): HashMap[A, W] = {
656+
val elems1 = new Array[HashMap[A, W]](elems.length)
657+
var i = 0
658+
while (i < elems.length) {
659+
val elem = elems(i)
660+
if (elem ne null) {
661+
val elem1 = elem.transformImpl(f)
662+
elems1(i) = elem1
663+
}
664+
i += 1
665+
}
666+
new HashTrieMap[A, W](bitmap, elems1, size)
667+
}
639668
}
640669

641670
/**

0 commit comments

Comments
 (0)