Skip to content

Commit 56e66b9

Browse files
committed
A new approach to Stepper and Stream materialization
Getting the most efficient Stepper implementation requires knowledge of the static type of a collection. This problem could be solved in the most elegant way by integrating Steppers into the collections framework as a replacement for Iterators (i.e. every collection gets a `stepper` method and `iterator` delegates to `stepper` by default). But this is at odds with the handling of specialized primitive Steppers in the current implementation. If we want `stepper` to be an instance methods instead of an extension method, there needs to be a single such method for all specialized Steppers. The fundamental change in this new implementation is to encode the translation from element type to Stepper type (including widening conversions) as a functional dependency via the new `StepperShape` trait. This greatly reduces the number of implicit methods and classes and keeps all specialized versions of `MakesStepper` together. The default base classes support all unboxing and widening conversions so that a simple `MakesStepper` for a collection of boxed elements only needs to handle the `AnyStepper` case. `keyStepper` and `valueStepper` are handled in the same way. `StreamConverters` use a separate `StreamShape` for the translation from element type to `BaseStream` subtype which is compatible with `StepConverters` and supports the same primitive types and widening conversions.
1 parent c022190 commit 56e66b9

22 files changed

+479
-726
lines changed

benchmark/src/main/scala/bench/CollectionSource.scala

+29-28
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import scala.collection.generic.CanBuildFrom
66
import scala.compat.java8.StreamConverters._
77
import scala.compat.java8.collectionImpl._
88
import scala.compat.java8.converterImpl._
9+
import scala.compat.java8.{MakesSequentialStream, MakesParallelStream}
910

1011
package object generate {
1112
private def myInty(n: Int) = 0 until n
@@ -25,42 +26,42 @@ package object generate {
2526
}
2627

2728
object Pstep {
28-
def i[CC](cc: CC)(implicit steppize: CC => MakesStepper[IntStepper with EfficientSubstep]): IntStepper =
29+
def i[CC](cc: CC)(implicit steppize: CC => MakesStepper[Int, EfficientSubstep]): IntStepper =
2930
steppize(cc).stepper
30-
def s[CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[String] with EfficientSubstep]): AnyStepper[String] =
31+
def s[CC](cc: CC)(implicit steppize: CC => MakesStepper[String, EfficientSubstep]): AnyStepper[String] =
3132
steppize(cc).stepper
3233
}
3334

3435
object Sstep {
35-
def i[CC](cc: CC)(implicit steppize: CC => MakesStepper[IntStepper]): IntStepper =
36+
def i[CC](cc: CC)(implicit steppize: CC => MakesStepper[Int, Any]): IntStepper =
3637
steppize(cc).stepper
37-
def s[CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[String]]): AnyStepper[String] =
38+
def s[CC](cc: CC)(implicit steppize: CC => MakesStepper[String, Any]): AnyStepper[String] =
3839
steppize(cc).stepper
3940
}
4041

4142
object PsStream {
42-
def i[CC](cc: CC)(implicit steppize: CC => MakesStepper[IntStepper with EfficientSubstep]): IntStream =
43+
def i[CC](cc: CC)(implicit steppize: CC => MakesStepper[Int, EfficientSubstep]): IntStream =
4344
steppize(cc).stepper.parStream
44-
def s[CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[String] with EfficientSubstep]): Stream[String] =
45+
def s[CC](cc: CC)(implicit steppize: CC => MakesStepper[String, EfficientSubstep]): Stream[String] =
4546
steppize(cc).stepper.parStream
4647
}
4748

4849
object SsStream {
49-
def i[CC](cc: CC)(implicit steppize: CC => MakesStepper[IntStepper]): IntStream =
50+
def i[CC](cc: CC)(implicit steppize: CC => MakesStepper[Int, Any]): IntStream =
5051
steppize(cc).stepper.seqStream
51-
def s[CC](cc: CC)(implicit steppize: CC => MakesStepper[AnyStepper[String]]): Stream[String] =
52+
def s[CC](cc: CC)(implicit steppize: CC => MakesStepper[String, Any]): Stream[String] =
5253
steppize(cc).stepper.seqStream
5354
}
5455

5556
object Sstream {
56-
def i[CC](cc: CC)(implicit streamize: CC => MakesSequentialStream[java.lang.Integer, IntStream]) =
57+
def i[CC](cc: CC)(implicit streamize: CC => MakesSequentialStream[Int, IntStream]) =
5758
streamize(cc).seqStream
5859
def s[CC](cc: CC)(implicit streamize: CC => MakesSequentialStream[String, Stream[String]]) =
5960
streamize(cc).seqStream
6061
}
6162

6263
object Pstream {
63-
def i[CC](cc: CC)(implicit streamize: CC => MakesParallelStream[java.lang.Integer, IntStream]) =
64+
def i[CC](cc: CC)(implicit streamize: CC => MakesParallelStream[Int, IntStream]) =
6465
streamize(cc).parStream
6566
def s[CC](cc: CC)(implicit streamize: CC => MakesParallelStream[String, Stream[String]]) =
6667
streamize(cc).parStream
@@ -78,14 +79,14 @@ package object generate {
7879
// Iterator
7980
def iI(j: Int)(implicit x: CC[Int] => Iterator[Int]) = x(cI(j))
8081
// Steppers (second letter--s = sequential, p = parallel)
81-
def tsI(j: Int)(implicit x: CC[Int] => MakesStepper[IntStepper]) = Sstep i cI(j)
82-
def tpI(j: Int)(implicit x: CC[Int] => MakesStepper[IntStepper with EfficientSubstep]) = Pstep i cI(j)
82+
def tsI(j: Int)(implicit x: CC[Int] => MakesStepper[Int, Any]) = Sstep i cI(j)
83+
def tpI(j: Int)(implicit x: CC[Int] => MakesStepper[Int, EfficientSubstep]) = Pstep i cI(j)
8384
// Streams
84-
def ssI(j: Int)(implicit x: CC[Int] => MakesSequentialStream[java.lang.Integer, IntStream]) = Sstream i cI(j)
85-
def spI(j: Int)(implicit x: CC[Int] => MakesParallelStream[java.lang.Integer, IntStream]) = Pstream i cI(j)
85+
def ssI(j: Int)(implicit x: CC[Int] => MakesSequentialStream[Int, IntStream]) = Sstream i cI(j)
86+
def spI(j: Int)(implicit x: CC[Int] => MakesParallelStream[Int, IntStream]) = Pstream i cI(j)
8687
// Streams via steppers
87-
def zsI(j: Int)(implicit x: CC[Int] => MakesStepper[IntStepper]) = SsStream i cI(j)
88-
def zpI(j: Int)(implicit x: CC[Int] => MakesStepper[IntStepper with EfficientSubstep]) = PsStream i cI(j)
88+
def zsI(j: Int)(implicit x: CC[Int] => MakesStepper[Int, Any]) = SsStream i cI(j)
89+
def zpI(j: Int)(implicit x: CC[Int] => MakesStepper[Int, EfficientSubstep]) = PsStream i cI(j)
8990
}
9091

9192
trait StringThingsOf[CC[_]] extends GenThingsOf[CC] {
@@ -95,14 +96,14 @@ package object generate {
9596
// Iterator
9697
def iS(j: Int)(implicit x: CC[String] => Iterator[String]) = x(cS(j))
9798
// Steppers (second letter--s = sequential, p = parallel)
98-
def tsS(j: Int)(implicit x: CC[String] => MakesStepper[AnyStepper[String]]) = Sstep s cS(j)
99-
def tpS(j: Int)(implicit x: CC[String] => MakesStepper[AnyStepper[String] with EfficientSubstep]) = Pstep s cS(j)
99+
def tsS(j: Int)(implicit x: CC[String] => MakesStepper[String, Any]) = Sstep s cS(j)
100+
def tpS(j: Int)(implicit x: CC[String] => MakesStepper[String, EfficientSubstep]) = Pstep s cS(j)
100101
// Streams
101102
def ssS(j: Int)(implicit x: CC[String] => MakesSequentialStream[String, Stream[String]]) = Sstream s cS(j)
102103
def spS(j: Int)(implicit x: CC[String] => MakesParallelStream[String, Stream[String]]) = Pstream s cS(j)
103104
// Streams via steppers
104-
def zsS(j: Int)(implicit x: CC[String] => MakesStepper[AnyStepper[String]]) = SsStream s cS(j)
105-
def zpS(j: Int)(implicit x: CC[String] => MakesStepper[AnyStepper[String] with EfficientSubstep]) = PsStream s cS(j)
105+
def zsS(j: Int)(implicit x: CC[String] => MakesStepper[String, Any]) = SsStream s cS(j)
106+
def zpS(j: Int)(implicit x: CC[String] => MakesStepper[String, EfficientSubstep]) = PsStream s cS(j)
106107
}
107108

108109
trait ThingsOf[CC[_]] extends IntThingsOf[CC] with StringThingsOf[CC] {}
@@ -158,16 +159,16 @@ package object generate {
158159

159160
// Streams from ArrayList (Java)
160161

161-
implicit val getsParStreamFromArrayListInt: (java.util.ArrayList[Int] => MakesParallelStream[java.lang.Integer, IntStream]) = ali => {
162-
new MakesParallelStream[java.lang.Integer, IntStream] {
162+
implicit val getsParStreamFromArrayListInt: (java.util.ArrayList[Int] => MakesParallelStream[Int, IntStream]) = ali => {
163+
new MakesParallelStream[Int, IntStream] {
163164
def parStream: IntStream = ali.
164165
asInstanceOf[java.util.ArrayList[java.lang.Integer]].
165166
parallelStream.parallel.
166167
mapToInt(new java.util.function.ToIntFunction[java.lang.Integer]{ def applyAsInt(i: java.lang.Integer) = i.intValue })
167168
}
168169
}
169-
implicit val getsSeqStreamFromArrayListInt: (java.util.ArrayList[Int] => MakesSequentialStream[java.lang.Integer, IntStream]) = ali => {
170-
new MakesSequentialStream[java.lang.Integer, IntStream] {
170+
implicit val getsSeqStreamFromArrayListInt: (java.util.ArrayList[Int] => MakesSequentialStream[Int, IntStream]) = ali => {
171+
new MakesSequentialStream[Int, IntStream] {
171172
def seqStream: IntStream = ali.
172173
asInstanceOf[java.util.ArrayList[java.lang.Integer]].
173174
stream().
@@ -187,16 +188,16 @@ package object generate {
187188

188189
// Streams from LinkedList (Java)
189190

190-
implicit val getsParStreamFromLinkedListInt: (java.util.LinkedList[Int] => MakesParallelStream[java.lang.Integer, IntStream]) = ali => {
191-
new MakesParallelStream[java.lang.Integer, IntStream] {
191+
implicit val getsParStreamFromLinkedListInt: (java.util.LinkedList[Int] => MakesParallelStream[Int, IntStream]) = ali => {
192+
new MakesParallelStream[Int, IntStream] {
192193
def parStream: IntStream = ali.
193194
asInstanceOf[java.util.LinkedList[java.lang.Integer]].
194195
parallelStream.parallel.
195196
mapToInt(new java.util.function.ToIntFunction[java.lang.Integer]{ def applyAsInt(i: java.lang.Integer) = i.intValue })
196197
}
197198
}
198-
implicit val getsSeqStreamFromLinkedListInt: (java.util.LinkedList[Int] => MakesSequentialStream[java.lang.Integer, IntStream]) = ali => {
199-
new MakesSequentialStream[java.lang.Integer, IntStream] {
199+
implicit val getsSeqStreamFromLinkedListInt: (java.util.LinkedList[Int] => MakesSequentialStream[Int, IntStream]) = ali => {
200+
new MakesSequentialStream[Int, IntStream] {
200201
def seqStream: IntStream = ali.
201202
asInstanceOf[java.util.LinkedList[java.lang.Integer]].
202203
stream().

src/main/java/scala/compat/java8/ScalaStreamSupport.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -482,9 +482,9 @@ public static DoubleStream doubleStreamAccumulatedValues(scala.collection.Map<?,
482482
*/
483483
public static IntStream intStream(scala.collection.BitSet coll) {
484484
// Let the value class figure out the casting!
485-
scala.compat.java8.converterImpl.RichBitSetCanStep rbscs =
485+
scala.compat.java8.converterImpl.RichBitSetCanStep rbscs =
486486
new scala.compat.java8.converterImpl.RichBitSetCanStep(coll);
487-
return StreamSupport.intStream(rbscs.stepper(), false);
487+
return StreamSupport.intStream(rbscs.stepper(StepperShape$.MODULE$.IntValue()), false);
488488
}
489489

490490
/**

0 commit comments

Comments
 (0)