Skip to content

Commit 1590004

Browse files
committed
Improved StepperShape
This does away with the default implementations of `MakesStepper` et. al. and moves the unboxing logic into `StepperShape` for simpler implementations with faster dispatch.
1 parent 56e66b9 commit 1590004

17 files changed

+137
-170
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ public static IntStream intStream(scala.collection.BitSet coll) {
484484
// Let the value class figure out the casting!
485485
scala.compat.java8.converterImpl.RichBitSetCanStep rbscs =
486486
new scala.compat.java8.converterImpl.RichBitSetCanStep(coll);
487-
return StreamSupport.intStream(rbscs.stepper(StepperShape$.MODULE$.IntValue()), false);
487+
return StreamSupport.intStream(rbscs.stepper(StepperShape$.MODULE$.intStepperShape()), false);
488488
}
489489

490490
/**

src/main/scala/scala/compat/java8/StreamConverters.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ sealed trait StreamShape[T, S <: BaseStream[_, S]] {
2121
def fromKeyStepper (mk: MakesKeyValueStepper[T, _, _], par: Boolean): S
2222
def fromValueStepper(mk: MakesKeyValueStepper[_, T, _], par: Boolean): S
2323
}
24-
object StreamShape extends StreamShapeLowPrio {
24+
object StreamShape extends StreamShapeLowPriority {
2525
// primitive
2626
implicit val IntValue = intStreamShape[Int]
2727
implicit val LongValue = longStreamShape[Long]
@@ -33,7 +33,7 @@ object StreamShape extends StreamShapeLowPrio {
3333
implicit val CharValue = intStreamShape[Char]
3434
implicit val FloatValue = doubleStreamShape[Float]
3535
}
36-
trait StreamShapeLowPrio {
36+
trait StreamShapeLowPriority {
3737
protected[this] abstract class BaseStreamShape[T, S <: BaseStream[_, S], St <: Stepper[_]](implicit ss: StepperShape[T, St]) extends StreamShape[T, S] {
3838
final def fromStepper (mk: MakesStepper[T, _], par: Boolean): S = stream(mk.stepper, par)
3939
final def fromKeyStepper (mk: MakesKeyValueStepper[T, _, _], par: Boolean): S = stream(mk.keyStepper, par)

src/main/scala/scala/compat/java8/converterImpl/MakesSteppers.scala

+63-91
Original file line numberDiff line numberDiff line change
@@ -18,104 +18,76 @@ trait MakesKeyValueStepper[K, V, +Extra] extends Any {
1818
def valueStepper[S <: Stepper[_]](implicit ss: StepperShape[V, S]): S with Extra
1919
}
2020

21-
sealed trait StepperShape[T, S <: Stepper[_]] { def ref: Boolean }
22-
object StepperShape extends StepperShapeLowPrio {
23-
private[this] def valueShape[T, S <: Stepper[_]]: StepperShape[T, S] = new StepperShape[T, S] { def ref = false }
21+
/** Encodes the translation from an element type `T` to the corresponding Stepper type `S` */
22+
sealed trait StepperShape[T, S <: Stepper[_]] {
23+
/** Return the Int constant (as defined in the `StepperShape` companion object) for this `StepperShape`. */
24+
def shape: Int
2425

25-
// primitive
26-
implicit val IntValue = valueShape[Int, IntStepper]
27-
implicit val LongValue = valueShape[Long, LongStepper]
28-
implicit val DoubleValue = valueShape[Double, DoubleStepper]
26+
/** Create an unboxing primitive sequential Stepper from a boxed `AnyStepper`.
27+
* This is an identity operation for reference shapes. */
28+
def seqUnbox(st: AnyStepper[T]): S
2929

30-
// widening
31-
implicit val ByteValue = valueShape[Byte, IntStepper]
32-
implicit val ShortValue = valueShape[Short, IntStepper]
33-
implicit val CharValue = valueShape[Char, IntStepper]
34-
implicit val FloatValue = valueShape[Float, DoubleStepper]
30+
/** Create an unboxing primitive parallel (i.e. `with EfficientSubstep`) Stepper from a boxed `AnyStepper`.
31+
* This is an identity operation for reference shapes. */
32+
def parUnbox(st: AnyStepper[T] with EfficientSubstep): S with EfficientSubstep
3533
}
36-
trait StepperShapeLowPrio {
34+
object StepperShape extends StepperShapeLowPriority {
3735
// reference
38-
implicit def anyStepperShape[T]: StepperShape[T, AnyStepper[T]] = new StepperShape[T, AnyStepper[T]] { def ref = true }
39-
}
40-
41-
/** Superclass for `MakesStepper` implementations which support parallelization. At least the `AnyStepper` case must be
42-
* implemented, all others default to building an `AnyStepper` and putting an unboxing conversion on top. */
43-
trait MakesParStepper[T] extends Any with MakesStepper[T, EfficientSubstep] {
44-
def stepper[S <: Stepper[_]](implicit ss: StepperShape[T, S]) = (ss match {
45-
case StepperShape.IntValue => new Stepper.UnboxingIntStepper (stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Int ]]) with EfficientSubstep
46-
case StepperShape.LongValue => new Stepper.UnboxingLongStepper (stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Long ]]) with EfficientSubstep
47-
case StepperShape.DoubleValue => new Stepper.UnboxingDoubleStepper(stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Double]]) with EfficientSubstep
48-
case StepperShape.ByteValue => new Stepper.UnboxingByteStepper (stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Byte ]]) with EfficientSubstep
49-
case StepperShape.ShortValue => new Stepper.UnboxingShortStepper (stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Short ]]) with EfficientSubstep
50-
case StepperShape.CharValue => new Stepper.UnboxingCharStepper (stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Char ]]) with EfficientSubstep
51-
case StepperShape.FloatValue => new Stepper.UnboxingFloatStepper (stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Float ]]) with EfficientSubstep
52-
case _ => throw new NotImplementedError("AnyStepper must be handled in `stepper` implementations")
53-
}).asInstanceOf[S with EfficientSubstep]
54-
}
36+
final val Reference = 0
5537

56-
/** Superclass for `MakesStepper` implementations which do not support parallelization. At least the `AnyStepper` case must be
57-
* implemented, all others default to building an `AnyStepper` and putting an unboxing conversion on top. */
58-
trait MakesSeqStepper[T] extends Any with MakesStepper[T, Any] {
59-
def stepper[S <: Stepper[_]](implicit ss: StepperShape[T, S]) = (ss match {
60-
case StepperShape.IntValue => new Stepper.UnboxingIntStepper (stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Int ]])
61-
case StepperShape.LongValue => new Stepper.UnboxingLongStepper (stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Long ]])
62-
case StepperShape.DoubleValue => new Stepper.UnboxingDoubleStepper(stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Double]])
63-
case StepperShape.ByteValue => new Stepper.UnboxingByteStepper (stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Byte ]])
64-
case StepperShape.ShortValue => new Stepper.UnboxingShortStepper (stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Short ]])
65-
case StepperShape.CharValue => new Stepper.UnboxingCharStepper (stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Char ]])
66-
case StepperShape.FloatValue => new Stepper.UnboxingFloatStepper (stepper(StepperShape.anyStepperShape[T]).asInstanceOf[AnyStepper[Float ]])
67-
case _ => throw new NotImplementedError("AnyStepper must be handled in `stepper` implementations")
68-
}).asInstanceOf[S]
69-
}
38+
// primitive
39+
final val IntValue = 1
40+
final val LongValue = 2
41+
final val DoubleValue = 3
7042

71-
/** Superclass for `MakesKeyalueStepper` implementations which support parallelization. At least the `AnyStepper` case must be
72-
* implemented, all others default to building an `AnyStepper` and putting an unboxing conversion on top. */
73-
trait MakesKeyValueParStepper[K, V] extends Any with MakesKeyValueStepper[K, V, EfficientSubstep] {
74-
def keyStepper[S <: Stepper[_]](implicit ss: StepperShape[K, S]) = (ss match {
75-
case StepperShape.IntValue => new Stepper.UnboxingIntStepper (keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Int ]]) with EfficientSubstep
76-
case StepperShape.LongValue => new Stepper.UnboxingLongStepper (keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Long ]]) with EfficientSubstep
77-
case StepperShape.DoubleValue => new Stepper.UnboxingDoubleStepper(keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Double]]) with EfficientSubstep
78-
case StepperShape.ByteValue => new Stepper.UnboxingByteStepper (keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Byte ]]) with EfficientSubstep
79-
case StepperShape.ShortValue => new Stepper.UnboxingShortStepper (keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Short ]]) with EfficientSubstep
80-
case StepperShape.CharValue => new Stepper.UnboxingCharStepper (keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Char ]]) with EfficientSubstep
81-
case StepperShape.FloatValue => new Stepper.UnboxingFloatStepper (keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Float ]]) with EfficientSubstep
82-
case _ => throw new NotImplementedError("AnyStepper case must be handled in `keyStepper` implementations")
83-
}).asInstanceOf[S with EfficientSubstep]
43+
// widening
44+
final val ByteValue = 4
45+
final val ShortValue = 5
46+
final val CharValue = 6
47+
final val FloatValue = 7
8448

85-
def valueStepper[S <: Stepper[_]](implicit ss: StepperShape[V, S]) = (ss match {
86-
case StepperShape.IntValue => new Stepper.UnboxingIntStepper (valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Int ]]) with EfficientSubstep
87-
case StepperShape.LongValue => new Stepper.UnboxingLongStepper (valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Long ]]) with EfficientSubstep
88-
case StepperShape.DoubleValue => new Stepper.UnboxingDoubleStepper(valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Double]]) with EfficientSubstep
89-
case StepperShape.ByteValue => new Stepper.UnboxingByteStepper (valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Byte ]]) with EfficientSubstep
90-
case StepperShape.ShortValue => new Stepper.UnboxingShortStepper (valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Short ]]) with EfficientSubstep
91-
case StepperShape.CharValue => new Stepper.UnboxingCharStepper (valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Char ]]) with EfficientSubstep
92-
case StepperShape.FloatValue => new Stepper.UnboxingFloatStepper (valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Float ]]) with EfficientSubstep
93-
case _ => throw new NotImplementedError("AnyStepper case must be handled in `valueStepper` implementations")
94-
}).asInstanceOf[S with EfficientSubstep]
49+
implicit val intStepperShape: StepperShape[Int, IntStepper] = new StepperShape[Int, IntStepper] {
50+
def shape = IntValue
51+
def seqUnbox(st: AnyStepper[Int]): IntStepper = new Stepper.UnboxingIntStepper(st)
52+
def parUnbox(st: AnyStepper[Int] with EfficientSubstep): IntStepper with EfficientSubstep = new Stepper.UnboxingIntStepper(st) with EfficientSubstep
53+
}
54+
implicit val longStepperShape: StepperShape[Long, LongStepper] = new StepperShape[Long, LongStepper] {
55+
def shape = LongValue
56+
def seqUnbox(st: AnyStepper[Long]): LongStepper = new Stepper.UnboxingLongStepper(st)
57+
def parUnbox(st: AnyStepper[Long] with EfficientSubstep): LongStepper with EfficientSubstep = new Stepper.UnboxingLongStepper(st) with EfficientSubstep
58+
}
59+
implicit val doubleStepperShape: StepperShape[Double, DoubleStepper] = new StepperShape[Double, DoubleStepper] {
60+
def shape = DoubleValue
61+
def seqUnbox(st: AnyStepper[Double]): DoubleStepper = new Stepper.UnboxingDoubleStepper(st)
62+
def parUnbox(st: AnyStepper[Double] with EfficientSubstep): DoubleStepper with EfficientSubstep = new Stepper.UnboxingDoubleStepper(st) with EfficientSubstep
63+
}
64+
implicit val byteStepperShape: StepperShape[Byte, IntStepper] = new StepperShape[Byte, IntStepper] {
65+
def shape = ByteValue
66+
def seqUnbox(st: AnyStepper[Byte]): IntStepper = new Stepper.UnboxingByteStepper(st)
67+
def parUnbox(st: AnyStepper[Byte] with EfficientSubstep): IntStepper with EfficientSubstep = new Stepper.UnboxingByteStepper(st) with EfficientSubstep
68+
}
69+
implicit val shortStepperShape: StepperShape[Short, IntStepper] = new StepperShape[Short, IntStepper] {
70+
def shape = ShortValue
71+
def seqUnbox(st: AnyStepper[Short]): IntStepper = new Stepper.UnboxingShortStepper(st)
72+
def parUnbox(st: AnyStepper[Short] with EfficientSubstep): IntStepper with EfficientSubstep = new Stepper.UnboxingShortStepper(st) with EfficientSubstep
73+
}
74+
implicit val charStepperShape: StepperShape[Char, IntStepper] = new StepperShape[Char, IntStepper] {
75+
def shape = CharValue
76+
def seqUnbox(st: AnyStepper[Char]): IntStepper = new Stepper.UnboxingCharStepper(st)
77+
def parUnbox(st: AnyStepper[Char] with EfficientSubstep): IntStepper with EfficientSubstep = new Stepper.UnboxingCharStepper(st) with EfficientSubstep
78+
}
79+
implicit val floatStepperShape: StepperShape[Float, DoubleStepper] = new StepperShape[Float, DoubleStepper] {
80+
def shape = FloatValue
81+
def seqUnbox(st: AnyStepper[Float]): DoubleStepper = new Stepper.UnboxingFloatStepper(st)
82+
def parUnbox(st: AnyStepper[Float] with EfficientSubstep): DoubleStepper with EfficientSubstep = new Stepper.UnboxingFloatStepper(st) with EfficientSubstep
83+
}
9584
}
85+
trait StepperShapeLowPriority {
86+
implicit def anyStepperShape[T] = anyStepperShapePrototype.asInstanceOf[StepperShape[T, AnyStepper[T]]]
9687

97-
/** Superclass for `MakesKeyalueStepper` implementations which do not support parallelization. At least the `AnyStepper` case must be
98-
* implemented, all others default to building an `AnyStepper` and putting an unboxing conversion on top. */
99-
trait MakesKeyValueSeqStepper[K, V] extends Any with MakesKeyValueStepper[K, V, Any] {
100-
def keyStepper[S <: Stepper[_]](implicit ss: StepperShape[K, S]) = (ss match {
101-
case StepperShape.IntValue => new Stepper.UnboxingIntStepper (keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Int ]])
102-
case StepperShape.LongValue => new Stepper.UnboxingLongStepper (keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Long ]])
103-
case StepperShape.DoubleValue => new Stepper.UnboxingDoubleStepper(keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Double]])
104-
case StepperShape.ByteValue => new Stepper.UnboxingByteStepper (keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Byte ]])
105-
case StepperShape.ShortValue => new Stepper.UnboxingShortStepper (keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Short ]])
106-
case StepperShape.CharValue => new Stepper.UnboxingCharStepper (keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Char ]])
107-
case StepperShape.FloatValue => new Stepper.UnboxingFloatStepper (keyStepper(StepperShape.anyStepperShape[K]).asInstanceOf[AnyStepper[Float ]])
108-
case _ => throw new NotImplementedError("AnyStepper case must be handled in `keyStepper` implementations")
109-
}).asInstanceOf[S]
110-
111-
def valueStepper[S <: Stepper[_]](implicit ss: StepperShape[V, S]) = (ss match {
112-
case StepperShape.IntValue => new Stepper.UnboxingIntStepper (valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Int ]])
113-
case StepperShape.LongValue => new Stepper.UnboxingLongStepper (valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Long ]])
114-
case StepperShape.DoubleValue => new Stepper.UnboxingDoubleStepper(valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Double]])
115-
case StepperShape.ByteValue => new Stepper.UnboxingByteStepper (valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Byte ]])
116-
case StepperShape.ShortValue => new Stepper.UnboxingShortStepper (valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Short ]])
117-
case StepperShape.CharValue => new Stepper.UnboxingCharStepper (valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Char ]])
118-
case StepperShape.FloatValue => new Stepper.UnboxingFloatStepper (valueStepper(StepperShape.anyStepperShape[V]).asInstanceOf[AnyStepper[Float ]])
119-
case _ => throw new NotImplementedError("AnyStepper case must be handled in `valueStepper` implementations")
120-
}).asInstanceOf[S]
88+
private[this] val anyStepperShapePrototype: StepperShape[AnyRef, AnyStepper[AnyRef]] = new StepperShape[AnyRef, AnyStepper[AnyRef]] {
89+
def shape = StepperShape.Reference
90+
def seqUnbox(st: AnyStepper[AnyRef]): AnyStepper[AnyRef] = st
91+
def parUnbox(st: AnyStepper[AnyRef] with EfficientSubstep): AnyStepper[AnyRef] with EfficientSubstep = st
92+
}
12193
}

src/main/scala/scala/compat/java8/converterImpl/StepsArray.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package scala.compat.java8.converterImpl
22

33
import language.implicitConversions
4+
import scala.annotation.switch
45

56
import scala.compat.java8.collectionImpl._
67
import scala.compat.java8.runtime._
@@ -69,9 +70,9 @@ extends StepsLongLikeIndexed[StepsLongArray](_i0, _iN) {
6970
// Value class adapters //
7071
//////////////////////////
7172

72-
final class RichArrayCanStep[T](private val underlying: Array[T]) extends AnyVal with MakesParStepper[T] {
73-
override def stepper[S <: Stepper[_]](implicit ss: StepperShape[T, S]) = (ss match {
74-
case ss if ss.ref =>
73+
final class RichArrayCanStep[T](private val underlying: Array[T]) extends AnyVal with MakesStepper[T, EfficientSubstep] {
74+
override def stepper[S <: Stepper[_]](implicit ss: StepperShape[T, S]) = ((ss.shape: @switch) match {
75+
case StepperShape.Reference =>
7576
if(underlying.isInstanceOf[Array[Boolean]])
7677
new StepsBoxedBooleanArray (underlying.asInstanceOf[Array[Boolean]], 0, underlying.length)
7778
else new StepsObjectArray[AnyRef](underlying.asInstanceOf[Array[AnyRef ]], 0, underlying.length)
@@ -82,6 +83,5 @@ final class RichArrayCanStep[T](private val underlying: Array[T]) extends AnyVal
8283
case StepperShape.ShortValue => new StepsWidenedShortArray (underlying.asInstanceOf[Array[Short ]], 0, underlying.length)
8384
case StepperShape.CharValue => new StepsWidenedCharArray (underlying.asInstanceOf[Array[Char ]], 0, underlying.length)
8485
case StepperShape.FloatValue => new StepsWidenedFloatArray (underlying.asInstanceOf[Array[Float ]], 0, underlying.length)
85-
case ss => super.stepper(ss)
8686
}).asInstanceOf[S with EfficientSubstep]
8787
}

src/main/scala/scala/compat/java8/converterImpl/StepsBitSet.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ extends StepsIntLikeSliced[Array[Long], StepsIntBitSet](_underlying, _i0, _iN) {
5353
// Value class adapter //
5454
/////////////////////////
5555

56-
final class RichBitSetCanStep(private val underlying: collection.BitSet) extends AnyVal with MakesParStepper[Int] {
56+
final class RichBitSetCanStep(private val underlying: collection.BitSet) extends AnyVal with MakesStepper[Int, EfficientSubstep] {
5757
override def stepper[S <: Stepper[_]](implicit ss: StepperShape[Int, S]) = {
5858
val bits: Array[Long] = underlying match {
5959
case m: collection.mutable.BitSet => CollectionInternals.getBitSetInternals(m)

src/main/scala/scala/compat/java8/converterImpl/StepsFlatHashTable.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package scala.compat.java8.converterImpl
22

33
import language.implicitConversions
4+
import scala.annotation.switch
45

56
import scala.compat.java8.collectionImpl._
67
import scala.compat.java8.runtime._
@@ -39,15 +40,14 @@ extends StepsLongLikeGapped[StepsLongFlatHashTable](_underlying, _i0, _iN) {
3940
// Value class adapters //
4041
//////////////////////////
4142

42-
final class RichFlatHashTableCanStep[T](private val underlying: collection.mutable.FlatHashTable[T]) extends AnyVal with MakesParStepper[T] {
43+
final class RichFlatHashTableCanStep[T](private val underlying: collection.mutable.FlatHashTable[T]) extends AnyVal with MakesStepper[T, EfficientSubstep] {
4344
override def stepper[S <: Stepper[_]](implicit ss: StepperShape[T, S]) = {
4445
val tbl = CollectionInternals.getTable(underlying)
45-
(ss match {
46-
case ss if ss.ref => new StepsAnyFlatHashTable[T](tbl, 0, tbl.length)
46+
((ss.shape: @switch) match {
4747
case StepperShape.IntValue => new StepsIntFlatHashTable (tbl, 0, tbl.length)
4848
case StepperShape.LongValue => new StepsLongFlatHashTable (tbl, 0, tbl.length)
4949
case StepperShape.DoubleValue => new StepsDoubleFlatHashTable(tbl, 0, tbl.length)
50-
case ss => super.stepper(ss)
50+
case _ => ss.parUnbox(new StepsAnyFlatHashTable[T](tbl, 0, tbl.length))
5151
}).asInstanceOf[S with EfficientSubstep]
5252
}
5353
}

0 commit comments

Comments
 (0)