Skip to content

Instantly share code, notes, and snippets.

@lrytz
Last active March 20, 2019 21:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lrytz/dc90e1bd6127e9556fbf87e814e77d97 to your computer and use it in GitHub Desktop.
Save lrytz/dc90e1bd6127e9556fbf87e814e77d97 to your computer and use it in GitHub Desktop.
/*
* 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