Last active
March 20, 2019 21:19
-
-
Save lrytz/dc90e1bd6127e9556fbf87e814e77d97 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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.function.{Consumer, DoubleConsumer, IntConsumer, LongConsumer} | |
import java.util.{PrimitiveIterator, Spliterator, Iterator => JIterator} | |
import java.{lang => jl} | |
import scala.collection.AbstractIterator | |
trait Stepper[@specialized(Double, Int, Long) A] { | |
def hasStep: Boolean | |
def nextStep(): A | |
def tryStep(f: A => Unit): Boolean | |
// may return null | |
def trySplit(): Stepper[A] | |
def estimateSize: Long | |
def characteristics: Int | |
// Not Spliterator[A] because when A=Int, we refine the type to Spliterator.OfInt, which is a | |
// subtype of Spliterator[Integer]. Could use a shape typeclass implicit argument to express it. | |
def spliterator: Spliterator[_] | |
def javaIterator: JIterator[_] | |
def iterator: Iterator[A] = new AbstractIterator[A] { | |
def hasNext: Boolean = hasStep | |
def next(): A = nextStep() | |
} | |
} | |
trait AnyStepper[A] extends Stepper[A] { self => | |
def tryStep(f: A => Unit): Boolean = if (hasStep) { f(nextStep()); true } else false | |
def trySplit(): AnyStepper[A] | |
def spliterator: Spliterator[A] = new Spliterator[A] { | |
// Override for efficiency: implement with hasStep / nextStep instead of tryAdvance | |
override def forEachRemaining(c: Consumer[_ >: A]): Unit = | |
while (self.hasStep) { c.accept(self.nextStep()) } | |
def tryAdvance(c: Consumer[_ >: A]): Boolean = | |
if (self.hasStep) { c.accept(self.nextStep()); true } else false | |
def trySplit(): Spliterator[A] = self.trySplit().spliterator | |
def estimateSize(): Long = self.estimateSize | |
def characteristics(): Int = self.characteristics | |
} | |
def javaIterator: JIterator[A] = new JIterator[A] { | |
def hasNext: Boolean = hasStep | |
def next(): A = nextStep() | |
} | |
} | |
trait IntStepper extends Stepper[Int] { self => | |
def tryStep(f: Int => Unit): Boolean = if (hasStep) { f(nextStep()); true } else false | |
def trySplit(): IntStepper | |
def spliterator: Spliterator.OfInt = new Spliterator.OfInt { | |
// Override for efficiency: implement with hasStep / nextStep instead of tryAdvance | |
override def forEachRemaining(c: IntConsumer): Unit = | |
while (self.hasStep) { c.accept(self.nextStep()) } | |
// Override for efficiency: implement with hasStep / nextStep instead of tryAdvance | |
override def forEachRemaining(c: Consumer[_ >: jl.Integer]): Unit = (c: AnyRef) match { | |
case ic: IntConsumer => forEachRemaining(ic) | |
case _ => while (self.hasStep) { c.accept(jl.Integer.valueOf(self.nextStep())) } | |
} | |
// Override for efficiency: don't wrap the function and call the `tryAdvance` overload | |
override def tryAdvance(c: Consumer[_ >: jl.Integer]): Boolean = (c: AnyRef) match { | |
case ic: IntConsumer => tryAdvance(ic) | |
case _ => if (self.hasStep) { c.accept(jl.Integer.valueOf(self.nextStep())); true } else false | |
} | |
def tryAdvance(c: IntConsumer): Boolean = | |
if (self.hasStep) { c.accept(self.nextStep()); true } else false | |
def trySplit(): Spliterator.OfInt = self.trySplit().spliterator | |
def estimateSize(): Long = self.estimateSize | |
def characteristics(): Int = self.characteristics | |
} | |
def javaIterator: PrimitiveIterator.OfInt = new PrimitiveIterator.OfInt { | |
def hasNext: Boolean = hasStep | |
def nextInt(): Int = nextStep() | |
} | |
} | |
trait DoubleStepper extends Stepper[Double] { self => | |
def tryStep(f: Double => Unit): Boolean = if (hasStep) { f(nextStep()); true } else false | |
def trySplit(): DoubleStepper | |
def spliterator: Spliterator.OfDouble = new Spliterator.OfDouble { | |
// Override for efficiency: implement with hasStep / nextStep instead of tryAdvance | |
override def forEachRemaining(c: DoubleConsumer): Unit = | |
while (self.hasStep) { c.accept(self.nextStep()) } | |
// Override for efficiency: implement with hasStep / nextStep instead of tryAdvance | |
override def forEachRemaining(c: Consumer[_ >: jl.Double]): Unit = (c: AnyRef) match { | |
case ic: DoubleConsumer => forEachRemaining(ic) | |
case _ => while (self.hasStep) { c.accept(jl.Double.valueOf(self.nextStep())) } | |
} | |
// Override for efficiency: don't wrap the function and call the `tryAdvance` overload | |
override def tryAdvance(c: Consumer[_ >: jl.Double]): Boolean = (c: AnyRef) match { | |
case ic: DoubleConsumer => tryAdvance(ic) | |
case _ => if (self.hasStep) { c.accept(java.lang.Double.valueOf(self.nextStep())); true } else false | |
} | |
def tryAdvance(c: DoubleConsumer): Boolean = | |
if (self.hasStep) { c.accept(self.nextStep()); true } else false | |
def trySplit(): Spliterator.OfDouble = self.trySplit().spliterator | |
def estimateSize(): Long = self.estimateSize | |
def characteristics(): Int = self.characteristics | |
} | |
def javaIterator: PrimitiveIterator.OfDouble = new PrimitiveIterator.OfDouble { | |
def hasNext: Boolean = hasStep | |
def nextDouble(): Double = nextStep() | |
} | |
} | |
trait LongStepper extends Stepper[Long] { self => | |
def tryStep(f: Long => Unit): Boolean = if (hasStep) { f(nextStep()); true } else false | |
def trySplit(): LongStepper | |
def spliterator: Spliterator.OfLong = new Spliterator.OfLong { | |
// Override for efficiency: implement with hasStep / nextStep instead of tryAdvance | |
override def forEachRemaining(c: LongConsumer): Unit = | |
while (self.hasStep) { c.accept(self.nextStep()) } | |
// Override for efficiency: implement with hasStep / nextStep instead of tryAdvance | |
override def forEachRemaining(c: Consumer[_ >: jl.Long]): Unit = (c: AnyRef) match { | |
case ic: LongConsumer => forEachRemaining(ic) | |
case _ => while (self.hasStep) { c.accept(jl.Long.valueOf(self.nextStep())) } | |
} | |
// Override for efficiency: don't wrap the function and call the `tryAdvance` overload | |
override def tryAdvance(c: Consumer[_ >: jl.Long]): Boolean = (c: AnyRef) match { | |
case ic: LongConsumer => tryAdvance(ic) | |
case _ => if (self.hasStep) { c.accept(jl.Long.valueOf(self.nextStep())); true } else false | |
} | |
def tryAdvance(c: LongConsumer): Boolean = | |
if (self.hasStep) { c.accept(self.nextStep()); true } else false | |
def trySplit(): Spliterator.OfLong = self.trySplit().spliterator | |
def estimateSize(): Long = self.estimateSize | |
def characteristics(): Int = self.characteristics | |
} | |
def javaIterator: PrimitiveIterator.OfLong = new PrimitiveIterator.OfLong { | |
def hasNext: Boolean = hasStep | |
def nextLong(): Long = nextStep() | |
} | |
} | |
trait EfficientSubstep | |
object Stepper { | |
/** Indicates that a Stepper delivers distinct values (e.g. is backed by a `Set`) */ | |
val Distinct: Int = Spliterator.DISTINCT | |
/** Indicates that a Stepper runs over an immutable collection */ | |
val Immutable: Int = Spliterator.IMMUTABLE | |
/** Indicates that a Stepper will not return any `null` values */ | |
val NonNull: Int = Spliterator.NONNULL | |
/** Indicates that a Stepper delivers elements in a particular order that should be maintained */ | |
val Ordered: Int = Spliterator.ORDERED | |
/** Indicates that a Stepper knows exactly how many elements it contains */ | |
val Sized: Int = Spliterator.SIZED | |
/** Indicates that a Stepper's children (created with substep()) will all know their size. Steppers that are SubSized must also be Sized. */ | |
val SubSized: Int = Spliterator.SUBSIZED | |
final def throwNSEE(): Nothing = throw new NoSuchElementException("Empty Stepper") | |
/* These adapter classes can wrap an AnyStepper of anumeric type into a possibly widened primitive Stepper type. | |
* This provides a basis for more efficient stream processing on unboxed values provided that the original source | |
* of the data is boxed. In other cases native implementations of the primitive stepper types should be provided | |
* (see for example StepsIntArray and StepsWidenedByteArray). */ | |
class UnboxingDoubleStepper(st: AnyStepper[Double]) extends DoubleStepper { | |
def hasStep: Boolean = st.hasStep | |
def nextStep(): Double = st.nextStep() | |
def estimateSize: Long = st.estimateSize | |
def characteristics: Int = st.characteristics | |
def trySplit(): DoubleStepper = { | |
val s = st.trySplit() | |
if (s == null) null | |
else new UnboxingDoubleStepper(s) | |
} | |
} | |
class UnboxingIntStepper(st: AnyStepper[Int]) extends IntStepper { | |
def hasStep: Boolean = st.hasStep | |
def nextStep(): Int = st.nextStep() | |
def estimateSize: Long = st.estimateSize | |
def characteristics: Int = st.characteristics | |
def trySplit(): IntStepper = { | |
val s = st.trySplit() | |
if (s == null) null | |
else new UnboxingIntStepper(s) | |
} | |
} | |
class UnboxingLongStepper(st: AnyStepper[Long]) extends LongStepper { | |
def hasStep: Boolean = st.hasStep | |
def nextStep(): Long = st.nextStep() | |
def estimateSize: Long = st.estimateSize | |
def characteristics: Int = st.characteristics | |
def trySplit(): LongStepper = { | |
val s = st.trySplit() | |
if (s == null) null | |
else new UnboxingLongStepper(s) | |
} | |
} | |
class UnboxingByteStepper(st: AnyStepper[Byte]) extends IntStepper { | |
def hasStep: Boolean = st.hasStep | |
def nextStep(): Int = st.nextStep() | |
def estimateSize: Long = st.estimateSize | |
def characteristics: Int = st.characteristics | |
def trySplit(): IntStepper = { | |
val s = st.trySplit() | |
if (s == null) null | |
else new UnboxingByteStepper(s) | |
} | |
} | |
class UnboxingCharStepper(st: AnyStepper[Char]) extends IntStepper { | |
def hasStep: Boolean = st.hasStep | |
def nextStep(): Int = st.nextStep() | |
def estimateSize: Long = st.estimateSize | |
def characteristics: Int = st.characteristics | |
def trySplit(): IntStepper = { | |
val s = st.trySplit() | |
if (s == null) null | |
else new UnboxingCharStepper(s) | |
} | |
} | |
class UnboxingShortStepper(st: AnyStepper[Short]) extends IntStepper { | |
def hasStep: Boolean = st.hasStep | |
def nextStep(): Int = st.nextStep() | |
def estimateSize: Long = st.estimateSize | |
def characteristics: Int = st.characteristics | |
def trySplit(): IntStepper = { | |
val s = st.trySplit() | |
if (s == null) null | |
else new UnboxingShortStepper(s) | |
} | |
} | |
class UnboxingFloatStepper(st: AnyStepper[Float]) extends DoubleStepper { | |
def hasStep: Boolean = st.hasStep | |
def nextStep(): Double = st.nextStep() | |
def estimateSize: Long = st.estimateSize | |
def characteristics: Int = st.characteristics | |
def trySplit(): DoubleStepper = { | |
val s = st.trySplit() | |
if (s == null) null | |
else new UnboxingFloatStepper(s) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment