diff --git a/build.sbt b/build.sbt index 9425c4eed1e9..d467f4f5b42d 100644 --- a/build.sbt +++ b/build.sbt @@ -5,6 +5,8 @@ val `scala3-compiler` = Build.`scala3-compiler` val `scala3-compiler-bootstrapped` = Build.`scala3-compiler-bootstrapped` val `scala3-library` = Build.`scala3-library` val `scala3-library-bootstrapped` = Build.`scala3-library-bootstrapped` +val `scala-library-internal` = Build.`scala-library-internal` +val `scala-library-internal-tasty` = Build.`scala-library-internal-tasty` val `scala3-library-bootstrappedJS` = Build.`scala3-library-bootstrappedJS` val `scala3-sbt-bridge` = Build.`scala3-sbt-bridge` val `scala3-sbt-bridge-tests` = Build.`scala3-sbt-bridge-tests` diff --git a/library-internal/src/scala/AnyVal.scala b/library-internal/src/scala/AnyVal.scala new file mode 100644 index 000000000000..29edaeb70af3 --- /dev/null +++ b/library-internal/src/scala/AnyVal.scala @@ -0,0 +1,58 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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 + +/** `AnyVal` is the root class of all ''value types'', which describe values + * not implemented as objects in the underlying host system. Value classes + * are specified in Scala Language Specification, section 12.2. + * + * The standard implementation includes nine `AnyVal` subtypes: + * + * [[scala.Double]], [[scala.Float]], [[scala.Long]], [[scala.Int]], [[scala.Char]], + * [[scala.Short]], and [[scala.Byte]] are the ''numeric value types''. + * + * [[scala.Unit]] and [[scala.Boolean]] are the ''non-numeric value types''. + * + * Other groupings: + * + * - The ''subrange types'' are [[scala.Byte]], [[scala.Short]], and [[scala.Char]]. + * - The ''integer types'' include the subrange types as well as [[scala.Int]] and [[scala.Long]]. + * - The ''floating point types'' are [[scala.Float]] and [[scala.Double]]. + * + * A subclass of `AnyVal` is called a ''user-defined value class'' + * and is treated specially by the compiler. Properly-defined user value classes provide a way + * to improve performance on user-defined types by avoiding object allocation at runtime, and by + * replacing virtual method invocations with static method invocations. + * + * User-defined value classes which avoid object allocation... + * + * - must have a single `val` parameter that is the underlying runtime representation. + * - can define `def`s, but no `val`s, `var`s, or nested `trait`s, `class`es or `object`s. + * - typically extend no other trait apart from `AnyVal`. + * - cannot be used in type tests or pattern matching. + * - may not override `equals` or `hashCode` methods. + * + * A minimal example: + * {{{ + * class Wrapper(val underlying: Int) extends AnyVal { + * def foo: Wrapper = new Wrapper(underlying * 19) + * } + * }}} + * + * It's important to note that user-defined value classes are limited, and in some circumstances, + * still must allocate a value class instance at runtime. These limitations and circumstances are + * explained in greater detail in the [[https://docs.scala-lang.org/overviews/core/value-classes.html Value Classes and Universal Traits]]. + */ +abstract class AnyVal extends Any { + def getClass(): Class[_ <: AnyVal] = null +} \ No newline at end of file diff --git a/library-internal/src/scala/Function0.scala b/library-internal/src/scala/Function0.scala new file mode 100644 index 000000000000..0cdea05ebc05 --- /dev/null +++ b/library-internal/src/scala/Function0.scala @@ -0,0 +1,45 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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. + */ + +// GENERATED CODE: DO NOT EDIT. +// genprod generated these sources at: 2022-01-17T20:47:12.170348200Z + +package scala + + +/** A function of 0 parameters. + * + * In the following example, the definition of `greeting` is + * shorthand, conceptually, for the anonymous class definition + * `anonfun0`, although the implementation details of how the + * function value is constructed may differ: + * + * {{{ + * object Main extends App { + * val name = "world" + * val greeting = () => s"hello, $name" + * + * val anonfun0 = new Function0[String] { + * def apply(): String = s"hello, $name" + * } + * assert(greeting() == anonfun0()) + * } + * }}} + */ +trait Function0[@specialized(Specializable.Primitives) +R] extends AnyRef { self => + /** Apply the body of this function to the arguments. + * @return the result of function application. + */ + def apply(): R + + override def toString(): String = "" +} diff --git a/scala2-library-cc/src/scala/Function1.scala b/library-internal/src/scala/Function1.scala similarity index 89% rename from scala2-library-cc/src/scala/Function1.scala rename to library-internal/src/scala/Function1.scala index 96ca493739ed..bf8af8eb2717 100644 --- a/scala2-library-cc/src/scala/Function1.scala +++ b/library-internal/src/scala/Function1.scala @@ -1,7 +1,7 @@ /* * Scala (https://www.scala-lang.org) * - * Copyright EPFL and Lightbend, Inc. + * Copyright EPFL and Lightbend, Inc. dba Akka * * Licensed under Apache License 2.0 * (http://www.apache.org/licenses/LICENSE-2.0). @@ -64,13 +64,13 @@ object Function1 { * is that the latter can specify inputs which it will not handle. */ @annotation.implicitNotFound(msg = "No implicit view available from ${T1} => ${R}.") -trait Function1[@specialized(Specializable.Arg) -T1, @specialized(Specializable.Return) +R] extends AnyRef { // FIXME: self => +trait Function1[@specialized(Specializable.Arg) -T1, @specialized(Specializable.Return) +R] extends AnyRef { // TODO: Fix me self => /** Apply the body of this function to the argument. * @return the result of function application. */ def apply(v1: T1): R - /** Composes two instances of Function1 in a new Function1, with this function applied last. + /** Composes two instances of `Function1` in a new `Function1`, with this function applied last. * * @tparam A the type to which function `g` can be applied * @param g a function A => T1 @@ -78,7 +78,7 @@ trait Function1[@specialized(Specializable.Arg) -T1, @specialized(Specializable. */ @annotation.unspecialized def compose[A](g: A => T1): A => R = { x => apply(g(x)) } - /** Composes two instances of Function1 in a new Function1, with this function applied first. + /** Composes two instances of `Function1` in a new `Function1`, with this function applied first. * * @tparam A the result type of function `g` * @param g a function R => A diff --git a/library-internal/src/scala/Function2.scala b/library-internal/src/scala/Function2.scala new file mode 100644 index 000000000000..f30d57e49344 --- /dev/null +++ b/library-internal/src/scala/Function2.scala @@ -0,0 +1,58 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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. + */ + +// GENERATED CODE: DO NOT EDIT. See scala.Function0 for timestamp. + +package scala + + +/** A function of 2 parameters. + * + * In the following example, the definition of `max` is + * shorthand, conceptually, for the anonymous class definition + * `anonfun2`, although the implementation details of how the + * function value is constructed may differ: + * + * {{{ + * object Main extends App { + * val max = (x: Int, y: Int) => if (x < y) y else x + * + * val anonfun2 = new Function2[Int, Int, Int] { + * def apply(x: Int, y: Int): Int = if (x < y) y else x + * } + * assert(max(0, 1) == anonfun2(0, 1)) + * } + * }}} + */ +trait Function2[@specialized(Specializable.Args) -T1, @specialized(Specializable.Args) -T2, @specialized(Specializable.Return) +R] extends AnyRef { self => + /** Apply the body of this function to the arguments. + * @return the result of function application. + */ + def apply(v1: T1, v2: T2): R + /** Creates a curried version of this function. + * + * @return a function `f` such that `f(x1)(x2) == apply(x1, x2)` + */ + @annotation.unspecialized def curried: T1 => T2 => R = { + (x1: T1) => (x2: T2) => apply(x1, x2) + } + /** Creates a tupled version of this function: instead of 2 arguments, + * it accepts a single [[scala.Tuple2]] argument. + * + * @return a function `f` such that `f((x1, x2)) == f(Tuple2(x1, x2)) == apply(x1, x2)` + */ + + @annotation.unspecialized def tupled: ((T1, T2)) => R = { + case ((x1, x2)) => apply(x1, x2) + } + override def toString(): String = "" +} diff --git a/library-internal/src/scala/Product1.scala b/library-internal/src/scala/Product1.scala new file mode 100644 index 000000000000..912f4dc8f0d8 --- /dev/null +++ b/library-internal/src/scala/Product1.scala @@ -0,0 +1,51 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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. + */ + +// GENERATED CODE: DO NOT EDIT. See scala.Function0 for timestamp. + +package scala + +object Product1 { + def unapply[T1](x: Product1[T1]): Option[Product1[T1]] = + Some(x) +} + +/** Product1 is a Cartesian product of 1 component. + */ +trait Product1[@specialized(Int, Long, Double) +T1] extends Any with Product { + /** The arity of this product. + * @return 1 + */ + override def productArity: Int = 1 + + + /** Returns the n-th projection of this product if 0 <= n < productArity, + * otherwise throws an `IndexOutOfBoundsException`. + * + * @param n number of the projection to be returned + * @return same as `._(n+1)`, for example `productElement(0)` is the same as `._1`. + * @throws IndexOutOfBoundsException if the `n` is out of range(n < 0 || n >= 1). + */ + + @throws(classOf[IndexOutOfBoundsException]) + override def productElement(n: Int): Any = n match { + case 0 => _1 + case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 0)") + } + + /** A projection of element 1 of this Product. + * @return A projection of element 1. + */ + def _1: T1 + + +} diff --git a/library-internal/src/scala/Product2.scala b/library-internal/src/scala/Product2.scala new file mode 100644 index 000000000000..0b9882b63769 --- /dev/null +++ b/library-internal/src/scala/Product2.scala @@ -0,0 +1,56 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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. + */ + +// GENERATED CODE: DO NOT EDIT. See scala.Function0 for timestamp. + +package scala + +object Product2 { + def unapply[T1, T2](x: Product2[T1, T2]): Option[Product2[T1, T2]] = + Some(x) +} + +/** Product2 is a Cartesian product of 2 components. + */ +trait Product2[@specialized(Int, Long, Double) +T1, @specialized(Int, Long, Double) +T2] extends Any with Product { + /** The arity of this product. + * @return 2 + */ + override def productArity: Int = 2 + + + /** Returns the n-th projection of this product if 0 <= n < productArity, + * otherwise throws an `IndexOutOfBoundsException`. + * + * @param n number of the projection to be returned + * @return same as `._(n+1)`, for example `productElement(0)` is the same as `._1`. + * @throws IndexOutOfBoundsException if the `n` is out of range(n < 0 || n >= 2). + */ + + @throws(classOf[IndexOutOfBoundsException]) + override def productElement(n: Int): Any = n match { + case 0 => _1 + case 1 => _2 + case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 1)") + } + + /** A projection of element 1 of this Product. + * @return A projection of element 1. + */ + def _1: T1 + /** A projection of element 2 of this Product. + * @return A projection of element 2. + */ + def _2: T2 + + +} \ No newline at end of file diff --git a/library-internal/src/scala/Tuple1.scala b/library-internal/src/scala/Tuple1.scala new file mode 100644 index 000000000000..d2093964625e --- /dev/null +++ b/library-internal/src/scala/Tuple1.scala @@ -0,0 +1,27 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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. + */ + +// GENERATED CODE: DO NOT EDIT. See scala.Function0 for timestamp. + +package scala + + +/** A tuple of 1 elements; the canonical representation of a [[scala.Product1]]. + * + * @constructor Create a new tuple with 1 elements. + * @param _1 Element 1 of this Tuple1 + */ +final case class Tuple1[@specialized(Int, Long, Double) +T1](_1: T1) extends Product1[T1] +{ + override def toString(): String = "(" + _1 + ")" + +} \ No newline at end of file diff --git a/library-internal/src/scala/Tuple2.scala b/library-internal/src/scala/Tuple2.scala new file mode 100644 index 000000000000..d519b347ae07 --- /dev/null +++ b/library-internal/src/scala/Tuple2.scala @@ -0,0 +1,35 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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. + */ + +// GENERATED CODE: DO NOT EDIT. See scala.Function0 for timestamp. + +package scala + + +/** A tuple of 2 elements; the canonical representation of a [[scala.Product2]]. + * + * @constructor Create a new tuple with 2 elements. Note that it is more idiomatic to create a Tuple2 via `(t1, t2)` + * @param _1 Element 1 of this Tuple2 + * @param _2 Element 2 of this Tuple2 + */ +final case class Tuple2[@specialized(Int, Long, Double, Char, Boolean/*, AnyRef*/) +T1, @specialized(Int, Long, Double, Char, Boolean/*, AnyRef*/) +T2](_1: T1, _2: T2) + extends Product2[T1, T2] +{ + override def toString(): String = "(" + _1 + "," + _2 + ")" + + /** Swaps the elements of this `Tuple`. + * @return a new Tuple where the first element is the second element of this Tuple and the + * second element is the first element of this Tuple. + */ + def swap: Tuple2[T2,T1] = Tuple2(_2, _1) + +} \ No newline at end of file diff --git a/scala2-library-bootstrapped/src/scala/collection/ArrayOps.scala b/library-internal/src/scala/collection/ArrayOps.scala similarity index 96% rename from scala2-library-bootstrapped/src/scala/collection/ArrayOps.scala rename to library-internal/src/scala/collection/ArrayOps.scala index d4659bbb0dba..f57f6a658886 100644 --- a/scala2-library-bootstrapped/src/scala/collection/ArrayOps.scala +++ b/library-internal/src/scala/collection/ArrayOps.scala @@ -1,7 +1,7 @@ /* * Scala (https://www.scala-lang.org) * - * Copyright EPFL and Lightbend, Inc. + * Copyright EPFL and Lightbend, Inc. dba Akka * * Licensed under Apache License 2.0 * (http://www.apache.org/licenses/LICENSE-2.0). @@ -44,6 +44,7 @@ import scala.Predef.{ // unimport all array-related implicit conversions to avoi _ } import scala.collection.Stepper.EfficientSplit +import scala.collection.generic.CommonErrors import scala.collection.immutable.Range import scala.collection.mutable.ArrayBuilder import scala.math.Ordering @@ -761,20 +762,19 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { true } - /** Applies a binary operator to a start value and all elements of this array, - * going left to right. - * - * @param z the start value. - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive elements of this array, - * going left to right with the start value `z` on the left: - * {{{ - * op(...op(z, x_1), x_2, ..., x_n) - * }}} - * where `x,,1,,, ..., x,,n,,` are the elements of this array. - * Returns `z` if this array is empty. - */ + /** Applies the given binary operator `op` to the given initial value `z` and + * all elements of this array, going left to right. Returns the initial value + * if this array is empty. + * + * If `x,,1,,`, `x,,2,,`, ..., `x,,n,,` are the elements of this array, the + * result is `op( op( ... op( op(z, x,,1,,), x,,2,,) ... ), x,,n,,)`. + * + * @param z An initial value. + * @param op A binary operator. + * @tparam B The result type of the binary operator. + * @return The result of applying `op` to `z` and all elements of this array, + * going left to right. Returns `z` if this array is empty. + */ def foldLeft[B](z: B)(op: (B, A) => B): B = { def f[@specialized(Specializable.Everything) T](xs: Array[T], op: (Any, Any) => Any, z: Any): Any = { val length = xs.length @@ -867,20 +867,20 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { res } - /** Applies a binary operator to all elements of this array and a start value, - * going right to left. - * - * @param z the start value. - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive elements of this array, - * going right to left with the start value `z` on the right: - * {{{ - * op(x_1, op(x_2, ... op(x_n, z)...)) - * }}} - * where `x,,1,,, ..., x,,n,,` are the elements of this array. - * Returns `z` if this array is empty. - */ + /** Applies the given binary operator `op` to all elements of this array and + * the given initial value `z`, going right to left. Returns the initial + * value if this array is empty. + * + * If `x,,1,,`, `x,,2,,`, ..., `x,,n,,` are the elements of this array, the + * result is `op(x,,1,,, op(x,,2,,, op( ... op(x,,n,,, z) ... )))`. + * + * @param z An initial value. + * @param op A binary operator. + * @tparam B The result type of the binary operator. + * @return The result of applying `op` to all elements of this array + * and `z`, going right to left. Returns `z` if this array + * is empty. + */ def foldRight[B](z: B)(op: (A, B) => B): B = { def f[@specialized(Specializable.Everything) T](xs: Array[T], op: (Any, Any) => Any, z: Any): Any = { var v = z @@ -907,15 +907,17 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { } - /** Folds the elements of this array using the specified associative binary operator. - * - * @tparam A1 a type parameter for the binary operator, a supertype of `A`. - * @param z a neutral element for the fold operation; may be added to the result - * an arbitrary number of times, and must not change the result (e.g., `Nil` for list concatenation, - * 0 for addition, or 1 for multiplication). - * @param op a binary operator that must be associative. - * @return the result of applying the fold operator `op` between all the elements, or `z` if this array is empty. - */ + /** Alias for [[foldLeft]]. + * + * The type parameter is more restrictive than for `foldLeft` to be + * consistent with [[IterableOnceOps.fold]]. + * + * @tparam A1 The type parameter for the binary operator, a supertype of `A`. + * @param z An initial value. + * @param op A binary operator. + * @return The result of applying `op` to `z` and all elements of this array, + * going left to right. Returns `z` if this string is empty. + */ def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op) /** Builds a new array by applying a function to all elements of this array. @@ -1174,8 +1176,7 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { /** A copy of this array with all elements of a collection appended. */ def appendedAll[B >: A : ClassTag](suffix: IterableOnce[B]): Array[B] = { val b = ArrayBuilder.make[B] - val k = suffix.knownSize - if(k >= 0) b.sizeHint(k + xs.length) + b.sizeHint(suffix, delta = xs.length) b.addAll(xs) b.addAll(suffix) b.result() @@ -1545,7 +1546,8 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @throws IndexOutOfBoundsException if `index` does not satisfy `0 <= index < length`. */ def updated[B >: A : ClassTag](index: Int, elem: B): Array[B] = { - if(index < 0 || index >= xs.length) throw new IndexOutOfBoundsException(s"$index is out of bounds (min 0, max ${xs.length-1})") + if(index < 0 || index >= xs.length) + throw CommonErrors.indexOutOfBounds(index = index, max = xs.length-1) val dest = toArray[B] dest(index) = elem dest @@ -1661,4 +1663,4 @@ final class ArrayOps[A](private val xs: Array[A]) extends AnyVal { * @return `true` if this array has `that` as a suffix, `false` otherwise. */ def endsWith[B >: A](that: Iterable[B]): Boolean = mutable.ArraySeq.make(xs).endsWith(that) -} +} \ No newline at end of file diff --git a/library-internal/src/scala/collection/Stepper.scala b/library-internal/src/scala/collection/Stepper.scala new file mode 100644 index 000000000000..348824557d4a --- /dev/null +++ b/library-internal/src/scala/collection/Stepper.scala @@ -0,0 +1,368 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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 + +import java.util.function.{Consumer, DoubleConsumer, IntConsumer, LongConsumer} +import java.util.{PrimitiveIterator, Spliterator, Iterator => JIterator} +import java.{lang => jl} + +import scala.collection.Stepper.EfficientSplit + +/** Steppers exist to enable creating Java streams over Scala collections, see + * [[scala.jdk.StreamConverters]]. Besides that use case, they allow iterating over collections + * holding unboxed primitives (e.g., `Array[Int]`) without boxing the elements. + * + * Steppers have an iterator-like interface with methods `hasStep` and `nextStep()`. The difference + * to iterators - and the reason `Stepper` is not a subtype of `Iterator` - is that there are + * hand-specialized variants of `Stepper` for `Int`, `Long` and `Double` ([[IntStepper]], etc.). + * These enable iterating over collections holding unboxed primitives (e.g., Arrays, + * [[scala.jdk.Accumulator]]s) without boxing the elements. + * + * The selection of primitive types (`Int`, `Long` and `Double`) matches the hand-specialized + * variants of Java Streams ([[java.util.stream.Stream]], [[java.util.stream.IntStream]], etc.) + * and the corresponding Java Spliterators ([[java.util.Spliterator]], [[java.util.Spliterator.OfInt]], etc.). + * + * Steppers can be converted to Scala Iterators, Java Iterators and Java Spliterators. Primitive + * Steppers are converted to the corresponding primitive Java Iterators and Spliterators. + * + * @tparam A the element type of the Stepper + */ +trait Stepper[@specialized(Double, Int, Long) +A] { + /** Check if there's an element available. */ + def hasStep: Boolean + + /** Return the next element and advance the stepper */ + def nextStep(): A + + /** Split this stepper, if applicable. The elements of the current Stepper are split up between + * the resulting Stepper and the current stepper. + * + * May return `null`, in which case the current Stepper yields the same elements as before. + * + * See method `trySplit` in [[java.util.Spliterator]]. + */ + def trySplit(): Stepper[A] + + /** Returns an estimate of the number of elements of this Stepper, or [[Long.MaxValue]]. See + * method `estimateSize` in [[java.util.Spliterator]]. + */ + def estimateSize: Long + + /** Returns a set of characteristics of this Stepper and its elements. See method + * `characteristics` in [[java.util.Spliterator]]. + */ + def characteristics: Int + + /** Returns a [[java.util.Spliterator]] corresponding to this Stepper. + * + * Note that the return type is `Spliterator[_]` instead of `Spliterator[A]` to allow returning + * a [[java.util.Spliterator.OfInt]] (which is a `Spliterator[Integer]`) in the subclass [[IntStepper]] + * (which is a `Stepper[Int]`). + */ + def spliterator[B >: A]: Spliterator[_] + + /** Returns a Java [[java.util.Iterator]] corresponding to this Stepper. + * + * Note that the return type is `Iterator[_]` instead of `Iterator[A]` to allow returning + * a [[java.util.PrimitiveIterator.OfInt]] (which is a `Iterator[Integer]`) in the subclass + * [[IntStepper]] (which is a `Stepper[Int]`). + */ + def javaIterator[B >: A]: JIterator[_] + + /** Returns an [[Iterator]] corresponding to this Stepper. Note that Iterators corresponding to + * primitive Steppers box the elements. + */ + def iterator: Iterator[A] = new AbstractIterator[A] { + def hasNext: Boolean = hasStep + def next(): A = nextStep() + } +} + +object Stepper { + /** A marker trait that indicates that a `Stepper` can call `trySplit` with at worst O(log N) time + * and space complexity, and that the division is likely to be reasonably even. Steppers marked + * with `EfficientSplit` can be converted to parallel streams with the `asJavaParStream` method + * defined in [[scala.jdk.StreamConverters]]. + */ + trait EfficientSplit + + private[collection] final def throwNSEE(): Nothing = throw new NoSuchElementException("Empty Stepper") + + /* These adapter classes can wrap an AnyStepper of a numeric 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 IntArrayStepper and WidenedByteArrayStepper). */ + + private[collection] 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) + } + } + + private[collection] 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) + } + } + + private[collection] 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) + } + } + + private[collection] 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) + } + } + + private[collection] 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) + } + } + + private[collection] 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) + } + } + + private[collection] 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) + } + } +} + +/** A Stepper for arbitrary element types. See [[Stepper]]. */ +trait AnyStepper[+A] extends Stepper[A] { + def trySplit(): AnyStepper[A] + + def spliterator[B >: A]: Spliterator[B] = new AnyStepper.AnyStepperSpliterator(this) + + def javaIterator[B >: A]: JIterator[B] = new JIterator[B] { + def hasNext: Boolean = hasStep + def next(): B = nextStep() + } +} + +object AnyStepper { + class AnyStepperSpliterator[A](s: AnyStepper[A]) extends Spliterator[A] { + def tryAdvance(c: Consumer[_ >: A]): Boolean = + if (s.hasStep) { c.accept(s.nextStep()); true } else false + def trySplit(): Spliterator[A] = { + val sp = s.trySplit() + if (sp == null) null else sp.spliterator + } + def estimateSize(): Long = s.estimateSize + def characteristics(): Int = s.characteristics + // Override for efficiency: implement with hasStep / nextStep instead of tryAdvance + override def forEachRemaining(c: Consumer[_ >: A]): Unit = + while (s.hasStep) { c.accept(s.nextStep()) } + } + + def ofSeqDoubleStepper(st: DoubleStepper): AnyStepper[Double] = new BoxedDoubleStepper(st) + def ofParDoubleStepper(st: DoubleStepper with EfficientSplit): AnyStepper[Double] with EfficientSplit = new BoxedDoubleStepper(st) with EfficientSplit + + def ofSeqIntStepper(st: IntStepper): AnyStepper[Int] = new BoxedIntStepper(st) + def ofParIntStepper(st: IntStepper with EfficientSplit): AnyStepper[Int] with EfficientSplit = new BoxedIntStepper(st) with EfficientSplit + + def ofSeqLongStepper(st: LongStepper): AnyStepper[Long] = new BoxedLongStepper(st) + def ofParLongStepper(st: LongStepper with EfficientSplit): AnyStepper[Long] with EfficientSplit = new BoxedLongStepper(st) with EfficientSplit + + private[collection] class BoxedDoubleStepper(st: DoubleStepper) extends AnyStepper[Double] { + def hasStep: Boolean = st.hasStep + def nextStep(): Double = st.nextStep() + def estimateSize: Long = st.estimateSize + def characteristics: Int = st.characteristics + def trySplit(): AnyStepper[Double] = { + val s = st.trySplit() + if (s == null) null else new BoxedDoubleStepper(s) + } + } + + private[collection] class BoxedIntStepper(st: IntStepper) extends AnyStepper[Int] { + def hasStep: Boolean = st.hasStep + def nextStep(): Int = st.nextStep() + def estimateSize: Long = st.estimateSize + def characteristics: Int = st.characteristics + def trySplit(): AnyStepper[Int] = { + val s = st.trySplit() + if (s == null) null else new BoxedIntStepper(s) + } + } + + private[collection] class BoxedLongStepper(st: LongStepper) extends AnyStepper[Long] { + def hasStep: Boolean = st.hasStep + def nextStep(): Long = st.nextStep() + def estimateSize: Long = st.estimateSize + def characteristics: Int = st.characteristics + def trySplit(): AnyStepper[Long] = { + val s = st.trySplit() + if (s == null) null else new BoxedLongStepper(s) + } + } +} + +/** A Stepper for Ints. See [[Stepper]]. */ +trait IntStepper extends Stepper[Int] { + def trySplit(): IntStepper + + def spliterator[B >: Int]: Spliterator.OfInt = new IntStepper.IntStepperSpliterator(this) + + def javaIterator[B >: Int]: PrimitiveIterator.OfInt = new PrimitiveIterator.OfInt { + def hasNext: Boolean = hasStep + def nextInt(): Int = nextStep() + } +} +object IntStepper { + class IntStepperSpliterator(s: IntStepper) extends Spliterator.OfInt { + def tryAdvance(c: IntConsumer): Boolean = + if (s.hasStep) { c.accept(s.nextStep()); true } else false + // 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 (s.hasStep) { c.accept(jl.Integer.valueOf(s.nextStep())); true } else false + } + // override required for dotty#6152 + override def trySplit(): Spliterator.OfInt = { + val sp = s.trySplit() + if (sp == null) null else sp.spliterator + } + def estimateSize(): Long = s.estimateSize + def characteristics(): Int = s.characteristics + // Override for efficiency: implement with hasStep / nextStep instead of tryAdvance + override def forEachRemaining(c: IntConsumer): Unit = + while (s.hasStep) { c.accept(s.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 (s.hasStep) { c.accept(jl.Integer.valueOf(s.nextStep())) } + } + } +} + +/** A Stepper for Doubles. See [[Stepper]]. */ +trait DoubleStepper extends Stepper[Double] { + def trySplit(): DoubleStepper + + def spliterator[B >: Double]: Spliterator.OfDouble = new DoubleStepper.DoubleStepperSpliterator(this) + + def javaIterator[B >: Double]: PrimitiveIterator.OfDouble = new PrimitiveIterator.OfDouble { + def hasNext: Boolean = hasStep + def nextDouble(): Double = nextStep() + } +} + +object DoubleStepper { + class DoubleStepperSpliterator(s: DoubleStepper) extends Spliterator.OfDouble { + def tryAdvance(c: DoubleConsumer): Boolean = + if (s.hasStep) { c.accept(s.nextStep()); true } else false + // 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 (s.hasStep) { c.accept(java.lang.Double.valueOf(s.nextStep())); true } else false + } + // override required for dotty#6152 + override def trySplit(): Spliterator.OfDouble = { + val sp = s.trySplit() + if (sp == null) null else sp.spliterator + } + def estimateSize(): Long = s.estimateSize + def characteristics(): Int = s.characteristics + // Override for efficiency: implement with hasStep / nextStep instead of tryAdvance + override def forEachRemaining(c: DoubleConsumer): Unit = + while (s.hasStep) { c.accept(s.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 (s.hasStep) { c.accept(jl.Double.valueOf(s.nextStep())) } + } + } +} + +/** A Stepper for Longs. See [[Stepper]]. */ +trait LongStepper extends Stepper[Long] { + def trySplit(): LongStepper + + def spliterator[B >: Long]: Spliterator.OfLong = new LongStepper.LongStepperSpliterator(this) + + def javaIterator[B >: Long]: PrimitiveIterator.OfLong = new PrimitiveIterator.OfLong { + def hasNext: Boolean = hasStep + def nextLong(): Long = nextStep() + } +} + +object LongStepper { + class LongStepperSpliterator(s: LongStepper) extends Spliterator.OfLong { + def tryAdvance(c: LongConsumer): Boolean = + if (s.hasStep) { c.accept(s.nextStep()); true } else false + // 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 (s.hasStep) { c.accept(java.lang.Long.valueOf(s.nextStep())); true } else false + } + // override required for dotty#6152 + override def trySplit(): Spliterator.OfLong = { + val sp = s.trySplit() + if (sp == null) null else sp.spliterator + } + def estimateSize(): Long = s.estimateSize + def characteristics(): Int = s.characteristics + // Override for efficiency: implement with hasStep / nextStep instead of tryAdvance + override def forEachRemaining(c: LongConsumer): Unit = + while (s.hasStep) { c.accept(s.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 (s.hasStep) { c.accept(jl.Long.valueOf(s.nextStep())) } + } + } +} \ No newline at end of file diff --git a/library-internal/src/scala/collection/immutable/Vector.scala b/library-internal/src/scala/collection/immutable/Vector.scala new file mode 100644 index 000000000000..f38cdbc77b5d --- /dev/null +++ b/library-internal/src/scala/collection/immutable/Vector.scala @@ -0,0 +1,2483 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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 +package immutable + +import java.lang.Math.{abs, max => mmax, min => mmin} +import java.util.Arrays.{copyOf, copyOfRange} +import java.util.{Arrays, Spliterator} + +import scala.annotation.switch +import scala.annotation.unchecked.uncheckedVariance +import scala.collection.Stepper.EfficientSplit +import scala.collection.generic.{CommonErrors, DefaultSerializable} +import scala.collection.immutable.VectorInline._ +import scala.collection.immutable.VectorStatics._ +import scala.collection.mutable.ReusableBuilder + + +/** $factoryInfo + * @define Coll `Vector` + * @define coll vector + */ +@SerialVersionUID(3L) +object Vector extends StrictOptimizedSeqFactory[Vector] { + + def empty[A]: Vector[A] = Vector0 + + def from[E](it: collection.IterableOnce[E]): Vector[E] = + it match { + case v: Vector[E] => v + case _ => + val knownSize = it.knownSize + if (knownSize == 0) empty[E] + else if (knownSize > 0 && knownSize <= WIDTH) { + val a1: Arr1 = it match { + case as: ArraySeq.ofRef[_] if as.elemTag.runtimeClass == classOf[AnyRef] => + as.unsafeArray.asInstanceOf[Arr1] + case it: Iterable[E] => + val a1 = new Arr1(knownSize) + @annotation.unused val copied = it.copyToArray(a1.asInstanceOf[Array[Any]]) + //assert(copied == knownSize) + a1 + case _ => + val a1 = new Arr1(knownSize) + @annotation.unused val copied = it.iterator.copyToArray(a1.asInstanceOf[Array[Any]]) + //assert(copied == knownSize) + a1.asInstanceOf[Arr1] + } + new Vector1[E](a1) + } else { + (newBuilder ++= it).result() + } + } + + def newBuilder[A]: ReusableBuilder[A, Vector[A]] = new VectorBuilder[A] + + /** Create a Vector with the same element at each index. + * + * Unlike `fill`, which takes a by-name argument for the value and can thereby + * compute different values for each index, this method guarantees that all + * elements are identical. This allows sparse allocation in O(log n) time and space. + */ + private[collection] def fillSparse[A](n: Int)(elem: A): Vector[A] = { + //TODO Make public; this method is private for now because it is not forward binary compatible + if(n <= 0) Vector0 + else { + val b = new VectorBuilder[A] + b.initSparse(n, elem) + b.result() + } + } + + private val defaultApplyPreferredMaxLength: Int = + // explicit StringOps to avoid initialization cycle with Predef (scala/bug#13009) + try new StringOps(System.getProperty("scala.collection.immutable.Vector.defaultApplyPreferredMaxLength", + "250")).toInt + catch { + case _: SecurityException => 250 + } + + private val emptyIterator = new NewVectorIterator(Vector0, 0, 0) +} + + +/** Vector is a general-purpose, immutable data structure. It provides random access and updates + * in O(log n) time, as well as very fast append/prepend/tail/init (amortized O(1), worst case O(log n)). + * Because vectors strike a good balance between fast random selections and fast random functional updates, + * they are currently the default implementation of immutable indexed sequences. + * + * Vectors are implemented by radix-balanced finger trees of width 32. There is a separate subclass + * for each level (0 to 6, with 0 being the empty vector and 6 a tree with a maximum width of 64 at the + * top level). + * + * Tree balancing: + * - Only the first dimension of an array may have a size < WIDTH + * - In a `data` (central) array the first dimension may be up to WIDTH-2 long, in `prefix1` and `suffix1` up + * to WIDTH, and in other `prefix` and `suffix` arrays up to WIDTH-1 + * - `prefix1` and `suffix1` are never empty + * - Balancing does not cross the main data array (i.e. prepending never touches the suffix and appending never touches + * the prefix). The level is increased/decreased when the affected side plus main data is already full/empty + * - All arrays are left-aligned and truncated + * + * In addition to the data slices (`prefix1`, `prefix2`, ..., `dataN`, ..., `suffix2`, `suffix1`) we store a running + * count of elements after each prefix for more efficient indexing without having to dereference all prefix arrays. + */ +sealed abstract class Vector[+A] private[immutable] (private[immutable] final val prefix1: Arr1) + extends AbstractSeq[A] + with IndexedSeq[A] + with IndexedSeqOps[A, Vector, Vector[A]] + with StrictOptimizedSeqOps[A, Vector, Vector[A]] + with IterableFactoryDefaults[A, Vector] + with DefaultSerializable { + + override def iterableFactory: SeqFactory[Vector] = Vector + + override final def length: Int = + if(this.isInstanceOf[BigVector[_]]) this.asInstanceOf[BigVector[_]].length0 + else prefix1.length + + override final def iterator: Iterator[A] = + if(this.isInstanceOf[Vector0.type]) Vector.emptyIterator + else new NewVectorIterator(this, length, vectorSliceCount) + + override final protected[collection] def filterImpl(pred: A => Boolean, isFlipped: Boolean): Vector[A] = { + var i = 0 + val len = prefix1.length + while (i != len) { + if (pred(prefix1(i).asInstanceOf[A]) == isFlipped) { + // each 1 bit indicates that index passes the filter. + // all indices < i are also assumed to pass the filter + var bitmap = 0 + var j = i + 1 + while (j < len) { + if (pred(prefix1(j).asInstanceOf[A]) != isFlipped) { + bitmap |= (1 << j) + } + j += 1 + } + val newLen = i + java.lang.Integer.bitCount(bitmap) + + if(this.isInstanceOf[BigVector[_]]) { + val b = new VectorBuilder[A] + var k = 0 + while(k < i) { + b.addOne(prefix1(k).asInstanceOf[A]) + k += 1 + } + k = i + 1 + while (i != newLen) { + if (((1 << k) & bitmap) != 0) { + b.addOne(prefix1(k).asInstanceOf[A]) + i += 1 + } + k += 1 + } + this.asInstanceOf[BigVector[A]].foreachRest { v => if(pred(v) != isFlipped) b.addOne(v) } + return b.result() + } else { + if (newLen == 0) return Vector0 + val newData = new Array[AnyRef](newLen) + System.arraycopy(prefix1, 0, newData, 0, i) + var k = i + 1 + while (i != newLen) { + if (((1 << k) & bitmap) != 0) { + newData(i) = prefix1(k) + i += 1 + } + k += 1 + } + return new Vector1[A](newData) + } + } + i += 1 + } + if(this.isInstanceOf[BigVector[_]]) { + val b = new VectorBuilder[A] + b.initFrom(prefix1) + this.asInstanceOf[BigVector[A]].foreachRest { v => if(pred(v) != isFlipped) b.addOne(v) } + b.result() + } else this + } + + // Dummy overrides to refine result types for binary compatibility: + override def updated[B >: A](index: Int, elem: B): Vector[B] = super.updated(index, elem) + override def appended[B >: A](elem: B): Vector[B] = super.appended(elem) + override def prepended[B >: A](elem: B): Vector[B] = super.prepended(elem) + override def prependedAll[B >: A](prefix: collection.IterableOnce[B]): Vector[B] = { + val k = prefix.knownSize + if (k == 0) this + else if (k < 0) super.prependedAll(prefix) + else prependedAll0(prefix, k) + } + + override final def appendedAll[B >: A](suffix: collection.IterableOnce[B]): Vector[B] = { + val k = suffix.knownSize + if (k == 0) this + else if (k < 0) super.appendedAll(suffix) + else appendedAll0(suffix, k) + } + + protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = { + // k >= 0, k = prefix.knownSize + val tinyAppendLimit = 4 + vectorSliceCount + if (k < tinyAppendLimit /*|| k < (this.size >>> Log2ConcatFaster)*/) { + var v: Vector[B] = this + val it = IndexedSeq.from(prefix).reverseIterator + while (it.hasNext) v = it.next() +: v + v + } else if (this.size < (k >>> Log2ConcatFaster) && prefix.isInstanceOf[Vector[_]]) { + var v = prefix.asInstanceOf[Vector[B]] + val it = this.iterator + while (it.hasNext) v = v :+ it.next() + v + } else if (k < this.size - AlignToFaster) { + new VectorBuilder[B].alignTo(k, this).addAll(prefix).addAll(this).result() + } else super.prependedAll(prefix) + } + + protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + // k >= 0, k = suffix.knownSize + val tinyAppendLimit = 4 + vectorSliceCount + if (k < tinyAppendLimit) { + var v: Vector[B] = this + suffix match { + case it: Iterable[_] => it.asInstanceOf[Iterable[B]].foreach(x => v = v.appended(x)) + case _ => suffix.iterator.foreach(x => v = v.appended(x)) + } + v + } else if (this.size < (k >>> Log2ConcatFaster) && suffix.isInstanceOf[Vector[_]]) { + var v = suffix.asInstanceOf[Vector[B]] + val ri = this.reverseIterator + while (ri.hasNext) v = v.prepended(ri.next()) + v + } else if (this.size < k - AlignToFaster && suffix.isInstanceOf[Vector[_]]) { + val v = suffix.asInstanceOf[Vector[B]] + new VectorBuilder[B].alignTo(this.size, v).addAll(this).addAll(v).result() + } else new VectorBuilder[B].initFrom(this).addAll(suffix).result() + } + + override def className = "Vector" + + @inline override final def take(n: Int): Vector[A] = slice(0, n) + @inline override final def drop(n: Int): Vector[A] = slice(n, length) + @inline override final def takeRight(n: Int): Vector[A] = slice(length - mmax(n, 0), length) + @inline override final def dropRight(n: Int): Vector[A] = slice(0, length - mmax(n, 0)) + override def tail: Vector[A] = slice(1, length) + override def init: Vector[A] = slice(0, length-1) + + /** Like slice but parameters must be 0 <= lo < hi < length */ + protected[this] def slice0(lo: Int, hi: Int): Vector[A] + + /** Number of slices */ + protected[immutable] def vectorSliceCount: Int + /** Slice at index */ + protected[immutable] def vectorSlice(idx: Int): Array[_ <: AnyRef] + /** Length of all slices up to and including index */ + protected[immutable] def vectorSlicePrefixLength(idx: Int): Int + + override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = iterator.copyToArray(xs, start, len) + + override def toVector: Vector[A] = this + + override protected def applyPreferredMaxLength: Int = Vector.defaultApplyPreferredMaxLength + + override def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit = { + val s = shape.shape match { + case StepperShape.IntShape => new IntVectorStepper(iterator.asInstanceOf[NewVectorIterator[Int]]) + case StepperShape.LongShape => new LongVectorStepper(iterator.asInstanceOf[NewVectorIterator[Long]]) + case StepperShape.DoubleShape => new DoubleVectorStepper(iterator.asInstanceOf[NewVectorIterator[Double]]) + case _ => shape.parUnbox(new AnyVectorStepper[A](iterator.asInstanceOf[NewVectorIterator[A]])) + } + s.asInstanceOf[S with EfficientSplit] + } + + protected[this] def ioob(index: Int): IndexOutOfBoundsException = + CommonErrors.indexOutOfBounds(index = index, max = length - 1) + + override final def head: A = + if (prefix1.length == 0) throw new NoSuchElementException("empty.head") + else prefix1(0).asInstanceOf[A] + + override final def last: A = { + if(this.isInstanceOf[BigVector[_]]) { + val suffix = this.asInstanceOf[BigVector[_]].suffix1 + if(suffix.length == 0) throw new NoSuchElementException("empty.tail") + else suffix(suffix.length-1) + } else prefix1(prefix1.length-1) + }.asInstanceOf[A] + + override final def foreach[U](f: A => U): Unit = { + val c = vectorSliceCount + var i = 0 + while (i < c) { + foreachRec(vectorSliceDim(c, i) - 1, vectorSlice(i), f) + i += 1 + } + } + + // The following definitions are needed for binary compatibility with ParVector + private[collection] def startIndex: Int = 0 + private[collection] def endIndex: Int = length + private[collection] def initIterator[B >: A](s: VectorIterator[B]): Unit = + s.it = iterator.asInstanceOf[NewVectorIterator[B]] +} + + +/** This class only exists because we cannot override `slice` in `Vector` in a binary-compatible way */ +private sealed abstract class VectorImpl[+A](_prefix1: Arr1) extends Vector[A](_prefix1) { + + override final def slice(from: Int, until: Int): Vector[A] = { + val lo = mmax(from, 0) + val hi = mmin(until, length) + if (hi <= lo) Vector0 + else if (hi - lo == length) this + else slice0(lo, hi) + } +} + + +/** Vector with suffix and length fields; all Vector subclasses except Vector1 extend this */ +private sealed abstract class BigVector[+A](_prefix1: Arr1, private[immutable] val suffix1: Arr1, private[immutable] val length0: Int) extends VectorImpl[A](_prefix1) { + + protected[immutable] final def foreachRest[U](f: A => U): Unit = { + val c = vectorSliceCount + var i = 1 + while(i < c) { + foreachRec(vectorSliceDim(c, i)-1, vectorSlice(i), f) + i += 1 + } + } +} + + +/** Empty vector */ +private object Vector0 extends BigVector[Nothing](empty1, empty1, 0) { + + def apply(index: Int): Nothing = throw ioob(index) + + override def updated[B >: Nothing](index: Int, elem: B): Vector[B] = throw ioob(index) + + override def appended[B >: Nothing](elem: B): Vector[B] = new Vector1(wrap1(elem)) + + override def prepended[B >: Nothing](elem: B): Vector[B] = new Vector1(wrap1(elem)) + + override def map[B](f: Nothing => B): Vector[B] = this + + override def tail: Vector[Nothing] = throw new UnsupportedOperationException("empty.tail") + + override def init: Vector[Nothing] = throw new UnsupportedOperationException("empty.init") + + protected[this] def slice0(lo: Int, hi: Int): Vector[Nothing] = this + + protected[immutable] def vectorSliceCount: Int = 0 + protected[immutable] def vectorSlice(idx: Int): Array[_ <: AnyRef] = null + protected[immutable] def vectorSlicePrefixLength(idx: Int): Int = 0 + + override def equals(o: Any): Boolean = { + if(this eq o.asInstanceOf[AnyRef]) true + else o match { + case that: Vector[_] => false + case o => super.equals(o) + } + } + + override protected[this]def prependedAll0[B >: Nothing](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + Vector.from(prefix) + + override protected[this]def appendedAll0[B >: Nothing](suffix: collection.IterableOnce[B], k: Int): Vector[B] = + Vector.from(suffix) + + override protected[this] def ioob(index: Int): IndexOutOfBoundsException = + new IndexOutOfBoundsException(s"$index is out of bounds (empty vector)") +} + +/** Flat ArraySeq-like structure */ +private final class Vector1[+A](_data1: Arr1) extends VectorImpl[A](_data1) { + + @inline def apply(index: Int): A = { + if(index >= 0 && index < prefix1.length) + prefix1(index).asInstanceOf[A] + else throw ioob(index) + } + + override def updated[B >: A](index: Int, elem: B): Vector[B] = { + if(index >= 0 && index < prefix1.length) + new Vector1(copyUpdate(prefix1, index, elem)) + else throw ioob(index) + } + + override def appended[B >: A](elem: B): Vector[B] = { + val len1 = prefix1.length + if(len1 < WIDTH) new Vector1(copyAppend1(prefix1, elem)) + else new Vector2(prefix1, WIDTH, empty2, wrap1(elem), WIDTH+1) + } + + override def prepended[B >: A](elem: B): Vector[B] = { + val len1 = prefix1.length + if(len1 < WIDTH) new Vector1(copyPrepend1(elem, prefix1)) + else new Vector2(wrap1(elem), 1, empty2, prefix1, len1+1) + } + + override def map[B](f: A => B): Vector[B] = new Vector1(mapElems1(prefix1, f)) + + protected[this] def slice0(lo: Int, hi: Int): Vector[A] = + new Vector1(copyOfRange(prefix1, lo, hi)) + + override def tail: Vector[A] = + if(prefix1.length == 1) Vector0 + else new Vector1(copyTail(prefix1)) + + override def init: Vector[A] = + if(prefix1.length == 1) Vector0 + else new Vector1(copyInit(prefix1)) + + protected[immutable] def vectorSliceCount: Int = 1 + protected[immutable] def vectorSlice(idx: Int): Array[_ <: AnyRef] = prefix1 + protected[immutable] def vectorSlicePrefixLength(idx: Int): Int = prefix1.length + + override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + prepend1IfSpace(prefix1, prefix) match { + case null => super.prependedAll0(prefix, k) + case data1b => new Vector1(data1b) + } + + override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + val data1b = append1IfSpace(prefix1, suffix) + if(data1b ne null) new Vector1(data1b) + else super.appendedAll0(suffix, k) + } +} + + +/** 2-dimensional radix-balanced finger tree */ +private final class Vector2[+A](_prefix1: Arr1, private[immutable] val len1: Int, + private[immutable] val data2: Arr2, + _suffix1: Arr1, + _length0: Int) extends BigVector[A](_prefix1, _suffix1, _length0) { + + @inline private[this] def copy(prefix1: Arr1 = prefix1, len1: Int = len1, + data2: Arr2 = data2, + suffix1: Arr1 = suffix1, + length0: Int = length0) = + new Vector2(prefix1, len1, data2, suffix1, length0) + + @inline def apply(index: Int): A = { + if(index >= 0 && index < length0) { + val io = index - len1 + if(io >= 0) { + val i2 = io >>> BITS + val i1 = io & MASK + if(i2 < data2.length) data2(i2)(i1) + else suffix1(io & MASK) + } else prefix1(index) + }.asInstanceOf[A] else throw ioob(index) + } + + override def updated[B >: A](index: Int, elem: B): Vector[B] = { + if(index >= 0 && index < length0) { + if(index >= len1) { + val io = index - len1 + val i2 = io >>> BITS + val i1 = io & MASK + if(i2 < data2.length) copy(data2 = copyUpdate(data2, i2, i1, elem)) + else copy(suffix1 = copyUpdate(suffix1, i1, elem)) + } else { + copy(prefix1 = copyUpdate(prefix1, index, elem)) + } + } else throw ioob(index) + } + + override def appended[B >: A](elem: B): Vector[B] = { + if (suffix1.length < WIDTH ) copy(suffix1 = copyAppend1(suffix1, elem), length0 = length0+1) + else if(data2.length < WIDTH-2) copy(data2 = copyAppend(data2, suffix1), suffix1 = wrap1(elem), length0 = length0+1) + else new Vector3(prefix1, len1, data2, WIDTH*(WIDTH-2) + len1, empty3, wrap2(suffix1), wrap1(elem), length0+1) + } + + override def prepended[B >: A](elem: B): Vector[B] = { + if (len1 < WIDTH ) copy(copyPrepend1(elem, prefix1), len1+1, length0 = length0+1) + else if(data2.length < WIDTH-2) copy(wrap1(elem), 1, copyPrepend(prefix1, data2), length0 = length0+1) + else new Vector3(wrap1(elem), 1, wrap2(prefix1), len1+1, empty3, data2, suffix1, length0+1) + } + + override def map[B](f: A => B): Vector[B] = + copy(prefix1 = mapElems1(prefix1, f), data2 = mapElems(2, data2, f), suffix1 = mapElems1(suffix1, f)) + + protected[this] def slice0(lo: Int, hi: Int): Vector[A] = { + val b = new VectorSliceBuilder(lo, hi) + b.consider(1, prefix1) + b.consider(2, data2) + b.consider(1, suffix1) + b.result() + } + + override def tail: Vector[A] = + if(len1 > 1) copy(copyTail(prefix1), len1-1, length0 = length0-1) + else slice0(1, length0) + + override def init: Vector[A] = + if(suffix1.length > 1) copy(suffix1 = copyInit(suffix1), length0 = length0-1) + else slice0(0, length0-1) + + protected[immutable] def vectorSliceCount: Int = 3 + protected[immutable] def vectorSlice(idx: Int): Array[_ <: AnyRef] = (idx: @switch) match { + case 0 => prefix1 + case 1 => data2 + case 2 => suffix1 + } + protected[immutable] def vectorSlicePrefixLength(idx: Int): Int = (idx: @switch) match { + case 0 => len1 + case 1 => length0 - suffix1.length + case 2 => length0 + } + + override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + prepend1IfSpace(prefix1, prefix) match { + case null => super.prependedAll0(prefix, k) + case prefix1b => + val diff = prefix1b.length - prefix1.length + copy(prefix1 = prefix1b, + len1 = len1 + diff, + length0 = length0 + diff, + ) + } + + override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + val suffix1b = append1IfSpace(suffix1, suffix) + if(suffix1b ne null) copy(suffix1 = suffix1b, length0 = length0-suffix1.length+suffix1b.length) + else super.appendedAll0(suffix, k) + } +} + + +/** 3-dimensional radix-balanced finger tree */ +private final class Vector3[+A](_prefix1: Arr1, private[immutable] val len1: Int, + private[immutable] val prefix2: Arr2, private[immutable] val len12: Int, + private[immutable] val data3: Arr3, + private[immutable] val suffix2: Arr2, _suffix1: Arr1, + _length0: Int) extends BigVector[A](_prefix1, _suffix1, _length0) { + + @inline private[this] def copy(prefix1: Arr1 = prefix1, len1: Int = len1, + prefix2: Arr2 = prefix2, len12: Int = len12, + data3: Arr3 = data3, + suffix2: Arr2 = suffix2, suffix1: Arr1 = suffix1, + length0: Int = length0) = + new Vector3(prefix1, len1, prefix2, len12, data3, suffix2, suffix1, length0) + + @inline def apply(index: Int): A = { + if(index >= 0 && index < length0) { + val io = index - len12 + if(io >= 0) { + val i3 = io >>> BITS2 + val i2 = (io >>> BITS) & MASK + val i1 = io & MASK + if(i3 < data3.length) data3(i3)(i2)(i1) + else if(i2 < suffix2.length) suffix2(i2)(i1) + else suffix1(i1) + } else if(index >= len1) { + val io = index - len1 + prefix2(io >>> BITS)(io & MASK) + } else prefix1(index) + }.asInstanceOf[A] else throw ioob(index) + } + + override def updated[B >: A](index: Int, elem: B): Vector[B] = { + if(index >= 0 && index < length0) { + if(index >= len12) { + val io = index - len12 + val i3 = io >>> BITS2 + val i2 = (io >>> BITS) & MASK + val i1 = io & MASK + if (i3 < data3.length ) copy(data3 = copyUpdate(data3, i3, i2, i1, elem)) + else if(i2 < suffix2.length) copy(suffix2 = copyUpdate(suffix2, i2, i1, elem)) + else copy(suffix1 = copyUpdate(suffix1, i1, elem)) + } else if(index >= len1) { + val io = index - len1 + copy(prefix2 = copyUpdate(prefix2, io >>> BITS, io & MASK, elem)) + } else { + copy(prefix1 = copyUpdate(prefix1, index, elem)) + } + } else throw ioob(index) + } + + override def appended[B >: A](elem: B): Vector[B] = { + if (suffix1.length < WIDTH ) copy(suffix1 = copyAppend1(suffix1, elem), length0 = length0+1) + else if(suffix2.length < WIDTH-1) copy(suffix2 = copyAppend(suffix2, suffix1), suffix1 = wrap1(elem), length0 = length0+1) + else if(data3.length < WIDTH-2) copy(data3 = copyAppend(data3, copyAppend(suffix2, suffix1)), suffix2 = empty2, suffix1 = wrap1(elem), length0 = length0+1) + else new Vector4(prefix1, len1, prefix2, len12, data3, (WIDTH-2)*WIDTH2 + len12, empty4, wrap3(copyAppend(suffix2, suffix1)), empty2, wrap1(elem), length0+1) + } + + override def prepended[B >: A](elem: B): Vector[B] = { + if (len1 < WIDTH ) copy(prefix1 = copyPrepend1(elem, prefix1), len1 = len1+1, len12 = len12+1, length0 = length0+1) + else if(len12 < WIDTH2 ) copy(prefix1 = wrap1(elem), len1 = 1, prefix2 = copyPrepend(prefix1, prefix2), len12 = len12+1, length0 = length0+1) + else if(data3.length < WIDTH-2) copy(prefix1 = wrap1(elem), len1 = 1, prefix2 = empty2, len12 = 1, data3 = copyPrepend(copyPrepend(prefix1, prefix2), data3), length0 = length0+1) + else new Vector4(wrap1(elem), 1, empty2, 1, wrap3(copyPrepend(prefix1, prefix2)), len12+1, empty4, data3, suffix2, suffix1, length0+1) + } + + override def map[B](f: A => B): Vector[B] = + copy(prefix1 = mapElems1(prefix1, f), prefix2 = mapElems(2, prefix2, f), + data3 = mapElems(3, data3, f), + suffix2 = mapElems(2, suffix2, f), suffix1 = mapElems1(suffix1, f)) + + protected[this] def slice0(lo: Int, hi: Int): Vector[A] = { + val b = new VectorSliceBuilder(lo, hi) + b.consider(1, prefix1) + b.consider(2, prefix2) + b.consider(3, data3) + b.consider(2, suffix2) + b.consider(1, suffix1) + b.result() + } + + override def tail: Vector[A] = + if(len1 > 1) copy(prefix1 = copyTail(prefix1), len1 = len1-1, len12 = len12-1, length0 = length0-1) + else slice0(1, length0) + + override def init: Vector[A] = + if(suffix1.length > 1) copy(suffix1 = copyInit(suffix1), length0 = length0-1) + else slice0(0, length0-1) + + protected[immutable] def vectorSliceCount: Int = 5 + protected[immutable] def vectorSlice(idx: Int): Array[_ <: AnyRef] = (idx: @switch) match { + case 0 => prefix1 + case 1 => prefix2 + case 2 => data3 + case 3 => suffix2 + case 4 => suffix1 + } + protected[immutable] def vectorSlicePrefixLength(idx: Int): Int = (idx: @switch) match { + case 0 => len1 + case 1 => len12 + case 2 => len12 + data3.length*WIDTH2 + case 3 => length0 - suffix1.length + case 4 => length0 + } + + override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + prepend1IfSpace(prefix1, prefix) match { + case null => super.prependedAll0(prefix, k) + case prefix1b => + val diff = prefix1b.length - prefix1.length + copy(prefix1 = prefix1b, + len1 = len1 + diff, + len12 = len12 + diff, + length0 = length0 + diff, + ) + } + + override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + val suffix1b = append1IfSpace(suffix1, suffix) + if(suffix1b ne null) copy(suffix1 = suffix1b, length0 = length0-suffix1.length+suffix1b.length) + else super.appendedAll0(suffix, k) + } +} + + +/** 4-dimensional radix-balanced finger tree */ +private final class Vector4[+A](_prefix1: Arr1, private[immutable] val len1: Int, + private[immutable] val prefix2: Arr2, private[immutable] val len12: Int, + private[immutable] val prefix3: Arr3, private[immutable] val len123: Int, + private[immutable] val data4: Arr4, + private[immutable] val suffix3: Arr3, private[immutable] val suffix2: Arr2, _suffix1: Arr1, + _length0: Int) extends BigVector[A](_prefix1, _suffix1, _length0) { + + @inline private[this] def copy(prefix1: Arr1 = prefix1, len1: Int = len1, + prefix2: Arr2 = prefix2, len12: Int = len12, + prefix3: Arr3 = prefix3, len123: Int = len123, + data4: Arr4 = data4, + suffix3: Arr3 = suffix3, suffix2: Arr2 = suffix2, suffix1: Arr1 = suffix1, + length0: Int = length0) = + new Vector4(prefix1, len1, prefix2, len12, prefix3, len123, data4, suffix3, suffix2, suffix1, length0) + + @inline def apply(index: Int): A = { + if(index >= 0 && index < length0) { + val io = index - len123 + if(io >= 0) { + val i4 = io >>> BITS3 + val i3 = (io >>> BITS2) & MASK + val i2 = (io >>> BITS) & MASK + val i1 = io & MASK + if(i4 < data4.length) data4(i4)(i3)(i2)(i1) + else if(i3 < suffix3.length) suffix3(i3)(i2)(i1) + else if(i2 < suffix2.length) suffix2(i2)(i1) + else suffix1(i1) + } else if(index >= len12) { + val io = index - len12 + prefix3(io >>> BITS2)((io >>> BITS) & MASK)(io & MASK) + } else if(index >= len1) { + val io = index - len1 + prefix2(io >>> BITS)(io & MASK) + } else prefix1(index) + }.asInstanceOf[A] else throw ioob(index) + } + + override def updated[B >: A](index: Int, elem: B): Vector[B] = { + if(index >= 0 && index < length0) { + if(index >= len123) { + val io = index - len123 + val i4 = io >>> BITS3 + val i3 = (io >>> BITS2) & MASK + val i2 = (io >>> BITS) & MASK + val i1 = io & MASK + if (i4 < data4.length ) copy(data4 = copyUpdate(data4, i4, i3, i2, i1, elem)) + else if(i3 < suffix3.length) copy(suffix3 = copyUpdate(suffix3, i3, i2, i1, elem)) + else if(i2 < suffix2.length) copy(suffix2 = copyUpdate(suffix2, i2, i1, elem)) + else copy(suffix1 = copyUpdate(suffix1, i1, elem)) + } else if(index >= len12) { + val io = index - len12 + copy(prefix3 = copyUpdate(prefix3, io >>> BITS2, (io >>> BITS) & MASK, io & MASK, elem)) + } else if(index >= len1) { + val io = index - len1 + copy(prefix2 = copyUpdate(prefix2, io >>> BITS, io & MASK, elem)) + } else { + copy(prefix1 = copyUpdate(prefix1, index, elem)) + } + } else throw ioob(index) + } + + override def appended[B >: A](elem: B): Vector[B] = { + if (suffix1.length < WIDTH ) copy(suffix1 = copyAppend1(suffix1, elem), length0 = length0+1) + else if(suffix2.length < WIDTH-1) copy(suffix2 = copyAppend(suffix2, suffix1), suffix1 = wrap1(elem), length0 = length0+1) + else if(suffix3.length < WIDTH-1) copy(suffix3 = copyAppend(suffix3, copyAppend(suffix2, suffix1)), suffix2 = empty2, suffix1 = wrap1(elem), length0 = length0+1) + else if(data4.length < WIDTH-2) copy(data4 = copyAppend(data4, copyAppend(suffix3, copyAppend(suffix2, suffix1))), suffix3 = empty3, suffix2 = empty2, suffix1 = wrap1(elem), length0 = length0+1) + else new Vector5(prefix1, len1, prefix2, len12, prefix3, len123, data4, (WIDTH-2)*WIDTH3 + len123, empty5, wrap4(copyAppend(suffix3, copyAppend(suffix2, suffix1))), empty3, empty2, wrap1(elem), length0+1) + } + + override def prepended[B >: A](elem: B): Vector[B] = { + if (len1 < WIDTH ) copy(copyPrepend1(elem, prefix1), len1+1, len12 = len12+1, len123 = len123+1, length0 = length0+1) + else if(len12 < WIDTH2 ) copy(wrap1(elem), 1, copyPrepend(prefix1, prefix2), len12+1, len123 = len123+1, length0 = length0+1) + else if(len123 < WIDTH3 ) copy(wrap1(elem), 1, empty2, 1, copyPrepend(copyPrepend(prefix1, prefix2), prefix3), len123+1, length0 = length0+1) + else if(data4.length < WIDTH-2) copy(wrap1(elem), 1, empty2, 1, empty3, 1, copyPrepend(copyPrepend(copyPrepend(prefix1, prefix2), prefix3), data4), length0 = length0+1) + else new Vector5(wrap1(elem), 1, empty2, 1, empty3, 1, wrap4(copyPrepend(copyPrepend(prefix1, prefix2), prefix3)), len123+1, empty5, data4, suffix3, suffix2, suffix1, length0+1) + } + + override def map[B](f: A => B): Vector[B] = + copy(prefix1 = mapElems1(prefix1, f), prefix2 = mapElems(2, prefix2, f), prefix3 = mapElems(3, prefix3, f), + data4 = mapElems(4, data4, f), + suffix3 = mapElems(3, suffix3, f), suffix2 = mapElems(2, suffix2, f), suffix1 = mapElems1(suffix1, f)) + + protected[this] def slice0(lo: Int, hi: Int): Vector[A] = { + val b = new VectorSliceBuilder(lo, hi) + b.consider(1, prefix1) + b.consider(2, prefix2) + b.consider(3, prefix3) + b.consider(4, data4) + b.consider(3, suffix3) + b.consider(2, suffix2) + b.consider(1, suffix1) + b.result() + } + + override def tail: Vector[A] = + if(len1 > 1) copy(copyTail(prefix1), len1-1, len12 = len12-1, len123 = len123-1, length0 = length0-1) + else slice0(1, length0) + + override def init: Vector[A] = + if(suffix1.length > 1) copy(suffix1 = copyInit(suffix1), length0 = length0-1) + else slice0(0, length0-1) + + protected[immutable] def vectorSliceCount: Int = 7 + protected[immutable] def vectorSlice(idx: Int): Array[_ <: AnyRef] = (idx: @switch) match { + case 0 => prefix1 + case 1 => prefix2 + case 2 => prefix3 + case 3 => data4 + case 4 => suffix3 + case 5 => suffix2 + case 6 => suffix1 + } + protected[immutable] def vectorSlicePrefixLength(idx: Int): Int = (idx: @switch) match { + case 0 => len1 + case 1 => len12 + case 2 => len123 + case 3 => len123 + data4.length*WIDTH3 + case 4 => len123 + data4.length*WIDTH3 + suffix3.length*WIDTH2 + case 5 => length0 - suffix1.length + case 6 => length0 + } + + override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + prepend1IfSpace(prefix1, prefix) match { + case null => super.prependedAll0(prefix, k) + case prefix1b => + val diff = prefix1b.length - prefix1.length + copy(prefix1 = prefix1b, + len1 = len1 + diff, + len12 = len12 + diff, + len123 = len123 + diff, + length0 = length0 + diff, + ) + } + + override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + val suffix1b = append1IfSpace(suffix1, suffix) + if(suffix1b ne null) copy(suffix1 = suffix1b, length0 = length0-suffix1.length+suffix1b.length) + else super.appendedAll0(suffix, k) + } +} + + +/** 5-dimensional radix-balanced finger tree */ +private final class Vector5[+A](_prefix1: Arr1, private[immutable] val len1: Int, + private[immutable] val prefix2: Arr2, private[immutable] val len12: Int, + private[immutable] val prefix3: Arr3, private[immutable] val len123: Int, + private[immutable] val prefix4: Arr4, private[immutable] val len1234: Int, + private[immutable] val data5: Arr5, + private[immutable] val suffix4: Arr4, private[immutable] val suffix3: Arr3, private[immutable] val suffix2: Arr2, _suffix1: Arr1, + _length0: Int) extends BigVector[A](_prefix1, _suffix1, _length0) { + + @inline private[this] def copy(prefix1: Arr1 = prefix1, len1: Int = len1, + prefix2: Arr2 = prefix2, len12: Int = len12, + prefix3: Arr3 = prefix3, len123: Int = len123, + prefix4: Arr4 = prefix4, len1234: Int = len1234, + data5: Arr5 = data5, + suffix4: Arr4 = suffix4, suffix3: Arr3 = suffix3, suffix2: Arr2 = suffix2, suffix1: Arr1 = suffix1, + length0: Int = length0) = + new Vector5(prefix1, len1, prefix2, len12, prefix3, len123, prefix4, len1234, data5, suffix4, suffix3, suffix2, suffix1, length0) + + @inline def apply(index: Int): A = { + if(index >= 0 && index < length0) { + val io = index - len1234 + if(io >= 0) { + val i5 = io >>> BITS4 + val i4 = (io >>> BITS3) & MASK + val i3 = (io >>> BITS2) & MASK + val i2 = (io >>> BITS) & MASK + val i1 = io & MASK + if(i5 < data5.length) data5(i5)(i4)(i3)(i2)(i1) + else if(i4 < suffix4.length) suffix4(i4)(i3)(i2)(i1) + else if(i3 < suffix3.length) suffix3(i3)(i2)(i1) + else if(i2 < suffix2.length) suffix2(i2)(i1) + else suffix1(i1) + } else if(index >= len123) { + val io = index - len123 + prefix4(io >>> BITS3)((io >>> BITS2) & MASK)((io >>> BITS) & MASK)(io & MASK) + } else if(index >= len12) { + val io = index - len12 + prefix3(io >>> BITS2)((io >>> BITS) & MASK)(io & MASK) + } else if(index >= len1) { + val io = index - len1 + prefix2(io >>> BITS)(io & MASK) + } else prefix1(index) + }.asInstanceOf[A] else throw ioob(index) + } + + override def updated[B >: A](index: Int, elem: B): Vector[B] = { + if(index >= 0 && index < length0) { + if(index >= len1234) { + val io = index - len1234 + val i5 = io >>> BITS4 + val i4 = (io >>> BITS3) & MASK + val i3 = (io >>> BITS2) & MASK + val i2 = (io >>> BITS) & MASK + val i1 = io & MASK + if (i5 < data5.length ) copy(data5 = copyUpdate(data5, i5, i4, i3, i2, i1, elem)) + else if(i4 < suffix4.length) copy(suffix4 = copyUpdate(suffix4, i4, i3, i2, i1, elem)) + else if(i3 < suffix3.length) copy(suffix3 = copyUpdate(suffix3, i3, i2, i1, elem)) + else if(i2 < suffix2.length) copy(suffix2 = copyUpdate(suffix2, i2, i1, elem)) + else copy(suffix1 = copyUpdate(suffix1, i1, elem)) + } else if(index >= len123) { + val io = index - len123 + copy(prefix4 = copyUpdate(prefix4, io >>> BITS3, (io >>> BITS2) & MASK, (io >>> BITS) & MASK, io & MASK, elem)) + } else if(index >= len12) { + val io = index - len12 + copy(prefix3 = copyUpdate(prefix3, io >>> BITS2, (io >>> BITS) & MASK, io & MASK, elem)) + } else if(index >= len1) { + val io = index - len1 + copy(prefix2 = copyUpdate(prefix2, io >>> BITS, io & MASK, elem)) + } else { + copy(prefix1 = copyUpdate(prefix1, index, elem)) + } + } else throw ioob(index) + } + + override def appended[B >: A](elem: B): Vector[B] = { + if (suffix1.length < WIDTH ) copy(suffix1 = copyAppend1(suffix1, elem), length0 = length0+1) + else if(suffix2.length < WIDTH-1) copy(suffix2 = copyAppend(suffix2, suffix1), suffix1 = wrap1(elem), length0 = length0+1) + else if(suffix3.length < WIDTH-1) copy(suffix3 = copyAppend(suffix3, copyAppend(suffix2, suffix1)), suffix2 = empty2, suffix1 = wrap1(elem), length0 = length0+1) + else if(suffix4.length < WIDTH-1) copy(suffix4 = copyAppend(suffix4, copyAppend(suffix3, copyAppend(suffix2, suffix1))), suffix3 = empty3, suffix2 = empty2, suffix1 = wrap1(elem), length0 = length0+1) + else if(data5.length < WIDTH-2) copy(data5 = copyAppend(data5, copyAppend(suffix4, copyAppend(suffix3, copyAppend(suffix2, suffix1)))), suffix4 = empty4, suffix3 = empty3, suffix2 = empty2, suffix1 = wrap1(elem), length0 = length0+1) + else new Vector6(prefix1, len1, prefix2, len12, prefix3, len123, prefix4, len1234, data5, (WIDTH-2)*WIDTH4 + len1234, empty6, wrap5(copyAppend(suffix4, copyAppend(suffix3, copyAppend(suffix2, suffix1)))), empty4, empty3, empty2, wrap1(elem), length0+1) + } + + override def prepended[B >: A](elem: B): Vector[B] = { + if (len1 < WIDTH ) copy(copyPrepend1(elem, prefix1), len1+1, len12 = len12+1, len123 = len123+1, len1234 = len1234+1, length0 = length0+1) + else if(len12 < WIDTH2 ) copy(wrap1(elem), 1, copyPrepend(prefix1, prefix2), len12+1, len123 = len123+1, len1234 = len1234+1, length0 = length0+1) + else if(len123 < WIDTH3 ) copy(wrap1(elem), 1, empty2, 1, copyPrepend(copyPrepend(prefix1, prefix2), prefix3), len123+1, len1234 = len1234+1, length0 = length0+1) + else if(len1234 < WIDTH4 ) copy(wrap1(elem), 1, empty2, 1, empty3, 1, copyPrepend(copyPrepend(copyPrepend(prefix1, prefix2), prefix3), prefix4), len1234+1, length0 = length0+1) + else if(data5.length < WIDTH-2) copy(wrap1(elem), 1, empty2, 1, empty3, 1, empty4, 1, copyPrepend(copyPrepend(copyPrepend(copyPrepend(prefix1, prefix2), prefix3), prefix4), data5), length0 = length0+1) + else new Vector6(wrap1(elem), 1, empty2, 1, empty3, 1, empty4, 1, wrap5(copyPrepend(copyPrepend(copyPrepend(prefix1, prefix2), prefix3), prefix4)), len1234+1, empty6, data5, suffix4, suffix3, suffix2, suffix1, length0+1) + } + + override def map[B](f: A => B): Vector[B] = + copy(prefix1 = mapElems1(prefix1, f), prefix2 = mapElems(2, prefix2, f), prefix3 = mapElems(3, prefix3, f), prefix4 = mapElems(4, prefix4, f), + data5 = mapElems(5, data5, f), + suffix4 = mapElems(4, suffix4, f), suffix3 = mapElems(3, suffix3, f), suffix2 = mapElems(2, suffix2, f), suffix1 = mapElems1(suffix1, f)) + + protected[this] def slice0(lo: Int, hi: Int): Vector[A] = { + val b = new VectorSliceBuilder(lo, hi) + b.consider(1, prefix1) + b.consider(2, prefix2) + b.consider(3, prefix3) + b.consider(4, prefix4) + b.consider(5, data5) + b.consider(4, suffix4) + b.consider(3, suffix3) + b.consider(2, suffix2) + b.consider(1, suffix1) + b.result() + } + + override def tail: Vector[A] = + if(len1 > 1) copy(copyTail(prefix1), len1-1, len12 = len12-1, len123 = len123-1, len1234 = len1234-1, length0 = length0-1) + else slice0(1, length0) + + override def init: Vector[A] = + if(suffix1.length > 1) copy(suffix1 = copyInit(suffix1), length0 = length0-1) + else slice0(0, length0-1) + + protected[immutable] def vectorSliceCount: Int = 9 + protected[immutable] def vectorSlice(idx: Int): Array[_ <: AnyRef] = (idx: @switch) match { + case 0 => prefix1 + case 1 => prefix2 + case 2 => prefix3 + case 3 => prefix4 + case 4 => data5 + case 5 => suffix4 + case 6 => suffix3 + case 7 => suffix2 + case 8 => suffix1 + } + protected[immutable] def vectorSlicePrefixLength(idx: Int): Int = (idx: @switch) match { + case 0 => len1 + case 1 => len12 + case 2 => len123 + case 3 => len1234 + case 4 => len1234 + data5.length*WIDTH4 + case 5 => len1234 + data5.length*WIDTH4 + suffix4.length*WIDTH3 + case 6 => len1234 + data5.length*WIDTH4 + suffix4.length*WIDTH3 + suffix3.length*WIDTH2 + case 7 => length0 - suffix1.length + case 8 => length0 + } + + override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + prepend1IfSpace(prefix1, prefix) match { + case null => super.prependedAll0(prefix, k) + case prefix1b => + val diff = prefix1b.length - prefix1.length + copy(prefix1 = prefix1b, + len1 = len1 + diff, + len12 = len12 + diff, + len123 = len123 + diff, + len1234 = len1234 + diff, + length0 = length0 + diff, + ) + } + + override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + val suffix1b = append1IfSpace(suffix1, suffix) + if(suffix1b ne null) copy(suffix1 = suffix1b, length0 = length0-suffix1.length+suffix1b.length) + else super.appendedAll0(suffix, k) + } +} + + +/** 6-dimensional radix-balanced finger tree */ +private final class Vector6[+A](_prefix1: Arr1, private[immutable] val len1: Int, + private[immutable] val prefix2: Arr2, private[immutable] val len12: Int, + private[immutable] val prefix3: Arr3, private[immutable] val len123: Int, + private[immutable] val prefix4: Arr4, private[immutable] val len1234: Int, + private[immutable] val prefix5: Arr5, private[immutable] val len12345: Int, + private[immutable] val data6: Arr6, + private[immutable] val suffix5: Arr5, private[immutable] val suffix4: Arr4, private[immutable] val suffix3: Arr3, private[immutable] val suffix2: Arr2, _suffix1: Arr1, + _length0: Int) extends BigVector[A](_prefix1, _suffix1, _length0) { + + @inline private[this] def copy(prefix1: Arr1 = prefix1, len1: Int = len1, + prefix2: Arr2 = prefix2, len12: Int = len12, + prefix3: Arr3 = prefix3, len123: Int = len123, + prefix4: Arr4 = prefix4, len1234: Int = len1234, + prefix5: Arr5 = prefix5, len12345: Int = len12345, + data6: Arr6 = data6, + suffix5: Arr5 = suffix5, suffix4: Arr4 = suffix4, suffix3: Arr3 = suffix3, suffix2: Arr2 = suffix2, suffix1: Arr1 = suffix1, + length0: Int = length0) = + new Vector6(prefix1, len1, prefix2, len12, prefix3, len123, prefix4, len1234, prefix5, len12345, data6, suffix5, suffix4, suffix3, suffix2, suffix1, length0) + + @inline def apply(index: Int): A = { + if(index >= 0 && index < length0) { + val io = index - len12345 + if(io >= 0) { + val i6 = io >>> BITS5 + val i5 = (io >>> BITS4) & MASK + val i4 = (io >>> BITS3) & MASK + val i3 = (io >>> BITS2) & MASK + val i2 = (io >>> BITS) & MASK + val i1 = io & MASK + if(i6 < data6.length) data6(i6)(i5)(i4)(i3)(i2)(i1) + else if(i5 < suffix5.length) suffix5(i5)(i4)(i3)(i2)(i1) + else if(i4 < suffix4.length) suffix4(i4)(i3)(i2)(i1) + else if(i3 < suffix3.length) suffix3(i3)(i2)(i1) + else if(i2 < suffix2.length) suffix2(i2)(i1) + else suffix1(i1) + } else if(index >= len1234) { + val io = index - len1234 + prefix5(io >>> BITS4)((io >>> BITS3) & MASK)((io >>> BITS2) & MASK)((io >>> BITS) & MASK)(io & MASK) + } else if(index >= len123) { + val io = index - len123 + prefix4(io >>> BITS3)((io >>> BITS2) & MASK)((io >>> BITS) & MASK)(io & MASK) + } else if(index >= len12) { + val io = index - len12 + prefix3(io >>> BITS2)((io >>> BITS) & MASK)(io & MASK) + } else if(index >= len1) { + val io = index - len1 + prefix2(io >>> BITS)(io & MASK) + } else prefix1(index) + }.asInstanceOf[A] else throw ioob(index) + } + + override def updated[B >: A](index: Int, elem: B): Vector[B] = { + if(index >= 0 && index < length0) { + if(index >= len12345) { + val io = index - len12345 + val i6 = io >>> BITS5 + val i5 = (io >>> BITS4) & MASK + val i4 = (io >>> BITS3) & MASK + val i3 = (io >>> BITS2) & MASK + val i2 = (io >>> BITS) & MASK + val i1 = io & MASK + if (i6 < data6.length ) copy(data6 = copyUpdate(data6, i6, i5, i4, i3, i2, i1, elem)) + else if(i5 < suffix5.length) copy(suffix5 = copyUpdate(suffix5, i5, i4, i3, i2, i1, elem)) + else if(i4 < suffix4.length) copy(suffix4 = copyUpdate(suffix4, i4, i3, i2, i1, elem)) + else if(i3 < suffix3.length) copy(suffix3 = copyUpdate(suffix3, i3, i2, i1, elem)) + else if(i2 < suffix2.length) copy(suffix2 = copyUpdate(suffix2, i2, i1, elem)) + else copy(suffix1 = copyUpdate(suffix1, i1, elem)) + } else if(index >= len1234) { + val io = index - len1234 + copy(prefix5 = copyUpdate(prefix5, io >>> BITS4, (io >>> BITS3) & MASK, (io >>> BITS2) & MASK, (io >>> BITS) & MASK, io & MASK, elem)) + } else if(index >= len123) { + val io = index - len123 + copy(prefix4 = copyUpdate(prefix4, io >>> BITS3, (io >>> BITS2) & MASK, (io >>> BITS) & MASK, io & MASK, elem)) + } else if(index >= len12) { + val io = index - len12 + copy(prefix3 = copyUpdate(prefix3, io >>> BITS2, (io >>> BITS) & MASK, io & MASK, elem)) + } else if(index >= len1) { + val io = index - len1 + copy(prefix2 = copyUpdate(prefix2, io >>> BITS, io & MASK, elem)) + } else { + copy(prefix1 = copyUpdate(prefix1, index, elem)) + } + } else throw ioob(index) + } + + override def appended[B >: A](elem: B): Vector[B] = { + if (suffix1.length < WIDTH ) copy(suffix1 = copyAppend1(suffix1, elem), length0 = length0+1) + else if(suffix2.length < WIDTH-1 ) copy(suffix2 = copyAppend(suffix2, suffix1), suffix1 = wrap1(elem), length0 = length0+1) + else if(suffix3.length < WIDTH-1 ) copy(suffix3 = copyAppend(suffix3, copyAppend(suffix2, suffix1)), suffix2 = empty2, suffix1 = wrap1(elem), length0 = length0+1) + else if(suffix4.length < WIDTH-1 ) copy(suffix4 = copyAppend(suffix4, copyAppend(suffix3, copyAppend(suffix2, suffix1))), suffix3 = empty3, suffix2 = empty2, suffix1 = wrap1(elem), length0 = length0+1) + else if(suffix5.length < WIDTH-1 ) copy(suffix5 = copyAppend(suffix5, copyAppend(suffix4, copyAppend(suffix3, copyAppend(suffix2, suffix1)))), suffix4 = empty4, suffix3 = empty3, suffix2 = empty2, suffix1 = wrap1(elem), length0 = length0+1) + else if(data6.length < LASTWIDTH-2) copy(data6 = copyAppend(data6, copyAppend(suffix5, copyAppend(suffix4, copyAppend(suffix3, copyAppend(suffix2, suffix1))))), suffix5 = empty5, suffix4 = empty4, suffix3 = empty3, suffix2 = empty2, suffix1 = wrap1(elem), length0 = length0+1) + else throw new IllegalArgumentException + } + + override def prepended[B >: A](elem: B): Vector[B] = { + if (len1 < WIDTH ) copy(copyPrepend1(elem, prefix1), len1+1, len12 = len12+1, len123 = len123+1, len1234 = len1234+1, len12345 = len12345+1, length0 = length0+1) + else if(len12 < WIDTH2 ) copy(wrap1(elem), 1, copyPrepend(prefix1, prefix2), len12+1, len123 = len123+1, len1234 = len1234+1, len12345 = len12345+1, length0 = length0+1) + else if(len123 < WIDTH3 ) copy(wrap1(elem), 1, empty2, 1, copyPrepend(copyPrepend(prefix1, prefix2), prefix3), len123+1, len1234 = len1234+1, len12345 = len12345+1, length0 = length0+1) + else if(len1234 < WIDTH4 ) copy(wrap1(elem), 1, empty2, 1, empty3, 1, copyPrepend(copyPrepend(copyPrepend(prefix1, prefix2), prefix3), prefix4), len1234+1, len12345 = len12345+1, length0 = length0+1) + else if(len12345 < WIDTH5 ) copy(wrap1(elem), 1, empty2, 1, empty3, 1, empty4, 1, copyPrepend(copyPrepend(copyPrepend(copyPrepend(prefix1, prefix2), prefix3), prefix4), prefix5), len12345+1, length0 = length0+1) + else if(data6.length < LASTWIDTH-2) copy(wrap1(elem), 1, empty2, 1, empty3, 1, empty4, 1, empty5, 1, copyPrepend(copyPrepend(copyPrepend(copyPrepend(copyPrepend(prefix1, prefix2), prefix3), prefix4), prefix5), data6), length0 = length0+1) + else throw new IllegalArgumentException + } + + override def map[B](f: A => B): Vector[B] = + copy(prefix1 = mapElems1(prefix1, f), prefix2 = mapElems(2, prefix2, f), prefix3 = mapElems(3, prefix3, f), prefix4 = mapElems(4, prefix4, f), prefix5 = mapElems(5, prefix5, f), + data6 = mapElems(6, data6, f), + suffix5 = mapElems(5, suffix5, f), suffix4 = mapElems(4, suffix4, f), suffix3 = mapElems(3, suffix3, f), suffix2 = mapElems(2, suffix2, f), suffix1 = mapElems1(suffix1, f)) + + protected[this] def slice0(lo: Int, hi: Int): Vector[A] = { + val b = new VectorSliceBuilder(lo, hi) + b.consider(1, prefix1) + b.consider(2, prefix2) + b.consider(3, prefix3) + b.consider(4, prefix4) + b.consider(5, prefix5) + b.consider(6, data6) + b.consider(5, suffix5) + b.consider(4, suffix4) + b.consider(3, suffix3) + b.consider(2, suffix2) + b.consider(1, suffix1) + b.result() + } + + override def tail: Vector[A] = + if(len1 > 1) copy(copyTail(prefix1), len1-1, len12 = len12-1, len123 = len123-1, len1234 = len1234-1, len12345 = len12345-1, length0 = length0-1) + else slice0(1, length0) + + override def init: Vector[A] = + if(suffix1.length > 1) copy(suffix1 = copyInit(suffix1), length0 = length0-1) + else slice0(0, length0-1) + + protected[immutable] def vectorSliceCount: Int = 11 + protected[immutable] def vectorSlice(idx: Int): Array[_ <: AnyRef] = (idx: @switch) match { + case 0 => prefix1 + case 1 => prefix2 + case 2 => prefix3 + case 3 => prefix4 + case 4 => prefix5 + case 5 => data6 + case 6 => suffix5 + case 7 => suffix4 + case 8 => suffix3 + case 9 => suffix2 + case 10 => suffix1 + } + protected[immutable] def vectorSlicePrefixLength(idx: Int): Int = (idx: @switch) match { + case 0 => len1 + case 1 => len12 + case 2 => len123 + case 3 => len1234 + case 4 => len12345 + case 5 => len12345 + data6.length*WIDTH5 + case 6 => len12345 + data6.length*WIDTH5 + suffix5.length*WIDTH4 + case 7 => len12345 + data6.length*WIDTH5 + suffix5.length*WIDTH4 + suffix4.length*WIDTH3 + case 8 => len12345 + data6.length*WIDTH5 + suffix5.length*WIDTH4 + suffix4.length*WIDTH3 + suffix3.length*WIDTH2 + case 9 => length0 - suffix1.length + case 10 => length0 + } + + override protected[this] def prependedAll0[B >: A](prefix: collection.IterableOnce[B], k: Int): Vector[B] = + prepend1IfSpace(prefix1, prefix) match { + case null => super.prependedAll0(prefix, k) + case prefix1b => + val diff = prefix1b.length - prefix1.length + copy(prefix1 = prefix1b, + len1 = len1 + diff, + len12 = len12 + diff, + len123 = len123 + diff, + len1234 = len1234 + diff, + len12345 = len12345 + diff, + length0 = length0 + diff, + ) + } + + override protected[this] def appendedAll0[B >: A](suffix: collection.IterableOnce[B], k: Int): Vector[B] = { + val suffix1b = append1IfSpace(suffix1, suffix) + if(suffix1b ne null) copy(suffix1 = suffix1b, length0 = length0-suffix1.length+suffix1b.length) + else super.appendedAll0(suffix, k) + } +} + + +/** Helper class for vector slicing. It is initialized with the validated start and end index, + * then the vector slices are added in succession with `consider`. No matter what the dimension + * of the originating vector is or where the cut is performed, this always results in a + * structure with the highest-dimensional data in the middle and fingers of decreasing dimension + * at both ends, which can be turned into a new vector with very little rebalancing. + */ +private final class VectorSliceBuilder(lo: Int, hi: Int) { + //println(s"***** VectorSliceBuilder($lo, $hi)") + + private[this] val slices = new Array[Array[AnyRef]](11) + private[this] var len, pos, maxDim = 0 + + @inline private[this] def prefixIdx(n: Int) = n-1 + @inline private[this] def suffixIdx(n: Int) = 11-n + + def consider[T <: AnyRef](n: Int, a: Array[T]): Unit = { + //println(s"***** consider($n, /${a.length})") + val count = a.length * (1 << (BITS*(n-1))) + val lo0 = mmax(lo-pos, 0) + val hi0 = mmin(hi-pos, count) + if(hi0 > lo0) { + addSlice(n, a, lo0, hi0) + len += (hi0 - lo0) + } + pos += count + } + + private[this] def addSlice[T <: AnyRef](n: Int, a: Array[T], lo: Int, hi: Int): Unit = { + //println(s"***** addSlice($n, /${a.length}, $lo, $hi)") + if(n == 1) { + add(1, copyOrUse(a, lo, hi)) + } else { + val bitsN = BITS * (n-1) + val widthN = 1 << bitsN + val loN = lo >>> bitsN + val hiN = hi >>> bitsN + val loRest = lo & (widthN - 1) + val hiRest = hi & (widthN - 1) + //println(s"***** bitsN=$bitsN, loN=$loN, hiN=$hiN, loRest=$loRest, hiRest=$hiRest") + if(loRest == 0) { + if(hiRest == 0) { + add(n, copyOrUse(a, loN, hiN)) + } else { + if(hiN > loN) add(n, copyOrUse(a, loN, hiN)) + addSlice(n-1, a(hiN).asInstanceOf[Array[AnyRef]], 0, hiRest) + } + } else { + if(hiN == loN) { + addSlice(n-1, a(loN).asInstanceOf[Array[AnyRef]], loRest, hiRest) + } else { + addSlice(n-1, a(loN).asInstanceOf[Array[AnyRef]], loRest, widthN) + if(hiRest == 0) { + if(hiN > loN+1) add(n, copyOrUse(a, loN+1, hiN)) + } else { + if(hiN > loN+1) add(n, copyOrUse(a, loN+1, hiN)) + addSlice(n-1, a(hiN).asInstanceOf[Array[AnyRef]], 0, hiRest) + } + } + } + } + } + + private[this] def add[T <: AnyRef](n: Int, a: Array[T]): Unit = { + //println(s"***** add($n, /${a.length})") + val idx = + if(n <= maxDim) suffixIdx(n) + else { maxDim = n; prefixIdx(n) } + slices(idx) = a.asInstanceOf[Array[AnyRef]] + } + + def result[A](): Vector[A] = { + //println(s"***** result: $len, $maxDim") + if(len <= 32) { + if(len == 0) Vector0 + else { + val prefix1 = slices(prefixIdx(1)) + val suffix1 = slices(suffixIdx(1)) + //println(s"***** prefix1: ${if(prefix1 == null) "null" else prefix1.mkString("[", ",", "]")}, suffix1: ${if(suffix1 == null) "null" else suffix1.mkString("[", ",", "]")}") + val a: Arr1 = + if(prefix1 ne null) { + if(suffix1 ne null) concatArrays(prefix1, suffix1) + else prefix1 + } else if(suffix1 ne null) suffix1 + else { + val prefix2 = slices(prefixIdx(2)).asInstanceOf[Arr2] + if(prefix2 ne null) prefix2(0) + else { + val suffix2 = slices(suffixIdx(2)).asInstanceOf[Arr2] + suffix2(0) + } + } + new Vector1(a) + } + } else { + balancePrefix(1) + balanceSuffix(1) + var resultDim = maxDim + if(resultDim < 6) { + val pre = slices(prefixIdx(maxDim)) + val suf = slices(suffixIdx(maxDim)) + if((pre ne null) && (suf ne null)) { + // The highest-dimensional data consists of two slices: concatenate if they fit into the main data array, + // otherwise increase the dimension + if(pre.length + suf.length <= WIDTH-2) { + slices(prefixIdx(maxDim)) = concatArrays(pre, suf) + slices(suffixIdx(maxDim)) = null + } else resultDim += 1 + } else { + // A single highest-dimensional slice could have length WIDTH-1 if it came from a prefix or suffix but we + // only allow WIDTH-2 for the main data, so increase the dimension in this case + val one = if(pre ne null) pre else suf + if(one.length > WIDTH-2) resultDim += 1 + } + } + val prefix1 = slices(prefixIdx(1)) + val suffix1 = slices(suffixIdx(1)) + val len1 = prefix1.length + val res = (resultDim: @switch) match { + case 2 => + val data2 = dataOr(2, empty2) + new Vector2[A](prefix1, len1, data2, suffix1, len) + case 3 => + val prefix2 = prefixOr(2, empty2) + val data3 = dataOr(3, empty3) + val suffix2 = suffixOr(2, empty2) + val len12 = len1 + (prefix2.length * WIDTH) + new Vector3[A](prefix1, len1, prefix2, len12, data3, suffix2, suffix1, len) + case 4 => + val prefix2 = prefixOr(2, empty2) + val prefix3 = prefixOr(3, empty3) + val data4 = dataOr(4, empty4) + val suffix3 = suffixOr(3, empty3) + val suffix2 = suffixOr(2, empty2) + val len12 = len1 + (prefix2.length * WIDTH) + val len123 = len12 + (prefix3.length * WIDTH2) + new Vector4[A](prefix1, len1, prefix2, len12, prefix3, len123, data4, suffix3, suffix2, suffix1, len) + case 5 => + val prefix2 = prefixOr(2, empty2) + val prefix3 = prefixOr(3, empty3) + val prefix4 = prefixOr(4, empty4) + val data5 = dataOr(5, empty5) + val suffix4 = suffixOr(4, empty4) + val suffix3 = suffixOr(3, empty3) + val suffix2 = suffixOr(2, empty2) + val len12 = len1 + (prefix2.length * WIDTH) + val len123 = len12 + (prefix3.length * WIDTH2) + val len1234 = len123 + (prefix4.length * WIDTH3) + new Vector5[A](prefix1, len1, prefix2, len12, prefix3, len123, prefix4, len1234, data5, suffix4, suffix3, suffix2, suffix1, len) + case 6 => + val prefix2 = prefixOr(2, empty2) + val prefix3 = prefixOr(3, empty3) + val prefix4 = prefixOr(4, empty4) + val prefix5 = prefixOr(5, empty5) + val data6 = dataOr(6, empty6) + val suffix5 = suffixOr(5, empty5) + val suffix4 = suffixOr(4, empty4) + val suffix3 = suffixOr(3, empty3) + val suffix2 = suffixOr(2, empty2) + val len12 = len1 + (prefix2.length * WIDTH) + val len123 = len12 + (prefix3.length * WIDTH2) + val len1234 = len123 + (prefix4.length * WIDTH3) + val len12345 = len1234 + (prefix5.length * WIDTH4) + new Vector6[A](prefix1, len1, prefix2, len12, prefix3, len123, prefix4, len1234, prefix5, len12345, data6, suffix5, suffix4, suffix3, suffix2, suffix1, len) + } + res + } + } + + @inline private[this] def prefixOr[T <: AnyRef](n: Int, a: Array[T]): Array[T] = { + val p = slices(prefixIdx(n)) + if(p ne null) p.asInstanceOf[Array[T]] else a + } + + @inline private[this] def suffixOr[T <: AnyRef](n: Int, a: Array[T]): Array[T] = { + val s = slices(suffixIdx(n)) + if(s ne null) s.asInstanceOf[Array[T]] else a + } + + @inline private[this] def dataOr[T <: AnyRef](n: Int, a: Array[T]): Array[T] = { + val p = slices(prefixIdx(n)) + if(p ne null) p.asInstanceOf[Array[T]] + else { + val s = slices(suffixIdx(n)) + if(s ne null) s.asInstanceOf[Array[T]] else a + } + } + + /** Ensure prefix is not empty */ + private[this] def balancePrefix(n: Int): Unit = { + if(slices(prefixIdx(n)) eq null) { + if(n == maxDim) { + slices(prefixIdx(n)) = slices(suffixIdx(n)) + slices(suffixIdx(n)) = null + } else { + balancePrefix(n+1) + val preN1 = slices(prefixIdx(n+1)).asInstanceOf[Array[Array[AnyRef]]] + //assert(preN1 ne null) + slices(prefixIdx(n)) = preN1(0) + if(preN1.length == 1) { + slices(prefixIdx(n+1)) = null + if((maxDim == n+1) && (slices(suffixIdx(n+1)) eq null)) maxDim = n + } else { + slices(prefixIdx(n+1)) = copyOfRange(preN1, 1, preN1.length).asInstanceOf[Array[AnyRef]] + } + } + } + } + + /** Ensure suffix is not empty */ + private[this] def balanceSuffix(n: Int): Unit = { + if(slices(suffixIdx(n)) eq null) { + if(n == maxDim) { + slices(suffixIdx(n)) = slices(prefixIdx(n)) + slices(prefixIdx(n)) = null + } else { + balanceSuffix(n+1) + val sufN1 = slices(suffixIdx(n+1)).asInstanceOf[Array[Array[AnyRef]]] + //assert(sufN1 ne null, s"n=$n, maxDim=$maxDim, slices=${slices.mkString(",")}") + slices(suffixIdx(n)) = sufN1(sufN1.length-1) + if(sufN1.length == 1) { + slices(suffixIdx(n+1)) = null + if((maxDim == n+1) && (slices(prefixIdx(n+1)) eq null)) maxDim = n + } else { + slices(suffixIdx(n+1)) = copyOfRange(sufN1, 0, sufN1.length-1).asInstanceOf[Array[AnyRef]] + } + } + } + } + + override def toString: String = + s"VectorSliceBuilder(lo=$lo, hi=$hi, len=$len, pos=$pos, maxDim=$maxDim)" + + private[immutable] def getSlices: Array[Array[AnyRef]] = slices +} + + +final class VectorBuilder[A] extends ReusableBuilder[A, Vector[A]] { + + private[this] var a6: Arr6 = _ + private[this] var a5: Arr5 = _ + private[this] var a4: Arr4 = _ + private[this] var a3: Arr3 = _ + private[this] var a2: Arr2 = _ + private[this] var a1: Arr1 = new Arr1(WIDTH) + private[this] var len1, lenRest, offset = 0 + private[this] var prefixIsRightAligned = false + private[this] var depth = 1 + + @inline private[this] final def setLen(i: Int): Unit = { + len1 = i & MASK + lenRest = i - len1 + } + + override def knownSize: Int = len1 + lenRest - offset + + @inline def size: Int = knownSize + @inline def isEmpty: Boolean = knownSize == 0 + @inline def nonEmpty: Boolean = knownSize != 0 + + def clear(): Unit = { + a6 = null + a5 = null + a4 = null + a3 = null + a2 = null + a1 = new Arr1(WIDTH) + len1 = 0 + lenRest = 0 + offset = 0 + prefixIsRightAligned = false + depth = 1 + } + + private[immutable] def initSparse(size: Int, elem: A): Unit = { + setLen(size) + Arrays.fill(a1, elem) + if(size > WIDTH) { + a2 = new Array(WIDTH) + Arrays.fill(a2.asInstanceOf[Array[AnyRef]], a1) + if(size > WIDTH2) { + a3 = new Array(WIDTH) + Arrays.fill(a3.asInstanceOf[Array[AnyRef]], a2) + if(size > WIDTH3) { + a4 = new Array(WIDTH) + Arrays.fill(a4.asInstanceOf[Array[AnyRef]], a3) + if(size > WIDTH4) { + a5 = new Array(WIDTH) + Arrays.fill(a5.asInstanceOf[Array[AnyRef]], a4) + if(size > WIDTH5) { + a6 = new Array(LASTWIDTH) + Arrays.fill(a6.asInstanceOf[Array[AnyRef]], a5) + depth = 6 + } else depth = 5 + } else depth = 4 + } else depth = 3 + } else depth = 2 + } else depth = 1 + } + + private[immutable] def initFrom(prefix1: Arr1): Unit = { + depth = 1 + setLen(prefix1.length) + a1 = copyOrUse(prefix1, 0, WIDTH) + if(len1 == 0 && lenRest > 0) { + // force advance() on next addition: + len1 = WIDTH + lenRest -= WIDTH + } + } + + private[immutable] def initFrom(v: Vector[_]): this.type = { + (v.vectorSliceCount: @switch) match { + case 0 => + case 1 => + val v1 = v.asInstanceOf[Vector1[_]] + depth = 1 + setLen(v1.prefix1.length) + a1 = copyOrUse(v1.prefix1, 0, WIDTH) + case 3 => + val v2 = v.asInstanceOf[Vector2[_]] + val d2 = v2.data2 + a1 = copyOrUse(v2.suffix1, 0, WIDTH) + depth = 2 + offset = WIDTH - v2.len1 + setLen(v2.length0 + offset) + a2 = new Arr2(WIDTH) + a2(0) = v2.prefix1 + System.arraycopy(d2, 0, a2, 1, d2.length) + a2(d2.length+1) = a1 + case 5 => + val v3 = v.asInstanceOf[Vector3[_]] + val d3 = v3.data3 + val s2 = v3.suffix2 + a1 = copyOrUse(v3.suffix1, 0, WIDTH) + depth = 3 + offset = WIDTH2 - v3.len12 + setLen(v3.length0 + offset) + a3 = new Arr3(WIDTH) + a3(0) = copyPrepend(v3.prefix1, v3.prefix2) + System.arraycopy(d3, 0, a3, 1, d3.length) + a2 = copyOf(s2, WIDTH) + a3(d3.length+1) = a2 + a2(s2.length) = a1 + case 7 => + val v4 = v.asInstanceOf[Vector4[_]] + val d4 = v4.data4 + val s3 = v4.suffix3 + val s2 = v4.suffix2 + a1 = copyOrUse(v4.suffix1, 0, WIDTH) + depth = 4 + offset = WIDTH3 - v4.len123 + setLen(v4.length0 + offset) + a4 = new Arr4(WIDTH) + a4(0) = copyPrepend(copyPrepend(v4.prefix1, v4.prefix2), v4.prefix3) + System.arraycopy(d4, 0, a4, 1, d4.length) + a3 = copyOf(s3, WIDTH) + a2 = copyOf(s2, WIDTH) + a4(d4.length+1) = a3 + a3(s3.length) = a2 + a2(s2.length) = a1 + case 9 => + val v5 = v.asInstanceOf[Vector5[_]] + val d5 = v5.data5 + val s4 = v5.suffix4 + val s3 = v5.suffix3 + val s2 = v5.suffix2 + a1 = copyOrUse(v5.suffix1, 0, WIDTH) + depth = 5 + offset = WIDTH4 - v5.len1234 + setLen(v5.length0 + offset) + a5 = new Arr5(WIDTH) + a5(0) = copyPrepend(copyPrepend(copyPrepend(v5.prefix1, v5.prefix2), v5.prefix3), v5.prefix4) + System.arraycopy(d5, 0, a5, 1, d5.length) + a4 = copyOf(s4, WIDTH) + a3 = copyOf(s3, WIDTH) + a2 = copyOf(s2, WIDTH) + a5(d5.length+1) = a4 + a4(s4.length) = a3 + a3(s3.length) = a2 + a2(s2.length) = a1 + case 11 => + val v6 = v.asInstanceOf[Vector6[_]] + val d6 = v6.data6 + val s5 = v6.suffix5 + val s4 = v6.suffix4 + val s3 = v6.suffix3 + val s2 = v6.suffix2 + a1 = copyOrUse(v6.suffix1, 0, WIDTH) + depth = 6 + offset = WIDTH5 - v6.len12345 + setLen(v6.length0 + offset) + a6 = new Arr6(LASTWIDTH) + a6(0) = copyPrepend(copyPrepend(copyPrepend(copyPrepend(v6.prefix1, v6.prefix2), v6.prefix3), v6.prefix4), v6.prefix5) + System.arraycopy(d6, 0, a6, 1, d6.length) + a5 = copyOf(s5, WIDTH) + a4 = copyOf(s4, WIDTH) + a3 = copyOf(s3, WIDTH) + a2 = copyOf(s2, WIDTH) + a6(d6.length+1) = a5 + a5(s5.length) = a4 + a4(s4.length) = a3 + a3(s3.length) = a2 + a2(s2.length) = a1 + } + if(len1 == 0 && lenRest > 0) { + // force advance() on next addition: + len1 = WIDTH + lenRest -= WIDTH + } + this + } + + //TODO Make public; this method is only private for binary compatibility + private[collection] def alignTo(before: Int, bigVector: Vector[A]): this.type = { + if (len1 != 0 || lenRest != 0) + throw new UnsupportedOperationException("A non-empty VectorBuilder cannot be aligned retrospectively. Please call .reset() or use a new VectorBuilder.") + val (prefixLength, maxPrefixLength) = bigVector match { + case Vector0 => (0, 1) + case v1: Vector1[_] => (0, 1) + case v2: Vector2[_] => (v2.len1, WIDTH) + case v3: Vector3[_] => (v3.len12, WIDTH2) + case v4: Vector4[_] => (v4.len123, WIDTH3) + case v5: Vector5[_] => (v5.len1234, WIDTH4) + case v6: Vector6[_] => (v6.len12345, WIDTH5) + } + if (maxPrefixLength == 1) return this // does not really make sense to align for <= 32 element-vector + val overallPrefixLength = (before + prefixLength) % maxPrefixLength + offset = (maxPrefixLength - overallPrefixLength) % maxPrefixLength + // pretend there are already `offset` elements added + advanceN(offset & ~MASK) + len1 = offset & MASK + prefixIsRightAligned = true + this + } + + /** + * Removes `offset` leading `null`s in the prefix. + * This is needed after calling `alignTo` and subsequent additions, + * directly before the result is used for creating a new Vector. + * Note that the outermost array keeps its length to keep the + * Builder re-usable. + * + * example: + * a2 = Array(null, ..., null, Array(null, .., null, 0, 1, .., x), Array(x+1, .., x+32), ...) + * becomes + * a2 = Array(Array(0, 1, .., x), Array(x+1, .., x+32), ..., ?, ..., ?) + */ + private[this] def leftAlignPrefix(): Unit = { + @inline def shrinkOffsetIfToLarge(width: Int): Unit = { + val newOffset = offset % width + lenRest -= offset - newOffset + offset = newOffset + } + var a: Array[AnyRef] = null // the array we modify + var aParent: Array[AnyRef] = null // a's parent, so aParent(0) == a + if (depth >= 6) { + a = a6.asInstanceOf[Array[AnyRef]] + val i = offset >>> BITS5 + if (i > 0) System.arraycopy(a, i, a, 0, LASTWIDTH - i) + shrinkOffsetIfToLarge(WIDTH5) + if ((lenRest >>> BITS5) == 0) depth = 5 + aParent = a + a = a(0).asInstanceOf[Array[AnyRef]] + } + if (depth >= 5) { + if (a == null) a = a5.asInstanceOf[Array[AnyRef]] + val i = (offset >>> BITS4) & MASK + if (depth == 5) { + if (i > 0) System.arraycopy(a, i, a, 0, WIDTH - i) + a5 = a.asInstanceOf[Arr5] + shrinkOffsetIfToLarge(WIDTH4) + if ((lenRest >>> BITS4) == 0) depth = 4 + } else { + if (i > 0) a = copyOfRange(a, i, WIDTH) + aParent(0) = a + } + aParent = a + a = a(0).asInstanceOf[Array[AnyRef]] + } + if (depth >= 4) { + if (a == null) a = a4.asInstanceOf[Array[AnyRef]] + val i = (offset >>> BITS3) & MASK + if (depth == 4) { + if (i > 0) System.arraycopy(a, i, a, 0, WIDTH - i) + a4 = a.asInstanceOf[Arr4] + shrinkOffsetIfToLarge(WIDTH3) + if ((lenRest >>> BITS3) == 0) depth = 3 + } else { + if (i > 0) a = copyOfRange(a, i, WIDTH) + aParent(0) = a + } + aParent = a + a = a(0).asInstanceOf[Array[AnyRef]] + } + if (depth >= 3) { + if (a == null) a = a3.asInstanceOf[Array[AnyRef]] + val i = (offset >>> BITS2) & MASK + if (depth == 3) { + if (i > 0) System.arraycopy(a, i, a, 0, WIDTH - i) + a3 = a.asInstanceOf[Arr3] + shrinkOffsetIfToLarge(WIDTH2) + if ((lenRest >>> BITS2) == 0) depth = 2 + } else { + if (i > 0) a = copyOfRange(a, i, WIDTH) + aParent(0) = a + } + aParent = a + a = a(0).asInstanceOf[Array[AnyRef]] + } + if (depth >= 2) { + if (a == null) a = a2.asInstanceOf[Array[AnyRef]] + val i = (offset >>> BITS) & MASK + if (depth == 2) { + if (i > 0) System.arraycopy(a, i, a, 0, WIDTH - i) + a2 = a.asInstanceOf[Arr2] + shrinkOffsetIfToLarge(WIDTH) + if ((lenRest >>> BITS) == 0) depth = 1 + } else { + if (i > 0) a = copyOfRange(a, i, WIDTH) + aParent(0) = a + } + aParent = a + a = a(0).asInstanceOf[Array[AnyRef]] + } + if (depth >= 1) { + if (a == null) a = a1.asInstanceOf[Array[AnyRef]] + val i = offset & MASK + if (depth == 1) { + if (i > 0) System.arraycopy(a, i, a, 0, WIDTH - i) + a1 = a.asInstanceOf[Arr1] + len1 -= offset + offset = 0 + } else { + if (i > 0) a = copyOfRange(a, i, WIDTH) + aParent(0) = a + } + } + prefixIsRightAligned = false + } + + def addOne(elem: A): this.type = { + if(len1 == WIDTH) advance() + a1(len1) = elem.asInstanceOf[AnyRef] + len1 += 1 + this + } + + private[this] def addArr1(data: Arr1): Unit = { + val dl = data.length + if(dl > 0) { + if(len1 == WIDTH) advance() + val copy1 = mmin(WIDTH-len1, dl) + val copy2 = dl - copy1 + System.arraycopy(data, 0, a1, len1, copy1) + len1 += copy1 + if(copy2 > 0) { + advance() + System.arraycopy(data, copy1, a1, 0, copy2) + len1 += copy2 + } + } + } + + private[this] def addArrN(slice: Array[AnyRef], dim: Int): Unit = { +// assert(dim >= 2) +// assert(lenRest % WIDTH == 0) +// assert(len1 == 0 || len1 == WIDTH) + if (slice.isEmpty) return + if (len1 == WIDTH) advance() + val sl = slice.length + (dim: @switch) match { + case 2 => + // lenRest is always a multiple of WIDTH + val copy1 = mmin(((WIDTH2 - lenRest) >>> BITS) & MASK, sl) + val copy2 = sl - copy1 + val destPos = (lenRest >>> BITS) & MASK + System.arraycopy(slice, 0, a2, destPos, copy1) + advanceN(WIDTH * copy1) + if (copy2 > 0) { + System.arraycopy(slice, copy1, a2, 0, copy2) + advanceN(WIDTH * copy2) + } + case 3 => + if (lenRest % WIDTH2 != 0) { + // lenRest is not multiple of WIDTH2, so this slice does not align, need to try lower dimension + slice.foreach(e => addArrN(e.asInstanceOf[Array[AnyRef]], 2)) + return + } + val copy1 = mmin(((WIDTH3 - lenRest) >>> BITS2) & MASK, sl) + val copy2 = sl - copy1 + val destPos = (lenRest >>> BITS2) & MASK + System.arraycopy(slice, 0, a3, destPos, copy1) + advanceN(WIDTH2 * copy1) + if (copy2 > 0) { + System.arraycopy(slice, copy1, a3, 0, copy2) + advanceN(WIDTH2 * copy2) + } + case 4 => + if (lenRest % WIDTH3 != 0) { + // lenRest is not multiple of WIDTH3, so this slice does not align, need to try lower dimensions + slice.foreach(e => addArrN(e.asInstanceOf[Array[AnyRef]], 3)) + return + } + val copy1 = mmin(((WIDTH4 - lenRest) >>> BITS3) & MASK, sl) + val copy2 = sl - copy1 + val destPos = (lenRest >>> BITS3) & MASK + System.arraycopy(slice, 0, a4, destPos, copy1) + advanceN(WIDTH3 * copy1) + if (copy2 > 0) { + System.arraycopy(slice, copy1, a4, 0, copy2) + advanceN(WIDTH3 * copy2) + } + case 5 => + if (lenRest % WIDTH4 != 0) { + // lenRest is not multiple of WIDTH4, so this slice does not align, need to try lower dimensions + slice.foreach(e => addArrN(e.asInstanceOf[Array[AnyRef]], 4)) + return + } + val copy1 = mmin(((WIDTH5 - lenRest) >>> BITS4) & MASK, sl) + val copy2 = sl - copy1 + val destPos = (lenRest >>> BITS4) & MASK + System.arraycopy(slice, 0, a5, destPos, copy1) + advanceN(WIDTH4 * copy1) + if (copy2 > 0) { + System.arraycopy(slice, copy1, a5, 0, copy2) + advanceN(WIDTH4 * copy2) + } + case 6 => // note width is now LASTWIDTH + if (lenRest % WIDTH5 != 0) { + // lenRest is not multiple of WIDTH5, so this slice does not align, need to try lower dimensions + slice.foreach(e => addArrN(e.asInstanceOf[Array[AnyRef]], 5)) + return + } + val copy1 = sl + // there is no copy2 because there can't be another a6 to copy to + val destPos = lenRest >>> BITS5 + if (destPos + copy1 > LASTWIDTH) + throw new IllegalArgumentException("exceeding 2^31 elements") + System.arraycopy(slice, 0, a6, destPos, copy1) + advanceN(WIDTH5 * copy1) + } + } + + private[this] def addVector(xs: Vector[A]): this.type = { + val sliceCount = xs.vectorSliceCount + var sliceIdx = 0 + while(sliceIdx < sliceCount) { + val slice = xs.vectorSlice(sliceIdx) + vectorSliceDim(sliceCount, sliceIdx) match { + case 1 => addArr1(slice.asInstanceOf[Arr1]) + case n if len1 == WIDTH || len1 == 0 => + addArrN(slice.asInstanceOf[Array[AnyRef]], n) + case n => foreachRec(n-2, slice, addArr1) + } + sliceIdx += 1 + } + this + } + + override def addAll(xs: IterableOnce[A]): this.type = xs match { + case v: Vector[_] => + if(len1 == 0 && lenRest == 0 && !prefixIsRightAligned) initFrom(v) + else addVector(v.asInstanceOf[Vector[A]]) + case _ => + super.addAll(xs) + } + + private[this] def advance(): Unit = { + val idx = lenRest + WIDTH + val xor = idx ^ lenRest + lenRest = idx + len1 = 0 + advance1(idx, xor) + } + + private[this] def advanceN(n: Int): Unit = if (n > 0) { + // assert(n % 32 == 0) + val idx = lenRest + n + val xor = idx ^ lenRest + lenRest = idx + len1 = 0 + advance1(idx, xor) + } + + private[this] def advance1(idx: Int, xor: Int): Unit = { + if (xor <= 0) { // level = 6 or something very unexpected happened + throw new IllegalArgumentException(s"advance1($idx, $xor): a1=$a1, a2=$a2, a3=$a3, a4=$a4, a5=$a5, a6=$a6, depth=$depth") + } else if (xor < WIDTH2) { // level = 1 + if (depth <= 1) { a2 = new Array(WIDTH); a2(0) = a1; depth = 2 } + a1 = new Array(WIDTH) + a2((idx >>> BITS) & MASK) = a1 + } else if (xor < WIDTH3) { // level = 2 + if (depth <= 2) { a3 = new Array(WIDTH); a3(0) = a2; depth = 3 } + a1 = new Array(WIDTH) + a2 = new Array(WIDTH) + a2((idx >>> BITS) & MASK) = a1 + a3((idx >>> BITS2) & MASK) = a2 + } else if (xor < WIDTH4) { // level = 3 + if (depth <= 3) { a4 = new Array(WIDTH); a4(0) = a3; depth = 4 } + a1 = new Array(WIDTH) + a2 = new Array(WIDTH) + a3 = new Array(WIDTH) + a2((idx >>> BITS) & MASK) = a1 + a3((idx >>> BITS2) & MASK) = a2 + a4((idx >>> BITS3) & MASK) = a3 + } else if (xor < WIDTH5) { // level = 4 + if (depth <= 4) { a5 = new Array(WIDTH); a5(0) = a4; depth = 5 } + a1 = new Array(WIDTH) + a2 = new Array(WIDTH) + a3 = new Array(WIDTH) + a4 = new Array(WIDTH) + a2((idx >>> BITS) & MASK) = a1 + a3((idx >>> BITS2) & MASK) = a2 + a4((idx >>> BITS3) & MASK) = a3 + a5((idx >>> BITS4) & MASK) = a4 + } else { // level = 5 + if (depth <= 5) { a6 = new Array(LASTWIDTH); a6(0) = a5; depth = 6 } + a1 = new Array(WIDTH) + a2 = new Array(WIDTH) + a3 = new Array(WIDTH) + a4 = new Array(WIDTH) + a5 = new Array(WIDTH) + a2((idx >>> BITS) & MASK) = a1 + a3((idx >>> BITS2) & MASK) = a2 + a4((idx >>> BITS3) & MASK) = a3 + a5((idx >>> BITS4) & MASK) = a4 + a6(idx >>> BITS5) = a5 + } + } + + def result(): Vector[A] = { + if (prefixIsRightAligned) leftAlignPrefix() + val len = len1 + lenRest + val realLen = len - offset + if(realLen == 0) Vector.empty + else if(len < 0) throw new IndexOutOfBoundsException(s"Vector cannot have negative size $len") + else if(len <= WIDTH) { + new Vector1(copyIfDifferentSize(a1, realLen)) + } else if(len <= WIDTH2) { + val i1 = (len-1) & MASK + val i2 = (len-1) >>> BITS + val data = copyOfRange(a2, 1, i2) + val prefix1 = a2(0) + val suffix1 = copyIfDifferentSize(a2(i2), i1+1) + new Vector2(prefix1, WIDTH-offset, data, suffix1, realLen) + } else if(len <= WIDTH3) { + val i1 = (len-1) & MASK + val i2 = ((len-1) >>> BITS) & MASK + val i3 = ((len-1) >>> BITS2) + val data = copyOfRange(a3, 1, i3) + val prefix2 = copyTail(a3(0)) + val prefix1 = a3(0)(0) + val suffix2 = copyOf(a3(i3), i2) + val suffix1 = copyIfDifferentSize(a3(i3)(i2), i1+1) + val len1 = prefix1.length + val len12 = len1 + prefix2.length*WIDTH + new Vector3(prefix1, len1, prefix2, len12, data, suffix2, suffix1, realLen) + } else if(len <= WIDTH4) { + val i1 = (len-1) & MASK + val i2 = ((len-1) >>> BITS) & MASK + val i3 = ((len-1) >>> BITS2) & MASK + val i4 = ((len-1) >>> BITS3) + val data = copyOfRange(a4, 1, i4) + val prefix3 = copyTail(a4(0)) + val prefix2 = copyTail(a4(0)(0)) + val prefix1 = a4(0)(0)(0) + val suffix3 = copyOf(a4(i4), i3) + val suffix2 = copyOf(a4(i4)(i3), i2) + val suffix1 = copyIfDifferentSize(a4(i4)(i3)(i2), i1+1) + val len1 = prefix1.length + val len12 = len1 + prefix2.length*WIDTH + val len123 = len12 + prefix3.length*WIDTH2 + new Vector4(prefix1, len1, prefix2, len12, prefix3, len123, data, suffix3, suffix2, suffix1, realLen) + } else if(len <= WIDTH5) { + val i1 = (len-1) & MASK + val i2 = ((len-1) >>> BITS) & MASK + val i3 = ((len-1) >>> BITS2) & MASK + val i4 = ((len-1) >>> BITS3) & MASK + val i5 = ((len-1) >>> BITS4) + val data = copyOfRange(a5, 1, i5) + val prefix4 = copyTail(a5(0)) + val prefix3 = copyTail(a5(0)(0)) + val prefix2 = copyTail(a5(0)(0)(0)) + val prefix1 = a5(0)(0)(0)(0) + val suffix4 = copyOf(a5(i5), i4) + val suffix3 = copyOf(a5(i5)(i4), i3) + val suffix2 = copyOf(a5(i5)(i4)(i3), i2) + val suffix1 = copyIfDifferentSize(a5(i5)(i4)(i3)(i2), i1+1) + val len1 = prefix1.length + val len12 = len1 + prefix2.length*WIDTH + val len123 = len12 + prefix3.length*WIDTH2 + val len1234 = len123 + prefix4.length*WIDTH3 + new Vector5(prefix1, len1, prefix2, len12, prefix3, len123, prefix4, len1234, data, suffix4, suffix3, suffix2, suffix1, realLen) + } else { + val i1 = (len-1) & MASK + val i2 = ((len-1) >>> BITS) & MASK + val i3 = ((len-1) >>> BITS2) & MASK + val i4 = ((len-1) >>> BITS3) & MASK + val i5 = ((len-1) >>> BITS4) & MASK + val i6 = ((len-1) >>> BITS5) + val data = copyOfRange(a6, 1, i6) + val prefix5 = copyTail(a6(0)) + val prefix4 = copyTail(a6(0)(0)) + val prefix3 = copyTail(a6(0)(0)(0)) + val prefix2 = copyTail(a6(0)(0)(0)(0)) + val prefix1 = a6(0)(0)(0)(0)(0) + val suffix5 = copyOf(a6(i6), i5) + val suffix4 = copyOf(a6(i6)(i5), i4) + val suffix3 = copyOf(a6(i6)(i5)(i4), i3) + val suffix2 = copyOf(a6(i6)(i5)(i4)(i3), i2) + val suffix1 = copyIfDifferentSize(a6(i6)(i5)(i4)(i3)(i2), i1+1) + val len1 = prefix1.length + val len12 = len1 + prefix2.length*WIDTH + val len123 = len12 + prefix3.length*WIDTH2 + val len1234 = len123 + prefix4.length*WIDTH3 + val len12345 = len1234 + prefix5.length*WIDTH4 + new Vector6(prefix1, len1, prefix2, len12, prefix3, len123, prefix4, len1234, prefix5, len12345, data, suffix5, suffix4, suffix3, suffix2, suffix1, realLen) + } + } + + override def toString: String = + s"VectorBuilder(len1=$len1, lenRest=$lenRest, offset=$offset, depth=$depth)" + + private[immutable] def getData: Array[Array[_]] = Array[Array[AnyRef]]( + a1, a2.asInstanceOf[Array[AnyRef]], a3.asInstanceOf[Array[AnyRef]], a4.asInstanceOf[Array[AnyRef]], + a5.asInstanceOf[Array[AnyRef]], a6.asInstanceOf[Array[AnyRef]] + ).asInstanceOf[Array[Array[_]]] +} + + +/** Compile-time definitions for Vector. No references to this object should appear in bytecode. */ +private[immutable] object VectorInline { + // compile-time numeric constants + final val BITS = 5 + final val WIDTH = 1 << BITS + final val MASK = WIDTH - 1 + final val BITS2 = BITS * 2 + final val WIDTH2 = 1 << BITS2 + final val BITS3 = BITS * 3 + final val WIDTH3 = 1 << BITS3 + final val BITS4 = BITS * 4 + final val WIDTH4 = 1 << BITS4 + final val BITS5 = BITS * 5 + final val WIDTH5 = 1 << BITS5 + final val LASTWIDTH = WIDTH << 1 // 1 extra bit in the last level to go up to Int.MaxValue (2^31-1) instead of 2^30: + final val Log2ConcatFaster = 5 + final val AlignToFaster = 64 + + type Arr1 = Array[AnyRef] + type Arr2 = Array[Array[AnyRef]] + type Arr3 = Array[Array[Array[AnyRef]]] + type Arr4 = Array[Array[Array[Array[AnyRef]]]] + type Arr5 = Array[Array[Array[Array[Array[AnyRef]]]]] + type Arr6 = Array[Array[Array[Array[Array[Array[AnyRef]]]]]] + + /** Dimension of the slice at index */ + @inline def vectorSliceDim(count: Int, idx: Int): Int = { + val c = count/2 + c+1-abs(idx-c) + } + + @inline def copyOrUse[T <: AnyRef](a: Array[T], start: Int, end: Int): Array[T] = + if(start == 0 && end == a.length) a else copyOfRange[T](a, start, end) + + @inline final def copyTail[T <: AnyRef](a: Array[T]): Array[T] = copyOfRange[T](a, 1, a.length) + + @inline final def copyInit[T <: AnyRef](a: Array[T]): Array[T] = copyOfRange[T](a, 0, a.length-1) + + @inline final def copyIfDifferentSize[T <: AnyRef](a: Array[T], len: Int): Array[T] = + if(a.length == len) a else copyOf[T](a, len) + + @inline final def wrap1(x: Any ): Arr1 = { val a = new Arr1(1); a(0) = x.asInstanceOf[AnyRef]; a } + @inline final def wrap2(x: Arr1): Arr2 = { val a = new Arr2(1); a(0) = x; a } + @inline final def wrap3(x: Arr2): Arr3 = { val a = new Arr3(1); a(0) = x; a } + @inline final def wrap4(x: Arr3): Arr4 = { val a = new Arr4(1); a(0) = x; a } + @inline final def wrap5(x: Arr4): Arr5 = { val a = new Arr5(1); a(0) = x; a } + + @inline final def copyUpdate(a1: Arr1, idx1: Int, elem: Any): Arr1 = { + val a1c = a1.clone() + a1c(idx1) = elem.asInstanceOf[AnyRef] + a1c + } + + @inline final def copyUpdate(a2: Arr2, idx2: Int, idx1: Int, elem: Any): Arr2 = { + val a2c = a2.clone() + a2c(idx2) = copyUpdate(a2c(idx2), idx1, elem) + a2c + } + + @inline final def copyUpdate(a3: Arr3, idx3: Int, idx2: Int, idx1: Int, elem: Any): Arr3 = { + val a3c = a3.clone() + a3c(idx3) = copyUpdate(a3c(idx3), idx2, idx1, elem) + a3c + } + + @inline final def copyUpdate(a4: Arr4, idx4: Int, idx3: Int, idx2: Int, idx1: Int, elem: Any): Arr4 = { + val a4c = a4.clone() + a4c(idx4) = copyUpdate(a4c(idx4), idx3, idx2, idx1, elem) + a4c + } + + @inline final def copyUpdate(a5: Arr5, idx5: Int, idx4: Int, idx3: Int, idx2: Int, idx1: Int, elem: Any): Arr5 = { + val a5c = a5.clone() + a5c(idx5) = copyUpdate(a5c(idx5), idx4, idx3, idx2, idx1, elem) + a5c + } + + @inline final def copyUpdate(a6: Arr6, idx6: Int, idx5: Int, idx4: Int, idx3: Int, idx2: Int, idx1: Int, elem: Any): Arr6 = { + val a6c = a6.clone() + a6c(idx6) = copyUpdate(a6c(idx6), idx5, idx4, idx3, idx2, idx1, elem) + a6c + } + + @inline final def concatArrays[T <: AnyRef](a: Array[T], b: Array[T]): Array[T] = { + val dest = copyOf[T](a, a.length+b.length) + System.arraycopy(b, 0, dest, a.length, b.length) + dest + } +} + + +/** Helper methods and constants for Vector. */ +private object VectorStatics { + + final def copyAppend1(a: Arr1, elem: Any): Arr1 = { + val alen = a.length + val ac = new Arr1(alen+1) + System.arraycopy(a, 0, ac, 0, alen) + ac(alen) = elem.asInstanceOf[AnyRef] + ac + } + + final def copyAppend[T <: AnyRef](a: Array[T], elem: T): Array[T] = { + val ac = copyOf(a, a.length+1) + ac(ac.length-1) = elem + ac + } + + final def copyPrepend1(elem: Any, a: Arr1): Arr1 = { + val ac = new Arr1(a.length+1) + System.arraycopy(a, 0, ac, 1, a.length) + ac(0) = elem.asInstanceOf[AnyRef] + ac + } + + final def copyPrepend[T <: AnyRef](elem: T, a: Array[T]): Array[T] = { + val ac = java.lang.reflect.Array.newInstance(a.getClass.getComponentType, a.length+1).asInstanceOf[Array[T]] + System.arraycopy(a, 0, ac, 1, a.length) + ac(0) = elem + ac + } + + final val empty1: Arr1 = new Array(0) + final val empty2: Arr2 = new Array(0) + final val empty3: Arr3 = new Array(0) + final val empty4: Arr4 = new Array(0) + final val empty5: Arr5 = new Array(0) + final val empty6: Arr6 = new Array(0) + + final def foreachRec[T <: AnyRef, A, U](level: Int, a: Array[T], f: A => U): Unit = { + var i = 0 + val len = a.length + if(level == 0) { + while(i < len) { + f(a(i).asInstanceOf[A]) + i += 1 + } + } else { + val l = level-1 + while(i < len) { + foreachRec(l, a(i).asInstanceOf[Array[AnyRef]], f) + i += 1 + } + } + } + + final def mapElems1[A, B](a: Arr1, f: A => B): Arr1 = { + var i = 0 + while(i < a.length) { + val v1 = a(i).asInstanceOf[AnyRef] + val v2 = f(v1.asInstanceOf[A]).asInstanceOf[AnyRef] + if(v1 ne v2) + return mapElems1Rest(a, f, i, v2) + i += 1 + } + a + } + + final def mapElems1Rest[A, B](a: Arr1, f: A => B, at: Int, v2: AnyRef): Arr1 = { + val ac = new Arr1(a.length) + if(at > 0) System.arraycopy(a, 0, ac, 0, at) + ac(at) = v2 + var i = at+1 + while(i < a.length) { + ac(i) = f(a(i).asInstanceOf[A]).asInstanceOf[AnyRef] + i += 1 + } + ac + } + + final def mapElems[A, B, T <: AnyRef](n: Int, a: Array[T], f: A => B): Array[T] = { + if(n == 1) + mapElems1[A, B](a.asInstanceOf[Arr1], f).asInstanceOf[Array[T]] + else { + var i = 0 + while(i < a.length) { + val v1 = a(i) + val v2 = mapElems(n-1, v1.asInstanceOf[Array[AnyRef]], f) + if(v1 ne v2) + return mapElemsRest(n, a, f, i, v2) + i += 1 + } + a + } + } + + final def mapElemsRest[A, B, T <: AnyRef](n: Int, a: Array[T], f: A => B, at: Int, v2: AnyRef): Array[T] = { + val ac = java.lang.reflect.Array.newInstance(a.getClass.getComponentType, a.length).asInstanceOf[Array[AnyRef]] + if(at > 0) System.arraycopy(a, 0, ac, 0, at) + ac(at) = v2 + var i = at+1 + while(i < a.length) { + ac(i) = mapElems(n-1, a(i).asInstanceOf[Array[AnyRef]], f) + i += 1 + } + ac.asInstanceOf[Array[T]] + } + + final def prepend1IfSpace(prefix1: Arr1, xs: IterableOnce[_]): Arr1 = xs match { + case it: Iterable[_] => + if(it.sizeCompare(WIDTH-prefix1.length) <= 0) { + it.size match { + case 0 => null + case 1 => copyPrepend(it.head.asInstanceOf[AnyRef], prefix1) + case s => + val prefix1b = new Arr1(prefix1.length + s) + System.arraycopy(prefix1, 0, prefix1b, s, prefix1.length) + @annotation.unused val copied = it.copyToArray(prefix1b.asInstanceOf[Array[Any]], 0) + //assert(copied == s) + prefix1b + } + } else null + case it => + val s = it.knownSize + if(s > 0 && s <= WIDTH-prefix1.length) { + val prefix1b = new Arr1(prefix1.length + s) + System.arraycopy(prefix1, 0, prefix1b, s, prefix1.length) + @annotation.unused val copied = it.iterator.copyToArray(prefix1b.asInstanceOf[Array[Any]], 0) + //assert(copied == s) + prefix1b + } else null + } + + final def append1IfSpace(suffix1: Arr1, xs: IterableOnce[_]): Arr1 = xs match { + case it: Iterable[_] => + if(it.sizeCompare(WIDTH-suffix1.length) <= 0) { + it.size match { + case 0 => null + case 1 => copyAppend(suffix1, it.head.asInstanceOf[AnyRef]) + case s => + val suffix1b = copyOf(suffix1, suffix1.length + s) + @annotation.unused val copied = it.copyToArray(suffix1b.asInstanceOf[Array[Any]], suffix1.length) + //assert(copied == s) + suffix1b + } + } else null + case it => + val s = it.knownSize + if(s > 0 && s <= WIDTH-suffix1.length) { + val suffix1b = copyOf(suffix1, suffix1.length + s) + @annotation.unused val copied = it.iterator.copyToArray(suffix1b.asInstanceOf[Array[Any]], suffix1.length) + //assert(copied == s) + suffix1b + } else null + } +} + + +private final class NewVectorIterator[A](v: Vector[A], private[this] var totalLength: Int, private[this] val sliceCount: Int) extends AbstractIterator[A] with java.lang.Cloneable { + + private[this] var a1: Arr1 = v.prefix1 + private[this] var a2: Arr2 = _ + private[this] var a3: Arr3 = _ + private[this] var a4: Arr4 = _ + private[this] var a5: Arr5 = _ + private[this] var a6: Arr6 = _ + private[this] var a1len = a1.length + private[this] var i1 = 0 // current index in a1 + private[this] var oldPos = 0 + private[this] var len1 = totalLength // remaining length relative to a1 + + private[this] var sliceIdx = 0 + private[this] var sliceDim = 1 + private[this] var sliceStart = 0 // absolute position + private[this] var sliceEnd = a1len // absolute position + + //override def toString: String = + // s"NewVectorIterator(v=$v, totalLength=$totalLength, sliceCount=$sliceCount): a1len=$a1len, len1=$len1, i1=$i1, sliceEnd=$sliceEnd" + + @inline override def knownSize = len1 - i1 + + @inline def hasNext: Boolean = len1 > i1 + + def next(): A = { + if(i1 == a1len) advance() + val r = a1(i1) + i1 += 1 + r.asInstanceOf[A] + } + + private[this] def advanceSlice(): Unit = { + if(!hasNext) Iterator.empty.next() + sliceIdx += 1 + var slice: Array[_ <: AnyRef] = v.vectorSlice(sliceIdx) + while(slice.length == 0) { + sliceIdx += 1 + slice = v.vectorSlice(sliceIdx) + } + sliceStart = sliceEnd + sliceDim = vectorSliceDim(sliceCount, sliceIdx) + (sliceDim: @switch) match { + case 1 => a1 = slice.asInstanceOf[Arr1] + case 2 => a2 = slice.asInstanceOf[Arr2] + case 3 => a3 = slice.asInstanceOf[Arr3] + case 4 => a4 = slice.asInstanceOf[Arr4] + case 5 => a5 = slice.asInstanceOf[Arr5] + case 6 => a6 = slice.asInstanceOf[Arr6] + } + sliceEnd = sliceStart + slice.length * (1 << (BITS*(sliceDim-1))) + if(sliceEnd > totalLength) sliceEnd = totalLength + if(sliceDim > 1) oldPos = (1 << (BITS*sliceDim))-1 + } + + private[this] def advance(): Unit = { + val pos = i1-len1+totalLength + if(pos == sliceEnd) advanceSlice() + if(sliceDim > 1) { + val io = pos - sliceStart + val xor = oldPos ^ io + advanceA(io, xor) + oldPos = io + } + len1 -= i1 + a1len = mmin(a1.length, len1) + i1 = 0 + } + + private[this] def advanceA(io: Int, xor: Int): Unit = { + if(xor < WIDTH2) { + a1 = a2((io >>> BITS) & MASK) + } else if(xor < WIDTH3) { + a2 = a3((io >>> BITS2) & MASK) + a1 = a2(0) + } else if(xor < WIDTH4) { + a3 = a4((io >>> BITS3) & MASK) + a2 = a3(0) + a1 = a2(0) + } else if(xor < WIDTH5) { + a4 = a5((io >>> BITS4) & MASK) + a3 = a4(0) + a2 = a3(0) + a1 = a2(0) + } else { + a5 = a6(io >>> BITS5) + a4 = a5(0) + a3 = a4(0) + a2 = a3(0) + a1 = a2(0) + } + } + + private[this] def setA(io: Int, xor: Int): Unit = { + if(xor < WIDTH2) { + a1 = a2((io >>> BITS) & MASK) + } else if(xor < WIDTH3) { + a2 = a3((io >>> BITS2) & MASK) + a1 = a2((io >>> BITS) & MASK) + } else if(xor < WIDTH4) { + a3 = a4((io >>> BITS3) & MASK) + a2 = a3((io >>> BITS2) & MASK) + a1 = a2((io >>> BITS) & MASK) + } else if(xor < WIDTH5) { + a4 = a5((io >>> BITS4) & MASK) + a3 = a4((io >>> BITS3) & MASK) + a2 = a3((io >>> BITS2) & MASK) + a1 = a2((io >>> BITS) & MASK) + } else { + a5 = a6(io >>> BITS5) + a4 = a5((io >>> BITS4) & MASK) + a3 = a4((io >>> BITS3) & MASK) + a2 = a3((io >>> BITS2) & MASK) + a1 = a2((io >>> BITS) & MASK) + } + } + + override def drop(n: Int): Iterator[A] = { + if(n > 0) { + val oldpos = i1-len1+totalLength + val newpos = mmin(oldpos + n, totalLength) + if(newpos == totalLength) { + i1 = 0 + len1 = 0 + a1len = 0 + } else { + while(newpos >= sliceEnd) advanceSlice() + val io = newpos - sliceStart + if(sliceDim > 1) { + val xor = oldPos ^ io + setA(io, xor) + oldPos = io + } + a1len = a1.length + i1 = io & MASK + len1 = i1 + (totalLength-newpos) + if(a1len > len1) a1len = len1 + } + } + this + } + + override def take(n: Int): Iterator[A] = { + if(n < knownSize) { + val trunc = knownSize - mmax(0, n) + totalLength -= trunc + len1 -= trunc + if(len1 < a1len) a1len = len1 + if(totalLength < sliceEnd) sliceEnd = totalLength + } + this + } + + override def slice(from: Int, until: Int): Iterator[A] = { + val _until = mmax(until, 0) + + val n = + if(from > 0) { + drop(from) + _until - from + } else _until + take(n) + } + + override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = { + val xsLen = xs.length + val total = IterableOnce.elemsToCopyToArray(knownSize, xsLen, start, len) + var copied = 0 + val isBoxed = xs.isInstanceOf[Array[AnyRef]] + while(copied < total) { + if(i1 == a1len) advance() + val count = mmin(total-copied, a1.length-i1) + if(isBoxed) System.arraycopy(a1, i1, xs, start+copied, count) + else Array.copy(a1, i1, xs, start+copied, count) + i1 += count + copied += count + } + total + } + + override def toVector: Vector[A] = + v.slice(i1-len1+totalLength, totalLength) + + protected[immutable] def split(at: Int): NewVectorIterator[A] = { + val it2 = clone().asInstanceOf[NewVectorIterator[A]] + it2.take(at) + drop(at) + it2 + } +} + + +private abstract class VectorStepperBase[A, Sub >: Null <: Stepper[A], Semi <: Sub](it: NewVectorIterator[A]) + extends Stepper[A] with EfficientSplit { + + protected[this] def build(it: NewVectorIterator[A]): Semi + + final def hasStep: Boolean = it.hasNext + + final def characteristics: Int = Spliterator.ORDERED + Spliterator.SIZED + Spliterator.SUBSIZED + + final def estimateSize: Long = it.knownSize + + def trySplit(): Sub = { + val len = it.knownSize + if(len > 1) build(it.split(len >>> 1)) + else null + } + + override final def iterator: Iterator[A] = it +} + +private class AnyVectorStepper[A](it: NewVectorIterator[A]) + extends VectorStepperBase[A, AnyStepper[A], AnyVectorStepper[A]](it) with AnyStepper[A] { + protected[this] def build(it: NewVectorIterator[A]) = new AnyVectorStepper(it) + def nextStep(): A = it.next() +} + +private class DoubleVectorStepper(it: NewVectorIterator[Double]) + extends VectorStepperBase[Double, DoubleStepper, DoubleVectorStepper](it) with DoubleStepper { + protected[this] def build(it: NewVectorIterator[Double]) = new DoubleVectorStepper(it) + def nextStep(): Double = it.next() +} + +private class IntVectorStepper(it: NewVectorIterator[Int]) + extends VectorStepperBase[Int, IntStepper, IntVectorStepper](it) with IntStepper { + protected[this] def build(it: NewVectorIterator[Int]) = new IntVectorStepper(it) + def nextStep(): Int = it.next() +} + +private class LongVectorStepper(it: NewVectorIterator[Long]) + extends VectorStepperBase[Long, LongStepper, LongVectorStepper](it) with LongStepper { + protected[this] def build(it: NewVectorIterator[Long]) = new LongVectorStepper(it) + def nextStep(): Long = it.next() +} + + +// The following definitions are needed for binary compatibility with ParVector +private[collection] class VectorIterator[+A](_startIndex: Int, private[this] var endIndex: Int) extends AbstractIterator[A] { + private[immutable] var it: NewVectorIterator[A @uncheckedVariance] = _ + def hasNext: Boolean = it.hasNext + def next(): A = it.next() + private[collection] def remainingElementCount: Int = it.size + private[collection] def remainingVector: Vector[A] = it.toVector +} diff --git a/library-internal/src/scala/jdk/Accumulator.scala b/library-internal/src/scala/jdk/Accumulator.scala new file mode 100644 index 000000000000..48450c989007 --- /dev/null +++ b/library-internal/src/scala/jdk/Accumulator.scala @@ -0,0 +1,404 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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.jdk + +import java.{lang => jl} + +import scala.collection.Stepper.EfficientSplit +import scala.collection.{Stepper, StepperShape, mutable} +import scala.language.implicitConversions + +/** Accumulators are mutable sequences with two distinct features: + * - An accumulator can be appended efficiently to another + * - There are manually specialized Accumulators for `Int`, `Long` and `Double` that don't box + * the elements + * + * These two features make Accumulators a good candidate to collect the results of a parallel Java + * stream pipeline into a Scala collection. The + * [[scala.collection.convert.StreamExtensions.StreamHasToScala.toScala]] extension method on Java + * streams (available by importing + * [[scala.jdk.StreamConverters `scala.jdk.StreamConverters._`]]) is specialized for + * Accumulators: they are built in parallel, the parts are merged efficiently. + * + * Building specialized Accumulators is handled transparently. As a user, using the + * [[Accumulator]] object as a factory automatically creates an [[IntAccumulator]], + * [[LongAccumulator]], [[DoubleAccumulator]] or [[AnyAccumulator]] depending on the element type. + * + * Note: to run the example, start the Scala REPL with `scala -Yrepl-class-based` to avoid + * deadlocks, see [[https://github.com/scala/bug/issues/9076]]. + * + * {{{ + * scala> import scala.jdk.StreamConverters._ + * import scala.jdk.StreamConverters._ + * + * scala> def isPrime(n: Int): Boolean = !(2 +: (3 to Math.sqrt(n).toInt by 2) exists (n % _ == 0)) + * isPrime: (n: Int)Boolean + * + * scala> val intAcc = (1 to 10000).asJavaParStream.filter(isPrime).toScala(scala.jdk.Accumulator) + * intAcc: scala.jdk.IntAccumulator = IntAccumulator(1, 3, 5, 7, 11, 13, 17, 19, ... + * + * scala> val stringAcc = (1 to 100).asJavaParStream.mapToObj("<>" * _).toScala(Accumulator) + * stringAcc: scala.jdk.AnyAccumulator[String] = AnyAccumulator(<>, <><>, <><><>, ... + * }}} + * + * There are two possibilities to process elements of a primitive Accumulator without boxing: + * specialized operations of the Accumulator, or the Stepper interface. The most common collection + * operations are overloaded or overridden in the primitive Accumulator classes, for example + * [[IntAccumulator.map(f:Int=>Int)* IntAccumulator.map]] or [[IntAccumulator.exists]]. + * Thanks to Scala's function specialization, + * `intAcc.exists(x => testOn(x))` does not incur boxing. + * + * The [[scala.collection.Stepper]] interface provides iterator-like `hasStep` and `nextStep` methods, and is + * specialized for `Int`, `Long` and `Double`. The `intAccumulator.stepper` method creates an + * [[scala.collection.IntStepper]] that yields the elements of the accumulator without boxing. + * + * Accumulators can hold more than `Int.MaxValue` elements. They have a [[sizeLong]] method that + * returns the size as a `Long`. Note that certain operations defined in [[scala.collection.Seq]] + * are implemented using [[length]], so they will not work correctly for large accumulators. + * + * The [[Accumulator]] class is a base class to share code between [[AnyAccumulator]] (for + * reference types) and the manual specializations [[IntAccumulator]], [[LongAccumulator]] and + * [[DoubleAccumulator]]. + */ +abstract class Accumulator[@specialized(Double, Int, Long) A, +CC[X] <: mutable.Seq[X], +C <: mutable.Seq[A]] + extends mutable.Seq[A] + with mutable.Builder[A, C] { + + /** + * Implementation Details + * + * Every subclass has two arrays + * - `current: Array[A]` + * - `history: Array[Array[A]]` + * + * Elements are added to `current` at [[index]] until it's full, then `current` is added to `history` at [[hIndex]]. + * [[nextBlockSize]] defines the size of the next `current`. See also [[cumulative]]. + */ + private[jdk] var index: Int = 0 + private[jdk] var hIndex: Int = 0 + private[jdk] var totalSize: Long = 0L + + /** + * The total number of elements stored in the history up to `history(i)` (where `0 <= i < hIndex`). + * This method is constant-time, the cumulative lengths are stored. + * - [[AnyAccumulator]] keeps a separate array to store the cumulative lengths. + * - [[LongAccumulator]] and [[DoubleAccumulator]] store the cumulative length at the last slot in every + * array in the history. Every array is allocated with 1 extra slot for this purpose. [[DoubleAccumulator]] + * converts the length to double for storing and back to long, which is correct for lengths that fit in the + * double's 52 fraction bits (so any collection that fits in memory). + * - [[IntAccumulator]] uses the last two slots in every array to store the cumulative length, every array is + * allocated with 1 extra slot. So `history(0)` has 17 slots of which the first 15 store elements. + */ + private[jdk] def cumulative(i: Int): Long + + private[jdk] def nextBlockSize: Int = { + if (totalSize < 32) 16 + else if (totalSize <= Int.MaxValue) { + val bit = 64 - jl.Long.numberOfLeadingZeros(totalSize) + 1 << (bit - (bit >> 2)) + } + else 1 << 24 + } + + protected def efficientStepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit + + final override def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit = + efficientStepper(shape) + + final override def length: Int = + if (sizeLong < Int.MaxValue) sizeLong.toInt + else throw new IllegalArgumentException(s"Size too large for an Int: $sizeLong") + + final override def knownSize: Int = if (sizeLong < Int.MaxValue) size else -1 + + /** Size of the accumulated collection, as a `Long` */ + final def sizeLong: Long = totalSize + + /** Remove all accumulated elements from this accumulator. */ + def clear(): Unit = { + index = 0 + hIndex = 0 + totalSize = 0L + } + + private[jdk] def seekSlot(ix: Long): Long = { + var lo = -1 + var hi = hIndex + while (lo + 1 < hi) { + val m = (lo + hi) >>> 1 // Shift allows division-as-unsigned, prevents overflow + if (cumulative(m) > ix) hi = m + else lo = m + } + (hi.toLong << 32) | (if (hi==0) ix else ix - cumulative(hi-1)).toInt + } +} + +/** Contains factory methods to build Accumulators. + * + * Note that the `Accumulator` object itself is not a factory, but it is implicitly convert to + * a factory according to the element type, see [[Accumulator.toFactory]]. + * + * This allows passing the `Accumulator` object as argument when a [[collection.Factory]], and + * the implicit [[Accumulator.AccumulatorFactoryShape]] instance is used to build a specialized + * Accumulator according to the element type: + * + * {{{ + * scala> val intAcc = Accumulator(1,2,3) + * intAcc: scala.collection.convert.IntAccumulator = IntAccumulator(1, 2, 3) + * + * scala> val anyAccc = Accumulator("K") + * anyAccc: scala.collection.convert.AnyAccumulator[String] = AnyAccumulator(K) + * + * scala> val intAcc2 = List(1,2,3).to(Accumulator) + * intAcc2: scala.jdk.IntAccumulator = IntAccumulator(1, 2, 3) + * + * scala> val anyAcc2 = List("K").to(Accumulator) + * anyAcc2: scala.jdk.AnyAccumulator[String] = AnyAccumulator(K) + * }}} + * + * @define coll Accumulator + * @define Coll `Accumulator` + */ +object Accumulator { + implicit def toFactory[A, C](sa: Accumulator.type)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): collection.Factory[A, C] = canAccumulate.factory + + /** Creates a target $coll from an existing source collection + * + * @param source Source collection + * @tparam A the type of the ${coll}’s elements + * @tparam C the (inferred) specific type of the $coll + * @return a new $coll with the elements of `source` + */ + def from[A, C](source: IterableOnce[A])(implicit canAccumulate: AccumulatorFactoryShape[A, C]): C = + source.iterator.to(canAccumulate.factory) + + /** An empty collection + * @tparam A the type of the ${coll}'s elements + */ + def empty[A, C](implicit canAccumulate: AccumulatorFactoryShape[A, C]): C = + canAccumulate.empty + + /** Creates an $coll with the specified elements. + * @tparam A the type of the ${coll}'s elements + * @tparam C the (inferred) specific type of the $coll + * @param elems the elements of the created $coll + * @return a new $coll with elements `elems` + */ + def apply[A, C](elems: A*)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): C = + canAccumulate.factory.fromSpecific(elems) + + /** Produces an $coll containing repeated applications of a function to a start value. + * + * @param start the start value of the $coll + * @param len the number of elements contained in the $coll + * @param f the function that's repeatedly applied + * @return an $coll with `len` values in the sequence `start, f(start), f(f(start)), ...` + */ + def iterate[A, C](start: A, len: Int)(f: A => A)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): C = + from(new collection.View.Iterate(start, len)(f)) + + /** Produces an $coll that uses a function `f` to produce elements of type `A` + * and update an internal state of type `S`. + * + * @param init State initial value + * @param f Computes the next element (or returns `None` to signal + * the end of the collection) + * @tparam A Type of the elements + * @tparam S Type of the internal state + * @tparam C Type (usually inferred) of the $coll + * @return an $coll that produces elements using `f` until `f` returns `None` + */ + def unfold[A, S, C](init: S)(f: S => Option[(A, S)])(implicit canAccumulate: AccumulatorFactoryShape[A, C]): C = + from(new collection.View.Unfold(init)(f)) + + /** Produces an $coll containing a sequence of increasing of integers. + * + * @param start the first element of the $coll + * @param end the end value of the $coll (the first value NOT contained) + * @return an $coll with values `start, start + 1, ..., end - 1` + */ + def range[A: Integral, C](start: A, end: A)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): C = + from(collection.immutable.NumericRange(start, end, implicitly[Integral[A]].one)) + + /** Produces an $coll containing equally spaced values in some integer interval. + * @param start the start value of the $coll + * @param end the end value of the $coll (the first value NOT contained) + * @param step the difference between successive elements of the $coll (must be positive or negative) + * @return an $coll with values `start, start + step, ...` up to, but excluding `end` + */ + def range[A: Integral, C](start: A, end: A, step: A)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): C = + from(collection.immutable.NumericRange(start, end, step)) + + /** + * @return A builder for $Coll objects. + * @tparam A the type of the ${coll}’s elements + * @tparam C the specific type of the $coll + */ + def newBuilder[A, C](implicit canAccumulate: AccumulatorFactoryShape[A, C]): collection.mutable.Builder[A, C] = + canAccumulate.factory.newBuilder + + /** Produces an $coll containing the results of some element computation a number of times. + * @param n the number of elements contained in the $coll. + * @param elem the element computation + * @return An $coll that contains the results of `n` evaluations of `elem`. + */ + def fill[A, C](n: Int)(elem: => A)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): C = + from(new collection.View.Fill(n)(elem)) + + /** Produces a two-dimensional $coll containing the results of some element computation a number of times. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param elem the element computation + * @return An $coll that contains the results of `n1 x n2` evaluations of `elem`. + */ + def fill[A, C](n1: Int, n2: Int)(elem: => A)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): AnyAccumulator[C] = + fill(n1)(fill(n2)(elem)(canAccumulate))(AccumulatorFactoryShape.anyAccumulatorFactoryShape[C]) + + /** Produces a three-dimensional $coll containing the results of some element computation a number of times. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3rd dimension + * @param elem the element computation + * @return An $coll that contains the results of `n1 x n2 x n3` evaluations of `elem`. + */ + def fill[A, C](n1: Int, n2: Int, n3: Int)(elem: => A)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): AnyAccumulator[AnyAccumulator[C]] = + fill(n1)(fill(n2, n3)(elem)(canAccumulate))(AccumulatorFactoryShape.anyAccumulatorFactoryShape[AnyAccumulator[C]]) + + /** Produces a four-dimensional $coll containing the results of some element computation a number of times. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3rd dimension + * @param n4 the number of elements in the 4th dimension + * @param elem the element computation + * @return An $coll that contains the results of `n1 x n2 x n3 x n4` evaluations of `elem`. + */ + def fill[A, C](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => A)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): AnyAccumulator[AnyAccumulator[AnyAccumulator[C]]] = + fill(n1)(fill(n2, n3, n4)(elem)(canAccumulate))(AccumulatorFactoryShape.anyAccumulatorFactoryShape[AnyAccumulator[AnyAccumulator[C]]]) + + /** Produces a five-dimensional $coll containing the results of some element computation a number of times. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3rd dimension + * @param n4 the number of elements in the 4th dimension + * @param n5 the number of elements in the 5th dimension + * @param elem the element computation + * @return An $coll that contains the results of `n1 x n2 x n3 x n4 x n5` evaluations of `elem`. + */ + def fill[A, C](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => A)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): AnyAccumulator[AnyAccumulator[AnyAccumulator[AnyAccumulator[C]]]] = + fill(n1)(fill(n2, n3, n4, n5)(elem)(canAccumulate))(AccumulatorFactoryShape.anyAccumulatorFactoryShape[AnyAccumulator[AnyAccumulator[AnyAccumulator[C]]]]) + + /** Produces an $coll containing values of a given function over a range of integer values starting from 0. + * @param n The number of elements in the $coll + * @param f The function computing element values + * @return An $coll consisting of elements `f(0), ..., f(n -1)` + */ + def tabulate[A, C](n: Int)(f: Int => A)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): C = + from(new collection.View.Tabulate(n)(f)) + + /** Produces a two-dimensional $coll containing values of a given function over ranges of integer values starting from 0. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param f The function computing element values + * @return An $coll consisting of elements `f(i1, i2)` + * for `0 <= i1 < n1` and `0 <= i2 < n2`. + */ + def tabulate[A, C](n1: Int, n2: Int)(f: (Int, Int) => A)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): AnyAccumulator[C] = + tabulate(n1)(i1 => tabulate(n2)(f(i1, _))(canAccumulate))(AccumulatorFactoryShape.anyAccumulatorFactoryShape[C]) + + /** Produces a three-dimensional $coll containing values of a given function over ranges of integer values starting from 0. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3rd dimension + * @param f The function computing element values + * @return An $coll consisting of elements `f(i1, i2, i3)` + * for `0 <= i1 < n1`, `0 <= i2 < n2`, and `0 <= i3 < n3`. + */ + def tabulate[A, C](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => A)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): AnyAccumulator[AnyAccumulator[C]] = + tabulate(n1)(i1 => tabulate(n2, n3)(f(i1, _, _))(canAccumulate))(AccumulatorFactoryShape.anyAccumulatorFactoryShape[AnyAccumulator[C]]) + + /** Produces a four-dimensional $coll containing values of a given function over ranges of integer values starting from 0. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3rd dimension + * @param n4 the number of elements in the 4th dimension + * @param f The function computing element values + * @return An $coll consisting of elements `f(i1, i2, i3, i4)` + * for `0 <= i1 < n1`, `0 <= i2 < n2`, `0 <= i3 < n3`, and `0 <= i4 < n4`. + */ + def tabulate[A, C](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => A)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): AnyAccumulator[AnyAccumulator[AnyAccumulator[C]]] = + tabulate(n1)(i1 => tabulate(n2, n3, n4)(f(i1, _, _, _))(canAccumulate))(AccumulatorFactoryShape.anyAccumulatorFactoryShape[AnyAccumulator[AnyAccumulator[C]]]) + + /** Produces a five-dimensional $coll containing values of a given function over ranges of integer values starting from 0. + * @param n1 the number of elements in the 1st dimension + * @param n2 the number of elements in the 2nd dimension + * @param n3 the number of elements in the 3rd dimension + * @param n4 the number of elements in the 4th dimension + * @param n5 the number of elements in the 5th dimension + * @param f The function computing element values + * @return An $coll consisting of elements `f(i1, i2, i3, i4, i5)` + * for `0 <= i1 < n1`, `0 <= i2 < n2`, `0 <= i3 < n3`, `0 <= i4 < n4`, and `0 <= i5 < n5`. + */ + def tabulate[A, C](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(f: (Int, Int, Int, Int, Int) => A)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): AnyAccumulator[AnyAccumulator[AnyAccumulator[AnyAccumulator[C]]]] = + tabulate(n1)(i1 => tabulate(n2, n3, n4, n5)(f(i1, _, _, _, _))(canAccumulate))(AccumulatorFactoryShape.anyAccumulatorFactoryShape[AnyAccumulator[AnyAccumulator[AnyAccumulator[C]]]]) + + /** Concatenates all argument collections into a single $coll. + * + * @param xss the collections that are to be concatenated. + * @return the concatenation of all the collections. + */ + def concat[A, C](xss: Iterable[A]*)(implicit canAccumulate: AccumulatorFactoryShape[A, C]): C = + if (xss.isEmpty) canAccumulate.empty + else { + val b = canAccumulate.factory.newBuilder + xss.foreach(b ++= _) + b.result() + } + + /** An implicit `AccumulatorFactoryShape` is used in Accumulator factory method to return + * specialized variants according to the element type. + */ + sealed trait AccumulatorFactoryShape[A, C] { + def factory: collection.Factory[A, C] + def empty: C + } + + object AccumulatorFactoryShape extends LowPriorityAccumulatorFactoryShape { + implicit val doubleAccumulatorFactoryShape: AccumulatorFactoryShape[Double, DoubleAccumulator] = new AccumulatorFactoryShape[Double, DoubleAccumulator] { + def factory: collection.Factory[Double, DoubleAccumulator] = DoubleAccumulator + def empty: DoubleAccumulator = DoubleAccumulator.empty + } + + implicit val intAccumulatorFactoryShape: AccumulatorFactoryShape[Int, IntAccumulator] = new AccumulatorFactoryShape[Int, IntAccumulator] { + def factory: collection.Factory[Int, IntAccumulator] = IntAccumulator + def empty: IntAccumulator = IntAccumulator.empty + } + + implicit val longAccumulatorFactoryShape: AccumulatorFactoryShape[Long, LongAccumulator] = new AccumulatorFactoryShape[Long, LongAccumulator] { + def factory: collection.Factory[Long, LongAccumulator] = LongAccumulator + def empty: LongAccumulator = LongAccumulator.empty + } + + implicit val jDoubleAccumulatorFactoryShape: AccumulatorFactoryShape[jl.Double, DoubleAccumulator] = doubleAccumulatorFactoryShape.asInstanceOf[AccumulatorFactoryShape[jl.Double, DoubleAccumulator]] + implicit val jIntegerAccumulatorFactoryShape: AccumulatorFactoryShape[jl.Integer, IntAccumulator] = intAccumulatorFactoryShape.asInstanceOf[AccumulatorFactoryShape[jl.Integer, IntAccumulator]] + implicit val jLongAccumulatorFactoryShape: AccumulatorFactoryShape[jl.Long, LongAccumulator] = longAccumulatorFactoryShape.asInstanceOf[AccumulatorFactoryShape[jl.Long, LongAccumulator]] + } + + sealed trait LowPriorityAccumulatorFactoryShape { + implicit def anyAccumulatorFactoryShape[A]: AccumulatorFactoryShape[A, AnyAccumulator[A]] = anyAccumulatorFactoryShapePrototype.asInstanceOf[AccumulatorFactoryShape[A, AnyAccumulator[A]]] + + private val anyAccumulatorFactoryShapePrototype = new AccumulatorFactoryShape[AnyRef, AnyAccumulator[AnyRef]] { + def factory: collection.Factory[AnyRef, AnyAccumulator[AnyRef]] = collection.IterableFactory.toFactory(AnyAccumulator) + def empty: AnyAccumulator[AnyRef] = AnyAccumulator.empty[AnyRef] + } + } +} \ No newline at end of file diff --git a/library-internal/src/scala/jdk/DoubleAccumulator.scala b/library-internal/src/scala/jdk/DoubleAccumulator.scala new file mode 100644 index 000000000000..dfdb2feba9ea --- /dev/null +++ b/library-internal/src/scala/jdk/DoubleAccumulator.scala @@ -0,0 +1,488 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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.jdk + +import java.io.{ObjectInputStream, ObjectOutputStream} +import java.util.Spliterator +import java.util.function.{Consumer, DoubleConsumer} +import java.{lang => jl} + +import scala.annotation._ +import scala.collection.Stepper.EfficientSplit +import scala.collection.{AnyStepper, DoubleStepper, Factory, SeqFactory, Stepper, StepperShape, mutable} +import scala.language.implicitConversions + +/** A specialized Accumulator that holds `Double`s without boxing, see [[Accumulator]]. */ +final class DoubleAccumulator + extends Accumulator[Double, AnyAccumulator, DoubleAccumulator] + with mutable.SeqOps[Double, AnyAccumulator, DoubleAccumulator] + with Serializable { + private[jdk] var current: Array[Double] = DoubleAccumulator.emptyDoubleArray + private[jdk] var history: Array[Array[Double]] = DoubleAccumulator.emptyDoubleArrayArray + + private[jdk] def cumulative(i: Int) = { val x = history(i); x(x.length-1).toLong } + + override protected[this] def className: String = "DoubleAccumulator" + + def efficientStepper[S <: Stepper[_]](implicit shape: StepperShape[Double, S]): S with EfficientSplit = { + val st = new DoubleAccumulatorStepper(this) + val r = + if (shape.shape == StepperShape.DoubleShape) st + else { + assert(shape.shape == StepperShape.ReferenceShape, s"unexpected StepperShape: $shape") + AnyStepper.ofParDoubleStepper(st) + } + r.asInstanceOf[S with EfficientSplit] + } + + private def expand(): Unit = { + if (index > 0) { + current(current.length-1) = (if (hIndex > 0) { val x = history(hIndex-1); x(x.length-1) } else 0) + index + if (hIndex >= history.length) hExpand() + history(hIndex) = current + hIndex += 1 + } + current = new Array[Double](nextBlockSize+1) + index = 0 + } + + private def hExpand(): Unit = { + if (hIndex == 0) history = new Array[Array[Double]](4) + else history = java.util.Arrays.copyOf(history, history.length << 1) + } + + /** Appends an element to this `DoubleAccumulator`. */ + def addOne(a: Double): this.type = { + totalSize += 1 + if (index+1 >= current.length) expand() + current(index) = a + index += 1 + this + } + + /** Result collection consisting of all elements appended so far. */ + override def result(): DoubleAccumulator = this + + /** Removes all elements from `that` and appends them to this `DoubleAccumulator`. */ + def drain(that: DoubleAccumulator): Unit = { + var h = 0 + var prev = 0L + var more = true + while (more && h < that.hIndex) { + val cuml = that.cumulative(h) + val n = (cuml - prev).toInt + if (current.length - index - 1 >= n) { + System.arraycopy(that.history(h), 0, current, index, n) + prev = cuml + index += n + h += 1 + } + else more = false + } + if (h >= that.hIndex && current.length - index - 1>= that.index) { + if (that.index > 0) System.arraycopy(that.current, 0, current, index, that.index) + index += that.index + } + else { + val slots = (if (index > 0) 1 else 0) + that.hIndex - h + if (hIndex + slots > history.length) { + val n = math.max(4, 1 << (32 - jl.Integer.numberOfLeadingZeros(1 + hIndex + slots))) + history = java.util.Arrays.copyOf(history, n) + } + var pv = if (hIndex > 0) cumulative(hIndex-1) else 0L + if (index > 0) { + val x = + if (index < (current.length >>> 3) && current.length - 1 > 32) { + val ans = java.util.Arrays.copyOf(current, index + 1) + ans(ans.length - 1) = current(current.length - 1) + ans + } + else current + pv = pv + index + x(x.length - 1) = pv.toDouble // see comment on Accumulator.cumulative + history(hIndex) = x + hIndex += 1 + } + while (h < that.hIndex) { + val cuml = that.cumulative(h) + pv = pv + cuml - prev + prev = cuml + val x = that.history(h) + x(x.length - 1) = pv.toDouble // see comment on Accumulator.cumulative + history(hIndex) = x + h += 1 + hIndex += 1 + } + index = that.index + current = that.current + } + totalSize += that.totalSize + that.clear() + } + + override def clear(): Unit = { + super.clear() + current = DoubleAccumulator.emptyDoubleArray + history = DoubleAccumulator.emptyDoubleArrayArray + } + + /** Retrieves the `ix`th element. */ + def apply(ix: Long): Double = { + if (totalSize - ix <= index || hIndex == 0) current((ix - (totalSize - index)).toInt) + else { + val w = seekSlot(ix) + history((w >>> 32).toInt)((w & 0xFFFFFFFFL).toInt) + } + } + + /** Retrieves the `ix`th element, using an `Int` index. */ + def apply(i: Int): Double = apply(i.toLong) + + def update(idx: Long, elem: Double): Unit = { + if (totalSize - idx <= index || hIndex == 0) current((idx - (totalSize - index)).toInt) = elem + else { + val w = seekSlot(idx) + history((w >>> 32).toInt)((w & 0xFFFFFFFFL).toInt) = elem + } + } + + def update(idx: Int, elem: Double): Unit = update(idx.toLong, elem) + + /** Returns an `Iterator` over the contents of this `DoubleAccumulator`. The `Iterator` is not specialized. */ + def iterator: Iterator[Double] = stepper.iterator + + override def foreach[U](f: Double => U): Unit = { + val s = stepper + while (s.hasStep) f(s.nextStep()) + } + + def map(f: Double => Double): DoubleAccumulator = { + val b = newSpecificBuilder + val s = stepper + while (s.hasStep) + b.addOne(f(s.nextStep())) + b.result() + } + + def flatMap(f: Double => IterableOnce[Double]): DoubleAccumulator = { + val b = newSpecificBuilder + val s = stepper + while (s.hasStep) + b.addAll(f(s.nextStep())) + b.result() + } + + def collect(pf: PartialFunction[Double, Double]): DoubleAccumulator = { + val b = newSpecificBuilder + val s = stepper + while (s.hasStep) { + val n = s.nextStep() + pf.runWith(b.addOne)(n) + } + b.result() + } + + private def filterAccImpl(pred: Double => Boolean, not: Boolean): DoubleAccumulator = { + val b = newSpecificBuilder + val s = stepper + while (s.hasStep) { + val n = s.nextStep() + if (pred(n) != not) b.addOne(n) + } + b.result() + } + + override def filter(pred: Double => Boolean): DoubleAccumulator = filterAccImpl(pred, not = false) + + override def filterNot(pred: Double => Boolean): DoubleAccumulator = filterAccImpl(pred, not = true) + + override def forall(p: Double => Boolean): Boolean = { + val s = stepper + while (s.hasStep) + if (!p(s.nextStep())) return false + true + } + + override def exists(p: Double => Boolean): Boolean = { + val s = stepper + while (s.hasStep) + if (p(s.nextStep())) return true + false + } + + override def count(p: Double => Boolean): Int = { + var r = 0 + val s = stepper + while (s.hasStep) + if (p(s.nextStep())) r += 1 + r + } + + def countLong(p: Double => Boolean): Long = { + var r = 0L + val s = stepper + while (s.hasStep) + if (p(s.nextStep())) r += 1 + r + } + + /** Copies the elements in this `DoubleAccumulator` into an `Array[Double]` */ + @nowarn // cat=lint-overload see toArray[B: ClassTag] + def toArray: Array[Double] = { + if (totalSize > Int.MaxValue) throw new IllegalArgumentException("Too many elements accumulated for an array: "+totalSize.toString) + val a = new Array[Double](totalSize.toInt) + var j = 0 + var h = 0 + var pv = 0L + while (h < hIndex) { + val x = history(h) + val cuml = x(x.length-1).toLong + val n = (cuml - pv).toInt + pv = cuml + System.arraycopy(x, 0, a, j, n) + j += n + h += 1 + } + System.arraycopy(current, 0, a, j, index) + j += index + a + } + + /** Copies the elements in this `DoubleAccumulator` to a `List` */ + override def toList: List[Double] = { + var ans: List[Double] = Nil + var i = index - 1 + while (i >= 0) { + ans = current(i) :: ans + i -= 1 + } + var h = hIndex - 1 + while (h >= 0) { + val a = history(h) + i = (cumulative(h) - (if (h == 0) 0L else cumulative(h-1))).toInt - 1 + while (i >= 0) { + ans = a(i) :: ans + i -= 1 + } + h -= 1 + } + ans + } + + /** + * Copy the elements in this `DoubleAccumulator` to a specified collection. + * Note that the target collection is not specialized. + * Usage example: `acc.to(Vector)` + */ + override def to[C1](factory: Factory[Double, C1]): C1 = { + if (totalSize > Int.MaxValue) throw new IllegalArgumentException("Too many elements accumulated for a Scala collection: "+totalSize.toString) + factory.fromSpecific(iterator) + } + + override protected def fromSpecific(coll: IterableOnce[Double]): DoubleAccumulator = DoubleAccumulator.fromSpecific(coll) + override protected def newSpecificBuilder: DoubleAccumulator = DoubleAccumulator.newBuilder + override def iterableFactory: SeqFactory[AnyAccumulator] = AnyAccumulator + + override def empty: DoubleAccumulator = DoubleAccumulator.empty + + private def writeReplace(): AnyRef = new DoubleAccumulator.SerializationProxy(this) +} + +object DoubleAccumulator extends collection.SpecificIterableFactory[Double, DoubleAccumulator] { + private val emptyDoubleArray = new Array[Double](0) + private val emptyDoubleArrayArray = new Array[Array[Double]](0) + + implicit def toJavaDoubleAccumulator(ia: DoubleAccumulator.type): collection.SpecificIterableFactory[jl.Double, DoubleAccumulator] = DoubleAccumulator.asInstanceOf[collection.SpecificIterableFactory[jl.Double, DoubleAccumulator]] + + import java.util.{function => jf} + + /** A `Supplier` of `DoubleAccumulator`s, suitable for use with `java.util.stream.DoubleStream`'s `collect` method. Suitable for `Stream[Double]` also. */ + def supplier: jf.Supplier[DoubleAccumulator] = () => new DoubleAccumulator + + /** A `BiConsumer` that adds an element to an `DoubleAccumulator`, suitable for use with `java.util.stream.DoubleStream`'s `collect` method. */ + def adder: jf.ObjDoubleConsumer[DoubleAccumulator] = (ac: DoubleAccumulator, a: Double) => ac addOne a + + /** A `BiConsumer` that adds a boxed `Double` to an `DoubleAccumulator`, suitable for use with `java.util.stream.Stream`'s `collect` method. */ + def boxedAdder: jf.BiConsumer[DoubleAccumulator, Double] = (ac: DoubleAccumulator, a: Double) => ac addOne a + + /** A `BiConsumer` that merges `DoubleAccumulator`s, suitable for use with `java.util.stream.DoubleStream`'s `collect` method. Suitable for `Stream[Double]` also. */ + def merger: jf.BiConsumer[DoubleAccumulator, DoubleAccumulator] = (a1: DoubleAccumulator, a2: DoubleAccumulator) => a1 drain a2 + + private def fromArray(a: Array[Double]): DoubleAccumulator = { + val r = new DoubleAccumulator + var i = 0 + while (i < a.length) { r addOne a(i); i += 1 } + r + } + + override def fromSpecific(it: IterableOnce[Double]): DoubleAccumulator = it match { + case acc: DoubleAccumulator => acc + case as: collection.immutable.ArraySeq.ofDouble => fromArray(as.unsafeArray) + case as: collection.mutable.ArraySeq.ofDouble => fromArray(as.array) // this case ensures Array(1).to(Accumulator) doesn't box + case _ => (new DoubleAccumulator).addAll(it) + } + + override def empty: DoubleAccumulator = new DoubleAccumulator + + override def newBuilder: DoubleAccumulator = new DoubleAccumulator + + class SerializationProxy[A](@transient private val acc: DoubleAccumulator) extends Serializable { + @transient private var result: DoubleAccumulator = _ + + private def writeObject(out: ObjectOutputStream): Unit = { + out.defaultWriteObject() + val size = acc.sizeLong + out.writeLong(size) + val st = acc.stepper + while (st.hasStep) + out.writeDouble(st.nextStep()) + } + + private def readObject(in: ObjectInputStream): Unit = { + in.defaultReadObject() + val res = new DoubleAccumulator() + var elems = in.readLong() + while (elems > 0) { + res += in.readDouble() + elems -= 1L + } + result = res + } + + private def readResolve(): AnyRef = result + } +} + +private[jdk] class DoubleAccumulatorStepper(private val acc: DoubleAccumulator) extends DoubleStepper with EfficientSplit { + import java.util.Spliterator._ + + private var h: Int = 0 + private var i: Int = 0 + private var a: Array[Double] = if (acc.hIndex > 0) acc.history(0) else acc.current + private var n: Long = if (acc.hIndex > 0) acc.cumulative(0) else acc.index + private var N: Long = acc.totalSize + + private def duplicateSelf(limit: Long): DoubleAccumulatorStepper = { + val ans = new DoubleAccumulatorStepper(acc) + ans.h = h + ans.i = i + ans.a = a + ans.n = n + ans.N = limit + ans + } + + private def loadMore(): Unit = { + h += 1 + if (h < acc.hIndex) { a = acc.history(h); n = acc.cumulative(h) - acc.cumulative(h-1) } + else { a = acc.current; n = acc.index } + i = 0 + } + + def characteristics: Int = ORDERED | SIZED | SUBSIZED | NONNULL + + def estimateSize: Long = N + + def hasStep: Boolean = N > 0 + + def nextStep(): Double = + if (n <= 0) throw new NoSuchElementException("next on empty Stepper") + else { + if (i >= n) loadMore() + val ans = a(i) + i += 1 + N -= 1 + ans + } + + def trySplit(): DoubleStepper = + if (N <= 1) null + else { + val half = N >> 1 + val M = (if (h <= 0) 0L else acc.cumulative(h-1)) + i + val R = M + half + val ans = duplicateSelf(half) + if (h < acc.hIndex) { + val w = acc.seekSlot(R) + h = (w >>> 32).toInt + if (h < acc.hIndex) { + a = acc.history(h) + n = acc.cumulative(h) - (if (h > 0) acc.cumulative(h-1) else 0) + } + else { + a = acc.current + n = acc.index + } + i = (w & 0xFFFFFFFFL).toInt + } + else i += half.toInt + N -= half + ans + } + + override def spliterator[B >: Double]: Spliterator.OfDouble = new DoubleStepper.DoubleStepperSpliterator(this) { + // Overridden for efficiency + override def tryAdvance(c: DoubleConsumer): Boolean = + if (N <= 0) false + else { + if (i >= n) loadMore() + c.accept(a(i)) + i += 1 + N -= 1 + true + } + + // Overridden for efficiency + override def tryAdvance(c: Consumer[_ >: jl.Double]): Boolean = (c: AnyRef) match { + case ic: DoubleConsumer => tryAdvance(ic) + case _ => + if (N <= 0) false + else { + if (i >= n) loadMore() + c.accept(a(i)) + i += 1 + N -= 1 + true + } + } + + // Overridden for efficiency + override def forEachRemaining(c: DoubleConsumer): Unit = + while (N > 0) { + if (i >= n) loadMore() + val i0 = i + if ((n-i) > N) n = i + N.toInt + while (i < n) { + c.accept(a(i)) + i += 1 + } + N -= (n - i0) + } + + // Overridden for efficiency + override def forEachRemaining(c: Consumer[_ >: jl.Double]): Unit = (c: AnyRef) match { + case ic: DoubleConsumer => forEachRemaining(ic) + case _ => + while (N > 0) { + if (i >= n) loadMore() + val i0 = i + if ((n-i) > N) n = i + N.toInt + while (i < n) { + c.accept(a(i)) + i += 1 + } + N -= (n - i0) + } + } + } +} diff --git a/library-internal/src/scala/jdk/FunctionWrappers.scala b/library-internal/src/scala/jdk/FunctionWrappers.scala new file mode 100644 index 000000000000..27153ffed820 --- /dev/null +++ b/library-internal/src/scala/jdk/FunctionWrappers.scala @@ -0,0 +1,1090 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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. + */ + +// GENERATED CODE: DO NOT EDIT. + + +package scala.jdk + +object FunctionWrappers { + case class FromJavaBiConsumer[T, U](jf: java.util.function.BiConsumer[T, U]) extends scala.Function2[T, U, Unit] { + def apply(x1: T, x2: U) = jf.accept(x1, x2) + } + + class RichBiConsumerAsFunction2[T, U](private val underlying: java.util.function.BiConsumer[T, U]) extends AnyVal { + @inline def asScala: scala.Function2[T, U, Unit] = underlying match { + case AsJavaBiConsumer((sf @ _)) => sf.asInstanceOf[scala.Function2[T, U, Unit]] + case _ => new FromJavaBiConsumer[T, U](underlying) + } + } + + case class AsJavaBiConsumer[T, U](sf: scala.Function2[T, U, Unit]) extends java.util.function.BiConsumer[T, U] { + def accept(x1: T, x2: U) = sf.apply(x1, x2) + } + + class RichFunction2AsBiConsumer[T, U](private val underlying: scala.Function2[T, U, Unit]) extends AnyVal { + @inline def asJava: java.util.function.BiConsumer[T, U] = underlying match { + case FromJavaBiConsumer((jf @ _)) => jf.asInstanceOf[java.util.function.BiConsumer[T, U]] + case _ => new AsJavaBiConsumer[T, U](underlying) + }; + @inline def asJavaBiConsumer: java.util.function.BiConsumer[T, U] = underlying match { + case FromJavaBiConsumer((sf @ _)) => sf.asInstanceOf[java.util.function.BiConsumer[T, U]] + case _ => new AsJavaBiConsumer[T, U](underlying) + } + } + + + case class FromJavaBiFunction[T, U, R](jf: java.util.function.BiFunction[T, U, R]) extends scala.Function2[T, U, R] { + def apply(x1: T, x2: U) = jf.apply(x1, x2) + } + + class RichBiFunctionAsFunction2[T, U, R](private val underlying: java.util.function.BiFunction[T, U, R]) extends AnyVal { + @inline def asScala: scala.Function2[T, U, R] = underlying match { + case AsJavaBiFunction((sf @ _)) => sf.asInstanceOf[scala.Function2[T, U, R]] + case _ => new FromJavaBiFunction[T, U, R](underlying) + } + } + + case class AsJavaBiFunction[T, U, R](sf: scala.Function2[T, U, R]) extends java.util.function.BiFunction[T, U, R] { + def apply(x1: T, x2: U) = sf.apply(x1, x2) + } + + class RichFunction2AsBiFunction[T, U, R](private val underlying: scala.Function2[T, U, R]) extends AnyVal { + @inline def asJava: java.util.function.BiFunction[T, U, R] = underlying match { + case FromJavaBiFunction((jf @ _)) => jf.asInstanceOf[java.util.function.BiFunction[T, U, R]] + case _ => new AsJavaBiFunction[T, U, R](underlying) + }; + @inline def asJavaBiFunction: java.util.function.BiFunction[T, U, R] = underlying match { + case FromJavaBiFunction((sf @ _)) => sf.asInstanceOf[java.util.function.BiFunction[T, U, R]] + case _ => new AsJavaBiFunction[T, U, R](underlying) + } + } + + + case class FromJavaBiPredicate[T, U](jf: java.util.function.BiPredicate[T, U]) extends scala.Function2[T, U, Boolean] { + def apply(x1: T, x2: U) = jf.test(x1, x2) + } + + class RichBiPredicateAsFunction2[T, U](private val underlying: java.util.function.BiPredicate[T, U]) extends AnyVal { + @inline def asScala: scala.Function2[T, U, Boolean] = underlying match { + case AsJavaBiPredicate((sf @ _)) => sf.asInstanceOf[scala.Function2[T, U, Boolean]] + case _ => new FromJavaBiPredicate[T, U](underlying) + } + } + + case class AsJavaBiPredicate[T, U](sf: scala.Function2[T, U, Boolean]) extends java.util.function.BiPredicate[T, U] { + def test(x1: T, x2: U) = sf.apply(x1, x2) + } + + class RichFunction2AsBiPredicate[T, U](private val underlying: scala.Function2[T, U, Boolean]) extends AnyVal { + @inline def asJava: java.util.function.BiPredicate[T, U] = underlying match { + case FromJavaBiPredicate((jf @ _)) => jf.asInstanceOf[java.util.function.BiPredicate[T, U]] + case _ => new AsJavaBiPredicate[T, U](underlying) + }; + @inline def asJavaBiPredicate: java.util.function.BiPredicate[T, U] = underlying match { + case FromJavaBiPredicate((sf @ _)) => sf.asInstanceOf[java.util.function.BiPredicate[T, U]] + case _ => new AsJavaBiPredicate[T, U](underlying) + } + } + + + case class FromJavaBinaryOperator[T](jf: java.util.function.BinaryOperator[T]) extends scala.Function2[T, T, T] { + def apply(x1: T, x2: T) = jf.apply(x1, x2) + } + + class RichBinaryOperatorAsFunction2[T](private val underlying: java.util.function.BinaryOperator[T]) extends AnyVal { + @inline def asScala: scala.Function2[T, T, T] = underlying match { + case AsJavaBinaryOperator((sf @ _)) => sf.asInstanceOf[scala.Function2[T, T, T]] + case _ => new FromJavaBinaryOperator[T](underlying) + } + } + + case class AsJavaBinaryOperator[T](sf: scala.Function2[T, T, T]) extends java.util.function.BinaryOperator[T] { + def apply(x1: T, x2: T) = sf.apply(x1, x2) + } + + class RichFunction2AsBinaryOperator[T](private val underlying: scala.Function2[T, T, T]) extends AnyVal { + @inline def asJava: java.util.function.BinaryOperator[T] = underlying match { + case FromJavaBinaryOperator((jf @ _)) => jf.asInstanceOf[java.util.function.BinaryOperator[T]] + case _ => new AsJavaBinaryOperator[T](underlying) + }; + @inline def asJavaBinaryOperator: java.util.function.BinaryOperator[T] = underlying match { + case FromJavaBinaryOperator((sf @ _)) => sf.asInstanceOf[java.util.function.BinaryOperator[T]] + case _ => new AsJavaBinaryOperator[T](underlying) + } + } + + + case class FromJavaBooleanSupplier(jf: java.util.function.BooleanSupplier) extends scala.Function0[Boolean] { + def apply() = jf.getAsBoolean() + } + + class RichBooleanSupplierAsFunction0(private val underlying: java.util.function.BooleanSupplier) extends AnyVal { + @inline def asScala: scala.Function0[Boolean] = underlying match { + case AsJavaBooleanSupplier((sf @ _)) => sf.asInstanceOf[scala.Function0[Boolean]] + case _ => new FromJavaBooleanSupplier(underlying) + } + } + + case class AsJavaBooleanSupplier(sf: scala.Function0[Boolean]) extends java.util.function.BooleanSupplier { + def getAsBoolean() = sf.apply() + } + + class RichFunction0AsBooleanSupplier(private val underlying: scala.Function0[Boolean]) extends AnyVal { + @inline def asJava: java.util.function.BooleanSupplier = underlying match { + case FromJavaBooleanSupplier((jf @ _)) => jf.asInstanceOf[java.util.function.BooleanSupplier] + case _ => new AsJavaBooleanSupplier(underlying) + } + } + + + case class FromJavaConsumer[T](jf: java.util.function.Consumer[T]) extends scala.Function1[T, Unit] { + def apply(x1: T) = jf.accept(x1) + } + + class RichConsumerAsFunction1[T](private val underlying: java.util.function.Consumer[T]) extends AnyVal { + @inline def asScala: scala.Function1[T, Unit] = underlying match { + case AsJavaConsumer((sf @ _)) => sf.asInstanceOf[scala.Function1[T, Unit]] + case _ => new FromJavaConsumer[T](underlying) + } + } + + case class AsJavaConsumer[T](sf: scala.Function1[T, Unit]) extends java.util.function.Consumer[T] { + def accept(x1: T) = sf.apply(x1) + } + + class RichFunction1AsConsumer[T](private val underlying: scala.Function1[T, Unit]) extends AnyVal { + @inline def asJava: java.util.function.Consumer[T] = underlying match { + case FromJavaConsumer((jf @ _)) => jf.asInstanceOf[java.util.function.Consumer[T]] + case _ => new AsJavaConsumer[T](underlying) + }; + @inline def asJavaConsumer: java.util.function.Consumer[T] = underlying match { + case FromJavaConsumer((sf @ _)) => sf.asInstanceOf[java.util.function.Consumer[T]] + case _ => new AsJavaConsumer[T](underlying) + } + } + + + case class FromJavaDoubleBinaryOperator(jf: java.util.function.DoubleBinaryOperator) extends scala.Function2[Double, Double, Double] { + def apply(x1: scala.Double, x2: scala.Double) = jf.applyAsDouble(x1, x2) + } + + class RichDoubleBinaryOperatorAsFunction2(private val underlying: java.util.function.DoubleBinaryOperator) extends AnyVal { + @inline def asScala: scala.Function2[Double, Double, Double] = underlying match { + case AsJavaDoubleBinaryOperator((sf @ _)) => sf.asInstanceOf[scala.Function2[Double, Double, Double]] + case _ => new FromJavaDoubleBinaryOperator(underlying) + } + } + + case class AsJavaDoubleBinaryOperator(sf: scala.Function2[Double, Double, Double]) extends java.util.function.DoubleBinaryOperator { + def applyAsDouble(x1: scala.Double, x2: scala.Double) = sf.apply(x1, x2) + } + + class RichFunction2AsDoubleBinaryOperator(private val underlying: scala.Function2[Double, Double, Double]) extends AnyVal { + @inline def asJava: java.util.function.DoubleBinaryOperator = underlying match { + case FromJavaDoubleBinaryOperator((jf @ _)) => jf.asInstanceOf[java.util.function.DoubleBinaryOperator] + case _ => new AsJavaDoubleBinaryOperator(underlying) + } + } + + + case class FromJavaDoubleConsumer(jf: java.util.function.DoubleConsumer) extends scala.Function1[Double, Unit] { + def apply(x1: scala.Double) = jf.accept(x1) + } + + class RichDoubleConsumerAsFunction1(private val underlying: java.util.function.DoubleConsumer) extends AnyVal { + @inline def asScala: scala.Function1[Double, Unit] = underlying match { + case AsJavaDoubleConsumer((sf @ _)) => sf.asInstanceOf[scala.Function1[Double, Unit]] + case _ => new FromJavaDoubleConsumer(underlying) + } + } + + case class AsJavaDoubleConsumer(sf: scala.Function1[Double, Unit]) extends java.util.function.DoubleConsumer { + def accept(x1: scala.Double) = sf.apply(x1) + } + + class RichFunction1AsDoubleConsumer(private val underlying: scala.Function1[Double, Unit]) extends AnyVal { + @inline def asJava: java.util.function.DoubleConsumer = underlying match { + case FromJavaDoubleConsumer((jf @ _)) => jf.asInstanceOf[java.util.function.DoubleConsumer] + case _ => new AsJavaDoubleConsumer(underlying) + } + } + + + case class FromJavaDoubleFunction[R](jf: java.util.function.DoubleFunction[R]) extends scala.Function1[Double, R] { + def apply(x1: scala.Double) = jf.apply(x1) + } + + class RichDoubleFunctionAsFunction1[R](private val underlying: java.util.function.DoubleFunction[R]) extends AnyVal { + @inline def asScala: scala.Function1[Double, R] = underlying match { + case AsJavaDoubleFunction((sf @ _)) => sf.asInstanceOf[scala.Function1[Double, R]] + case _ => new FromJavaDoubleFunction[R](underlying) + } + } + + case class AsJavaDoubleFunction[R](sf: scala.Function1[Double, R]) extends java.util.function.DoubleFunction[R] { + def apply(x1: scala.Double) = sf.apply(x1) + } + + class RichFunction1AsDoubleFunction[R](private val underlying: scala.Function1[Double, R]) extends AnyVal { + @inline def asJava: java.util.function.DoubleFunction[R] = underlying match { + case FromJavaDoubleFunction((jf @ _)) => jf.asInstanceOf[java.util.function.DoubleFunction[R]] + case _ => new AsJavaDoubleFunction[R](underlying) + }; + @inline def asJavaDoubleFunction: java.util.function.DoubleFunction[R] = underlying match { + case FromJavaDoubleFunction((sf @ _)) => sf.asInstanceOf[java.util.function.DoubleFunction[R]] + case _ => new AsJavaDoubleFunction[R](underlying) + } + } + + + case class FromJavaDoublePredicate(jf: java.util.function.DoublePredicate) extends scala.Function1[Double, Boolean] { + def apply(x1: scala.Double) = jf.test(x1) + } + + class RichDoublePredicateAsFunction1(private val underlying: java.util.function.DoublePredicate) extends AnyVal { + @inline def asScala: scala.Function1[Double, Boolean] = underlying match { + case AsJavaDoublePredicate((sf @ _)) => sf.asInstanceOf[scala.Function1[Double, Boolean]] + case _ => new FromJavaDoublePredicate(underlying) + } + } + + case class AsJavaDoublePredicate(sf: scala.Function1[Double, Boolean]) extends java.util.function.DoublePredicate { + def test(x1: scala.Double) = sf.apply(x1) + } + + class RichFunction1AsDoublePredicate(private val underlying: scala.Function1[Double, Boolean]) extends AnyVal { + @inline def asJava: java.util.function.DoublePredicate = underlying match { + case FromJavaDoublePredicate((jf @ _)) => jf.asInstanceOf[java.util.function.DoublePredicate] + case _ => new AsJavaDoublePredicate(underlying) + } + } + + + case class FromJavaDoubleSupplier(jf: java.util.function.DoubleSupplier) extends scala.Function0[Double] { + def apply() = jf.getAsDouble() + } + + class RichDoubleSupplierAsFunction0(private val underlying: java.util.function.DoubleSupplier) extends AnyVal { + @inline def asScala: scala.Function0[Double] = underlying match { + case AsJavaDoubleSupplier((sf @ _)) => sf.asInstanceOf[scala.Function0[Double]] + case _ => new FromJavaDoubleSupplier(underlying) + } + } + + case class AsJavaDoubleSupplier(sf: scala.Function0[Double]) extends java.util.function.DoubleSupplier { + def getAsDouble() = sf.apply() + } + + class RichFunction0AsDoubleSupplier(private val underlying: scala.Function0[Double]) extends AnyVal { + @inline def asJava: java.util.function.DoubleSupplier = underlying match { + case FromJavaDoubleSupplier((jf @ _)) => jf.asInstanceOf[java.util.function.DoubleSupplier] + case _ => new AsJavaDoubleSupplier(underlying) + } + } + + + case class FromJavaDoubleToIntFunction(jf: java.util.function.DoubleToIntFunction) extends scala.Function1[Double, Int] { + def apply(x1: scala.Double) = jf.applyAsInt(x1) + } + + class RichDoubleToIntFunctionAsFunction1(private val underlying: java.util.function.DoubleToIntFunction) extends AnyVal { + @inline def asScala: scala.Function1[Double, Int] = underlying match { + case AsJavaDoubleToIntFunction((sf @ _)) => sf.asInstanceOf[scala.Function1[Double, Int]] + case _ => new FromJavaDoubleToIntFunction(underlying) + } + } + + case class AsJavaDoubleToIntFunction(sf: scala.Function1[Double, Int]) extends java.util.function.DoubleToIntFunction { + def applyAsInt(x1: scala.Double) = sf.apply(x1) + } + + class RichFunction1AsDoubleToIntFunction(private val underlying: scala.Function1[Double, Int]) extends AnyVal { + @inline def asJava: java.util.function.DoubleToIntFunction = underlying match { + case FromJavaDoubleToIntFunction((jf @ _)) => jf.asInstanceOf[java.util.function.DoubleToIntFunction] + case _ => new AsJavaDoubleToIntFunction(underlying) + } + } + + + case class FromJavaDoubleToLongFunction(jf: java.util.function.DoubleToLongFunction) extends scala.Function1[Double, Long] { + def apply(x1: scala.Double) = jf.applyAsLong(x1) + } + + class RichDoubleToLongFunctionAsFunction1(private val underlying: java.util.function.DoubleToLongFunction) extends AnyVal { + @inline def asScala: scala.Function1[Double, Long] = underlying match { + case AsJavaDoubleToLongFunction((sf @ _)) => sf.asInstanceOf[scala.Function1[Double, Long]] + case _ => new FromJavaDoubleToLongFunction(underlying) + } + } + + case class AsJavaDoubleToLongFunction(sf: scala.Function1[Double, Long]) extends java.util.function.DoubleToLongFunction { + def applyAsLong(x1: scala.Double) = sf.apply(x1) + } + + class RichFunction1AsDoubleToLongFunction(private val underlying: scala.Function1[Double, Long]) extends AnyVal { + @inline def asJava: java.util.function.DoubleToLongFunction = underlying match { + case FromJavaDoubleToLongFunction((jf @ _)) => jf.asInstanceOf[java.util.function.DoubleToLongFunction] + case _ => new AsJavaDoubleToLongFunction(underlying) + } + } + + + case class FromJavaDoubleUnaryOperator(jf: java.util.function.DoubleUnaryOperator) extends scala.Function1[Double, Double] { + def apply(x1: scala.Double) = jf.applyAsDouble(x1) + } + + class RichDoubleUnaryOperatorAsFunction1(private val underlying: java.util.function.DoubleUnaryOperator) extends AnyVal { + @inline def asScala: scala.Function1[Double, Double] = underlying match { + case AsJavaDoubleUnaryOperator((sf @ _)) => sf.asInstanceOf[scala.Function1[Double, Double]] + case _ => new FromJavaDoubleUnaryOperator(underlying) + } + } + + case class AsJavaDoubleUnaryOperator(sf: scala.Function1[Double, Double]) extends java.util.function.DoubleUnaryOperator { + def applyAsDouble(x1: scala.Double) = sf.apply(x1) + } + + class RichFunction1AsDoubleUnaryOperator(private val underlying: scala.Function1[Double, Double]) extends AnyVal { + @inline def asJava: java.util.function.DoubleUnaryOperator = underlying match { + case FromJavaDoubleUnaryOperator((jf @ _)) => jf.asInstanceOf[java.util.function.DoubleUnaryOperator] + case _ => new AsJavaDoubleUnaryOperator(underlying) + } + } + + + case class FromJavaFunction[T, R](jf: java.util.function.Function[T, R]) extends scala.Function1[T, R] { + def apply(x1: T) = jf.apply(x1) + } + + class RichFunctionAsFunction1[T, R](private val underlying: java.util.function.Function[T, R]) extends AnyVal { + @inline def asScala: scala.Function1[T, R] = underlying match { + case AsJavaFunction((sf @ _)) => sf.asInstanceOf[scala.Function1[T, R]] + case _ => new FromJavaFunction[T, R](underlying) + } + } + + case class AsJavaFunction[T, R](sf: scala.Function1[T, R]) extends java.util.function.Function[T, R] { + def apply(x1: T) = sf.apply(x1) + } + + class RichFunction1AsFunction[T, R](private val underlying: scala.Function1[T, R]) extends AnyVal { + @inline def asJava: java.util.function.Function[T, R] = underlying match { + case FromJavaFunction((jf @ _)) => jf.asInstanceOf[java.util.function.Function[T, R]] + case _ => new AsJavaFunction[T, R](underlying) + }; + @inline def asJavaFunction: java.util.function.Function[T, R] = underlying match { + case FromJavaFunction((sf @ _)) => sf.asInstanceOf[java.util.function.Function[T, R]] + case _ => new AsJavaFunction[T, R](underlying) + } + } + + + case class FromJavaIntBinaryOperator(jf: java.util.function.IntBinaryOperator) extends scala.Function2[Int, Int, Int] { + def apply(x1: scala.Int, x2: scala.Int) = jf.applyAsInt(x1, x2) + } + + class RichIntBinaryOperatorAsFunction2(private val underlying: java.util.function.IntBinaryOperator) extends AnyVal { + @inline def asScala: scala.Function2[Int, Int, Int] = underlying match { + case AsJavaIntBinaryOperator((sf @ _)) => sf.asInstanceOf[scala.Function2[Int, Int, Int]] + case _ => new FromJavaIntBinaryOperator(underlying) + } + } + + case class AsJavaIntBinaryOperator(sf: scala.Function2[Int, Int, Int]) extends java.util.function.IntBinaryOperator { + def applyAsInt(x1: scala.Int, x2: scala.Int) = sf.apply(x1, x2) + } + + class RichFunction2AsIntBinaryOperator(private val underlying: scala.Function2[Int, Int, Int]) extends AnyVal { + @inline def asJava: java.util.function.IntBinaryOperator = underlying match { + case FromJavaIntBinaryOperator((jf @ _)) => jf.asInstanceOf[java.util.function.IntBinaryOperator] + case _ => new AsJavaIntBinaryOperator(underlying) + } + } + + + case class FromJavaIntConsumer(jf: java.util.function.IntConsumer) extends scala.Function1[Int, Unit] { + def apply(x1: scala.Int) = jf.accept(x1) + } + + class RichIntConsumerAsFunction1(private val underlying: java.util.function.IntConsumer) extends AnyVal { + @inline def asScala: scala.Function1[Int, Unit] = underlying match { + case AsJavaIntConsumer((sf @ _)) => sf.asInstanceOf[scala.Function1[Int, Unit]] + case _ => new FromJavaIntConsumer(underlying) + } + } + + case class AsJavaIntConsumer(sf: scala.Function1[Int, Unit]) extends java.util.function.IntConsumer { + def accept(x1: scala.Int) = sf.apply(x1) + } + + class RichFunction1AsIntConsumer(private val underlying: scala.Function1[Int, Unit]) extends AnyVal { + @inline def asJava: java.util.function.IntConsumer = underlying match { + case FromJavaIntConsumer((jf @ _)) => jf.asInstanceOf[java.util.function.IntConsumer] + case _ => new AsJavaIntConsumer(underlying) + } + } + + + case class FromJavaIntFunction[R](jf: java.util.function.IntFunction[R]) extends scala.Function1[Int, R] { + def apply(x1: scala.Int) = jf.apply(x1) + } + + class RichIntFunctionAsFunction1[R](private val underlying: java.util.function.IntFunction[R]) extends AnyVal { + @inline def asScala: scala.Function1[Int, R] = underlying match { + case AsJavaIntFunction((sf @ _)) => sf.asInstanceOf[scala.Function1[Int, R]] + case _ => new FromJavaIntFunction[R](underlying) + } + } + + case class AsJavaIntFunction[R](sf: scala.Function1[Int, R]) extends java.util.function.IntFunction[R] { + def apply(x1: scala.Int) = sf.apply(x1) + } + + class RichFunction1AsIntFunction[R](private val underlying: scala.Function1[Int, R]) extends AnyVal { + @inline def asJava: java.util.function.IntFunction[R] = underlying match { + case FromJavaIntFunction((jf @ _)) => jf.asInstanceOf[java.util.function.IntFunction[R]] + case _ => new AsJavaIntFunction[R](underlying) + }; + @inline def asJavaIntFunction: java.util.function.IntFunction[R] = underlying match { + case FromJavaIntFunction((sf @ _)) => sf.asInstanceOf[java.util.function.IntFunction[R]] + case _ => new AsJavaIntFunction[R](underlying) + } + } + + + case class FromJavaIntPredicate(jf: java.util.function.IntPredicate) extends scala.Function1[Int, Boolean] { + def apply(x1: scala.Int) = jf.test(x1) + } + + class RichIntPredicateAsFunction1(private val underlying: java.util.function.IntPredicate) extends AnyVal { + @inline def asScala: scala.Function1[Int, Boolean] = underlying match { + case AsJavaIntPredicate((sf @ _)) => sf.asInstanceOf[scala.Function1[Int, Boolean]] + case _ => new FromJavaIntPredicate(underlying) + } + } + + case class AsJavaIntPredicate(sf: scala.Function1[Int, Boolean]) extends java.util.function.IntPredicate { + def test(x1: scala.Int) = sf.apply(x1) + } + + class RichFunction1AsIntPredicate(private val underlying: scala.Function1[Int, Boolean]) extends AnyVal { + @inline def asJava: java.util.function.IntPredicate = underlying match { + case FromJavaIntPredicate((jf @ _)) => jf.asInstanceOf[java.util.function.IntPredicate] + case _ => new AsJavaIntPredicate(underlying) + } + } + + + case class FromJavaIntSupplier(jf: java.util.function.IntSupplier) extends scala.Function0[Int] { + def apply() = jf.getAsInt() + } + + class RichIntSupplierAsFunction0(private val underlying: java.util.function.IntSupplier) extends AnyVal { + @inline def asScala: scala.Function0[Int] = underlying match { + case AsJavaIntSupplier((sf @ _)) => sf.asInstanceOf[scala.Function0[Int]] + case _ => new FromJavaIntSupplier(underlying) + } + } + + case class AsJavaIntSupplier(sf: scala.Function0[Int]) extends java.util.function.IntSupplier { + def getAsInt() = sf.apply() + } + + class RichFunction0AsIntSupplier(private val underlying: scala.Function0[Int]) extends AnyVal { + @inline def asJava: java.util.function.IntSupplier = underlying match { + case FromJavaIntSupplier((jf @ _)) => jf.asInstanceOf[java.util.function.IntSupplier] + case _ => new AsJavaIntSupplier(underlying) + } + } + + + case class FromJavaIntToDoubleFunction(jf: java.util.function.IntToDoubleFunction) extends scala.Function1[Int, Double] { + def apply(x1: scala.Int) = jf.applyAsDouble(x1) + } + + class RichIntToDoubleFunctionAsFunction1(private val underlying: java.util.function.IntToDoubleFunction) extends AnyVal { + @inline def asScala: scala.Function1[Int, Double] = underlying match { + case AsJavaIntToDoubleFunction((sf @ _)) => sf.asInstanceOf[scala.Function1[Int, Double]] + case _ => new FromJavaIntToDoubleFunction(underlying) + } + } + + case class AsJavaIntToDoubleFunction(sf: scala.Function1[Int, Double]) extends java.util.function.IntToDoubleFunction { + def applyAsDouble(x1: scala.Int) = sf.apply(x1) + } + + class RichFunction1AsIntToDoubleFunction(private val underlying: scala.Function1[Int, Double]) extends AnyVal { + @inline def asJava: java.util.function.IntToDoubleFunction = underlying match { + case FromJavaIntToDoubleFunction((jf @ _)) => jf.asInstanceOf[java.util.function.IntToDoubleFunction] + case _ => new AsJavaIntToDoubleFunction(underlying) + } + } + + + case class FromJavaIntToLongFunction(jf: java.util.function.IntToLongFunction) extends scala.Function1[Int, Long] { + def apply(x1: scala.Int) = jf.applyAsLong(x1) + } + + class RichIntToLongFunctionAsFunction1(private val underlying: java.util.function.IntToLongFunction) extends AnyVal { + @inline def asScala: scala.Function1[Int, Long] = underlying match { + case AsJavaIntToLongFunction((sf @ _)) => sf.asInstanceOf[scala.Function1[Int, Long]] + case _ => new FromJavaIntToLongFunction(underlying) + } + } + + case class AsJavaIntToLongFunction(sf: scala.Function1[Int, Long]) extends java.util.function.IntToLongFunction { + def applyAsLong(x1: scala.Int) = sf.apply(x1) + } + + class RichFunction1AsIntToLongFunction(private val underlying: scala.Function1[Int, Long]) extends AnyVal { + @inline def asJava: java.util.function.IntToLongFunction = underlying match { + case FromJavaIntToLongFunction((jf @ _)) => jf.asInstanceOf[java.util.function.IntToLongFunction] + case _ => new AsJavaIntToLongFunction(underlying) + } + } + + + case class FromJavaIntUnaryOperator(jf: java.util.function.IntUnaryOperator) extends scala.Function1[Int, Int] { + def apply(x1: scala.Int) = jf.applyAsInt(x1) + } + + class RichIntUnaryOperatorAsFunction1(private val underlying: java.util.function.IntUnaryOperator) extends AnyVal { + @inline def asScala: scala.Function1[Int, Int] = underlying match { + case AsJavaIntUnaryOperator((sf @ _)) => sf.asInstanceOf[scala.Function1[Int, Int]] + case _ => new FromJavaIntUnaryOperator(underlying) + } + } + + case class AsJavaIntUnaryOperator(sf: scala.Function1[Int, Int]) extends java.util.function.IntUnaryOperator { + def applyAsInt(x1: scala.Int) = sf.apply(x1) + } + + class RichFunction1AsIntUnaryOperator(private val underlying: scala.Function1[Int, Int]) extends AnyVal { + @inline def asJava: java.util.function.IntUnaryOperator = underlying match { + case FromJavaIntUnaryOperator((jf @ _)) => jf.asInstanceOf[java.util.function.IntUnaryOperator] + case _ => new AsJavaIntUnaryOperator(underlying) + } + } + + + case class FromJavaLongBinaryOperator(jf: java.util.function.LongBinaryOperator) extends scala.Function2[Long, Long, Long] { + def apply(x1: scala.Long, x2: scala.Long) = jf.applyAsLong(x1, x2) + } + + class RichLongBinaryOperatorAsFunction2(private val underlying: java.util.function.LongBinaryOperator) extends AnyVal { + @inline def asScala: scala.Function2[Long, Long, Long] = underlying match { + case AsJavaLongBinaryOperator((sf @ _)) => sf.asInstanceOf[scala.Function2[Long, Long, Long]] + case _ => new FromJavaLongBinaryOperator(underlying) + } + } + + case class AsJavaLongBinaryOperator(sf: scala.Function2[Long, Long, Long]) extends java.util.function.LongBinaryOperator { + def applyAsLong(x1: scala.Long, x2: scala.Long) = sf.apply(x1, x2) + } + + class RichFunction2AsLongBinaryOperator(private val underlying: scala.Function2[Long, Long, Long]) extends AnyVal { + @inline def asJava: java.util.function.LongBinaryOperator = underlying match { + case FromJavaLongBinaryOperator((jf @ _)) => jf.asInstanceOf[java.util.function.LongBinaryOperator] + case _ => new AsJavaLongBinaryOperator(underlying) + } + } + + + case class FromJavaLongConsumer(jf: java.util.function.LongConsumer) extends scala.Function1[Long, Unit] { + def apply(x1: scala.Long) = jf.accept(x1) + } + + class RichLongConsumerAsFunction1(private val underlying: java.util.function.LongConsumer) extends AnyVal { + @inline def asScala: scala.Function1[Long, Unit] = underlying match { + case AsJavaLongConsumer((sf @ _)) => sf.asInstanceOf[scala.Function1[Long, Unit]] + case _ => new FromJavaLongConsumer(underlying) + } + } + + case class AsJavaLongConsumer(sf: scala.Function1[Long, Unit]) extends java.util.function.LongConsumer { + def accept(x1: scala.Long) = sf.apply(x1) + } + + class RichFunction1AsLongConsumer(private val underlying: scala.Function1[Long, Unit]) extends AnyVal { + @inline def asJava: java.util.function.LongConsumer = underlying match { + case FromJavaLongConsumer((jf @ _)) => jf.asInstanceOf[java.util.function.LongConsumer] + case _ => new AsJavaLongConsumer(underlying) + } + } + + + case class FromJavaLongFunction[R](jf: java.util.function.LongFunction[R]) extends scala.Function1[Long, R] { + def apply(x1: scala.Long) = jf.apply(x1) + } + + class RichLongFunctionAsFunction1[R](private val underlying: java.util.function.LongFunction[R]) extends AnyVal { + @inline def asScala: scala.Function1[Long, R] = underlying match { + case AsJavaLongFunction((sf @ _)) => sf.asInstanceOf[scala.Function1[Long, R]] + case _ => new FromJavaLongFunction[R](underlying) + } + } + + case class AsJavaLongFunction[R](sf: scala.Function1[Long, R]) extends java.util.function.LongFunction[R] { + def apply(x1: scala.Long) = sf.apply(x1) + } + + class RichFunction1AsLongFunction[R](private val underlying: scala.Function1[Long, R]) extends AnyVal { + @inline def asJava: java.util.function.LongFunction[R] = underlying match { + case FromJavaLongFunction((jf @ _)) => jf.asInstanceOf[java.util.function.LongFunction[R]] + case _ => new AsJavaLongFunction[R](underlying) + }; + @inline def asJavaLongFunction: java.util.function.LongFunction[R] = underlying match { + case FromJavaLongFunction((sf @ _)) => sf.asInstanceOf[java.util.function.LongFunction[R]] + case _ => new AsJavaLongFunction[R](underlying) + } + } + + + case class FromJavaLongPredicate(jf: java.util.function.LongPredicate) extends scala.Function1[Long, Boolean] { + def apply(x1: scala.Long) = jf.test(x1) + } + + class RichLongPredicateAsFunction1(private val underlying: java.util.function.LongPredicate) extends AnyVal { + @inline def asScala: scala.Function1[Long, Boolean] = underlying match { + case AsJavaLongPredicate((sf @ _)) => sf.asInstanceOf[scala.Function1[Long, Boolean]] + case _ => new FromJavaLongPredicate(underlying) + } + } + + case class AsJavaLongPredicate(sf: scala.Function1[Long, Boolean]) extends java.util.function.LongPredicate { + def test(x1: scala.Long) = sf.apply(x1) + } + + class RichFunction1AsLongPredicate(private val underlying: scala.Function1[Long, Boolean]) extends AnyVal { + @inline def asJava: java.util.function.LongPredicate = underlying match { + case FromJavaLongPredicate((jf @ _)) => jf.asInstanceOf[java.util.function.LongPredicate] + case _ => new AsJavaLongPredicate(underlying) + } + } + + + case class FromJavaLongSupplier(jf: java.util.function.LongSupplier) extends scala.Function0[Long] { + def apply() = jf.getAsLong() + } + + class RichLongSupplierAsFunction0(private val underlying: java.util.function.LongSupplier) extends AnyVal { + @inline def asScala: scala.Function0[Long] = underlying match { + case AsJavaLongSupplier((sf @ _)) => sf.asInstanceOf[scala.Function0[Long]] + case _ => new FromJavaLongSupplier(underlying) + } + } + + case class AsJavaLongSupplier(sf: scala.Function0[Long]) extends java.util.function.LongSupplier { + def getAsLong() = sf.apply() + } + + class RichFunction0AsLongSupplier(private val underlying: scala.Function0[Long]) extends AnyVal { + @inline def asJava: java.util.function.LongSupplier = underlying match { + case FromJavaLongSupplier((jf @ _)) => jf.asInstanceOf[java.util.function.LongSupplier] + case _ => new AsJavaLongSupplier(underlying) + } + } + + + case class FromJavaLongToDoubleFunction(jf: java.util.function.LongToDoubleFunction) extends scala.Function1[Long, Double] { + def apply(x1: scala.Long) = jf.applyAsDouble(x1) + } + + class RichLongToDoubleFunctionAsFunction1(private val underlying: java.util.function.LongToDoubleFunction) extends AnyVal { + @inline def asScala: scala.Function1[Long, Double] = underlying match { + case AsJavaLongToDoubleFunction((sf @ _)) => sf.asInstanceOf[scala.Function1[Long, Double]] + case _ => new FromJavaLongToDoubleFunction(underlying) + } + } + + case class AsJavaLongToDoubleFunction(sf: scala.Function1[Long, Double]) extends java.util.function.LongToDoubleFunction { + def applyAsDouble(x1: scala.Long) = sf.apply(x1) + } + + class RichFunction1AsLongToDoubleFunction(private val underlying: scala.Function1[Long, Double]) extends AnyVal { + @inline def asJava: java.util.function.LongToDoubleFunction = underlying match { + case FromJavaLongToDoubleFunction((jf @ _)) => jf.asInstanceOf[java.util.function.LongToDoubleFunction] + case _ => new AsJavaLongToDoubleFunction(underlying) + } + } + + + case class FromJavaLongToIntFunction(jf: java.util.function.LongToIntFunction) extends scala.Function1[Long, Int] { + def apply(x1: scala.Long) = jf.applyAsInt(x1) + } + + class RichLongToIntFunctionAsFunction1(private val underlying: java.util.function.LongToIntFunction) extends AnyVal { + @inline def asScala: scala.Function1[Long, Int] = underlying match { + case AsJavaLongToIntFunction((sf @ _)) => sf.asInstanceOf[scala.Function1[Long, Int]] + case _ => new FromJavaLongToIntFunction(underlying) + } + } + + case class AsJavaLongToIntFunction(sf: scala.Function1[Long, Int]) extends java.util.function.LongToIntFunction { + def applyAsInt(x1: scala.Long) = sf.apply(x1) + } + + class RichFunction1AsLongToIntFunction(private val underlying: scala.Function1[Long, Int]) extends AnyVal { + @inline def asJava: java.util.function.LongToIntFunction = underlying match { + case FromJavaLongToIntFunction((jf @ _)) => jf.asInstanceOf[java.util.function.LongToIntFunction] + case _ => new AsJavaLongToIntFunction(underlying) + } + } + + + case class FromJavaLongUnaryOperator(jf: java.util.function.LongUnaryOperator) extends scala.Function1[Long, Long] { + def apply(x1: scala.Long) = jf.applyAsLong(x1) + } + + class RichLongUnaryOperatorAsFunction1(private val underlying: java.util.function.LongUnaryOperator) extends AnyVal { + @inline def asScala: scala.Function1[Long, Long] = underlying match { + case AsJavaLongUnaryOperator((sf @ _)) => sf.asInstanceOf[scala.Function1[Long, Long]] + case _ => new FromJavaLongUnaryOperator(underlying) + } + } + + case class AsJavaLongUnaryOperator(sf: scala.Function1[Long, Long]) extends java.util.function.LongUnaryOperator { + def applyAsLong(x1: scala.Long) = sf.apply(x1) + } + + class RichFunction1AsLongUnaryOperator(private val underlying: scala.Function1[Long, Long]) extends AnyVal { + @inline def asJava: java.util.function.LongUnaryOperator = underlying match { + case FromJavaLongUnaryOperator((jf @ _)) => jf.asInstanceOf[java.util.function.LongUnaryOperator] + case _ => new AsJavaLongUnaryOperator(underlying) + } + } + + + case class FromJavaObjDoubleConsumer[T](jf: java.util.function.ObjDoubleConsumer[T]) extends scala.Function2[T, Double, Unit] { + def apply(x1: T, x2: scala.Double) = jf.accept(x1, x2) + } + + class RichObjDoubleConsumerAsFunction2[T](private val underlying: java.util.function.ObjDoubleConsumer[T]) extends AnyVal { + @inline def asScala: scala.Function2[T, Double, Unit] = underlying match { + case AsJavaObjDoubleConsumer((sf @ _)) => sf.asInstanceOf[scala.Function2[T, Double, Unit]] + case _ => new FromJavaObjDoubleConsumer[T](underlying) + } + } + + case class AsJavaObjDoubleConsumer[T](sf: scala.Function2[T, Double, Unit]) extends java.util.function.ObjDoubleConsumer[T] { + def accept(x1: T, x2: scala.Double) = sf.apply(x1, x2) + } + + class RichFunction2AsObjDoubleConsumer[T](private val underlying: scala.Function2[T, Double, Unit]) extends AnyVal { + @inline def asJava: java.util.function.ObjDoubleConsumer[T] = underlying match { + case FromJavaObjDoubleConsumer((jf @ _)) => jf.asInstanceOf[java.util.function.ObjDoubleConsumer[T]] + case _ => new AsJavaObjDoubleConsumer[T](underlying) + }; + @inline def asJavaObjDoubleConsumer: java.util.function.ObjDoubleConsumer[T] = underlying match { + case FromJavaObjDoubleConsumer((sf @ _)) => sf.asInstanceOf[java.util.function.ObjDoubleConsumer[T]] + case _ => new AsJavaObjDoubleConsumer[T](underlying) + } + } + + + case class FromJavaObjIntConsumer[T](jf: java.util.function.ObjIntConsumer[T]) extends scala.Function2[T, Int, Unit] { + def apply(x1: T, x2: scala.Int) = jf.accept(x1, x2) + } + + class RichObjIntConsumerAsFunction2[T](private val underlying: java.util.function.ObjIntConsumer[T]) extends AnyVal { + @inline def asScala: scala.Function2[T, Int, Unit] = underlying match { + case AsJavaObjIntConsumer((sf @ _)) => sf.asInstanceOf[scala.Function2[T, Int, Unit]] + case _ => new FromJavaObjIntConsumer[T](underlying) + } + } + + case class AsJavaObjIntConsumer[T](sf: scala.Function2[T, Int, Unit]) extends java.util.function.ObjIntConsumer[T] { + def accept(x1: T, x2: scala.Int) = sf.apply(x1, x2) + } + + class RichFunction2AsObjIntConsumer[T](private val underlying: scala.Function2[T, Int, Unit]) extends AnyVal { + @inline def asJava: java.util.function.ObjIntConsumer[T] = underlying match { + case FromJavaObjIntConsumer((jf @ _)) => jf.asInstanceOf[java.util.function.ObjIntConsumer[T]] + case _ => new AsJavaObjIntConsumer[T](underlying) + }; + @inline def asJavaObjIntConsumer: java.util.function.ObjIntConsumer[T] = underlying match { + case FromJavaObjIntConsumer((sf @ _)) => sf.asInstanceOf[java.util.function.ObjIntConsumer[T]] + case _ => new AsJavaObjIntConsumer[T](underlying) + } + } + + + case class FromJavaObjLongConsumer[T](jf: java.util.function.ObjLongConsumer[T]) extends scala.Function2[T, Long, Unit] { + def apply(x1: T, x2: scala.Long) = jf.accept(x1, x2) + } + + class RichObjLongConsumerAsFunction2[T](private val underlying: java.util.function.ObjLongConsumer[T]) extends AnyVal { + @inline def asScala: scala.Function2[T, Long, Unit] = underlying match { + case AsJavaObjLongConsumer((sf @ _)) => sf.asInstanceOf[scala.Function2[T, Long, Unit]] + case _ => new FromJavaObjLongConsumer[T](underlying) + } + } + + case class AsJavaObjLongConsumer[T](sf: scala.Function2[T, Long, Unit]) extends java.util.function.ObjLongConsumer[T] { + def accept(x1: T, x2: scala.Long) = sf.apply(x1, x2) + } + + class RichFunction2AsObjLongConsumer[T](private val underlying: scala.Function2[T, Long, Unit]) extends AnyVal { + @inline def asJava: java.util.function.ObjLongConsumer[T] = underlying match { + case FromJavaObjLongConsumer((jf @ _)) => jf.asInstanceOf[java.util.function.ObjLongConsumer[T]] + case _ => new AsJavaObjLongConsumer[T](underlying) + }; + @inline def asJavaObjLongConsumer: java.util.function.ObjLongConsumer[T] = underlying match { + case FromJavaObjLongConsumer((sf @ _)) => sf.asInstanceOf[java.util.function.ObjLongConsumer[T]] + case _ => new AsJavaObjLongConsumer[T](underlying) + } + } + + + case class FromJavaPredicate[T](jf: java.util.function.Predicate[T]) extends scala.Function1[T, Boolean] { + def apply(x1: T) = jf.test(x1) + } + + class RichPredicateAsFunction1[T](private val underlying: java.util.function.Predicate[T]) extends AnyVal { + @inline def asScala: scala.Function1[T, Boolean] = underlying match { + case AsJavaPredicate((sf @ _)) => sf.asInstanceOf[scala.Function1[T, Boolean]] + case _ => new FromJavaPredicate[T](underlying) + } + } + + case class AsJavaPredicate[T](sf: scala.Function1[T, Boolean]) extends java.util.function.Predicate[T] { + def test(x1: T) = sf.apply(x1) + } + + class RichFunction1AsPredicate[T](private val underlying: scala.Function1[T, Boolean]) extends AnyVal { + @inline def asJava: java.util.function.Predicate[T] = underlying match { + case FromJavaPredicate((jf @ _)) => jf.asInstanceOf[java.util.function.Predicate[T]] + case _ => new AsJavaPredicate[T](underlying) + }; + @inline def asJavaPredicate: java.util.function.Predicate[T] = underlying match { + case FromJavaPredicate((sf @ _)) => sf.asInstanceOf[java.util.function.Predicate[T]] + case _ => new AsJavaPredicate[T](underlying) + } + } + + + case class FromJavaSupplier[T](jf: java.util.function.Supplier[T]) extends scala.Function0[T] { + def apply() = jf.get() + } + + class RichSupplierAsFunction0[T](private val underlying: java.util.function.Supplier[T]) extends AnyVal { + @inline def asScala: scala.Function0[T] = underlying match { + case AsJavaSupplier((sf @ _)) => sf.asInstanceOf[scala.Function0[T]] + case _ => new FromJavaSupplier[T](underlying) + } + } + + case class AsJavaSupplier[T](sf: scala.Function0[T]) extends java.util.function.Supplier[T] { + def get() = sf.apply() + } + + class RichFunction0AsSupplier[T](private val underlying: scala.Function0[T]) extends AnyVal { + @inline def asJava: java.util.function.Supplier[T] = underlying match { + case FromJavaSupplier((jf @ _)) => jf.asInstanceOf[java.util.function.Supplier[T]] + case _ => new AsJavaSupplier[T](underlying) + }; + @inline def asJavaSupplier: java.util.function.Supplier[T] = underlying match { + case FromJavaSupplier((sf @ _)) => sf.asInstanceOf[java.util.function.Supplier[T]] + case _ => new AsJavaSupplier[T](underlying) + } + } + + + case class FromJavaToDoubleBiFunction[T, U](jf: java.util.function.ToDoubleBiFunction[T, U]) extends scala.Function2[T, U, Double] { + def apply(x1: T, x2: U) = jf.applyAsDouble(x1, x2) + } + + class RichToDoubleBiFunctionAsFunction2[T, U](private val underlying: java.util.function.ToDoubleBiFunction[T, U]) extends AnyVal { + @inline def asScala: scala.Function2[T, U, Double] = underlying match { + case AsJavaToDoubleBiFunction((sf @ _)) => sf.asInstanceOf[scala.Function2[T, U, Double]] + case _ => new FromJavaToDoubleBiFunction[T, U](underlying) + } + } + + case class AsJavaToDoubleBiFunction[T, U](sf: scala.Function2[T, U, Double]) extends java.util.function.ToDoubleBiFunction[T, U] { + def applyAsDouble(x1: T, x2: U) = sf.apply(x1, x2) + } + + class RichFunction2AsToDoubleBiFunction[T, U](private val underlying: scala.Function2[T, U, Double]) extends AnyVal { + @inline def asJava: java.util.function.ToDoubleBiFunction[T, U] = underlying match { + case FromJavaToDoubleBiFunction((jf @ _)) => jf.asInstanceOf[java.util.function.ToDoubleBiFunction[T, U]] + case _ => new AsJavaToDoubleBiFunction[T, U](underlying) + }; + @inline def asJavaToDoubleBiFunction: java.util.function.ToDoubleBiFunction[T, U] = underlying match { + case FromJavaToDoubleBiFunction((sf @ _)) => sf.asInstanceOf[java.util.function.ToDoubleBiFunction[T, U]] + case _ => new AsJavaToDoubleBiFunction[T, U](underlying) + } + } + + + case class FromJavaToDoubleFunction[T](jf: java.util.function.ToDoubleFunction[T]) extends scala.Function1[T, Double] { + def apply(x1: T) = jf.applyAsDouble(x1) + } + + class RichToDoubleFunctionAsFunction1[T](private val underlying: java.util.function.ToDoubleFunction[T]) extends AnyVal { + @inline def asScala: scala.Function1[T, Double] = underlying match { + case AsJavaToDoubleFunction((sf @ _)) => sf.asInstanceOf[scala.Function1[T, Double]] + case _ => new FromJavaToDoubleFunction[T](underlying) + } + } + + case class AsJavaToDoubleFunction[T](sf: scala.Function1[T, Double]) extends java.util.function.ToDoubleFunction[T] { + def applyAsDouble(x1: T) = sf.apply(x1) + } + + class RichFunction1AsToDoubleFunction[T](private val underlying: scala.Function1[T, Double]) extends AnyVal { + @inline def asJava: java.util.function.ToDoubleFunction[T] = underlying match { + case FromJavaToDoubleFunction((jf @ _)) => jf.asInstanceOf[java.util.function.ToDoubleFunction[T]] + case _ => new AsJavaToDoubleFunction[T](underlying) + }; + @inline def asJavaToDoubleFunction: java.util.function.ToDoubleFunction[T] = underlying match { + case FromJavaToDoubleFunction((sf @ _)) => sf.asInstanceOf[java.util.function.ToDoubleFunction[T]] + case _ => new AsJavaToDoubleFunction[T](underlying) + } + } + + + case class FromJavaToIntBiFunction[T, U](jf: java.util.function.ToIntBiFunction[T, U]) extends scala.Function2[T, U, Int] { + def apply(x1: T, x2: U) = jf.applyAsInt(x1, x2) + } + + class RichToIntBiFunctionAsFunction2[T, U](private val underlying: java.util.function.ToIntBiFunction[T, U]) extends AnyVal { + @inline def asScala: scala.Function2[T, U, Int] = underlying match { + case AsJavaToIntBiFunction((sf @ _)) => sf.asInstanceOf[scala.Function2[T, U, Int]] + case _ => new FromJavaToIntBiFunction[T, U](underlying) + } + } + + case class AsJavaToIntBiFunction[T, U](sf: scala.Function2[T, U, Int]) extends java.util.function.ToIntBiFunction[T, U] { + def applyAsInt(x1: T, x2: U) = sf.apply(x1, x2) + } + + class RichFunction2AsToIntBiFunction[T, U](private val underlying: scala.Function2[T, U, Int]) extends AnyVal { + @inline def asJava: java.util.function.ToIntBiFunction[T, U] = underlying match { + case FromJavaToIntBiFunction((jf @ _)) => jf.asInstanceOf[java.util.function.ToIntBiFunction[T, U]] + case _ => new AsJavaToIntBiFunction[T, U](underlying) + }; + @inline def asJavaToIntBiFunction: java.util.function.ToIntBiFunction[T, U] = underlying match { + case FromJavaToIntBiFunction((sf @ _)) => sf.asInstanceOf[java.util.function.ToIntBiFunction[T, U]] + case _ => new AsJavaToIntBiFunction[T, U](underlying) + } + } + + + case class FromJavaToIntFunction[T](jf: java.util.function.ToIntFunction[T]) extends scala.Function1[T, Int] { + def apply(x1: T) = jf.applyAsInt(x1) + } + + class RichToIntFunctionAsFunction1[T](private val underlying: java.util.function.ToIntFunction[T]) extends AnyVal { + @inline def asScala: scala.Function1[T, Int] = underlying match { + case AsJavaToIntFunction((sf @ _)) => sf.asInstanceOf[scala.Function1[T, Int]] + case _ => new FromJavaToIntFunction[T](underlying) + } + } + + case class AsJavaToIntFunction[T](sf: scala.Function1[T, Int]) extends java.util.function.ToIntFunction[T] { + def applyAsInt(x1: T) = sf.apply(x1) + } + + class RichFunction1AsToIntFunction[T](private val underlying: scala.Function1[T, Int]) extends AnyVal { + @inline def asJava: java.util.function.ToIntFunction[T] = underlying match { + case FromJavaToIntFunction((jf @ _)) => jf.asInstanceOf[java.util.function.ToIntFunction[T]] + case _ => new AsJavaToIntFunction[T](underlying) + }; + @inline def asJavaToIntFunction: java.util.function.ToIntFunction[T] = underlying match { + case FromJavaToIntFunction((sf @ _)) => sf.asInstanceOf[java.util.function.ToIntFunction[T]] + case _ => new AsJavaToIntFunction[T](underlying) + } + } + + + case class FromJavaToLongBiFunction[T, U](jf: java.util.function.ToLongBiFunction[T, U]) extends scala.Function2[T, U, Long] { + def apply(x1: T, x2: U) = jf.applyAsLong(x1, x2) + } + + class RichToLongBiFunctionAsFunction2[T, U](private val underlying: java.util.function.ToLongBiFunction[T, U]) extends AnyVal { + @inline def asScala: scala.Function2[T, U, Long] = underlying match { + case AsJavaToLongBiFunction((sf @ _)) => sf.asInstanceOf[scala.Function2[T, U, Long]] + case _ => new FromJavaToLongBiFunction[T, U](underlying) + } + } + + case class AsJavaToLongBiFunction[T, U](sf: scala.Function2[T, U, Long]) extends java.util.function.ToLongBiFunction[T, U] { + def applyAsLong(x1: T, x2: U) = sf.apply(x1, x2) + } + + class RichFunction2AsToLongBiFunction[T, U](private val underlying: scala.Function2[T, U, Long]) extends AnyVal { + @inline def asJava: java.util.function.ToLongBiFunction[T, U] = underlying match { + case FromJavaToLongBiFunction((jf @ _)) => jf.asInstanceOf[java.util.function.ToLongBiFunction[T, U]] + case _ => new AsJavaToLongBiFunction[T, U](underlying) + }; + @inline def asJavaToLongBiFunction: java.util.function.ToLongBiFunction[T, U] = underlying match { + case FromJavaToLongBiFunction((sf @ _)) => sf.asInstanceOf[java.util.function.ToLongBiFunction[T, U]] + case _ => new AsJavaToLongBiFunction[T, U](underlying) + } + } + + + case class FromJavaToLongFunction[T](jf: java.util.function.ToLongFunction[T]) extends scala.Function1[T, Long] { + def apply(x1: T) = jf.applyAsLong(x1) + } + + class RichToLongFunctionAsFunction1[T](private val underlying: java.util.function.ToLongFunction[T]) extends AnyVal { + @inline def asScala: scala.Function1[T, Long] = underlying match { + case AsJavaToLongFunction((sf @ _)) => sf.asInstanceOf[scala.Function1[T, Long]] + case _ => new FromJavaToLongFunction[T](underlying) + } + } + + case class AsJavaToLongFunction[T](sf: scala.Function1[T, Long]) extends java.util.function.ToLongFunction[T] { + def applyAsLong(x1: T) = sf.apply(x1) + } + + class RichFunction1AsToLongFunction[T](private val underlying: scala.Function1[T, Long]) extends AnyVal { + @inline def asJava: java.util.function.ToLongFunction[T] = underlying match { + case FromJavaToLongFunction((jf @ _)) => jf.asInstanceOf[java.util.function.ToLongFunction[T]] + case _ => new AsJavaToLongFunction[T](underlying) + }; + @inline def asJavaToLongFunction: java.util.function.ToLongFunction[T] = underlying match { + case FromJavaToLongFunction((sf @ _)) => sf.asInstanceOf[java.util.function.ToLongFunction[T]] + case _ => new AsJavaToLongFunction[T](underlying) + } + } + + + case class FromJavaUnaryOperator[T](jf: java.util.function.UnaryOperator[T]) extends scala.Function1[T, T] { + def apply(x1: T) = jf.apply(x1) + } + + class RichUnaryOperatorAsFunction1[T](private val underlying: java.util.function.UnaryOperator[T]) extends AnyVal { + @inline def asScala: scala.Function1[T, T] = underlying match { + case AsJavaUnaryOperator((sf @ _)) => sf.asInstanceOf[scala.Function1[T, T]] + case _ => new FromJavaUnaryOperator[T](underlying) + } + } + + case class AsJavaUnaryOperator[T](sf: scala.Function1[T, T]) extends java.util.function.UnaryOperator[T] { + def apply(x1: T) = sf.apply(x1) + } + + class RichFunction1AsUnaryOperator[T](private val underlying: scala.Function1[T, T]) extends AnyVal { + @inline def asJava: java.util.function.UnaryOperator[T] = underlying match { + case FromJavaUnaryOperator((jf @ _)) => jf.asInstanceOf[java.util.function.UnaryOperator[T]] + case _ => new AsJavaUnaryOperator[T](underlying) + }; + @inline def asJavaUnaryOperator: java.util.function.UnaryOperator[T] = underlying match { + case FromJavaUnaryOperator((sf @ _)) => sf.asInstanceOf[java.util.function.UnaryOperator[T]] + case _ => new AsJavaUnaryOperator[T](underlying) + } + } +} diff --git a/library-internal/src/scala/jdk/IntAccumulator.scala b/library-internal/src/scala/jdk/IntAccumulator.scala new file mode 100644 index 000000000000..9b7a904b36e3 --- /dev/null +++ b/library-internal/src/scala/jdk/IntAccumulator.scala @@ -0,0 +1,493 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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.jdk + +import java.io.{ObjectInputStream, ObjectOutputStream} +import java.util.Spliterator +import java.util.function.{Consumer, IntConsumer} +import java.{lang => jl} + +import scala.annotation._ +import scala.collection.Stepper.EfficientSplit +import scala.collection.{AnyStepper, Factory, IntStepper, SeqFactory, Stepper, StepperShape, mutable} +import scala.language.implicitConversions + +/** A specialized Accumulator that holds `Int`s without boxing, see [[Accumulator]]. */ +final class IntAccumulator + extends Accumulator[Int, AnyAccumulator, IntAccumulator] + with mutable.SeqOps[Int, AnyAccumulator, IntAccumulator] + with Serializable { + private[jdk] var current: Array[Int] = IntAccumulator.emptyIntArray + private[jdk] var history: Array[Array[Int]] = IntAccumulator.emptyIntArrayArray + + private[jdk] def cumulative(i: Int) = { val x = history(i); x(x.length-2).toLong << 32 | (x(x.length-1)&0xFFFFFFFFL) } + + override protected[this] def className: String = "IntAccumulator" + + def efficientStepper[S <: Stepper[_]](implicit shape: StepperShape[Int, S]): S with EfficientSplit = { + val st = new IntAccumulatorStepper(this) + val r = + if (shape.shape == StepperShape.IntShape) st + else { + assert(shape.shape == StepperShape.ReferenceShape, s"unexpected StepperShape: $shape") + AnyStepper.ofParIntStepper(st) + } + r.asInstanceOf[S with EfficientSplit] + } + + private def expand(): Unit = { + if (index > 0) { + val cuml = (if (hIndex > 0) cumulative(hIndex-1) else 0) + index + current(current.length-2) = (cuml >>> 32).toInt + current(current.length-1) = (cuml & 0xFFFFFFFFL).toInt + if (hIndex >= history.length) hExpand() + history(hIndex) = current + hIndex += 1 + } + current = new Array[Int](nextBlockSize+1) + index = 0 + } + + private def hExpand(): Unit = { + if (hIndex == 0) history = new Array[Array[Int]](4) + else history = java.util.Arrays.copyOf(history, history.length << 1) + } + + /** Appends an element to this `IntAccumulator`. */ + def addOne(a: Int): this.type = { + totalSize += 1 + if (index+2 >= current.length) expand() + current(index) = a + index += 1 + this + } + + /** Result collection consisting of all elements appended so far. */ + override def result(): IntAccumulator = this + + /** Removes all elements from `that` and appends them to this `IntAccumulator`. */ + def drain(that: IntAccumulator): Unit = { + var h = 0 + var prev = 0L + var more = true + while (more && h < that.hIndex) { + val cuml = that.cumulative(h) + val n = (cuml - prev).toInt + if (current.length - index - 2 >= n) { + System.arraycopy(that.history(h), 0, current, index, n) + prev = cuml + index += n + h += 1 + } + else more = false + } + if (h >= that.hIndex && current.length - index - 2 >= that.index) { + if (that.index > 0) System.arraycopy(that.current, 0, current, index, that.index) + index += that.index + } + else { + val slots = (if (index > 0) 1 else 0) + that.hIndex - h + if (hIndex + slots > history.length) { + val n = math.max(4, 1 << (32 - jl.Integer.numberOfLeadingZeros(1 + hIndex + slots))) + history = java.util.Arrays.copyOf(history, n) + } + var pv = if (hIndex > 0) cumulative(hIndex-1) else 0L + if (index > 0) { + val x = + if (index < (current.length >>> 3) && current.length - 1 > 32) { + val ans = java.util.Arrays.copyOf(current, index + 2) + ans(ans.length - 2) = current(current.length - 2) + ans(ans.length - 1) = current(current.length - 1) + ans + } + else current + pv = pv + index + x(x.length - 2) = (pv >>> 32).toInt + x(x.length - 1) = (pv & 0xFFFFFFFFL).toInt + history(hIndex) = x + hIndex += 1 + } + while (h < that.hIndex) { + val cuml = that.cumulative(h) + pv = pv + cuml - prev + prev = cuml + val x = that.history(h) + x(x.length - 2) = (pv >>> 32).toInt + x(x.length - 1) = (pv & 0xFFFFFFFFL).toInt + history(hIndex) = x + h += 1 + hIndex += 1 + } + index = that.index + current = that.current + } + totalSize += that.totalSize + that.clear() + } + + override def clear(): Unit = { + super.clear() + current = IntAccumulator.emptyIntArray + history = IntAccumulator.emptyIntArrayArray + } + + /** Retrieves the `ix`th element. */ + def apply(ix: Long): Int = { + if (totalSize - ix <= index || hIndex == 0) current((ix - (totalSize - index)).toInt) + else { + val w = seekSlot(ix) + history((w >>> 32).toInt)((w & 0xFFFFFFFFL).toInt) + } + } + + /** Retrieves the `ix`th element, using an `Int` index. */ + def apply(i: Int): Int = apply(i.toLong) + + def update(idx: Long, elem: Int): Unit = { + if (totalSize - idx <= index || hIndex == 0) current((idx - (totalSize - index)).toInt) = elem + else { + val w = seekSlot(idx) + history((w >>> 32).toInt)((w & 0xFFFFFFFFL).toInt) = elem + } + } + + def update(idx: Int, elem: Int): Unit = update(idx.toLong, elem) + + /** Returns an `Iterator` over the contents of this `IntAccumulator`. The `Iterator` is not specialized. */ + def iterator: Iterator[Int] = stepper.iterator + + override def foreach[U](f: Int => U): Unit = { + val s = stepper + while (s.hasStep) f(s.nextStep()) + } + + def map(f: Int => Int): IntAccumulator = { + val b = newSpecificBuilder + val s = stepper + while (s.hasStep) + b.addOne(f(s.nextStep())) + b.result() + } + + def flatMap(f: Int => IterableOnce[Int]): IntAccumulator = { + val b = newSpecificBuilder + val s = stepper + while (s.hasStep) + b.addAll(f(s.nextStep())) + b.result() + } + + def collect(pf: PartialFunction[Int, Int]): IntAccumulator = { + val b = newSpecificBuilder + val s = stepper + while (s.hasStep) { + val n = s.nextStep() + pf.runWith(b.addOne)(n) + } + b.result() + } + + private def filterAccImpl(pred: Int => Boolean, not: Boolean): IntAccumulator = { + val b = newSpecificBuilder + val s = stepper + while (s.hasStep) { + val n = s.nextStep() + if (pred(n) != not) b.addOne(n) + } + b.result() + } + + override def filter(pred: Int => Boolean): IntAccumulator = filterAccImpl(pred, not = false) + + override def filterNot(pred: Int => Boolean): IntAccumulator = filterAccImpl(pred, not = true) + + override def forall(p: Int => Boolean): Boolean = { + val s = stepper + while (s.hasStep) + if (!p(s.nextStep())) return false + true + } + + override def exists(p: Int => Boolean): Boolean = { + val s = stepper + while (s.hasStep) + if (p(s.nextStep())) return true + false + } + + override def count(p: Int => Boolean): Int = { + var r = 0 + val s = stepper + while (s.hasStep) + if (p(s.nextStep())) r += 1 + r + } + + def countLong(p: Int => Boolean): Long = { + var r = 0L + val s = stepper + while (s.hasStep) + if (p(s.nextStep())) r += 1 + r + } + + /** Copies the elements in this `IntAccumulator` into an `Array[Int]` */ + @nowarn // cat=lint-overload see toArray[B: ClassTag] + def toArray: Array[Int] = { + if (totalSize > Int.MaxValue) throw new IllegalArgumentException("Too many elements accumulated for an array: "+totalSize.toString) + val a = new Array[Int](totalSize.toInt) + var j = 0 + var h = 0 + var pv = 0L + while (h < hIndex) { + val x = history(h) + val cuml = cumulative(h) + val n = (cuml - pv).toInt + pv = cuml + System.arraycopy(x, 0, a, j, n) + j += n + h += 1 + } + System.arraycopy(current, 0, a, j, index) + j += index + a + } + + /** Copies the elements in this `IntAccumulator` to a `List` */ + override def toList: List[Int] = { + var ans: List[Int] = Nil + var i = index - 1 + while (i >= 0) { + ans = current(i) :: ans + i -= 1 + } + var h = hIndex - 1 + while (h >= 0) { + val a = history(h) + i = (cumulative(h) - (if (h == 0) 0L else cumulative(h-1))).toInt - 1 + while (i >= 0) { + ans = a(i) :: ans + i -= 1 + } + h -= 1 + } + ans + } + + /** + * Copy the elements in this `IntAccumulator` to a specified collection. + * Note that the target collection is not specialized. + * Usage example: `acc.to(Vector)` + */ + override def to[C1](factory: Factory[Int, C1]): C1 = { + if (totalSize > Int.MaxValue) throw new IllegalArgumentException("Too many elements accumulated for a Scala collection: "+totalSize.toString) + factory.fromSpecific(iterator) + } + + override protected def fromSpecific(coll: IterableOnce[Int]): IntAccumulator = IntAccumulator.fromSpecific(coll) + override protected def newSpecificBuilder: IntAccumulator = IntAccumulator.newBuilder + override def iterableFactory: SeqFactory[AnyAccumulator] = AnyAccumulator + + override def empty: IntAccumulator = IntAccumulator.empty + + private def writeReplace(): AnyRef = new IntAccumulator.SerializationProxy(this) +} + +object IntAccumulator extends collection.SpecificIterableFactory[Int, IntAccumulator] { + private val emptyIntArray = new Array[Int](0) + private val emptyIntArrayArray = new Array[Array[Int]](0) + + implicit def toJavaIntegerAccumulator(ia: IntAccumulator.type): collection.SpecificIterableFactory[jl.Integer, IntAccumulator] = IntAccumulator.asInstanceOf[collection.SpecificIterableFactory[jl.Integer, IntAccumulator]] + + import java.util.{function => jf} + + /** A `Supplier` of `IntAccumulator`s, suitable for use with `java.util.stream.IntStream`'s `collect` method. Suitable for `Stream[Int]` also. */ + def supplier: jf.Supplier[IntAccumulator] = () => new IntAccumulator + + /** A `BiConsumer` that adds an element to an `IntAccumulator`, suitable for use with `java.util.stream.IntStream`'s `collect` method. */ + def adder: jf.ObjIntConsumer[IntAccumulator] = (ac: IntAccumulator, a: Int) => ac addOne a + + /** A `BiConsumer` that adds a boxed `Int` to an `IntAccumulator`, suitable for use with `java.util.stream.Stream`'s `collect` method. */ + def boxedAdder: jf.BiConsumer[IntAccumulator, Int] = (ac: IntAccumulator, a: Int) => ac addOne a + + /** A `BiConsumer` that merges `IntAccumulator`s, suitable for use with `java.util.stream.IntStream`'s `collect` method. Suitable for `Stream[Int]` also. */ + def merger: jf.BiConsumer[IntAccumulator, IntAccumulator] = (a1: IntAccumulator, a2: IntAccumulator) => a1 drain a2 + + private def fromArray(a: Array[Int]): IntAccumulator = { + val r = new IntAccumulator + var i = 0 + while (i < a.length) { r addOne a(i); i += 1 } + r + } + + override def fromSpecific(it: IterableOnce[Int]): IntAccumulator = it match { + case acc: IntAccumulator => acc + case as: collection.immutable.ArraySeq.ofInt => fromArray(as.unsafeArray) + case as: collection.mutable.ArraySeq.ofInt => fromArray(as.array) // this case ensures Array(1).to(Accumulator) doesn't box + case _ => (new IntAccumulator).addAll(it) + } + + override def empty: IntAccumulator = new IntAccumulator + + override def newBuilder: IntAccumulator = new IntAccumulator + + class SerializationProxy[A](@transient private val acc: IntAccumulator) extends Serializable { + @transient private var result: IntAccumulator = _ + + private def writeObject(out: ObjectOutputStream): Unit = { + out.defaultWriteObject() + val size = acc.sizeLong + out.writeLong(size) + val st = acc.stepper + while (st.hasStep) + out.writeInt(st.nextStep()) + } + + private def readObject(in: ObjectInputStream): Unit = { + in.defaultReadObject() + val res = new IntAccumulator() + var elems = in.readLong() + while (elems > 0) { + res += in.readInt() + elems -= 1L + } + result = res + } + + private def readResolve(): AnyRef = result + } +} + +private[jdk] class IntAccumulatorStepper(private val acc: IntAccumulator) extends IntStepper with EfficientSplit { + import java.util.Spliterator._ + + private var h: Int = 0 + private var i: Int = 0 + private var a: Array[Int] = if (acc.hIndex > 0) acc.history(0) else acc.current + private var n: Long = if (acc.hIndex > 0) acc.cumulative(0) else acc.index + private var N: Long = acc.totalSize + + private def duplicateSelf(limit: Long): IntAccumulatorStepper = { + val ans = new IntAccumulatorStepper(acc) + ans.h = h + ans.i = i + ans.a = a + ans.n = n + ans.N = limit + ans + } + + private def loadMore(): Unit = { + h += 1 + if (h < acc.hIndex) { a = acc.history(h); n = acc.cumulative(h) - acc.cumulative(h-1) } + else { a = acc.current; n = acc.index } + i = 0 + } + + def characteristics: Int = ORDERED | SIZED | SUBSIZED | NONNULL + + def estimateSize: Long = N + + def hasStep: Boolean = N > 0 + + def nextStep(): Int = + if (N <= 0) throw new NoSuchElementException("next on empty Stepper") + else { + if (i >= n) loadMore() + val ans = a(i) + i += 1 + N -= 1 + ans + } + + def trySplit(): IntStepper = + if (N <= 1) null + else { + val half = N >> 1 + val M = (if (h <= 0) 0L else acc.cumulative(h-1)) + i + val R = M + half + val ans = duplicateSelf(half) + if (h < acc.hIndex) { + val w = acc.seekSlot(R) + h = (w >>> 32).toInt + if (h < acc.hIndex) { + a = acc.history(h) + n = acc.cumulative(h) - (if (h > 0) acc.cumulative(h-1) else 0) + } + else { + a = acc.current + n = acc.index + } + i = (w & 0xFFFFFFFFL).toInt + } + else i += half.toInt + N -= half + ans + } + + override def spliterator[B >: Int]: Spliterator.OfInt = new IntStepper.IntStepperSpliterator(this) { + // Overridden for efficiency + override def tryAdvance(c: IntConsumer): Boolean = + if (N <= 0) false + else { + if (i >= n) loadMore() + c.accept(a(i)) + i += 1 + N -= 1 + true + } + + // Overridden for efficiency + override def tryAdvance(c: Consumer[_ >: jl.Integer]): Boolean = (c: AnyRef) match { + case ic: IntConsumer => tryAdvance(ic) + case _ => + if (N <= 0) false + else { + if (i >= n) loadMore() + c.accept(a(i)) + i += 1 + N -= 1 + true + } + } + + // Overridden for efficiency + override def forEachRemaining(c: IntConsumer): Unit = + while (N > 0) { + if (i >= n) loadMore() + val i0 = i + if ((n-i) > N) n = i + N.toInt + while (i < n) { + c.accept(a(i)) + i += 1 + } + N -= (n - i0) + } + + // Overridden for efficiency + override def forEachRemaining(c: Consumer[_ >: jl.Integer]): Unit = (c: AnyRef) match { + case ic: IntConsumer => forEachRemaining(ic) + case _ => + while (N > 0) { + if (i >= n) loadMore() + val i0 = i + if ((n-i) > N) n = i + N.toInt + while (i < n) { + c.accept(a(i)) + i += 1 + } + N -= (n - i0) + } + } + } +} diff --git a/library-internal/src/scala/jdk/LongAccumulator.scala b/library-internal/src/scala/jdk/LongAccumulator.scala new file mode 100644 index 000000000000..38b868ae1111 --- /dev/null +++ b/library-internal/src/scala/jdk/LongAccumulator.scala @@ -0,0 +1,488 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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.jdk + +import java.io.{ObjectInputStream, ObjectOutputStream} +import java.util.Spliterator +import java.util.function.{Consumer, LongConsumer} +import java.{lang => jl} + +import scala.annotation._ +import scala.collection.Stepper.EfficientSplit +import scala.collection.{AnyStepper, Factory, LongStepper, SeqFactory, Stepper, StepperShape, mutable} +import scala.language.implicitConversions + +/** A specialized Accumulator that holds `Long`s without boxing, see [[Accumulator]]. */ +final class LongAccumulator + extends Accumulator[Long, AnyAccumulator, LongAccumulator] + with mutable.SeqOps[Long, AnyAccumulator, LongAccumulator] + with Serializable { + private[jdk] var current: Array[Long] = LongAccumulator.emptyLongArray + private[jdk] var history: Array[Array[Long]] = LongAccumulator.emptyLongArrayArray + + private[jdk] def cumulative(i: Int) = { val x = history(i); x(x.length-1) } + + override protected[this] def className: String = "LongAccumulator" + + def efficientStepper[S <: Stepper[_]](implicit shape: StepperShape[Long, S]): S with EfficientSplit = { + val st = new LongAccumulatorStepper(this) + val r = + if (shape.shape == StepperShape.LongShape) st + else { + assert(shape.shape == StepperShape.ReferenceShape, s"unexpected StepperShape: $shape") + AnyStepper.ofParLongStepper(st) + } + r.asInstanceOf[S with EfficientSplit] + } + + private def expand(): Unit = { + if (index > 0) { + current(current.length-1) = (if (hIndex > 0) { val x = history(hIndex-1); x(x.length-1) } else 0) + index + if (hIndex >= history.length) hExpand() + history(hIndex) = current + hIndex += 1 + } + current = new Array[Long](nextBlockSize+1) + index = 0 + } + + private def hExpand(): Unit = { + if (hIndex == 0) history = new Array[Array[Long]](4) + else history = java.util.Arrays.copyOf(history, history.length << 1) + } + + /** Appends an element to this `LongAccumulator`. */ + def addOne(a: Long): this.type = { + totalSize += 1 + if (index+1 >= current.length) expand() + current(index) = a + index += 1 + this + } + + /** Result collection consisting of all elements appended so far. */ + override def result(): LongAccumulator = this + + /** Removes all elements from `that` and appends them to this `LongAccumulator`. */ + def drain(that: LongAccumulator): Unit = { + var h = 0 + var prev = 0L + var more = true + while (more && h < that.hIndex) { + val cuml = that.cumulative(h) + val n = (cuml - prev).toInt + if (current.length - index - 1 >= n) { + System.arraycopy(that.history(h), 0, current, index, n) + prev = cuml + index += n + h += 1 + } + else more = false + } + if (h >= that.hIndex && current.length - index - 1>= that.index) { + if (that.index > 0) System.arraycopy(that.current, 0, current, index, that.index) + index += that.index + } + else { + val slots = (if (index > 0) 1 else 0) + that.hIndex - h + if (hIndex + slots > history.length) { + val n = math.max(4, 1 << (32 - jl.Integer.numberOfLeadingZeros(1 + hIndex + slots))) + history = java.util.Arrays.copyOf(history, n) + } + var pv = if (hIndex > 0) cumulative(hIndex-1) else 0L + if (index > 0) { + val x = + if (index < (current.length >>> 3) && current.length - 1 > 32) { + val ans = java.util.Arrays.copyOf(current, index + 1) + ans(ans.length - 1) = current(current.length - 1) + ans + } + else current + pv = pv + index + x(x.length - 1) = pv + history(hIndex) = x + hIndex += 1 + } + while (h < that.hIndex) { + val cuml = that.cumulative(h) + pv = pv + cuml - prev + prev = cuml + val x = that.history(h) + x(x.length - 1) = pv + history(hIndex) = x + h += 1 + hIndex += 1 + } + index = that.index + current = that.current + } + totalSize += that.totalSize + that.clear() + } + + override def clear(): Unit = { + super.clear() + current = LongAccumulator.emptyLongArray + history = LongAccumulator.emptyLongArrayArray + } + + /** Retrieves the `ix`th element. */ + def apply(ix: Long): Long = { + if (totalSize - ix <= index || hIndex == 0) current((ix - (totalSize - index)).toInt) + else { + val w = seekSlot(ix) + history((w >>> 32).toInt)((w & 0xFFFFFFFFL).toInt) + } + } + + /** Retrieves the `ix`th element, using an `Int` index. */ + def apply(i: Int): Long = apply(i.toLong) + + def update(idx: Long, elem: Long): Unit = { + if (totalSize - idx <= index || hIndex == 0) current((idx - (totalSize - index)).toInt) = elem + else { + val w = seekSlot(idx) + history((w >>> 32).toInt)((w & 0xFFFFFFFFL).toInt) = elem + } + } + + def update(idx: Int, elem: Long): Unit = update(idx.toLong, elem) + + /** Returns an `Iterator` over the contents of this `LongAccumulator`. The `Iterator` is not specialized. */ + def iterator: Iterator[Long] = stepper.iterator + + override def foreach[U](f: Long => U): Unit = { + val s = stepper + while (s.hasStep) f(s.nextStep()) + } + + def map(f: Long => Long): LongAccumulator = { + val b = newSpecificBuilder + val s = stepper + while (s.hasStep) + b.addOne(f(s.nextStep())) + b.result() + } + + def flatMap(f: Long => IterableOnce[Long]): LongAccumulator = { + val b = newSpecificBuilder + val s = stepper + while (s.hasStep) + b.addAll(f(s.nextStep())) + b.result() + } + + def collect(pf: PartialFunction[Long, Long]): LongAccumulator = { + val b = newSpecificBuilder + val s = stepper + while (s.hasStep) { + val n = s.nextStep() + pf.runWith(b.addOne)(n) + } + b.result() + } + + private def filterAccImpl(pred: Long => Boolean, not: Boolean): LongAccumulator = { + val b = newSpecificBuilder + val s = stepper + while (s.hasStep) { + val n = s.nextStep() + if (pred(n) != not) b.addOne(n) + } + b.result() + } + + override def filter(pred: Long => Boolean): LongAccumulator = filterAccImpl(pred, not = false) + + override def filterNot(pred: Long => Boolean): LongAccumulator = filterAccImpl(pred, not = true) + + override def forall(p: Long => Boolean): Boolean = { + val s = stepper + while (s.hasStep) + if (!p(s.nextStep())) return false + true + } + + override def exists(p: Long => Boolean): Boolean = { + val s = stepper + while (s.hasStep) + if (p(s.nextStep())) return true + false + } + + override def count(p: Long => Boolean): Int = { + var r = 0 + val s = stepper + while (s.hasStep) + if (p(s.nextStep())) r += 1 + r + } + + def countLong(p: Long => Boolean): Long = { + var r = 0L + val s = stepper + while (s.hasStep) + if (p(s.nextStep())) r += 1 + r + } + + /** Copies the elements in this `LongAccumulator` into an `Array[Long]` */ + @nowarn // cat=lint-overload see toArray[B: ClassTag] + def toArray: Array[Long] = { + if (totalSize > Int.MaxValue) throw new IllegalArgumentException("Too many elements accumulated for an array: "+totalSize.toString) + val a = new Array[Long](totalSize.toInt) + var j = 0 + var h = 0 + var pv = 0L + while (h < hIndex) { + val x = history(h) + val cuml = x(x.length-1) + val n = (cuml - pv).toInt + pv = cuml + System.arraycopy(x, 0, a, j, n) + j += n + h += 1 + } + System.arraycopy(current, 0, a, j, index) + j += index + a + } + + /** Copies the elements in this `LongAccumulator` to a `List` */ + override def toList: List[Long] = { + var ans: List[Long] = Nil + var i = index - 1 + while (i >= 0) { + ans = current(i) :: ans + i -= 1 + } + var h = hIndex - 1 + while (h >= 0) { + val a = history(h) + i = (cumulative(h) - (if (h == 0) 0L else cumulative(h-1))).toInt - 1 + while (i >= 0) { + ans = a(i) :: ans + i -= 1 + } + h -= 1 + } + ans + } + + /** + * Copy the elements in this `LongAccumulator` to a specified collection. + * Note that the target collection is not specialized. + * Usage example: `acc.to(Vector)` + */ + override def to[C1](factory: Factory[Long, C1]): C1 = { + if (totalSize > Int.MaxValue) throw new IllegalArgumentException("Too many elements accumulated for a Scala collection: "+totalSize.toString) + factory.fromSpecific(iterator) + } + + override protected def fromSpecific(coll: IterableOnce[Long]): LongAccumulator = LongAccumulator.fromSpecific(coll) + override protected def newSpecificBuilder: LongAccumulator = LongAccumulator.newBuilder + override def iterableFactory: SeqFactory[AnyAccumulator] = AnyAccumulator + + override def empty: LongAccumulator = LongAccumulator.empty + + private def writeReplace(): AnyRef = new LongAccumulator.SerializationProxy(this) +} + +object LongAccumulator extends collection.SpecificIterableFactory[Long, LongAccumulator] { + private val emptyLongArray = new Array[Long](0) + private val emptyLongArrayArray = new Array[Array[Long]](0) + + implicit def toJavaLongAccumulator(ia: LongAccumulator.type): collection.SpecificIterableFactory[jl.Long, LongAccumulator] = LongAccumulator.asInstanceOf[collection.SpecificIterableFactory[jl.Long, LongAccumulator]] + + import java.util.{function => jf} + + /** A `Supplier` of `LongAccumulator`s, suitable for use with `java.util.stream.LongStream`'s `collect` method. Suitable for `Stream[Long]` also. */ + def supplier: jf.Supplier[LongAccumulator] = () => new LongAccumulator + + /** A `BiConsumer` that adds an element to an `LongAccumulator`, suitable for use with `java.util.stream.LongStream`'s `collect` method. */ + def adder: jf.ObjLongConsumer[LongAccumulator] = (ac: LongAccumulator, a: Long) => ac addOne a + + /** A `BiConsumer` that adds a boxed `Long` to an `LongAccumulator`, suitable for use with `java.util.stream.Stream`'s `collect` method. */ + def boxedAdder: jf.BiConsumer[LongAccumulator, Long] = (ac: LongAccumulator, a: Long) => ac addOne a + + /** A `BiConsumer` that merges `LongAccumulator`s, suitable for use with `java.util.stream.LongStream`'s `collect` method. Suitable for `Stream[Long]` also. */ + def merger: jf.BiConsumer[LongAccumulator, LongAccumulator] = (a1: LongAccumulator, a2: LongAccumulator) => a1 drain a2 + + private def fromArray(a: Array[Long]): LongAccumulator = { + val r = new LongAccumulator + var i = 0 + while (i < a.length) { r addOne a(i); i += 1 } + r + } + + override def fromSpecific(it: IterableOnce[Long]): LongAccumulator = it match { + case acc: LongAccumulator => acc + case as: collection.immutable.ArraySeq.ofLong => fromArray(as.unsafeArray) + case as: collection.mutable.ArraySeq.ofLong => fromArray(as.array) // this case ensures Array(1).to(Accumulator) doesn't box + case _ => (new LongAccumulator).addAll(it) + } + + override def empty: LongAccumulator = new LongAccumulator + + override def newBuilder: LongAccumulator = new LongAccumulator + + class SerializationProxy[A](@transient private val acc: LongAccumulator) extends Serializable { + @transient private var result: LongAccumulator = _ + + private def writeObject(out: ObjectOutputStream): Unit = { + out.defaultWriteObject() + val size = acc.sizeLong + out.writeLong(size) + val st = acc.stepper + while (st.hasStep) + out.writeLong(st.nextStep()) + } + + private def readObject(in: ObjectInputStream): Unit = { + in.defaultReadObject() + val res = new LongAccumulator() + var elems = in.readLong() + while (elems > 0) { + res += in.readLong() + elems -= 1L + } + result = res + } + + private def readResolve(): AnyRef = result + } +} + +private[jdk] class LongAccumulatorStepper(private val acc: LongAccumulator) extends LongStepper with EfficientSplit { + import java.util.Spliterator._ + + private var h: Int = 0 + private var i: Int = 0 + private var a: Array[Long] = if (acc.hIndex > 0) acc.history(0) else acc.current + private var n: Long = if (acc.hIndex > 0) acc.cumulative(0) else acc.index + private var N: Long = acc.totalSize + + private def duplicateSelf(limit: Long): LongAccumulatorStepper = { + val ans = new LongAccumulatorStepper(acc) + ans.h = h + ans.i = i + ans.a = a + ans.n = n + ans.N = limit + ans + } + + private def loadMore(): Unit = { + h += 1 + if (h < acc.hIndex) { a = acc.history(h); n = acc.cumulative(h) - acc.cumulative(h-1) } + else { a = acc.current; n = acc.index } + i = 0 + } + + def characteristics: Int = ORDERED | SIZED | SUBSIZED | NONNULL + + def estimateSize: Long = N + + def hasStep: Boolean = N > 0 + + def nextStep(): Long = + if (n <= 0) throw new NoSuchElementException("next on empty Stepper") + else { + if (i >= n) loadMore() + val ans = a(i) + i += 1 + N -= 1 + ans + } + + def trySplit(): LongStepper = + if (N <= 1) null + else { + val half = N >> 1 + val M = (if (h <= 0) 0L else acc.cumulative(h-1)) + i + val R = M + half + val ans = duplicateSelf(half) + if (h < acc.hIndex) { + val w = acc.seekSlot(R) + h = (w >>> 32).toInt + if (h < acc.hIndex) { + a = acc.history(h) + n = acc.cumulative(h) - (if (h > 0) acc.cumulative(h-1) else 0) + } + else { + a = acc.current + n = acc.index + } + i = (w & 0xFFFFFFFFL).toInt + } + else i += half.toInt + N -= half + ans + } + + override def spliterator[B >: Long]: Spliterator.OfLong = new LongStepper.LongStepperSpliterator(this) { + // Overridden for efficiency + override def tryAdvance(c: LongConsumer): Boolean = + if (N <= 0) false + else { + if (i >= n) loadMore() + c.accept(a(i)) + i += 1 + N -= 1 + true + } + + // Overridden for efficiency + override def tryAdvance(c: Consumer[_ >: jl.Long]): Boolean = (c: AnyRef) match { + case ic: LongConsumer => tryAdvance(ic) + case _ => + if (N <= 0) false + else { + if (i >= n) loadMore() + c.accept(a(i)) + i += 1 + N -= 1 + true + } + } + + // Overridden for efficiency + override def forEachRemaining(c: LongConsumer): Unit = + while (N > 0) { + if (i >= n) loadMore() + val i0 = i + if ((n-i) > N) n = i + N.toInt + while (i < n) { + c.accept(a(i)) + i += 1 + } + N -= (n - i0) + } + + // Overridden for efficiency + override def forEachRemaining(c: Consumer[_ >: jl.Long]): Unit = (c: AnyRef) match { + case ic: LongConsumer => forEachRemaining(ic) + case _ => + while (N > 0) { + if (i >= n) loadMore() + val i0 = i + if ((n-i) > N) n = i + N.toInt + while (i < n) { + c.accept(a(i)) + i += 1 + } + N -= (n - i0) + } + } + } +} diff --git a/library-internal/src/scala/runtime/AbstractFunction0.scala b/library-internal/src/scala/runtime/AbstractFunction0.scala new file mode 100644 index 000000000000..c322efcd6281 --- /dev/null +++ b/library-internal/src/scala/runtime/AbstractFunction0.scala @@ -0,0 +1,19 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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. + */ + +// GENERATED CODE: DO NOT EDIT. See scala.Function0 for timestamp. + +package scala.runtime + +abstract class AbstractFunction0[@specialized(Specializable.Primitives) +R] extends Function0[R] { + +} diff --git a/library-internal/src/scala/runtime/AbstractFunction1.scala b/library-internal/src/scala/runtime/AbstractFunction1.scala new file mode 100644 index 000000000000..7b9527b610c1 --- /dev/null +++ b/library-internal/src/scala/runtime/AbstractFunction1.scala @@ -0,0 +1,19 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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. + */ + +// GENERATED CODE: DO NOT EDIT. See scala.Function0 for timestamp. + +package scala.runtime + +abstract class AbstractFunction1[@specialized(Specializable.Arg) -T1, @specialized(Specializable.Return) +R] extends Function1[T1, R] { + +} \ No newline at end of file diff --git a/library-internal/src/scala/runtime/AbstractFunction2.scala b/library-internal/src/scala/runtime/AbstractFunction2.scala new file mode 100644 index 000000000000..7c8d1628e545 --- /dev/null +++ b/library-internal/src/scala/runtime/AbstractFunction2.scala @@ -0,0 +1,19 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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. + */ + +// GENERATED CODE: DO NOT EDIT. See scala.Function0 for timestamp. + +package scala.runtime + +abstract class AbstractFunction2[@specialized(Specializable.Args) -T1, @specialized(Specializable.Args) -T2, @specialized(Specializable.Return) +R] extends Function2[T1, T2, R] { + +} diff --git a/library-internal/src/scala/runtime/AbstractPartialFunction.scala b/library-internal/src/scala/runtime/AbstractPartialFunction.scala new file mode 100644 index 000000000000..f4e8ae1b7818 --- /dev/null +++ b/library-internal/src/scala/runtime/AbstractPartialFunction.scala @@ -0,0 +1,36 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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 +package runtime + +/** `AbstractPartialFunction` reformulates all operations of its supertrait `PartialFunction` + * in terms of `isDefinedAt` and `applyOrElse`. + * + * This allows more efficient implementations in many cases: + * - optimized `orElse` method supports chained `orElse` in linear time, + * and with no slow-down if the `orElse` part is not needed. + * - optimized `lift` method helps to avoid double evaluation of pattern matchers & guards + * of partial function literals. + * + * This trait is used as a basis for implementation of all partial function literals. + */ +abstract class AbstractPartialFunction[@specialized(Specializable.Arg) -T1, @specialized(Specializable.Return) +R] extends Function1[T1, R] with PartialFunction[T1, R] { self => + // this method must be overridden for better performance, + // for backwards compatibility, fall back to the one inherited from PartialFunction + // this assumes the old-school partial functions override the apply method, though + // override def applyOrElse[A1 <: T1, B1 >: R](x: A1, default: A1 => B1): B1 = ??? + + // probably okay to make final since classes compiled before have overridden against the old version of AbstractPartialFunction + // let's not make it final so as not to confuse anyone + /*final*/ def apply(x: T1): R = applyOrElse(x, PartialFunction.empty) +} diff --git a/library-internal/src/scala/runtime/NonLocalReturnControl.scala b/library-internal/src/scala/runtime/NonLocalReturnControl.scala new file mode 100644 index 000000000000..025727b5d589 --- /dev/null +++ b/library-internal/src/scala/runtime/NonLocalReturnControl.scala @@ -0,0 +1,21 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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.runtime + +import scala.util.control.ControlThrowable + +// remove Unit specialization when binary compatibility permits +@annotation.nowarn("cat=lint-unit-specialization") +class NonLocalReturnControl[@specialized(Byte, Short, Int, Long, Char, Float, Double, Boolean, Unit) T](val key: AnyRef, val value: T) extends ControlThrowable { + final override def fillInStackTrace(): Throwable = this +} \ No newline at end of file diff --git a/library-internal/src/scala/util/Sorting.scala b/library-internal/src/scala/util/Sorting.scala new file mode 100644 index 000000000000..7e2da2434f82 --- /dev/null +++ b/library-internal/src/scala/util/Sorting.scala @@ -0,0 +1,302 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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 +package util + +import scala.reflect.ClassTag +import scala.math.Ordering + +/** The `Sorting` object provides convenience wrappers for `java.util.Arrays.sort`. + * Methods that defer to `java.util.Arrays.sort` say that they do or under what + * conditions that they do. + * + * `Sorting` also implements a general-purpose quicksort and stable (merge) sort + * for those cases where `java.util.Arrays.sort` could only be used at the cost + * of a large memory penalty. If performance rather than memory usage is the + * primary concern, one may wish to find alternate strategies to use + * `java.util.Arrays.sort` directly e.g. by boxing primitives to use + * a custom ordering on them. + * + * `Sorting` provides methods where you can provide a comparison function, or + * can request a sort of items that are [[scala.math.Ordered]] or that + * otherwise have an implicit or explicit [[scala.math.Ordering]]. + * + * Note also that high-performance non-default sorts for numeric types + * are not provided. If this is required, it is advisable to investigate + * other libraries that cover this use case. + */ +object Sorting { + /** Sort an array of Doubles using `java.util.Arrays.sort`. */ + def quickSort(a: Array[Double]): Unit = java.util.Arrays.sort(a) + + /** Sort an array of Ints using `java.util.Arrays.sort`. */ + def quickSort(a: Array[Int]): Unit = java.util.Arrays.sort(a) + + /** Sort an array of Floats using `java.util.Arrays.sort`. */ + def quickSort(a: Array[Float]): Unit = java.util.Arrays.sort(a) + + private final val qsortThreshold = 16 + + /** Sort array `a` with quicksort, using the Ordering on its elements. + * This algorithm sorts in place, so no additional memory is used aside from + * what might be required to box individual elements during comparison. + */ + def quickSort[K: Ordering](a: Array[K]): Unit = { + // Must have iN >= i0 or math will fail. Also, i0 >= 0. + def inner(a: Array[K], i0: Int, iN: Int, ord: Ordering[K]): Unit = { + if (iN - i0 < qsortThreshold) insertionSort(a, i0, iN, ord) + else { + val iK = (i0 + iN) >>> 1 // Unsigned div by 2 + // Find index of median of first, central, and last elements + var pL = + if (ord.compare(a(i0), a(iN - 1)) <= 0) + if (ord.compare(a(i0), a(iK)) < 0) + if (ord.compare(a(iN - 1), a(iK)) < 0) iN - 1 else iK + else i0 + else + if (ord.compare(a(i0), a(iK)) < 0) i0 + else + if (ord.compare(a(iN - 1), a(iK)) <= 0) iK + else iN - 1 + val pivot = a(pL) + // pL is the start of the pivot block; move it into the middle if needed + if (pL != iK) { a(pL) = a(iK); a(iK) = pivot; pL = iK } + // Elements equal to the pivot will be in range pL until pR + var pR = pL + 1 + // Items known to be less than pivot are below iA (range i0 until iA) + var iA = i0 + // Items known to be greater than pivot are at or above iB (range iB until iN) + var iB = iN + // Scan through everything in the buffer before the pivot(s) + while (pL - iA > 0) { + val current = a(iA) + ord.compare(current, pivot) match { + case 0 => + // Swap current out with pivot block + a(iA) = a(pL - 1) + a(pL - 1) = current + pL -= 1 + case x if x < 0 => + // Already in place. Just update indices. + iA += 1 + case _ if iB > pR => + // Wrong side. There's room on the other side, so swap + a(iA) = a(iB - 1) + a(iB - 1) = current + iB -= 1 + case _ => + // Wrong side and there is no room. Swap by rotating pivot block. + a(iA) = a(pL - 1) + a(pL - 1) = a(pR - 1) + a(pR - 1) = current + pL -= 1 + pR -= 1 + iB -= 1 + } + } + // Get anything remaining in buffer after the pivot(s) + while (iB - pR > 0) { + val current = a(iB - 1) + ord.compare(current, pivot) match { + case 0 => + // Swap current out with pivot block + a(iB - 1) = a(pR) + a(pR) = current + pR += 1 + case x if x > 0 => + // Already in place. Just update indices. + iB -= 1 + case _ => + // Wrong side and we already know there is no room. Swap by rotating pivot block. + a(iB - 1) = a(pR) + a(pR) = a(pL) + a(pL) = current + iA += 1 + pL += 1 + pR += 1 + } + } + // Use tail recursion on large half (Sedgewick's method) so we don't blow up the stack if pivots are poorly chosen + if (iA - i0 < iN - iB) { + inner(a, i0, iA, ord) // True recursion + inner(a, iB, iN, ord) // Should be tail recursion + } + else { + inner(a, iB, iN, ord) // True recursion + inner(a, i0, iA, ord) // Should be tail recursion + } + } + } + inner(a, 0, a.length, implicitly[Ordering[K]]) + } + + private final val mergeThreshold = 32 + + // Ordering[T] might be slow especially for boxed primitives, so use binary search variant of insertion sort + // Caller must pass iN >= i0 or math will fail. Also, i0 >= 0. + private def insertionSort[@specialized T](a: Array[T], i0: Int, iN: Int, ord: Ordering[T]): Unit = { + val n = iN - i0 + if (n < 2) return + if (ord.compare(a(i0), a(i0+1)) > 0) { + val temp = a(i0) + a(i0) = a(i0+1) + a(i0+1) = temp + } + var m = 2 + while (m < n) { + // Speed up already-sorted case by checking last element first + val next = a(i0 + m) + if (ord.compare(next, a(i0+m-1)) < 0) { + var iA = i0 + var iB = i0 + m - 1 + while (iB - iA > 1) { + val ix = (iA + iB) >>> 1 // Use bit shift to get unsigned div by 2 + if (ord.compare(next, a(ix)) < 0) iB = ix + else iA = ix + } + val ix = iA + (if (ord.compare(next, a(iA)) < 0) 0 else 1) + var i = i0 + m + while (i > ix) { + a(i) = a(i-1) + i -= 1 + } + a(ix) = next + } + m += 1 + } + } + + // Caller is required to pass iN >= i0, else math will fail. Also, i0 >= 0. + private def mergeSort[@specialized T: ClassTag](a: Array[T], i0: Int, iN: Int, ord: Ordering[T], scratch: Array[T] = null): Unit = { + if (iN - i0 < mergeThreshold) insertionSort(a, i0, iN, ord) + else { + val iK = (i0 + iN) >>> 1 // Bit shift equivalent to unsigned math, no overflow + val sc = if (scratch eq null) new Array[T](iK - i0) else scratch + mergeSort(a, i0, iK, ord, sc) + mergeSort(a, iK, iN, ord, sc) + mergeSorted(a, i0, iK, iN, ord, sc) + } + } + + // Must have 0 <= i0 < iK < iN + private def mergeSorted[@specialized T](a: Array[T], i0: Int, iK: Int, iN: Int, ord: Ordering[T], scratch: Array[T]): Unit = { + // Check to make sure we're not already in order + if (ord.compare(a(iK-1), a(iK)) > 0) { + var i = i0 + val jN = iK - i0 + var j = 0 + while (i < iK) { + scratch (j) = a(i) + i += 1 + j += 1 + } + var k = i0 + j = 0 + while (i < iN && j < jN) { + if (ord.compare(a(i), scratch(j)) < 0) { a(k) = a(i); i += 1 } + else { a(k) = scratch(j); j += 1 } + k += 1 + } + while (j < jN) { a(k) = scratch(j); j += 1; k += 1 } + // Don't need to finish a(i) because it's already in place, k = i + } + } + + // Why would you even do this? + private def booleanSort(a: Array[Boolean], from: Int, until: Int): Unit = { + var i = from + var n = 0 + while (i < until) { + if (!a(i)) n += 1 + i += 1 + } + i = 0 + while (i < n) { + a(from + i) = false + i += 1 + } + while (from + i < until) { + a(from + i) = true + i += 1 + } + } + + // TODO: add upper bound: T <: AnyRef, propagate to callers below (not binary compatible) + // Maybe also rename all these methods to `sort`. + @inline private def sort[T](a: Array[T], from: Int, until: Int, ord: Ordering[T]): Unit = (a: @unchecked) match { + case _: Array[AnyRef] => + // Note that runtime matches are covariant, so could actually be any Array[T] s.t. T is not primitive (even boxed value classes) + if (a.length > 1 && (ord eq null)) throw new NullPointerException("Ordering") + java.util.Arrays.sort(a, from, until, ord) + case a: Array[Int] => if (ord eq Ordering.Int) java.util.Arrays.sort(a, from, until) else mergeSort[Int](a, from, until, ord) + case a: Array[Double] => mergeSort[Double](a, from, until, ord) // Because not all NaNs are identical, stability is meaningful! + case a: Array[Long] => if (ord eq Ordering.Long) java.util.Arrays.sort(a, from, until) else mergeSort[Long](a, from, until, ord) + case a: Array[Float] => mergeSort[Float](a, from, until, ord) // Because not all NaNs are identical, stability is meaningful! + case a: Array[Char] => if (ord eq Ordering.Char) java.util.Arrays.sort(a, from, until) else mergeSort[Char](a, from, until, ord) + case a: Array[Byte] => if (ord eq Ordering.Byte) java.util.Arrays.sort(a, from, until) else mergeSort[Byte](a, from, until, ord) + case a: Array[Short] => if (ord eq Ordering.Short) java.util.Arrays.sort(a, from, until) else mergeSort[Short](a, from, until, ord) + case a: Array[Boolean] => if (ord eq Ordering.Boolean) booleanSort(a, from, until) else mergeSort[Boolean](a, from, until, ord) + // Array[Unit] is matched as an Array[AnyRef] due to covariance in runtime matching. Not worth catching it as a special case. + case null => throw new NullPointerException + } + + /** Sort array `a` using the Ordering on its elements, preserving the original ordering where possible. + * Uses `java.util.Arrays.sort` unless `K` is a primitive type. This is the same as `stableSort(a, 0, a.length)`. */ + @`inline` def stableSort[K: Ordering](a: Array[K]): Unit = stableSort(a, 0, a.length) + + /** Sort array `a` or a part of it using the Ordering on its elements, preserving the original ordering where possible. + * Uses `java.util.Arrays.sort` unless `K` is a primitive type. + * + * @param a The array to sort + * @param from The first index in the array to sort + * @param until The last index (exclusive) in the array to sort + */ + def stableSort[K: Ordering](a: Array[K], from: Int, until: Int): Unit = sort(a, from, until, Ordering[K]) + + /** Sort array `a` using function `f` that computes the less-than relation for each element. + * Uses `java.util.Arrays.sort` unless `K` is a primitive type. This is the same as `stableSort(a, f, 0, a.length)`. */ + @`inline` def stableSort[K](a: Array[K], f: (K, K) => Boolean): Unit = stableSort(a, f, 0, a.length) + + // TODO: make this fast for primitive K (could be specialized if it didn't go through Ordering) + /** Sort array `a` or a part of it using function `f` that computes the less-than relation for each element. + * Uses `java.util.Arrays.sort` unless `K` is a primitive type. + * + * @param a The array to sort + * @param f A function that computes the less-than relation for each element + * @param from The first index in the array to sort + * @param until The last index (exclusive) in the array to sort + */ + def stableSort[K](a: Array[K], f: (K, K) => Boolean, from: Int, until: Int): Unit = sort(a, from, until, Ordering fromLessThan f) + + /** A sorted Array, using the Ordering for the elements in the sequence `a`. Uses `java.util.Arrays.sort` unless `K` is a primitive type. */ + def stableSort[K: ClassTag: Ordering](a: scala.collection.Seq[K]): Array[K] = { + val ret = a.toArray + sort(ret, 0, ret.length, Ordering[K]) + ret + } + + // TODO: make this fast for primitive K (could be specialized if it didn't go through Ordering) + /** A sorted Array, given a function `f` that computes the less-than relation for each item in the sequence `a`. Uses `java.util.Arrays.sort` unless `K` is a primitive type. */ + def stableSort[K: ClassTag](a: scala.collection.Seq[K], f: (K, K) => Boolean): Array[K] = { + val ret = a.toArray + sort(ret, 0, ret.length, Ordering fromLessThan f) + ret + } + + /** A sorted Array, given an extraction function `f` that returns an ordered key for each item in the sequence `a`. Uses `java.util.Arrays.sort` unless `K` is a primitive type. */ + def stableSort[K: ClassTag, M: Ordering](a: scala.collection.Seq[K], f: K => M): Array[K] = { + val ret = a.toArray + sort(ret, 0, ret.length, Ordering[M] on f) + ret + } +} diff --git a/library-internal/src/scala/util/hashing/MurmurHash3.scala b/library-internal/src/scala/util/hashing/MurmurHash3.scala new file mode 100644 index 000000000000..92967006dfa2 --- /dev/null +++ b/library-internal/src/scala/util/hashing/MurmurHash3.scala @@ -0,0 +1,482 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. dba Akka + * + * 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 +package util.hashing + +import java.lang.Integer.{ rotateLeft => rotl } + +private[hashing] class MurmurHash3 { + /** Mix in a block of data into an intermediate hash value. */ + final def mix(hash: Int, data: Int): Int = { + var h = mixLast(hash, data) + h = rotl(h, 13) + h * 5 + 0xe6546b64 + } + + /** May optionally be used as the last mixing step. Is a little bit faster than mix, + * as it does no further mixing of the resulting hash. For the last element this is not + * necessary as the hash is thoroughly mixed during finalization anyway. */ + final def mixLast(hash: Int, data: Int): Int = { + var k = data + + k *= 0xcc9e2d51 + k = rotl(k, 15) + k *= 0x1b873593 + + hash ^ k + } + + /** Finalize a hash to incorporate the length and make sure all bits avalanche. */ + final def finalizeHash(hash: Int, length: Int): Int = avalanche(hash ^ length) + + /** Force all bits of the hash to avalanche. Used for finalizing the hash. */ + private final def avalanche(hash: Int): Int = { + var h = hash + + h ^= h >>> 16 + h *= 0x85ebca6b + h ^= h >>> 13 + h *= 0xc2b2ae35 + h ^= h >>> 16 + + h + } + + private[scala] def tuple2Hash(x: Int, y: Int, seed: Int): Int = { + var h = seed + h = mix(h, "Tuple2".hashCode) + h = mix(h, x) + h = mix(h, y) + finalizeHash(h, 2) + } + + // @deprecated("use `caseClassHash` instead", "2.13.17") + // The deprecation is commented because this method is called by the synthetic case class hashCode. + // In this case, the `seed` already has the case class name mixed in and `ignorePrefix` is set to true. + // Case classes compiled before 2.13.17 call this method with `productSeed` and `ignorePrefix = false`. + // See `productHashCode` in `SyntheticMethods` for details. + final def productHash(x: Product, seed: Int, ignorePrefix: Boolean = false): Int = { + val arr = x.productArity + if (arr == 0) + if (!ignorePrefix) x.productPrefix.hashCode else seed + else { + var h = seed + if (!ignorePrefix) h = mix(h, x.productPrefix.hashCode) + var i = 0 + while (i < arr) { + h = mix(h, x.productElement(i).##) + i += 1 + } + finalizeHash(h, arr) + } + } + + /** See the [[MurmurHash3.caseClassHash(x:Product,caseClassName:String)]] overload */ + final def caseClassHash(x: Product, seed: Int, caseClassName: String): Int = { + val arr = x.productArity + val aye = (if (caseClassName != null) caseClassName else x.productPrefix).hashCode + if (arr == 0) aye + else { + var h = seed + h = mix(h, aye) + var i = 0 + while (i < arr) { + h = mix(h, x.productElement(i).##) + i += 1 + } + finalizeHash(h, arr) + } + } + + + /** Compute the hash of a string */ + final def stringHash(str: String, seed: Int): Int = { + var h = seed + var i = 0 + while (i + 1 < str.length) { + val data = (str.charAt(i) << 16) + str.charAt(i + 1) + h = mix(h, data) + i += 2 + } + if (i < str.length) h = mixLast(h, str.charAt(i).toInt) + finalizeHash(h, str.length) + } + + /** Compute a hash that is symmetric in its arguments - that is a hash + * where the order of appearance of elements does not matter. + * This is useful for hashing sets, for example. + */ + final def unorderedHash(xs: IterableOnce[Any], seed: Int): Int = { + var a, b, n = 0 + var c = 1 + val iterator = xs.iterator + while (iterator.hasNext) { + val x = iterator.next() + val h = x.## + a += h + b ^= h + c *= h | 1 + n += 1 + } + var h = seed + h = mix(h, a) + h = mix(h, b) + h = mixLast(h, c) + finalizeHash(h, n) + } + + /** Compute a hash that depends on the order of its arguments. Potential range + * hashes are recognized to produce a hash that is compatible with rangeHash. + */ + final def orderedHash(xs: IterableOnce[Any], seed: Int): Int = { + val it = xs.iterator + var h = seed + if(!it.hasNext) return finalizeHash(h, 0) + val x0 = it.next() + if(!it.hasNext) return finalizeHash(mix(h, x0.##), 1) + val x1 = it.next() + + val initial = x0.## + h = mix(h, initial) + val h0 = h + var prev = x1.## + val rangeDiff = prev - initial + var i = 2 + while (it.hasNext) { + h = mix(h, prev) + val hash = it.next().## + if(rangeDiff != hash - prev || rangeDiff == 0) { + h = mix(h, hash) + i += 1 + while (it.hasNext) { + h = mix(h, it.next().##) + i += 1 + } + return finalizeHash(h, i) + } + prev = hash + i += 1 + } + avalanche(mix(mix(h0, rangeDiff), prev)) + + } + + /** Compute the hash of an array. Potential range hashes are recognized to produce a + * hash that is compatible with rangeHash. + */ + final def arrayHash[@specialized T](a: Array[T], seed: Int): Int = { + var h = seed + val l = a.length + l match { + case 0 => + finalizeHash(h, 0) + case 1 => + finalizeHash(mix(h, a(0).##), 1) + case _ => + val initial = a(0).## + h = mix(h, initial) + val h0 = h + var prev = a(1).## + val rangeDiff = prev - initial + var i = 2 + while (i < l) { + h = mix(h, prev) + val hash = a(i).## + if(rangeDiff != hash - prev || rangeDiff == 0) { + h = mix(h, hash) + i += 1 + while (i < l) { + h = mix(h, a(i).##) + i += 1 + } + return finalizeHash(h, l) + } + prev = hash + i += 1 + } + avalanche(mix(mix(h0, rangeDiff), prev)) + } + } + + /** Compute the hash of a Range with at least 2 elements. Ranges with fewer + * elements need to use seqHash instead. The `last` parameter must be the + * actual last element produced by a Range, not the nominal `end`. + */ + final def rangeHash(start: Int, step: Int, last: Int, seed: Int): Int = + avalanche(mix(mix(mix(seed, start), step), last)) + + /** Compute the hash of a byte array. Faster than arrayHash, because + * it hashes 4 bytes at once. Note that the result is not compatible with + * arrayHash! + */ + final def bytesHash(data: Array[Byte], seed: Int): Int = { + var len = data.length + var h = seed + + // Body + var i = 0 + while(len >= 4) { + var k = data(i + 0) & 0xFF + k |= (data(i + 1) & 0xFF) << 8 + k |= (data(i + 2) & 0xFF) << 16 + k |= (data(i + 3) & 0xFF) << 24 + + h = mix(h, k) + + i += 4 + len -= 4 + } + + // Tail + var k = 0 + if(len == 3) k ^= (data(i + 2) & 0xFF) << 16 + if(len >= 2) k ^= (data(i + 1) & 0xFF) << 8 + if(len >= 1) { + k ^= (data(i + 0) & 0xFF) + h = mixLast(h, k) + } + + // Finalization + finalizeHash(h, data.length) + } + + /** Compute the hash of an IndexedSeq. Potential range hashes are recognized to produce a + * hash that is compatible with rangeHash. + */ + final def indexedSeqHash(a: scala.collection.IndexedSeq[Any], seed: Int): Int = { + var h = seed + val l = a.length + l match { + case 0 => + finalizeHash(h, 0) + case 1 => + finalizeHash(mix(h, a(0).##), 1) + case _ => + val initial = a(0).## + h = mix(h, initial) + val h0 = h + var prev = a(1).## + val rangeDiff = prev - initial + var i = 2 + while (i < l) { + h = mix(h, prev) + val hash = a(i).## + if(rangeDiff != hash - prev || rangeDiff == 0) { + h = mix(h, hash) + i += 1 + while (i < l) { + h = mix(h, a(i).##) + i += 1 + } + return finalizeHash(h, l) + } + prev = hash + i += 1 + } + avalanche(mix(mix(h0, rangeDiff), prev)) + } + } + + /** Compute the hash of a List. Potential range hashes are recognized to produce a + * hash that is compatible with rangeHash. + */ + final def listHash(xs: scala.collection.immutable.List[_], seed: Int): Int = { + var n = 0 + var h = seed + var rangeState = 0 // 0 = no data, 1 = first elem read, 2 = has valid diff, 3 = invalid + var rangeDiff = 0 + var prev = 0 + var initial = 0 + var elems = xs + while (!elems.isEmpty) { + val head = elems.head + val tail = elems.tail + val hash = head.## + h = mix(h, hash) + rangeState match { + case 0 => + initial = hash + rangeState = 1 + case 1 => + rangeDiff = hash - prev + rangeState = 2 + case 2 => + if(rangeDiff != hash - prev || rangeDiff == 0) rangeState = 3 + case _ => + } + prev = hash + n += 1 + elems = tail + } + if(rangeState == 2) rangeHash(initial, rangeDiff, prev, seed) + else finalizeHash(h, n) + } +} + +/** + * An implementation of Austin Appleby's MurmurHash 3 algorithm + * (MurmurHash3_x86_32). This object contains methods that hash + * values of various types as well as means to construct `Hashing` + * objects. + * + * This algorithm is designed to generate well-distributed non-cryptographic + * hashes. It is designed to hash data in 32 bit chunks (ints). + * + * The mix method needs to be called at each step to update the intermediate + * hash value. For the last chunk to incorporate into the hash mixLast may + * be used instead, which is slightly faster. Finally finalizeHash needs to + * be called to compute the final hash value. + * + * This is based on the earlier MurmurHash3 code by Rex Kerr, but the + * MurmurHash3 algorithm was since changed by its creator Austin Appleby + * to remedy some weaknesses and improve performance. This represents the + * latest and supposedly final version of the algorithm (revision 136). Even + * so, test the generated hashes in between Scala versions, even for point + * releases, as fast, non-cryptographic hashing algorithms evolve rapidly. + * + * @see [[https://github.com/aappleby/smhasher]] + */ +object MurmurHash3 extends MurmurHash3 { + final val arraySeed = 0x3c074a61 + final val stringSeed = 0xf7ca7fd2 + final val productSeed = 0xcafebabe + final val symmetricSeed = 0xb592f7ae + final val traversableSeed = 0xe73a8b15 + final val seqSeed = "Seq".hashCode + final val mapSeed = "Map".hashCode + final val setSeed = "Set".hashCode + + def arrayHash[@specialized T](a: Array[T]): Int = arrayHash(a, arraySeed) + def bytesHash(data: Array[Byte]): Int = bytesHash(data, arraySeed) + def orderedHash(xs: IterableOnce[Any]): Int = orderedHash(xs, symmetricSeed) + def stringHash(x: String): Int = stringHash(x, stringSeed) + def unorderedHash(xs: IterableOnce[Any]): Int = unorderedHash(xs, traversableSeed) + def rangeHash(start: Int, step: Int, last: Int): Int = rangeHash(start, step, last, seqSeed) + + @deprecated("use `caseClassHash` instead", "2.13.17") + def productHash(x: Product): Int = caseClassHash(x, productSeed, null) + + /** + * Compute the `hashCode` of a case class instance. This method returns the same value as `x.hashCode` + * if `x` is an instance of a case class with the default, synthetic `hashCode`. + * + * This method can be used to implement case classes with a cached `hashCode`: + * {{{ + * case class C(data: Data) { + * override lazy val hashCode: Int = MurmurHash3.caseClassHash(this) + * } + * }}} + * + * '''NOTE''': For case classes (or subclasses) that override `productPrefix`, the `caseClassName` parameter + * needs to be specified in order to obtain the same result as the synthetic `hashCode`. Otherwise, the value + * is not in sync with the case class `equals` method (scala/bug#13033). + * + * {{{ + * scala> case class C(x: Int) { override def productPrefix = "Y" } + * + * scala> C(1).hashCode + * val res0: Int = -668012062 + * + * scala> MurmurHash3.caseClassHash(C(1)) + * val res1: Int = 1015658380 + * + * scala> MurmurHash3.caseClassHash(C(1), "C") + * val res2: Int = -668012062 + * }}} + */ + def caseClassHash(x: Product, caseClassName: String = null): Int = caseClassHash(x, productSeed, caseClassName) + + private[scala] def arraySeqHash[@specialized T](a: Array[T]): Int = arrayHash(a, seqSeed) + private[scala] def tuple2Hash(x: Any, y: Any): Int = tuple2Hash(x.##, y.##, productSeed) + + /** To offer some potential for optimization. + */ + def seqHash(xs: scala.collection.Seq[_]): Int = xs match { + case xs: scala.collection.IndexedSeq[_] => indexedSeqHash(xs, seqSeed) + case xs: List[_] => listHash(xs, seqSeed) + case xs => orderedHash(xs, seqSeed) + } + + def mapHash(xs: scala.collection.Map[_, _]): Int = { + if (xs.isEmpty) emptyMapHash + else { + class accum extends Function2[Any, Any, Unit] { + var a, b, n = 0 + var c = 1 + override def apply(k: Any, v: Any): Unit = { + val h = tuple2Hash(k, v) + a += h + b ^= h + c *= h | 1 + n += 1 + } + } + val accum = new accum + var h = mapSeed + xs.foreachEntry(accum) + h = mix(h, accum.a) + h = mix(h, accum.b) + h = mixLast(h, accum.c) + finalizeHash(h, accum.n) + } + } + + private[scala] val emptyMapHash = unorderedHash(Nil, mapSeed) + def setHash(xs: scala.collection.Set[_]): Int = unorderedHash(xs, setSeed) + + class ArrayHashing[@specialized T] extends Hashing[Array[T]] { + def hash(a: Array[T]) = arrayHash(a) + } + + def arrayHashing[@specialized T] = new ArrayHashing[T] + + def bytesHashing = new Hashing[Array[Byte]] { + def hash(data: Array[Byte]) = bytesHash(data) + } + + def orderedHashing = new Hashing[IterableOnce[Any]] { + def hash(xs: IterableOnce[Any]) = orderedHash(xs) + } + + @deprecated("use `caseClassHashing` instead", "2.13.17") + def productHashing = new Hashing[Product] { + def hash(x: Product) = caseClassHash(x) + } + + def caseClassHashing = new Hashing[Product] { + def hash(x: Product) = caseClassHash(x) + } + + def stringHashing = new Hashing[String] { + def hash(x: String) = stringHash(x) + } + + def unorderedHashing = new Hashing[IterableOnce[Any]] { + def hash(xs: IterableOnce[Any]) = unorderedHash(xs) + } + +// /** All this trouble and foreach still appears faster. +// * Leaving in place in case someone would like to investigate further. +// */ +// def linearSeqHash(xs: scala.collection.LinearSeq[_], seed: Int): Int = { +// var n = 0 +// var h = seed +// var elems = xs +// while (elems.nonEmpty) { +// h = mix(h, elems.head.##) +// n += 1 +// elems = elems.tail +// } +// finalizeHash(h, n) +// } +} \ No newline at end of file diff --git a/project/Build.scala b/project/Build.scala index 0c057b6a7884..6ef082bdf36b 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -23,7 +23,6 @@ import sbt.Package.ManifestAttributes import sbt.PublishBinPlugin.autoImport._ import dotty.tools.sbtplugin.RepublishPlugin import dotty.tools.sbtplugin.RepublishPlugin.autoImport._ -import dotty.tools.sbtplugin.ScalaLibraryPlugin import sbt.plugins.SbtPlugin import sbt.ScriptedPlugin.autoImport._ @@ -1144,6 +1143,21 @@ object Build { lazy val `scala3-library` = project.in(file("library")).asDottyLibrary(NonBootstrapped) lazy val `scala3-library-bootstrapped`: Project = project.in(file("library")).asDottyLibrary(Bootstrapped) + lazy val `scala-library-internal` = project.in(file("library-internal")) + .settings(commonSettings) + .settings( + scalaVersion := "2.13.16" + ) + + lazy val `scala-library-internal-tasty` = project.in(file("library-internal-tasty")) + .withCommonSettings(Bootstrapped) + .dependsOn(dottyCompiler(Bootstrapped) % "provided; compile->runtime; test->test") + .settings( + scalacOptions := Seq("-Werror:false", "-Ycompile-scala2-library"), + (Compile / sources) := (`scala-library-internal` / Compile / sources).value.filterNot(_.getPath.endsWith("AnyVal.scala")), + (Compile / packageBin / mappings) := (Compile / packageBin / mappings).value.filter(_._2.endsWith(".tasty")) + ) + def dottyLibrary(implicit mode: Mode): Project = mode match { case NonBootstrapped => `scala3-library` case Bootstrapped => `scala3-library-bootstrapped` @@ -1220,23 +1234,25 @@ object Build { * * This version of the library is not (yet) TASTy/binary compatible with the Scala 2 compiled library. */ - lazy val `scala2-library-bootstrapped` = project.in(file("scala2-library-bootstrapped")). - enablePlugins(ScalaLibraryPlugin). - withCommonSettings(Bootstrapped). - dependsOn(dottyCompiler(Bootstrapped) % "provided; compile->runtime; test->test"). - settings(scala2LibraryBootstrappedSettings). - settings(moduleName := "scala2-library") + lazy val `scala2-library-bootstrapped` = project.in(file("scala2-library-bootstrapped")) + .withCommonSettings(Bootstrapped) + .dependsOn(dottyCompiler(Bootstrapped) % "provided; compile->runtime; test->test") + .dependsOn(`scala-library-internal-tasty` % "provided", `scala-library-internal` % "provided") + .settings(scala2LibraryBootstrappedSettings) + .settings(moduleName := "scala2-library") + // -Ycheck:all is set in project/scripts/scala2-library-tasty-mima.sh /** Scala 2 library compiled by dotty using the latest published sources of the library. * * This version of the library is not (yet) TASTy/binary compatible with the Scala 2 compiled library. */ - lazy val `scala2-library-cc` = project.in(file("scala2-library-cc")). - withCommonSettings(Bootstrapped). - dependsOn(dottyCompiler(Bootstrapped) % "provided; compile->runtime; test->test"). - settings(scala2LibraryBootstrappedSettings). - settings(moduleName := "scala2-library-cc") + lazy val `scala2-library-cc` = project.in(file("scala2-library-cc")) + .withCommonSettings(Bootstrapped) + .dependsOn(dottyCompiler(Bootstrapped) % "provided; compile->runtime; test->test") + .dependsOn(`scala-library-internal-tasty` % "provided", `scala-library-internal` % "provided") + .settings(scala2LibraryBootstrappedSettings) + .settings(moduleName := "scala2-library-cc") lazy val scala2LibraryBootstrappedSettings = Seq( javaOptions := (`scala3-compiler-bootstrapped` / javaOptions).value, @@ -1279,11 +1295,38 @@ object Build { // sources from https://github.com/scala/scala/tree/2.13.x/src/library-aux val path = file.getPath.replace('\\', '/') path.endsWith("scala-library-src/scala/Any.scala") || - path.endsWith("scala-library-src/scala/AnyVal.scala") || path.endsWith("scala-library-src/scala/AnyRef.scala") || path.endsWith("scala-library-src/scala/Nothing.scala") || path.endsWith("scala-library-src/scala/Null.scala") || - path.endsWith("scala-library-src/scala/Singleton.scala") + path.endsWith("scala-library-src/scala/Singleton.scala") || + // Ignore sources with @specialised in `scala` and non-compilable `AnyVal` + path.endsWith("scala-library-src/scala/AnyVal.scala") || + path.endsWith("scala-library-src/scala/Function0.scala") || + path.endsWith("scala-library-src/scala/Function1.scala") || + path.endsWith("scala-library-src/scala/Function2.scala") || + path.endsWith("scala-library-src/scala/Product1.scala") || + path.endsWith("scala-library-src/scala/Product2.scala") || + path.endsWith("scala-library-src/scala/Tuple1.scala") || + path.endsWith("scala-library-src/scala/Tuple2.scala") || + // Ignore sources with @specialised in `scala.collection` + path.endsWith("scala-library-src/scala/collection/Stepper.scala") || + path.endsWith("scala-library-src/scala/collection/ArrayOps.scala") || + path.endsWith("scala-library-src/scala/collection/immutable/Vector.scala") || + // Ignore sources with @specialised in `scala.jdk` + path.endsWith("scala-library-src/scala/jdk/Accumulator.scala") || + path.endsWith("scala-library-src/scala/jdk/DoubleAccumulator.scala") || + path.endsWith("scala-library-src/scala/jdk/IntAccumulator.scala") || + path.endsWith("scala-library-src/scala/jdk/LongAccumulator.scala") || + path.endsWith("scala-library-src/scala/jdk/FunctionWrappers.scala") || + // Ignore sources with @specialised in `scala.util` + path.endsWith("scala-library-src/scala/util/Sorting.scala") || + path.endsWith("scala-library-src/scala/util/hashing/MurmurHash3.scala") || + // Ignore sources with @specialised in `scala.runtime` + path.endsWith("scala-library-src/scala/runtime/NonLocalReturnControl.scala") || + path.endsWith("scala-library-src/scala/runtime/AbstractFunction0.scala") || + path.endsWith("scala-library-src/scala/runtime/AbstractFunction1.scala") || + path.endsWith("scala-library-src/scala/runtime/AbstractFunction2.scala") || + path.endsWith("scala-library-src/scala/runtime/AbstractPartialFunction.scala") } // These sources should be never compiled, filtering them out was not working correctly sometimes ignoredSources.foreach(_.delete()) @@ -1300,10 +1343,13 @@ object Build { (Test / managedClasspath) ~= { _.filterNot(file => file.data.getName == s"scala-library-$stdlibBootstrappedVersion.jar") }, + (Compile / packageBin / mappings) ++= (`scala-library-internal` / Compile / packageBin / mappings).value, + (Compile / packageBin / mappings) ++= (`scala-library-internal-tasty` / Compile / packageBin / mappings).value, mimaCheckDirection := "both", mimaBackwardIssueFilters := Scala2LibraryBootstrappedMiMaFilters.BackwardsBreakingChanges, mimaForwardIssueFilters := Scala2LibraryBootstrappedMiMaFilters.ForwardsBreakingChanges, customMimaReportBinaryIssues("Scala2LibraryBootstrappedMiMaFilters"), + mimaCurrentClassfiles := (Compile / packageBin).value, mimaPreviousArtifacts += "org.scala-lang" % "scala-library" % stdlibBootstrappedVersion, mimaExcludeAnnotations ++= Seq( "scala.annotation.experimental", @@ -1314,8 +1360,8 @@ object Build { tastyMiMaPreviousArtifacts += "org.scala-lang" % "scala-library" % stdlibBootstrappedVersion, tastyMiMaCurrentClasspath := { val javaBootCp = tastyMiMaJavaBootClasspath.value - val classDir = (Compile / classDirectory).value.toPath() - val cp0 = Attributed.data((Compile / fullClasspath).value).map(_.toPath()) + val classDir = (Compile / packageBin).value.toPath() + val cp0 = Attributed.data((Compile / fullClasspath).value).map(_.toPath()).filterNot(_.toString().contains("library-internal")) val cp: Seq[Path] = classDir +: (javaBootCp ++ cp0) (cp, classDir) }, @@ -2582,9 +2628,11 @@ object ScaladocConfigs { def defaultSourceLinks(version: String = dottyNonBootstrappedVersion, refVersion: String = dottyVersion) = Def.task { def stdLibVersion = stdlibVersion(NonBootstrapped) def srcManaged(v: String, s: String) = s"out/bootstrap/scala2-library-bootstrapped/scala-$v/src_managed/main/$s-library-src" + def srcManaged2 = s"library-internal/src" SourceLinks( List( scalaSrcLink(stdLibVersion, srcManaged(version, "scala") + "="), + scalaSrcLink(stdLibVersion, srcManaged2 + "="), dottySrcLink(refVersion, "library/src=", "#library/src"), dottySrcLink(refVersion), "docs=github://scala/scala3/main#docs" @@ -2671,6 +2719,7 @@ object ScaladocConfigs { lazy val Scala3 = Def.task { val dottyJars: Seq[java.io.File] = Seq( (`scala2-library-bootstrapped`/Compile/products).value, + (`scala-library-internal-tasty`/Compile/products).value, (`scala3-library-bootstrapped`/Compile/products).value, (`scala3-interfaces`/Compile/products).value, (`tasty-core-bootstrapped`/Compile/products).value, @@ -2737,6 +2786,7 @@ object ScaladocConfigs { .withTargets( Seq( s"out/bootstrap/scala2-library-bootstrapped/scala-$version-bin-SNAPSHOT-nonbootstrapped/classes", + s"out/bootstrap/scala-library-internal-tasty/scala-$version-bin-SNAPSHOT-nonbootstrapped/classes", s"out/bootstrap/scala3-library-bootstrapped/scala-$version-bin-SNAPSHOT-nonbootstrapped/classes", s"tmp/interfaces/target/classes", s"out/bootstrap/tasty-core-bootstrapped/scala-$version-bin-SNAPSHOT-nonbootstrapped/classes" diff --git a/project/ScalaLibraryPlugin.scala b/project/ScalaLibraryPlugin.scala deleted file mode 100644 index 2eac7271644a..000000000000 --- a/project/ScalaLibraryPlugin.scala +++ /dev/null @@ -1,108 +0,0 @@ -package dotty.tools.sbtplugin - -import sbt.* -import sbt.Keys.* -import scala.jdk.CollectionConverters.* -import java.nio.file.Files - -object ScalaLibraryPlugin extends AutoPlugin { - - override def trigger = noTrigger - - val fetchScala2ClassFiles = taskKey[(Set[File], File)]("Fetch the files to use that were compiled with Scala 2") - //val scala2LibraryVersion = settingKey[String]("Version of the Scala 2 Standard Library") - - override def projectSettings = Seq ( - fetchScala2ClassFiles := { - val stream = streams.value - val cache = stream.cacheDirectory - val target = cache / "scala-library-classes" - val report = update.value - - val scalaLibraryBinaryJar = report.select( - configuration = configurationFilter(), - module = (_: ModuleID).name == "scala-library", - artifact = artifactFilter(`type` = "jar")).headOption.getOrElse { - sys.error(s"Could not fetch scala-library binary JAR") - } - - if (!target.exists()) { - IO.createDirectory(target) - } - - (FileFunction.cached(cache / "fetch-scala-library-classes", FilesInfo.lastModified, FilesInfo.exists) { _ => - stream.log.info(s"Unpacking scala-library binaries to persistent directory: ${target.getAbsolutePath}") - IO.unzip(scalaLibraryBinaryJar, target) - (target ** "*.class").get.toSet - } (Set(scalaLibraryBinaryJar)), target) - - }, - (Compile / compile) := { - val stream = streams.value - val target = (Compile / classDirectory).value - val (files, reference) = fetchScala2ClassFiles.value; - val analysis = (Compile / compile).value - stream.log.info(s"Copying files from Scala 2 Standard Library to $target") - for (file <- files; id <- file.relativeTo(reference).map(_.toString())) { - if (filesToCopy(id)) { - stream.log.debug(s"Copying file '${id}' to ${target / id}") - IO.copyFile(file, target / id) - } - } - - val overwrittenBinaries = Files.walk((Compile / classDirectory).value.toPath()) - .iterator() - .asScala - .map(_.toFile) - .map(_.relativeTo((Compile / classDirectory).value).get) - .toSet - val diff = files.filterNot(_.relativeTo(reference).exists(overwrittenBinaries)) - - IO.copy(diff.map { file => - file -> (Compile / classDirectory).value / file.relativeTo(reference).get.getPath - }) - - analysis - } - ) - - private lazy val filesToCopy = Set( - "scala/Tuple1.class", - "scala/Tuple2.class", - "scala/collection/DoubleStepper.class", - "scala/collection/IntStepper.class", - "scala/collection/LongStepper.class", - "scala/collection/immutable/DoubleVectorStepper.class", - "scala/collection/immutable/IntVectorStepper.class", - "scala/collection/immutable/LongVectorStepper.class", - "scala/jdk/DoubleAccumulator.class", - "scala/jdk/IntAccumulator.class", - "scala/jdk/LongAccumulator.class", - "scala/jdk/FunctionWrappers$FromJavaDoubleBinaryOperator.class", - "scala/jdk/FunctionWrappers$FromJavaBooleanSupplier.class", - "scala/jdk/FunctionWrappers$FromJavaDoubleConsumer.class", - "scala/jdk/FunctionWrappers$FromJavaDoublePredicate.class", - "scala/jdk/FunctionWrappers$FromJavaDoubleSupplier.class", - "scala/jdk/FunctionWrappers$FromJavaDoubleToIntFunction.class", - "scala/jdk/FunctionWrappers$FromJavaDoubleToLongFunction.class", - "scala/jdk/FunctionWrappers$FromJavaIntBinaryOperator.class", - "scala/jdk/FunctionWrappers$FromJavaDoubleUnaryOperator.class", - "scala/jdk/FunctionWrappers$FromJavaIntPredicate.class", - "scala/jdk/FunctionWrappers$FromJavaIntConsumer.class", - "scala/jdk/FunctionWrappers$FromJavaIntSupplier.class", - "scala/jdk/FunctionWrappers$FromJavaIntToDoubleFunction.class", - "scala/jdk/FunctionWrappers$FromJavaIntToLongFunction.class", - "scala/jdk/FunctionWrappers$FromJavaIntUnaryOperator.class", - "scala/jdk/FunctionWrappers$FromJavaLongBinaryOperator.class", - "scala/jdk/FunctionWrappers$FromJavaLongConsumer.class", - "scala/jdk/FunctionWrappers$FromJavaLongPredicate.class", - "scala/jdk/FunctionWrappers$FromJavaLongSupplier.class", - "scala/jdk/FunctionWrappers$FromJavaLongToDoubleFunction.class", - "scala/jdk/FunctionWrappers$FromJavaLongToIntFunction.class", - "scala/jdk/FunctionWrappers$FromJavaLongUnaryOperator.class", - "scala/collection/ArrayOps$ReverseIterator.class", - "scala/runtime/NonLocalReturnControl.class", - "scala/util/Sorting.class", "scala/util/Sorting$.class", // Contains @specialized annotation - ) - -} diff --git a/scala2-library-cc/src/scala/collection/ArrayOps.scala b/scala2-library-cc/src/scala/collection/ArrayOps.scala.ignore similarity index 100% rename from scala2-library-cc/src/scala/collection/ArrayOps.scala rename to scala2-library-cc/src/scala/collection/ArrayOps.scala.ignore diff --git a/scala2-library-cc/src/scala/collection/Stepper.scala b/scala2-library-cc/src/scala/collection/Stepper.scala.ignore similarity index 100% rename from scala2-library-cc/src/scala/collection/Stepper.scala rename to scala2-library-cc/src/scala/collection/Stepper.scala.ignore diff --git a/scala2-library-cc/src/scala/collection/immutable/Vector.scala b/scala2-library-cc/src/scala/collection/immutable/Vector.scala.ignore similarity index 100% rename from scala2-library-cc/src/scala/collection/immutable/Vector.scala rename to scala2-library-cc/src/scala/collection/immutable/Vector.scala.ignore