Skip to content

Commit ae43152

Browse files
authored
Merge pull request scala#6776 from julienrf/generic-strict-impls
Factor out strict implementations of transformation operations.
2 parents eaeda75 + deb94ea commit ae43152

19 files changed

+219
-95
lines changed

src/library/scala/collection/Seq.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,9 @@ trait SeqOps[+A, +CC[_], +C] extends Any
181181

182182
// Make `concat` an alias for `appendedAll` so that it benefits from performance
183183
// overrides of this method
184-
@`inline` final override def concat[B >: A](suffix: Iterable[B]): CC[B] = appendedAll(suffix)
184+
// TODO https://github.com/scala/bug/issues/10853 Uncomment final
185+
@deprecatedOverriding("This method should be final, but is not due to scala/bug#10853", "2.13.0")
186+
@`inline` /*final*/ override def concat[B >: A](suffix: Iterable[B]): CC[B] = appendedAll(suffix)
185187

186188
/** Produces a new sequence which contains all elements of this $coll and also all elements of
187189
* a given sequence. `xs union ys` is equivalent to `xs ++ ys`.

src/library/scala/collection/SortedMap.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _],
186186
}
187187

188188
object SortedMapOps {
189-
private final val ordMsg = "No implicit Ordering[${K2}] found to build a SortedMap[${K2}, ${V2}]. You may want to upcast to a Map[${K}, ${V}] first by calling `unsorted`."
189+
private[collection] final val ordMsg = "No implicit Ordering[${K2}] found to build a SortedMap[${K2}, ${V2}]. You may want to upcast to a Map[${K}, ${V}] first by calling `unsorted`."
190190

191191
/** Specializes `MapWithFilter` for sorted Map collections
192192
*

src/library/scala/collection/StrictOptimizedIterableOps.scala

Lines changed: 75 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ import scala.annotation.unchecked.uncheckedVariance
55
import scala.language.higherKinds
66

77
/**
8-
* Trait that overrides operations to take advantage of strict builders.
8+
* Trait that overrides iterable operations to take advantage of strict builders.
99
*
1010
* @tparam A Elements type
11+
* @tparam CC Collection type constructor
1112
* @tparam C Collection type
1213
*/
1314
trait StrictOptimizedIterableOps[+A, +CC[_], +C]
@@ -70,26 +71,71 @@ trait StrictOptimizedIterableOps[+A, +CC[_], +C]
7071
// the view-based implementations, but they turn out to be slightly faster because
7172
// a couple of indirection levels are removed
7273

73-
override def map[B](f: A => B): CC[B] = {
74-
val b = iterableFactory.newBuilder[B]
74+
override def map[B](f: A => B): CC[B] =
75+
strictOptimizedMap(iterableFactory.newBuilder, f)
76+
77+
/**
78+
* @param b Builder to use to build the resulting collection
79+
* @param f Element transformation function
80+
* @tparam B Type of elements of the resulting collection (e.g. `String`)
81+
* @tparam C2 Type of the resulting collection (e.g. `List[String]`)
82+
* @return The resulting collection
83+
*/
84+
@inline protected[this] final def strictOptimizedMap[B, C2](b: mutable.Builder[B, C2], f: A => B): C2 = {
7585
val it = iterator
7686
while (it.hasNext) {
7787
b += f(it.next())
7888
}
7989
b.result()
8090
}
8191

82-
override def flatMap[B](f: A => IterableOnce[B]): CC[B] = {
83-
val b = iterableFactory.newBuilder[B]
92+
override def flatMap[B](f: A => IterableOnce[B]): CC[B] =
93+
strictOptimizedFlatMap(iterableFactory.newBuilder, f)
94+
95+
/**
96+
* @param b Builder to use to build the resulting collection
97+
* @param f Element transformation function
98+
* @tparam B Type of elements of the resulting collection (e.g. `String`)
99+
* @tparam C2 Type of the resulting collection (e.g. `List[String]`)
100+
* @return The resulting collection
101+
*/
102+
@inline protected[this] final def strictOptimizedFlatMap[B, C2](b: mutable.Builder[B, C2], f: A => IterableOnce[B]): C2 = {
84103
val it = iterator
85104
while (it.hasNext) {
86105
b ++= f(it.next())
87106
}
88107
b.result()
89108
}
90109

91-
override def collect[B](pf: PartialFunction[A, B]): CC[B] = {
92-
val b = iterableFactory.newBuilder[B]
110+
override def concat[B >: A](suffix: Iterable[B]): CC[B] =
111+
strictOptimizedConcat(suffix, iterableFactory.newBuilder[B])
112+
113+
/**
114+
* @param that Elements to concatenate to this collection
115+
* @param b Builder to use to build the resulting collection
116+
* @tparam B Type of elements of the resulting collections (e.g. `Int`)
117+
* @tparam C2 Type of the resulting collection (e.g. `List[Int]`)
118+
* @return The resulting collection
119+
*/
120+
@inline protected[this] final def strictOptimizedConcat[B >: A, C2](that: Iterable[B], b: mutable.Builder[B, C2]): C2 = {
121+
val it1 = iterator
122+
val it2 = that.iterator
123+
b ++= it1
124+
b ++= it2
125+
b.result()
126+
}
127+
128+
override def collect[B](pf: PartialFunction[A, B]): CC[B] =
129+
strictOptimizedCollect(iterableFactory.newBuilder, pf)
130+
131+
/**
132+
* @param b Builder to use to build the resulting collection
133+
* @param pf Element transformation partial function
134+
* @tparam B Type of elements of the resulting collection (e.g. `String`)
135+
* @tparam C2 Type of the resulting collection (e.g. `List[String]`)
136+
* @return The resulting collection
137+
*/
138+
@inline protected[this] final def strictOptimizedCollect[B, C2](b: mutable.Builder[B, C2], pf: PartialFunction[A, B]): C2 = {
93139
val it = iterator
94140
while (it.hasNext) {
95141
val elem = it.next()
@@ -100,17 +146,35 @@ trait StrictOptimizedIterableOps[+A, +CC[_], +C]
100146
b.result()
101147
}
102148

103-
override def flatten[B](implicit toIterableOnce: A => IterableOnce[B]): CC[B] = {
104-
val b = iterableFactory.newBuilder[B]
149+
override def flatten[B](implicit toIterableOnce: A => IterableOnce[B]): CC[B] =
150+
strictOptimizedFlatten(iterableFactory.newBuilder)
151+
152+
/**
153+
* @param b Builder to use to build the resulting collection
154+
* @param toIterableOnce Evidence that `A` can be seen as an `IterableOnce[B]`
155+
* @tparam B Type of elements of the resulting collection (e.g. `Int`)
156+
* @tparam C2 Type of the resulting collection (e.g. `List[Int]`)
157+
* @return The resulting collection
158+
*/
159+
@inline protected[this] final def strictOptimizedFlatten[B, C2](b: mutable.Builder[B, C2])(implicit toIterableOnce: A => IterableOnce[B]): C2 = {
105160
val it = iterator
106161
while (it.hasNext) {
107162
b ++= toIterableOnce(it.next())
108163
}
109164
b.result()
110165
}
111166

112-
override def zip[B](that: Iterable[B]): CC[(A @uncheckedVariance, B)] = {
113-
val b = iterableFactory.newBuilder[(A, B)]
167+
override def zip[B](that: Iterable[B]): CC[(A @uncheckedVariance, B)] =
168+
strictOptimizedZip(that, iterableFactory.newBuilder[(A, B)])
169+
170+
/**
171+
* @param that Collection to zip with this collection
172+
* @param b Builder to use to build the resulting collection
173+
* @tparam B Type of elements of the second collection (e.g. `String`)
174+
* @tparam C2 Type of the resulting collection (e.g. `List[(Int, String)]`)
175+
* @return The resulting collection
176+
*/
177+
@inline protected[this] final def strictOptimizedZip[B, C2](that: Iterable[B], b: mutable.Builder[(A, B), C2]): C2 = {
114178
val it1 = iterator
115179
val it2 = that.iterator
116180
while (it1.hasNext && it2.hasNext) {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package scala.collection
2+
3+
import scala.language.higherKinds
4+
5+
/**
6+
* Trait that overrides map operations to take advantage of strict builders.
7+
*
8+
* @tparam K Type of keys
9+
* @tparam V Type of values
10+
* @tparam CC Collection type constructor
11+
* @tparam C Collection type
12+
*/
13+
trait StrictOptimizedMapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C]
14+
extends MapOps[K, V, CC, C]
15+
with StrictOptimizedIterableOps[(K, V), Iterable, C] {
16+
17+
override def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] =
18+
strictOptimizedMap(mapFactory.newBuilder, f)
19+
20+
override def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] =
21+
strictOptimizedFlatMap(mapFactory.newBuilder, f)
22+
23+
override def concat[V2 >: V](suffix: Iterable[(K, V2)]): CC[K, V2] =
24+
strictOptimizedConcat(suffix, mapFactory.newBuilder)
25+
26+
override def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)]): CC[K2, V2] =
27+
strictOptimizedCollect(mapFactory.newBuilder, pf)
28+
29+
}

src/library/scala/collection/StrictOptimizedSeqOps.scala

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import scala.language.higherKinds
88
*/
99
trait StrictOptimizedSeqOps [+A, +CC[_], +C]
1010
extends Any
11-
with SeqOps[A, CC, C]
12-
with StrictOptimizedIterableOps[A, CC, C] {
11+
with StrictOptimizedIterableOps[A, CC, C]
12+
with SeqOps[A, CC, C] {
1313

1414
override def distinctBy[B](f: A => B): C = {
1515
val builder = newSpecificBuilder
@@ -42,12 +42,8 @@ trait StrictOptimizedSeqOps [+A, +CC[_], +C]
4242
b.result()
4343
}
4444

45-
override def appendedAll[B >: A](suffix: Iterable[B]): CC[B] = {
46-
val b = iterableFactory.newBuilder[B]
47-
b ++= this
48-
b ++= suffix
49-
b.result()
50-
}
45+
override def appendedAll[B >: A](suffix: Iterable[B]): CC[B] =
46+
strictOptimizedConcat(suffix, iterableFactory.newBuilder)
5147

5248
override def prependedAll[B >: A](prefix: Iterable[B]): CC[B] = {
5349
val b = iterableFactory.newBuilder[B]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package scala.collection
2+
3+
/**
4+
* Trait that overrides set operations to take advantage of strict builders.
5+
*
6+
* @tparam A Elements type
7+
* @tparam CC Collection type constructor
8+
* @tparam C Collection type
9+
*/
10+
trait StrictOptimizedSetOps[A, +CC[_], +C <: SetOps[A, CC, C]]
11+
extends SetOps[A, CC, C]
12+
with StrictOptimizedIterableOps[A, CC, C] {
13+
14+
override def concat(that: Iterable[A]): C =
15+
strictOptimizedConcat(that, newSpecificBuilder)
16+
17+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package scala.collection
2+
3+
import scala.annotation.implicitNotFound
4+
5+
/**
6+
* Trait that overrides sorted map operations to take advantage of strict builders.
7+
*
8+
* @tparam K Type of keys
9+
* @tparam V Type of values
10+
* @tparam CC Collection type constructor
11+
* @tparam C Collection type
12+
*/
13+
trait StrictOptimizedSortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], +C <: SortedMapOps[K, V, CC, C]]
14+
extends SortedMapOps[K, V, CC, C]
15+
with StrictOptimizedMapOps[K, V, Map, C] {
16+
17+
override def map[K2, V2](f: ((K, V)) => (K2, V2))(implicit @implicitNotFound(SortedMapOps.ordMsg) ordering: Ordering[K2]): CC[K2, V2] =
18+
strictOptimizedMap(sortedMapFactory.newBuilder, f)
19+
20+
override def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)])(implicit @implicitNotFound(SortedMapOps.ordMsg) ordering: Ordering[K2]): CC[K2, V2] =
21+
strictOptimizedFlatMap(sortedMapFactory.newBuilder, f)
22+
23+
override def concat[V2 >: V](xs: Iterable[(K, V2)]): CC[K, V2] =
24+
strictOptimizedConcat(xs, sortedMapFactory.newBuilder)
25+
26+
override def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)])(implicit @implicitNotFound(SortedMapOps.ordMsg) ordering: Ordering[K2]): CC[K2, V2] =
27+
strictOptimizedCollect(sortedMapFactory.newBuilder, pf)
28+
29+
}

src/library/scala/collection/StrictOptimizedSortedSetOps.scala

Lines changed: 20 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,48 +6,27 @@ import scala.annotation.implicitNotFound
66
import scala.annotation.unchecked.uncheckedVariance
77
import scala.language.higherKinds
88

9+
/**
10+
* Trait that overrides sorted set operations to take advantage of strict builders.
11+
*
12+
* @tparam A Elements type
13+
* @tparam CC Collection type constructor
14+
* @tparam C Collection type
15+
*/
916
trait StrictOptimizedSortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]]
1017
extends SortedSetOps[A, CC, C]
11-
with StrictOptimizedIterableOps[A, Set, C] {
12-
13-
override def map[B](f: A => B)(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] = {
14-
val b = sortedIterableFactory.newBuilder[B]
15-
val it = iterator
16-
while (it.hasNext) {
17-
b += f(it.next())
18-
}
19-
b.result()
20-
}
21-
22-
override def flatMap[B](f: A => IterableOnce[B])(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] = {
23-
val b = sortedIterableFactory.newBuilder[B]
24-
val it = iterator
25-
while (it.hasNext) {
26-
b ++= f(it.next())
27-
}
28-
b.result()
29-
}
30-
31-
override def zip[B](that: Iterable[B])(implicit @implicitNotFound(SortedSetOps.zipOrdMsg) ev: Ordering[(A @uncheckedVariance, B)]): CC[(A @uncheckedVariance, B)] = { // sound bcs of VarianceNot
32-
val b = sortedIterableFactory.newBuilder[(A, B)]
33-
val it1 = iterator
34-
val it2 = that.iterator
35-
while (it1.hasNext && it2.hasNext) {
36-
b += ((it1.next(), it2.next()))
37-
}
38-
b.result()
39-
}
40-
41-
override def collect[B](pf: PartialFunction[A, B])(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] = {
42-
val b = sortedIterableFactory.newBuilder[B]
43-
val it = iterator
44-
while (it.hasNext) {
45-
val elem = it.next()
46-
if (pf.isDefinedAt(elem)) {
47-
b += pf.apply(elem)
48-
}
49-
}
50-
b.result()
51-
}
18+
with StrictOptimizedSetOps[A, Set, C] {
19+
20+
override def map[B](f: A => B)(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] =
21+
strictOptimizedMap(sortedIterableFactory.newBuilder, f)
22+
23+
override def flatMap[B](f: A => IterableOnce[B])(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] =
24+
strictOptimizedFlatMap(sortedIterableFactory.newBuilder, f)
25+
26+
override def zip[B](that: Iterable[B])(implicit @implicitNotFound(SortedSetOps.zipOrdMsg) ev: Ordering[(A @uncheckedVariance, B)]): CC[(A @uncheckedVariance, B)] =
27+
strictOptimizedZip(that, sortedIterableFactory.newBuilder[(A, B)])
28+
29+
override def collect[B](pf: PartialFunction[A, B])(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] =
30+
strictOptimizedCollect(sortedIterableFactory.newBuilder, pf)
5231

5332
}

src/library/scala/collection/immutable/BitSet.scala

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ sealed abstract class BitSet
2222
with collection.BitSet
2323
with SortedSetOps[Int, SortedSet, BitSet]
2424
with collection.BitSetOps[BitSet]
25-
with StrictOptimizedIterableOps[Int, Set, BitSet] {
25+
with StrictOptimizedIterableOps[Int, Set, BitSet]
26+
with StrictOptimizedSortedSetOps[Int, SortedSet, BitSet] {
2627

2728
def bitSetFactory = BitSet
2829

@@ -49,17 +50,17 @@ sealed abstract class BitSet
4950
*/
5051
protected def updateWord(idx: Int, w: Long): BitSet
5152

52-
override def map(f: Int => Int): BitSet = super[BitSet].map(f)
53+
override def map(f: Int => Int): BitSet = strictOptimizedMap(newSpecificBuilder, f)
5354
override def map[B](f: Int => B)(implicit @implicitNotFound(collection.BitSet.ordMsg) ev: Ordering[B]): SortedSet[B] =
54-
super[SortedSetOps].map(f)
55+
super[StrictOptimizedSortedSetOps].map(f)
5556

56-
override def flatMap(f: Int => IterableOnce[Int]): BitSet = super[BitSet].flatMap(f)
57+
override def flatMap(f: Int => IterableOnce[Int]): BitSet = strictOptimizedFlatMap(newSpecificBuilder, f)
5758
override def flatMap[B](f: Int => IterableOnce[B])(implicit @implicitNotFound(collection.BitSet.ordMsg) ev: Ordering[B]): SortedSet[B] =
58-
super[SortedSetOps].flatMap(f)
59+
super[StrictOptimizedSortedSetOps].flatMap(f)
5960

60-
override def collect(pf: PartialFunction[Int, Int]): BitSet = super[BitSet].collect(pf)
61+
override def collect(pf: PartialFunction[Int, Int]): BitSet = strictOptimizedCollect(newSpecificBuilder, pf)
6162
override def collect[B](pf: scala.PartialFunction[Int, B])(implicit @implicitNotFound(collection.BitSet.ordMsg) ev: Ordering[B]): SortedSet[B] =
62-
super[SortedSetOps].collect(pf)
63+
super[StrictOptimizedSortedSetOps].collect(pf)
6364

6465
// necessary for disambiguation
6566
override def zip[B](that: scala.Iterable[B])(implicit @implicitNotFound(collection.BitSet.zipOrdMsg) ev: Ordering[(Int, B)]): SortedSet[(Int, B)] =

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ package scala
22
package collection.immutable
33

44
import java.io.{ObjectInputStream, ObjectOutputStream}
5-
6-
import collection.{Iterator, MapFactory, StrictOptimizedIterableOps}
7-
import collection.Hashing.computeHash
8-
import scala.annotation.unchecked.{uncheckedVariance => uV}
95
import java.lang.Integer.bitCount
106
import java.lang.System.arraycopy
117

8+
import scala.annotation.unchecked.{uncheckedVariance => uV}
9+
import scala.collection.Hashing.computeHash
1210
import scala.collection.mutable.{Builder, ImmutableBuilder}
11+
import scala.collection.{Iterator, MapFactory, StrictOptimizedIterableOps, StrictOptimizedMapOps}
1312

1413
/** This class implements immutable maps using a Compressed Hash-Array Mapped Prefix-tree.
1514
* See paper https://michael.steindorfer.name/publications/oopsla15.pdf for more details.
@@ -26,7 +25,8 @@ import scala.collection.mutable.{Builder, ImmutableBuilder}
2625
final class ChampHashMap[K, +V] private[immutable] (private val rootNode: MapNode[K, V], private val cachedJavaKeySetHashCode: Int, private val cachedSize: Int)
2726
extends AbstractMap[K, V]
2827
with MapOps[K, V, ChampHashMap, ChampHashMap[K, V]]
29-
with StrictOptimizedIterableOps[(K, V), Iterable /* ChampHashMap */, ChampHashMap[K, V]] {
28+
with StrictOptimizedIterableOps[(K, V), Iterable, ChampHashMap[K, V]]
29+
with StrictOptimizedMapOps[K, V, ChampHashMap, ChampHashMap[K, V]] {
3030

3131
override def mapFactory: MapFactory[ChampHashMap] = ChampHashMap
3232

@@ -162,8 +162,8 @@ private[immutable] sealed abstract class MapNode[K, +V] extends MapNodeSource[K,
162162

163163
private class BitmapIndexedMapNode[K, +V](val dataMap: Int, val nodeMap: Int, val content: Array[Any]) extends MapNode[K, V] {
164164

165-
import Node._
166165
import MapNode._
166+
import Node._
167167

168168
/*
169169
assert(checkInvariantContentIsWellTyped())

0 commit comments

Comments
 (0)