scala.collection.convert.StreamExtensions.scala Maven / Gradle / Ivy
The newest version!
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc.
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/
package scala.collection.convert
import java.util.Spliterator
import java.util.stream._
import java.{lang => jl}
import scala.annotation.implicitNotFound
import scala.collection.Stepper.EfficientSplit
import scala.collection._
import scala.collection.convert.StreamExtensions.{AccumulatorFactoryInfo, StreamShape, StreamUnboxer}
import scala.jdk.CollectionConverters._
import scala.jdk._
/** Defines extension methods to create Java Streams for Scala collections, available through
* [[scala.jdk.javaapi.StreamConverters]].
*/
trait StreamExtensions {
// collections
implicit class IterableHasSeqStream[A](cc: IterableOnce[A]) {
/** Create a sequential [[java.util.stream.Stream Java Stream]] for this collection. If the
* collection contains primitive values, a corresponding specialized Stream is returned (e.g.,
* [[java.util.stream.IntStream `IntStream`]]).
*/
def asJavaSeqStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit s: StreamShape[A, S, St], st: StepperShape[A, St]): S =
s.fromStepper(cc.stepper, par = false)
}
// Not `CC[X] <: IterableOnce[X]`, but `C` with an extra constraint, to support non-parametric classes like IntAccumulator
implicit class IterableNonGenericHasParStream[A, C <: IterableOnce[_]](c: C)(implicit ev: C <:< IterableOnce[A]) {
private type IterableOnceWithEfficientStepper = IterableOnce[A] {
def stepper[S <: Stepper[_]](implicit shape : StepperShape[A, S]) : S with EfficientSplit
}
/** Create a parallel [[java.util.stream.Stream Java Stream]] for this collection. If the
* collection contains primitive values, a corresponding specialized Stream is returned (e.g.,
* [[java.util.stream.IntStream `IntStream`]]).
*/
def asJavaParStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit
s: StreamShape[A, S, St],
st: StepperShape[A, St],
@implicitNotFound("`parStream` can only be called on collections where `stepper` returns a `Stepper with EfficientSplit`")
isEfficient: C <:< IterableOnceWithEfficientStepper): S =
s.fromStepper(ev(c).stepper, par = true)
}
// maps
implicit class MapHasSeqKeyValueStream[K, V, CC[X, Y] <: collection.MapOps[X, Y, collection.Map, _]](cc: CC[K, V]) {
/** Create a sequential [[java.util.stream.Stream Java Stream]] for the keys of this map. If
* the keys are primitive values, a corresponding specialized Stream is returned (e.g.,
* [[java.util.stream.IntStream `IntStream`]]).
*/
def asJavaSeqKeyStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit s: StreamShape[K, S, St], st: StepperShape[K, St]): S =
s.fromStepper(cc.keyStepper, par = false)
/** Create a sequential [[java.util.stream.Stream Java Stream]] for the values of this map. If
* the values are primitives, a corresponding specialized Stream is returned (e.g.,
* [[java.util.stream.IntStream `IntStream`]]).
*/
def asJavaSeqValueStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit s: StreamShape[V, S, St], st: StepperShape[V, St]): S =
s.fromStepper(cc.valueStepper, par = false)
// The asJavaSeqStream extension method for IterableOnce doesn't apply because its `CC` takes a single type parameter, whereas the one here takes two
/** Create a sequential [[java.util.stream.Stream Java Stream]] for the `(key, value)` pairs of
* this map.
*/
def asJavaSeqStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit s: StreamShape[(K, V), S, St], st: StepperShape[(K, V), St]): S =
s.fromStepper(cc.stepper, par = false)
}
implicit class MapHasParKeyValueStream[K, V, CC[X, Y] <: collection.MapOps[X, Y, collection.Map, _]](cc: CC[K, V]) {
private type MapOpsWithEfficientKeyStepper = collection.MapOps[K, V, collection.Map, _] { def keyStepper[S <: Stepper[_]](implicit shape : StepperShape[K, S]) : S with EfficientSplit }
private type MapOpsWithEfficientValueStepper = collection.MapOps[K, V, collection.Map, _] { def valueStepper[S <: Stepper[_]](implicit shape : StepperShape[V, S]) : S with EfficientSplit }
private type MapOpsWithEfficientStepper = collection.MapOps[K, V, collection.Map, _] { def stepper[S <: Stepper[_]](implicit shape : StepperShape[(K, V), S]) : S with EfficientSplit }
/** Create a parallel [[java.util.stream.Stream Java Stream]] for the keys of this map. If
* the keys are primitive values, a corresponding specialized Stream is returned (e.g.,
* [[java.util.stream.IntStream `IntStream`]]).
*/
def asJavaParKeyStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit
s: StreamShape[K, S, St],
st: StepperShape[K, St],
@implicitNotFound("parKeyStream can only be called on maps where `keyStepper` returns a `Stepper with EfficientSplit`")
isEfficient: CC[K, V] <:< MapOpsWithEfficientKeyStepper): S =
s.fromStepper(cc.keyStepper, par = true)
/** Create a parallel [[java.util.stream.Stream Java Stream]] for the values of this map. If
* the values are primitives, a corresponding specialized Stream is returned (e.g.,
* [[java.util.stream.IntStream `IntStream`]]).
*/
def asJavaParValueStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit
s: StreamShape[V, S, St],
st: StepperShape[V, St],
@implicitNotFound("parValueStream can only be called on maps where `valueStepper` returns a `Stepper with EfficientSplit`")
isEfficient: CC[K, V] <:< MapOpsWithEfficientValueStepper): S =
s.fromStepper(cc.valueStepper, par = true)
// The asJavaParStream extension method for IterableOnce doesn't apply because its `CC` takes a single type parameter, whereas the one here takes two
/** Create a parallel [[java.util.stream.Stream Java Stream]] for the `(key, value)` pairs of
* this map.
*/
def asJavaParStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit
s: StreamShape[(K, V), S, St],
st: StepperShape[(K, V), St],
@implicitNotFound("parStream can only be called on maps where `stepper` returns a `Stepper with EfficientSplit`")
isEfficient: CC[K, V] <:< MapOpsWithEfficientStepper): S =
s.fromStepper(cc.stepper, par = true)
}
// steppers
implicit class StepperHasSeqStream[A](stepper: Stepper[A]) {
/** Create a sequential [[java.util.stream.Stream Java Stream]] for this stepper. If the
* stepper yields primitive values, a corresponding specialized Stream is returned (e.g.,
* [[java.util.stream.IntStream `IntStream`]]).
*/
def asJavaSeqStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit s: StreamShape[A, S, St], st: StepperShape[A, St]): S = {
val sStepper = stepper match {
case as: AnyStepper[A] => st.seqUnbox(as)
case _ => stepper.asInstanceOf[St]
}
s.fromStepper(sStepper, par = false)
}
}
implicit class StepperHasParStream[A](stepper: Stepper[A] with EfficientSplit) {
/** Create a parallel [[java.util.stream.Stream Java Stream]] for this stepper. If the
* stepper yields primitive values, a corresponding specialized Stream is returned (e.g.,
* [[java.util.stream.IntStream `IntStream`]]).
*/
def asJavaParStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit s: StreamShape[A, S, St], st: StepperShape[A, St]): S = {
val sStepper = stepper match {
case as: AnyStepper[A] with EfficientSplit => st.parUnbox(as)
case _ => stepper.asInstanceOf[St]
}
s.fromStepper(sStepper, par = true)
}
}
// arrays
// uses the JDK array spliterators (`DoubleArraySpliterator`). users can also call
// `array.stepper.seqStream`, which then uses the Scala steppers (`DoubleArrayStepper`). the
// steppers are also available on byte/short/char/float arrays (`WidenedByteArrayStepper`),
// JDK spliterators only for double/int/long/reference.
implicit class DoubleArrayHasSeqParStream(a: Array[Double]) {
/** Create a sequential [[java.util.stream.DoubleStream Java DoubleStream]] for this array. */
def asJavaSeqStream: DoubleStream = java.util.Arrays.stream(a)
/** Create a parallel [[java.util.stream.DoubleStream Java DoubleStream]] for this array. */
def asJavaParStream: DoubleStream = asJavaSeqStream.parallel
}
implicit class IntArrayHasSeqParStream(a: Array[Int]) {
/** Create a sequential [[java.util.stream.IntStream Java IntStream]] for this array. */
def asJavaSeqStream: IntStream = java.util.Arrays.stream(a)
/** Create a parallel [[java.util.stream.IntStream Java IntStream]] for this array. */
def asJavaParStream: IntStream = asJavaSeqStream.parallel
}
implicit class LongArrayHasSeqParStream(a: Array[Long]) {
/** Create a sequential [[java.util.stream.LongStream Java LongStream]] for this array. */
def asJavaSeqStream: LongStream = java.util.Arrays.stream(a)
/** Create a parallel [[java.util.stream.LongStream Java LongStream]] for this array. */
def asJavaParStream: LongStream = asJavaSeqStream.parallel
}
implicit class AnyArrayHasSeqParStream[A <: AnyRef](a: Array[A]) {
/** Create a sequential [[java.util.stream.Stream Java Stream]] for this array. */
def asJavaSeqStream: Stream[A] = java.util.Arrays.stream(a)
/** Create a parallel [[java.util.stream.Stream Java Stream]] for this array. */
def asJavaParStream: Stream[A] = asJavaSeqStream.parallel
}
implicit class ByteArrayHasSeqParStream(a: Array[Byte]) {
/** Create a sequential [[java.util.stream.IntStream Java IntStream]] for this array. */
def asJavaSeqStream: IntStream = a.stepper.asJavaSeqStream
/** Create a parallel [[java.util.stream.IntStream Java IntStream]] for this array. */
def asJavaParStream: IntStream = a.stepper.asJavaParStream
}
implicit class ShortArrayHasSeqParStream(a: Array[Short]) {
/** Create a sequential [[java.util.stream.IntStream Java IntStream]] for this array. */
def asJavaSeqStream: IntStream = a.stepper.asJavaSeqStream
/** Create a parallel [[java.util.stream.IntStream Java IntStream]] for this array. */
def asJavaParStream: IntStream = a.stepper.asJavaParStream
}
implicit class CharArrayHasSeqParStream(a: Array[Char]) {
/** Create a sequential [[java.util.stream.IntStream Java IntStream]] for this array. */
def asJavaSeqStream: IntStream = a.stepper.asJavaSeqStream
/** Create a parallel [[java.util.stream.IntStream Java IntStream]] for this array. */
def asJavaParStream: IntStream = a.stepper.asJavaParStream
}
implicit class FloatArrayHasSeqParStream(a: Array[Float]) {
/** Create a sequential [[java.util.stream.DoubleStream Java DoubleStream]] for this array. */
def asJavaSeqStream: DoubleStream = a.stepper.asJavaSeqStream
/** Create a parallel [[java.util.stream.DoubleStream Java DoubleStream]] for this array. */
def asJavaParStream: DoubleStream = a.stepper.asJavaParStream
}
// strings
implicit class StringHasSeqParStream(s: String) {
/**
* A sequential stream on the characters of a string, same as [[asJavaSeqCharStream]]. See also
* [[asJavaSeqCodePointStream]].
*/
def asJavaSeqStream: IntStream = StreamSupport.intStream(s.stepper.spliterator, /* par = */ false)
/**
* A parallel stream on the characters of a string, same as [[asJavaParCharStream]]. See also
* [[asJavaParCodePointStream]].
*/
def asJavaParStream: IntStream = StreamSupport.intStream(s.stepper.spliterator, /* par = */ true)
/** A sequential stream on the characters of a string. See also [[asJavaSeqCodePointStream]]. */
def asJavaSeqCharStream: IntStream = StreamSupport.intStream(s.charStepper.spliterator, /* par = */ false)
/** A parallel stream on the characters of a string. See also [[asJavaParCodePointStream]]. */
def asJavaParCharStream: IntStream = StreamSupport.intStream(s.charStepper.spliterator, /* par = */ true)
/** A sequential stream on the code points of a string. See also [[asJavaSeqCharStream]]. */
def asJavaSeqCodePointStream: IntStream = StreamSupport.intStream(s.codePointStepper.spliterator, /* par = */ false)
/** A parallel stream on the code points of a string. See also [[asJavaParCharStream]]. */
def asJavaParCodePointStream: IntStream = StreamSupport.intStream(s.codePointStepper.spliterator, /* par = */ true)
}
// toScala for streams
implicit class StreamHasToScala[A](stream: Stream[A]) {
/**
* Copy the elements of this stream into a Scala collection.
*
* Converting a parallel streams to an [[scala.jdk.Accumulator]] using `stream.toScala(Accumulator)`
* builds the result in parallel.
*
* A `toScala(Accumulator)` call automatically converts streams of boxed integers, longs or
* doubles are converted to the primitive accumulators ([[scala.jdk.IntAccumulator]], etc.).
*
* When converting a parallel stream to a different Scala collection, the stream is first
* converted into an [[scala.jdk.Accumulator]], which supports parallel building. The accumulator is
* then converted to the target collection. Note that the stream is processed eagerly while
* building the accumulator, even if the target collection is lazy.
*
* Sequential streams are directly converted to the target collection. If the target collection
* is lazy, the conversion is lazy as well.
*/
def toScala[C1](factory: collection.Factory[A, C1])(implicit info: AccumulatorFactoryInfo[A, C1]): C1 = {
def anyAcc = stream.collect(AnyAccumulator.supplier[A], AnyAccumulator.adder[A], AnyAccumulator.merger[A])
if (info.companion == AnyAccumulator) anyAcc.asInstanceOf[C1]
else if (info.companion == IntAccumulator) stream.asInstanceOf[Stream[Int]].collect(IntAccumulator.supplier, IntAccumulator.boxedAdder, IntAccumulator.merger).asInstanceOf[C1]
else if (info.companion == LongAccumulator) stream.asInstanceOf[Stream[Long]].collect(LongAccumulator.supplier, LongAccumulator.boxedAdder, LongAccumulator.merger).asInstanceOf[C1]
else if (info.companion == DoubleAccumulator) stream.asInstanceOf[Stream[Double]].collect(DoubleAccumulator.supplier, DoubleAccumulator.boxedAdder, DoubleAccumulator.merger).asInstanceOf[C1]
else if (stream.isParallel) anyAcc.to(factory)
else factory.fromSpecific(stream.iterator.asScala)
}
/** Convert a generic Java Stream wrapping a primitive type to a corresponding primitive
* Stream.
*/
def asJavaPrimitiveStream[S](implicit unboxer: StreamUnboxer[A, S]): S = unboxer(stream)
}
implicit class IntStreamHasToScala(stream: IntStream) {
/**
* Copy the elements of this stream into a Scala collection.
*
* Converting a parallel streams to an [[scala.jdk.Accumulator]] using `stream.toScala(Accumulator)`
* builds the result in parallel.
*
* A `toScala(Accumulator)` call automatically converts the `IntStream` to a primitive
* [[scala.jdk.IntAccumulator]].
*
* When converting a parallel stream to a different Scala collection, the stream is first
* converted into an [[scala.jdk.Accumulator]], which supports parallel building. The accumulator is
* then converted to the target collection. Note that the stream is processed eagerly while
* building the accumulator, even if the target collection is lazy.
*
* Sequential streams are directly converted to the target collection. If the target collection
* is lazy, the conversion is lazy as well.
*/
def toScala[C1](factory: collection.Factory[Int, C1])(implicit info: AccumulatorFactoryInfo[Int, C1]): C1 = {
def intAcc = stream.collect(IntAccumulator.supplier, IntAccumulator.adder, IntAccumulator.merger)
if (info.companion == AnyAccumulator) stream.collect(AnyAccumulator.supplier[Int], AnyAccumulator.unboxedIntAdder, AnyAccumulator.merger[Int]).asInstanceOf[C1]
else if (info.companion == IntAccumulator) intAcc.asInstanceOf[C1]
else if (stream.isParallel) intAcc.to(factory)
else factory.fromSpecific(stream.iterator.asInstanceOf[java.util.Iterator[Int]].asScala)
}
}
implicit class LongStreamHasToScala(stream: LongStream) {
/**
* Copy the elements of this stream into a Scala collection.
*
* Converting a parallel streams to an [[scala.jdk.Accumulator]] using `stream.toScala(Accumulator)`
* builds the result in parallel.
*
* A `toScala(Accumulator)` call automatically converts the `LongStream` to a primitive
* [[scala.jdk.LongAccumulator]].
*
* When converting a parallel stream to a different Scala collection, the stream is first
* converted into an [[scala.jdk.Accumulator]], which supports parallel building. The accumulator is
* then converted to the target collection. Note that the stream is processed eagerly while
* building the accumulator, even if the target collection is lazy.
*
* Sequential streams are directly converted to the target collection. If the target collection
* is lazy, the conversion is lazy as well.
*/
def toScala[C1](factory: collection.Factory[Long, C1])(implicit info: AccumulatorFactoryInfo[Long, C1]): C1 = {
def longAcc = stream.collect(LongAccumulator.supplier, LongAccumulator.adder, LongAccumulator.merger)
if (info.companion == AnyAccumulator) stream.collect(AnyAccumulator.supplier[Long], AnyAccumulator.unboxedLongAdder, AnyAccumulator.merger[Long]).asInstanceOf[C1]
else if (info.companion == LongAccumulator) longAcc.asInstanceOf[C1]
else if (stream.isParallel) longAcc.to(factory)
else factory.fromSpecific(stream.iterator.asInstanceOf[java.util.Iterator[Long]].asScala)
}
}
implicit class DoubleStreamHasToScala(stream: DoubleStream) {
/**
* Copy the elements of this stream into a Scala collection.
*
* Converting a parallel streams to an [[scala.jdk.Accumulator]] using `stream.toScala(Accumulator)`
* builds the result in parallel.
*
* A `toScala(Accumulator)` call automatically converts the `DoubleStream` to a primitive
* [[scala.jdk.DoubleAccumulator]].
*
* When converting a parallel stream to a different Scala collection, the stream is first
* converted into an [[scala.jdk.Accumulator]], which supports parallel building. The accumulator is
* then converted to the target collection. Note that the stream is processed eagerly while
* building the accumulator, even if the target collection is lazy.
*
* Sequential streams are directly converted to the target collection. If the target collection
* is lazy, the conversion is lazy as well.
*/
def toScala[C1](factory: collection.Factory[Double, C1])(implicit info: AccumulatorFactoryInfo[Double, C1]): C1 = {
def doubleAcc = stream.collect(DoubleAccumulator.supplier, DoubleAccumulator.adder, DoubleAccumulator.merger)
if (info.companion == AnyAccumulator) stream.collect(AnyAccumulator.supplier[Double], AnyAccumulator.unboxedDoubleAdder, AnyAccumulator.merger[Double]).asInstanceOf[C1]
else if (info.companion == DoubleAccumulator) doubleAcc.asInstanceOf[C1]
else if (stream.isParallel) doubleAcc.to(factory)
else factory.fromSpecific(stream.iterator.asInstanceOf[java.util.Iterator[Double]].asScala)
}
}
}
object StreamExtensions {
/** An implicit StreamShape instance connects element types with the corresponding specialized
* Stream and Stepper types. This is used in `asJavaStream` extension methods to create
* generic or primitive streams according to the element type.
*/
sealed trait StreamShape[T, S <: BaseStream[_, _], St <: Stepper[_]] {
final def fromStepper(st: St, par: Boolean): S = mkStream(st, par)
protected def mkStream(st: St, par: Boolean): S
}
object StreamShape extends StreamShapeLowPriority1 {
// primitive
implicit val intStreamShape : StreamShape[Int , IntStream , IntStepper] = mkIntStreamShape[Int]
implicit val longStreamShape : StreamShape[Long , LongStream , LongStepper] = mkLongStreamShape[Long]
implicit val doubleStreamShape: StreamShape[Double, DoubleStream, DoubleStepper] = mkDoubleStreamShape[Double]
// widening
implicit val byteStreamShape : StreamShape[Byte , IntStream , IntStepper] = mkIntStreamShape[Byte]
implicit val shortStreamShape: StreamShape[Short, IntStream , IntStepper] = mkIntStreamShape[Short]
implicit val charStreamShape : StreamShape[Char , IntStream , IntStepper] = mkIntStreamShape[Char]
implicit val floatStreamShape: StreamShape[Float, DoubleStream, DoubleStepper] = mkDoubleStreamShape[Float]
// boxed java primitives
implicit val jIntegerStreamShape : StreamShape[jl.Integer , IntStream , IntStepper ] = mkIntStreamShape[jl.Integer]
implicit val jLongStreamShape : StreamShape[jl.Long , LongStream , LongStepper ] = mkLongStreamShape[jl.Long]
implicit val jDoubleStreamShape : StreamShape[jl.Double , DoubleStream, DoubleStepper] = mkDoubleStreamShape[jl.Double]
implicit val jByteStreamShape : StreamShape[jl.Byte , IntStream , IntStepper ] = mkIntStreamShape[jl.Byte]
implicit val jShortStreamShape : StreamShape[jl.Short , IntStream , IntStepper ] = mkIntStreamShape[jl.Short]
implicit val jCharacterStreamShape : StreamShape[jl.Character, IntStream , IntStepper ] = mkIntStreamShape[jl.Character]
implicit val jFloatStreamShape : StreamShape[jl.Float , DoubleStream, DoubleStepper] = mkDoubleStreamShape[jl.Float]
private def mkIntStreamShape[T]: StreamShape[T, IntStream, IntStepper] = new StreamShape[T, IntStream, IntStepper] {
protected def mkStream(st: IntStepper, par: Boolean): IntStream = StreamSupport.intStream(st.spliterator, par)
}
private def mkLongStreamShape[T]: StreamShape[T, LongStream, LongStepper] = new StreamShape[T, LongStream, LongStepper] {
protected def mkStream(st: LongStepper, par: Boolean): LongStream = StreamSupport.longStream(st.spliterator, par)
}
private def mkDoubleStreamShape[T]: StreamShape[T, DoubleStream, DoubleStepper] = new StreamShape[T, DoubleStream, DoubleStepper] {
protected def mkStream(st: DoubleStepper, par: Boolean): DoubleStream = StreamSupport.doubleStream(st.spliterator, par)
}
}
trait StreamShapeLowPriority1 {
// reference
implicit def anyStreamShape[T]: StreamShape[T, Stream[T], Stepper[T]] = anyStreamShapePrototype.asInstanceOf[StreamShape[T, Stream[T], Stepper[T]]]
private[this] val anyStreamShapePrototype: StreamShape[AnyRef, Stream[AnyRef], Stepper[AnyRef]] = new StreamShape[AnyRef, Stream[AnyRef], Stepper[AnyRef]] {
def mkStream(s: Stepper[AnyRef], par: Boolean): Stream[AnyRef] = StreamSupport.stream(s.spliterator.asInstanceOf[Spliterator[AnyRef]], par)
}
}
/** Connects a stream element type `A` to the corresponding, potentially specialized, Stream type.
* Used in the `stream.asJavaPrimitiveStream` extension method.
*/
sealed trait StreamUnboxer[A, S] {
def apply(s: Stream[A]): S
}
object StreamUnboxer {
implicit val intStreamUnboxer: StreamUnboxer[Int, IntStream] = new StreamUnboxer[Int, IntStream] {
def apply(s: Stream[Int]): IntStream = s.mapToInt(x => x)
}
implicit val javaIntegerStreamUnboxer: StreamUnboxer[jl.Integer, IntStream] = intStreamUnboxer.asInstanceOf[StreamUnboxer[jl.Integer, IntStream]]
implicit val longStreamUnboxer: StreamUnboxer[Long, LongStream] = new StreamUnboxer[Long, LongStream] {
def apply(s: Stream[Long]): LongStream = s.mapToLong(x => x)
}
implicit val javaLongStreamUnboxer: StreamUnboxer[jl.Long, LongStream] = longStreamUnboxer.asInstanceOf[StreamUnboxer[jl.Long, LongStream]]
implicit val doubleStreamUnboxer: StreamUnboxer[Double, DoubleStream] = new StreamUnboxer[Double, DoubleStream] {
def apply(s: Stream[Double]): DoubleStream = s.mapToDouble(x => x)
}
implicit val javaDoubleStreamUnboxer: StreamUnboxer[jl.Double, DoubleStream] = doubleStreamUnboxer.asInstanceOf[StreamUnboxer[jl.Double, DoubleStream]]
}
/** An implicit `AccumulatorFactoryInfo` connects primitive element types to the corresponding
* specialized [[scala.jdk.Accumulator]] factory. This is used in the `stream.toScala` extension methods
* to ensure collecting a primitive stream into a primitive accumulator does not box.
*
* When converting to a collection other than `Accumulator`, the generic
* `noAccumulatorFactoryInfo` is passed.
*/
trait AccumulatorFactoryInfo[A, C] {
val companion: AnyRef
}
trait LowPriorityAccumulatorFactoryInfo {
implicit def noAccumulatorFactoryInfo[A, C]: AccumulatorFactoryInfo[A, C] = noAccumulatorFactoryInfoPrototype.asInstanceOf[AccumulatorFactoryInfo[A, C]]
private val noAccumulatorFactoryInfoPrototype: AccumulatorFactoryInfo[AnyRef, AnyRef] = new AccumulatorFactoryInfo[AnyRef, AnyRef] {
val companion: AnyRef = null
}
}
object AccumulatorFactoryInfo extends LowPriorityAccumulatorFactoryInfo {
implicit def anyAccumulatorFactoryInfo[A]: AccumulatorFactoryInfo[A, AnyAccumulator[A]] = anyAccumulatorFactoryInfoPrototype.asInstanceOf[AccumulatorFactoryInfo[A, AnyAccumulator[A]]]
private object anyAccumulatorFactoryInfoPrototype extends AccumulatorFactoryInfo[AnyRef, AnyAccumulator[AnyRef]] {
val companion: AnyRef = AnyAccumulator
}
implicit val intAccumulatorFactoryInfo: AccumulatorFactoryInfo[Int, IntAccumulator] = new AccumulatorFactoryInfo[Int, IntAccumulator] {
val companion: AnyRef = IntAccumulator
}
implicit val longAccumulatorFactoryInfo: AccumulatorFactoryInfo[Long, LongAccumulator] = new AccumulatorFactoryInfo[Long, LongAccumulator] {
val companion: AnyRef = LongAccumulator
}
implicit val doubleAccumulatorFactoryInfo: AccumulatorFactoryInfo[Double, DoubleAccumulator] = new AccumulatorFactoryInfo[Double, DoubleAccumulator] {
val companion: AnyRef = DoubleAccumulator
}
implicit val jIntegerAccumulatorFactoryInfo: AccumulatorFactoryInfo[jl.Integer, IntAccumulator] = intAccumulatorFactoryInfo.asInstanceOf[AccumulatorFactoryInfo[jl.Integer, IntAccumulator]]
implicit val jLongAccumulatorFactoryInfo: AccumulatorFactoryInfo[jl.Long, IntAccumulator] = longAccumulatorFactoryInfo.asInstanceOf[AccumulatorFactoryInfo[jl.Long, IntAccumulator]]
implicit val jDoubleAccumulatorFactoryInfo: AccumulatorFactoryInfo[jl.Double, IntAccumulator] = doubleAccumulatorFactoryInfo.asInstanceOf[AccumulatorFactoryInfo[jl.Double, IntAccumulator]]
}
}