Skip to content

Commit 5736880

Browse files
committed
Make CHAMP HashMap and HashSet the default
The `Map` and `Set` delegate factories already used them but now they are named `s.c.i.HashMap` and `s.c.i.HashSet`. The old implementations are still available under `OldHashMap` and `OldHashSet` and they can still be selected by setting the environment variable `SCALA_COLLECTION_IMMUTABLE_USE_BASELINE` to `true`.
1 parent ca5a07d commit 5736880

34 files changed

+486
-466
lines changed

src/library/scala/collection/Map.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ package collection
44
import scala.annotation.unchecked.uncheckedVariance
55
import scala.collection.generic.DefaultSerializationProxy
66
import scala.collection.mutable.StringBuilder
7-
import scala.language.{higherKinds, implicitConversions}
7+
import scala.language.higherKinds
88
import scala.util.hashing.MurmurHash3
99

1010
/** Base Map type */

src/library/scala/collection/immutable/ChampHashMap.scala

Lines changed: 43 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,19 @@ import scala.util.hashing.MurmurHash3
1919
*
2020
* @author Michael J. Steindorfer
2121
* @since 2.13
22-
* @define Coll `immutable.ChampHashMap`
22+
* @define Coll `immutable.HashMap`
2323
* @define coll immutable champ hash map
2424
*/
2525

26-
final class ChampHashMap[K, +V] private[immutable] (private val rootNode: MapNode[K, V], private val cachedJavaKeySetHashCode: Int)
26+
final class HashMap[K, +V] private[immutable] (private val rootNode: MapNode[K, V], private val cachedJavaKeySetHashCode: Int)
2727
extends AbstractMap[K, V]
28-
with MapOps[K, V, ChampHashMap, ChampHashMap[K, V]]
29-
with StrictOptimizedIterableOps[(K, V), Iterable, ChampHashMap[K, V]]
30-
with StrictOptimizedMapOps[K, V, ChampHashMap, ChampHashMap[K, V]] {
28+
with MapOps[K, V, HashMap, HashMap[K, V]]
29+
with StrictOptimizedIterableOps[(K, V), Iterable, HashMap[K, V]]
30+
with StrictOptimizedMapOps[K, V, HashMap, HashMap[K, V]] {
3131

32-
override def mapFactory: MapFactory[ChampHashMap] = ChampHashMap
32+
def this() = this(MapNode.empty, 0)
33+
34+
override def mapFactory: MapFactory[HashMap] = HashMap
3335

3436
override def knownSize: Int = rootNode.size
3537

@@ -74,7 +76,7 @@ final class ChampHashMap[K, +V] private[immutable] (private val rootNode: MapNod
7476
rootNode.getOrElse(key, keyUnimprovedHash, keyHash, 0, default)
7577
}
7678

77-
def updated[V1 >: V](key: K, value: V1): ChampHashMap[K, V1] = {
79+
def updated[V1 >: V](key: K, value: V1): HashMap[K, V1] = {
7880
val keyUnimprovedHash = key.##
7981
val keyHash = improve(keyUnimprovedHash)
8082

@@ -83,30 +85,30 @@ final class ChampHashMap[K, +V] private[immutable] (private val rootNode: MapNod
8385
if (newRootNode ne rootNode) {
8486
val replaced = rootNode.size == newRootNode.size
8587
val newCachedJavaKeySetHashCode = cachedJavaKeySetHashCode + (if (replaced) 0 else keyHash)
86-
ChampHashMap(newRootNode.get, newCachedJavaKeySetHashCode)
88+
HashMap(newRootNode.get, newCachedJavaKeySetHashCode)
8789
} else
8890
this
8991
}
9092

91-
def remove(key: K): ChampHashMap[K, V] = {
93+
def remove(key: K): HashMap[K, V] = {
9294
val keyUnimprovedHash = key.##
9395
val keyHash = improve(keyUnimprovedHash)
9496

9597
val newRootNode = rootNode.removed(key, keyUnimprovedHash, keyHash, 0)
9698

9799
if (newRootNode ne rootNode)
98-
ChampHashMap(newRootNode, cachedJavaKeySetHashCode - keyHash)
100+
HashMap(newRootNode, cachedJavaKeySetHashCode - keyHash)
99101
else this
100102
}
101103

102-
override def concat[V1 >: V](that: scala.IterableOnce[(K, V1)]): ChampHashMap[K, V1] = {
103-
// TODO PERF We could avoid recomputing entry hash's when `that` is another `ChampHashMap`
104+
override def concat[V1 >: V](that: scala.IterableOnce[(K, V1)]): HashMap[K, V1] = {
105+
// TODO PERF We could avoid recomputing entry hash's when `that` is another `HashMap`
104106
super.concat(that)
105107
}
106108

107-
override def tail: ChampHashMap[K, V] = this - head._1
109+
override def tail: HashMap[K, V] = this - head._1
108110

109-
override def init: ChampHashMap[K, V] = this - last._1
111+
override def init: HashMap[K, V] = this - last._1
110112

111113
override def head: (K, V) = iterator.next()
112114

@@ -116,7 +118,7 @@ final class ChampHashMap[K, +V] private[immutable] (private val rootNode: MapNod
116118

117119
override def equals(that: Any): Boolean =
118120
that match {
119-
case map: ChampHashMap[K, V] =>
121+
case map: HashMap[K, V] =>
120122
(this eq map) ||
121123
(this.size == map.size) &&
122124
(this.cachedJavaKeySetHashCode == map.cachedJavaKeySetHashCode) &&
@@ -130,7 +132,21 @@ final class ChampHashMap[K, +V] private[immutable] (private val rootNode: MapNod
130132
// assert(hash == super.hashCode())
131133
hash
132134
}
133-
override protected[this] def className = "ChampHashMap"
135+
136+
override protected[this] def className = "HashMap"
137+
138+
private type MergeFunction[A1, B1] = ((A1, B1), (A1, B1)) => (A1, B1)
139+
140+
//TODO optimize (https://github.com/scala/bug/issues/11077)
141+
def merged[V1 >: V](that: HashMap[K, V1])(mergef: MergeFunction[K, V1]): HashMap[K, V1] = {
142+
val thisKeys = this.keySet
143+
if(mergef eq null)
144+
that.removeAll(thisKeys) ++ this
145+
else {
146+
val thatKeys = that.keySet
147+
that.removeAll(thisKeys) ++ this.removeAll(thatKeys) ++ thisKeys.intersect(thatKeys).map { case k => mergef((k, this(k)), (k, that(k))) }
148+
}
149+
}
134150
}
135151

136152
private[immutable] object MapNode {
@@ -726,28 +742,28 @@ private final class MapKeyValueTupleHashIterator[K, V](rootNode: MapNode[K, V])
726742
/**
727743
* $factoryInfo
728744
*
729-
* @define Coll `immutable.ChampHashMap`
745+
* @define Coll `immutable.HashMap`
730746
* @define coll immutable champ hash map
731747
*/
732748
@SerialVersionUID(3L)
733-
object ChampHashMap extends MapFactory[ChampHashMap] {
749+
object HashMap extends MapFactory[HashMap] {
734750

735-
private[ChampHashMap] def apply[K, V](rootNode: MapNode[K, V], cachedJavaHashCode: Int) =
736-
new ChampHashMap[K, V](rootNode, cachedJavaHashCode)
751+
private[HashMap] def apply[K, V](rootNode: MapNode[K, V], cachedJavaHashCode: Int) =
752+
new HashMap[K, V](rootNode, cachedJavaHashCode)
737753

738-
private final val EmptyMap = new ChampHashMap(MapNode.empty, 0)
754+
private final val EmptyMap = new HashMap(MapNode.empty, 0)
739755

740-
def empty[K, V]: ChampHashMap[K, V] =
741-
EmptyMap.asInstanceOf[ChampHashMap[K, V]]
756+
def empty[K, V]: HashMap[K, V] =
757+
EmptyMap.asInstanceOf[HashMap[K, V]]
742758

743-
def from[K, V](source: collection.IterableOnce[(K, V)]): ChampHashMap[K, V] =
759+
def from[K, V](source: collection.IterableOnce[(K, V)]): HashMap[K, V] =
744760
source match {
745-
case hs: ChampHashMap[K, V] => hs
761+
case hs: HashMap[K, V] => hs
746762
case _ => (newBuilder[K, V] ++= source).result()
747763
}
748764

749-
def newBuilder[K, V]: Builder[(K, V), ChampHashMap[K, V]] =
750-
new ImmutableBuilder[(K, V), ChampHashMap[K, V]](empty) {
765+
def newBuilder[K, V]: Builder[(K, V), HashMap[K, V]] =
766+
new ImmutableBuilder[(K, V), HashMap[K, V]](empty) {
751767
def addOne(element: (K, V)): this.type = {
752768
elems = elems + element
753769
this

src/library/scala/collection/immutable/ChampHashSet.scala

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ import scala.util.hashing.MurmurHash3
1818
*
1919
* @author Michael J. Steindorfer
2020
* @since 2.13
21-
* @define Coll `immutable.ChampHashSet`
21+
* @define Coll `immutable.HashSet`
2222
* @define coll immutable champ hash set
2323
*/
24-
final class ChampHashSet[A] private[immutable] (val rootNode: SetNode[A], val cachedJavaHashCode: Int)
24+
final class HashSet[A] private[immutable] (val rootNode: SetNode[A], val cachedJavaHashCode: Int)
2525
extends AbstractSet[A]
26-
with SetOps[A, ChampHashSet, ChampHashSet[A]]
27-
with StrictOptimizedIterableOps[A, ChampHashSet, ChampHashSet[A]] {
26+
with SetOps[A, HashSet, HashSet[A]]
27+
with StrictOptimizedIterableOps[A, HashSet, HashSet[A]] {
2828

29-
override def iterableFactory: IterableFactory[ChampHashSet] = ChampHashSet
29+
override def iterableFactory: IterableFactory[HashSet] = HashSet
3030

3131
override def knownSize: Int = rootNode.size
3232

@@ -47,30 +47,30 @@ final class ChampHashSet[A] private[immutable] (val rootNode: SetNode[A], val ca
4747
rootNode.contains(element, elementUnimprovedHash, elementHash, 0)
4848
}
4949

50-
def incl(element: A): ChampHashSet[A] = {
50+
def incl(element: A): HashSet[A] = {
5151
val elementUnimprovedHash = element.##
5252
val elementHash = improve(elementUnimprovedHash)
5353
val newRootNode = rootNode.updated(element, elementUnimprovedHash, elementHash, 0)
5454

5555
if (newRootNode ne rootNode) {
5656
val newCachedJavaHashCode = cachedJavaHashCode + (if (newRootNode.size == rootNode.size) 0 else elementHash)
57-
ChampHashSet(newRootNode, newCachedJavaHashCode)
57+
HashSet(newRootNode, newCachedJavaHashCode)
5858
} else this
5959
}
6060

61-
def excl(element: A): ChampHashSet[A] = {
61+
def excl(element: A): HashSet[A] = {
6262
val elementUnimprovedHash = element.##
6363
val elementHash = improve(elementUnimprovedHash)
6464
val newRootNode = rootNode.removed(element, elementUnimprovedHash, elementHash, 0)
6565

6666
if (rootNode ne newRootNode)
67-
ChampHashSet(newRootNode, cachedJavaHashCode - elementHash)
67+
HashSet(newRootNode, cachedJavaHashCode - elementHash)
6868
else this
6969
}
7070

71-
override def tail: ChampHashSet[A] = this - head
71+
override def tail: HashSet[A] = this - head
7272

73-
override def init: ChampHashSet[A] = this - last
73+
override def init: HashSet[A] = this - last
7474

7575
override def head: A = iterator.next()
7676

@@ -79,21 +79,21 @@ final class ChampHashSet[A] private[immutable] (val rootNode: SetNode[A], val ca
7979
override def foreach[U](f: A => U): Unit = rootNode.foreach(f)
8080

8181
def subsetOf(that: Set[A]): Boolean = if (that.isEmpty) true else that match {
82-
case set: ChampHashSet[A] => rootNode.subsetOf(set.rootNode, 0)
82+
case set: HashSet[A] => rootNode.subsetOf(set.rootNode, 0)
8383
case _ => super.subsetOf(that)
8484
}
8585

8686
override def equals(that: Any): Boolean =
8787
that match {
88-
case set: ChampHashSet[A] =>
88+
case set: HashSet[A] =>
8989
(this eq set) ||
9090
(this.size == set.size) &&
9191
(this.cachedJavaHashCode == set.cachedJavaHashCode) &&
9292
(this.rootNode == set.rootNode)
9393
case _ => super.equals(that)
9494
}
9595

96-
override protected[this] def className = "ChampHashSet"
96+
override protected[this] def className = "HashSet"
9797

9898
override def hashCode(): Int = {
9999
val it = new SetHashIterator(rootNode)
@@ -646,29 +646,29 @@ private final class SetHashIterator[A](rootNode: SetNode[A])
646646
/**
647647
* $factoryInfo
648648
*
649-
* @define Coll `immutable.ChampHashSet`
649+
* @define Coll `immutable.HashSet`
650650
* @define coll immutable champ hash set
651651
*/
652652
@SerialVersionUID(3L)
653-
object ChampHashSet extends IterableFactory[ChampHashSet] {
653+
object HashSet extends IterableFactory[HashSet] {
654654

655-
private[ChampHashSet] def apply[A](rootNode: SetNode[A], cachedJavaHashCode: Int) =
656-
new ChampHashSet[A](rootNode, cachedJavaHashCode)
655+
private[HashSet] def apply[A](rootNode: SetNode[A], cachedJavaHashCode: Int) =
656+
new HashSet[A](rootNode, cachedJavaHashCode)
657657

658-
private final val EmptySet = new ChampHashSet(SetNode.empty, 0)
658+
private final val EmptySet = new HashSet(SetNode.empty, 0)
659659

660-
def empty[A]: ChampHashSet[A] =
661-
EmptySet.asInstanceOf[ChampHashSet[A]]
660+
def empty[A]: HashSet[A] =
661+
EmptySet.asInstanceOf[HashSet[A]]
662662

663-
def from[A](source: collection.IterableOnce[A]): ChampHashSet[A] =
663+
def from[A](source: collection.IterableOnce[A]): HashSet[A] =
664664
source match {
665-
case hs: ChampHashSet[A] => hs
665+
case hs: HashSet[A] => hs
666666
case _ if source.knownSize == 0 => empty[A]
667667
case _ => (newBuilder[A] ++= source).result()
668668
}
669669

670-
def newBuilder[A]: Builder[A, ChampHashSet[A]] =
671-
new ImmutableBuilder[A, ChampHashSet[A]](empty) {
670+
def newBuilder[A]: Builder[A, HashSet[A]] =
671+
new ImmutableBuilder[A, HashSet[A]](empty) {
672672
def addOne(element: A): this.type = {
673673
elems = elems + element
674674
this

src/library/scala/collection/immutable/Map.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ object Map extends MapFactory[Map] {
389389
else if (key == key2) new Map4(key1, value1, key2, value, key3, value3, key4, value4)
390390
else if (key == key3) new Map4(key1, value1, key2, value2, key3, value, key4, value4)
391391
else if (key == key4) new Map4(key1, value1, key2, value2, key3, value3, key4, value)
392-
else (if (useBaseline) HashMap.empty[K, V1] else ChampHashMap.empty[K, V1]).updated(key1,value1).updated(key2, value2).updated(key3, value3).updated(key4, value4).updated(key, value)
392+
else (if (useBaseline) OldHashMap.empty[K, V1] else HashMap.empty[K, V1]).updated(key1,value1).updated(key2, value2).updated(key3, value3).updated(key4, value4).updated(key, value)
393393
def remove(key: K): Map[K, V] =
394394
if (key == key1) new Map3(key2, value2, key3, value3, key4, value4)
395395
else if (key == key2) new Map3(key1, value1, key3, value3, key4, value4)

0 commit comments

Comments
 (0)