diff --git a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala
index 58daa01e4bdf..bff35134f878 100644
--- a/compiler/src/dotty/tools/backend/jvm/GenBCode.scala
+++ b/compiler/src/dotty/tools/backend/jvm/GenBCode.scala
@@ -109,7 +109,7 @@ class GenBCode extends Phase { self =>
result
finally
// frontendAccess and postProcessor are created lazilly, clean them up only if they were initialized
- if _frontendAccess ne null then
+ if !(_frontendAccess eq null) then
frontendAccess.compilerSettings.outputDirectory match {
case jar: JarArchive =>
if (ctx.run.nn.suspendedUnits.nonEmpty)
@@ -120,7 +120,7 @@ class GenBCode extends Phase { self =>
jar.close()
case _ => ()
}
- if _postProcessor ne null then
+ if !(_postProcessor eq null) then
postProcessor.classfileWriter.close()
generatedClassHandler.close()
}
diff --git a/library/src/scala/AnyVal.scala b/library/src/scala/AnyVal.scala
new file mode 100644
index 000000000000..412b02c44c16
--- /dev/null
+++ b/library/src/scala/AnyVal.scala
@@ -0,0 +1,59 @@
+/*
+ * 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/src/scala/AnyValCompanion.scala b/library/src/scala/AnyValCompanion.scala
new file mode 100644
index 000000000000..2bb8584f8bac
--- /dev/null
+++ b/library/src/scala/AnyValCompanion.scala
@@ -0,0 +1,25 @@
+/*
+ * 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
+
+/** A common supertype for companion classes of primitive types.
+ *
+ * A common trait for /companion/ objects of primitive types comes handy
+ * when parameterizing code on types. For instance, the specialized
+ * annotation is passed a sequence of types on which to specialize:
+ * {{{
+ * class Tuple1[@specialized(Unit, Int, Double) T]
+ * }}}
+ *
+ */
+private[scala] trait AnyValCompanion extends Specializable { }
diff --git a/library/src/scala/App.scala b/library/src/scala/App.scala
new file mode 100644
index 000000000000..896cf8d9b22e
--- /dev/null
+++ b/library/src/scala/App.scala
@@ -0,0 +1,104 @@
+/*
+ * 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
+
+import java.lang.System.{currentTimeMillis => currentTime}
+
+import scala.annotation.nowarn
+import scala.collection.mutable.ListBuffer
+
+/** The `App` trait can be used to quickly turn objects
+ * into executable programs. Here is an example:
+ * {{{
+ * object Main extends App {
+ * Console.println("Hello World: " + (args mkString ", "))
+ * }
+ * }}}
+ *
+ * No explicit `main` method is needed. Instead,
+ * the whole class body becomes the “main method”.
+ *
+ * `args` returns the current command line arguments as an array.
+ *
+ * ==Caveats==
+ *
+ * '''''It should be noted that this trait is implemented using the [[DelayedInit]]
+ * functionality, which means that fields of the object will not have been initialized
+ * before the main method has been executed.'''''
+ *
+ * Future versions of this trait will no longer extend `DelayedInit`.
+ *
+ * In Scala 3, the `DelayedInit` feature was dropped. `App` exists only in a limited form
+ * that also does not support command line arguments and will be deprecated in the future.
+ *
+ * [[https://docs.scala-lang.org/scala3/book/methods-main-methods.html @main]] methods are the
+ * recommended scheme to generate programs that can be invoked from the command line in Scala 3.
+ *
+ * {{{
+ * @main def runMyProgram(args: String*): Unit = {
+ * // your program here
+ * }
+ * }}}
+ *
+ * If programs need to cross-build between Scala 2 and Scala 3, it is recommended to use an
+ * explicit `main` method:
+ * {{{
+ * object Main {
+ * def main(args: Array[String]): Unit = {
+ * // your program here
+ * }
+ * }
+ * }}}
+ */
+@nowarn("""cat=deprecation&origin=scala\.DelayedInit""")
+trait App extends DelayedInit {
+
+ /** The time when the execution of this program started, in milliseconds since 1
+ * January 1970 UTC. */
+ final val executionStart: Long = currentTime
+
+ /** The command line arguments passed to the application's `main` method.
+ */
+ protected final def args: Array[String] = _args
+
+ private[this] var _args: Array[String] = _
+
+ private[this] val initCode = new ListBuffer[() => Unit]
+
+ /** The init hook. This saves all initialization code for execution within `main`.
+ * This method is normally never called directly from user code.
+ * Instead it is called as compiler-generated code for those classes and objects
+ * (but not traits) that inherit from the `DelayedInit` trait and that do not
+ * themselves define a `delayedInit` method.
+ * @param body the initialization code to be stored for later execution
+ */
+ @deprecated("the delayedInit mechanism will disappear", "2.11.0")
+ override def delayedInit(body: => Unit): Unit = {
+ initCode += (() => body)
+ }
+
+ /** The main method.
+ * This stores all arguments so that they can be retrieved with `args`
+ * and then executes all initialization code segments in the order in which
+ * they were passed to `delayedInit`.
+ * @param args the arguments passed to the main method
+ */
+ final def main(args: Array[String]) = {
+ this._args = args
+ for (proc <- initCode) proc()
+ if (util.Properties.propIsSet("scala.time")) {
+ val total = currentTime - executionStart
+ Console.println("[total " + total + "ms]")
+ }
+ }
+}
diff --git a/library/src/scala/Array.scala b/library/src/scala/Array.scala
new file mode 100644
index 000000000000..cf8e53fe6c60
--- /dev/null
+++ b/library/src/scala/Array.scala
@@ -0,0 +1,692 @@
+/*
+ * 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
+
+//import scala.collection.generic._
+import scala.collection.{Factory, immutable, mutable}
+import mutable.ArrayBuilder
+import immutable.ArraySeq
+import scala.language.implicitConversions
+import scala.reflect.{ClassTag, classTag}
+import scala.runtime.BoxedUnit
+import scala.runtime.ScalaRunTime
+import scala.runtime.ScalaRunTime.{array_apply, array_update}
+
+/** Utility methods for operating on arrays.
+ * For example:
+ * {{{
+ * val a = Array(1, 2)
+ * val b = Array.ofDim[Int](2)
+ * val c = Array.concat(a, b)
+ * }}}
+ * where the array objects `a`, `b` and `c` have respectively the values
+ * `Array(1, 2)`, `Array(0, 0)` and `Array(1, 2, 0, 0)`.
+ */
+object Array {
+ val emptyBooleanArray = new Array[Boolean](0)
+ val emptyByteArray = new Array[Byte](0)
+ val emptyCharArray = new Array[Char](0)
+ val emptyDoubleArray = new Array[Double](0)
+ val emptyFloatArray = new Array[Float](0)
+ val emptyIntArray = new Array[Int](0)
+ val emptyLongArray = new Array[Long](0)
+ val emptyShortArray = new Array[Short](0)
+ val emptyObjectArray = new Array[Object](0)
+
+ /** Provides an implicit conversion from the Array object to a collection Factory */
+ implicit def toFactory[A : ClassTag](dummy: Array.type): Factory[A, Array[A]] = new ArrayFactory(dummy)
+ @SerialVersionUID(3L)
+ private class ArrayFactory[A : ClassTag](dummy: Array.type) extends Factory[A, Array[A]] with Serializable {
+ def fromSpecific(it: IterableOnce[A]): Array[A] = Array.from[A](it)
+ def newBuilder: mutable.Builder[A, Array[A]] = Array.newBuilder[A]
+ }
+
+ /**
+ * Returns a new [[scala.collection.mutable.ArrayBuilder]].
+ */
+ def newBuilder[T](implicit t: ClassTag[T]): ArrayBuilder[T] = ArrayBuilder.make[T](using t)
+
+ /** Build an array from the iterable collection.
+ *
+ * {{{
+ * scala> val a = Array.from(Seq(1, 5))
+ * val a: Array[Int] = Array(1, 5)
+ *
+ * scala> val b = Array.from(Range(1, 5))
+ * val b: Array[Int] = Array(1, 2, 3, 4)
+ * }}}
+ *
+ * @param it the iterable collection
+ * @return an array consisting of elements of the iterable collection
+ */
+ def from[A : ClassTag](it: IterableOnce[A]): Array[A] = it match {
+ case it: Iterable[A] => it.toArray[A]
+ case _ => it.iterator.toArray[A]
+ }
+
+ private def slowcopy(src : AnyRef,
+ srcPos : Int,
+ dest : AnyRef,
+ destPos : Int,
+ length : Int): Unit = {
+ var i = srcPos
+ var j = destPos
+ val srcUntil = srcPos + length
+ while (i < srcUntil) {
+ array_update(dest, j, array_apply(src, i))
+ i += 1
+ j += 1
+ }
+ }
+
+ /** Copy one array to another.
+ * Equivalent to Java's
+ * `System.arraycopy(src, srcPos, dest, destPos, length)`,
+ * except that this also works for polymorphic and boxed arrays.
+ *
+ * Note that the passed-in `dest` array will be modified by this call.
+ *
+ * @param src the source array.
+ * @param srcPos starting position in the source array.
+ * @param dest destination array.
+ * @param destPos starting position in the destination array.
+ * @param length the number of array elements to be copied.
+ *
+ * @see `java.lang.System#arraycopy`
+ */
+ def copy(src: AnyRef, srcPos: Int, dest: AnyRef, destPos: Int, length: Int): Unit = {
+ val srcClass = src.getClass
+ val destClass = dest.getClass
+ if (srcClass.isArray && ((destClass eq srcClass) ||
+ (destClass.isArray && !srcClass.getComponentType.isPrimitive && !destClass.getComponentType.isPrimitive)))
+ java.lang.System.arraycopy(src, srcPos, dest, destPos, length)
+ else
+ slowcopy(src, srcPos, dest, destPos, length)
+ }
+
+ /** Copy one array to another, truncating or padding with default values (if
+ * necessary) so the copy has the specified length.
+ *
+ * Equivalent to Java's
+ * `java.util.Arrays.copyOf(original, newLength)`,
+ * except that this works for primitive and object arrays in a single method.
+ *
+ * @see `java.util.Arrays#copyOf`
+ */
+ def copyOf[A](original: Array[A], newLength: Int): Array[A] = ((original: @unchecked) match {
+ case x: Array[BoxedUnit] => newUnitArray(newLength).asInstanceOf[Array[A]]
+ case x: Array[AnyRef] => java.util.Arrays.copyOf(x, newLength)
+ case x: Array[Int] => java.util.Arrays.copyOf(x, newLength)
+ case x: Array[Double] => java.util.Arrays.copyOf(x, newLength)
+ case x: Array[Long] => java.util.Arrays.copyOf(x, newLength)
+ case x: Array[Float] => java.util.Arrays.copyOf(x, newLength)
+ case x: Array[Char] => java.util.Arrays.copyOf(x, newLength)
+ case x: Array[Byte] => java.util.Arrays.copyOf(x, newLength)
+ case x: Array[Short] => java.util.Arrays.copyOf(x, newLength)
+ case x: Array[Boolean] => java.util.Arrays.copyOf(x, newLength)
+ }).asInstanceOf[Array[A]]
+
+ /** Copy one array to another, truncating or padding with default values (if
+ * necessary) so the copy has the specified length. The new array can have
+ * a different type than the original one as long as the values are
+ * assignment-compatible. When copying between primitive and object arrays,
+ * boxing and unboxing are supported.
+ *
+ * Equivalent to Java's
+ * `java.util.Arrays.copyOf(original, newLength, newType)`,
+ * except that this works for all combinations of primitive and object arrays
+ * in a single method.
+ *
+ * @see `java.util.Arrays#copyOf`
+ */
+ def copyAs[A](original: Array[_], newLength: Int)(implicit ct: ClassTag[A]): Array[A] = {
+ val runtimeClass = ct.runtimeClass
+ if (runtimeClass == Void.TYPE) newUnitArray(newLength).asInstanceOf[Array[A]]
+ else {
+ val destClass = runtimeClass.asInstanceOf[Class[A]]
+ if (destClass.isAssignableFrom(original.getClass.getComponentType)) {
+ if (destClass.isPrimitive) copyOf[A](original.asInstanceOf[Array[A]], newLength)
+ else {
+ val destArrayClass = java.lang.reflect.Array.newInstance(destClass, 0).getClass.asInstanceOf[Class[Array[AnyRef]]]
+ java.util.Arrays.copyOf(original.asInstanceOf[Array[AnyRef]], newLength, destArrayClass).asInstanceOf[Array[A]]
+ }
+ } else {
+ val dest = new Array[A](newLength)
+ Array.copy(original, 0, dest, 0, original.length)
+ dest
+ }
+ }
+ }
+
+ private def newUnitArray(len: Int): Array[Unit] = {
+ val result = new Array[Unit](len)
+ java.util.Arrays.fill(result.asInstanceOf[Array[AnyRef]], ())
+ result
+ }
+
+ /** Returns an array of length 0 */
+ def empty[T: ClassTag]: Array[T] = new Array[T](0)
+
+ /** Creates an array with given elements.
+ *
+ * @param xs the elements to put in the array
+ * @return an array containing all elements from xs.
+ */
+ // Subject to a compiler optimization in Cleanup.
+ // Array(e0, ..., en) is translated to { val a = new Array(3); a(i) = ei; a }
+ def apply[T: ClassTag](xs: T*): Array[T] = {
+ val len = xs.length
+ xs match {
+ case wa: immutable.ArraySeq[_] if wa.unsafeArray.getClass.getComponentType == classTag[T].runtimeClass =>
+ // We get here in test/files/run/sd760a.scala, `Array[T](t)` for
+ // a specialized type parameter `T`. While we still pay for two
+ // copies of the array it is better than before when we also boxed
+ // each element when populating the result.
+ ScalaRunTime.array_clone(wa.unsafeArray).asInstanceOf[Array[T]]
+ case _ =>
+ val array = new Array[T](len)
+ val iterator = xs.iterator
+ var i = 0
+ while (iterator.hasNext) {
+ array(i) = iterator.next(); i += 1
+ }
+ array
+ }
+ }
+
+ /** Creates an array of `Boolean` objects */
+ // Subject to a compiler optimization in Cleanup, see above.
+ def apply(x: Boolean, xs: Boolean*): Array[Boolean] = {
+ val array = new Array[Boolean](xs.length + 1)
+ array(0) = x
+ val iterator = xs.iterator
+ var i = 1
+ while (iterator.hasNext) {
+ array(i) = iterator.next(); i += 1
+ }
+ array
+ }
+
+ /** Creates an array of `Byte` objects */
+ // Subject to a compiler optimization in Cleanup, see above.
+ def apply(x: Byte, xs: Byte*): Array[Byte] = {
+ val array = new Array[Byte](xs.length + 1)
+ array(0) = x
+ val iterator = xs.iterator
+ var i = 1
+ while (iterator.hasNext) {
+ array(i) = iterator.next(); i += 1
+ }
+ array
+ }
+
+ /** Creates an array of `Short` objects */
+ // Subject to a compiler optimization in Cleanup, see above.
+ def apply(x: Short, xs: Short*): Array[Short] = {
+ val array = new Array[Short](xs.length + 1)
+ array(0) = x
+ val iterator = xs.iterator
+ var i = 1
+ while (iterator.hasNext) {
+ array(i) = iterator.next(); i += 1
+ }
+ array
+ }
+
+ /** Creates an array of `Char` objects */
+ // Subject to a compiler optimization in Cleanup, see above.
+ def apply(x: Char, xs: Char*): Array[Char] = {
+ val array = new Array[Char](xs.length + 1)
+ array(0) = x
+ val iterator = xs.iterator
+ var i = 1
+ while (iterator.hasNext) {
+ array(i) = iterator.next(); i += 1
+ }
+ array
+ }
+
+ /** Creates an array of `Int` objects */
+ // Subject to a compiler optimization in Cleanup, see above.
+ def apply(x: Int, xs: Int*): Array[Int] = {
+ val array = new Array[Int](xs.length + 1)
+ array(0) = x
+ val iterator = xs.iterator
+ var i = 1
+ while (iterator.hasNext) {
+ array(i) = iterator.next(); i += 1
+ }
+ array
+ }
+
+ /** Creates an array of `Long` objects */
+ // Subject to a compiler optimization in Cleanup, see above.
+ def apply(x: Long, xs: Long*): Array[Long] = {
+ val array = new Array[Long](xs.length + 1)
+ array(0) = x
+ val iterator = xs.iterator
+ var i = 1
+ while (iterator.hasNext) {
+ array(i) = iterator.next(); i += 1
+ }
+ array
+ }
+
+ /** Creates an array of `Float` objects */
+ // Subject to a compiler optimization in Cleanup, see above.
+ def apply(x: Float, xs: Float*): Array[Float] = {
+ val array = new Array[Float](xs.length + 1)
+ array(0) = x
+ val iterator = xs.iterator
+ var i = 1
+ while (iterator.hasNext) {
+ array(i) = iterator.next(); i += 1
+ }
+ array
+ }
+
+ /** Creates an array of `Double` objects */
+ // Subject to a compiler optimization in Cleanup, see above.
+ def apply(x: Double, xs: Double*): Array[Double] = {
+ val array = new Array[Double](xs.length + 1)
+ array(0) = x
+ val iterator = xs.iterator
+ var i = 1
+ while (iterator.hasNext) {
+ array(i) = iterator.next(); i += 1
+ }
+ array
+ }
+
+ /** Creates an array of `Unit` objects */
+ def apply(x: Unit, xs: Unit*): Array[Unit] = {
+ val array = new Array[Unit](xs.length + 1)
+ array(0) = x
+ val iterator = xs.iterator
+ var i = 1
+ while (iterator.hasNext) {
+ array(i) = iterator.next(); i += 1
+ }
+ array
+ }
+
+ /** Creates array with given dimensions */
+ def ofDim[T: ClassTag](n1: Int): Array[T] =
+ new Array[T](n1)
+ /** Creates a 2-dimensional array */
+ def ofDim[T: ClassTag](n1: Int, n2: Int): Array[Array[T]] = {
+ val arr: Array[Array[T]] = (new Array[Array[T]](n1): Array[Array[T]])
+ for (i <- 0 until n1) arr(i) = new Array[T](n2)
+ arr
+ // tabulate(n1)(_ => ofDim[T](n2))
+ }
+ /** Creates a 3-dimensional array */
+ def ofDim[T: ClassTag](n1: Int, n2: Int, n3: Int): Array[Array[Array[T]]] =
+ tabulate(n1)(_ => ofDim[T](n2, n3))
+ /** Creates a 4-dimensional array */
+ def ofDim[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int): Array[Array[Array[Array[T]]]] =
+ tabulate(n1)(_ => ofDim[T](n2, n3, n4))
+ /** Creates a 5-dimensional array */
+ def ofDim[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int): Array[Array[Array[Array[Array[T]]]]] =
+ tabulate(n1)(_ => ofDim[T](n2, n3, n4, n5))
+
+ /** Concatenates all arrays into a single array.
+ *
+ * @param xss the given arrays
+ * @return the array created from concatenating `xss`
+ */
+ def concat[T: ClassTag](xss: Array[T]*): Array[T] = {
+ val b = newBuilder[T]
+ b.sizeHint(xss.map(_.length).sum)
+ for (xs <- xss) b ++= xs
+ b.result()
+ }
+
+ /** Returns an array that contains the results of some element computation a number
+ * of times.
+ *
+ * Note that this means that `elem` is computed a total of n times:
+ * {{{
+ * scala> Array.fill(3){ math.random }
+ * res3: Array[Double] = Array(0.365461167592537, 1.550395944913685E-4, 0.7907242137333306)
+ * }}}
+ *
+ * @param n the number of elements desired
+ * @param elem the element computation
+ * @return an Array of size n, where each element contains the result of computing
+ * `elem`.
+ */
+ def fill[T: ClassTag](n: Int)(elem: => T): Array[T] = {
+ if (n <= 0) {
+ empty[T]
+ } else {
+ val array = new Array[T](n)
+ var i = 0
+ while (i < n) {
+ array(i) = elem
+ i += 1
+ }
+ array
+ }
+ }
+
+ /** Returns a two-dimensional array that contains 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
+ */
+ def fill[T: ClassTag](n1: Int, n2: Int)(elem: => T): Array[Array[T]] =
+ tabulate(n1)(_ => fill(n2)(elem))
+
+ /** Returns a three-dimensional array that contains 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
+ */
+ def fill[T: ClassTag](n1: Int, n2: Int, n3: Int)(elem: => T): Array[Array[Array[T]]] =
+ tabulate(n1)(_ => fill(n2, n3)(elem))
+
+ /** Returns a four-dimensional array that contains 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
+ */
+ def fill[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => T): Array[Array[Array[Array[T]]]] =
+ tabulate(n1)(_ => fill(n2, n3, n4)(elem))
+
+ /** Returns a five-dimensional array that contains 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
+ */
+ def fill[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => T): Array[Array[Array[Array[Array[T]]]]] =
+ tabulate(n1)(_ => fill(n2, n3, n4, n5)(elem))
+
+ /** Returns an array containing values of a given function over a range of integer
+ * values starting from 0.
+ *
+ * @param n The number of elements in the array
+ * @param f The function computing element values
+ * @return An `Array` consisting of elements `f(0),f(1), ..., f(n - 1)`
+ */
+ def tabulate[T: ClassTag](n: Int)(f: Int => T): Array[T] = {
+ if (n <= 0) {
+ empty[T]
+ } else {
+ val array = new Array[T](n)
+ var i = 0
+ while (i < n) {
+ array(i) = f(i)
+ i += 1
+ }
+ array
+ }
+ }
+
+ /** Returns a two-dimensional array 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
+ */
+ def tabulate[T: ClassTag](n1: Int, n2: Int)(f: (Int, Int) => T): Array[Array[T]] =
+ tabulate(n1)(i1 => tabulate(n2)(f(i1, _)))
+
+ /** Returns a three-dimensional array 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
+ */
+ def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => T): Array[Array[Array[T]]] =
+ tabulate(n1)(i1 => tabulate(n2, n3)(f(i1, _, _)))
+
+ /** Returns a four-dimensional array 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
+ */
+ def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => T): Array[Array[Array[Array[T]]]] =
+ tabulate(n1)(i1 => tabulate(n2, n3, n4)(f(i1, _, _, _)))
+
+ /** Returns a five-dimensional array 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
+ */
+ def tabulate[T: ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(f: (Int, Int, Int, Int, Int) => T): Array[Array[Array[Array[Array[T]]]]] =
+ tabulate(n1)(i1 => tabulate(n2, n3, n4, n5)(f(i1, _, _, _, _)))
+
+ /** Returns an array containing a sequence of increasing integers in a range.
+ *
+ * @param start the start value of the array
+ * @param end the end value of the array, exclusive (in other words, this is the first value '''not''' returned)
+ * @return the array with values in range `start, start + 1, ..., end - 1`
+ * up to, but excluding, `end`.
+ */
+ def range(start: Int, end: Int): Array[Int] = range(start, end, 1)
+
+ /** Returns an array containing equally spaced values in some integer interval.
+ *
+ * @param start the start value of the array
+ * @param end the end value of the array, exclusive (in other words, this is the first value '''not''' returned)
+ * @param step the increment value of the array (may not be zero)
+ * @return the array with values in `start, start + step, ...` up to, but excluding `end`
+ */
+ def range(start: Int, end: Int, step: Int): Array[Int] = {
+ if (step == 0) throw new IllegalArgumentException("zero step")
+ val array = new Array[Int](immutable.Range.count(start, end, step, isInclusive = false))
+
+ var n = 0
+ var i = start
+ while (if (step < 0) end < i else i < end) {
+ array(n) = i
+ i += step
+ n += 1
+ }
+ array
+ }
+
+ /** Returns an array containing repeated applications of a function to a start value.
+ *
+ * @param start the start value of the array
+ * @param len the number of elements returned by the array
+ * @param f the function that is repeatedly applied
+ * @return the array returning `len` values in the sequence `start, f(start), f(f(start)), ...`
+ */
+ def iterate[T: ClassTag](start: T, len: Int)(f: T => T): Array[T] = {
+ if (len > 0) {
+ val array = new Array[T](len)
+ var acc = start
+ var i = 1
+ array(0) = acc
+
+ while (i < len) {
+ acc = f(acc)
+ array(i) = acc
+ i += 1
+ }
+ array
+ } else {
+ empty[T]
+ }
+ }
+
+ /** Compare two arrays per element.
+ *
+ * A more efficient version of `xs.sameElements(ys)`.
+ *
+ * Note that arrays are invariant in Scala, but it may
+ * be sound to cast an array of arbitrary reference type
+ * to `Array[AnyRef]`. Arrays on the JVM are covariant
+ * in their element type.
+ *
+ * `Array.equals(xs.asInstanceOf[Array[AnyRef]], ys.asInstanceOf[Array[AnyRef]])`
+ *
+ * @param xs an array of AnyRef
+ * @param ys an array of AnyRef
+ * @return true if corresponding elements are equal
+ */
+ def equals(xs: Array[AnyRef], ys: Array[AnyRef]): Boolean =
+ (xs eq ys) ||
+ (xs.length == ys.length) && {
+ var i = 0
+ while (i < xs.length && xs(i) == ys(i)) i += 1
+ i >= xs.length
+ }
+
+ /** Called in a pattern match like `{ case Array(x,y,z) => println('3 elements')}`.
+ *
+ * @param x the selector value
+ * @return sequence wrapped in a [[scala.Some]], if `x` is an Array, otherwise `None`
+ */
+ def unapplySeq[T](x: Array[T]): UnapplySeqWrapper[T] = new UnapplySeqWrapper(x)
+
+ final class UnapplySeqWrapper[T](private val a: Array[T]) extends AnyVal {
+ def isEmpty: false = false
+ def get: UnapplySeqWrapper[T] = this
+ def lengthCompare(len: Int): Int = a.lengthCompare(len)
+ def apply(i: Int): T = a(i)
+ def drop(n: Int): scala.Seq[T] = ArraySeq.unsafeWrapArray(a.drop(n)) // clones the array, also if n == 0
+ def toSeq: scala.Seq[T] = a.toSeq // clones the array
+ }
+}
+
+/** Arrays are mutable, indexed collections of values. `Array[T]` is Scala's representation
+ * for Java's `T[]`.
+ *
+ * {{{
+ * val numbers = Array(1, 2, 3, 4)
+ * val first = numbers(0) // read the first element
+ * numbers(3) = 100 // replace the 4th array element with 100
+ * val biggerNumbers = numbers.map(_ * 2) // multiply all numbers by two
+ * }}}
+ *
+ * Arrays make use of two common pieces of Scala syntactic sugar, shown on lines 2 and 3 of the above
+ * example code.
+ * Line 2 is translated into a call to `apply(Int)`, while line 3 is translated into a call to
+ * `update(Int, T)`.
+ *
+ * Two implicit conversions exist in [[scala.Predef]] that are frequently applied to arrays: a conversion
+ * to [[scala.collection.ArrayOps]] (shown on line 4 of the example above) and a conversion
+ * to [[scala.collection.mutable.ArraySeq]] (a subtype of [[scala.collection.Seq]]).
+ * Both types make available many of the standard operations found in the Scala collections API.
+ * The conversion to `ArrayOps` is temporary, as all operations defined on `ArrayOps` return an `Array`,
+ * while the conversion to `ArraySeq` is permanent as all operations return a `ArraySeq`.
+ *
+ * The conversion to `ArrayOps` takes priority over the conversion to `ArraySeq`. For instance,
+ * consider the following code:
+ *
+ * {{{
+ * val arr = Array(1, 2, 3)
+ * val arrReversed = arr.reverse
+ * val seqReversed : collection.Seq[Int] = arr.reverse
+ * }}}
+ *
+ * Value `arrReversed` will be of type `Array[Int]`, with an implicit conversion to `ArrayOps` occurring
+ * to perform the `reverse` operation. The value of `seqReversed`, on the other hand, will be computed
+ * by converting to `ArraySeq` first and invoking the variant of `reverse` that returns another
+ * `ArraySeq`.
+ *
+ * @see [[https://www.scala-lang.org/files/archive/spec/2.13/ Scala Language Specification]], for in-depth information on the transformations the Scala compiler makes on Arrays (Sections 6.6 and 6.15 respectively.)
+ * @see [[https://docs.scala-lang.org/sips/scala-2-8-arrays.html "Scala 2.8 Arrays"]] the Scala Improvement Document detailing arrays since Scala 2.8.
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/arrays.html "The Scala 2.8 Collections' API"]] section on `Array` by Martin Odersky for more information.
+ * @hideImplicitConversion scala.Predef.booleanArrayOps
+ * @hideImplicitConversion scala.Predef.byteArrayOps
+ * @hideImplicitConversion scala.Predef.charArrayOps
+ * @hideImplicitConversion scala.Predef.doubleArrayOps
+ * @hideImplicitConversion scala.Predef.floatArrayOps
+ * @hideImplicitConversion scala.Predef.intArrayOps
+ * @hideImplicitConversion scala.Predef.longArrayOps
+ * @hideImplicitConversion scala.Predef.refArrayOps
+ * @hideImplicitConversion scala.Predef.shortArrayOps
+ * @hideImplicitConversion scala.Predef.unitArrayOps
+ * @hideImplicitConversion scala.LowPriorityImplicits.wrapRefArray
+ * @hideImplicitConversion scala.LowPriorityImplicits.wrapIntArray
+ * @hideImplicitConversion scala.LowPriorityImplicits.wrapDoubleArray
+ * @hideImplicitConversion scala.LowPriorityImplicits.wrapLongArray
+ * @hideImplicitConversion scala.LowPriorityImplicits.wrapFloatArray
+ * @hideImplicitConversion scala.LowPriorityImplicits.wrapCharArray
+ * @hideImplicitConversion scala.LowPriorityImplicits.wrapByteArray
+ * @hideImplicitConversion scala.LowPriorityImplicits.wrapShortArray
+ * @hideImplicitConversion scala.LowPriorityImplicits.wrapBooleanArray
+ * @hideImplicitConversion scala.LowPriorityImplicits.wrapUnitArray
+ * @hideImplicitConversion scala.LowPriorityImplicits.genericWrapArray
+ * @define coll array
+ * @define Coll `Array`
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ * @define collectExample
+ * @define undefinedorder
+ */
+final class Array[T](_length: Int) extends java.io.Serializable with java.lang.Cloneable {
+
+ /** The length of the array */
+ def length: Int = throw new Error()
+
+ /** The element at given index.
+ *
+ * Indices start at `0`; `xs.apply(0)` is the first element of array `xs`.
+ * Note the indexing syntax `xs(i)` is a shorthand for `xs.apply(i)`.
+ *
+ * @param i the index
+ * @return the element at the given index
+ * @throws ArrayIndexOutOfBoundsException if `i < 0` or `length <= i`
+ */
+ def apply(i: Int): T = throw new Error()
+
+ /** Update the element at given index.
+ *
+ * Indices start at `0`; `xs.update(i, x)` replaces the i^th^ element in the array.
+ * Note the syntax `xs(i) = x` is a shorthand for `xs.update(i, x)`.
+ *
+ * @param i the index
+ * @param x the value to be written at index `i`
+ * @throws ArrayIndexOutOfBoundsException if `i < 0` or `length <= i`
+ */
+ def update(i: Int, x: T): Unit = { throw new Error() }
+
+ /** Clone the Array.
+ *
+ * @return A clone of the Array.
+ */
+ override def clone(): Array[T] = throw new Error()
+}
diff --git a/library/src/scala/Boolean.scala b/library/src/scala/Boolean.scala
new file mode 100644
index 000000000000..ea8a2e37cda9
--- /dev/null
+++ b/library/src/scala/Boolean.scala
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+// DO NOT EDIT, CHANGES WILL BE LOST
+// This auto-generated code can be modified in "project/GenerateAnyVals.scala".
+// Afterwards, running "sbt generateSources" regenerates this source file.
+
+package scala
+
+/** `Boolean` (equivalent to Java's `boolean` primitive type) is a
+ * subtype of [[scala.AnyVal]]. Instances of `Boolean` are not
+ * represented by an object in the underlying runtime system.
+ *
+ * There is an implicit conversion from [[scala.Boolean]] => [[scala.runtime.RichBoolean]]
+ * which provides useful non-primitive operations.
+ */
+final abstract class Boolean private extends AnyVal {
+ /** Negates a Boolean expression.
+ *
+ * - `!a` results in `false` if and only if `a` evaluates to `true` and
+ * - `!a` results in `true` if and only if `a` evaluates to `false`.
+ *
+ * @return the negated expression
+ */
+ def unary_! : Boolean
+
+ /** Compares two Boolean expressions and returns `true` if they evaluate to the same value.
+ *
+ * `a == b` returns `true` if and only if
+ * - `a` and `b` are `true` or
+ * - `a` and `b` are `false`.
+ */
+ def ==(x: Boolean): Boolean
+
+ /**
+ * Compares two Boolean expressions and returns `true` if they evaluate to a different value.
+ *
+ * `a != b` returns `true` if and only if
+ * - `a` is `true` and `b` is `false` or
+ * - `a` is `false` and `b` is `true`.
+ */
+ def !=(x: Boolean): Boolean
+
+ /** Compares two Boolean expressions and returns `true` if one or both of them evaluate to true.
+ *
+ * `a || b` returns `true` if and only if
+ * - `a` is `true` or
+ * - `b` is `true` or
+ * - `a` and `b` are `true`.
+ *
+ * @note This method uses 'short-circuit' evaluation and
+ * behaves as if it was declared as `def ||(x: => Boolean): Boolean`.
+ * If `a` evaluates to `true`, `true` is returned without evaluating `b`.
+ */
+ def ||(x: Boolean): Boolean
+
+ /** Compares two Boolean expressions and returns `true` if both of them evaluate to true.
+ *
+ * `a && b` returns `true` if and only if
+ * - `a` and `b` are `true`.
+ *
+ * @note This method uses 'short-circuit' evaluation and
+ * behaves as if it was declared as `def &&(x: => Boolean): Boolean`.
+ * If `a` evaluates to `false`, `false` is returned without evaluating `b`.
+ */
+ def &&(x: Boolean): Boolean
+
+ // Compiler won't build with these seemingly more accurate signatures
+ // def ||(x: => Boolean): Boolean
+ // def &&(x: => Boolean): Boolean
+
+ /** Compares two Boolean expressions and returns `true` if one or both of them evaluate to true.
+ *
+ * `a | b` returns `true` if and only if
+ * - `a` is `true` or
+ * - `b` is `true` or
+ * - `a` and `b` are `true`.
+ *
+ * @note This method evaluates both `a` and `b`, even if the result is already determined after evaluating `a`.
+ */
+ def |(x: Boolean): Boolean
+
+ /** Compares two Boolean expressions and returns `true` if both of them evaluate to true.
+ *
+ * `a & b` returns `true` if and only if
+ * - `a` and `b` are `true`.
+ *
+ * @note This method evaluates both `a` and `b`, even if the result is already determined after evaluating `a`.
+ */
+ def &(x: Boolean): Boolean
+
+ /** Compares two Boolean expressions and returns `true` if they evaluate to a different value.
+ *
+ * `a ^ b` returns `true` if and only if
+ * - `a` is `true` and `b` is `false` or
+ * - `a` is `false` and `b` is `true`.
+ */
+ def ^(x: Boolean): Boolean
+
+ // Provide a more specific return type for Scaladoc
+ override def getClass(): Class[Boolean] = ???
+}
+
+object Boolean extends AnyValCompanion {
+
+ /** Transform a value type into a boxed reference type.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.boxToBoolean`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the Boolean to be boxed
+ * @return a java.lang.Boolean offering `x` as its underlying value.
+ */
+ def box(x: Boolean): java.lang.Boolean = ???
+
+ /** Transform a boxed type into a value type. Note that this
+ * method is not typesafe: it accepts any Object, but will throw
+ * an exception if the argument is not a java.lang.Boolean.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.unboxToBoolean`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the java.lang.Boolean to be unboxed.
+ * @throws ClassCastException if the argument is not a java.lang.Boolean
+ * @return the Boolean resulting from calling booleanValue() on `x`
+ */
+ def unbox(x: java.lang.Object): Boolean = ???
+
+ /** The String representation of the scala.Boolean companion object. */
+ override def toString = "object scala.Boolean"
+
+}
+
diff --git a/library/src/scala/Byte.scala b/library/src/scala/Byte.scala
new file mode 100644
index 000000000000..1f32d4d0bca1
--- /dev/null
+++ b/library/src/scala/Byte.scala
@@ -0,0 +1,487 @@
+/*
+ * 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.
+ */
+
+// DO NOT EDIT, CHANGES WILL BE LOST
+// This auto-generated code can be modified in "project/GenerateAnyVals.scala".
+// Afterwards, running "sbt generateSources" regenerates this source file.
+
+package scala
+
+/** `Byte`, a 8-bit signed integer (equivalent to Java's `byte` primitive type) is a
+ * subtype of [[scala.AnyVal]]. Instances of `Byte` are not
+ * represented by an object in the underlying runtime system.
+ *
+ * There is an implicit conversion from [[scala.Byte]] => [[scala.runtime.RichByte]]
+ * which provides useful non-primitive operations.
+ */
+final abstract class Byte private extends AnyVal {
+ def toByte: Byte
+ def toShort: Short
+ def toChar: Char
+ def toInt: Int
+ def toLong: Long
+ def toFloat: Float
+ def toDouble: Double
+
+ /**
+ * Returns the bitwise negation of this value.
+ * @example {{{
+ * ~5 == -6
+ * // in binary: ~00000101 ==
+ * // 11111010
+ * }}}
+ */
+ def unary_~ : Int
+ /** Returns this value, unmodified. */
+ def unary_+ : Int
+ /** Returns the negation of this value. */
+ def unary_- : Int
+
+ @deprecated("Adding a number and a String is deprecated. Use the string interpolation `s\"$num$str\"`", "2.13.0")
+ def +(x: String): String
+
+ /**
+ * Returns this value bit-shifted left by the specified number of bits,
+ * filling in the new right bits with zeroes.
+ * @example {{{ 6 << 3 == 48 // in binary: 0110 << 3 == 0110000 }}}
+ */
+ def <<(x: Int): Int
+ /**
+ * Returns this value bit-shifted left by the specified number of bits,
+ * filling in the new right bits with zeroes.
+ * @example {{{ 6 << 3 == 48 // in binary: 0110 << 3 == 0110000 }}}
+ */
+ @deprecated("shifting a value by a `Long` argument is deprecated (except when the value is a `Long`).\nCall `toInt` on the argument to maintain the current behavior and avoid the deprecation warning.", "2.12.7")
+ def <<(x: Long): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling the new left bits with zeroes.
+ * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}}
+ * @example {{{
+ * -21 >>> 3 == 536870909
+ * // in binary: 11111111 11111111 11111111 11101011 >>> 3 ==
+ * // 00011111 11111111 11111111 11111101
+ * }}}
+ */
+ def >>>(x: Int): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling the new left bits with zeroes.
+ * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}}
+ * @example {{{
+ * -21 >>> 3 == 536870909
+ * // in binary: 11111111 11111111 11111111 11101011 >>> 3 ==
+ * // 00011111 11111111 11111111 11111101
+ * }}}
+ */
+ @deprecated("shifting a value by a `Long` argument is deprecated (except when the value is a `Long`).\nCall `toInt` on the argument to maintain the current behavior and avoid the deprecation warning.", "2.12.7")
+ def >>>(x: Long): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling in the left bits with the same value as the left-most bit of this.
+ * The effect of this is to retain the sign of the value.
+ * @example {{{
+ * -21 >> 3 == -3
+ * // in binary: 11111111 11111111 11111111 11101011 >> 3 ==
+ * // 11111111 11111111 11111111 11111101
+ * }}}
+ */
+ def >>(x: Int): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling in the left bits with the same value as the left-most bit of this.
+ * The effect of this is to retain the sign of the value.
+ * @example {{{
+ * -21 >> 3 == -3
+ * // in binary: 11111111 11111111 11111111 11101011 >> 3 ==
+ * // 11111111 11111111 11111111 11111101
+ * }}}
+ */
+ @deprecated("shifting a value by a `Long` argument is deprecated (except when the value is a `Long`).\nCall `toInt` on the argument to maintain the current behavior and avoid the deprecation warning.", "2.12.7")
+ def >>(x: Long): Int
+
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Byte): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Short): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Char): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Int): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Long): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Float): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Double): Boolean
+
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Byte): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Short): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Char): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Int): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Long): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Float): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Double): Boolean
+
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Byte): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Short): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Char): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Int): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Long): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Float): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Double): Boolean
+
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Byte): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Short): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Char): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Int): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Long): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Float): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Byte): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Short): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Char): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Int): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Long): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Float): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Byte): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Short): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Char): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Int): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Long): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Float): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Double): Boolean
+
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Byte): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Short): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Char): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Int): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Long): Long
+
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Byte): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Short): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Char): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Int): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Long): Long
+
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Byte): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Short): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Char): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Int): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Long): Long
+
+ /** Returns the sum of this value and `x`. */
+ def +(x: Byte): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Short): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Char): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Int): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Long): Long
+ /** Returns the sum of this value and `x`. */
+ def +(x: Float): Float
+ /** Returns the sum of this value and `x`. */
+ def +(x: Double): Double
+
+ /** Returns the difference of this value and `x`. */
+ def -(x: Byte): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Short): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Char): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Int): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Long): Long
+ /** Returns the difference of this value and `x`. */
+ def -(x: Float): Float
+ /** Returns the difference of this value and `x`. */
+ def -(x: Double): Double
+
+ /** Returns the product of this value and `x`. */
+ def *(x: Byte): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Short): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Char): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Int): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Long): Long
+ /** Returns the product of this value and `x`. */
+ def *(x: Float): Float
+ /** Returns the product of this value and `x`. */
+ def *(x: Double): Double
+
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Byte): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Short): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Char): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Int): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Long): Long
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Float): Float
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Double): Double
+
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Byte): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Short): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Char): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Int): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Long): Long
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Float): Float
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Double): Double
+
+ // Provide a more specific return type for Scaladoc
+ override def getClass(): Class[Byte] = ???
+}
+
+object Byte extends AnyValCompanion {
+ /** The smallest value representable as a Byte. */
+ final val MinValue = java.lang.Byte.MIN_VALUE
+
+ /** The largest value representable as a Byte. */
+ final val MaxValue = java.lang.Byte.MAX_VALUE
+
+ /** Transform a value type into a boxed reference type.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.boxToByte`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the Byte to be boxed
+ * @return a java.lang.Byte offering `x` as its underlying value.
+ */
+ def box(x: Byte): java.lang.Byte = ???
+
+ /** Transform a boxed type into a value type. Note that this
+ * method is not typesafe: it accepts any Object, but will throw
+ * an exception if the argument is not a java.lang.Byte.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.unboxToByte`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the java.lang.Byte to be unboxed.
+ * @throws ClassCastException if the argument is not a java.lang.Byte
+ * @return the Byte resulting from calling byteValue() on `x`
+ */
+ def unbox(x: java.lang.Object): Byte = ???
+
+ /** The String representation of the scala.Byte companion object. */
+ override def toString = "object scala.Byte"
+ /** Language mandated coercions from Byte to "wider" types. */
+ import scala.language.implicitConversions
+ implicit def byte2short(x: Byte): Short = x.toShort
+ implicit def byte2int(x: Byte): Int = x.toInt
+ implicit def byte2long(x: Byte): Long = x.toLong
+ implicit def byte2float(x: Byte): Float = x.toFloat
+ implicit def byte2double(x: Byte): Double = x.toDouble
+}
+
diff --git a/library/src/scala/Char.scala b/library/src/scala/Char.scala
new file mode 100644
index 000000000000..52871422a39e
--- /dev/null
+++ b/library/src/scala/Char.scala
@@ -0,0 +1,486 @@
+/*
+ * 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.
+ */
+
+// DO NOT EDIT, CHANGES WILL BE LOST
+// This auto-generated code can be modified in "project/GenerateAnyVals.scala".
+// Afterwards, running "sbt generateSources" regenerates this source file.
+
+package scala
+
+/** `Char`, a 16-bit unsigned integer (equivalent to Java's `char` primitive type) is a
+ * subtype of [[scala.AnyVal]]. Instances of `Char` are not
+ * represented by an object in the underlying runtime system.
+ *
+ * There is an implicit conversion from [[scala.Char]] => [[scala.runtime.RichChar]]
+ * which provides useful non-primitive operations.
+ */
+final abstract class Char private extends AnyVal {
+ def toByte: Byte
+ def toShort: Short
+ def toChar: Char
+ def toInt: Int
+ def toLong: Long
+ def toFloat: Float
+ def toDouble: Double
+
+ /**
+ * Returns the bitwise negation of this value.
+ * @example {{{
+ * ~5 == -6
+ * // in binary: ~00000101 ==
+ * // 11111010
+ * }}}
+ */
+ def unary_~ : Int
+ /** Returns this value, unmodified. */
+ def unary_+ : Int
+ /** Returns the negation of this value. */
+ def unary_- : Int
+
+ @deprecated("Adding a number and a String is deprecated. Use the string interpolation `s\"$num$str\"`", "2.13.0")
+ def +(x: String): String
+
+ /**
+ * Returns this value bit-shifted left by the specified number of bits,
+ * filling in the new right bits with zeroes.
+ * @example {{{ 6 << 3 == 48 // in binary: 0110 << 3 == 0110000 }}}
+ */
+ def <<(x: Int): Int
+ /**
+ * Returns this value bit-shifted left by the specified number of bits,
+ * filling in the new right bits with zeroes.
+ * @example {{{ 6 << 3 == 48 // in binary: 0110 << 3 == 0110000 }}}
+ */
+ @deprecated("shifting a value by a `Long` argument is deprecated (except when the value is a `Long`).\nCall `toInt` on the argument to maintain the current behavior and avoid the deprecation warning.", "2.12.7")
+ def <<(x: Long): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling the new left bits with zeroes.
+ * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}}
+ * @example {{{
+ * -21 >>> 3 == 536870909
+ * // in binary: 11111111 11111111 11111111 11101011 >>> 3 ==
+ * // 00011111 11111111 11111111 11111101
+ * }}}
+ */
+ def >>>(x: Int): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling the new left bits with zeroes.
+ * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}}
+ * @example {{{
+ * -21 >>> 3 == 536870909
+ * // in binary: 11111111 11111111 11111111 11101011 >>> 3 ==
+ * // 00011111 11111111 11111111 11111101
+ * }}}
+ */
+ @deprecated("shifting a value by a `Long` argument is deprecated (except when the value is a `Long`).\nCall `toInt` on the argument to maintain the current behavior and avoid the deprecation warning.", "2.12.7")
+ def >>>(x: Long): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling in the left bits with the same value as the left-most bit of this.
+ * The effect of this is to retain the sign of the value.
+ * @example {{{
+ * -21 >> 3 == -3
+ * // in binary: 11111111 11111111 11111111 11101011 >> 3 ==
+ * // 11111111 11111111 11111111 11111101
+ * }}}
+ */
+ def >>(x: Int): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling in the left bits with the same value as the left-most bit of this.
+ * The effect of this is to retain the sign of the value.
+ * @example {{{
+ * -21 >> 3 == -3
+ * // in binary: 11111111 11111111 11111111 11101011 >> 3 ==
+ * // 11111111 11111111 11111111 11111101
+ * }}}
+ */
+ @deprecated("shifting a value by a `Long` argument is deprecated (except when the value is a `Long`).\nCall `toInt` on the argument to maintain the current behavior and avoid the deprecation warning.", "2.12.7")
+ def >>(x: Long): Int
+
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Byte): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Short): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Char): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Int): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Long): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Float): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Double): Boolean
+
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Byte): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Short): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Char): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Int): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Long): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Float): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Double): Boolean
+
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Byte): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Short): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Char): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Int): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Long): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Float): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Double): Boolean
+
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Byte): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Short): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Char): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Int): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Long): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Float): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Byte): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Short): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Char): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Int): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Long): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Float): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Byte): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Short): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Char): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Int): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Long): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Float): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Double): Boolean
+
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Byte): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Short): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Char): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Int): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Long): Long
+
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Byte): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Short): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Char): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Int): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Long): Long
+
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Byte): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Short): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Char): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Int): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Long): Long
+
+ /** Returns the sum of this value and `x`. */
+ def +(x: Byte): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Short): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Char): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Int): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Long): Long
+ /** Returns the sum of this value and `x`. */
+ def +(x: Float): Float
+ /** Returns the sum of this value and `x`. */
+ def +(x: Double): Double
+
+ /** Returns the difference of this value and `x`. */
+ def -(x: Byte): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Short): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Char): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Int): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Long): Long
+ /** Returns the difference of this value and `x`. */
+ def -(x: Float): Float
+ /** Returns the difference of this value and `x`. */
+ def -(x: Double): Double
+
+ /** Returns the product of this value and `x`. */
+ def *(x: Byte): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Short): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Char): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Int): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Long): Long
+ /** Returns the product of this value and `x`. */
+ def *(x: Float): Float
+ /** Returns the product of this value and `x`. */
+ def *(x: Double): Double
+
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Byte): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Short): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Char): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Int): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Long): Long
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Float): Float
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Double): Double
+
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Byte): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Short): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Char): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Int): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Long): Long
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Float): Float
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Double): Double
+
+ // Provide a more specific return type for Scaladoc
+ override def getClass(): Class[Char] = ???
+}
+
+object Char extends AnyValCompanion {
+ /** The smallest value representable as a Char. */
+ final val MinValue = java.lang.Character.MIN_VALUE
+
+ /** The largest value representable as a Char. */
+ final val MaxValue = java.lang.Character.MAX_VALUE
+
+ /** Transform a value type into a boxed reference type.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.boxToCharacter`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the Char to be boxed
+ * @return a java.lang.Character offering `x` as its underlying value.
+ */
+ def box(x: Char): java.lang.Character = ???
+
+ /** Transform a boxed type into a value type. Note that this
+ * method is not typesafe: it accepts any Object, but will throw
+ * an exception if the argument is not a java.lang.Character.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.unboxToChar`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the java.lang.Character to be unboxed.
+ * @throws ClassCastException if the argument is not a java.lang.Character
+ * @return the Char resulting from calling charValue() on `x`
+ */
+ def unbox(x: java.lang.Object): Char = ???
+
+ /** The String representation of the scala.Char companion object. */
+ override def toString = "object scala.Char"
+ /** Language mandated coercions from Char to "wider" types. */
+ import scala.language.implicitConversions
+ implicit def char2int(x: Char): Int = x.toInt
+ implicit def char2long(x: Char): Long = x.toLong
+ implicit def char2float(x: Char): Float = x.toFloat
+ implicit def char2double(x: Char): Double = x.toDouble
+}
+
diff --git a/library/src/scala/Console.scala b/library/src/scala/Console.scala
new file mode 100644
index 000000000000..82e5ac10413e
--- /dev/null
+++ b/library/src/scala/Console.scala
@@ -0,0 +1,281 @@
+/*
+ * 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
+
+import java.io.{ BufferedReader, InputStream, InputStreamReader, OutputStream, PrintStream, Reader }
+import scala.io.AnsiColor
+import scala.util.DynamicVariable
+
+/** Implements functionality for printing Scala values on the terminal. For reading values
+ * use [[scala.io.StdIn$ StdIn]].
+ * Also defines constants for marking up text on ANSI terminals.
+ *
+ * == Console Output ==
+ *
+ * Use the print methods to output text.
+ * {{{
+ * scala> Console.printf(
+ * "Today the outside temperature is a balmy %.1f°C. %<.1f°C beats the previous record of %.1f°C.\n",
+ * -137.0,
+ * -135.05)
+ * Today the outside temperature is a balmy -137.0°C. -137.0°C beats the previous record of -135.1°C.
+ * }}}
+ *
+ * == ANSI escape codes ==
+ * Use the ANSI escape codes for colorizing console output either to STDOUT or STDERR.
+ * {{{
+ * import Console.{GREEN, RED, RESET, YELLOW_B, UNDERLINED}
+ *
+ * object PrimeTest {
+ *
+ * def isPrime(): Unit = {
+ *
+ * val candidate = io.StdIn.readInt().ensuring(_ > 1)
+ *
+ * val prime = (2 to candidate - 1).forall(candidate % _ != 0)
+ *
+ * if (prime)
+ * Console.println(s"\${RESET}\${GREEN}yes\${RESET}")
+ * else
+ * Console.err.println(s"\${RESET}\${YELLOW_B}\${RED}\${UNDERLINED}NO!\${RESET}")
+ * }
+ *
+ * def main(args: Array[String]): Unit = isPrime()
+ *
+ * }
+ * }}}
+ *
+ *
+ *
\$ scala PrimeTest
+ *
1234567891
+ *
yes
+ *
\$ scala PrimeTest
+ *
56474
+ *
NO!
+ *
+ *
+ * == IO redefinition ==
+ *
+ * Use IO redefinition to temporarily swap in a different set of input and/or output streams. In this example the stream based
+ * method above is wrapped into a function.
+ *
+ * {{{
+ * import java.io.{ByteArrayOutputStream, StringReader}
+ *
+ * object FunctionalPrimeTest {
+ *
+ * def isPrime(candidate: Int): Boolean = {
+ *
+ * val input = new StringReader(s"\$candidate\n")
+ * val outCapture = new ByteArrayOutputStream
+ * val errCapture = new ByteArrayOutputStream
+ *
+ * Console.withIn(input) {
+ * Console.withOut(outCapture) {
+ * Console.withErr(errCapture) {
+ * PrimeTest.isPrime()
+ * }
+ * }
+ * }
+ *
+ * if (outCapture.toByteArray.nonEmpty) // "yes"
+ * true
+ * else if (errCapture.toByteArray.nonEmpty) // "NO!"
+ * false
+ * else throw new IllegalArgumentException(candidate.toString)
+ * }
+ *
+ * def main(args: Array[String]): Unit = {
+ * val primes = (2 to 50) filter (isPrime)
+ * println(s"First primes: \$primes")
+ * }
+ *
+ * }
+ * }}}
+ *
+ *
+ *
+ *
+ * @groupname console-output Console Output
+ * @groupprio console-output 30
+ * @groupdesc console-output These methods provide output via the console.
+ *
+ * @groupname io-default IO Defaults
+ * @groupprio io-default 50
+ * @groupdesc io-default These values provide direct access to the standard IO channels
+ *
+ * @groupname io-redefinition IO Redefinition
+ * @groupprio io-redefinition 60
+ * @groupdesc io-redefinition These methods allow substituting alternative streams for the duration of
+ * a body of code. Threadsafe by virtue of [[scala.util.DynamicVariable]].
+ *
+ */
+object Console extends AnsiColor {
+ private[this] val outVar = new DynamicVariable[PrintStream](java.lang.System.out)
+ private[this] val errVar = new DynamicVariable[PrintStream](java.lang.System.err)
+ private[this] val inVar = new DynamicVariable[BufferedReader](
+ new BufferedReader(new InputStreamReader(java.lang.System.in)))
+
+ protected def setOutDirect(out: PrintStream): Unit = outVar.value = out
+ protected def setErrDirect(err: PrintStream): Unit = errVar.value = err
+ protected def setInDirect(in: BufferedReader): Unit = inVar.value = in
+
+ /** The default output, can be overridden by `withOut`
+ * @group io-default
+ */
+ def out: PrintStream = outVar.value
+ /** The default error, can be overridden by `withErr`
+ * @group io-default
+ */
+ def err: PrintStream = errVar.value
+ /** The default input, can be overridden by `withIn`
+ * @group io-default
+ */
+ def in: BufferedReader = inVar.value
+
+ /** Sets the default output stream for the duration
+ * of execution of one thunk.
+ *
+ * @example {{{
+ * withOut(Console.err) { println("This goes to default _error_") }
+ * }}}
+ *
+ * @param out the new output stream.
+ * @param thunk the code to execute with
+ * the new output stream active
+ * @return the results of `thunk`
+ * @see `withOut[T](out:OutputStream)(thunk: => T)`
+ * @group io-redefinition
+ */
+ def withOut[T](out: PrintStream)(thunk: => T): T =
+ outVar.withValue(out)(thunk)
+
+ /** Sets the default output stream for the duration
+ * of execution of one thunk.
+ *
+ * @param out the new output stream.
+ * @param thunk the code to execute with
+ * the new output stream active
+ * @return the results of `thunk`
+ * @see `withOut[T](out:PrintStream)(thunk: => T)`
+ * @group io-redefinition
+ */
+ def withOut[T](out: OutputStream)(thunk: => T): T =
+ withOut(new PrintStream(out))(thunk)
+
+ /** Set the default error stream for the duration
+ * of execution of one thunk.
+ * @example {{{
+ * withErr(Console.out) { err.println("This goes to default _out_") }
+ * }}}
+ *
+ * @param err the new error stream.
+ * @param thunk the code to execute with
+ * the new error stream active
+ * @return the results of `thunk`
+ * @see `withErr[T](err:OutputStream)(thunk: => T)`
+ * @group io-redefinition
+ */
+ def withErr[T](err: PrintStream)(thunk: => T): T =
+ errVar.withValue(err)(thunk)
+
+ /** Sets the default error stream for the duration
+ * of execution of one thunk.
+ *
+ * @param err the new error stream.
+ * @param thunk the code to execute with
+ * the new error stream active
+ * @return the results of `thunk`
+ * @see `withErr[T](err:PrintStream)(thunk: => T)`
+ * @group io-redefinition
+ */
+ def withErr[T](err: OutputStream)(thunk: => T): T =
+ withErr(new PrintStream(err))(thunk)
+
+ /** Sets the default input stream for the duration
+ * of execution of one thunk.
+ *
+ * @example {{{
+ * val someFile:Reader = openFile("file.txt")
+ * withIn(someFile) {
+ * // Reads a line from file.txt instead of default input
+ * println(readLine)
+ * }
+ * }}}
+ *
+ * @param thunk the code to execute with
+ * the new input stream active
+ *
+ * @return the results of `thunk`
+ * @see `withIn[T](in:InputStream)(thunk: => T)`
+ * @group io-redefinition
+ */
+ def withIn[T](reader: Reader)(thunk: => T): T =
+ inVar.withValue(new BufferedReader(reader))(thunk)
+
+ /** Sets the default input stream for the duration
+ * of execution of one thunk.
+ *
+ * @param in the new input stream.
+ * @param thunk the code to execute with
+ * the new input stream active
+ * @return the results of `thunk`
+ * @see `withIn[T](reader:Reader)(thunk: => T)`
+ * @group io-redefinition
+ */
+ def withIn[T](in: InputStream)(thunk: => T): T =
+ withIn(new InputStreamReader(in))(thunk)
+
+ /** Prints an object to `out` using its `toString` method.
+ *
+ * @param obj the object to print; may be null.
+ * @group console-output
+ */
+ def print(obj: Any): Unit = {
+ out.print(if (null == obj) "null" else obj.toString())
+ }
+
+ /** Flushes the output stream. This function is required when partial
+ * output (i.e. output not terminated by a newline character) has
+ * to be made visible on the terminal.
+ * @group console-output
+ */
+ def flush(): Unit = { out.flush() }
+
+ /** Prints a newline character on the default output.
+ * @group console-output
+ */
+ def println(): Unit = { out.println() }
+
+ /** Prints out an object to the default output, followed by a newline character.
+ *
+ * @param x the object to print.
+ * @group console-output
+ */
+ def println(x: Any): Unit = { out.println(x) }
+
+ /** Prints its arguments as a formatted string to the default output,
+ * based on a string pattern (in a fashion similar to printf in C).
+ *
+ * The interpretation of the formatting patterns is described in [[java.util.Formatter]].
+ *
+ * @param text the pattern for formatting the arguments.
+ * @param args the arguments used to instantiating the pattern.
+ * @throws java.lang.IllegalArgumentException if there was a problem with the format string or arguments
+ * @group console-output
+ */
+ def printf(text: String, args: Any*): Unit = { out.print(text.format(args: _*)) }
+}
diff --git a/library/src/scala/DelayedInit.scala b/library/src/scala/DelayedInit.scala
new file mode 100644
index 000000000000..924d405d6c9d
--- /dev/null
+++ b/library/src/scala/DelayedInit.scala
@@ -0,0 +1,52 @@
+/*
+ * 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
+
+/** Classes and objects (but note, not traits) inheriting the `DelayedInit`
+ * marker trait will have their initialization code rewritten as follows:
+ * `code` becomes `delayedInit(code)`.
+ *
+ * Initialization code comprises all statements and all value definitions
+ * that are executed during initialization.
+ *
+ * Example:
+ * {{{
+ * trait Helper extends DelayedInit {
+ * def delayedInit(body: => Unit) = {
+ * println("dummy text, printed before initialization of C")
+ * body // evaluates the initialization code of C
+ * }
+ * }
+ *
+ * class C extends Helper {
+ * println("this is the initialization code of C")
+ * }
+ *
+ * object Test extends App {
+ * val c = new C
+ * }
+ * }}}
+ *
+ * Should result in the following being printed:
+ * {{{
+ * dummy text, printed before initialization of C
+ * this is the initialization code of C
+ * }}}
+ *
+ * @see "Delayed Initialization" subsection of the Scala Language Specification (section 5.1)
+ *
+ */
+@deprecated("DelayedInit semantics can be surprising. Support for `App` will continue. See the release notes for more details: https://github.com/scala/scala/releases/tag/v2.11.0", "2.11.0")
+trait DelayedInit {
+ def delayedInit(x: => Unit): Unit
+}
diff --git a/library/src/scala/Double.scala b/library/src/scala/Double.scala
new file mode 100644
index 000000000000..84d9f31daa90
--- /dev/null
+++ b/library/src/scala/Double.scala
@@ -0,0 +1,255 @@
+/*
+ * 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.
+ */
+
+// DO NOT EDIT, CHANGES WILL BE LOST
+// This auto-generated code can be modified in "project/GenerateAnyVals.scala".
+// Afterwards, running "sbt generateSources" regenerates this source file.
+
+package scala
+
+/** `Double`, a 64-bit IEEE-754 floating point number (equivalent to Java's `double` primitive type) is a
+ * subtype of [[scala.AnyVal]]. Instances of `Double` are not
+ * represented by an object in the underlying runtime system.
+ *
+ * There is an implicit conversion from [[scala.Double]] => [[scala.runtime.RichDouble]]
+ * which provides useful non-primitive operations.
+ */
+final abstract class Double private extends AnyVal {
+ def toByte: Byte
+ def toShort: Short
+ def toChar: Char
+ def toInt: Int
+ def toLong: Long
+ def toFloat: Float
+ def toDouble: Double
+
+ /** Returns this value, unmodified. */
+ def unary_+ : Double
+ /** Returns the negation of this value. */
+ def unary_- : Double
+
+ @deprecated("Adding a number and a String is deprecated. Use the string interpolation `s\"$num$str\"`", "2.13.0")
+ def +(x: String): String
+
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Byte): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Short): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Char): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Int): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Long): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Float): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Double): Boolean
+
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Byte): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Short): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Char): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Int): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Long): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Float): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Double): Boolean
+
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Byte): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Short): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Char): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Int): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Long): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Float): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Double): Boolean
+
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Byte): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Short): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Char): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Int): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Long): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Float): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Byte): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Short): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Char): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Int): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Long): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Float): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Byte): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Short): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Char): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Int): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Long): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Float): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Double): Boolean
+
+ /** Returns the sum of this value and `x`. */
+ def +(x: Byte): Double
+ /** Returns the sum of this value and `x`. */
+ def +(x: Short): Double
+ /** Returns the sum of this value and `x`. */
+ def +(x: Char): Double
+ /** Returns the sum of this value and `x`. */
+ def +(x: Int): Double
+ /** Returns the sum of this value and `x`. */
+ def +(x: Long): Double
+ /** Returns the sum of this value and `x`. */
+ def +(x: Float): Double
+ /** Returns the sum of this value and `x`. */
+ def +(x: Double): Double
+
+ /** Returns the difference of this value and `x`. */
+ def -(x: Byte): Double
+ /** Returns the difference of this value and `x`. */
+ def -(x: Short): Double
+ /** Returns the difference of this value and `x`. */
+ def -(x: Char): Double
+ /** Returns the difference of this value and `x`. */
+ def -(x: Int): Double
+ /** Returns the difference of this value and `x`. */
+ def -(x: Long): Double
+ /** Returns the difference of this value and `x`. */
+ def -(x: Float): Double
+ /** Returns the difference of this value and `x`. */
+ def -(x: Double): Double
+
+ /** Returns the product of this value and `x`. */
+ def *(x: Byte): Double
+ /** Returns the product of this value and `x`. */
+ def *(x: Short): Double
+ /** Returns the product of this value and `x`. */
+ def *(x: Char): Double
+ /** Returns the product of this value and `x`. */
+ def *(x: Int): Double
+ /** Returns the product of this value and `x`. */
+ def *(x: Long): Double
+ /** Returns the product of this value and `x`. */
+ def *(x: Float): Double
+ /** Returns the product of this value and `x`. */
+ def *(x: Double): Double
+
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Byte): Double
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Short): Double
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Char): Double
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Int): Double
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Long): Double
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Float): Double
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Double): Double
+
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Byte): Double
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Short): Double
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Char): Double
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Int): Double
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Long): Double
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Float): Double
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Double): Double
+
+ // Provide a more specific return type for Scaladoc
+ override def getClass(): Class[Double] = ???
+}
+
+object Double extends AnyValCompanion {
+ /** The smallest positive value greater than 0.0d which is
+ * representable as a Double.
+ */
+ final val MinPositiveValue = java.lang.Double.MIN_VALUE
+ final val NaN = java.lang.Double.NaN
+ final val PositiveInfinity = java.lang.Double.POSITIVE_INFINITY
+ final val NegativeInfinity = java.lang.Double.NEGATIVE_INFINITY
+
+ /** The negative number with the greatest (finite) absolute value which is representable
+ * by a Double. Note that it differs from [[java.lang.Double.MIN_VALUE]], which
+ * is the smallest positive value representable by a Double. In Scala that number
+ * is called Double.MinPositiveValue.
+ */
+ final val MinValue = -java.lang.Double.MAX_VALUE
+
+ /** The largest finite positive number representable as a Double. */
+ final val MaxValue = java.lang.Double.MAX_VALUE
+
+ /** Transform a value type into a boxed reference type.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.boxToDouble`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the Double to be boxed
+ * @return a java.lang.Double offering `x` as its underlying value.
+ */
+ def box(x: Double): java.lang.Double = ???
+
+ /** Transform a boxed type into a value type. Note that this
+ * method is not typesafe: it accepts any Object, but will throw
+ * an exception if the argument is not a java.lang.Double.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.unboxToDouble`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the java.lang.Double to be unboxed.
+ * @throws ClassCastException if the argument is not a java.lang.Double
+ * @return the Double resulting from calling doubleValue() on `x`
+ */
+ def unbox(x: java.lang.Object): Double = ???
+
+ /** The String representation of the scala.Double companion object. */
+ override def toString = "object scala.Double"
+}
+
diff --git a/library/src/scala/DummyImplicit.scala b/library/src/scala/DummyImplicit.scala
new file mode 100644
index 000000000000..07e7acfc6ebb
--- /dev/null
+++ b/library/src/scala/DummyImplicit.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
+
+/** A type for which there is always an implicit value. */
+final class DummyImplicit private ()
+
+object DummyImplicit {
+ /** An implicit value yielding a `DummyImplicit`. */
+ implicit val dummyImplicit: DummyImplicit = new DummyImplicit
+}
diff --git a/library/src/scala/Dynamic.scala b/library/src/scala/Dynamic.scala
new file mode 100644
index 000000000000..f80df3e49b7d
--- /dev/null
+++ b/library/src/scala/Dynamic.scala
@@ -0,0 +1,38 @@
+/*
+ * 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
+
+/** A marker trait that enables dynamic invocations. Instances `x` of this
+ * trait allow method invocations `x.meth(args)` for arbitrary method
+ * names `meth` and argument lists `args` as well as field accesses
+ * `x.field` for arbitrary field names `field`.
+ *
+ * If a call is not natively supported by `x` (i.e. if type checking
+ * fails), it is rewritten according to the following rules:
+ *
+ * {{{
+ * foo.method("blah") ~~> foo.applyDynamic("method")("blah")
+ * foo.method(x = "blah") ~~> foo.applyDynamicNamed("method")(("x", "blah"))
+ * foo.method(x = 1, 2) ~~> foo.applyDynamicNamed("method")(("x", 1), ("", 2))
+ * foo.field ~~> foo.selectDynamic("field")
+ * foo.varia = 10 ~~> foo.updateDynamic("varia")(10)
+ * foo.arr(10) = 13 ~~> foo.selectDynamic("arr").update(10, 13)
+ * foo.arr(10) ~~> foo.applyDynamic("arr")(10)
+ * }}}
+ *
+ * Defining direct or indirect subclasses of this trait
+ * is only possible if the language feature `dynamics` is enabled.
+ */
+trait Dynamic extends Any
+
+
diff --git a/library/src/scala/Enumeration.scala b/library/src/scala/Enumeration.scala
new file mode 100644
index 000000000000..bf61198f7d3b
--- /dev/null
+++ b/library/src/scala/Enumeration.scala
@@ -0,0 +1,350 @@
+/*
+ * 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
+
+import scala.collection.{SpecificIterableFactory, StrictOptimizedIterableOps, View, immutable, mutable}
+import java.lang.reflect.{Field => JField, Method => JMethod}
+
+import scala.annotation.{implicitNotFound, tailrec}
+import scala.reflect.NameTransformer._
+import scala.util.matching.Regex
+
+/** Defines a finite set of values specific to the enumeration. Typically
+ * these values enumerate all possible forms something can take and provide
+ * a lightweight alternative to case classes.
+ *
+ * Each call to a `Value` method adds a new unique value to the enumeration.
+ * To be accessible, these values are usually defined as `val` members of
+ * the enumeration.
+ *
+ * All values in an enumeration share a common, unique type defined as the
+ * `Value` type member of the enumeration (`Value` selected on the stable
+ * identifier path of the enumeration instance).
+ *
+ * Values SHOULD NOT be added to an enumeration after its construction;
+ * doing so makes the enumeration thread-unsafe. If values are added to an
+ * enumeration from multiple threads (in a non-synchronized fashion) after
+ * construction, the behavior of the enumeration is undefined.
+ *
+ * @example {{{
+ * // Define a new enumeration with a type alias and work with the full set of enumerated values
+ * object WeekDay extends Enumeration {
+ * type WeekDay = Value
+ * val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
+ * }
+ * import WeekDay._
+ *
+ * def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)
+ *
+ * WeekDay.values filter isWorkingDay foreach println
+ * // output:
+ * // Mon
+ * // Tue
+ * // Wed
+ * // Thu
+ * // Fri
+ * }}}
+ *
+ * @example {{{
+ * // Example of adding attributes to an enumeration by extending the Enumeration.Val class
+ * object Planet extends Enumeration {
+ * protected case class PlanetVal(mass: Double, radius: Double) extends super.Val {
+ * def surfaceGravity: Double = Planet.G * mass / (radius * radius)
+ * def surfaceWeight(otherMass: Double): Double = otherMass * surfaceGravity
+ * }
+ * import scala.language.implicitConversions
+ * implicit def valueToPlanetVal(x: Value): PlanetVal = x.asInstanceOf[PlanetVal]
+ *
+ * val G: Double = 6.67300E-11
+ * val Mercury = PlanetVal(3.303e+23, 2.4397e6)
+ * val Venus = PlanetVal(4.869e+24, 6.0518e6)
+ * val Earth = PlanetVal(5.976e+24, 6.37814e6)
+ * val Mars = PlanetVal(6.421e+23, 3.3972e6)
+ * val Jupiter = PlanetVal(1.9e+27, 7.1492e7)
+ * val Saturn = PlanetVal(5.688e+26, 6.0268e7)
+ * val Uranus = PlanetVal(8.686e+25, 2.5559e7)
+ * val Neptune = PlanetVal(1.024e+26, 2.4746e7)
+ * }
+ *
+ * println(Planet.values.filter(_.radius > 7.0e6))
+ * // output:
+ * // Planet.ValueSet(Jupiter, Saturn, Uranus, Neptune)
+ * }}}
+ *
+ * @param initial The initial value from which to count the integers that
+ * identifies values at run-time.
+ */
+@SerialVersionUID(8476000850333817230L)
+abstract class Enumeration (initial: Int) extends Serializable {
+ thisenum =>
+
+ def this() = this(0)
+
+ /* Note that `readResolve` cannot be private, since otherwise
+ the JVM does not invoke it when deserializing subclasses. */
+ protected def readResolve(): AnyRef = thisenum.getClass.getField(MODULE_INSTANCE_NAME).get(null)
+
+ /** The name of this enumeration.
+ */
+ override def toString: String =
+ ((getClass.getName stripSuffix MODULE_SUFFIX_STRING split '.').last split
+ Regex.quote(NAME_JOIN_STRING)).last
+
+ /** The mapping from the integer used to identify values to the actual
+ * values. */
+ private val vmap: mutable.Map[Int, Value] = new mutable.HashMap
+
+ /** The cache listing all values of this enumeration. */
+ @transient private var vset: ValueSet = null
+ @transient @volatile private var vsetDefined = false
+
+ /** The mapping from the integer used to identify values to their
+ * names. */
+ private[this] val nmap: mutable.Map[Int, String] = new mutable.HashMap
+
+ /** The values of this enumeration as a set.
+ */
+ def values: ValueSet = {
+ if (!vsetDefined) {
+ vset = (ValueSet.newBuilder ++= vmap.values).result()
+ vsetDefined = true
+ }
+ vset
+ }
+
+ /** The integer to use to identify the next created value. */
+ protected var nextId: Int = initial
+
+ /** The string to use to name the next created value. */
+ protected var nextName: Iterator[String] = _
+
+ private def nextNameOrNull =
+ if (nextName != null && nextName.hasNext) nextName.next() else null
+
+ /** The highest integer amongst those used to identify values in this
+ * enumeration. */
+ private[this] var topId = initial
+
+ /** The lowest integer amongst those used to identify values in this
+ * enumeration, but no higher than 0. */
+ private[this] var bottomId = if(initial < 0) initial else 0
+
+ /** The one higher than the highest integer amongst those used to identify
+ * values in this enumeration. */
+ final def maxId = topId
+
+ /** The value of this enumeration with given id `x`
+ */
+ final def apply(x: Int): Value = vmap(x)
+
+ /** Return a `Value` from this `Enumeration` whose name matches
+ * the argument `s`. The names are determined automatically via reflection.
+ *
+ * @param s an `Enumeration` name
+ * @return the `Value` of this `Enumeration` if its name matches `s`
+ * @throws NoSuchElementException if no `Value` with a matching
+ * name is in this `Enumeration`
+ */
+ final def withName(s: String): Value = values.byName.getOrElse(s,
+ throw new NoSuchElementException(s"No value found for '$s'"))
+
+ /** Creates a fresh value, part of this enumeration. */
+ protected final def Value: Value = Value(nextId)
+
+ /** Creates a fresh value, part of this enumeration, identified by the
+ * integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @return Fresh value identified by `i`.
+ */
+ protected final def Value(i: Int): Value = Value(i, nextNameOrNull)
+
+ /** Creates a fresh value, part of this enumeration, called `name`.
+ *
+ * @param name A human-readable name for that value.
+ * @return Fresh value called `name`.
+ */
+ protected final def Value(name: String): Value = Value(nextId, name)
+
+ /** Creates a fresh value, part of this enumeration, called `name`
+ * and identified by the integer `i`.
+ *
+ * @param i An integer that identifies this value at run-time. It must be
+ * unique amongst all values of the enumeration.
+ * @param name A human-readable name for that value.
+ * @return Fresh value with the provided identifier `i` and name `name`.
+ */
+ protected final def Value(i: Int, name: String): Value = new Val(i, name)
+
+ private def populateNameMap(): Unit = {
+ @tailrec def getFields(clazz: Class[_], acc: Array[JField]): Array[JField] = {
+ if (clazz == null)
+ acc
+ else
+ getFields(clazz.getSuperclass, if (clazz.getDeclaredFields.isEmpty) acc else acc ++ clazz.getDeclaredFields)
+ }
+ val fields = getFields(getClass.getSuperclass, getClass.getDeclaredFields)
+ def isValDef(m: JMethod): Boolean = fields exists (fd => fd.getName == m.getName && fd.getType == m.getReturnType)
+
+ // The list of possible Value methods: 0-args which return a conforming type
+ val methods: Array[JMethod] = getClass.getMethods filter (m => m.getParameterTypes.isEmpty &&
+ classOf[Value].isAssignableFrom(m.getReturnType) &&
+ m.getDeclaringClass != classOf[Enumeration] &&
+ isValDef(m))
+ methods foreach { m =>
+ val name = m.getName
+ // invoke method to obtain actual `Value` instance
+ val value = m.invoke(this).asInstanceOf[Value]
+ // verify that outer points to the correct Enumeration: ticket #3616.
+ if (value.outerEnum eq thisenum) {
+ val id: Int = value.id
+ nmap += ((id, name))
+ }
+ }
+ }
+
+ /* Obtains the name for the value with id `i`. If no name is cached
+ * in `nmap`, it populates `nmap` using reflection.
+ */
+ private def nameOf(i: Int): String = synchronized { nmap.getOrElse(i, { populateNameMap() ; nmap(i) }) }
+
+ /** The type of the enumerated values. */
+ @SerialVersionUID(7091335633555234129L)
+ abstract class Value extends Ordered[Value] with Serializable {
+ /** the id and bit location of this enumeration value */
+ def id: Int
+ /** a marker so we can tell whose values belong to whom come reflective-naming time */
+ private[Enumeration] val outerEnum = thisenum
+
+ override def compare(that: Value): Int =
+ if (this.id < that.id) -1
+ else if (this.id == that.id) 0
+ else 1
+ override def equals(other: Any): Boolean = other match {
+ case that: Enumeration#Value => (outerEnum eq that.outerEnum) && (id == that.id)
+ case _ => false
+ }
+ override def hashCode: Int = id.##
+
+ /** Create a ValueSet which contains this value and another one */
+ def + (v: Value): ValueSet = ValueSet(this, v)
+ }
+
+ /** A class implementing the [[scala.Enumeration.Value]] type. This class
+ * can be overridden to change the enumeration's naming and integer
+ * identification behaviour.
+ */
+ @SerialVersionUID(0 - 3501153230598116017L)
+ protected class Val(i: Int, name: String) extends Value with Serializable {
+ def this(i: Int) = this(i, nextNameOrNull)
+ def this(name: String) = this(nextId, name)
+ def this() = this(nextId)
+
+ assert(!vmap.isDefinedAt(i), "Duplicate id: " + i)
+ vmap(i) = this
+ vsetDefined = false
+ nextId = i + 1
+ if (nextId > topId) topId = nextId
+ if (i < bottomId) bottomId = i
+ def id: Int = i
+ override def toString(): String =
+ if (name != null) name
+ else try thisenum.nameOf(i)
+ catch { case _: NoSuchElementException => "" }
+
+ protected def readResolve(): AnyRef = {
+ val enumeration = thisenum.readResolve().asInstanceOf[Enumeration]
+ if (enumeration.vmap == null) this
+ else enumeration.vmap(i)
+ }
+ }
+
+ /** An ordering by id for values of this set */
+ implicit object ValueOrdering extends Ordering[Value] {
+ def compare(x: Value, y: Value): Int = x compare y
+ }
+
+ /** A class for sets of values.
+ * Iterating through this set will yield values in increasing order of their ids.
+ *
+ * @param nnIds The set of ids of values (adjusted so that the lowest value does
+ * not fall below zero), organized as a `BitSet`.
+ * @define Coll `collection.immutable.SortedSet`
+ */
+ @SerialVersionUID(7229671200427364242L)
+ class ValueSet private[ValueSet] (private[this] var nnIds: immutable.BitSet)
+ extends immutable.AbstractSet[Value]
+ with immutable.SortedSet[Value]
+ with immutable.SortedSetOps[Value, immutable.SortedSet, ValueSet]
+ with StrictOptimizedIterableOps[Value, immutable.Set, ValueSet]
+ with Serializable {
+
+ implicit def ordering: Ordering[Value] = ValueOrdering
+ def rangeImpl(from: Option[Value], until: Option[Value]): ValueSet =
+ new ValueSet(nnIds.rangeImpl(from.map(_.id - bottomId), until.map(_.id - bottomId)))
+
+ override def empty: ValueSet = ValueSet.empty
+ override def knownSize: Int = nnIds.size
+ override def isEmpty: Boolean = nnIds.isEmpty
+ def contains(v: Value): Boolean = nnIds contains (v.id - bottomId)
+ def incl (value: Value): ValueSet = new ValueSet(nnIds + (value.id - bottomId))
+ def excl (value: Value): ValueSet = new ValueSet(nnIds - (value.id - bottomId))
+ def iterator: Iterator[Value] = nnIds.iterator map (id => thisenum.apply(bottomId + id))
+ override def iteratorFrom(start: Value): Iterator[Value] = nnIds iteratorFrom start.id map (id => thisenum.apply(bottomId + id))
+ override def className: String = s"$thisenum.ValueSet"
+ /** Creates a bit mask for the zero-adjusted ids in this set as a
+ * new array of longs */
+ def toBitMask: Array[Long] = nnIds.toBitMask
+
+ override protected def fromSpecific(coll: IterableOnce[Value]): ValueSet = ValueSet.fromSpecific(coll)
+ override protected def newSpecificBuilder = ValueSet.newBuilder
+
+ def map(f: Value => Value): ValueSet = fromSpecific(new View.Map(this, f))
+ def flatMap(f: Value => IterableOnce[Value]): ValueSet = fromSpecific(new View.FlatMap(this, f))
+
+ // necessary for disambiguation:
+ override def map[B](f: Value => B)(implicit @implicitNotFound(ValueSet.ordMsg) ev: Ordering[B]): immutable.SortedSet[B] =
+ super[SortedSet].map[B](f)
+ override def flatMap[B](f: Value => IterableOnce[B])(implicit @implicitNotFound(ValueSet.ordMsg) ev: Ordering[B]): immutable.SortedSet[B] =
+ super[SortedSet].flatMap[B](f)
+ override def zip[B](that: IterableOnce[B])(implicit @implicitNotFound(ValueSet.zipOrdMsg) ev: Ordering[(Value, B)]): immutable.SortedSet[(Value, B)] =
+ super[SortedSet].zip[B](that)
+ override def collect[B](pf: PartialFunction[Value, B])(implicit @implicitNotFound(ValueSet.ordMsg) ev: Ordering[B]): immutable.SortedSet[B] =
+ super[SortedSet].collect[B](pf)
+
+ @transient private[Enumeration] lazy val byName: Map[String, Value] = iterator.map( v => v.toString -> v).toMap
+ }
+
+ /** A factory object for value sets */
+ @SerialVersionUID(3L)
+ object ValueSet extends SpecificIterableFactory[Value, ValueSet] {
+ private final val ordMsg = "No implicit Ordering[${B}] found to build a SortedSet[${B}]. You may want to upcast to a Set[Value] first by calling `unsorted`."
+ private final val zipOrdMsg = "No implicit Ordering[${B}] found to build a SortedSet[(Value, ${B})]. You may want to upcast to a Set[Value] first by calling `unsorted`."
+
+ /** The empty value set */
+ val empty: ValueSet = new ValueSet(immutable.BitSet.empty)
+ /** A value set containing all the values for the zero-adjusted ids
+ * corresponding to the bits in an array */
+ def fromBitMask(elems: Array[Long]): ValueSet = new ValueSet(immutable.BitSet.fromBitMask(elems))
+ /** A builder object for value sets */
+ def newBuilder: mutable.Builder[Value, ValueSet] = new mutable.Builder[Value, ValueSet] {
+ private[this] val b = new mutable.BitSet
+ def addOne (x: Value) = { b += (x.id - bottomId); this }
+ def clear() = b.clear()
+ def result() = new ValueSet(b.toImmutable)
+ }
+ def fromSpecific(it: IterableOnce[Value]): ValueSet =
+ newBuilder.addAll(it).result()
+ }
+}
diff --git a/library/src/scala/Equals.scala b/library/src/scala/Equals.scala
new file mode 100644
index 000000000000..0c35742a6746
--- /dev/null
+++ b/library/src/scala/Equals.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.
+ */
+
+package scala
+
+/** An interface containing operations for equality.
+ * The only method not already present in class `AnyRef` is `canEqual`.
+ */
+trait Equals extends Any {
+ /** Checks whether this instance can possibly equal `that`.
+ *
+ * A method that should be called from every well-designed equals method
+ * that is open to be overridden in a subclass. See
+ * [[https://www.artima.com/pins1ed/object-equality.html Programming in Scala,
+ * Chapter 28]] for discussion and design.
+ *
+ * @param that the value being probed for possible equality
+ * @return true if this instance can possibly equal `that`, otherwise false
+ */
+ def canEqual(that: Any): Boolean
+
+ /** Checks whether this instance is equal to `that`.
+ * This universal equality method is defined in `AnyRef`.
+ */
+ def equals(that: Any): Boolean
+}
diff --git a/library/src/scala/Float.scala b/library/src/scala/Float.scala
new file mode 100644
index 000000000000..c63620ed8d53
--- /dev/null
+++ b/library/src/scala/Float.scala
@@ -0,0 +1,258 @@
+/*
+ * 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.
+ */
+
+// DO NOT EDIT, CHANGES WILL BE LOST
+// This auto-generated code can be modified in "project/GenerateAnyVals.scala".
+// Afterwards, running "sbt generateSources" regenerates this source file.
+
+package scala
+
+/** `Float`, a 32-bit IEEE-754 floating point number (equivalent to Java's `float` primitive type) is a
+ * subtype of [[scala.AnyVal]]. Instances of `Float` are not
+ * represented by an object in the underlying runtime system.
+ *
+ * There is an implicit conversion from [[scala.Float]] => [[scala.runtime.RichFloat]]
+ * which provides useful non-primitive operations.
+ */
+final abstract class Float private extends AnyVal {
+ def toByte: Byte
+ def toShort: Short
+ def toChar: Char
+ def toInt: Int
+ def toLong: Long
+ def toFloat: Float
+ def toDouble: Double
+
+ /** Returns this value, unmodified. */
+ def unary_+ : Float
+ /** Returns the negation of this value. */
+ def unary_- : Float
+
+ @deprecated("Adding a number and a String is deprecated. Use the string interpolation `s\"$num$str\"`", "2.13.0")
+ def +(x: String): String
+
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Byte): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Short): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Char): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Int): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Long): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Float): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Double): Boolean
+
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Byte): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Short): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Char): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Int): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Long): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Float): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Double): Boolean
+
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Byte): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Short): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Char): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Int): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Long): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Float): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Double): Boolean
+
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Byte): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Short): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Char): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Int): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Long): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Float): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Byte): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Short): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Char): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Int): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Long): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Float): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Byte): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Short): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Char): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Int): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Long): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Float): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Double): Boolean
+
+ /** Returns the sum of this value and `x`. */
+ def +(x: Byte): Float
+ /** Returns the sum of this value and `x`. */
+ def +(x: Short): Float
+ /** Returns the sum of this value and `x`. */
+ def +(x: Char): Float
+ /** Returns the sum of this value and `x`. */
+ def +(x: Int): Float
+ /** Returns the sum of this value and `x`. */
+ def +(x: Long): Float
+ /** Returns the sum of this value and `x`. */
+ def +(x: Float): Float
+ /** Returns the sum of this value and `x`. */
+ def +(x: Double): Double
+
+ /** Returns the difference of this value and `x`. */
+ def -(x: Byte): Float
+ /** Returns the difference of this value and `x`. */
+ def -(x: Short): Float
+ /** Returns the difference of this value and `x`. */
+ def -(x: Char): Float
+ /** Returns the difference of this value and `x`. */
+ def -(x: Int): Float
+ /** Returns the difference of this value and `x`. */
+ def -(x: Long): Float
+ /** Returns the difference of this value and `x`. */
+ def -(x: Float): Float
+ /** Returns the difference of this value and `x`. */
+ def -(x: Double): Double
+
+ /** Returns the product of this value and `x`. */
+ def *(x: Byte): Float
+ /** Returns the product of this value and `x`. */
+ def *(x: Short): Float
+ /** Returns the product of this value and `x`. */
+ def *(x: Char): Float
+ /** Returns the product of this value and `x`. */
+ def *(x: Int): Float
+ /** Returns the product of this value and `x`. */
+ def *(x: Long): Float
+ /** Returns the product of this value and `x`. */
+ def *(x: Float): Float
+ /** Returns the product of this value and `x`. */
+ def *(x: Double): Double
+
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Byte): Float
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Short): Float
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Char): Float
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Int): Float
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Long): Float
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Float): Float
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Double): Double
+
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Byte): Float
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Short): Float
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Char): Float
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Int): Float
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Long): Float
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Float): Float
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Double): Double
+
+ // Provide a more specific return type for Scaladoc
+ override def getClass(): Class[Float] = ???
+}
+
+object Float extends AnyValCompanion {
+ /** The smallest positive value greater than 0.0f which is
+ * representable as a Float.
+ */
+ final val MinPositiveValue = java.lang.Float.MIN_VALUE
+ final val NaN = java.lang.Float.NaN
+ final val PositiveInfinity = java.lang.Float.POSITIVE_INFINITY
+ final val NegativeInfinity = java.lang.Float.NEGATIVE_INFINITY
+
+ /** The negative number with the greatest (finite) absolute value which is representable
+ * by a Float. Note that it differs from [[java.lang.Float.MIN_VALUE]], which
+ * is the smallest positive value representable by a Float. In Scala that number
+ * is called Float.MinPositiveValue.
+ */
+ final val MinValue = -java.lang.Float.MAX_VALUE
+
+ /** The largest finite positive number representable as a Float. */
+ final val MaxValue = java.lang.Float.MAX_VALUE
+
+ /** Transform a value type into a boxed reference type.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.boxToFloat`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the Float to be boxed
+ * @return a java.lang.Float offering `x` as its underlying value.
+ */
+ def box(x: Float): java.lang.Float = ???
+
+ /** Transform a boxed type into a value type. Note that this
+ * method is not typesafe: it accepts any Object, but will throw
+ * an exception if the argument is not a java.lang.Float.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.unboxToFloat`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the java.lang.Float to be unboxed.
+ * @throws ClassCastException if the argument is not a java.lang.Float
+ * @return the Float resulting from calling floatValue() on `x`
+ */
+ def unbox(x: java.lang.Object): Float = ???
+
+ /** The String representation of the scala.Float companion object. */
+ override def toString = "object scala.Float"
+ /** Language mandated coercions from Float to "wider" types. */
+ import scala.language.implicitConversions
+ implicit def float2double(x: Float): Double = x.toDouble
+}
+
diff --git a/library/src/scala/Function.scala b/library/src/scala/Function.scala
new file mode 100644
index 000000000000..be612752552e
--- /dev/null
+++ b/library/src/scala/Function.scala
@@ -0,0 +1,130 @@
+/*
+ * 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
+
+/** A module defining utility methods for higher-order functional programming.
+ */
+object Function {
+ /** Given a sequence of functions `f,,1,,`, ..., `f,,n,,`, return the
+ * function `f,,1,, andThen ... andThen f,,n,,`.
+ *
+ * @param fs The given sequence of functions
+ */
+ def chain[T](fs: scala.collection.Seq[T => T]): T => T = { x => fs.foldLeft(x)((x, f) => f(x)) }
+
+ /** The constant function */
+ def const[T, U](x: T)(y: U): T = x
+
+ /** Turns a function `A => Option[B]` into a `PartialFunction[A, B]`.
+ *
+ * '''Important note''': this transformation implies the original function
+ * may be called 2 or more times on each logical invocation, because the
+ * only way to supply an implementation of `isDefinedAt` is to call the
+ * function and examine the return value.
+ * See also [[scala.PartialFunction]], method `applyOrElse`.
+ *
+ * @param f a function `T => Option[R]`
+ * @return a partial function defined for those inputs where
+ * f returns `Some(_)` and undefined where `f` returns `None`.
+ * @see [[scala.PartialFunction]], method `lift`.
+ */
+ def unlift[T, R](f: T => Option[R]): PartialFunction[T, R] = PartialFunction.unlifted(f)
+
+ /** Uncurrying for functions of arity 2. This transforms a unary function
+ * returning another unary function into a function of arity 2.
+ */
+ def uncurried[T1, T2, R](f: T1 => T2 => R): (T1, T2) => R = {
+ (x1, x2) => f(x1)(x2)
+ }
+
+ /** Uncurrying for functions of arity 3.
+ */
+ def uncurried[T1, T2, T3, R](f: T1 => T2 => T3 => R): (T1, T2, T3) => R = {
+ (x1, x2, x3) => f(x1)(x2)(x3)
+ }
+
+ /** Uncurrying for functions of arity 4.
+ */
+ def uncurried[T1, T2, T3, T4, R](f: T1 => T2 => T3 => T4 => R): (T1, T2, T3, T4) => R = {
+ (x1, x2, x3, x4) => f(x1)(x2)(x3)(x4)
+ }
+
+ /** Uncurrying for functions of arity 5.
+ */
+ def uncurried[T1, T2, T3, T4, T5, R](f: T1 => T2 => T3 => T4 => T5 => R): (T1, T2, T3, T4, T5) => R = {
+ (x1, x2, x3, x4, x5) => f(x1)(x2)(x3)(x4)(x5)
+ }
+
+ /** Tupling for functions of arity 2. This transforms a function
+ * of arity 2 into a unary function that takes a pair of arguments.
+ *
+ * @note These functions are slotted for deprecation, but it is on
+ * hold pending superior type inference for tupling anonymous functions.
+ */
+ // @deprecated("use `f.tupled` instead")
+ def tupled[T1, T2, R](f: (T1, T2) => R): ((T1, T2)) => R = {
+ case ((x1, x2)) => f(x1, x2)
+ }
+
+ /** Tupling for functions of arity 3. This transforms a function
+ * of arity 3 into a unary function that takes a triple of arguments.
+ */
+ // @deprecated("use `f.tupled` instead")
+ def tupled[T1, T2, T3, R](f: (T1, T2, T3) => R): ((T1, T2, T3)) => R = {
+ case ((x1, x2, x3)) => f(x1, x2, x3)
+ }
+
+ /** Tupling for functions of arity 4. This transforms a function
+ * of arity 4 into a unary function that takes a 4-tuple of arguments.
+ */
+ // @deprecated("use `f.tupled` instead")
+ def tupled[T1, T2, T3, T4, R](f: (T1, T2, T3, T4) => R): ((T1, T2, T3, T4)) => R = {
+ case ((x1, x2, x3, x4)) => f(x1, x2, x3, x4)
+ }
+
+ /** Tupling for functions of arity 5. This transforms a function
+ * of arity 5 into a unary function that takes a 5-tuple of arguments.
+ */
+ // @deprecated("use `f.tupled` instead")
+ def tupled[T1, T2, T3, T4, T5, R](f: (T1, T2, T3, T4, T5) => R): ((T1, T2, T3, T4, T5)) => R = {
+ case ((x1, x2, x3, x4, x5)) => f(x1, x2, x3, x4, x5)
+ }
+
+ /** Un-tupling for functions of arity 2. This transforms a function taking
+ * a pair of arguments into a binary function which takes each argument separately.
+ */
+ def untupled[T1, T2, R](f: ((T1, T2)) => R): (T1, T2) => R = {
+ (x1, x2) => f((x1, x2))
+ }
+
+ /** Un-tupling for functions of arity 3. This transforms a function taking
+ * a triple of arguments into a ternary function which takes each argument separately.
+ */
+ def untupled[T1, T2, T3, R](f: ((T1, T2, T3)) => R): (T1, T2, T3) => R = {
+ (x1, x2, x3) => f((x1, x2, x3))
+ }
+
+ /** Un-tupling for functions of arity 4. This transforms a function taking
+ * a 4-tuple of arguments into a function of arity 4 which takes each argument separately.
+ */
+ def untupled[T1, T2, T3, T4, R](f: ((T1, T2, T3, T4)) => R): (T1, T2, T3, T4) => R = {
+ (x1, x2, x3, x4) => f((x1, x2, x3, x4))
+ }
+
+ /** Un-tupling for functions of arity 5. This transforms a function taking
+ * a 5-tuple of arguments into a function of arity 5 which takes each argument separately.
+ */
+ def untupled[T1, T2, T3, T4, T5, R](f: ((T1, T2, T3, T4, T5)) => R): (T1, T2, T3, T4, T5) => R = {
+ (x1, x2, x3, x4, x5) => f((x1, x2, x3, x4, x5))
+ }
+}
diff --git a/library/src/scala/Function0.scala b/library/src/scala/Function0.scala
new file mode 100644
index 000000000000..0cdea05ebc05
--- /dev/null
+++ b/library/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/library/src/scala/Function1.scala b/library/src/scala/Function1.scala
new file mode 100644
index 000000000000..10d366303ab2
--- /dev/null
+++ b/library/src/scala/Function1.scala
@@ -0,0 +1,90 @@
+/*
+ * 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 Function1 {
+
+ implicit final class UnliftOps[A, B] private[Function1](private val f: A => Option[B]) extends AnyVal {
+ /** Converts an optional function to a partial function.
+ *
+ * @example Unlike [[Function.unlift]], this [[UnliftOps.unlift]] method can be used in extractors.
+ * {{{
+ * val of: Int => Option[String] = { i =>
+ * if (i == 2) {
+ * Some("matched by an optional function")
+ * } else {
+ * None
+ * }
+ * }
+ *
+ * util.Random.nextInt(4) match {
+ * case of.unlift(m) => // Convert an optional function to a pattern
+ * println(m)
+ * case _ =>
+ * println("Not matched")
+ * }
+ * }}}
+ */
+ def unlift: PartialFunction[A, B] = Function.unlift(f)
+ }
+
+}
+
+/** A function of 1 parameter.
+ *
+ * In the following example, the definition of `succ` is
+ * shorthand, conceptually, for the anonymous class definition
+ * `anonfun1`, although the implementation details of how the
+ * function value is constructed may differ:
+ *
+ * {{{
+ * object Main extends App {
+ * val succ = (x: Int) => x + 1
+ * val anonfun1 = new Function1[Int, Int] {
+ * def apply(x: Int): Int = x + 1
+ * }
+ * assert(succ(0) == anonfun1(0))
+ * }
+ * }}}
+ *
+ * Note that the difference between `Function1` and [[scala.PartialFunction]]
+ * 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 { 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.
+ *
+ * @tparam A the type to which function `g` can be applied
+ * @param g a function A => T1
+ * @return a new function `f` such that `f(x) == apply(g(x))`
+ */
+ @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.
+ *
+ * @tparam A the result type of function `g`
+ * @param g a function R => A
+ * @return a new function `f` such that `f(x) == g(apply(x))`
+ */
+ @annotation.unspecialized def andThen[A](g: R => A): T1 => A = { x => g(apply(x)) }
+
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function10.scala b/library/src/scala/Function10.scala
new file mode 100644
index 000000000000..59192bf8ee7d
--- /dev/null
+++ b/library/src/scala/Function10.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 10 parameters.
+ *
+ */
+trait Function10[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9)(x10) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => T10 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9, x10: T10) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)).curried
+ }
+ /** Creates a tupled version of this function: instead of 10 arguments,
+ * it accepts a single [[scala.Tuple10]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)) == f(Tuple10(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function11.scala b/library/src/scala/Function11.scala
new file mode 100644
index 000000000000..10b1509bf369
--- /dev/null
+++ b/library/src/scala/Function11.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 11 parameters.
+ *
+ */
+trait Function11[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9)(x10)(x11) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => T10 => T11 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9, x10: T10, x11: T11) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)).curried
+ }
+ /** Creates a tupled version of this function: instead of 11 arguments,
+ * it accepts a single [[scala.Tuple11]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)) == f(Tuple11(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function12.scala b/library/src/scala/Function12.scala
new file mode 100644
index 000000000000..08d962583108
--- /dev/null
+++ b/library/src/scala/Function12.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 12 parameters.
+ *
+ */
+trait Function12[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9)(x10)(x11)(x12) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => T10 => T11 => T12 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9, x10: T10, x11: T11, x12: T12) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12)).curried
+ }
+ /** Creates a tupled version of this function: instead of 12 arguments,
+ * it accepts a single [[scala.Tuple12]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12)) == f(Tuple12(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function13.scala b/library/src/scala/Function13.scala
new file mode 100644
index 000000000000..971368c1d467
--- /dev/null
+++ b/library/src/scala/Function13.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 13 parameters.
+ *
+ */
+trait Function13[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9)(x10)(x11)(x12)(x13) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => T10 => T11 => T12 => T13 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9, x10: T10, x11: T11, x12: T12, x13: T13) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13)).curried
+ }
+ /** Creates a tupled version of this function: instead of 13 arguments,
+ * it accepts a single [[scala.Tuple13]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13)) == f(Tuple13(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function14.scala b/library/src/scala/Function14.scala
new file mode 100644
index 000000000000..c0b72feef42c
--- /dev/null
+++ b/library/src/scala/Function14.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 14 parameters.
+ *
+ */
+trait Function14[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9)(x10)(x11)(x12)(x13)(x14) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => T10 => T11 => T12 => T13 => T14 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9, x10: T10, x11: T11, x12: T12, x13: T13, x14: T14) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14)).curried
+ }
+ /** Creates a tupled version of this function: instead of 14 arguments,
+ * it accepts a single [[scala.Tuple14]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14)) == f(Tuple14(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function15.scala b/library/src/scala/Function15.scala
new file mode 100644
index 000000000000..67c7e1dc470a
--- /dev/null
+++ b/library/src/scala/Function15.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 15 parameters.
+ *
+ */
+trait Function15[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9)(x10)(x11)(x12)(x13)(x14)(x15) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => T10 => T11 => T12 => T13 => T14 => T15 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9, x10: T10, x11: T11, x12: T12, x13: T13, x14: T14, x15: T15) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15)).curried
+ }
+ /** Creates a tupled version of this function: instead of 15 arguments,
+ * it accepts a single [[scala.Tuple15]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15)) == f(Tuple15(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function16.scala b/library/src/scala/Function16.scala
new file mode 100644
index 000000000000..8ea8dec9b117
--- /dev/null
+++ b/library/src/scala/Function16.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 16 parameters.
+ *
+ */
+trait Function16[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9)(x10)(x11)(x12)(x13)(x14)(x15)(x16) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => T10 => T11 => T12 => T13 => T14 => T15 => T16 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9, x10: T10, x11: T11, x12: T12, x13: T13, x14: T14, x15: T15, x16: T16) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16)).curried
+ }
+ /** Creates a tupled version of this function: instead of 16 arguments,
+ * it accepts a single [[scala.Tuple16]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16)) == f(Tuple16(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function17.scala b/library/src/scala/Function17.scala
new file mode 100644
index 000000000000..bc157115963d
--- /dev/null
+++ b/library/src/scala/Function17.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 17 parameters.
+ *
+ */
+trait Function17[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9)(x10)(x11)(x12)(x13)(x14)(x15)(x16)(x17) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => T10 => T11 => T12 => T13 => T14 => T15 => T16 => T17 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9, x10: T10, x11: T11, x12: T12, x13: T13, x14: T14, x15: T15, x16: T16, x17: T17) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17)).curried
+ }
+ /** Creates a tupled version of this function: instead of 17 arguments,
+ * it accepts a single [[scala.Tuple17]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17)) == f(Tuple17(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function18.scala b/library/src/scala/Function18.scala
new file mode 100644
index 000000000000..d8ff8db313c6
--- /dev/null
+++ b/library/src/scala/Function18.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 18 parameters.
+ *
+ */
+trait Function18[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17, v18: T18): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9)(x10)(x11)(x12)(x13)(x14)(x15)(x16)(x17)(x18) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => T10 => T11 => T12 => T13 => T14 => T15 => T16 => T17 => T18 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9, x10: T10, x11: T11, x12: T12, x13: T13, x14: T14, x15: T15, x16: T16, x17: T17, x18: T18) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18)).curried
+ }
+ /** Creates a tupled version of this function: instead of 18 arguments,
+ * it accepts a single [[scala.Tuple18]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18)) == f(Tuple18(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function19.scala b/library/src/scala/Function19.scala
new file mode 100644
index 000000000000..9d79b5c2d7c1
--- /dev/null
+++ b/library/src/scala/Function19.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 19 parameters.
+ *
+ */
+trait Function19[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17, v18: T18, v19: T19): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9)(x10)(x11)(x12)(x13)(x14)(x15)(x16)(x17)(x18)(x19) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => T10 => T11 => T12 => T13 => T14 => T15 => T16 => T17 => T18 => T19 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9, x10: T10, x11: T11, x12: T12, x13: T13, x14: T14, x15: T15, x16: T16, x17: T17, x18: T18, x19: T19) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19)).curried
+ }
+ /** Creates a tupled version of this function: instead of 19 arguments,
+ * it accepts a single [[scala.Tuple19]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19)) == f(Tuple19(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function2.scala b/library/src/scala/Function2.scala
new file mode 100644
index 000000000000..f30d57e49344
--- /dev/null
+++ b/library/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/src/scala/Function20.scala b/library/src/scala/Function20.scala
new file mode 100644
index 000000000000..1ed5e55a1616
--- /dev/null
+++ b/library/src/scala/Function20.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 20 parameters.
+ *
+ */
+trait Function20[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17, v18: T18, v19: T19, v20: T20): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9)(x10)(x11)(x12)(x13)(x14)(x15)(x16)(x17)(x18)(x19)(x20) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => T10 => T11 => T12 => T13 => T14 => T15 => T16 => T17 => T18 => T19 => T20 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9, x10: T10, x11: T11, x12: T12, x13: T13, x14: T14, x15: T15, x16: T16, x17: T17, x18: T18, x19: T19, x20: T20) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20)).curried
+ }
+ /** Creates a tupled version of this function: instead of 20 arguments,
+ * it accepts a single [[scala.Tuple20]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20)) == f(Tuple20(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function21.scala b/library/src/scala/Function21.scala
new file mode 100644
index 000000000000..4c81489ec323
--- /dev/null
+++ b/library/src/scala/Function21.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 21 parameters.
+ *
+ */
+trait Function21[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, -T21, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17, v18: T18, v19: T19, v20: T20, v21: T21): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9)(x10)(x11)(x12)(x13)(x14)(x15)(x16)(x17)(x18)(x19)(x20)(x21) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => T10 => T11 => T12 => T13 => T14 => T15 => T16 => T17 => T18 => T19 => T20 => T21 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9, x10: T10, x11: T11, x12: T12, x13: T13, x14: T14, x15: T15, x16: T16, x17: T17, x18: T18, x19: T19, x20: T20, x21: T21) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21)).curried
+ }
+ /** Creates a tupled version of this function: instead of 21 arguments,
+ * it accepts a single [[scala.Tuple21]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21)) == f(Tuple21(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function22.scala b/library/src/scala/Function22.scala
new file mode 100644
index 000000000000..c3911f34c08e
--- /dev/null
+++ b/library/src/scala/Function22.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 22 parameters.
+ *
+ */
+trait Function22[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, -T21, -T22, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9, v10: T10, v11: T11, v12: T12, v13: T13, v14: T14, v15: T15, v16: T16, v17: T17, v18: T18, v19: T19, v20: T20, v21: T21, v22: T22): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9)(x10)(x11)(x12)(x13)(x14)(x15)(x16)(x17)(x18)(x19)(x20)(x21)(x22) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => T10 => T11 => T12 => T13 => T14 => T15 => T16 => T17 => T18 => T19 => T20 => T21 => T22 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9, x10: T10, x11: T11, x12: T12, x13: T13, x14: T14, x15: T15, x16: T16, x17: T17, x18: T18, x19: T19, x20: T20, x21: T21, x22: T22) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22)).curried
+ }
+ /** Creates a tupled version of this function: instead of 22 arguments,
+ * it accepts a single [[scala.Tuple22]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22)) == f(Tuple22(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function3.scala b/library/src/scala/Function3.scala
new file mode 100644
index 000000000000..77c1a8f38541
--- /dev/null
+++ b/library/src/scala/Function3.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 3 parameters.
+ *
+ */
+trait Function3[-T1, -T2, -T3, +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, v3: T3): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3) == apply(x1, x2, x3)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => R = {
+ (x1: T1) => (x2: T2) => (x3: T3) => apply(x1, x2, x3)
+ }
+ /** Creates a tupled version of this function: instead of 3 arguments,
+ * it accepts a single [[scala.Tuple3]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3)) == f(Tuple3(x1, x2, x3)) == apply(x1, x2, x3)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3)) => R = {
+ case ((x1, x2, x3)) => apply(x1, x2, x3)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function4.scala b/library/src/scala/Function4.scala
new file mode 100644
index 000000000000..f68164cf2727
--- /dev/null
+++ b/library/src/scala/Function4.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 4 parameters.
+ *
+ */
+trait Function4[-T1, -T2, -T3, -T4, +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, v3: T3, v4: T4): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4) == apply(x1, x2, x3, x4)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => R = {
+ (x1: T1) => (x2: T2) => (x3: T3) => (x4: T4) => apply(x1, x2, x3, x4)
+ }
+ /** Creates a tupled version of this function: instead of 4 arguments,
+ * it accepts a single [[scala.Tuple4]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4)) == f(Tuple4(x1, x2, x3, x4)) == apply(x1, x2, x3, x4)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4)) => R = {
+ case ((x1, x2, x3, x4)) => apply(x1, x2, x3, x4)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function5.scala b/library/src/scala/Function5.scala
new file mode 100644
index 000000000000..b5c347f5ee30
--- /dev/null
+++ b/library/src/scala/Function5.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 5 parameters.
+ *
+ */
+trait Function5[-T1, -T2, -T3, -T4, -T5, +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, v3: T3, v4: T4, v5: T5): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5) == apply(x1, x2, x3, x4, x5)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5) => self.apply(x1, x2, x3, x4, x5)).curried
+ }
+ /** Creates a tupled version of this function: instead of 5 arguments,
+ * it accepts a single [[scala.Tuple5]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5)) == f(Tuple5(x1, x2, x3, x4, x5)) == apply(x1, x2, x3, x4, x5)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5)) => R = {
+ case ((x1, x2, x3, x4, x5)) => apply(x1, x2, x3, x4, x5)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function6.scala b/library/src/scala/Function6.scala
new file mode 100644
index 000000000000..784a51f61e59
--- /dev/null
+++ b/library/src/scala/Function6.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 6 parameters.
+ *
+ */
+trait Function6[-T1, -T2, -T3, -T4, -T5, -T6, +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, v3: T3, v4: T4, v5: T5, v6: T6): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6) == apply(x1, x2, x3, x4, x5, x6)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6) => self.apply(x1, x2, x3, x4, x5, x6)).curried
+ }
+ /** Creates a tupled version of this function: instead of 6 arguments,
+ * it accepts a single [[scala.Tuple6]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6)) == f(Tuple6(x1, x2, x3, x4, x5, x6)) == apply(x1, x2, x3, x4, x5, x6)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6)) => R = {
+ case ((x1, x2, x3, x4, x5, x6)) => apply(x1, x2, x3, x4, x5, x6)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function7.scala b/library/src/scala/Function7.scala
new file mode 100644
index 000000000000..07c90bfd91d3
--- /dev/null
+++ b/library/src/scala/Function7.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 7 parameters.
+ *
+ */
+trait Function7[-T1, -T2, -T3, -T4, -T5, -T6, -T7, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7) == apply(x1, x2, x3, x4, x5, x6, x7)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7) => self.apply(x1, x2, x3, x4, x5, x6, x7)).curried
+ }
+ /** Creates a tupled version of this function: instead of 7 arguments,
+ * it accepts a single [[scala.Tuple7]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7)) == f(Tuple7(x1, x2, x3, x4, x5, x6, x7)) == apply(x1, x2, x3, x4, x5, x6, x7)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7)) => apply(x1, x2, x3, x4, x5, x6, x7)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function8.scala b/library/src/scala/Function8.scala
new file mode 100644
index 000000000000..27ee36b2de90
--- /dev/null
+++ b/library/src/scala/Function8.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 8 parameters.
+ *
+ */
+trait Function8[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8) == apply(x1, x2, x3, x4, x5, x6, x7, x8)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8)).curried
+ }
+ /** Creates a tupled version of this function: instead of 8 arguments,
+ * it accepts a single [[scala.Tuple8]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8)) == f(Tuple8(x1, x2, x3, x4, x5, x6, x7, x8)) == apply(x1, x2, x3, x4, x5, x6, x7, x8)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8)) => apply(x1, x2, x3, x4, x5, x6, x7, x8)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Function9.scala b/library/src/scala/Function9.scala
new file mode 100644
index 000000000000..5bf1a5b16565
--- /dev/null
+++ b/library/src/scala/Function9.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 9 parameters.
+ *
+ */
+trait Function9[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, +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, v3: T3, v4: T4, v5: T5, v6: T6, v7: T7, v8: T8, v9: T9): R
+ /** Creates a curried version of this function.
+ *
+ * @return a function `f` such that `f(x1)(x2)(x3)(x4)(x5)(x6)(x7)(x8)(x9) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9)`
+ */
+ @annotation.unspecialized def curried: T1 => T2 => T3 => T4 => T5 => T6 => T7 => T8 => T9 => R = {
+ (x1: T1) => ((x2: T2, x3: T3, x4: T4, x5: T5, x6: T6, x7: T7, x8: T8, x9: T9) => self.apply(x1, x2, x3, x4, x5, x6, x7, x8, x9)).curried
+ }
+ /** Creates a tupled version of this function: instead of 9 arguments,
+ * it accepts a single [[scala.Tuple9]] argument.
+ *
+ * @return a function `f` such that `f((x1, x2, x3, x4, x5, x6, x7, x8, x9)) == f(Tuple9(x1, x2, x3, x4, x5, x6, x7, x8, x9)) == apply(x1, x2, x3, x4, x5, x6, x7, x8, x9)`
+ */
+
+ @annotation.unspecialized def tupled: ((T1, T2, T3, T4, T5, T6, T7, T8, T9)) => R = {
+ case ((x1, x2, x3, x4, x5, x6, x7, x8, x9)) => apply(x1, x2, x3, x4, x5, x6, x7, x8, x9)
+ }
+ override def toString(): String = ""
+}
diff --git a/library/src/scala/Int.scala b/library/src/scala/Int.scala
new file mode 100644
index 000000000000..003bd502a730
--- /dev/null
+++ b/library/src/scala/Int.scala
@@ -0,0 +1,486 @@
+/*
+ * 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.
+ */
+
+// DO NOT EDIT, CHANGES WILL BE LOST
+// This auto-generated code can be modified in "project/GenerateAnyVals.scala".
+// Afterwards, running "sbt generateSources" regenerates this source file.
+
+package scala
+
+/** `Int`, a 32-bit signed integer (equivalent to Java's `int` primitive type) is a
+ * subtype of [[scala.AnyVal]]. Instances of `Int` are not
+ * represented by an object in the underlying runtime system.
+ *
+ * There is an implicit conversion from [[scala.Int]] => [[scala.runtime.RichInt]]
+ * which provides useful non-primitive operations.
+ */
+final abstract class Int private extends AnyVal {
+ def toByte: Byte
+ def toShort: Short
+ def toChar: Char
+ def toInt: Int
+ def toLong: Long
+ def toFloat: Float
+ def toDouble: Double
+
+ /**
+ * Returns the bitwise negation of this value.
+ * @example {{{
+ * ~5 == -6
+ * // in binary: ~00000101 ==
+ * // 11111010
+ * }}}
+ */
+ def unary_~ : Int
+ /** Returns this value, unmodified. */
+ def unary_+ : Int
+ /** Returns the negation of this value. */
+ def unary_- : Int
+
+ @deprecated("Adding a number and a String is deprecated. Use the string interpolation `s\"$num$str\"`", "2.13.0")
+ def +(x: String): String
+
+ /**
+ * Returns this value bit-shifted left by the specified number of bits,
+ * filling in the new right bits with zeroes.
+ * @example {{{ 6 << 3 == 48 // in binary: 0110 << 3 == 0110000 }}}
+ */
+ def <<(x: Int): Int
+ /**
+ * Returns this value bit-shifted left by the specified number of bits,
+ * filling in the new right bits with zeroes.
+ * @example {{{ 6 << 3 == 48 // in binary: 0110 << 3 == 0110000 }}}
+ */
+ @deprecated("shifting a value by a `Long` argument is deprecated (except when the value is a `Long`).\nCall `toInt` on the argument to maintain the current behavior and avoid the deprecation warning.", "2.12.7")
+ def <<(x: Long): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling the new left bits with zeroes.
+ * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}}
+ * @example {{{
+ * -21 >>> 3 == 536870909
+ * // in binary: 11111111 11111111 11111111 11101011 >>> 3 ==
+ * // 00011111 11111111 11111111 11111101
+ * }}}
+ */
+ def >>>(x: Int): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling the new left bits with zeroes.
+ * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}}
+ * @example {{{
+ * -21 >>> 3 == 536870909
+ * // in binary: 11111111 11111111 11111111 11101011 >>> 3 ==
+ * // 00011111 11111111 11111111 11111101
+ * }}}
+ */
+ @deprecated("shifting a value by a `Long` argument is deprecated (except when the value is a `Long`).\nCall `toInt` on the argument to maintain the current behavior and avoid the deprecation warning.", "2.12.7")
+ def >>>(x: Long): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling in the left bits with the same value as the left-most bit of this.
+ * The effect of this is to retain the sign of the value.
+ * @example {{{
+ * -21 >> 3 == -3
+ * // in binary: 11111111 11111111 11111111 11101011 >> 3 ==
+ * // 11111111 11111111 11111111 11111101
+ * }}}
+ */
+ def >>(x: Int): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling in the left bits with the same value as the left-most bit of this.
+ * The effect of this is to retain the sign of the value.
+ * @example {{{
+ * -21 >> 3 == -3
+ * // in binary: 11111111 11111111 11111111 11101011 >> 3 ==
+ * // 11111111 11111111 11111111 11111101
+ * }}}
+ */
+ @deprecated("shifting a value by a `Long` argument is deprecated (except when the value is a `Long`).\nCall `toInt` on the argument to maintain the current behavior and avoid the deprecation warning.", "2.12.7")
+ def >>(x: Long): Int
+
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Byte): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Short): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Char): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Int): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Long): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Float): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Double): Boolean
+
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Byte): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Short): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Char): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Int): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Long): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Float): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Double): Boolean
+
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Byte): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Short): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Char): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Int): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Long): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Float): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Double): Boolean
+
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Byte): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Short): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Char): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Int): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Long): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Float): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Byte): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Short): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Char): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Int): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Long): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Float): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Byte): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Short): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Char): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Int): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Long): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Float): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Double): Boolean
+
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Byte): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Short): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Char): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Int): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Long): Long
+
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Byte): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Short): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Char): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Int): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Long): Long
+
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Byte): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Short): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Char): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Int): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Long): Long
+
+ /** Returns the sum of this value and `x`. */
+ def +(x: Byte): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Short): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Char): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Int): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Long): Long
+ /** Returns the sum of this value and `x`. */
+ def +(x: Float): Float
+ /** Returns the sum of this value and `x`. */
+ def +(x: Double): Double
+
+ /** Returns the difference of this value and `x`. */
+ def -(x: Byte): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Short): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Char): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Int): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Long): Long
+ /** Returns the difference of this value and `x`. */
+ def -(x: Float): Float
+ /** Returns the difference of this value and `x`. */
+ def -(x: Double): Double
+
+ /** Returns the product of this value and `x`. */
+ def *(x: Byte): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Short): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Char): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Int): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Long): Long
+ /** Returns the product of this value and `x`. */
+ def *(x: Float): Float
+ /** Returns the product of this value and `x`. */
+ def *(x: Double): Double
+
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Byte): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Short): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Char): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Int): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Long): Long
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Float): Float
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Double): Double
+
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Byte): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Short): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Char): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Int): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Long): Long
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Float): Float
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Double): Double
+
+ // Provide a more specific return type for Scaladoc
+ override def getClass(): Class[Int] = ???
+}
+
+object Int extends AnyValCompanion {
+ /** The smallest value representable as an Int. */
+ final val MinValue = java.lang.Integer.MIN_VALUE
+
+ /** The largest value representable as an Int. */
+ final val MaxValue = java.lang.Integer.MAX_VALUE
+
+ /** Transform a value type into a boxed reference type.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.boxToInteger`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the Int to be boxed
+ * @return a java.lang.Integer offering `x` as its underlying value.
+ */
+ def box(x: Int): java.lang.Integer = ???
+
+ /** Transform a boxed type into a value type. Note that this
+ * method is not typesafe: it accepts any Object, but will throw
+ * an exception if the argument is not a java.lang.Integer.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.unboxToInt`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the java.lang.Integer to be unboxed.
+ * @throws ClassCastException if the argument is not a java.lang.Integer
+ * @return the Int resulting from calling intValue() on `x`
+ */
+ def unbox(x: java.lang.Object): Int = ???
+
+ /** The String representation of the scala.Int companion object. */
+ override def toString = "object scala.Int"
+ /** Language mandated coercions from Int to "wider" types. */
+ import scala.language.implicitConversions
+ @deprecated("Implicit conversion from Int to Float is dangerous because it loses precision. Write `.toFloat` instead.", "2.13.1")
+ implicit def int2float(x: Int): Float = x.toFloat
+ implicit def int2long(x: Int): Long = x.toLong
+ implicit def int2double(x: Int): Double = x.toDouble
+}
+
diff --git a/library/src/scala/Long.scala b/library/src/scala/Long.scala
new file mode 100644
index 000000000000..09bd35c64677
--- /dev/null
+++ b/library/src/scala/Long.scala
@@ -0,0 +1,483 @@
+/*
+ * 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.
+ */
+
+// DO NOT EDIT, CHANGES WILL BE LOST
+// This auto-generated code can be modified in "project/GenerateAnyVals.scala".
+// Afterwards, running "sbt generateSources" regenerates this source file.
+
+package scala
+
+/** `Long`, a 64-bit signed integer (equivalent to Java's `long` primitive type) is a
+ * subtype of [[scala.AnyVal]]. Instances of `Long` are not
+ * represented by an object in the underlying runtime system.
+ *
+ * There is an implicit conversion from [[scala.Long]] => [[scala.runtime.RichLong]]
+ * which provides useful non-primitive operations.
+ */
+final abstract class Long private extends AnyVal {
+ def toByte: Byte
+ def toShort: Short
+ def toChar: Char
+ def toInt: Int
+ def toLong: Long
+ def toFloat: Float
+ def toDouble: Double
+
+ /**
+ * Returns the bitwise negation of this value.
+ * @example {{{
+ * ~5 == -6
+ * // in binary: ~00000101 ==
+ * // 11111010
+ * }}}
+ */
+ def unary_~ : Long
+ /** Returns this value, unmodified. */
+ def unary_+ : Long
+ /** Returns the negation of this value. */
+ def unary_- : Long
+
+ @deprecated("Adding a number and a String is deprecated. Use the string interpolation `s\"$num$str\"`", "2.13.0")
+ def +(x: String): String
+
+ /**
+ * Returns this value bit-shifted left by the specified number of bits,
+ * filling in the new right bits with zeroes.
+ * @example {{{ 6 << 3 == 48 // in binary: 0110 << 3 == 0110000 }}}
+ */
+ def <<(x: Int): Long
+ /**
+ * Returns this value bit-shifted left by the specified number of bits,
+ * filling in the new right bits with zeroes.
+ * @example {{{ 6 << 3 == 48 // in binary: 0110 << 3 == 0110000 }}}
+ */
+ def <<(x: Long): Long
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling the new left bits with zeroes.
+ * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}}
+ * @example {{{
+ * -21 >>> 3 == 536870909
+ * // in binary: 11111111 11111111 11111111 11101011 >>> 3 ==
+ * // 00011111 11111111 11111111 11111101
+ * }}}
+ */
+ def >>>(x: Int): Long
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling the new left bits with zeroes.
+ * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}}
+ * @example {{{
+ * -21 >>> 3 == 536870909
+ * // in binary: 11111111 11111111 11111111 11101011 >>> 3 ==
+ * // 00011111 11111111 11111111 11111101
+ * }}}
+ */
+ def >>>(x: Long): Long
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling in the left bits with the same value as the left-most bit of this.
+ * The effect of this is to retain the sign of the value.
+ * @example {{{
+ * -21 >> 3 == -3
+ * // in binary: 11111111 11111111 11111111 11101011 >> 3 ==
+ * // 11111111 11111111 11111111 11111101
+ * }}}
+ */
+ def >>(x: Int): Long
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling in the left bits with the same value as the left-most bit of this.
+ * The effect of this is to retain the sign of the value.
+ * @example {{{
+ * -21 >> 3 == -3
+ * // in binary: 11111111 11111111 11111111 11101011 >> 3 ==
+ * // 11111111 11111111 11111111 11111101
+ * }}}
+ */
+ def >>(x: Long): Long
+
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Byte): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Short): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Char): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Int): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Long): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Float): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Double): Boolean
+
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Byte): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Short): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Char): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Int): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Long): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Float): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Double): Boolean
+
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Byte): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Short): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Char): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Int): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Long): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Float): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Double): Boolean
+
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Byte): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Short): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Char): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Int): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Long): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Float): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Byte): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Short): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Char): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Int): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Long): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Float): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Byte): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Short): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Char): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Int): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Long): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Float): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Double): Boolean
+
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Byte): Long
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Short): Long
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Char): Long
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Int): Long
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Long): Long
+
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Byte): Long
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Short): Long
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Char): Long
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Int): Long
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Long): Long
+
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Byte): Long
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Short): Long
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Char): Long
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Int): Long
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Long): Long
+
+ /** Returns the sum of this value and `x`. */
+ def +(x: Byte): Long
+ /** Returns the sum of this value and `x`. */
+ def +(x: Short): Long
+ /** Returns the sum of this value and `x`. */
+ def +(x: Char): Long
+ /** Returns the sum of this value and `x`. */
+ def +(x: Int): Long
+ /** Returns the sum of this value and `x`. */
+ def +(x: Long): Long
+ /** Returns the sum of this value and `x`. */
+ def +(x: Float): Float
+ /** Returns the sum of this value and `x`. */
+ def +(x: Double): Double
+
+ /** Returns the difference of this value and `x`. */
+ def -(x: Byte): Long
+ /** Returns the difference of this value and `x`. */
+ def -(x: Short): Long
+ /** Returns the difference of this value and `x`. */
+ def -(x: Char): Long
+ /** Returns the difference of this value and `x`. */
+ def -(x: Int): Long
+ /** Returns the difference of this value and `x`. */
+ def -(x: Long): Long
+ /** Returns the difference of this value and `x`. */
+ def -(x: Float): Float
+ /** Returns the difference of this value and `x`. */
+ def -(x: Double): Double
+
+ /** Returns the product of this value and `x`. */
+ def *(x: Byte): Long
+ /** Returns the product of this value and `x`. */
+ def *(x: Short): Long
+ /** Returns the product of this value and `x`. */
+ def *(x: Char): Long
+ /** Returns the product of this value and `x`. */
+ def *(x: Int): Long
+ /** Returns the product of this value and `x`. */
+ def *(x: Long): Long
+ /** Returns the product of this value and `x`. */
+ def *(x: Float): Float
+ /** Returns the product of this value and `x`. */
+ def *(x: Double): Double
+
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Byte): Long
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Short): Long
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Char): Long
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Int): Long
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Long): Long
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Float): Float
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Double): Double
+
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Byte): Long
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Short): Long
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Char): Long
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Int): Long
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Long): Long
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Float): Float
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Double): Double
+
+ // Provide a more specific return type for Scaladoc
+ override def getClass(): Class[Long] = ???
+}
+
+object Long extends AnyValCompanion {
+ /** The smallest value representable as a Long. */
+ final val MinValue = java.lang.Long.MIN_VALUE
+
+ /** The largest value representable as a Long. */
+ final val MaxValue = java.lang.Long.MAX_VALUE
+
+ /** Transform a value type into a boxed reference type.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.boxToLong`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the Long to be boxed
+ * @return a java.lang.Long offering `x` as its underlying value.
+ */
+ def box(x: Long): java.lang.Long = ???
+
+ /** Transform a boxed type into a value type. Note that this
+ * method is not typesafe: it accepts any Object, but will throw
+ * an exception if the argument is not a java.lang.Long.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.unboxToLong`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the java.lang.Long to be unboxed.
+ * @throws ClassCastException if the argument is not a java.lang.Long
+ * @return the Long resulting from calling longValue() on `x`
+ */
+ def unbox(x: java.lang.Object): Long = ???
+
+ /** The String representation of the scala.Long companion object. */
+ override def toString = "object scala.Long"
+ /** Language mandated coercions from Long to "wider" types. */
+ import scala.language.implicitConversions
+ @deprecated("Implicit conversion from Long to Float is dangerous because it loses precision. Write `.toFloat` instead.", "2.13.1")
+ implicit def long2float(x: Long): Float = x.toFloat
+ @deprecated("Implicit conversion from Long to Double is dangerous because it loses precision. Write `.toDouble` instead.", "2.13.1")
+ implicit def long2double(x: Long): Double = x.toDouble
+}
+
diff --git a/library/src/scala/MatchError.scala b/library/src/scala/MatchError.scala
new file mode 100644
index 000000000000..39fa11e817f0
--- /dev/null
+++ b/library/src/scala/MatchError.scala
@@ -0,0 +1,40 @@
+/*
+ * 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
+
+/** This class implements errors which are thrown whenever an
+ * object doesn't match any pattern of a pattern matching
+ * expression.
+ */
+final class MatchError(@transient obj: Any) extends RuntimeException {
+ /** There's no reason we need to call toString eagerly,
+ * so defer it until getMessage is called or object is serialized
+ */
+ private[this] lazy val objString = {
+ def ofClass = "of class " + obj.getClass.getName
+ if (obj == null) "null"
+ else
+ try s"$obj ($ofClass)"
+ catch {
+ case _: Throwable => "an instance " + ofClass
+ }
+ }
+
+ @throws[java.io.ObjectStreamException]
+ private def writeReplace(): Object = {
+ objString
+ this
+ }
+
+ override def getMessage() = objString
+}
diff --git a/library/src/scala/NotImplementedError.scala b/library/src/scala/NotImplementedError.scala
new file mode 100644
index 000000000000..22361b78b85b
--- /dev/null
+++ b/library/src/scala/NotImplementedError.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
+
+/** Throwing this exception can be a temporary replacement for a method
+ * body that remains to be implemented. For instance, the exception is thrown by
+ * `Predef.???`.
+ */
+final class NotImplementedError(msg: String) extends Error(msg) {
+ def this() = this("an implementation is missing")
+}
diff --git a/library/src/scala/Option.scala b/library/src/scala/Option.scala
new file mode 100644
index 000000000000..6605712123c8
--- /dev/null
+++ b/library/src/scala/Option.scala
@@ -0,0 +1,628 @@
+/*
+ * 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
+
+object Option {
+
+ import scala.language.implicitConversions
+
+ /** An implicit conversion that converts an option to an iterable value */
+ implicit def option2Iterable[A](xo: Option[A]): Iterable[A] =
+ if (xo.isEmpty) Iterable.empty else Iterable.single(xo.get)
+
+ /** An Option factory which creates Some(x) if the argument is not null,
+ * and None if it is null.
+ *
+ * @param x the value
+ * @return Some(value) if value != null, None if value == null
+ */
+ def apply[A](x: A): Option[A] = if (x == null) None else Some(x)
+
+ /** An Option factory which returns `None` in a manner consistent with
+ * the collections hierarchy.
+ */
+ def empty[A] : Option[A] = None
+
+ /** When a given condition is true, evaluates the `a` argument and returns
+ * Some(a). When the condition is false, `a` is not evaluated and None is
+ * returned.
+ */
+ def when[A](cond: Boolean)(a: => A): Option[A] =
+ if (cond) Some(a) else None
+
+ /** Unless a given condition is true, this will evaluate the `a` argument and
+ * return Some(a). Otherwise, `a` is not evaluated and None is returned.
+ */
+ @inline def unless[A](cond: Boolean)(a: => A): Option[A] =
+ when(!cond)(a)
+}
+
+/** Represents optional values. Instances of `Option`
+ * are either an instance of $some or the object $none.
+ *
+ * The most idiomatic way to use an $option instance is to treat it
+ * as a collection or monad and use `map`,`flatMap`, `filter`, or
+ * `foreach`:
+ *
+ * {{{
+ * val name: Option[String] = request getParameter "name"
+ * val upper = name map { _.trim } filter { _.length != 0 } map { _.toUpperCase }
+ * println(upper getOrElse "")
+ * }}}
+ *
+ * Note that this is equivalent to {{{
+ * val upper = for {
+ * name <- request getParameter "name"
+ * trimmed <- Some(name.trim)
+ * upper <- Some(trimmed.toUpperCase) if trimmed.length != 0
+ * } yield upper
+ * println(upper getOrElse "")
+ * }}}
+ *
+ * Because of how for comprehension works, if $none is returned
+ * from `request.getParameter`, the entire expression results in
+ * $none
+ *
+ * This allows for sophisticated chaining of $option values without
+ * having to check for the existence of a value.
+ *
+ * These are useful methods that exist for both $some and $none.
+ * - [[isDefined]] — True if not empty
+ * - [[isEmpty]] — True if empty
+ * - [[nonEmpty]] — True if not empty
+ * - [[orElse]] — Evaluate and return alternate optional value if empty
+ * - [[getOrElse]] — Evaluate and return alternate value if empty
+ * - [[get]] — Return value, throw exception if empty
+ * - [[fold]] — Apply function on optional value, return default if empty
+ * - [[map]] — Apply a function on the optional value
+ * - [[flatMap]] — Same as map but function must return an optional value
+ * - [[foreach]] — Apply a procedure on option value
+ * - [[collect]] — Apply partial pattern match on optional value
+ * - [[filter]] — An optional value satisfies predicate
+ * - [[filterNot]] — An optional value doesn't satisfy predicate
+ * - [[exists]] — Apply predicate on optional value, or false if empty
+ * - [[forall]] — Apply predicate on optional value, or true if empty
+ * - [[contains]] — Checks if value equals optional value, or false if empty
+ * - [[zip]] — Combine two optional values to make a paired optional value
+ * - [[unzip]] — Split an optional pair to two optional values
+ * - [[unzip3]] — Split an optional triple to three optional values
+ * - [[toList]] — Unary list of optional value, otherwise the empty list
+ *
+ * A less-idiomatic way to use $option values is via pattern matching: {{{
+ * val nameMaybe = request getParameter "name"
+ * nameMaybe match {
+ * case Some(name) =>
+ * println(name.trim.toUppercase)
+ * case None =>
+ * println("No name value")
+ * }
+ * }}}
+ *
+ * Interacting with code that can occasionally return null can be
+ * safely wrapped in $option to become $none and $some otherwise. {{{
+ * val abc = new java.util.HashMap[Int, String]
+ * abc.put(1, "A")
+ * bMaybe = Option(abc.get(2))
+ * bMaybe match {
+ * case Some(b) =>
+ * println(s"Found \$b")
+ * case None =>
+ * println("Not found")
+ * }
+ * }}}
+ *
+ * @note Many of the methods in here are duplicative with those
+ * in the Iterable hierarchy, but they are duplicated for a reason:
+ * the implicit conversion tends to leave one with an Iterable in
+ * situations where one could have retained an Option.
+ *
+ * @define none `None`
+ * @define some [[scala.Some]]
+ * @define option [[scala.Option]]
+ * @define p `p`
+ * @define f `f`
+ * @define coll option
+ * @define Coll `Option`
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ * @define collectExample
+ * @define undefinedorder
+ */
+@SerialVersionUID(-114498752079829388L) // value computed by serialver for 2.11.2, annotation added in 2.11.4
+sealed abstract class Option[+A] extends IterableOnce[A] with Product with Serializable {
+ self =>
+
+ /** Returns true if the option is $none, false otherwise.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(_) => false
+ * case None => true
+ * }
+ * }}}
+ */
+ final def isEmpty: Boolean = this eq None
+
+ /** Returns true if the option is an instance of $some, false otherwise.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(_) => true
+ * case None => false
+ * }
+ * }}}
+ */
+ final def isDefined: Boolean = !isEmpty
+
+ override final def knownSize: Int = if (isEmpty) 0 else 1
+
+ /** Returns the option's value.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => x
+ * case None => throw new Exception
+ * }
+ * }}}
+ * @note The option must be nonempty.
+ * @throws NoSuchElementException if the option is empty.
+ */
+ def get: A
+
+ /** Returns the option's value if the option is nonempty, otherwise
+ * return the result of evaluating `default`.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => x
+ * case None => default
+ * }
+ * }}}
+ *
+ * @param default the default expression.
+ */
+ @inline final def getOrElse[B >: A](default: => B): B =
+ if (isEmpty) default else this.get
+
+ /** Returns the option's value if it is nonempty,
+ * or `null` if it is empty.
+ *
+ * Although the use of null is discouraged, code written to use
+ * $option must often interface with code that expects and returns nulls.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => x
+ * case None => null
+ * }
+ * }}}
+ * @example {{{
+ * val initialText: Option[String] = getInitialText
+ * val textField = new JComponent(initialText.orNull,20)
+ * }}}
+ */
+ @inline final def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse ev(null)
+
+ /** Returns a $some containing the result of applying $f to this $option's
+ * value if this $option is nonempty.
+ * Otherwise return $none.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => Some(f(x))
+ * case None => None
+ * }
+ * }}}
+ * @note This is similar to `flatMap` except here,
+ * $f does not need to wrap its result in an $option.
+ *
+ * @param f the function to apply
+ * @see flatMap
+ * @see foreach
+ */
+ @inline final def map[B](f: A => B): Option[B] =
+ if (isEmpty) None else Some(f(this.get))
+
+ /** Returns the result of applying $f to this $option's
+ * value if the $option is nonempty. Otherwise, evaluates
+ * expression `ifEmpty`.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => f(x)
+ * case None => ifEmpty
+ * }
+ * }}}
+ * This is also equivalent to:
+ * {{{
+ * option map f getOrElse ifEmpty
+ * }}}
+ * @param ifEmpty the expression to evaluate if empty.
+ * @param f the function to apply if nonempty.
+ */
+ @inline final def fold[B](ifEmpty: => B)(f: A => B): B =
+ if (isEmpty) ifEmpty else f(this.get)
+
+ /** Returns the result of applying $f to this $option's value if
+ * this $option is nonempty.
+ * Returns $none if this $option is empty.
+ * Slightly different from `map` in that $f is expected to
+ * return an $option (which could be $none).
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => f(x)
+ * case None => None
+ * }
+ * }}}
+ * @param f the function to apply
+ * @see map
+ * @see foreach
+ */
+ @inline final def flatMap[B](f: A => Option[B]): Option[B] =
+ if (isEmpty) None else f(this.get)
+
+ /** Returns the nested $option value if it is nonempty. Otherwise,
+ * return $none.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(Some(b)) => Some(b)
+ * case _ => None
+ * }
+ * }}}
+ * @example {{{
+ * Some(Some("something")).flatten
+ * }}}
+ *
+ * @param ev an implicit conversion that asserts that the value is
+ * also an $option.
+ * @see flatMap
+ */
+ def flatten[B](implicit ev: A <:< Option[B]): Option[B] =
+ if (isEmpty) None else ev(this.get)
+
+ /** Returns this $option if it is nonempty '''and''' applying the predicate $p to
+ * this $option's value returns true. Otherwise, return $none.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) if p(x) => Some(x)
+ * case _ => None
+ * }
+ * }}}
+ * @param p the predicate used for testing.
+ */
+ @inline final def filter(p: A => Boolean): Option[A] =
+ if (isEmpty || p(this.get)) this else None
+
+ /** Returns this $option if it is nonempty '''and''' applying the predicate $p to
+ * this $option's value returns false. Otherwise, return $none.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) if !p(x) => Some(x)
+ * case _ => None
+ * }
+ * }}}
+ * @param p the predicate used for testing.
+ */
+ @inline final def filterNot(p: A => Boolean): Option[A] =
+ if (isEmpty || !p(this.get)) this else None
+
+ /** Returns false if the option is $none, true otherwise.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(_) => true
+ * case None => false
+ * }
+ * }}}
+ * @note Implemented here to avoid the implicit conversion to Iterable.
+ */
+ final def nonEmpty: Boolean = isDefined
+
+ /** Necessary to keep $option from being implicitly converted to
+ * [[scala.collection.Iterable]] in `for` comprehensions.
+ */
+ @inline final def withFilter(p: A => Boolean): WithFilter = new WithFilter(p)
+
+ /** We need a whole WithFilter class to honor the "doesn't create a new
+ * collection" contract even though it seems unlikely to matter much in a
+ * collection with max size 1.
+ */
+ class WithFilter(p: A => Boolean) {
+ def map[B](f: A => B): Option[B] = self filter p map f
+ def flatMap[B](f: A => Option[B]): Option[B] = self filter p flatMap f
+ def foreach[U](f: A => U): Unit = self filter p foreach f
+ def withFilter(q: A => Boolean): WithFilter = new WithFilter(x => p(x) && q(x))
+ }
+
+ /** Tests whether the option contains a given value as an element.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => x == elem
+ * case None => false
+ * }
+ * }}}
+ * @example {{{
+ * // Returns true because Some instance contains string "something" which equals "something".
+ * Some("something") contains "something"
+ *
+ * // Returns false because "something" != "anything".
+ * Some("something") contains "anything"
+ *
+ * // Returns false when method called on None.
+ * None contains "anything"
+ * }}}
+ *
+ * @param elem the element to test.
+ * @return `true` if the option has an element that is equal (as
+ * determined by `==`) to `elem`, `false` otherwise.
+ */
+ final def contains[A1 >: A](elem: A1): Boolean =
+ !isEmpty && this.get == elem
+
+ /** Returns true if this option is nonempty '''and''' the predicate
+ * $p returns true when applied to this $option's value.
+ * Otherwise, returns false.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => p(x)
+ * case None => false
+ * }
+ * }}}
+ * @param p the predicate to test
+ */
+ @inline final def exists(p: A => Boolean): Boolean =
+ !isEmpty && p(this.get)
+
+ /** Returns true if this option is empty '''or''' the predicate
+ * $p returns true when applied to this $option's value.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => p(x)
+ * case None => true
+ * }
+ * }}}
+ * @param p the predicate to test
+ */
+ @inline final def forall(p: A => Boolean): Boolean = isEmpty || p(this.get)
+
+ /** Apply the given procedure $f to the option's value,
+ * if it is nonempty. Otherwise, do nothing.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => f(x)
+ * case None => ()
+ * }
+ * }}}
+ * @param f the procedure to apply.
+ * @see map
+ * @see flatMap
+ */
+ @inline final def foreach[U](f: A => U): Unit = {
+ if (!isEmpty) f(this.get)
+ }
+
+ /** Returns a $some containing the result of
+ * applying `pf` to this $option's contained
+ * value, '''if''' this option is
+ * nonempty '''and''' `pf` is defined for that value.
+ * Returns $none otherwise.
+ *
+ * @example {{{
+ * // Returns Some(HTTP) because the partial function covers the case.
+ * Some("http") collect {case "http" => "HTTP"}
+ *
+ * // Returns None because the partial function doesn't cover the case.
+ * Some("ftp") collect {case "http" => "HTTP"}
+ *
+ * // Returns None because the option is empty. There is no value to pass to the partial function.
+ * None collect {case value => value}
+ * }}}
+ *
+ * @param pf the partial function.
+ * @return the result of applying `pf` to this $option's
+ * value (if possible), or $none.
+ */
+ @inline final def collect[B](pf: PartialFunction[A, B]): Option[B] =
+ if (!isEmpty) pf.lift(this.get) else None
+
+ /** Returns this $option if it is nonempty,
+ * otherwise return the result of evaluating `alternative`.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => Some(x)
+ * case None => alternative
+ * }
+ * }}}
+ * @param alternative the alternative expression.
+ */
+ @inline final def orElse[B >: A](alternative: => Option[B]): Option[B] =
+ if (isEmpty) alternative else this
+
+ /** Returns a $some formed from this option and another option
+ * by combining the corresponding elements in a pair.
+ * If either of the two options is empty, $none is returned.
+ *
+ * This is equivalent to:
+ * {{{
+ * (option1, option2) match {
+ * case (Some(x), Some(y)) => Some((x, y))
+ * case _ => None
+ * }
+ * }}}
+ * @example {{{
+ * // Returns Some(("foo", "bar")) because both options are nonempty.
+ * Some("foo") zip Some("bar")
+ *
+ * // Returns None because `that` option is empty.
+ * Some("foo") zip None
+ *
+ * // Returns None because `this` option is empty.
+ * None zip Some("bar")
+ * }}}
+ *
+ * @param that the options which is going to be zipped
+ */
+ final def zip[A1 >: A, B](that: Option[B]): Option[(A1, B)] =
+ if (isEmpty || that.isEmpty) None else Some((this.get, that.get))
+
+ /** Converts an Option of a pair into an Option of the first element and an Option of the second element.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some((x, y)) => (Some(x), Some(y))
+ * case _ => (None, None)
+ * }
+ * }}}
+ * @tparam A1 the type of the first half of the element pair
+ * @tparam A2 the type of the second half of the element pair
+ * @param asPair an implicit conversion which asserts that the element type
+ * of this Option is a pair.
+ * @return a pair of Options, containing, respectively, the first and second half
+ * of the element pair of this Option.
+ */
+ final def unzip[A1, A2](implicit asPair: A <:< (A1, A2)): (Option[A1], Option[A2]) = {
+ if (isEmpty)
+ (None, None)
+ else {
+ val e = asPair(this.get)
+ (Some(e._1), Some(e._2))
+ }
+ }
+
+ /** Converts an Option of a triple into three Options, one containing the element from each position of the triple.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some((x, y, z)) => (Some(x), Some(y), Some(z))
+ * case _ => (None, None, None)
+ * }
+ * }}}
+ * @tparam A1 the type of the first of three elements in the triple
+ * @tparam A2 the type of the second of three elements in the triple
+ * @tparam A3 the type of the third of three elements in the triple
+ * @param asTriple an implicit conversion which asserts that the element type
+ * of this Option is a triple.
+ * @return a triple of Options, containing, respectively, the first, second, and third
+ * elements from the element triple of this Option.
+ */
+ final def unzip3[A1, A2, A3](implicit asTriple: A <:< (A1, A2, A3)): (Option[A1], Option[A2], Option[A3]) = {
+ if (isEmpty)
+ (None, None, None)
+ else {
+ val e = asTriple(this.get)
+ (Some(e._1), Some(e._2), Some(e._3))
+ }
+ }
+
+ /** Returns a singleton iterator returning the $option's value
+ * if it is nonempty, or an empty iterator if the option is empty.
+ */
+ def iterator: Iterator[A] =
+ if (isEmpty) collection.Iterator.empty else collection.Iterator.single(this.get)
+
+ /** Returns a singleton list containing the $option's value
+ * if it is nonempty, or the empty list if the $option is empty.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => List(x)
+ * case None => Nil
+ * }
+ * }}}
+ */
+ def toList: List[A] =
+ if (isEmpty) List() else new ::(this.get, Nil)
+
+ /** Returns a [[scala.util.Left]] containing the given
+ * argument `left` if this $option is empty, or
+ * a [[scala.util.Right]] containing this $option's value if
+ * this is nonempty.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => Right(x)
+ * case None => Left(left)
+ * }
+ * }}}
+ * @param left the expression to evaluate and return if this is empty
+ * @see toLeft
+ */
+ @inline final def toRight[X](left: => X): Either[X, A] =
+ if (isEmpty) Left(left) else Right(this.get)
+
+ /** Returns a [[scala.util.Right]] containing the given
+ * argument `right` if this is empty, or
+ * a [[scala.util.Left]] containing this $option's value
+ * if this $option is nonempty.
+ *
+ * This is equivalent to:
+ * {{{
+ * option match {
+ * case Some(x) => Left(x)
+ * case None => Right(right)
+ * }
+ * }}}
+ * @param right the expression to evaluate and return if this is empty
+ * @see toRight
+ */
+ @inline final def toLeft[X](right: => X): Either[A, X] =
+ if (isEmpty) Right(right) else Left(this.get)
+}
+
+/** Class `Some[A]` represents existing values of type
+ * `A`.
+ */
+@SerialVersionUID(1234815782226070388L) // value computed by serialver for 2.11.2, annotation added in 2.11.4
+final case class Some[+A](value: A) extends Option[A] {
+ def get: A = value
+}
+
+
+/** This case object represents non-existent values.
+ */
+@SerialVersionUID(5066590221178148012L) // value computed by serialver for 2.11.2, annotation added in 2.11.4
+case object None extends Option[Nothing] {
+ def get: Nothing = throw new NoSuchElementException("None.get")
+}
diff --git a/library/src/scala/PartialFunction.scala b/library/src/scala/PartialFunction.scala
new file mode 100644
index 000000000000..992a7972921f
--- /dev/null
+++ b/library/src/scala/PartialFunction.scala
@@ -0,0 +1,403 @@
+/*
+ * 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
+
+import scala.annotation.nowarn
+
+/** A partial function of type `PartialFunction[A, B]` is a unary function
+ * where the domain does not necessarily include all values of type `A`.
+ * The function [[isDefinedAt]] allows to test dynamically if a value is in
+ * the domain of the function.
+ *
+ * Even if `isDefinedAt` returns true for an `a: A`, calling `apply(a)` may
+ * still throw an exception, so the following code is legal:
+ *
+ * {{{
+ * val f: PartialFunction[Int, Any] = { case x => x / 0 } // ArithmeticException: / by zero
+ * }}}
+ *
+ * It is the responsibility of the caller to call `isDefinedAt` before
+ * calling `apply`, because if `isDefinedAt` is false, it is not guaranteed
+ * `apply` will throw an exception to indicate an error condition. If an
+ * exception is not thrown, evaluation may result in an arbitrary value.
+ *
+ * The usual way to respect this contract is to call [[applyOrElse]],
+ * which is expected to be more efficient than calling both `isDefinedAt`
+ * and `apply`.
+ *
+ * The main distinction between `PartialFunction` and [[scala.Function1]] is
+ * that the user of a `PartialFunction` may choose to do something different
+ * with input that is declared to be outside its domain. For example:
+ *
+ * {{{
+ * val sample = 1 to 10
+ * def isEven(n: Int) = n % 2 == 0
+ * val eveningNews: PartialFunction[Int, String] = {
+ * case x if isEven(x) => s"\$x is even"
+ * }
+ *
+ * // The method collect is described as "filter + map"
+ * // because it uses a PartialFunction to select elements
+ * // to which the function is applied.
+ * val evenNumbers = sample.collect(eveningNews)
+ *
+ * val oddlyEnough: PartialFunction[Int, String] = {
+ * case x if !isEven(x) => s"\$x is odd"
+ * }
+ *
+ * // The method orElse allows chaining another PartialFunction
+ * // to handle input outside the declared domain.
+ * val numbers = sample.map(eveningNews orElse oddlyEnough)
+ *
+ * // same as
+ * val numbers = sample.map(n => eveningNews.applyOrElse(n, oddlyEnough))
+ *
+ * val half: PartialFunction[Int, Int] = {
+ * case x if isEven(x) => x / 2
+ * }
+ *
+ * // Calculating the domain of a composition can be expensive.
+ * val oddByHalf = half.andThen(oddlyEnough)
+ *
+ * // Invokes `half.apply` on even elements!
+ * val oddBalls = sample.filter(oddByHalf.isDefinedAt)
+ *
+ * // Better than filter(oddByHalf.isDefinedAt).map(oddByHalf)
+ * val oddBalls = sample.collect(oddByHalf)
+ *
+ * // Providing "default" values.
+ * val oddsAndEnds = sample.map(n => oddByHalf.applyOrElse(n, (i: Int) => s"[\$i]"))
+ * }}}
+ *
+ * @note Optional [[Function]]s, [[PartialFunction]]s and extractor objects
+ * can be converted to each other as shown in the following table.
+ *
+ * | How to convert ... | to a [[PartialFunction]] | to an optional [[Function]] | to an extractor |
+ * | :---: | --- | --- | --- |
+ * | from a [[PartialFunction]] | [[Predef.identity]] | [[lift]] | [[Predef.identity]] |
+ * | from optional [[Function]] | [[Function1.UnliftOps#unlift]] or [[Function.unlift]] | [[Predef.identity]] | [[Function1.UnliftOps#unlift]] |
+ * | from an extractor | `{ case extractor(x) => x }` | `extractor.unapply _` | [[Predef.identity]] |
+ *
+ *
+ * @define applyOrElseOrElse Note that calling [[isDefinedAt]] on the resulting partial function
+ * may apply the first partial function and execute its side effect.
+ * For efficiency, it is recommended to call [[applyOrElse]] instead of [[isDefinedAt]] or [[apply]].
+ */
+trait PartialFunction[-A, +B] extends (A => B) { self =>
+ import PartialFunction._
+
+ /** Tries to extract a `B` from an `A` in a pattern matching expression. */
+ def unapply(a: A): Option[B] = lift(a)
+
+ /** Returns an extractor object with a `unapplySeq` method, which extracts each element of a sequence data.
+ *
+ * @example {{{
+ * val firstChar: String => Option[Char] = _.headOption
+ *
+ * Seq("foo", "bar", "baz") match {
+ * case firstChar.unlift.elementWise(c0, c1, c2) =>
+ * println(s"\$c0, \$c1, \$c2") // Output: f, b, b
+ * }
+ * }}}
+ */
+ def elementWise: ElementWiseExtractor[A, B] = new ElementWiseExtractor[A, B](this)
+
+ /** Checks if a value is contained in the function's domain.
+ *
+ * @param x the value to test
+ * @return `'''true'''`, iff `x` is in the domain of this function, `'''false'''` otherwise.
+ */
+ def isDefinedAt(x: A): Boolean
+
+ /** Composes this partial function with a fallback partial function which
+ * gets applied where this partial function is not defined.
+ *
+ * @param that the fallback function
+ * @tparam A1 the argument type of the fallback function
+ * @tparam B1 the result type of the fallback function
+ * @return a partial function which has as domain the union of the domains
+ * of this partial function and `that`. The resulting partial function
+ * takes `x` to `this(x)` where `this` is defined, and to `that(x)` where it is not.
+ */
+ def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]): PartialFunction[A1, B1] =
+ new OrElse[A1, B1] (this, that)
+ //TODO: why not overload it with orElse(that: F1): F1?
+
+ /** Composes this partial function with a transformation function that
+ * gets applied to results of this partial function.
+ *
+ * If the runtime type of the function is a `PartialFunction` then the
+ * other `andThen` method is used (note its cautions).
+ *
+ * @param k the transformation function
+ * @tparam C the result type of the transformation function.
+ * @return a partial function with the domain of this partial function,
+ * possibly narrowed by the specified function, which maps
+ * arguments `x` to `k(this(x))`.
+ */
+ override def andThen[C](k: B => C): PartialFunction[A, C] = k match {
+ case pf: PartialFunction[B, C] => andThen(pf)
+ case _ => new AndThen[A, B, C](this, k)
+ }
+
+ /**
+ * Composes this partial function with another partial function that
+ * gets applied to results of this partial function.
+ *
+ * $applyOrElseOrElse
+ *
+ * @param k the transformation function
+ * @tparam C the result type of the transformation function.
+ * @return a partial function with the domain of this partial function narrowed by
+ * other partial function, which maps arguments `x` to `k(this(x))`.
+ */
+ def andThen[C](k: PartialFunction[B, C]): PartialFunction[A, C] =
+ new Combined[A, B, C](this, k)
+
+ /**
+ * Composes another partial function `k` with this partial function so that this
+ * partial function gets applied to results of `k`.
+ *
+ * $applyOrElseOrElse
+ *
+ * @param k the transformation function
+ * @tparam R the parameter type of the transformation function.
+ * @return a partial function with the domain of other partial function narrowed by
+ * this partial function, which maps arguments `x` to `this(k(x))`.
+ */
+ def compose[R](k: PartialFunction[R, A]): PartialFunction[R, B] =
+ new Combined[R, A, B](k, this)
+
+ /** Turns this partial function into a plain function returning an `Option` result.
+ * @see Function.unlift
+ * @return a function that takes an argument `x` to `Some(this(x))` if `this`
+ * is defined for `x`, and to `None` otherwise.
+ */
+ def lift: A => Option[B] = new Lifted(this)
+
+ /** Applies this partial function to the given argument when it is contained in the function domain.
+ * Applies fallback function where this partial function is not defined.
+ *
+ * Note that expression `pf.applyOrElse(x, default)` is equivalent to
+ * {{{ if(pf isDefinedAt x) pf(x) else default(x) }}}
+ * except that `applyOrElse` method can be implemented more efficiently.
+ * For all partial function literals the compiler generates an `applyOrElse` implementation which
+ * avoids double evaluation of pattern matchers and guards.
+ * This makes `applyOrElse` the basis for the efficient implementation for many operations and scenarios, such as:
+ *
+ * - combining partial functions into `orElse`/`andThen` chains does not lead to
+ * excessive `apply`/`isDefinedAt` evaluation
+ * - `lift` and `unlift` do not evaluate source functions twice on each invocation
+ * - `runWith` allows efficient imperative-style combining of partial functions
+ * with conditionally applied actions
+ *
+ * For non-literal partial function classes with nontrivial `isDefinedAt` method
+ * it is recommended to override `applyOrElse` with custom implementation that avoids
+ * double `isDefinedAt` evaluation. This may result in better performance
+ * and more predictable behavior w.r.t. side effects.
+ *
+ * @param x the function argument
+ * @param default the fallback function
+ * @return the result of this function or fallback function application.
+ */
+ def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 =
+ if (isDefinedAt(x)) apply(x) else default(x)
+
+ /** Composes this partial function with an action function which
+ * gets applied to results of this partial function.
+ * The action function is invoked only for its side effects; its result is ignored.
+ *
+ * Note that expression `pf.runWith(action)(x)` is equivalent to
+ * {{{ if(pf isDefinedAt x) { action(pf(x)); true } else false }}}
+ * except that `runWith` is implemented via `applyOrElse` and thus potentially more efficient.
+ * Using `runWith` avoids double evaluation of pattern matchers and guards for partial function literals.
+ * @see `applyOrElse`.
+ *
+ * @param action the action function
+ * @return a function which maps arguments `x` to `isDefinedAt(x)`. The resulting function
+ * runs `action(this(x))` where `this` is defined.
+ */
+ def runWith[U](action: B => U): A => Boolean = { x =>
+ val z = applyOrElse(x, checkFallback[B])
+ if (!fallbackOccurred(z)) { action(z); true } else false
+ }
+}
+
+/** A few handy operations which leverage the extra bit of information
+ * available in partial functions. Examples:
+ * {{{
+ * import PartialFunction._
+ *
+ * def strangeConditional(other: Any): Boolean = cond(other) {
+ * case x: String if x == "abc" || x == "def" => true
+ * case x: Int => true
+ * }
+ * def onlyInt(v: Any): Option[Int] = condOpt(v) { case x: Int => x }
+ * }}}
+ */
+object PartialFunction {
+
+ final class ElementWiseExtractor[-A, +B] private[PartialFunction] (private val pf: PartialFunction[A, B]) extends AnyVal {
+ @nowarn("cat=lint-nonlocal-return")
+ def unapplySeq(seq: Seq[A]): Option[Seq[B]] = {
+ Some(seq.map {
+ case pf(b) => b
+ case _ => return None
+ })
+ }
+ }
+
+ /** Composite function produced by `PartialFunction#orElse` method
+ */
+ private class OrElse[-A, +B] (f1: PartialFunction[A, B], f2: PartialFunction[A, B])
+ extends scala.runtime.AbstractPartialFunction[A, B] with Serializable {
+ def isDefinedAt(x: A) = f1.isDefinedAt(x) || f2.isDefinedAt(x)
+
+ override def apply(x: A): B = f1.applyOrElse(x, f2)
+
+ override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = {
+ val z = f1.applyOrElse(x, checkFallback[B])
+ if (!fallbackOccurred(z)) z else f2.applyOrElse(x, default)
+ }
+
+ override def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]): OrElse[A1, B1] =
+ new OrElse[A1, B1] (f1, f2 orElse that)
+
+ override def andThen[C](k: B => C): OrElse[A, C] =
+ new OrElse[A, C] (f1 andThen k, f2 andThen k)
+ }
+
+ /** Composite function produced by `PartialFunction#andThen` method
+ */
+ private class AndThen[-A, B, +C] (pf: PartialFunction[A, B], k: B => C) extends PartialFunction[A, C] with Serializable {
+ def isDefinedAt(x: A) = pf.isDefinedAt(x)
+
+ def apply(x: A): C = k(pf(x))
+
+ override def applyOrElse[A1 <: A, C1 >: C](x: A1, default: A1 => C1): C1 = {
+ val z = pf.applyOrElse(x, checkFallback[B])
+ if (!fallbackOccurred(z)) k(z) else default(x)
+ }
+ }
+
+ /** Composite function produced by `PartialFunction#andThen` method
+ */
+ private class Combined[-A, B, +C] (pf: PartialFunction[A, B], k: PartialFunction[B, C]) extends PartialFunction[A, C] with Serializable {
+ def isDefinedAt(x: A): Boolean = {
+ val b: B = pf.applyOrElse(x, checkFallback[B])
+ if (!fallbackOccurred(b)) k.isDefinedAt(b) else false
+ }
+
+ def apply(x: A): C = k(pf(x))
+
+ override def applyOrElse[A1 <: A, C1 >: C](x: A1, default: A1 => C1): C1 = {
+ val pfv = pf.applyOrElse(x, checkFallback[B])
+ if (!fallbackOccurred(pfv)) k.applyOrElse(pfv, (_: B) => default(x)) else default(x)
+ }
+ }
+
+ /** To implement patterns like {{{ if(pf isDefinedAt x) f1(pf(x)) else f2(x) }}} efficiently
+ * the following trick is used:
+ *
+ * To avoid double evaluation of pattern matchers & guards `applyOrElse` method is used here
+ * instead of `isDefinedAt`/`apply` pair.
+ *
+ * After call to `applyOrElse` we need both the function result it returned and
+ * the fact if the function's argument was contained in its domain. The only degree of freedom we have here
+ * to achieve this goal is tweaking with the continuation argument (`default`) of `applyOrElse` method.
+ * The obvious way is to throw an exception from `default` function and to catch it after
+ * calling `applyOrElse` but I consider this somewhat inefficient.
+ *
+ * I know only one way how you can do this task efficiently: `default` function should return unique marker object
+ * which never may be returned by any other (regular/partial) function. This way after calling `applyOrElse` you need
+ * just one reference comparison to distinguish if `pf isDefined x` or not.
+ *
+ * This correctly interacts with specialization as return type of `applyOrElse`
+ * (which is parameterized upper bound) can never be specialized.
+ *
+ * Here `fallback_fn` is used as both unique marker object and special fallback function that returns it.
+ */
+ private[this] val fallback_fn: Any => Any = _ => fallback_fn
+ private def checkFallback[B] = fallback_fn.asInstanceOf[Any => B]
+ private def fallbackOccurred[B](x: B) = fallback_fn eq x.asInstanceOf[AnyRef]
+
+ private class Lifted[-A, +B] (val pf: PartialFunction[A, B])
+ extends scala.runtime.AbstractFunction1[A, Option[B]] with Serializable {
+
+ def apply(x: A): Option[B] = {
+ val z = pf.applyOrElse(x, checkFallback[B])
+ if (!fallbackOccurred(z)) Some(z) else None
+ }
+ }
+
+ private class Unlifted[A, B] (f: A => Option[B]) extends scala.runtime.AbstractPartialFunction[A, B] with Serializable {
+ def isDefinedAt(x: A): Boolean = f(x).isDefined
+
+ override def applyOrElse[A1 <: A, B1 >: B](x: A1, default: A1 => B1): B1 = {
+ f(x).getOrElse(default(x))
+ }
+
+ override def lift = f
+ }
+
+ private[scala] def unlifted[A, B](f: A => Option[B]): PartialFunction[A, B] = f match {
+ case lf: Lifted[A, B] => lf.pf
+ case ff => new Unlifted(ff)
+ }
+
+ /** Converts an ordinary function to a partial function. Note that calling `isDefinedAt(x)` on
+ * this partial function will return `true` for every `x`.
+ * @param f an ordinary function
+ * @return a partial function which delegates to the ordinary function `f`
+ */
+ def fromFunction[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }
+
+ private[this] val constFalse: Any => Boolean = { _ => false}
+
+ private[this] val empty_pf: PartialFunction[Any, Nothing] = new PartialFunction[Any, Nothing] with Serializable {
+ def isDefinedAt(x: Any) = false
+ def apply(x: Any) = throw new MatchError(x)
+ override def orElse[A1, B1](that: PartialFunction[A1, B1]) = that
+ override def andThen[C](k: Nothing => C): PartialFunction[Any, Nothing] = this
+ override val lift: Any => None.type = (x: Any) => None
+ override def runWith[U](action: Nothing => U) = constFalse
+ }
+
+ /** The partial function with empty domain.
+ * Any attempt to invoke empty partial function leads to throwing [[scala.MatchError]] exception.
+ */
+ def empty[A, B] : PartialFunction[A, B] = empty_pf
+
+ /** A Boolean test that is the result of the given function where defined,
+ * and false otherwise.
+ *
+ * It behaves like a `case _ => false` were added to the partial function.
+ *
+ * @param x the value to test
+ * @param pf the partial function
+ * @return true, iff `x` is in the domain of `pf` and `pf(x) == true`.
+ */
+ def cond[A](x: A)(pf: PartialFunction[A, Boolean]): Boolean = pf.applyOrElse(x, constFalse)
+
+ /** Apply the function to the given value if defined, and return the result
+ * in a `Some`; otherwise, return `None`.
+ *
+ * @param x the value to test
+ * @param pf the PartialFunction[T, U]
+ * @return `Some(pf(x))` if `pf isDefinedAt x`, `None` otherwise.
+ */
+ def condOpt[A, B](x: A)(pf: PartialFunction[A, B]): Option[B] = {
+ val z = pf.applyOrElse(x, checkFallback[B])
+ if (!fallbackOccurred(z)) Some(z) else None
+ }
+}
diff --git a/library/src/scala/Predef.scala b/library/src/scala/Predef.scala
new file mode 100644
index 000000000000..baf6a220c6f9
--- /dev/null
+++ b/library/src/scala/Predef.scala
@@ -0,0 +1,650 @@
+/*
+ * 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
+
+import scala.language.implicitConversions
+
+import scala.collection.{mutable, immutable, ArrayOps, StringOps}, immutable.WrappedString
+import scala.annotation.{elidable, implicitNotFound, experimental}, elidable.ASSERTION
+import scala.annotation.meta.{ companionClass, companionMethod }
+import scala.annotation.internal.RuntimeChecked
+import scala.compiletime.summonFrom
+
+/** The `Predef` object provides definitions that are accessible in all Scala
+ * compilation units without explicit qualification.
+ *
+ * === Commonly Used Types ===
+ * Predef provides type aliases for types which are commonly used, such as
+ * the immutable collection types [[scala.collection.immutable.Map]] and
+ * [[scala.collection.immutable.Set]].
+ *
+ * === Console Output ===
+ * For basic console output, `Predef` provides convenience methods [[print(x:Any* print]] and [[println(x:Any* println]],
+ * which are aliases of the methods in the object [[scala.Console]].
+ *
+ * === Assertions ===
+ * A set of `assert` functions are provided for use as a way to document
+ * and dynamically check invariants in code. Invocations of `assert` can be elided
+ * at compile time by providing the command line option `-Xdisable-assertions`,
+ * which raises `-Xelide-below` above `elidable.ASSERTION`, to the `scalac` command.
+ *
+ * Variants of `assert` intended for use with static analysis tools are also
+ * provided: `assume`, `require` and `ensuring`. `require` and `ensuring` are
+ * intended for use as a means of design-by-contract style specification
+ * of pre- and post-conditions on functions, with the intention that these
+ * specifications could be consumed by a static analysis tool. For instance,
+ *
+ * {{{
+ * def addNaturals(nats: List[Int]): Int = {
+ * require(nats forall (_ >= 0), "List contains negative numbers")
+ * nats.foldLeft(0)(_ + _)
+ * } ensuring(_ >= 0)
+ * }}}
+ *
+ * The declaration of `addNaturals` states that the list of integers passed should
+ * only contain natural numbers (i.e. non-negative), and that the result returned
+ * will also be natural. `require` is distinct from `assert` in that if the
+ * condition fails, then the caller of the function is to blame rather than a
+ * logical error having been made within `addNaturals` itself. `ensuring` is a
+ * form of `assert` that declares the guarantee the function is providing with
+ * regards to its return value.
+ *
+ * === Implicit Conversions ===
+ * A number of commonly applied implicit conversions are also defined here, and
+ * in the parent type [[scala.LowPriorityImplicits]]. Implicit conversions
+ * are provided for the "widening" of numeric values, for instance, converting a
+ * Short value to a Long value as required, and to add additional higher-order
+ * functions to Array values. These are described in more detail in the documentation of [[scala.Array]].
+ *
+ * @groupname utilities Utility Methods
+ * @groupprio utilities 10
+ *
+ * @groupname assertions Assertions
+ * @groupprio assertions 20
+ * @groupdesc assertions These methods support program verification and runtime correctness.
+ *
+ * @groupname console-output Console Output
+ * @groupprio console-output 30
+ * @groupdesc console-output These methods provide output via the console.
+ *
+ * @groupname aliases Aliases
+ * @groupprio aliases 50
+ * @groupdesc aliases These aliases bring selected immutable types into scope without any imports.
+ *
+ * @groupname conversions-string String Conversions
+ * @groupprio conversions-string 60
+ * @groupdesc conversions-string Conversions from String to StringOps or WrappedString.
+ *
+ * @groupname implicit-classes-any Implicit Classes
+ * @groupprio implicit-classes-any 70
+ * @groupdesc implicit-classes-any These implicit classes add useful extension methods to every type.
+ *
+ * @groupname char-sequence-wrappers CharSequence Wrappers
+ * @groupprio char-sequence-wrappers 80
+ * @groupdesc char-sequence-wrappers Wrappers that implements CharSequence and were implicit classes.
+ *
+ * @groupname conversions-java-to-anyval Java to Scala
+ * @groupprio conversions-java-to-anyval 90
+ * @groupdesc conversions-java-to-anyval Implicit conversion from Java primitive wrapper types to Scala equivalents.
+ *
+ * @groupname conversions-anyval-to-java Scala to Java
+ * @groupprio conversions-anyval-to-java 100
+ * @groupdesc conversions-anyval-to-java Implicit conversion from Scala AnyVals to Java primitive wrapper types equivalents.
+ *
+ * @groupname conversions-array-to-wrapped-array Array to ArraySeq
+ * @groupprio conversions-array-to-wrapped-array 110
+ * @groupdesc conversions-array-to-wrapped-array Conversions from Arrays to ArraySeqs.
+ */
+object Predef extends LowPriorityImplicits {
+ /**
+ * Retrieve the runtime representation of a class type. `classOf[T]` is equivalent to
+ * the class literal `T.class` in Java.
+ *
+ * @example {{{
+ * val listClass = classOf[List[_]]
+ * // listClass is java.lang.Class[List[_]] = class scala.collection.immutable.List
+ *
+ * val mapIntString = classOf[Map[Int,String]]
+ * // mapIntString is java.lang.Class[Map[Int,String]] = interface scala.collection.immutable.Map
+ * }}}
+ *
+ * @return The runtime [[Class]] representation of type `T`.
+ * @group utilities
+ */
+ def classOf[T]: Class[T] = null // This is a stub method. The actual implementation is filled in by the compiler.
+
+ /**
+ * Retrieve the single value of a type with a unique inhabitant.
+ *
+ * @example {{{
+ * object Foo
+ * val foo = valueOf[Foo.type]
+ * // foo is Foo.type = Foo
+ *
+ * val bar = valueOf[23]
+ * // bar is 23.type = 23
+ * }}}
+ * @group utilities
+ */
+ @inline def valueOf[T](implicit vt: ValueOf[T]): T = vt.value
+
+ /** The `String` type in Scala has all the methods of the underlying
+ * [[java.lang.String]], of which it is just an alias.
+ *
+ * In addition, extension methods in [[scala.collection.StringOps]]
+ * are added implicitly through the conversion [[augmentString]].
+ * @group aliases
+ */
+ type String = java.lang.String
+ /** @group aliases */
+ type Class[T] = java.lang.Class[T]
+
+ // miscellaneous -----------------------------------------------------
+ scala.`package` // to force scala package object to be seen.
+ scala.collection.immutable.List // to force Nil, :: to be seen.
+
+ /** @group aliases */
+ type Function[-A, +B] = Function1[A, B]
+
+ /** @group aliases */
+ type Map[K, +V] = immutable.Map[K, V]
+ /** @group aliases */
+ type Set[A] = immutable.Set[A]
+ /** @group aliases */
+ val Map = immutable.Map
+ /** @group aliases */
+ val Set = immutable.Set
+
+ /**
+ * Allows destructuring tuples with the same syntax as constructing them.
+ *
+ * @example {{{
+ * val tup = "foobar" -> 3
+ *
+ * val c = tup match {
+ * case str -> i => str.charAt(i)
+ * }
+ * }}}
+ * @group aliases
+ */
+ val -> = Tuple2
+
+ // Manifest types, companions, and incantations for summoning
+ // TODO undeprecated until Scala reflection becomes non-experimental
+ // @deprecated("this notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0")
+ type OptManifest[T] = scala.reflect.OptManifest[T]
+ @implicitNotFound(msg = "No Manifest available for ${T}.")
+ // TODO undeprecated until Scala reflection becomes non-experimental
+ // @deprecated("use `scala.reflect.ClassTag` (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0")
+ type Manifest[T] = scala.reflect.Manifest[T]
+ // TODO undeprecated until Scala reflection becomes non-experimental
+ // @deprecated("use `scala.reflect.ClassTag` (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0")
+ val Manifest = scala.reflect.Manifest
+ // TODO undeprecated until Scala reflection becomes non-experimental
+ // @deprecated("this notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0")
+ val NoManifest = scala.reflect.NoManifest
+
+ // TODO undeprecated until Scala reflection becomes non-experimental
+ // @deprecated("use scala.reflect.classTag[T] and scala.reflect.runtime.universe.typeTag[T] instead", "2.10.0")
+ def manifest[T](implicit m: Manifest[T]): Manifest[T] = m
+ // TODO undeprecated until Scala reflection becomes non-experimental
+ // @deprecated("this notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0")
+ def optManifest[T](implicit m: OptManifest[T]): OptManifest[T] = m
+
+ // Minor variations on identity functions
+
+ /**
+ * A method that returns its input value.
+ * @tparam A type of the input value x.
+ * @param x the value of type `A` to be returned.
+ * @return the value `x`.
+ * @group utilities */
+ @inline def identity[A](x: A): A = x // see `$conforms` for the implicit version
+
+ /** Summon an implicit value of type `T`. Usually, the argument is not passed explicitly.
+ *
+ * @tparam T the type of the value to be summoned
+ * @return the implicit value of type `T`
+ * @group utilities
+ */
+ @inline def implicitly[T](implicit e: T): T = e // TODO: when dependent method types are on by default, give this result type `e.type`, so that inliner has better chance of knowing which method to inline in calls like `implicitly[MatchingStrategy[Option]].zero`
+
+ /** Used to mark code blocks as being expressions, instead of being taken as part of anonymous classes and the like.
+ * This is just a different name for [[identity]].
+ *
+ * @example Separating code blocks from `new`:
+ * {{{
+ * val x = new AnyRef
+ * {
+ * val y = ...
+ * println(y)
+ * }
+ * // the { ... } block is seen as the body of an anonymous class
+ *
+ * val x = new AnyRef
+ *
+ * {
+ * val y = ...
+ * println(y)
+ * }
+ * // an empty line is a brittle "fix"
+ *
+ * val x = new AnyRef
+ * locally {
+ * val y = ...
+ * println(y)
+ * }
+ * // locally guards the block and helps communicate intent
+ * }}}
+ * @group utilities
+ */
+ @inline def locally[T](@deprecatedName("x") x: T): T = x
+
+ // assertions ---------------------------------------------------------
+
+ transparent inline def assert(inline assertion: Boolean, inline message: => Any): Unit =
+ if !assertion then scala.runtime.Scala3RunTime.assertFailed(message)
+
+ transparent inline def assert(inline assertion: Boolean): Unit =
+ if !assertion then scala.runtime.Scala3RunTime.assertFailed()
+
+ /** Tests an expression, throwing an `AssertionError` if false.
+ * This method differs from assert only in the intent expressed:
+ * assert contains a predicate which needs to be proven, while
+ * assume contains an axiom for a static checker. Calls to this method
+ * will not be generated if `-Xelide-below` is greater than `ASSERTION`.
+ *
+ * @see [[scala.annotation.elidable elidable]]
+ * @param assumption the expression to test
+ * @group assertions
+ */
+ @elidable(ASSERTION)
+ def assume(assumption: Boolean): Unit = {
+ if (!assumption)
+ throw new java.lang.AssertionError("assumption failed")
+ }
+
+ /** Tests an expression, throwing an `AssertionError` if false.
+ * This method differs from assert only in the intent expressed:
+ * assert contains a predicate which needs to be proven, while
+ * assume contains an axiom for a static checker. Calls to this method
+ * will not be generated if `-Xelide-below` is greater than `ASSERTION`.
+ *
+ * @see [[scala.annotation.elidable elidable]]
+ * @param assumption the expression to test
+ * @param message a String to include in the failure message
+ * @group assertions
+ */
+ @elidable(ASSERTION) @inline
+ final def assume(assumption: Boolean, message: => Any): Unit = {
+ if (!assumption)
+ throw new java.lang.AssertionError("assumption failed: "+ message)
+ }
+
+ /** Tests an expression, throwing an `IllegalArgumentException` if false.
+ * This method is similar to `assert`, but blames the caller of the method
+ * for violating the condition.
+ *
+ * @param requirement the expression to test
+ * @group assertions
+ */
+ def require(requirement: Boolean): Unit = {
+ if (!requirement)
+ throw new IllegalArgumentException("requirement failed")
+ }
+
+ /** Tests an expression, throwing an `IllegalArgumentException` if false.
+ * This method is similar to `assert`, but blames the caller of the method
+ * for violating the condition.
+ *
+ * @param requirement the expression to test
+ * @param message a String to include in the failure message
+ * @group assertions
+ */
+ @inline final def require(requirement: Boolean, message: => Any): Unit = {
+ if (!requirement)
+ throw new IllegalArgumentException("requirement failed: "+ message)
+ }
+
+ /** `???` can be used for marking methods that remain to be implemented.
+ * @throws NotImplementedError when `???` is invoked.
+ * @group utilities
+ */
+ def ??? : Nothing = throw new NotImplementedError
+
+ // implicit classes -----------------------------------------------------
+
+ /** @group implicit-classes-any */
+ implicit final class ArrowAssoc[A](private val self: A) extends AnyVal {
+ @inline def -> [B](y: B): (A, B) = (self, y)
+ @deprecated("Use `->` instead. If you still wish to display it as one character, consider using a font with programming ligatures such as Fira Code.", "2.13.0")
+ def →[B](y: B): (A, B) = ->(y)
+ }
+
+ /** @group implicit-classes-any */
+ implicit final class Ensuring[A](private val self: A) extends AnyVal {
+ def ensuring(cond: Boolean): A = { assert(cond); self }
+ def ensuring(cond: Boolean, msg: => Any): A = { assert(cond, msg); self }
+ def ensuring(cond: A => Boolean): A = { assert(cond(self)); self }
+ def ensuring(cond: A => Boolean, msg: => Any): A = { assert(cond(self), msg); self }
+ }
+
+ /** @group implicit-classes-any */
+ implicit final class StringFormat[A](private val self: A) extends AnyVal {
+ /** Returns string formatted according to given `format` string.
+ * Format strings are as for `String.format`
+ * (@see java.lang.String.format).
+ */
+ @deprecated("Use `formatString.format(value)` instead of `value.formatted(formatString)`,\nor use the `f\"\"` string interpolator. In Java 15 and later, `formatted` resolves to the new method in String which has reversed parameters.", "2.12.16")
+ @inline def formatted(fmtstr: String): String = fmtstr format self
+ }
+
+ /** Injects String concatenation operator `+` to any classes.
+ * @group implicit-classes-any
+ */
+ @(deprecated @companionMethod)("Implicit injection of + is deprecated. Convert to String to call +", "2.13.0")
+ @(deprecated @companionClass)("Implicit injection of + is deprecated. Convert to String to call +", "2.13.0") // for Scaladoc
+ // scala/bug#8229 retaining the pre 2.11 name for source compatibility in shadowing this implicit
+ implicit final class any2stringadd[A](private val self: A) extends AnyVal {
+ def +(other: String): String = String.valueOf(self) + other
+ }
+
+ /** @group char-sequence-wrappers */
+ final class SeqCharSequence(sequenceOfChars: scala.collection.IndexedSeq[Char]) extends CharSequence {
+ def length: Int = sequenceOfChars.length
+ def charAt(index: Int): Char = sequenceOfChars(index)
+ def subSequence(start: Int, end: Int): CharSequence = new SeqCharSequence(sequenceOfChars.slice(start, end))
+ override def toString = sequenceOfChars.mkString
+ }
+
+ /** @group char-sequence-wrappers */
+ def SeqCharSequence(sequenceOfChars: scala.collection.IndexedSeq[Char]): SeqCharSequence = new SeqCharSequence(sequenceOfChars)
+
+ /** @group char-sequence-wrappers */
+ final class ArrayCharSequence(arrayOfChars: Array[Char]) extends CharSequence {
+ def length: Int = arrayOfChars.length
+ def charAt(index: Int): Char = arrayOfChars(index)
+ def subSequence(start: Int, end: Int): CharSequence = new runtime.ArrayCharSequence(arrayOfChars, start, end)
+ override def toString = arrayOfChars.mkString
+ }
+
+ /** @group char-sequence-wrappers */
+ def ArrayCharSequence(arrayOfChars: Array[Char]): ArrayCharSequence = new ArrayCharSequence(arrayOfChars)
+
+ /** @group conversions-string */
+ @inline implicit def augmentString(x: String): StringOps = new StringOps(x)
+
+ // printing -----------------------------------------------------------
+
+ /** Prints an object to `out` using its `toString` method.
+ *
+ * @param x the object to print; may be null.
+ * @group console-output
+ */
+ def print(x: Any): Unit = Console.print(x)
+
+ /** Prints a newline character on the default output.
+ * @group console-output
+ */
+ def println(): Unit = Console.println()
+
+ /** Prints out an object to the default output, followed by a newline character.
+ *
+ * @param x the object to print.
+ * @group console-output
+ */
+ def println(x: Any): Unit = Console.println(x)
+
+ /** Prints its arguments as a formatted string to the default output,
+ * based on a string pattern (in a fashion similar to printf in C).
+ *
+ * The interpretation of the formatting patterns is described in
+ * [[java.util.Formatter]].
+ *
+ * Consider using the [[scala.StringContext.f f interpolator]] as more type safe and idiomatic.
+ *
+ * @param text the pattern for formatting the arguments.
+ * @param xs the arguments used to instantiate the pattern.
+ * @throws java.lang.IllegalArgumentException if there was a problem with the format string or arguments
+ *
+ * @see [[scala.StringContext.f StringContext.f]]
+ * @group console-output
+ */
+ def printf(text: String, xs: Any*): Unit = Console.print(text.format(xs: _*))
+
+ // views --------------------------------------------------------------
+
+ // these two are morally deprecated but the @deprecated annotation has been moved to the extension method themselves,
+ // in order to provide a more specific deprecation method.
+ implicit def tuple2ToZippedOps[T1, T2](x: (T1, T2)): runtime.Tuple2Zipped.Ops[T1, T2] = new runtime.Tuple2Zipped.Ops(x)
+ implicit def tuple3ToZippedOps[T1, T2, T3](x: (T1, T2, T3)): runtime.Tuple3Zipped.Ops[T1, T2, T3] = new runtime.Tuple3Zipped.Ops(x)
+
+ // Not specialized anymore since 2.13 but we still need separate methods
+ // to avoid https://github.com/scala/bug/issues/10746
+ // TODO: should not need @inline. add heuristic to inline factories for value classes.
+ @inline implicit def genericArrayOps[T](xs: Array[T]): ArrayOps[T] = new ArrayOps(xs)
+ @inline implicit def booleanArrayOps(xs: Array[Boolean]): ArrayOps[Boolean] = new ArrayOps(xs)
+ @inline implicit def byteArrayOps(xs: Array[Byte]): ArrayOps[Byte] = new ArrayOps(xs)
+ @inline implicit def charArrayOps(xs: Array[Char]): ArrayOps[Char] = new ArrayOps(xs)
+ @inline implicit def doubleArrayOps(xs: Array[Double]): ArrayOps[Double] = new ArrayOps(xs)
+ @inline implicit def floatArrayOps(xs: Array[Float]): ArrayOps[Float] = new ArrayOps(xs)
+ @inline implicit def intArrayOps(xs: Array[Int]): ArrayOps[Int] = new ArrayOps(xs)
+ @inline implicit def longArrayOps(xs: Array[Long]): ArrayOps[Long] = new ArrayOps(xs)
+ @inline implicit def refArrayOps[T <: AnyRef](xs: Array[T]): ArrayOps[T] = new ArrayOps(xs)
+ @inline implicit def shortArrayOps(xs: Array[Short]): ArrayOps[Short] = new ArrayOps(xs)
+ @inline implicit def unitArrayOps(xs: Array[Unit]): ArrayOps[Unit] = new ArrayOps(xs)
+
+ // "Autoboxing" and "Autounboxing" ---------------------------------------------------
+
+ /** @group conversions-anyval-to-java */
+ implicit def byte2Byte(x: Byte): java.lang.Byte = x.asInstanceOf[java.lang.Byte]
+ /** @group conversions-anyval-to-java */
+ implicit def short2Short(x: Short): java.lang.Short = x.asInstanceOf[java.lang.Short]
+ /** @group conversions-anyval-to-java */
+ implicit def char2Character(x: Char): java.lang.Character = x.asInstanceOf[java.lang.Character]
+ /** @group conversions-anyval-to-java */
+ implicit def int2Integer(x: Int): java.lang.Integer = x.asInstanceOf[java.lang.Integer]
+ /** @group conversions-anyval-to-java */
+ implicit def long2Long(x: Long): java.lang.Long = x.asInstanceOf[java.lang.Long]
+ /** @group conversions-anyval-to-java */
+ implicit def float2Float(x: Float): java.lang.Float = x.asInstanceOf[java.lang.Float]
+ /** @group conversions-anyval-to-java */
+ implicit def double2Double(x: Double): java.lang.Double = x.asInstanceOf[java.lang.Double]
+ /** @group conversions-anyval-to-java */
+ implicit def boolean2Boolean(x: Boolean): java.lang.Boolean = x.asInstanceOf[java.lang.Boolean]
+
+ /** @group conversions-java-to-anyval */
+ implicit def Byte2byte(x: java.lang.Byte): Byte = x.asInstanceOf[Byte]
+ /** @group conversions-java-to-anyval */
+ implicit def Short2short(x: java.lang.Short): Short = x.asInstanceOf[Short]
+ /** @group conversions-java-to-anyval */
+ implicit def Character2char(x: java.lang.Character): Char = x.asInstanceOf[Char]
+ /** @group conversions-java-to-anyval */
+ implicit def Integer2int(x: java.lang.Integer): Int = x.asInstanceOf[Int]
+ /** @group conversions-java-to-anyval */
+ implicit def Long2long(x: java.lang.Long): Long = x.asInstanceOf[Long]
+ /** @group conversions-java-to-anyval */
+ implicit def Float2float(x: java.lang.Float): Float = x.asInstanceOf[Float]
+ /** @group conversions-java-to-anyval */
+ implicit def Double2double(x: java.lang.Double): Double = x.asInstanceOf[Double]
+ /** @group conversions-java-to-anyval */
+ implicit def Boolean2boolean(x: java.lang.Boolean): Boolean = x.asInstanceOf[Boolean]
+
+ /** An implicit of type `A => A` is available for all `A` because it can always
+ * be implemented using the identity function. This also means that an
+ * implicit of type `A => B` is always available when `A <: B`, because
+ * `(A => A) <: (A => B)`.
+ */
+ // $ to avoid accidental shadowing (e.g. scala/bug#7788)
+ implicit def $conforms[A]: A => A = <:<.refl
+
+ /**
+ * Retrieve the single value of a type with a unique inhabitant.
+ *
+ * @example {{{
+ * object Foo
+ * val foo = valueOf[Foo.type]
+ * // foo is Foo.type = Foo
+ *
+ * val bar = valueOf[23]
+ * // bar is 23.type = 23
+ * }}}
+ * @group utilities
+ */
+ inline def valueOf[T]: T = summonFrom {
+ case ev: ValueOf[T] => ev.value
+ }
+
+ /** Summon a given value of type `T`. Usually, the argument is not passed explicitly.
+ *
+ * @tparam T the type of the value to be summoned
+ * @return the given value typed: the provided type parameter
+ */
+ transparent inline def summon[T](using x: T): x.type = x
+
+ // Extension methods for working with explicit nulls
+
+ /** Strips away the nullability from a value. Note that `.nn` performs a checked cast,
+ * so if invoked on a `null` value it will throw an `NullPointerException`.
+ * @example {{{
+ * val s1: String | Null = "hello"
+ * val s2: String = s1.nn
+ *
+ * val s3: String | Null = null
+ * val s4: String = s3.nn // throw NullPointerException
+ * }}}
+ */
+ extension [T](x: T | Null) inline def nn: x.type & T =
+ if x.asInstanceOf[Any] == null then scala.runtime.Scala3RunTime.nnFail()
+ x.asInstanceOf[x.type & T]
+
+ extension (inline x: AnyRef | Null)
+ /** Enables an expression of type `T|Null`, where `T` is a subtype of `AnyRef`, to be checked for `null`
+ * using `eq` rather than only `==`. This is needed because `Null` no longer has
+ * `eq` or `ne` methods, only `==` and `!=` inherited from `Any`. */
+ inline def eq(inline y: AnyRef | Null): Boolean =
+ x.asInstanceOf[AnyRef] eq y.asInstanceOf[AnyRef]
+ /** Enables an expression of type `T|Null`, where `T` is a subtype of `AnyRef`, to be checked for `null`
+ * using `ne` rather than only `!=`. This is needed because `Null` no longer has
+ * `eq` or `ne` methods, only `==` and `!=` inherited from `Any`. */
+ inline def ne(inline y: AnyRef | Null): Boolean =
+ !(x eq y)
+
+ extension (opt: Option.type)
+ @experimental
+ inline def fromNullable[T](t: T | Null): Option[T] = Option(t).asInstanceOf[Option[T]]
+
+ /** A type supporting Self-based type classes.
+ *
+ * A is TC
+ *
+ * expands to
+ *
+ * TC { type Self = A }
+ *
+ * which is what is needed for a context bound `[A: TC]`.
+ */
+ @experimental
+ infix type is[A <: AnyKind, B <: Any{type Self <: AnyKind}] = B { type Self = A }
+
+ extension [T](x: T)
+ /**Asserts that a term should be exempt from static checks that can be reliably checked at runtime.
+ * @example {{{
+ * val xs: Option[Int] = Option(1)
+ * xs.runtimeChecked match
+ * case Some(x) => x // `Some(_)` can be checked at runtime, so no warning
+ * }}}
+ * @example {{{
+ * val xs: List[Int] = List(1,2,3)
+ * val y :: ys = xs.runtimeChecked // `_ :: _` can be checked at runtime, so no warning
+ * }}}
+ */
+ @experimental
+ inline def runtimeChecked: x.type @RuntimeChecked = x: @RuntimeChecked
+
+}
+
+/** The `LowPriorityImplicits` class provides implicit values that
+* are valid in all Scala compilation units without explicit qualification,
+* but that are partially overridden by higher-priority conversions in object
+* `Predef`.
+*/
+// scala/bug#7335 Parents of Predef are defined in the same compilation unit to avoid
+// cyclic reference errors compiling the standard library *without* a previously
+// compiled copy on the classpath.
+private[scala] abstract class LowPriorityImplicits extends LowPriorityImplicits2 {
+ import mutable.ArraySeq
+
+ /** We prefer the java.lang.* boxed types to these wrappers in
+ * any potential conflicts. Conflicts do exist because the wrappers
+ * need to implement ScalaNumber in order to have a symmetric equals
+ * method, but that implies implementing java.lang.Number as well.
+ *
+ * Note - these are inlined because they are value classes, but
+ * the call to xxxWrapper is not eliminated even though it does nothing.
+ * Even inlined, every call site does a no-op retrieval of Predef's MODULE$
+ * because maybe loading Predef has side effects!
+ */
+ @inline implicit def byteWrapper(x: Byte): runtime.RichByte = new runtime.RichByte(x)
+ @inline implicit def shortWrapper(x: Short): runtime.RichShort = new runtime.RichShort(x)
+ @inline implicit def intWrapper(x: Int): runtime.RichInt = new runtime.RichInt(x)
+ @inline implicit def charWrapper(c: Char): runtime.RichChar = new runtime.RichChar(c)
+ @inline implicit def longWrapper(x: Long): runtime.RichLong = new runtime.RichLong(x)
+ @inline implicit def floatWrapper(x: Float): runtime.RichFloat = new runtime.RichFloat(x)
+ @inline implicit def doubleWrapper(x: Double): runtime.RichDouble = new runtime.RichDouble(x)
+ @inline implicit def booleanWrapper(x: Boolean): runtime.RichBoolean = new runtime.RichBoolean(x)
+
+ /** @group conversions-array-to-wrapped-array */
+ implicit def genericWrapArray[T](xs: Array[T]): ArraySeq[T] =
+ if (xs eq null) null
+ else ArraySeq.make(xs)
+
+ // Since the JVM thinks arrays are covariant, one 0-length Array[AnyRef]
+ // is as good as another for all T <: AnyRef. Instead of creating 100,000,000
+ // unique ones by way of this implicit, let's share one.
+ /** @group conversions-array-to-wrapped-array */
+ implicit def wrapRefArray[T <: AnyRef](xs: Array[T]): ArraySeq.ofRef[T] = {
+ if (xs eq null) null
+ else if (xs.length == 0) ArraySeq.empty[AnyRef].asInstanceOf[ArraySeq.ofRef[T]]
+ else new ArraySeq.ofRef[T](xs)
+ }
+
+ /** @group conversions-array-to-wrapped-array */
+ implicit def wrapIntArray(xs: Array[Int]): ArraySeq.ofInt = if (xs ne null) new ArraySeq.ofInt(xs) else null
+ /** @group conversions-array-to-wrapped-array */
+ implicit def wrapDoubleArray(xs: Array[Double]): ArraySeq.ofDouble = if (xs ne null) new ArraySeq.ofDouble(xs) else null
+ /** @group conversions-array-to-wrapped-array */
+ implicit def wrapLongArray(xs: Array[Long]): ArraySeq.ofLong = if (xs ne null) new ArraySeq.ofLong(xs) else null
+ /** @group conversions-array-to-wrapped-array */
+ implicit def wrapFloatArray(xs: Array[Float]): ArraySeq.ofFloat = if (xs ne null) new ArraySeq.ofFloat(xs) else null
+ /** @group conversions-array-to-wrapped-array */
+ implicit def wrapCharArray(xs: Array[Char]): ArraySeq.ofChar = if (xs ne null) new ArraySeq.ofChar(xs) else null
+ /** @group conversions-array-to-wrapped-array */
+ implicit def wrapByteArray(xs: Array[Byte]): ArraySeq.ofByte = if (xs ne null) new ArraySeq.ofByte(xs) else null
+ /** @group conversions-array-to-wrapped-array */
+ implicit def wrapShortArray(xs: Array[Short]): ArraySeq.ofShort = if (xs ne null) new ArraySeq.ofShort(xs) else null
+ /** @group conversions-array-to-wrapped-array */
+ implicit def wrapBooleanArray(xs: Array[Boolean]): ArraySeq.ofBoolean = if (xs ne null) new ArraySeq.ofBoolean(xs) else null
+ /** @group conversions-array-to-wrapped-array */
+ implicit def wrapUnitArray(xs: Array[Unit]): ArraySeq.ofUnit = if (xs ne null) new ArraySeq.ofUnit(xs) else null
+
+ /** @group conversions-string */
+ implicit def wrapString(s: String): WrappedString = if (s ne null) new WrappedString(s) else null
+}
+
+private[scala] abstract class LowPriorityImplicits2 {
+ @deprecated("implicit conversions from Array to immutable.IndexedSeq are implemented by copying; use `toIndexedSeq` explicitly if you want to copy, or use the more efficient non-copying ArraySeq.unsafeWrapArray", since="2.13.0")
+ implicit def copyArrayToImmutableIndexedSeq[T](xs: Array[T]): IndexedSeq[T] =
+ if (xs eq null) null
+ else new ArrayOps(xs).toIndexedSeq
+}
diff --git a/library/src/scala/Product.scala b/library/src/scala/Product.scala
new file mode 100644
index 000000000000..c0fa80a95ef5
--- /dev/null
+++ b/library/src/scala/Product.scala
@@ -0,0 +1,72 @@
+/*
+ * 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
+
+/** Base trait for all products, which in the standard library include at
+ * least [[scala.Product1]] through [[scala.Product22]] and therefore also
+ * their subclasses [[scala.Tuple1]] through [[scala.Tuple22]]. In addition,
+ * all case classes implement `Product` with synthetically generated methods.
+ */
+trait Product extends Any with Equals {
+ /** The size of this product.
+ * @return for a product `A(x,,1,,, ..., x,,k,,)`, returns `k`
+ */
+ def productArity: Int
+
+ /** The n^th^ element of this product, 0-based. In other words, for a
+ * product `A(x,,1,,, ..., x,,k,,)`, returns `x,,(n+1),,` where `0 <= n < k`.
+ *
+ * @param n the index of the element to return
+ * @throws IndexOutOfBoundsException if the `n` is out of range(n < 0 || n >= productArity).
+ * @return the element `n` elements after the first element
+ */
+ def productElement(n: Int): Any
+
+ /** An iterator over all the elements of this product.
+ * @return in the default implementation, an `Iterator[Any]`
+ */
+ def productIterator: Iterator[Any] = new scala.collection.AbstractIterator[Any] {
+ private[this] var c: Int = 0
+ private[this] val cmax = productArity
+ def hasNext: Boolean = c < cmax
+ def next(): Any = { val result = productElement(c); c += 1; result }
+ }
+
+ /** A string used in the `toString` methods of derived classes.
+ * Implementations may override this method to prepend a string prefix
+ * to the result of `toString` methods.
+ *
+ * @return in the default implementation, the empty string
+ */
+ def productPrefix: String = ""
+
+ /** The name of the n^th^ element of this product, 0-based.
+ * In the default implementation, an empty string.
+ *
+ * @param n the index of the element name to return
+ * @throws IndexOutOfBoundsException if the `n` is out of range(n < 0 || n >= productArity).
+ * @return the name of the specified element
+ */
+ def productElementName(n: Int): String =
+ if (n >= 0 && n < productArity) ""
+ else throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max ${productArity-1})")
+
+ /** An iterator over the names of all the elements of this product.
+ */
+ def productElementNames: Iterator[String] = new scala.collection.AbstractIterator[String] {
+ private[this] var c: Int = 0
+ private[this] val cmax = productArity
+ def hasNext: Boolean = c < cmax
+ def next(): String = { val result = productElementName(c); c += 1; result }
+ }
+}
diff --git a/library/src/scala/Product1.scala b/library/src/scala/Product1.scala
new file mode 100644
index 000000000000..912f4dc8f0d8
--- /dev/null
+++ b/library/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/src/scala/Product10.scala b/library/src/scala/Product10.scala
new file mode 100644
index 000000000000..8ab742e3458f
--- /dev/null
+++ b/library/src/scala/Product10.scala
@@ -0,0 +1,96 @@
+/*
+ * 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 Product10 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10](x: Product10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]): Option[Product10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]] =
+ Some(x)
+}
+
+/** Product10 is a Cartesian product of 10 components.
+ */
+trait Product10[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10] extends Any with Product {
+ /** The arity of this product.
+ * @return 10
+ */
+ override def productArity: Int = 10
+
+
+ /** 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 >= 10).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case 9 => _10
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 9)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+ /** A projection of element 10 of this Product.
+ * @return A projection of element 10.
+ */
+ def _10: T10
+
+
+}
diff --git a/library/src/scala/Product11.scala b/library/src/scala/Product11.scala
new file mode 100644
index 000000000000..c970235fc693
--- /dev/null
+++ b/library/src/scala/Product11.scala
@@ -0,0 +1,101 @@
+/*
+ * 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 Product11 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11](x: Product11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]): Option[Product11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]] =
+ Some(x)
+}
+
+/** Product11 is a Cartesian product of 11 components.
+ */
+trait Product11[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11] extends Any with Product {
+ /** The arity of this product.
+ * @return 11
+ */
+ override def productArity: Int = 11
+
+
+ /** 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 >= 11).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case 9 => _10
+ case 10 => _11
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 10)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+ /** A projection of element 10 of this Product.
+ * @return A projection of element 10.
+ */
+ def _10: T10
+ /** A projection of element 11 of this Product.
+ * @return A projection of element 11.
+ */
+ def _11: T11
+
+
+}
diff --git a/library/src/scala/Product12.scala b/library/src/scala/Product12.scala
new file mode 100644
index 000000000000..2823288e430b
--- /dev/null
+++ b/library/src/scala/Product12.scala
@@ -0,0 +1,106 @@
+/*
+ * 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 Product12 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12](x: Product12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]): Option[Product12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]] =
+ Some(x)
+}
+
+/** Product12 is a Cartesian product of 12 components.
+ */
+trait Product12[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12] extends Any with Product {
+ /** The arity of this product.
+ * @return 12
+ */
+ override def productArity: Int = 12
+
+
+ /** 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 >= 12).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case 9 => _10
+ case 10 => _11
+ case 11 => _12
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 11)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+ /** A projection of element 10 of this Product.
+ * @return A projection of element 10.
+ */
+ def _10: T10
+ /** A projection of element 11 of this Product.
+ * @return A projection of element 11.
+ */
+ def _11: T11
+ /** A projection of element 12 of this Product.
+ * @return A projection of element 12.
+ */
+ def _12: T12
+
+
+}
diff --git a/library/src/scala/Product13.scala b/library/src/scala/Product13.scala
new file mode 100644
index 000000000000..25e804081407
--- /dev/null
+++ b/library/src/scala/Product13.scala
@@ -0,0 +1,111 @@
+/*
+ * 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 Product13 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13](x: Product13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]): Option[Product13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]] =
+ Some(x)
+}
+
+/** Product13 is a Cartesian product of 13 components.
+ */
+trait Product13[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13] extends Any with Product {
+ /** The arity of this product.
+ * @return 13
+ */
+ override def productArity: Int = 13
+
+
+ /** 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 >= 13).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case 9 => _10
+ case 10 => _11
+ case 11 => _12
+ case 12 => _13
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 12)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+ /** A projection of element 10 of this Product.
+ * @return A projection of element 10.
+ */
+ def _10: T10
+ /** A projection of element 11 of this Product.
+ * @return A projection of element 11.
+ */
+ def _11: T11
+ /** A projection of element 12 of this Product.
+ * @return A projection of element 12.
+ */
+ def _12: T12
+ /** A projection of element 13 of this Product.
+ * @return A projection of element 13.
+ */
+ def _13: T13
+
+
+}
diff --git a/library/src/scala/Product14.scala b/library/src/scala/Product14.scala
new file mode 100644
index 000000000000..76afd49e1856
--- /dev/null
+++ b/library/src/scala/Product14.scala
@@ -0,0 +1,116 @@
+/*
+ * 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 Product14 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14](x: Product14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]): Option[Product14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]] =
+ Some(x)
+}
+
+/** Product14 is a Cartesian product of 14 components.
+ */
+trait Product14[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14] extends Any with Product {
+ /** The arity of this product.
+ * @return 14
+ */
+ override def productArity: Int = 14
+
+
+ /** 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 >= 14).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case 9 => _10
+ case 10 => _11
+ case 11 => _12
+ case 12 => _13
+ case 13 => _14
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 13)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+ /** A projection of element 10 of this Product.
+ * @return A projection of element 10.
+ */
+ def _10: T10
+ /** A projection of element 11 of this Product.
+ * @return A projection of element 11.
+ */
+ def _11: T11
+ /** A projection of element 12 of this Product.
+ * @return A projection of element 12.
+ */
+ def _12: T12
+ /** A projection of element 13 of this Product.
+ * @return A projection of element 13.
+ */
+ def _13: T13
+ /** A projection of element 14 of this Product.
+ * @return A projection of element 14.
+ */
+ def _14: T14
+
+
+}
diff --git a/library/src/scala/Product15.scala b/library/src/scala/Product15.scala
new file mode 100644
index 000000000000..dd6e49a33eba
--- /dev/null
+++ b/library/src/scala/Product15.scala
@@ -0,0 +1,121 @@
+/*
+ * 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 Product15 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15](x: Product15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]): Option[Product15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]] =
+ Some(x)
+}
+
+/** Product15 is a Cartesian product of 15 components.
+ */
+trait Product15[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15] extends Any with Product {
+ /** The arity of this product.
+ * @return 15
+ */
+ override def productArity: Int = 15
+
+
+ /** 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 >= 15).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case 9 => _10
+ case 10 => _11
+ case 11 => _12
+ case 12 => _13
+ case 13 => _14
+ case 14 => _15
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 14)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+ /** A projection of element 10 of this Product.
+ * @return A projection of element 10.
+ */
+ def _10: T10
+ /** A projection of element 11 of this Product.
+ * @return A projection of element 11.
+ */
+ def _11: T11
+ /** A projection of element 12 of this Product.
+ * @return A projection of element 12.
+ */
+ def _12: T12
+ /** A projection of element 13 of this Product.
+ * @return A projection of element 13.
+ */
+ def _13: T13
+ /** A projection of element 14 of this Product.
+ * @return A projection of element 14.
+ */
+ def _14: T14
+ /** A projection of element 15 of this Product.
+ * @return A projection of element 15.
+ */
+ def _15: T15
+
+
+}
diff --git a/library/src/scala/Product16.scala b/library/src/scala/Product16.scala
new file mode 100644
index 000000000000..900ccdcab195
--- /dev/null
+++ b/library/src/scala/Product16.scala
@@ -0,0 +1,126 @@
+/*
+ * 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 Product16 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16](x: Product16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16]): Option[Product16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16]] =
+ Some(x)
+}
+
+/** Product16 is a Cartesian product of 16 components.
+ */
+trait Product16[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16] extends Any with Product {
+ /** The arity of this product.
+ * @return 16
+ */
+ override def productArity: Int = 16
+
+
+ /** 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 >= 16).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case 9 => _10
+ case 10 => _11
+ case 11 => _12
+ case 12 => _13
+ case 13 => _14
+ case 14 => _15
+ case 15 => _16
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 15)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+ /** A projection of element 10 of this Product.
+ * @return A projection of element 10.
+ */
+ def _10: T10
+ /** A projection of element 11 of this Product.
+ * @return A projection of element 11.
+ */
+ def _11: T11
+ /** A projection of element 12 of this Product.
+ * @return A projection of element 12.
+ */
+ def _12: T12
+ /** A projection of element 13 of this Product.
+ * @return A projection of element 13.
+ */
+ def _13: T13
+ /** A projection of element 14 of this Product.
+ * @return A projection of element 14.
+ */
+ def _14: T14
+ /** A projection of element 15 of this Product.
+ * @return A projection of element 15.
+ */
+ def _15: T15
+ /** A projection of element 16 of this Product.
+ * @return A projection of element 16.
+ */
+ def _16: T16
+
+
+}
diff --git a/library/src/scala/Product17.scala b/library/src/scala/Product17.scala
new file mode 100644
index 000000000000..4e6636f2e5d1
--- /dev/null
+++ b/library/src/scala/Product17.scala
@@ -0,0 +1,131 @@
+/*
+ * 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 Product17 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17](x: Product17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17]): Option[Product17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17]] =
+ Some(x)
+}
+
+/** Product17 is a Cartesian product of 17 components.
+ */
+trait Product17[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17] extends Any with Product {
+ /** The arity of this product.
+ * @return 17
+ */
+ override def productArity: Int = 17
+
+
+ /** 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 >= 17).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case 9 => _10
+ case 10 => _11
+ case 11 => _12
+ case 12 => _13
+ case 13 => _14
+ case 14 => _15
+ case 15 => _16
+ case 16 => _17
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 16)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+ /** A projection of element 10 of this Product.
+ * @return A projection of element 10.
+ */
+ def _10: T10
+ /** A projection of element 11 of this Product.
+ * @return A projection of element 11.
+ */
+ def _11: T11
+ /** A projection of element 12 of this Product.
+ * @return A projection of element 12.
+ */
+ def _12: T12
+ /** A projection of element 13 of this Product.
+ * @return A projection of element 13.
+ */
+ def _13: T13
+ /** A projection of element 14 of this Product.
+ * @return A projection of element 14.
+ */
+ def _14: T14
+ /** A projection of element 15 of this Product.
+ * @return A projection of element 15.
+ */
+ def _15: T15
+ /** A projection of element 16 of this Product.
+ * @return A projection of element 16.
+ */
+ def _16: T16
+ /** A projection of element 17 of this Product.
+ * @return A projection of element 17.
+ */
+ def _17: T17
+
+
+}
diff --git a/library/src/scala/Product18.scala b/library/src/scala/Product18.scala
new file mode 100644
index 000000000000..4a68f49f5623
--- /dev/null
+++ b/library/src/scala/Product18.scala
@@ -0,0 +1,136 @@
+/*
+ * 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 Product18 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18](x: Product18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18]): Option[Product18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18]] =
+ Some(x)
+}
+
+/** Product18 is a Cartesian product of 18 components.
+ */
+trait Product18[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18] extends Any with Product {
+ /** The arity of this product.
+ * @return 18
+ */
+ override def productArity: Int = 18
+
+
+ /** 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 >= 18).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case 9 => _10
+ case 10 => _11
+ case 11 => _12
+ case 12 => _13
+ case 13 => _14
+ case 14 => _15
+ case 15 => _16
+ case 16 => _17
+ case 17 => _18
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 17)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+ /** A projection of element 10 of this Product.
+ * @return A projection of element 10.
+ */
+ def _10: T10
+ /** A projection of element 11 of this Product.
+ * @return A projection of element 11.
+ */
+ def _11: T11
+ /** A projection of element 12 of this Product.
+ * @return A projection of element 12.
+ */
+ def _12: T12
+ /** A projection of element 13 of this Product.
+ * @return A projection of element 13.
+ */
+ def _13: T13
+ /** A projection of element 14 of this Product.
+ * @return A projection of element 14.
+ */
+ def _14: T14
+ /** A projection of element 15 of this Product.
+ * @return A projection of element 15.
+ */
+ def _15: T15
+ /** A projection of element 16 of this Product.
+ * @return A projection of element 16.
+ */
+ def _16: T16
+ /** A projection of element 17 of this Product.
+ * @return A projection of element 17.
+ */
+ def _17: T17
+ /** A projection of element 18 of this Product.
+ * @return A projection of element 18.
+ */
+ def _18: T18
+
+
+}
diff --git a/library/src/scala/Product19.scala b/library/src/scala/Product19.scala
new file mode 100644
index 000000000000..fdc4c232742d
--- /dev/null
+++ b/library/src/scala/Product19.scala
@@ -0,0 +1,141 @@
+/*
+ * 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 Product19 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19](x: Product19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19]): Option[Product19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19]] =
+ Some(x)
+}
+
+/** Product19 is a Cartesian product of 19 components.
+ */
+trait Product19[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19] extends Any with Product {
+ /** The arity of this product.
+ * @return 19
+ */
+ override def productArity: Int = 19
+
+
+ /** 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 >= 19).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case 9 => _10
+ case 10 => _11
+ case 11 => _12
+ case 12 => _13
+ case 13 => _14
+ case 14 => _15
+ case 15 => _16
+ case 16 => _17
+ case 17 => _18
+ case 18 => _19
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 18)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+ /** A projection of element 10 of this Product.
+ * @return A projection of element 10.
+ */
+ def _10: T10
+ /** A projection of element 11 of this Product.
+ * @return A projection of element 11.
+ */
+ def _11: T11
+ /** A projection of element 12 of this Product.
+ * @return A projection of element 12.
+ */
+ def _12: T12
+ /** A projection of element 13 of this Product.
+ * @return A projection of element 13.
+ */
+ def _13: T13
+ /** A projection of element 14 of this Product.
+ * @return A projection of element 14.
+ */
+ def _14: T14
+ /** A projection of element 15 of this Product.
+ * @return A projection of element 15.
+ */
+ def _15: T15
+ /** A projection of element 16 of this Product.
+ * @return A projection of element 16.
+ */
+ def _16: T16
+ /** A projection of element 17 of this Product.
+ * @return A projection of element 17.
+ */
+ def _17: T17
+ /** A projection of element 18 of this Product.
+ * @return A projection of element 18.
+ */
+ def _18: T18
+ /** A projection of element 19 of this Product.
+ * @return A projection of element 19.
+ */
+ def _19: T19
+
+
+}
diff --git a/library/src/scala/Product2.scala b/library/src/scala/Product2.scala
new file mode 100644
index 000000000000..2498e9727b7f
--- /dev/null
+++ b/library/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
+
+
+}
diff --git a/library/src/scala/Product20.scala b/library/src/scala/Product20.scala
new file mode 100644
index 000000000000..206dc1e375cc
--- /dev/null
+++ b/library/src/scala/Product20.scala
@@ -0,0 +1,146 @@
+/*
+ * 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 Product20 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20](x: Product20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20]): Option[Product20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20]] =
+ Some(x)
+}
+
+/** Product20 is a Cartesian product of 20 components.
+ */
+trait Product20[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20] extends Any with Product {
+ /** The arity of this product.
+ * @return 20
+ */
+ override def productArity: Int = 20
+
+
+ /** 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 >= 20).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case 9 => _10
+ case 10 => _11
+ case 11 => _12
+ case 12 => _13
+ case 13 => _14
+ case 14 => _15
+ case 15 => _16
+ case 16 => _17
+ case 17 => _18
+ case 18 => _19
+ case 19 => _20
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 19)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+ /** A projection of element 10 of this Product.
+ * @return A projection of element 10.
+ */
+ def _10: T10
+ /** A projection of element 11 of this Product.
+ * @return A projection of element 11.
+ */
+ def _11: T11
+ /** A projection of element 12 of this Product.
+ * @return A projection of element 12.
+ */
+ def _12: T12
+ /** A projection of element 13 of this Product.
+ * @return A projection of element 13.
+ */
+ def _13: T13
+ /** A projection of element 14 of this Product.
+ * @return A projection of element 14.
+ */
+ def _14: T14
+ /** A projection of element 15 of this Product.
+ * @return A projection of element 15.
+ */
+ def _15: T15
+ /** A projection of element 16 of this Product.
+ * @return A projection of element 16.
+ */
+ def _16: T16
+ /** A projection of element 17 of this Product.
+ * @return A projection of element 17.
+ */
+ def _17: T17
+ /** A projection of element 18 of this Product.
+ * @return A projection of element 18.
+ */
+ def _18: T18
+ /** A projection of element 19 of this Product.
+ * @return A projection of element 19.
+ */
+ def _19: T19
+ /** A projection of element 20 of this Product.
+ * @return A projection of element 20.
+ */
+ def _20: T20
+
+
+}
diff --git a/library/src/scala/Product21.scala b/library/src/scala/Product21.scala
new file mode 100644
index 000000000000..0cbb44068fc8
--- /dev/null
+++ b/library/src/scala/Product21.scala
@@ -0,0 +1,151 @@
+/*
+ * 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 Product21 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21](x: Product21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21]): Option[Product21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21]] =
+ Some(x)
+}
+
+/** Product21 is a Cartesian product of 21 components.
+ */
+trait Product21[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20, +T21] extends Any with Product {
+ /** The arity of this product.
+ * @return 21
+ */
+ override def productArity: Int = 21
+
+
+ /** 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 >= 21).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case 9 => _10
+ case 10 => _11
+ case 11 => _12
+ case 12 => _13
+ case 13 => _14
+ case 14 => _15
+ case 15 => _16
+ case 16 => _17
+ case 17 => _18
+ case 18 => _19
+ case 19 => _20
+ case 20 => _21
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 20)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+ /** A projection of element 10 of this Product.
+ * @return A projection of element 10.
+ */
+ def _10: T10
+ /** A projection of element 11 of this Product.
+ * @return A projection of element 11.
+ */
+ def _11: T11
+ /** A projection of element 12 of this Product.
+ * @return A projection of element 12.
+ */
+ def _12: T12
+ /** A projection of element 13 of this Product.
+ * @return A projection of element 13.
+ */
+ def _13: T13
+ /** A projection of element 14 of this Product.
+ * @return A projection of element 14.
+ */
+ def _14: T14
+ /** A projection of element 15 of this Product.
+ * @return A projection of element 15.
+ */
+ def _15: T15
+ /** A projection of element 16 of this Product.
+ * @return A projection of element 16.
+ */
+ def _16: T16
+ /** A projection of element 17 of this Product.
+ * @return A projection of element 17.
+ */
+ def _17: T17
+ /** A projection of element 18 of this Product.
+ * @return A projection of element 18.
+ */
+ def _18: T18
+ /** A projection of element 19 of this Product.
+ * @return A projection of element 19.
+ */
+ def _19: T19
+ /** A projection of element 20 of this Product.
+ * @return A projection of element 20.
+ */
+ def _20: T20
+ /** A projection of element 21 of this Product.
+ * @return A projection of element 21.
+ */
+ def _21: T21
+
+
+}
diff --git a/library/src/scala/Product22.scala b/library/src/scala/Product22.scala
new file mode 100644
index 000000000000..df6963c03843
--- /dev/null
+++ b/library/src/scala/Product22.scala
@@ -0,0 +1,156 @@
+/*
+ * 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 Product22 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22](x: Product22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22]): Option[Product22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22]] =
+ Some(x)
+}
+
+/** Product22 is a Cartesian product of 22 components.
+ */
+trait Product22[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20, +T21, +T22] extends Any with Product {
+ /** The arity of this product.
+ * @return 22
+ */
+ override def productArity: Int = 22
+
+
+ /** 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 >= 22).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case 9 => _10
+ case 10 => _11
+ case 11 => _12
+ case 12 => _13
+ case 13 => _14
+ case 14 => _15
+ case 15 => _16
+ case 16 => _17
+ case 17 => _18
+ case 18 => _19
+ case 19 => _20
+ case 20 => _21
+ case 21 => _22
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 21)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+ /** A projection of element 10 of this Product.
+ * @return A projection of element 10.
+ */
+ def _10: T10
+ /** A projection of element 11 of this Product.
+ * @return A projection of element 11.
+ */
+ def _11: T11
+ /** A projection of element 12 of this Product.
+ * @return A projection of element 12.
+ */
+ def _12: T12
+ /** A projection of element 13 of this Product.
+ * @return A projection of element 13.
+ */
+ def _13: T13
+ /** A projection of element 14 of this Product.
+ * @return A projection of element 14.
+ */
+ def _14: T14
+ /** A projection of element 15 of this Product.
+ * @return A projection of element 15.
+ */
+ def _15: T15
+ /** A projection of element 16 of this Product.
+ * @return A projection of element 16.
+ */
+ def _16: T16
+ /** A projection of element 17 of this Product.
+ * @return A projection of element 17.
+ */
+ def _17: T17
+ /** A projection of element 18 of this Product.
+ * @return A projection of element 18.
+ */
+ def _18: T18
+ /** A projection of element 19 of this Product.
+ * @return A projection of element 19.
+ */
+ def _19: T19
+ /** A projection of element 20 of this Product.
+ * @return A projection of element 20.
+ */
+ def _20: T20
+ /** A projection of element 21 of this Product.
+ * @return A projection of element 21.
+ */
+ def _21: T21
+ /** A projection of element 22 of this Product.
+ * @return A projection of element 22.
+ */
+ def _22: T22
+
+
+}
diff --git a/library/src/scala/Product3.scala b/library/src/scala/Product3.scala
new file mode 100644
index 000000000000..48de4b6e7d20
--- /dev/null
+++ b/library/src/scala/Product3.scala
@@ -0,0 +1,61 @@
+/*
+ * 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 Product3 {
+ def unapply[T1, T2, T3](x: Product3[T1, T2, T3]): Option[Product3[T1, T2, T3]] =
+ Some(x)
+}
+
+/** Product3 is a Cartesian product of 3 components.
+ */
+trait Product3[+T1, +T2, +T3] extends Any with Product {
+ /** The arity of this product.
+ * @return 3
+ */
+ override def productArity: Int = 3
+
+
+ /** 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 >= 3).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 2)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+
+
+}
diff --git a/library/src/scala/Product4.scala b/library/src/scala/Product4.scala
new file mode 100644
index 000000000000..7b34b570f1f0
--- /dev/null
+++ b/library/src/scala/Product4.scala
@@ -0,0 +1,66 @@
+/*
+ * 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 Product4 {
+ def unapply[T1, T2, T3, T4](x: Product4[T1, T2, T3, T4]): Option[Product4[T1, T2, T3, T4]] =
+ Some(x)
+}
+
+/** Product4 is a Cartesian product of 4 components.
+ */
+trait Product4[+T1, +T2, +T3, +T4] extends Any with Product {
+ /** The arity of this product.
+ * @return 4
+ */
+ override def productArity: Int = 4
+
+
+ /** 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 >= 4).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 3)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+
+
+}
diff --git a/library/src/scala/Product5.scala b/library/src/scala/Product5.scala
new file mode 100644
index 000000000000..769e2f0b22d3
--- /dev/null
+++ b/library/src/scala/Product5.scala
@@ -0,0 +1,71 @@
+/*
+ * 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 Product5 {
+ def unapply[T1, T2, T3, T4, T5](x: Product5[T1, T2, T3, T4, T5]): Option[Product5[T1, T2, T3, T4, T5]] =
+ Some(x)
+}
+
+/** Product5 is a Cartesian product of 5 components.
+ */
+trait Product5[+T1, +T2, +T3, +T4, +T5] extends Any with Product {
+ /** The arity of this product.
+ * @return 5
+ */
+ override def productArity: Int = 5
+
+
+ /** 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 >= 5).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 4)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+
+
+}
diff --git a/library/src/scala/Product6.scala b/library/src/scala/Product6.scala
new file mode 100644
index 000000000000..aff1fbb92e46
--- /dev/null
+++ b/library/src/scala/Product6.scala
@@ -0,0 +1,76 @@
+/*
+ * 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 Product6 {
+ def unapply[T1, T2, T3, T4, T5, T6](x: Product6[T1, T2, T3, T4, T5, T6]): Option[Product6[T1, T2, T3, T4, T5, T6]] =
+ Some(x)
+}
+
+/** Product6 is a Cartesian product of 6 components.
+ */
+trait Product6[+T1, +T2, +T3, +T4, +T5, +T6] extends Any with Product {
+ /** The arity of this product.
+ * @return 6
+ */
+ override def productArity: Int = 6
+
+
+ /** 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 >= 6).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 5)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+
+
+}
diff --git a/library/src/scala/Product7.scala b/library/src/scala/Product7.scala
new file mode 100644
index 000000000000..7aef56fc53a6
--- /dev/null
+++ b/library/src/scala/Product7.scala
@@ -0,0 +1,81 @@
+/*
+ * 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 Product7 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7](x: Product7[T1, T2, T3, T4, T5, T6, T7]): Option[Product7[T1, T2, T3, T4, T5, T6, T7]] =
+ Some(x)
+}
+
+/** Product7 is a Cartesian product of 7 components.
+ */
+trait Product7[+T1, +T2, +T3, +T4, +T5, +T6, +T7] extends Any with Product {
+ /** The arity of this product.
+ * @return 7
+ */
+ override def productArity: Int = 7
+
+
+ /** 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 >= 7).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 6)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+
+
+}
diff --git a/library/src/scala/Product8.scala b/library/src/scala/Product8.scala
new file mode 100644
index 000000000000..f8604b887358
--- /dev/null
+++ b/library/src/scala/Product8.scala
@@ -0,0 +1,86 @@
+/*
+ * 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 Product8 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8](x: Product8[T1, T2, T3, T4, T5, T6, T7, T8]): Option[Product8[T1, T2, T3, T4, T5, T6, T7, T8]] =
+ Some(x)
+}
+
+/** Product8 is a Cartesian product of 8 components.
+ */
+trait Product8[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8] extends Any with Product {
+ /** The arity of this product.
+ * @return 8
+ */
+ override def productArity: Int = 8
+
+
+ /** 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 >= 8).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 7)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+
+
+}
diff --git a/library/src/scala/Product9.scala b/library/src/scala/Product9.scala
new file mode 100644
index 000000000000..6731142a015b
--- /dev/null
+++ b/library/src/scala/Product9.scala
@@ -0,0 +1,91 @@
+/*
+ * 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 Product9 {
+ def unapply[T1, T2, T3, T4, T5, T6, T7, T8, T9](x: Product9[T1, T2, T3, T4, T5, T6, T7, T8, T9]): Option[Product9[T1, T2, T3, T4, T5, T6, T7, T8, T9]] =
+ Some(x)
+}
+
+/** Product9 is a Cartesian product of 9 components.
+ */
+trait Product9[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9] extends Any with Product {
+ /** The arity of this product.
+ * @return 9
+ */
+ override def productArity: Int = 9
+
+
+ /** 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 >= 9).
+ */
+
+ @throws(classOf[IndexOutOfBoundsException])
+ override def productElement(n: Int): Any = n match {
+ case 0 => _1
+ case 1 => _2
+ case 2 => _3
+ case 3 => _4
+ case 4 => _5
+ case 5 => _6
+ case 6 => _7
+ case 7 => _8
+ case 8 => _9
+ case _ => throw new IndexOutOfBoundsException(s"$n is out of bounds (min 0, max 8)")
+ }
+
+ /** 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
+ /** A projection of element 3 of this Product.
+ * @return A projection of element 3.
+ */
+ def _3: T3
+ /** A projection of element 4 of this Product.
+ * @return A projection of element 4.
+ */
+ def _4: T4
+ /** A projection of element 5 of this Product.
+ * @return A projection of element 5.
+ */
+ def _5: T5
+ /** A projection of element 6 of this Product.
+ * @return A projection of element 6.
+ */
+ def _6: T6
+ /** A projection of element 7 of this Product.
+ * @return A projection of element 7.
+ */
+ def _7: T7
+ /** A projection of element 8 of this Product.
+ * @return A projection of element 8.
+ */
+ def _8: T8
+ /** A projection of element 9 of this Product.
+ * @return A projection of element 9.
+ */
+ def _9: T9
+
+
+}
diff --git a/library/src/scala/Proxy.scala b/library/src/scala/Proxy.scala
new file mode 100644
index 000000000000..8da03133e3cd
--- /dev/null
+++ b/library/src/scala/Proxy.scala
@@ -0,0 +1,48 @@
+/*
+ * 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
+
+/** This class implements a simple proxy that forwards all calls to
+ * the public, non-final methods defined in class `Any` to another
+ * object self. Those methods are:
+ * {{{
+ * def hashCode(): Int
+ * def equals(other: Any): Boolean
+ * def toString(): String
+ * }}}
+ * '''Note:''' forwarding methods in this way will most likely create
+ * an asymmetric equals method, which is not generally recommended.
+ */
+@deprecated("Explicitly override hashCode, equals and toString instead.", "2.13.0")
+trait Proxy extends Any {
+ def self: Any
+
+ override def hashCode: Int = self.hashCode
+ override def equals(that: Any): Boolean = that match {
+ case null => false
+ case _ =>
+ val x = that.asInstanceOf[AnyRef]
+ (x eq this.asInstanceOf[AnyRef]) || (x eq self.asInstanceOf[AnyRef]) || (x equals self)
+ }
+ override def toString = "" + self
+}
+
+@deprecated("All members of this object are deprecated.", "2.13.0")
+object Proxy {
+ /** A proxy which exposes the type it is proxying for via a type parameter.
+ */
+ @deprecated("Explicitly override hashCode, equals and toString instead.", "2.13.0")
+ trait Typed[T] extends Any with Proxy {
+ def self: T
+ }
+}
diff --git a/library/src/scala/SerialVersionUID.scala b/library/src/scala/SerialVersionUID.scala
new file mode 100644
index 000000000000..0c85b2591247
--- /dev/null
+++ b/library/src/scala/SerialVersionUID.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.
+ */
+
+package scala
+
+/**
+ * Annotation for specifying the `serialVersionUID` field of a (serializable) class.
+ *
+ * On the JVM, a class with this annotation will receive a `private`, `static`,
+ * and `final` field called `serialVersionUID` with the provided `value`,
+ * which the JVM's serialization mechanism uses to determine serialization
+ * compatibility between different versions of a class.
+ *
+ * @see [[java.io.Serializable]]
+ * @see [[Serializable]]
+ */
+@deprecatedInheritance("Scheduled for being final in the future", "2.13.0")
+class SerialVersionUID(value: Long) extends scala.annotation.ConstantAnnotation
diff --git a/library/src/scala/Short.scala b/library/src/scala/Short.scala
new file mode 100644
index 000000000000..4a56d71d0733
--- /dev/null
+++ b/library/src/scala/Short.scala
@@ -0,0 +1,486 @@
+/*
+ * 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.
+ */
+
+// DO NOT EDIT, CHANGES WILL BE LOST
+// This auto-generated code can be modified in "project/GenerateAnyVals.scala".
+// Afterwards, running "sbt generateSources" regenerates this source file.
+
+package scala
+
+/** `Short`, a 16-bit signed integer (equivalent to Java's `short` primitive type) is a
+ * subtype of [[scala.AnyVal]]. Instances of `Short` are not
+ * represented by an object in the underlying runtime system.
+ *
+ * There is an implicit conversion from [[scala.Short]] => [[scala.runtime.RichShort]]
+ * which provides useful non-primitive operations.
+ */
+final abstract class Short private extends AnyVal {
+ def toByte: Byte
+ def toShort: Short
+ def toChar: Char
+ def toInt: Int
+ def toLong: Long
+ def toFloat: Float
+ def toDouble: Double
+
+ /**
+ * Returns the bitwise negation of this value.
+ * @example {{{
+ * ~5 == -6
+ * // in binary: ~00000101 ==
+ * // 11111010
+ * }}}
+ */
+ def unary_~ : Int
+ /** Returns this value, unmodified. */
+ def unary_+ : Int
+ /** Returns the negation of this value. */
+ def unary_- : Int
+
+ @deprecated("Adding a number and a String is deprecated. Use the string interpolation `s\"$num$str\"`", "2.13.0")
+ def +(x: String): String
+
+ /**
+ * Returns this value bit-shifted left by the specified number of bits,
+ * filling in the new right bits with zeroes.
+ * @example {{{ 6 << 3 == 48 // in binary: 0110 << 3 == 0110000 }}}
+ */
+ def <<(x: Int): Int
+ /**
+ * Returns this value bit-shifted left by the specified number of bits,
+ * filling in the new right bits with zeroes.
+ * @example {{{ 6 << 3 == 48 // in binary: 0110 << 3 == 0110000 }}}
+ */
+ @deprecated("shifting a value by a `Long` argument is deprecated (except when the value is a `Long`).\nCall `toInt` on the argument to maintain the current behavior and avoid the deprecation warning.", "2.12.7")
+ def <<(x: Long): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling the new left bits with zeroes.
+ * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}}
+ * @example {{{
+ * -21 >>> 3 == 536870909
+ * // in binary: 11111111 11111111 11111111 11101011 >>> 3 ==
+ * // 00011111 11111111 11111111 11111101
+ * }}}
+ */
+ def >>>(x: Int): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling the new left bits with zeroes.
+ * @example {{{ 21 >>> 3 == 2 // in binary: 010101 >>> 3 == 010 }}}
+ * @example {{{
+ * -21 >>> 3 == 536870909
+ * // in binary: 11111111 11111111 11111111 11101011 >>> 3 ==
+ * // 00011111 11111111 11111111 11111101
+ * }}}
+ */
+ @deprecated("shifting a value by a `Long` argument is deprecated (except when the value is a `Long`).\nCall `toInt` on the argument to maintain the current behavior and avoid the deprecation warning.", "2.12.7")
+ def >>>(x: Long): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling in the left bits with the same value as the left-most bit of this.
+ * The effect of this is to retain the sign of the value.
+ * @example {{{
+ * -21 >> 3 == -3
+ * // in binary: 11111111 11111111 11111111 11101011 >> 3 ==
+ * // 11111111 11111111 11111111 11111101
+ * }}}
+ */
+ def >>(x: Int): Int
+ /**
+ * Returns this value bit-shifted right by the specified number of bits,
+ * filling in the left bits with the same value as the left-most bit of this.
+ * The effect of this is to retain the sign of the value.
+ * @example {{{
+ * -21 >> 3 == -3
+ * // in binary: 11111111 11111111 11111111 11101011 >> 3 ==
+ * // 11111111 11111111 11111111 11111101
+ * }}}
+ */
+ @deprecated("shifting a value by a `Long` argument is deprecated (except when the value is a `Long`).\nCall `toInt` on the argument to maintain the current behavior and avoid the deprecation warning.", "2.12.7")
+ def >>(x: Long): Int
+
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Byte): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Short): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Char): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Int): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Long): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Float): Boolean
+ /** Returns `true` if this value is equal to x, `false` otherwise. */
+ def ==(x: Double): Boolean
+
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Byte): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Short): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Char): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Int): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Long): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Float): Boolean
+ /** Returns `true` if this value is not equal to x, `false` otherwise. */
+ def !=(x: Double): Boolean
+
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Byte): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Short): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Char): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Int): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Long): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Float): Boolean
+ /** Returns `true` if this value is less than x, `false` otherwise. */
+ def <(x: Double): Boolean
+
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Byte): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Short): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Char): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Int): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Long): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Float): Boolean
+ /** Returns `true` if this value is less than or equal to x, `false` otherwise. */
+ def <=(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Byte): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Short): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Char): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Int): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Long): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Float): Boolean
+ /** Returns `true` if this value is greater than x, `false` otherwise. */
+ def >(x: Double): Boolean
+
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Byte): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Short): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Char): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Int): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Long): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Float): Boolean
+ /** Returns `true` if this value is greater than or equal to x, `false` otherwise. */
+ def >=(x: Double): Boolean
+
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Byte): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Short): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Char): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Int): Int
+ /**
+ * Returns the bitwise OR of this value and `x`.
+ * @example {{{
+ * (0xf0 | 0xaa) == 0xfa
+ * // in binary: 11110000
+ * // | 10101010
+ * // --------
+ * // 11111010
+ * }}}
+ */
+ def |(x: Long): Long
+
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Byte): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Short): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Char): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Int): Int
+ /**
+ * Returns the bitwise AND of this value and `x`.
+ * @example {{{
+ * (0xf0 & 0xaa) == 0xa0
+ * // in binary: 11110000
+ * // & 10101010
+ * // --------
+ * // 10100000
+ * }}}
+ */
+ def &(x: Long): Long
+
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Byte): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Short): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Char): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Int): Int
+ /**
+ * Returns the bitwise XOR of this value and `x`.
+ * @example {{{
+ * (0xf0 ^ 0xaa) == 0x5a
+ * // in binary: 11110000
+ * // ^ 10101010
+ * // --------
+ * // 01011010
+ * }}}
+ */
+ def ^(x: Long): Long
+
+ /** Returns the sum of this value and `x`. */
+ def +(x: Byte): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Short): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Char): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Int): Int
+ /** Returns the sum of this value and `x`. */
+ def +(x: Long): Long
+ /** Returns the sum of this value and `x`. */
+ def +(x: Float): Float
+ /** Returns the sum of this value and `x`. */
+ def +(x: Double): Double
+
+ /** Returns the difference of this value and `x`. */
+ def -(x: Byte): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Short): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Char): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Int): Int
+ /** Returns the difference of this value and `x`. */
+ def -(x: Long): Long
+ /** Returns the difference of this value and `x`. */
+ def -(x: Float): Float
+ /** Returns the difference of this value and `x`. */
+ def -(x: Double): Double
+
+ /** Returns the product of this value and `x`. */
+ def *(x: Byte): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Short): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Char): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Int): Int
+ /** Returns the product of this value and `x`. */
+ def *(x: Long): Long
+ /** Returns the product of this value and `x`. */
+ def *(x: Float): Float
+ /** Returns the product of this value and `x`. */
+ def *(x: Double): Double
+
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Byte): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Short): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Char): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Int): Int
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Long): Long
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Float): Float
+ /** Returns the quotient of this value and `x`. */
+ def /(x: Double): Double
+
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Byte): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Short): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Char): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Int): Int
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Long): Long
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Float): Float
+ /** Returns the remainder of the division of this value by `x`. */
+ def %(x: Double): Double
+
+ // Provide a more specific return type for Scaladoc
+ override def getClass(): Class[Short] = ???
+}
+
+object Short extends AnyValCompanion {
+ /** The smallest value representable as a Short. */
+ final val MinValue = java.lang.Short.MIN_VALUE
+
+ /** The largest value representable as a Short. */
+ final val MaxValue = java.lang.Short.MAX_VALUE
+
+ /** Transform a value type into a boxed reference type.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.boxToShort`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the Short to be boxed
+ * @return a java.lang.Short offering `x` as its underlying value.
+ */
+ def box(x: Short): java.lang.Short = ???
+
+ /** Transform a boxed type into a value type. Note that this
+ * method is not typesafe: it accepts any Object, but will throw
+ * an exception if the argument is not a java.lang.Short.
+ *
+ * Runtime implementation determined by `scala.runtime.BoxesRunTime.unboxToShort`. See [[https://github.com/scala/scala src/library/scala/runtime/BoxesRunTime.java]].
+ *
+ * @param x the java.lang.Short to be unboxed.
+ * @throws ClassCastException if the argument is not a java.lang.Short
+ * @return the Short resulting from calling shortValue() on `x`
+ */
+ def unbox(x: java.lang.Object): Short = ???
+
+ /** The String representation of the scala.Short companion object. */
+ override def toString = "object scala.Short"
+ /** Language mandated coercions from Short to "wider" types. */
+ import scala.language.implicitConversions
+ implicit def short2int(x: Short): Int = x.toInt
+ implicit def short2long(x: Short): Long = x.toLong
+ implicit def short2float(x: Short): Float = x.toFloat
+ implicit def short2double(x: Short): Double = x.toDouble
+}
+
diff --git a/library/src/scala/Specializable.scala b/library/src/scala/Specializable.scala
new file mode 100644
index 000000000000..54fb59dba83e
--- /dev/null
+++ b/library/src/scala/Specializable.scala
@@ -0,0 +1,38 @@
+/*
+ * 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
+
+/** A common supertype for companions of specializable types.
+ * Should not be extended in user code.
+ */
+trait Specializable
+
+object Specializable {
+ // No type parameter in @specialized annotation.
+ trait SpecializedGroup
+
+ // Smuggle a list of types by way of a tuple upon which Group is parameterized.
+ class Group[T >: Null](value: T) extends SpecializedGroup
+
+ final val Primitives: Group[(Byte, Short, Int, Long, Char, Float, Double, Boolean, Unit)] = null
+ final val Everything: Group[(Byte, Short, Int, Long, Char, Float, Double, Boolean, Unit, AnyRef)] = null
+ final val Bits32AndUp: Group[(Int, Long, Float, Double)] = null
+ final val Integral: Group[(Byte, Short, Int, Long, Char)] = null
+ final val AllNumeric: Group[(Byte, Short, Int, Long, Char, Float, Double)] = null
+ final val BestOfBreed: Group[(Int, Double, Boolean, Unit, AnyRef)] = null
+ final val Unit: Group[Tuple1[Unit]] = null
+
+ final val Arg: Group[(Int, Long, Float, Double)] = null
+ final val Args: Group[(Int, Long, Double)] = null
+ final val Return: Group[(Int, Long, Float, Double, Boolean, Unit)] = null
+}
diff --git a/library/src/scala/StringContext.scala b/library/src/scala/StringContext.scala
new file mode 100644
index 000000000000..ec5c49a2349e
--- /dev/null
+++ b/library/src/scala/StringContext.scala
@@ -0,0 +1,476 @@
+/*
+ * 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
+
+import java.lang.{ StringBuilder => JLSBuilder }
+import scala.annotation.tailrec
+import scala.collection.mutable.ArrayBuilder
+
+/** This class provides the basic mechanism to do String Interpolation.
+ * String Interpolation allows users
+ * to embed variable references directly in *processed* string literals.
+ * Here's an example:
+ * {{{
+ * val name = "James"
+ * println(s"Hello, \$name") // Hello, James
+ * }}}
+ *
+ * Any processed string literal is rewritten as an instantiation and
+ * method call against this class. For example:
+ * {{{
+ * s"Hello, \$name"
+ * }}}
+ *
+ * is rewritten to be:
+ *
+ * {{{
+ * StringContext("Hello, ", "").s(name)
+ * }}}
+ *
+ * By default, this class provides the `raw`, `s` and `f` methods as
+ * available interpolators.
+ *
+ * To provide your own string interpolator, create an implicit class
+ * which adds a method to `StringContext`. Here's an example:
+ * {{{
+ * implicit class JsonHelper(private val sc: StringContext) extends AnyVal {
+ * def json(args: Any*): JSONObject = ...
+ * }
+ * val x: JSONObject = json"{ a: \$a }"
+ * }}}
+ *
+ * Here the `JsonHelper` extension class implicitly adds the `json` method to
+ * `StringContext` which can be used for `json` string literals.
+ *
+ * @param parts The parts that make up the interpolated string,
+ * without the expressions that get inserted by interpolation.
+ */
+case class StringContext(parts: String*) {
+
+ import StringContext.{checkLengths => scCheckLengths, glob, processEscapes, standardInterpolator => scStandardInterpolator}
+
+ @deprecated("use same-named method on StringContext companion object", "2.13.0")
+ def checkLengths(args: scala.collection.Seq[Any]): Unit = scCheckLengths(args, parts)
+
+ /** The simple string interpolator.
+ *
+ * It inserts its arguments between corresponding parts of the string context.
+ * It also treats standard escape sequences as defined in the Scala specification.
+ * Here's an example of usage:
+ * {{{
+ * val name = "James"
+ * println(s"Hello, \$name") // Hello, James
+ * }}}
+ * In this example, the expression \$name is replaced with the `toString` of the
+ * variable `name`.
+ * The `s` interpolator can take the `toString` of any arbitrary expression within
+ * a `\${}` block, for example:
+ * {{{
+ * println(s"1 + 1 = \${1 + 1}")
+ * }}}
+ * will print the string `1 + 1 = 2`.
+ *
+ * @param `args` The arguments to be inserted into the resulting string.
+ * @throws IllegalArgumentException
+ * if the number of `parts` in the enclosing `StringContext` does not exceed
+ * the number of arguments `arg` by exactly 1.
+ * @throws StringContext.InvalidEscapeException
+ * if a `parts` string contains a backslash (`\`) character
+ * that does not start a valid escape sequence.
+ * @note The Scala compiler may replace a call to this method with an equivalent, but more efficient,
+ * use of a StringBuilder.
+ */
+ def s(args: Any*): String = macro ??? // fasttracked to scala.tools.reflect.FastStringInterpolator::interpolateS
+ object s {
+ /** The simple string matcher.
+ *
+ * Attempts to match the input string to the given interpolated patterns via
+ * a naive globbing, that is the reverse of the simple interpolator.
+ *
+ * Here is an example usage:
+ *
+ * {{{
+ * val s"Hello, \$name" = "Hello, James"
+ * println(name) // "James"
+ * }}}
+ *
+ * In this example, the string "James" ends up matching the location where the pattern
+ * `\$name` is positioned, and thus ends up bound to that variable.
+ *
+ * Multiple matches are supported:
+ *
+ * {{{
+ * val s"\$greeting, \$name" = "Hello, James"
+ * println(greeting) // "Hello"
+ * println(name) // "James"
+ * }}}
+ *
+ * And the `s` matcher can match an arbitrary pattern within the `\${}` block, for example:
+ *
+ * {{{
+ * val TimeSplitter = "([0-9]+)[.:]([0-9]+)".r
+ * val s"The time is \${TimeSplitter(hours, mins)}" = "The time is 10.50"
+ * println(hours) // 10
+ * println(mins) // 50
+ * }}}
+ *
+ * Here, we use the `TimeSplitter` regex within the `s` matcher, further splitting the
+ * matched string "10.50" into its constituent parts
+ */
+ def unapplySeq(s: String): Option[Seq[String]] = glob(parts.map(processEscapes), s)
+ }
+ /** The raw string interpolator.
+ *
+ * It inserts its arguments between corresponding parts of the string context.
+ * As opposed to the simple string interpolator `s`, this one does not treat
+ * standard escape sequences as defined in the Scala specification.
+ *
+ * For example, the raw processed string `raw"a\nb"` is equal to the scala string `"a\\nb"`.
+ *
+ * ''Note:'' Even when using the raw interpolator, Scala will process Unicode escapes.
+ * Unicode processing in the raw interpolator is deprecated as of scala 2.13.2 and
+ * will be removed in the future
+ * For example:
+ * {{{
+ * scala> raw"\u005cu0023"
+ * res0: String = #
+ * }}}
+ *
+ * @param `args` The arguments to be inserted into the resulting string.
+ * @throws IllegalArgumentException
+ * if the number of `parts` in the enclosing `StringContext` does not exceed
+ * the number of arguments `arg` by exactly 1.
+ * @note The Scala compiler may replace a call to this method with an equivalent, but more efficient,
+ * use of a StringBuilder.
+ */
+ def raw(args: Any*): String = macro ??? // fasttracked to scala.tools.reflect.FastStringInterpolator::interpolateRaw
+
+ @deprecated("Use the static method StringContext.standardInterpolator instead of the instance method", "2.13.0")
+ def standardInterpolator(process: String => String, args: Seq[Any]): String = scStandardInterpolator(process, args, parts)
+
+ /** The formatted string interpolator.
+ *
+ * It inserts its arguments between corresponding parts of the string context.
+ * It also treats standard escape sequences as defined in the Scala specification.
+ * Finally, if an interpolated expression is followed by a `parts` string
+ * that starts with a formatting specifier, the expression is formatted according to that
+ * specifier. All specifiers allowed in Java format strings are handled, and in the same
+ * way they are treated in Java.
+ *
+ * For example:
+ * {{{
+ * val height = 1.9d
+ * val name = "James"
+ * println(f"\$name%s is \$height%2.2f meters tall") // James is 1.90 meters tall
+ * }}}
+ *
+ * @param `args` The arguments to be inserted into the resulting string.
+ * @throws IllegalArgumentException
+ * if the number of `parts` in the enclosing `StringContext` does not exceed
+ * the number of arguments `arg` by exactly 1.
+ * @throws StringContext.InvalidEscapeException
+ * if a `parts` string contains a backslash (`\`) character
+ * that does not start a valid escape sequence.
+ *
+ * Note: The `f` method works by assembling a format string from all the `parts` strings and using
+ * `java.lang.String.format` to format all arguments with that format string. The format string is
+ * obtained by concatenating all `parts` strings, and performing two transformations:
+ *
+ * 1. Let a _formatting position_ be a start of any `parts` string except the first one.
+ * If a formatting position does not refer to a `%` character (which is assumed to
+ * start a format specifier), then the string format specifier `%s` is inserted.
+ *
+ * 2. Any `%` characters not in formatting positions must begin one of the conversions
+ * `%%` (the literal percent) or `%n` (the platform-specific line separator).
+ */
+ def f[A >: Any](args: A*): String = macro ??? // fasttracked to scala.tools.reflect.FormatInterpolator::interpolateF
+}
+
+object StringContext {
+ /**
+ * Linear time glob-matching implementation.
+ * Adapted from https://research.swtch.com/glob
+ *
+ * @param patternChunks The non-wildcard portions of the input pattern,
+ * separated by wildcards
+ * @param input The input you wish to match against
+ * @return None if there is no match, Some containing the sequence of matched
+ * wildcard strings if there is a match
+ */
+ def glob(patternChunks: Seq[String], input: String): Option[Seq[String]] = {
+ var patternIndex = 0
+ var inputIndex = 0
+ var nextPatternIndex = 0
+ var nextInputIndex = 0
+
+ val numWildcards = patternChunks.length - 1
+ val matchStarts = Array.fill(numWildcards)(-1)
+ val matchEnds = Array.fill(numWildcards)(-1)
+
+ val nameLength = input.length
+ // The final pattern is as long as all the chunks, separated by 1-character
+ // glob-wildcard placeholders
+ val patternLength = patternChunks.iterator.map(_.length).sum + numWildcards
+
+ // Convert the input pattern chunks into a single sequence of shorts; each
+ // non-negative short represents a character, while -1 represents a glob wildcard
+ val pattern = {
+ val b = new ArrayBuilder.ofShort ; b.sizeHint(patternLength)
+ patternChunks.head.foreach(c => b.addOne(c.toShort))
+ patternChunks.tail.foreach { s => b.addOne(-1) ; s.foreach(c => b.addOne(c.toShort)) }
+ b.result()
+ }
+
+ // Lookup table for each character in the pattern to check whether or not
+ // it refers to a glob wildcard; a non-negative integer indicates which
+ // glob wildcard it represents, while -1 means it doesn't represent any
+ val matchIndices = {
+ val arr = Array.fill(patternLength + 1)(-1)
+ patternChunks.init.zipWithIndex.foldLeft(0) { case (ttl, (chunk, i)) =>
+ val sum = ttl + chunk.length
+ arr(sum) = i
+ sum + 1
+ }
+ arr
+ }
+
+ while (patternIndex < patternLength || inputIndex < nameLength) {
+ matchIndices(patternIndex) match {
+ case -1 => // do nothing
+ case n =>
+ matchStarts(n) = matchStarts(n) match {
+ case -1 => inputIndex
+ case s => math.min(s, inputIndex)
+ }
+ matchEnds(n) = matchEnds(n) match {
+ case -1 => inputIndex
+ case s => math.max(s, inputIndex)
+ }
+ }
+
+ val continue = if (patternIndex < patternLength) {
+ val c = pattern(patternIndex)
+ c match {
+ case -1 => // zero-or-more-character wildcard
+ // Try to match at nx. If that doesn't work out, restart at nx+1 next.
+ nextPatternIndex = patternIndex
+ nextInputIndex = inputIndex + 1
+ patternIndex += 1
+ true
+ case _ => // ordinary character
+ if (inputIndex < nameLength && input(inputIndex) == c) {
+ patternIndex += 1
+ inputIndex += 1
+ true
+ } else {
+ false
+ }
+ }
+ } else false
+
+ // Mismatch. Maybe restart.
+ if (!continue) {
+ if (0 < nextInputIndex && nextInputIndex <= nameLength) {
+ patternIndex = nextPatternIndex
+ inputIndex = nextInputIndex
+ } else {
+ return None
+ }
+ }
+ }
+
+ // Matched all of pattern to all of name. Success.
+ Some(collection.immutable.ArraySeq.unsafeWrapArray(
+ Array.tabulate(patternChunks.length - 1)(n => input.slice(matchStarts(n), matchEnds(n)))
+ ))
+ }
+
+ /** An exception that is thrown if a string contains a backslash (`\`) character
+ * that does not start a valid escape sequence.
+ * @param str The offending string
+ * @param index The index of the offending backslash character in `str`.
+ */
+ class InvalidEscapeException(str: String, val index: Int) extends IllegalArgumentException(
+ s"""invalid escape ${
+ require(index >= 0 && index < str.length)
+ val ok = s"""[\\b, \\t, \\n, \\f, \\r, \\\\, \\", \\', \\uxxxx]"""
+ if (index == str.length - 1) "at terminal" else s"'\\${str(index + 1)}' not one of $ok at"
+ } index $index in "$str". Use \\\\ for literal \\."""
+ )
+
+ protected[scala] class InvalidUnicodeEscapeException(str: String, val escapeStart: Int, val index: Int) extends IllegalArgumentException(
+ s"""invalid unicode escape at index $index of $str"""
+ )
+
+ private[this] def readUEscape(src: String, startindex: Int): (Char, Int) = {
+ val len = src.length()
+ def loop(uindex: Int): (Char, Int) = {
+ def loopCP(dindex: Int, codepoint: Int): (Char, Int) = {
+ //supports BMP + surrogate escapes
+ //but only in four hex-digit code units (uxxxx)
+ if(dindex >= 4) {
+ val usRead = uindex - startindex
+ val digitsRead = dindex
+ (codepoint.asInstanceOf[Char], usRead + digitsRead)
+ }
+ else if (dindex + uindex >= len)
+ throw new InvalidUnicodeEscapeException(src, startindex, uindex + dindex)
+ else {
+ val ch = src(dindex + uindex)
+ val e = ch.asDigit
+ if(e >= 0 && e <= 15) loopCP(dindex + 1, (codepoint << 4) + e)
+ else throw new InvalidUnicodeEscapeException(src, startindex, uindex + dindex)
+ }
+ }
+ if(uindex >= len) throw new InvalidUnicodeEscapeException(src, startindex, uindex - 1)
+ //allow one or more `u` characters between the
+ //backslash and the code unit
+ else if(src(uindex) == 'u') loop(uindex + 1)
+ else loopCP(0, 0)
+ }
+ loop(startindex)
+ }
+
+ /** Expands standard Scala escape sequences in a string.
+ * Escape sequences are:
+ * control: `\b`, `\t`, `\n`, `\f`, `\r`
+ * escape: `\\`, `\"`, `\'`
+ *
+ * @param str A string that may contain escape sequences
+ * @return The string with all escape sequences expanded.
+ */
+ @deprecated("use processEscapes", "2.13.0")
+ def treatEscapes(str: String): String = processEscapes(str)
+
+ /** Expands standard Scala escape sequences in a string.
+ * Escape sequences are:
+ * control: `\b`, `\t`, `\n`, `\f`, `\r`
+ * escape: `\\`, `\"`, `\'`
+ *
+ * @param str A string that may contain escape sequences
+ * @return The string with all escape sequences expanded.
+ */
+ def processEscapes(str: String): String =
+ str indexOf '\\' match {
+ case -1 => str
+ case i => replace(str, i)
+ }
+
+ protected[scala] def processUnicode(str: String): String =
+ str indexOf "\\u" match {
+ case -1 => str
+ case i => replaceU(str, i)
+ }
+
+ //replace escapes with given first escape
+ private[this] def replace(str: String, first: Int): String = {
+ val len = str.length()
+ val b = new JLSBuilder
+ // append replacement starting at index `i`, with `next` backslash
+ @tailrec def loop(i: Int, next: Int): String = {
+ if (next >= 0) {
+ //require(str(next) == '\\')
+ if (next > i) b.append(str, i, next)
+ var idx = next + 1
+ if (idx >= len) throw new InvalidEscapeException(str, next)
+ val c = str(idx) match {
+ case 'u' => 'u'
+ case 'b' => '\b'
+ case 't' => '\t'
+ case 'n' => '\n'
+ case 'f' => '\f'
+ case 'r' => '\r'
+ case '"' => '"'
+ case '\'' => '\''
+ case '\\' => '\\'
+ case _ => throw new InvalidEscapeException(str, next)
+ }
+ val (ch, advance) = if (c == 'u') readUEscape(str, idx)
+ else (c, 1)
+ idx += advance
+ b append ch
+ loop(idx, str.indexOf('\\', idx))
+ } else {
+ if (i < len) b.append(str, i, len)
+ b.toString
+ }
+ }
+ loop(0, first)
+ }
+
+ /** replace Unicode escapes starting at index `backslash` which must be the
+ * index of the first index of a backslash character followed by a `u`
+ * character
+ *
+ * If a backslash is followed by one or more `u` characters and there is
+ * an odd number of backslashes immediately preceding the `u`, processing
+ * the escape is attempted and an invalid escape is an error.
+ * The odd backslashes rule is, well, odd, but is grandfathered in from
+ * pre-2.13.2 times, when this same rule existed in the scanner, and was also
+ * odd. Since escape handling here is for backwards compatibility only, that
+ * backwards compatibility is also retained.
+ * Otherwise, the backslash is not taken to introduce an escape and the
+ * backslash is taken to be literal
+ */
+ private[this] def replaceU(str: String, backslash: Int): String = {
+ val len = str.length()
+ val b = new JLSBuilder
+
+ @tailrec def loop(i: Int, next: Int): String = {
+ if (next >= 0) {
+ //require(str(next) == '\\' && str(next + 1) == 'u')
+ def oddBackslashes(ibackslash: Int): Boolean =
+ if (ibackslash > 0 && str(ibackslash - 1) == '\\') oddBackslashes(ibackslash - 1)
+ else ((next - ibackslash) % 2) == 0
+
+ if(oddBackslashes(next)) {
+ if (next > i) b.append(str, i, next)
+ val idx = next + 1
+ val (ch, advance) = readUEscape(str, idx)
+ val nextCharIndex = idx + advance
+ b.append(ch)
+ loop(nextCharIndex, str.indexOf("\\u", nextCharIndex))
+ }
+ else loop(i, str.indexOf("\\u", next + 1))
+ }
+ else {
+ if (i < len) b.append(str, i, len)
+ b.toString()
+ }
+ }
+ loop(0, backslash)
+ }
+
+ def standardInterpolator(process: String => String, args: scala.collection.Seq[Any], parts: Seq[String]): String = {
+ StringContext.checkLengths(args, parts)
+ val pi = parts.iterator
+ val ai = args.iterator
+ val bldr = new JLSBuilder(process(pi.next()))
+ while (ai.hasNext) {
+ bldr append ai.next()
+ bldr append process(pi.next())
+ }
+ bldr.toString
+ }
+
+ /** Checks that the length of the given argument `args` is one less than the number
+ * of `parts` supplied to the `StringContext`.
+ *
+ * @throws IllegalArgumentException if this is not the case.
+ */
+ def checkLengths(args: scala.collection.Seq[Any], parts: Seq[String]): Unit =
+ if (parts.length != args.length + 1)
+ throw new IllegalArgumentException("wrong number of arguments ("+ args.length
+ +") for interpolated string with "+ parts.length +" parts")
+
+}
diff --git a/library/src/scala/Symbol.scala b/library/src/scala/Symbol.scala
new file mode 100644
index 000000000000..36a99c5e4e6e
--- /dev/null
+++ b/library/src/scala/Symbol.scala
@@ -0,0 +1,84 @@
+/*
+ * 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
+
+/** This class provides a simple way to get unique objects for equal strings.
+ * Since symbols are interned, they can be compared using reference equality.
+ */
+final class Symbol private (val name: String) extends Serializable {
+ /** A string representation of this symbol.
+ */
+ override def toString(): String = s"Symbol($name)"
+
+ @throws(classOf[java.io.ObjectStreamException])
+ private def readResolve(): Any = Symbol.apply(name)
+ override def hashCode = name.hashCode()
+ override def equals(other: Any) = this eq other.asInstanceOf[AnyRef]
+}
+
+object Symbol extends UniquenessCache[String, Symbol] {
+ override def apply(name: String): Symbol = super.apply(name)
+ protected def valueFromKey(name: String): Symbol = new Symbol(name)
+ protected def keyFromValue(sym: Symbol): Option[String] = Some(sym.name)
+}
+
+/** This is private so it won't appear in the library API, but
+ * abstracted to offer some hope of reusability. */
+private[scala] abstract class UniquenessCache[K, V >: Null] {
+ import java.lang.ref.WeakReference
+ import java.util.WeakHashMap
+ import java.util.concurrent.locks.ReentrantReadWriteLock
+
+ private[this] val rwl = new ReentrantReadWriteLock()
+ private[this] val rlock = rwl.readLock
+ private[this] val wlock = rwl.writeLock
+ private[this] val map = new WeakHashMap[K, WeakReference[V]]
+
+ protected def valueFromKey(k: K): V
+ protected def keyFromValue(v: V): Option[K]
+
+ def apply(name: K): V = {
+ def cached(): V = {
+ rlock.lock
+ try {
+ val reference = map get name
+ if (reference == null) null
+ else reference.get // will be null if we were gc-ed
+ }
+ finally rlock.unlock
+ }
+ def updateCache(): V = {
+ wlock.lock
+ try {
+ val res = cached()
+ if (res != null) res
+ else {
+ // If we don't remove the old String key from the map, we can
+ // wind up with one String as the key and a different String as
+ // the name field in the Symbol, which can lead to surprising GC
+ // behavior and duplicate Symbols. See scala/bug#6706.
+ map remove name
+ val sym = valueFromKey(name)
+ map.put(name, new WeakReference(sym))
+ sym
+ }
+ }
+ finally wlock.unlock
+ }
+ cached() match {
+ case null => updateCache()
+ case res => res
+ }
+ }
+ def unapply(other: V): Option[K] = keyFromValue(other)
+}
diff --git a/library/src/scala/Tuple1.scala b/library/src/scala/Tuple1.scala
new file mode 100644
index 000000000000..6af3d3582b14
--- /dev/null
+++ b/library/src/scala/Tuple1.scala
@@ -0,0 +1,28 @@
+/*
+ * 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 + ")"
+
+}
diff --git a/library/src/scala/Tuple10.scala b/library/src/scala/Tuple10.scala
new file mode 100644
index 000000000000..63fa78016769
--- /dev/null
+++ b/library/src/scala/Tuple10.scala
@@ -0,0 +1,37 @@
+/*
+ * 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 10 elements; the canonical representation of a [[scala.Product10]].
+ *
+ * @constructor Create a new tuple with 10 elements. Note that it is more idiomatic to create a Tuple10 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)`
+ * @param _1 Element 1 of this Tuple10
+ * @param _2 Element 2 of this Tuple10
+ * @param _3 Element 3 of this Tuple10
+ * @param _4 Element 4 of this Tuple10
+ * @param _5 Element 5 of this Tuple10
+ * @param _6 Element 6 of this Tuple10
+ * @param _7 Element 7 of this Tuple10
+ * @param _8 Element 8 of this Tuple10
+ * @param _9 Element 9 of this Tuple10
+ * @param _10 Element 10 of this Tuple10
+ */
+final case class Tuple10[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10)
+ extends Product10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + ")"
+
+}
diff --git a/library/src/scala/Tuple11.scala b/library/src/scala/Tuple11.scala
new file mode 100644
index 000000000000..3cdf35e84b8c
--- /dev/null
+++ b/library/src/scala/Tuple11.scala
@@ -0,0 +1,38 @@
+/*
+ * 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 11 elements; the canonical representation of a [[scala.Product11]].
+ *
+ * @constructor Create a new tuple with 11 elements. Note that it is more idiomatic to create a Tuple11 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)`
+ * @param _1 Element 1 of this Tuple11
+ * @param _2 Element 2 of this Tuple11
+ * @param _3 Element 3 of this Tuple11
+ * @param _4 Element 4 of this Tuple11
+ * @param _5 Element 5 of this Tuple11
+ * @param _6 Element 6 of this Tuple11
+ * @param _7 Element 7 of this Tuple11
+ * @param _8 Element 8 of this Tuple11
+ * @param _9 Element 9 of this Tuple11
+ * @param _10 Element 10 of this Tuple11
+ * @param _11 Element 11 of this Tuple11
+ */
+final case class Tuple11[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11)
+ extends Product11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + ")"
+
+}
diff --git a/library/src/scala/Tuple12.scala b/library/src/scala/Tuple12.scala
new file mode 100644
index 000000000000..b27538f446c2
--- /dev/null
+++ b/library/src/scala/Tuple12.scala
@@ -0,0 +1,40 @@
+/*
+ * 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 12 elements; the canonical representation of a [[scala.Product12]].
+ *
+ * @constructor Create a new tuple with 12 elements. Note that it is more idiomatic to create a Tuple12 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12)`
+ * @param _1 Element 1 of this Tuple12
+ * @param _2 Element 2 of this Tuple12
+ * @param _3 Element 3 of this Tuple12
+ * @param _4 Element 4 of this Tuple12
+ * @param _5 Element 5 of this Tuple12
+ * @param _6 Element 6 of this Tuple12
+ * @param _7 Element 7 of this Tuple12
+ * @param _8 Element 8 of this Tuple12
+ * @param _9 Element 9 of this Tuple12
+ * @param _10 Element 10 of this Tuple12
+ * @param _11 Element 11 of this Tuple12
+ * @param _12 Element 12 of this Tuple12
+ */
+final case class Tuple12[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12)
+ extends Product12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 +
+ "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + ")"
+
+}
diff --git a/library/src/scala/Tuple13.scala b/library/src/scala/Tuple13.scala
new file mode 100644
index 000000000000..84f2f3cecc28
--- /dev/null
+++ b/library/src/scala/Tuple13.scala
@@ -0,0 +1,41 @@
+/*
+ * 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 13 elements; the canonical representation of a [[scala.Product13]].
+ *
+ * @constructor Create a new tuple with 13 elements. Note that it is more idiomatic to create a Tuple13 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13)`
+ * @param _1 Element 1 of this Tuple13
+ * @param _2 Element 2 of this Tuple13
+ * @param _3 Element 3 of this Tuple13
+ * @param _4 Element 4 of this Tuple13
+ * @param _5 Element 5 of this Tuple13
+ * @param _6 Element 6 of this Tuple13
+ * @param _7 Element 7 of this Tuple13
+ * @param _8 Element 8 of this Tuple13
+ * @param _9 Element 9 of this Tuple13
+ * @param _10 Element 10 of this Tuple13
+ * @param _11 Element 11 of this Tuple13
+ * @param _12 Element 12 of this Tuple13
+ * @param _13 Element 13 of this Tuple13
+ */
+final case class Tuple13[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13)
+ extends Product13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 +
+ "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + ")"
+
+}
diff --git a/library/src/scala/Tuple14.scala b/library/src/scala/Tuple14.scala
new file mode 100644
index 000000000000..08cd54c0cb82
--- /dev/null
+++ b/library/src/scala/Tuple14.scala
@@ -0,0 +1,42 @@
+/*
+ * 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 14 elements; the canonical representation of a [[scala.Product14]].
+ *
+ * @constructor Create a new tuple with 14 elements. Note that it is more idiomatic to create a Tuple14 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14)`
+ * @param _1 Element 1 of this Tuple14
+ * @param _2 Element 2 of this Tuple14
+ * @param _3 Element 3 of this Tuple14
+ * @param _4 Element 4 of this Tuple14
+ * @param _5 Element 5 of this Tuple14
+ * @param _6 Element 6 of this Tuple14
+ * @param _7 Element 7 of this Tuple14
+ * @param _8 Element 8 of this Tuple14
+ * @param _9 Element 9 of this Tuple14
+ * @param _10 Element 10 of this Tuple14
+ * @param _11 Element 11 of this Tuple14
+ * @param _12 Element 12 of this Tuple14
+ * @param _13 Element 13 of this Tuple14
+ * @param _14 Element 14 of this Tuple14
+ */
+final case class Tuple14[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14)
+ extends Product14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 +
+ "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + ")"
+
+}
diff --git a/library/src/scala/Tuple15.scala b/library/src/scala/Tuple15.scala
new file mode 100644
index 000000000000..b4a932352092
--- /dev/null
+++ b/library/src/scala/Tuple15.scala
@@ -0,0 +1,43 @@
+/*
+ * 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 15 elements; the canonical representation of a [[scala.Product15]].
+ *
+ * @constructor Create a new tuple with 15 elements. Note that it is more idiomatic to create a Tuple15 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15)`
+ * @param _1 Element 1 of this Tuple15
+ * @param _2 Element 2 of this Tuple15
+ * @param _3 Element 3 of this Tuple15
+ * @param _4 Element 4 of this Tuple15
+ * @param _5 Element 5 of this Tuple15
+ * @param _6 Element 6 of this Tuple15
+ * @param _7 Element 7 of this Tuple15
+ * @param _8 Element 8 of this Tuple15
+ * @param _9 Element 9 of this Tuple15
+ * @param _10 Element 10 of this Tuple15
+ * @param _11 Element 11 of this Tuple15
+ * @param _12 Element 12 of this Tuple15
+ * @param _13 Element 13 of this Tuple15
+ * @param _14 Element 14 of this Tuple15
+ * @param _15 Element 15 of this Tuple15
+ */
+final case class Tuple15[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15)
+ extends Product15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 +
+ "," + _8 + "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + ")"
+
+}
diff --git a/library/src/scala/Tuple16.scala b/library/src/scala/Tuple16.scala
new file mode 100644
index 000000000000..417fa3aff002
--- /dev/null
+++ b/library/src/scala/Tuple16.scala
@@ -0,0 +1,44 @@
+/*
+ * 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 16 elements; the canonical representation of a [[scala.Product16]].
+ *
+ * @constructor Create a new tuple with 16 elements. Note that it is more idiomatic to create a Tuple16 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16)`
+ * @param _1 Element 1 of this Tuple16
+ * @param _2 Element 2 of this Tuple16
+ * @param _3 Element 3 of this Tuple16
+ * @param _4 Element 4 of this Tuple16
+ * @param _5 Element 5 of this Tuple16
+ * @param _6 Element 6 of this Tuple16
+ * @param _7 Element 7 of this Tuple16
+ * @param _8 Element 8 of this Tuple16
+ * @param _9 Element 9 of this Tuple16
+ * @param _10 Element 10 of this Tuple16
+ * @param _11 Element 11 of this Tuple16
+ * @param _12 Element 12 of this Tuple16
+ * @param _13 Element 13 of this Tuple16
+ * @param _14 Element 14 of this Tuple16
+ * @param _15 Element 15 of this Tuple16
+ * @param _16 Element 16 of this Tuple16
+ */
+final case class Tuple16[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16)
+ extends Product16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 +
+ "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + ")"
+
+}
diff --git a/library/src/scala/Tuple17.scala b/library/src/scala/Tuple17.scala
new file mode 100644
index 000000000000..e7d63a81d1e9
--- /dev/null
+++ b/library/src/scala/Tuple17.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. See scala.Function0 for timestamp.
+
+package scala
+
+
+/** A tuple of 17 elements; the canonical representation of a [[scala.Product17]].
+ *
+ * @constructor Create a new tuple with 17 elements. Note that it is more idiomatic to create a Tuple17 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17)`
+ * @param _1 Element 1 of this Tuple17
+ * @param _2 Element 2 of this Tuple17
+ * @param _3 Element 3 of this Tuple17
+ * @param _4 Element 4 of this Tuple17
+ * @param _5 Element 5 of this Tuple17
+ * @param _6 Element 6 of this Tuple17
+ * @param _7 Element 7 of this Tuple17
+ * @param _8 Element 8 of this Tuple17
+ * @param _9 Element 9 of this Tuple17
+ * @param _10 Element 10 of this Tuple17
+ * @param _11 Element 11 of this Tuple17
+ * @param _12 Element 12 of this Tuple17
+ * @param _13 Element 13 of this Tuple17
+ * @param _14 Element 14 of this Tuple17
+ * @param _15 Element 15 of this Tuple17
+ * @param _16 Element 16 of this Tuple17
+ * @param _17 Element 17 of this Tuple17
+ */
+final case class Tuple17[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17)
+ extends Product17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 +
+ "," + _9 + "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + "," + _17 + ")"
+
+}
diff --git a/library/src/scala/Tuple18.scala b/library/src/scala/Tuple18.scala
new file mode 100644
index 000000000000..86875130951a
--- /dev/null
+++ b/library/src/scala/Tuple18.scala
@@ -0,0 +1,46 @@
+/*
+ * 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 18 elements; the canonical representation of a [[scala.Product18]].
+ *
+ * @constructor Create a new tuple with 18 elements. Note that it is more idiomatic to create a Tuple18 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18)`
+ * @param _1 Element 1 of this Tuple18
+ * @param _2 Element 2 of this Tuple18
+ * @param _3 Element 3 of this Tuple18
+ * @param _4 Element 4 of this Tuple18
+ * @param _5 Element 5 of this Tuple18
+ * @param _6 Element 6 of this Tuple18
+ * @param _7 Element 7 of this Tuple18
+ * @param _8 Element 8 of this Tuple18
+ * @param _9 Element 9 of this Tuple18
+ * @param _10 Element 10 of this Tuple18
+ * @param _11 Element 11 of this Tuple18
+ * @param _12 Element 12 of this Tuple18
+ * @param _13 Element 13 of this Tuple18
+ * @param _14 Element 14 of this Tuple18
+ * @param _15 Element 15 of this Tuple18
+ * @param _16 Element 16 of this Tuple18
+ * @param _17 Element 17 of this Tuple18
+ * @param _18 Element 18 of this Tuple18
+ */
+final case class Tuple18[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18)
+ extends Product18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 +
+ "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + "," + _17 + "," + _18 + ")"
+
+}
diff --git a/library/src/scala/Tuple19.scala b/library/src/scala/Tuple19.scala
new file mode 100644
index 000000000000..e3826ddd3073
--- /dev/null
+++ b/library/src/scala/Tuple19.scala
@@ -0,0 +1,47 @@
+/*
+ * 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 19 elements; the canonical representation of a [[scala.Product19]].
+ *
+ * @constructor Create a new tuple with 19 elements. Note that it is more idiomatic to create a Tuple19 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19)`
+ * @param _1 Element 1 of this Tuple19
+ * @param _2 Element 2 of this Tuple19
+ * @param _3 Element 3 of this Tuple19
+ * @param _4 Element 4 of this Tuple19
+ * @param _5 Element 5 of this Tuple19
+ * @param _6 Element 6 of this Tuple19
+ * @param _7 Element 7 of this Tuple19
+ * @param _8 Element 8 of this Tuple19
+ * @param _9 Element 9 of this Tuple19
+ * @param _10 Element 10 of this Tuple19
+ * @param _11 Element 11 of this Tuple19
+ * @param _12 Element 12 of this Tuple19
+ * @param _13 Element 13 of this Tuple19
+ * @param _14 Element 14 of this Tuple19
+ * @param _15 Element 15 of this Tuple19
+ * @param _16 Element 16 of this Tuple19
+ * @param _17 Element 17 of this Tuple19
+ * @param _18 Element 18 of this Tuple19
+ * @param _19 Element 19 of this Tuple19
+ */
+final case class Tuple19[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19)
+ extends Product19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 +
+ "," + _10 + "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + "," + _17 + "," + _18 + "," + _19 + ")"
+
+}
diff --git a/library/src/scala/Tuple2.scala b/library/src/scala/Tuple2.scala
new file mode 100644
index 000000000000..3429ed7dea62
--- /dev/null
+++ b/library/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)
+
+}
diff --git a/library/src/scala/Tuple20.scala b/library/src/scala/Tuple20.scala
new file mode 100644
index 000000000000..1d4826b94841
--- /dev/null
+++ b/library/src/scala/Tuple20.scala
@@ -0,0 +1,48 @@
+/*
+ * 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 20 elements; the canonical representation of a [[scala.Product20]].
+ *
+ * @constructor Create a new tuple with 20 elements. Note that it is more idiomatic to create a Tuple20 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20)`
+ * @param _1 Element 1 of this Tuple20
+ * @param _2 Element 2 of this Tuple20
+ * @param _3 Element 3 of this Tuple20
+ * @param _4 Element 4 of this Tuple20
+ * @param _5 Element 5 of this Tuple20
+ * @param _6 Element 6 of this Tuple20
+ * @param _7 Element 7 of this Tuple20
+ * @param _8 Element 8 of this Tuple20
+ * @param _9 Element 9 of this Tuple20
+ * @param _10 Element 10 of this Tuple20
+ * @param _11 Element 11 of this Tuple20
+ * @param _12 Element 12 of this Tuple20
+ * @param _13 Element 13 of this Tuple20
+ * @param _14 Element 14 of this Tuple20
+ * @param _15 Element 15 of this Tuple20
+ * @param _16 Element 16 of this Tuple20
+ * @param _17 Element 17 of this Tuple20
+ * @param _18 Element 18 of this Tuple20
+ * @param _19 Element 19 of this Tuple20
+ * @param _20 Element 20 of this Tuple20
+ */
+final case class Tuple20[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19, _20: T20)
+ extends Product20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 +
+ "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + "," + _17 + "," + _18 + "," + _19 + "," + _20 + ")"
+
+}
diff --git a/library/src/scala/Tuple21.scala b/library/src/scala/Tuple21.scala
new file mode 100644
index 000000000000..01503f0e9362
--- /dev/null
+++ b/library/src/scala/Tuple21.scala
@@ -0,0 +1,49 @@
+/*
+ * 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 21 elements; the canonical representation of a [[scala.Product21]].
+ *
+ * @constructor Create a new tuple with 21 elements. Note that it is more idiomatic to create a Tuple21 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20, t21)`
+ * @param _1 Element 1 of this Tuple21
+ * @param _2 Element 2 of this Tuple21
+ * @param _3 Element 3 of this Tuple21
+ * @param _4 Element 4 of this Tuple21
+ * @param _5 Element 5 of this Tuple21
+ * @param _6 Element 6 of this Tuple21
+ * @param _7 Element 7 of this Tuple21
+ * @param _8 Element 8 of this Tuple21
+ * @param _9 Element 9 of this Tuple21
+ * @param _10 Element 10 of this Tuple21
+ * @param _11 Element 11 of this Tuple21
+ * @param _12 Element 12 of this Tuple21
+ * @param _13 Element 13 of this Tuple21
+ * @param _14 Element 14 of this Tuple21
+ * @param _15 Element 15 of this Tuple21
+ * @param _16 Element 16 of this Tuple21
+ * @param _17 Element 17 of this Tuple21
+ * @param _18 Element 18 of this Tuple21
+ * @param _19 Element 19 of this Tuple21
+ * @param _20 Element 20 of this Tuple21
+ * @param _21 Element 21 of this Tuple21
+ */
+final case class Tuple21[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20, +T21](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19, _20: T20, _21: T21)
+ extends Product21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 +
+ "," + _11 + "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + "," + _17 + "," + _18 + "," + _19 + "," + _20 + "," + _21 + ")"
+
+}
diff --git a/library/src/scala/Tuple22.scala b/library/src/scala/Tuple22.scala
new file mode 100644
index 000000000000..3f84e75a5dc6
--- /dev/null
+++ b/library/src/scala/Tuple22.scala
@@ -0,0 +1,50 @@
+/*
+ * 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 22 elements; the canonical representation of a [[scala.Product22]].
+ *
+ * @constructor Create a new tuple with 22 elements. Note that it is more idiomatic to create a Tuple22 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20, t21, t22)`
+ * @param _1 Element 1 of this Tuple22
+ * @param _2 Element 2 of this Tuple22
+ * @param _3 Element 3 of this Tuple22
+ * @param _4 Element 4 of this Tuple22
+ * @param _5 Element 5 of this Tuple22
+ * @param _6 Element 6 of this Tuple22
+ * @param _7 Element 7 of this Tuple22
+ * @param _8 Element 8 of this Tuple22
+ * @param _9 Element 9 of this Tuple22
+ * @param _10 Element 10 of this Tuple22
+ * @param _11 Element 11 of this Tuple22
+ * @param _12 Element 12 of this Tuple22
+ * @param _13 Element 13 of this Tuple22
+ * @param _14 Element 14 of this Tuple22
+ * @param _15 Element 15 of this Tuple22
+ * @param _16 Element 16 of this Tuple22
+ * @param _17 Element 17 of this Tuple22
+ * @param _18 Element 18 of this Tuple22
+ * @param _19 Element 19 of this Tuple22
+ * @param _20 Element 20 of this Tuple22
+ * @param _21 Element 21 of this Tuple22
+ * @param _22 Element 22 of this Tuple22
+ */
+final case class Tuple22[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9, +T10, +T11, +T12, +T13, +T14, +T15, +T16, +T17, +T18, +T19, +T20, +T21, +T22](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9, _10: T10, _11: T11, _12: T12, _13: T13, _14: T14, _15: T15, _16: T16, _17: T17, _18: T18, _19: T19, _20: T20, _21: T21, _22: T22)
+ extends Product22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + "," + _10 + "," + _11 +
+ "," + _12 + "," + _13 + "," + _14 + "," + _15 + "," + _16 + "," + _17 + "," + _18 + "," + _19 + "," + _20 + "," + _21 + "," + _22 + ")"
+
+}
diff --git a/library/src/scala/Tuple3.scala b/library/src/scala/Tuple3.scala
new file mode 100644
index 000000000000..b053d9c4c6b2
--- /dev/null
+++ b/library/src/scala/Tuple3.scala
@@ -0,0 +1,30 @@
+/*
+ * 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 3 elements; the canonical representation of a [[scala.Product3]].
+ *
+ * @constructor Create a new tuple with 3 elements. Note that it is more idiomatic to create a Tuple3 via `(t1, t2, t3)`
+ * @param _1 Element 1 of this Tuple3
+ * @param _2 Element 2 of this Tuple3
+ * @param _3 Element 3 of this Tuple3
+ */
+final case class Tuple3[+T1, +T2, +T3](_1: T1, _2: T2, _3: T3)
+ extends Product3[T1, T2, T3]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + ")"
+
+}
diff --git a/library/src/scala/Tuple4.scala b/library/src/scala/Tuple4.scala
new file mode 100644
index 000000000000..29970f510398
--- /dev/null
+++ b/library/src/scala/Tuple4.scala
@@ -0,0 +1,31 @@
+/*
+ * 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 4 elements; the canonical representation of a [[scala.Product4]].
+ *
+ * @constructor Create a new tuple with 4 elements. Note that it is more idiomatic to create a Tuple4 via `(t1, t2, t3, t4)`
+ * @param _1 Element 1 of this Tuple4
+ * @param _2 Element 2 of this Tuple4
+ * @param _3 Element 3 of this Tuple4
+ * @param _4 Element 4 of this Tuple4
+ */
+final case class Tuple4[+T1, +T2, +T3, +T4](_1: T1, _2: T2, _3: T3, _4: T4)
+ extends Product4[T1, T2, T3, T4]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + ")"
+
+}
diff --git a/library/src/scala/Tuple5.scala b/library/src/scala/Tuple5.scala
new file mode 100644
index 000000000000..b6dbd2ea6cd4
--- /dev/null
+++ b/library/src/scala/Tuple5.scala
@@ -0,0 +1,32 @@
+/*
+ * 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 5 elements; the canonical representation of a [[scala.Product5]].
+ *
+ * @constructor Create a new tuple with 5 elements. Note that it is more idiomatic to create a Tuple5 via `(t1, t2, t3, t4, t5)`
+ * @param _1 Element 1 of this Tuple5
+ * @param _2 Element 2 of this Tuple5
+ * @param _3 Element 3 of this Tuple5
+ * @param _4 Element 4 of this Tuple5
+ * @param _5 Element 5 of this Tuple5
+ */
+final case class Tuple5[+T1, +T2, +T3, +T4, +T5](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5)
+ extends Product5[T1, T2, T3, T4, T5]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + ")"
+
+}
diff --git a/library/src/scala/Tuple6.scala b/library/src/scala/Tuple6.scala
new file mode 100644
index 000000000000..834d81a43e84
--- /dev/null
+++ b/library/src/scala/Tuple6.scala
@@ -0,0 +1,33 @@
+/*
+ * 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 6 elements; the canonical representation of a [[scala.Product6]].
+ *
+ * @constructor Create a new tuple with 6 elements. Note that it is more idiomatic to create a Tuple6 via `(t1, t2, t3, t4, t5, t6)`
+ * @param _1 Element 1 of this Tuple6
+ * @param _2 Element 2 of this Tuple6
+ * @param _3 Element 3 of this Tuple6
+ * @param _4 Element 4 of this Tuple6
+ * @param _5 Element 5 of this Tuple6
+ * @param _6 Element 6 of this Tuple6
+ */
+final case class Tuple6[+T1, +T2, +T3, +T4, +T5, +T6](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6)
+ extends Product6[T1, T2, T3, T4, T5, T6]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + ")"
+
+}
diff --git a/library/src/scala/Tuple7.scala b/library/src/scala/Tuple7.scala
new file mode 100644
index 000000000000..d6e86752addd
--- /dev/null
+++ b/library/src/scala/Tuple7.scala
@@ -0,0 +1,34 @@
+/*
+ * 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 7 elements; the canonical representation of a [[scala.Product7]].
+ *
+ * @constructor Create a new tuple with 7 elements. Note that it is more idiomatic to create a Tuple7 via `(t1, t2, t3, t4, t5, t6, t7)`
+ * @param _1 Element 1 of this Tuple7
+ * @param _2 Element 2 of this Tuple7
+ * @param _3 Element 3 of this Tuple7
+ * @param _4 Element 4 of this Tuple7
+ * @param _5 Element 5 of this Tuple7
+ * @param _6 Element 6 of this Tuple7
+ * @param _7 Element 7 of this Tuple7
+ */
+final case class Tuple7[+T1, +T2, +T3, +T4, +T5, +T6, +T7](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7)
+ extends Product7[T1, T2, T3, T4, T5, T6, T7]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + ")"
+
+}
diff --git a/library/src/scala/Tuple8.scala b/library/src/scala/Tuple8.scala
new file mode 100644
index 000000000000..035d44e5330e
--- /dev/null
+++ b/library/src/scala/Tuple8.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 8 elements; the canonical representation of a [[scala.Product8]].
+ *
+ * @constructor Create a new tuple with 8 elements. Note that it is more idiomatic to create a Tuple8 via `(t1, t2, t3, t4, t5, t6, t7, t8)`
+ * @param _1 Element 1 of this Tuple8
+ * @param _2 Element 2 of this Tuple8
+ * @param _3 Element 3 of this Tuple8
+ * @param _4 Element 4 of this Tuple8
+ * @param _5 Element 5 of this Tuple8
+ * @param _6 Element 6 of this Tuple8
+ * @param _7 Element 7 of this Tuple8
+ * @param _8 Element 8 of this Tuple8
+ */
+final case class Tuple8[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8)
+ extends Product8[T1, T2, T3, T4, T5, T6, T7, T8]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + ")"
+
+}
diff --git a/library/src/scala/Tuple9.scala b/library/src/scala/Tuple9.scala
new file mode 100644
index 000000000000..50869e2c9b22
--- /dev/null
+++ b/library/src/scala/Tuple9.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.
+ */
+
+// GENERATED CODE: DO NOT EDIT. See scala.Function0 for timestamp.
+
+package scala
+
+
+/** A tuple of 9 elements; the canonical representation of a [[scala.Product9]].
+ *
+ * @constructor Create a new tuple with 9 elements. Note that it is more idiomatic to create a Tuple9 via `(t1, t2, t3, t4, t5, t6, t7, t8, t9)`
+ * @param _1 Element 1 of this Tuple9
+ * @param _2 Element 2 of this Tuple9
+ * @param _3 Element 3 of this Tuple9
+ * @param _4 Element 4 of this Tuple9
+ * @param _5 Element 5 of this Tuple9
+ * @param _6 Element 6 of this Tuple9
+ * @param _7 Element 7 of this Tuple9
+ * @param _8 Element 8 of this Tuple9
+ * @param _9 Element 9 of this Tuple9
+ */
+final case class Tuple9[+T1, +T2, +T3, +T4, +T5, +T6, +T7, +T8, +T9](_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7, _8: T8, _9: T9)
+ extends Product9[T1, T2, T3, T4, T5, T6, T7, T8, T9]
+{
+ override def toString(): String = "(" + _1 + "," + _2 + "," + _3 + "," + _4 + "," + _5 + "," + _6 + "," + _7 + "," + _8 + "," + _9 + ")"
+
+}
diff --git a/library/src/scala/UninitializedError.scala b/library/src/scala/UninitializedError.scala
new file mode 100644
index 000000000000..84332c9a9d3e
--- /dev/null
+++ b/library/src/scala/UninitializedError.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.
+ */
+
+package scala
+
+/** This class represents uninitialized variable/value errors.
+ */
+// TODO: remove
+@deprecated("will be removed in a future release", since = "2.12.7")
+final class UninitializedError extends RuntimeException("uninitialized value")
diff --git a/library/src/scala/UninitializedFieldError.scala b/library/src/scala/UninitializedFieldError.scala
new file mode 100644
index 000000000000..d516abb68936
--- /dev/null
+++ b/library/src/scala/UninitializedFieldError.scala
@@ -0,0 +1,23 @@
+/*
+ * 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
+
+/** This class implements errors which are thrown whenever a
+ * field is used before it has been initialized.
+ *
+ * Such runtime checks are not emitted by default.
+ * They can be enabled by the `-Xcheckinit` compiler option.
+ */
+final case class UninitializedFieldError(msg: String) extends RuntimeException(msg) {
+ def this(obj: Any) = this("" + obj)
+}
diff --git a/library/src/scala/Unit.scala b/library/src/scala/Unit.scala
new file mode 100644
index 000000000000..66fde8c72038
--- /dev/null
+++ b/library/src/scala/Unit.scala
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+// DO NOT EDIT, CHANGES WILL BE LOST
+// This auto-generated code can be modified in "project/GenerateAnyVals.scala".
+// Afterwards, running "sbt generateSources" regenerates this source file.
+
+package scala
+
+
+/** `Unit` is a subtype of [[scala.AnyVal]]. There is only one value of type
+ * `Unit`, `()`, and it is not represented by any object in the underlying
+ * runtime system. A method with return type `Unit` is analogous to a Java
+ * method which is declared `void`.
+ */
+final abstract class Unit private extends AnyVal {
+ // Provide a more specific return type for Scaladoc
+ override def getClass(): Class[Unit] = ???
+}
+
+@scala.annotation.compileTimeOnly("`Unit` companion object is not allowed in source; instead, use `()` for the unit value")
+object Unit extends AnyValCompanion {
+
+ /** Transform a value type into a boxed reference type.
+ *
+ * This method is not intended for use in source code.
+ * The runtime representation of this value is platform specific.
+ *
+ * @param x the Unit to be boxed
+ * @return a scala.runtime.BoxedUnit offering `x` as its underlying value.
+ */
+ def box(x: Unit): scala.runtime.BoxedUnit = scala.runtime.BoxedUnit.UNIT
+
+ /** Transform a boxed type into a value type. Note that this
+ * method is not typesafe: it accepts any Object, but will throw
+ * an exception if the argument is not a scala.runtime.BoxedUnit.
+ *
+ * This method is not intended for use in source code.
+ * The result of successfully unboxing a value is `()`.
+ *
+ * @param x the scala.runtime.BoxedUnit to be unboxed.
+ * @throws ClassCastException if the argument is not a scala.runtime.BoxedUnit
+ * @return the Unit value ()
+ */
+ def unbox(x: java.lang.Object): Unit = x.asInstanceOf[scala.runtime.BoxedUnit]
+
+ /** The String representation of the scala.Unit companion object. */
+ override def toString = "object scala.Unit"
+}
+
diff --git a/library/src/scala/ValueOf.scala b/library/src/scala/ValueOf.scala
new file mode 100644
index 000000000000..30d5f7ff40c7
--- /dev/null
+++ b/library/src/scala/ValueOf.scala
@@ -0,0 +1,55 @@
+/*
+ * 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
+
+/**
+ * `ValueOf[T]` provides the unique value of the type `T` where `T` is a type which has a
+ * single inhabitant. Eligible types are singleton types of the form `stablePath.type`,
+ * Unit and singleton types corresponding to value literals.
+ *
+ * The value itself can conveniently be retrieved with [[Predef#valueOf]], which requires
+ * a `ValueOf` to be available in implicit scope.
+ *
+ * The compiler provides instances of `ValueOf[T]` for all eligible types. Typically
+ * an instance would be required where a runtime value corresponding to a type level
+ * computation is needed.
+
+ * For example, we might define a type `Residue[M <: Int]` corresponding to the group of
+ * integers modulo `M`. We could then mandate that residues can be summed only when they
+ * are parameterized by the same modulus,
+ *
+ * {{{
+ * case class Residue[M <: Int](n: Int) extends AnyVal {
+ * def +(rhs: Residue[M])(implicit m: ValueOf[M]): Residue[M] =
+ * Residue((this.n + rhs.n) % valueOf[M])
+ * }
+ *
+ * val fiveModTen = Residue[10](5)
+ * val nineModTen = Residue[10](9)
+ *
+ * fiveModTen + nineModTen // OK == Residue[10](4)
+ *
+ * val fourModEleven = Residue[11](4)
+ *
+ * fiveModTen + fourModEleven // compiler error: type mismatch;
+ * // found : Residue[11]
+ * // required: Residue[10]
+ * }}}
+ *
+ * Notice that here the modulus is encoded in the type of the values and so does not
+ * incur any additional per-value storage cost. When a runtime value of the modulus
+ * is required in the implementation of `+` it is provided at the call site via the
+ * implicit argument `m` of type `ValueOf[M]`.
+ */
+@scala.annotation.implicitNotFound(msg = "No singleton value available for ${T}; eligible singleton types for `ValueOf` synthesis include literals and stable paths.")
+final class ValueOf[T](val value: T) extends AnyVal
diff --git a/library/src/scala/annotation/Annotation.scala b/library/src/scala/annotation/Annotation.scala
new file mode 100644
index 000000000000..a78842cbf1c4
--- /dev/null
+++ b/library/src/scala/annotation/Annotation.scala
@@ -0,0 +1,26 @@
+/*
+ * 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.annotation
+
+/**
+ * A base class for annotations.
+ *
+ * Annotations extending this class directly are not preserved in the classfile. To enable storing
+ * annotations in the classfile's Scala signature and make it available to Scala reflection and
+ * other tools, the annotation needs to inherit from [[scala.annotation.StaticAnnotation]].
+ *
+ * Annotation classes defined in Scala are not stored in classfiles in a Java-compatible manner
+ * and therefore not visible in Java reflection. In order to achieve this, the annotation has to
+ * be written in Java.
+ */
+abstract class Annotation
diff --git a/library/src/scala/annotation/ClassfileAnnotation.scala b/library/src/scala/annotation/ClassfileAnnotation.scala
new file mode 100644
index 000000000000..be3c98b6130a
--- /dev/null
+++ b/library/src/scala/annotation/ClassfileAnnotation.scala
@@ -0,0 +1,20 @@
+/*
+ * 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.annotation
+
+/** A base class for classfile annotations. These are stored as
+ * [[https://docs.oracle.com/javase/8/docs/technotes/guides/language/annotations.html Java annotations]]
+ * in classfiles.
+ */
+@deprecated("Annotation classes need to be written in Java in order to be stored in classfiles in a Java-compatible manner", "2.13.0")
+trait ClassfileAnnotation extends ConstantAnnotation
diff --git a/library/src/scala/annotation/ConstantAnnotation.scala b/library/src/scala/annotation/ConstantAnnotation.scala
new file mode 100644
index 000000000000..b9a933371cc8
--- /dev/null
+++ b/library/src/scala/annotation/ConstantAnnotation.scala
@@ -0,0 +1,44 @@
+/*
+ * 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.annotation
+
+/**
+ * Annotation classes extending this trait only accept constant values as arguments.
+ *
+ * Note that this trait extends [[StaticAnnotation]], so constant annotations are persisted in the
+ * classfile.
+ *
+ * The implementation requires arguments of constant annotations to be passed as named arguments,
+ * except if there is a single argument, which then defines the annotation's parameter named
+ * `value`.
+ *
+ * Constant annotations may use default arguments. Note that the internal representation of an
+ * annotation usage (which is visible for compiler plugins, for example) only contains arguments
+ * that are explicitly provided.
+ *
+ * Constant annotations are not allowed to define auxiliary constructors, and the primary
+ * constructor is required to have a single parameter list.
+ *
+ * Example:
+ *
+ * {{{
+ * class Ann(value: Int, x: Int = 0) extends scala.annotation.ConstantAnnotation
+ * class Test {
+ * def someInt = 0
+ * @Ann(value = 0, x = 1) def g = 0
+ * @Ann(0) def f = 0 // Internal representation contains `@Ann(value = 0)`
+ * @Ann(someInt) // error: argument needs to be a compile-time constant
+ * }
+ * }}}
+ */
+trait ConstantAnnotation extends StaticAnnotation
diff --git a/library/src/scala/annotation/StaticAnnotation.scala b/library/src/scala/annotation/StaticAnnotation.scala
new file mode 100644
index 000000000000..dc0136db70af
--- /dev/null
+++ b/library/src/scala/annotation/StaticAnnotation.scala
@@ -0,0 +1,23 @@
+/*
+ * 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.annotation
+
+/**
+ * A base class for static annotations. These are available to the Scala type checker or Scala
+ * reflection, even across different compilation units.
+ *
+ * Annotation classes defined in Scala are not stored in classfiles in a Java-compatible manner
+ * and therefore not visible in Java reflection. In order to achieve this, the annotation has to
+ * be written in Java.
+ */
+trait StaticAnnotation extends Annotation
diff --git a/library/src/scala/annotation/TypeConstraint.scala b/library/src/scala/annotation/TypeConstraint.scala
new file mode 100644
index 000000000000..b9b5a62aa3c9
--- /dev/null
+++ b/library/src/scala/annotation/TypeConstraint.scala
@@ -0,0 +1,26 @@
+/*
+ * 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.annotation
+
+/** A marker for annotations that, when applied to a type, should be treated
+ * as a constraint on the annotated type.
+ *
+ * A proper constraint should restrict the type based only on information
+ * mentioned within the type. A Scala compiler can use this assumption to
+ * rewrite the contents of the constraint as necessary. To contrast, a type
+ * annotation whose meaning depends on the context where it is written
+ * down is not a proper constrained type, and this marker should not be
+ * applied. A Scala compiler will drop such annotations in cases where it
+ * would rewrite a type constraint.
+ */
+trait TypeConstraint extends Annotation
diff --git a/library/src/scala/annotation/compileTimeOnly.scala b/library/src/scala/annotation/compileTimeOnly.scala
new file mode 100644
index 000000000000..e2eb7560b8bf
--- /dev/null
+++ b/library/src/scala/annotation/compileTimeOnly.scala
@@ -0,0 +1,33 @@
+/*
+ * 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.annotation
+
+import scala.annotation.meta._
+
+/**
+ * An annotation that designates that an annottee should not be referred to after
+ * type checking (which includes macro expansion).
+ *
+ * Examples of potential use:
+ * 1) The annottee can only appear in the arguments of some other macro
+ * that will eliminate it from the AST during expansion.
+ * 2) The annottee is a macro and should have been expanded away,
+ * so if hasn't, something wrong has happened.
+ * (Comes in handy to provide better support for new macro flavors,
+ * e.g. macro annotations, that can't be expanded by the vanilla compiler).
+ *
+ * @param message the error message to print during compilation if a reference remains
+ * after type checking
+ */
+@getter @setter @beanGetter @beanSetter @companionClass @companionMethod
+final class compileTimeOnly(message: String) extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/elidable.scala b/library/src/scala/annotation/elidable.scala
new file mode 100644
index 000000000000..e15f0de8d9f1
--- /dev/null
+++ b/library/src/scala/annotation/elidable.scala
@@ -0,0 +1,156 @@
+/*
+ * 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.annotation
+
+/** An annotation for methods whose bodies may be excluded
+ * from compiler-generated bytecode.
+ *
+ * Behavior is influenced by passing `-Xelide-below ` to `scalac`.
+ * Calls to methods marked elidable (as well as the method body) will
+ * be omitted from generated code if the priority given the annotation
+ * is lower than that given on the command line.
+ *
+ * {{{
+ * @elidable(123) // annotation priority
+ * scalac -Xelide-below 456 // command line priority
+ * }}}
+ *
+ * The method call will be replaced with an expression which depends on
+ * the type of the elided expression. In decreasing order of precedence:
+ *
+ * {{{
+ * Unit ()
+ * Boolean false
+ * T <: AnyVal 0
+ * T >: Null null
+ * T >: Nothing Predef.???
+ * }}}
+ *
+ * Complete example:
+ * {{{
+ * import scala.annotation._, elidable._
+ * object Test extends App {
+ * def expensiveComputation(): Int = { Thread.sleep(1000) ; 172 }
+ *
+ * @elidable(WARNING) def warning(msg: String) = println(msg)
+ * @elidable(FINE) def debug(msg: String) = println(msg)
+ * @elidable(FINE) def computedValue = expensiveComputation()
+ *
+ * warning("Warning! Danger! Warning!")
+ * debug("Debug! Danger! Debug!")
+ * println("I computed a value: " + computedValue)
+ * }
+ * % scalac example.scala && scala Test
+ * Warning! Danger! Warning!
+ * Debug! Danger! Debug!
+ * I computed a value: 172
+ *
+ * // INFO lies between WARNING and FINE
+ * % scalac -Xelide-below INFO example.scala && scala Test
+ * Warning! Danger! Warning!
+ * I computed a value: 0
+ * }}}
+ *
+ * Note that only concrete methods can be marked `@elidable`. A non-annotated method
+ * is not elided, even if it overrides / implements a method that has the annotation.
+ *
+ * Also note that the static type determines which annotations are considered:
+ *
+ * {{{
+ * import scala.annotation._, elidable._
+ * class C { @elidable(0) def f(): Unit = ??? }
+ * object O extends C { override def f(): Unit = println("O.f") }
+ * object Test extends App {
+ * O.f() // not elided
+ * (O: C).f() // elided if compiled with `-Xelide-below 1`
+ * }
+ * }}}
+ *
+ * Note for Scala 3 users:
+ * If you're using Scala 3, the annotation exists since Scala 3 uses the Scala 2
+ * standard library, but it's unsupported by the Scala 3 compiler. Instead, to
+ * achieve the same result you'd want to utilize the `inline if` feature to
+ * introduce behavior that makes a method de facto elided at compile-time.
+ * {{{
+ * type LogLevel = Int
+ *
+ * object LogLevel:
+ * inline val Info = 0
+ * inline val Warn = 1
+ * inline val Debug = 2
+ *
+ * inline val appLogLevel = LogLevel.Warn
+ *
+ * inline def log(msg: String, inline level: LogLevel): Unit =
+ * inline if (level <= appLogLevel) then println(msg)
+ *
+ * log("Warn log", LogLevel.Warn)
+ *
+ * log("Debug log", LogLevel. Debug)
+ * }}}
+ */
+final class elidable(final val level: Int) extends scala.annotation.ConstantAnnotation
+
+/** This useless appearing code was necessary to allow people to use
+ * named constants for the elidable annotation. This is what it takes
+ * to convince the compiler to fold the constants: otherwise when it's
+ * time to check an elision level it's staring at a tree like
+ * {{{
+ * (Select(Level, Select(FINEST, Apply(intValue, Nil))))
+ * }}}
+ * instead of the number `300`.
+ */
+object elidable {
+ /** The levels `ALL` and `OFF` are confusing in this context because
+ * the sentiment being expressed when using the annotation is at cross
+ * purposes with the one being expressed via `-Xelide-below`. This
+ * confusion reaches its zenith at level `OFF`, where the annotation means
+ * ''never elide this method'' but `-Xelide-below OFF` is how you would
+ * say ''elide everything possible''.
+ *
+ * With no simple remedy at hand, the issue is now at least documented,
+ * and aliases `MAXIMUM` and `MINIMUM` are offered.
+ */
+ final val ALL = Int.MinValue // Level.ALL.intValue()
+ final val FINEST = 300 // Level.FINEST.intValue()
+ final val FINER = 400 // Level.FINER.intValue()
+ final val FINE = 500 // Level.FINE.intValue()
+ final val CONFIG = 700 // Level.CONFIG.intValue()
+ final val INFO = 800 // Level.INFO.intValue()
+ final val WARNING = 900 // Level.WARNING.intValue()
+ final val SEVERE = 1000 // Level.SEVERE.intValue()
+ final val OFF = Int.MaxValue // Level.OFF.intValue()
+
+ // a couple aliases for the confusing ALL and OFF
+ final val MAXIMUM = OFF
+ final val MINIMUM = ALL
+
+ // and we can add a few of our own
+ final val ASSERTION = 2000 // we should make this more granular
+
+ // for command line parsing so we can use names or ints
+ val byName: Map[String, Int] = Map(
+ "FINEST" -> FINEST,
+ "FINER" -> FINER,
+ "FINE" -> FINE,
+ "CONFIG" -> CONFIG,
+ "INFO" -> INFO,
+ "WARNING" -> WARNING,
+ "SEVERE" -> SEVERE,
+ "ASSERTION" -> ASSERTION,
+ "ALL" -> ALL,
+ "OFF" -> OFF,
+ "MAXIMUM" -> MAXIMUM,
+ "MINIMUM" -> MINIMUM
+ )
+}
diff --git a/library/src/scala/annotation/implicitAmbiguous.scala b/library/src/scala/annotation/implicitAmbiguous.scala
new file mode 100644
index 000000000000..5520c945fef2
--- /dev/null
+++ b/library/src/scala/annotation/implicitAmbiguous.scala
@@ -0,0 +1,42 @@
+/*
+ * 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.annotation
+
+/**
+ * To customize the error message that's emitted when an implicit search finds
+ * multiple ambiguous values, annotate at least one of the implicit values
+ * `@implicitAmbiguous`. Assuming the implicit value is a method with type
+ * parameters `X1,..., XN`, the error message will be the result of replacing
+ * all occurrences of `\${Xi}` in the string `msg` with the string representation
+ * of the corresponding type argument `Ti`.
+ *
+ * If more than one `@implicitAmbiguous` annotation is collected, the compiler is
+ * free to pick any of them to display.
+ *
+ * Nice errors can direct users to fix imports or even tell them why code
+ * intentionally doesn't compile.
+ *
+ * {{{
+ * trait =!=[C, D]
+ *
+ * implicit def neq[E, F] : E =!= F = null
+ *
+ * @annotation.implicitAmbiguous("Could not prove \${J} =!= \${J}")
+ * implicit def neqAmbig1[G, H, J] : J =!= J = null
+ * implicit def neqAmbig2[I] : I =!= I = null
+ *
+ * implicitly[Int =!= Int]
+ * }}}
+ */
+@meta.getter
+final class implicitAmbiguous(msg: String) extends scala.annotation.ConstantAnnotation
diff --git a/library/src/scala/annotation/implicitNotFound.scala b/library/src/scala/annotation/implicitNotFound.scala
new file mode 100644
index 000000000000..55a9179a394f
--- /dev/null
+++ b/library/src/scala/annotation/implicitNotFound.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.
+ */
+
+package scala.annotation
+
+/**
+ * To customize the error message that's emitted when an implicit of type
+ * `C[T1,..., TN]` cannot be found, annotate the class `C` with `@implicitNotFound`.
+ * Assuming `C` has type parameters `X1, ..., XN`, the error message will be the
+ * result of replacing all occurrences of `\${Xi}` in the string `msg` with the
+ * string representation of the corresponding type argument `Ti`.
+ * The annotation is effectively inherited by subtypes if they are not annotated.
+ *
+ * The annotation can also be attached to implicit parameters. In this case, `\${Xi}`
+ * can refer to type parameters in the current scope. The `@implicitNotFound` message
+ * on the parameter takes precedence over the one on the parameter's type.
+ *
+ * {{{
+ * import scala.annotation.implicitNotFound
+ *
+ * @implicitNotFound("Could not find an implicit C[\${T}, \${U}]")
+ * class C[T, U]
+ *
+ * class K[A] {
+ * def m[B](implicit c: C[List[A], B]) = 0
+ * def n[B](implicit @implicitNotFound("Specific message for C of list of \${A} and \${B}") c: C[List[A], B]) = 1
+ * }
+ *
+ * object Test {
+ * val k = new K[Int]
+ * k.m[String]
+ * k.n[String]
+ * }
+ * }}}
+ *
+ * The compiler issues the following error messages:
+ *
+ *
+ * Test.scala:13: error: Could not find an implicit C[List[Int], String]
+ * k.m[String]
+ * ^
+ * Test.scala:14: error: Specific message for C of list of Int and String
+ * k.n[String]
+ * ^
+ *
+ */
+final class implicitNotFound(msg: String) extends scala.annotation.ConstantAnnotation
diff --git a/library/src/scala/annotation/meta/beanGetter.scala b/library/src/scala/annotation/meta/beanGetter.scala
new file mode 100644
index 000000000000..58d37bfb1cde
--- /dev/null
+++ b/library/src/scala/annotation/meta/beanGetter.scala
@@ -0,0 +1,18 @@
+/*
+ * 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.annotation.meta
+
+/**
+ * Consult the documentation in package [[scala.annotation.meta]].
+ */
+final class beanGetter extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/meta/beanSetter.scala b/library/src/scala/annotation/meta/beanSetter.scala
new file mode 100644
index 000000000000..670c67259fa8
--- /dev/null
+++ b/library/src/scala/annotation/meta/beanSetter.scala
@@ -0,0 +1,18 @@
+/*
+ * 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.annotation.meta
+
+/**
+ * Consult the documentation in package [[scala.annotation.meta]].
+ */
+final class beanSetter extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/meta/companionClass.scala b/library/src/scala/annotation/meta/companionClass.scala
new file mode 100644
index 000000000000..0a7b072b521d
--- /dev/null
+++ b/library/src/scala/annotation/meta/companionClass.scala
@@ -0,0 +1,22 @@
+/*
+ * 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.annotation.meta
+
+/**
+ * When defining an implicit class, the Scala compiler creates an implicit
+ * conversion method for it. Annotations `@companionClass` and `@companionMethod`
+ * control where an annotation on the implicit class will go. By default, annotations
+ * on an implicit class end up only on the class.
+ *
+ */
+final class companionClass extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/meta/companionMethod.scala b/library/src/scala/annotation/meta/companionMethod.scala
new file mode 100644
index 000000000000..2e0080a1d61f
--- /dev/null
+++ b/library/src/scala/annotation/meta/companionMethod.scala
@@ -0,0 +1,22 @@
+/*
+ * 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.annotation.meta
+
+/**
+ * When defining an implicit class, the Scala compiler creates an implicit
+ * conversion method for it. Annotations `@companionClass` and `@companionMethod`
+ * control where an annotation on the implicit class will go. By default, annotations
+ * on an implicit class end up only on the class.
+ *
+ */
+final class companionMethod extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/meta/companionObject.scala b/library/src/scala/annotation/meta/companionObject.scala
new file mode 100644
index 000000000000..dc817b138707
--- /dev/null
+++ b/library/src/scala/annotation/meta/companionObject.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.
+ */
+
+package scala.annotation.meta
+
+/**
+ * Currently unused; intended as an annotation target for classes such as case classes
+ * that automatically generate a companion object
+ */
+final class companionObject extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/meta/field.scala b/library/src/scala/annotation/meta/field.scala
new file mode 100644
index 000000000000..ccd64a0179f7
--- /dev/null
+++ b/library/src/scala/annotation/meta/field.scala
@@ -0,0 +1,18 @@
+/*
+ * 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.annotation.meta
+
+/**
+ * Consult the documentation in package [[scala.annotation.meta]].
+ */
+final class field extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/meta/getter.scala b/library/src/scala/annotation/meta/getter.scala
new file mode 100644
index 000000000000..acbc7989c901
--- /dev/null
+++ b/library/src/scala/annotation/meta/getter.scala
@@ -0,0 +1,18 @@
+/*
+ * 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.annotation.meta
+
+/**
+ * Consult the documentation in package [[scala.annotation.meta]].
+ */
+final class getter extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/meta/languageFeature.scala b/library/src/scala/annotation/meta/languageFeature.scala
new file mode 100644
index 000000000000..f2d9c7890d47
--- /dev/null
+++ b/library/src/scala/annotation/meta/languageFeature.scala
@@ -0,0 +1,18 @@
+/*
+ * 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.annotation.meta
+
+/**
+ * An annotation giving particulars for a language feature in object `scala.language`.
+ */
+final class languageFeature(feature: String, enableRequired: Boolean) extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/meta/package.scala b/library/src/scala/annotation/meta/package.scala
new file mode 100644
index 000000000000..ab315e412e07
--- /dev/null
+++ b/library/src/scala/annotation/meta/package.scala
@@ -0,0 +1,80 @@
+/*
+ * 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.annotation
+
+/**
+ * When defining a field, the Scala compiler creates up to four accessors
+ * for it: a getter, a setter, and if the field is annotated with
+ * `@BeanProperty`, a bean getter and a bean setter.
+ *
+ * For instance in the following class definition
+ *
+ * {{{
+ * class C(@myAnnot @BeanProperty var c: Int)
+ * }}}
+ *
+ * there are six entities which can carry the annotation `@myAnnot`: the
+ * constructor parameter, the generated field and the four accessors.
+ *
+ * By default, annotations on (`val`-, `var`- or plain) constructor parameters
+ * end up on the parameter, not on any other entity. Annotations on fields
+ * by default only end up on the field.
+ *
+ * The meta-annotations in package `scala.annotation.meta` are used
+ * to control where annotations on fields and class parameters are copied.
+ * This is done by annotating either the annotation type or the annotation
+ * class with one or several of the meta-annotations in this package.
+ *
+ * ==Annotating the annotation type==
+ *
+ * The target meta-annotations can be put on the annotation type when
+ * instantiating the annotation. In the following example, the annotation
+ * `@Id` will be added only to the bean getter `getX`.
+ *
+ * {{{
+ * import javax.persistence.Id
+ * class A {
+ * @(Id @beanGetter) @BeanProperty val x = 0
+ * }
+ * }}}
+ *
+ * In order to annotate the field as well, the meta-annotation `@field`
+ * would need to be added.
+ *
+ * The syntax can be improved using a type alias:
+ *
+ * {{{
+ * object ScalaJPA {
+ * type Id = javax.persistence.Id @beanGetter
+ * }
+ * import ScalaJPA.Id
+ * class A {
+ * @Id @BeanProperty val x = 0
+ * }
+ * }}}
+ *
+ * ==Annotating the annotation class==
+ *
+ * For annotations defined in Scala, a default target can be specified
+ * in the annotation class itself, for example
+ *
+ * {{{
+ * @getter
+ * class myAnnotation extends Annotation
+ * }}}
+ *
+ * This only changes the default target for the annotation `myAnnotation`.
+ * When instantiating the annotation, the target can still be specified
+ * as described in the last section.
+ */
+package object meta
diff --git a/library/src/scala/annotation/meta/param.scala b/library/src/scala/annotation/meta/param.scala
new file mode 100644
index 000000000000..8c69a3b644b1
--- /dev/null
+++ b/library/src/scala/annotation/meta/param.scala
@@ -0,0 +1,18 @@
+/*
+ * 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.annotation.meta
+
+/**
+ * Consult the documentation in package [[scala.annotation.meta]].
+ */
+final class param extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/meta/setter.scala b/library/src/scala/annotation/meta/setter.scala
new file mode 100644
index 000000000000..b37979bec597
--- /dev/null
+++ b/library/src/scala/annotation/meta/setter.scala
@@ -0,0 +1,18 @@
+/*
+ * 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.annotation.meta
+
+/**
+ * Consult the documentation in package [[scala.annotation.meta]].
+ */
+final class setter extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/migration.scala b/library/src/scala/annotation/migration.scala
new file mode 100644
index 000000000000..81ef78dbd367
--- /dev/null
+++ b/library/src/scala/annotation/migration.scala
@@ -0,0 +1,30 @@
+/*
+ * 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.annotation
+
+/**
+ * An annotation that marks a member as having changed semantics
+ * between versions. This is intended for methods which for one
+ * reason or another retain the same name and type signature,
+ * but some aspect of their behavior is different. An illustrative
+ * examples is Stack.iterator, which reversed from LIFO to FIFO
+ * order between Scala 2.7 and 2.8.
+ *
+ * @param message A message describing the change, which is emitted
+ * by the compiler if the flag `-Xmigration` indicates a version
+ * prior to the changedIn version.
+ *
+ * @param changedIn The version, in which the behaviour change was
+ * introduced.
+ */
+private[scala] final class migration(message: String, changedIn: String) extends scala.annotation.ConstantAnnotation
diff --git a/library/src/scala/annotation/nowarn.scala b/library/src/scala/annotation/nowarn.scala
new file mode 100644
index 000000000000..a1cc7a056abb
--- /dev/null
+++ b/library/src/scala/annotation/nowarn.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.annotation
+
+/** An annotation for local warning suppression.
+ *
+ * The optional `value` parameter allows selectively silencing messages, see `scalac -Wconf:help`
+ * for help. Examples:
+ *
+ * {{{
+ * def f = {
+ * 1: @nowarn // don't warn "a pure expression does nothing in statement position"
+ * 2
+ * }
+ *
+ * @nowarn def f = { 1; deprecated() } // don't warn
+ *
+ * @nowarn("msg=pure expression does nothing")
+ * def f = { 1; deprecated() } // show deprecation warning
+ * }}}
+ *
+ * To ensure that a `@nowarn` annotation actually suppresses a warning, enable `-Xlint:unused` or `-Wunused:nowarn`.
+ * The unused annotation warning is emitted in category `unused-nowarn` and can be selectively managed
+ * using `-Wconf:cat=unused-nowarn:s`.
+ */
+class nowarn(value: String = "") extends ConstantAnnotation
diff --git a/library/src/scala/annotation/showAsInfix.scala b/library/src/scala/annotation/showAsInfix.scala
new file mode 100644
index 000000000000..9c4ecbe2eea1
--- /dev/null
+++ b/library/src/scala/annotation/showAsInfix.scala
@@ -0,0 +1,39 @@
+/*
+ * 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.annotation
+
+/**
+ * This annotation configures how Scala prints two-parameter generic types.
+ *
+ * By default, types with symbolic names are printed infix; while types without
+ * them are printed using the regular generic type syntax.
+ *
+ * Example of usage:
+ {{{
+ scala> class Map[T, U]
+ defined class Map
+
+ scala> def foo: Int Map Int = ???
+ foo: Map[Int,Int]
+
+ scala> @showAsInfix class Map[T, U]
+ defined class Map
+
+ scala> def foo: Int Map Int = ???
+ foo: Int Map Int
+ }}}
+ *
+ * @param enabled whether to show this type as an infix type operator.
+ */
+@deprecatedInheritance("Scheduled for being final in the future", "2.13.0")
+class showAsInfix(enabled: Boolean = true) extends annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/strictfp.scala b/library/src/scala/annotation/strictfp.scala
new file mode 100644
index 000000000000..40e297fc4d97
--- /dev/null
+++ b/library/src/scala/annotation/strictfp.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.
+ */
+
+package scala.annotation
+
+/** If this annotation is present on a method or its enclosing class,
+ * the strictfp flag will be emitted.
+ */
+@deprecatedInheritance("Scheduled for being final in the future", "2.13.0")
+class strictfp extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/switch.scala b/library/src/scala/annotation/switch.scala
new file mode 100644
index 000000000000..f4af17741fe6
--- /dev/null
+++ b/library/src/scala/annotation/switch.scala
@@ -0,0 +1,33 @@
+/*
+ * 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.annotation
+
+/** An annotation to be applied to a match expression. If present,
+ * the compiler will verify that the match has been compiled to a
+ * [[https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-3.html#jvms-3.10 tableswitch or lookupswitch]]
+ * and issue a warning if it instead compiles into a series of conditional expressions.
+ * Example usage:
+{{{
+ val Constant = 'Q'
+ def tokenMe(ch: Char) = (ch: @switch) match {
+ case ' ' | '\t' | '\n' => 1
+ case 'A' | 'Z' | '$' => 2
+ case '5' | Constant => 3 // a non-literal may prevent switch generation: this would not compile
+ case _ => 4
+ }
+}}}
+ *
+ * Note: for pattern matches with one or two cases, the compiler generates jump instructions.
+ * Annotating such a match with `@switch` does not issue any warning.
+ */
+final class switch extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/tailrec.scala b/library/src/scala/annotation/tailrec.scala
new file mode 100644
index 000000000000..7b3f80dbf66f
--- /dev/null
+++ b/library/src/scala/annotation/tailrec.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.annotation
+
+/** A method annotation which verifies that the method will be compiled
+ * with tail call optimization.
+ *
+ * If it is present, the compiler will issue an error if the method cannot
+ * be optimized into a loop.
+ */
+final class tailrec extends StaticAnnotation
diff --git a/library/src/scala/annotation/unchecked/uncheckedStable.scala b/library/src/scala/annotation/unchecked/uncheckedStable.scala
new file mode 100644
index 000000000000..12a18d635fe4
--- /dev/null
+++ b/library/src/scala/annotation/unchecked/uncheckedStable.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.annotation.unchecked
+
+import scala.annotation.meta.{field, getter}
+
+/** An annotation for values that are assumed to be stable even though their
+ * types are volatile.
+ */
+@getter @field
+final class uncheckedStable extends scala.annotation.StaticAnnotation {}
diff --git a/library/src/scala/annotation/unchecked/uncheckedVariance.scala b/library/src/scala/annotation/unchecked/uncheckedVariance.scala
new file mode 100644
index 000000000000..60f06ad95f7d
--- /dev/null
+++ b/library/src/scala/annotation/unchecked/uncheckedVariance.scala
@@ -0,0 +1,17 @@
+/*
+ * 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.annotation.unchecked
+
+/** An annotation for type arguments for which one wants to suppress variance checking.
+ */
+final class uncheckedVariance extends scala.annotation.StaticAnnotation {}
diff --git a/library/src/scala/annotation/unspecialized.scala b/library/src/scala/annotation/unspecialized.scala
new file mode 100644
index 000000000000..c0f668a75298
--- /dev/null
+++ b/library/src/scala/annotation/unspecialized.scala
@@ -0,0 +1,20 @@
+/*
+ * 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.annotation
+
+/** A method annotation which suppresses the creation of
+ * additional specialized forms based on enclosing specialized
+ * type parameters.
+ */
+@deprecatedInheritance("Scheduled for being final in the future", "2.13.0")
+class unspecialized extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/annotation/unused.scala b/library/src/scala/annotation/unused.scala
new file mode 100644
index 000000000000..270286864822
--- /dev/null
+++ b/library/src/scala/annotation/unused.scala
@@ -0,0 +1,26 @@
+/*
+ * 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.annotation
+
+/** Mark an element unused for a given context.
+ *
+ * Unused warnings are suppressed for elements known to be unused.
+ *
+ * For example, a method parameter may be marked `@unused`
+ * because the method is designed to be overridden by
+ * an implementation that does use the parameter.
+ */
+@meta.getter @meta.setter
+class unused(message: String) extends StaticAnnotation {
+ def this() = this("")
+}
diff --git a/library/src/scala/annotation/varargs.scala b/library/src/scala/annotation/varargs.scala
new file mode 100644
index 000000000000..68d1080a53f8
--- /dev/null
+++ b/library/src/scala/annotation/varargs.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.
+ */
+
+package scala.annotation
+
+/** A method annotation which instructs the compiler to generate a
+ * Java varargs-style forwarder method for interop. This annotation can
+ * only be applied to methods with repeated parameters.
+ */
+final class varargs extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/beans/BeanProperty.scala b/library/src/scala/beans/BeanProperty.scala
new file mode 100644
index 000000000000..7b2ef0c9d516
--- /dev/null
+++ b/library/src/scala/beans/BeanProperty.scala
@@ -0,0 +1,38 @@
+/*
+ * 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.beans
+
+import scala.annotation.meta.{beanGetter, beanSetter, field}
+
+/** When attached to a field, this annotation adds a setter and a getter
+ * method following the Java Bean convention. For example:
+ * {{{
+ * @BeanProperty
+ * var status = ""
+ * }}}
+ * adds the following methods to the class:
+ * {{{
+ * def setStatus(s: String): Unit = { this.status = s }
+ * def getStatus(): String = this.status
+ * }}}
+ * For fields of type `Boolean`, if you need a getter named `isStatus`,
+ * use the `scala.beans.BooleanBeanProperty` annotation instead.
+ *
+ * In Scala 2, the added methods are visible from both Scala and Java.
+ *
+ * In Scala 3, that has changed. The added methods are only visible from
+ * Java (including via Java reflection).
+ */
+@field @beanGetter @beanSetter
+@deprecatedInheritance("Scheduled for being final in the future", "2.13.0")
+class BeanProperty extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/beans/BooleanBeanProperty.scala b/library/src/scala/beans/BooleanBeanProperty.scala
new file mode 100644
index 000000000000..72d253df2f8b
--- /dev/null
+++ b/library/src/scala/beans/BooleanBeanProperty.scala
@@ -0,0 +1,23 @@
+/*
+ * 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.beans
+
+import scala.annotation.meta.{beanGetter, beanSetter, field}
+
+/** This annotation has the same functionality as
+ * `scala.beans.BeanProperty`, but the generated Bean getter will be
+ * named `isFieldName` instead of `getFieldName`.
+ */
+@field @beanGetter @beanSetter
+@deprecatedInheritance("Scheduled for being final in the future", "2.13.0")
+class BooleanBeanProperty extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/collection/ArrayOps.scala b/library/src/scala/collection/ArrayOps.scala
new file mode 100644
index 000000000000..08758e2ab46a
--- /dev/null
+++ b/library/src/scala/collection/ArrayOps.scala
@@ -0,0 +1,1666 @@
+/*
+ * 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 collection
+
+import java.lang.Math.{max, min}
+import java.util.Arrays
+
+import scala.Predef.{ // unimport all array-related implicit conversions to avoid triggering them accidentally
+ genericArrayOps => _,
+ booleanArrayOps => _,
+ byteArrayOps => _,
+ charArrayOps => _,
+ doubleArrayOps => _,
+ floatArrayOps => _,
+ intArrayOps => _,
+ longArrayOps => _,
+ refArrayOps => _,
+ shortArrayOps => _,
+ unitArrayOps => _,
+ genericWrapArray => _,
+ wrapRefArray => _,
+ wrapIntArray => _,
+ wrapDoubleArray => _,
+ wrapLongArray => _,
+ wrapFloatArray => _,
+ wrapCharArray => _,
+ wrapByteArray => _,
+ wrapShortArray => _,
+ wrapBooleanArray => _,
+ wrapUnitArray => _,
+ wrapString => _,
+ copyArrayToImmutableIndexedSeq => _,
+ _
+}
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.generic.CommonErrors
+import scala.collection.immutable.Range
+import scala.collection.mutable.ArrayBuilder
+import scala.math.Ordering
+import scala.reflect.ClassTag
+import scala.util.Sorting
+
+object ArrayOps {
+
+ @SerialVersionUID(3L)
+ private class ArrayView[A](xs: Array[A]) extends AbstractIndexedSeqView[A] {
+ def length = xs.length
+ def apply(n: Int) = xs(n)
+ override def toString: String = immutable.ArraySeq.unsafeWrapArray(xs).mkString("ArrayView(", ", ", ")")
+ }
+
+ /** A lazy filtered array. No filtering is applied until one of `foreach`, `map` or `flatMap` is called. */
+ class WithFilter[A](p: A => Boolean, xs: Array[A]) {
+
+ /** Apply `f` to each element for its side effects.
+ * Note: [U] parameter needed to help scalac's type inference.
+ */
+ def foreach[U](f: A => U): Unit = {
+ val len = xs.length
+ var i = 0
+ while(i < len) {
+ val x = xs(i)
+ if(p(x)) f(x)
+ i += 1
+ }
+ }
+
+ /** Builds a new array by applying a function to all elements of this array.
+ *
+ * @param f the function to apply to each element.
+ * @tparam B the element type of the returned array.
+ * @return a new array resulting from applying the given function
+ * `f` to each element of this array and collecting the results.
+ */
+ def map[B: ClassTag](f: A => B): Array[B] = {
+ val b = ArrayBuilder.make[B]
+ var i = 0
+ while (i < xs.length) {
+ val x = xs(i)
+ if(p(x)) b += f(x)
+ i = i + 1
+ }
+ b.result()
+ }
+
+ /** Builds a new array by applying a function to all elements of this array
+ * and using the elements of the resulting collections.
+ *
+ * @param f the function to apply to each element.
+ * @tparam B the element type of the returned array.
+ * @return a new array resulting from applying the given collection-valued function
+ * `f` to each element of this array and concatenating the results.
+ */
+ def flatMap[B: ClassTag](f: A => IterableOnce[B]): Array[B] = {
+ val b = ArrayBuilder.make[B]
+ var i = 0
+ while(i < xs.length) {
+ val x = xs(i)
+ if(p(x)) b ++= f(xs(i))
+ i += 1
+ }
+ b.result()
+ }
+
+ def flatMap[BS, B](f: A => BS)(implicit asIterable: BS => Iterable[B], m: ClassTag[B]): Array[B] =
+ flatMap[B](x => asIterable(f(x)))
+
+ /** Creates a new non-strict filter which combines this filter with the given predicate. */
+ def withFilter(q: A => Boolean): WithFilter[A] = new WithFilter[A](a => p(a) && q(a), xs)
+ }
+
+ @SerialVersionUID(3L)
+ private[collection] final class ArrayIterator[@specialized(Specializable.Everything) A](xs: Array[A]) extends AbstractIterator[A] with Serializable {
+ private[this] var pos = 0
+ private[this] val len = xs.length
+ override def knownSize: Int = len - pos
+ def hasNext: Boolean = pos < len
+ def next(): A = {
+ if (pos >= xs.length) Iterator.empty.next()
+ val r = xs(pos)
+ pos += 1
+ r
+ }
+ override def drop(n: Int): Iterator[A] = {
+ if (n > 0) {
+ val newPos = pos + n
+ pos =
+ if (newPos < 0 /* overflow */) len
+ else Math.min(len, newPos)
+ }
+ this
+ }
+ }
+
+ @SerialVersionUID(3L)
+ private final class ReverseIterator[@specialized(Specializable.Everything) A](xs: Array[A]) extends AbstractIterator[A] with Serializable {
+ private[this] var pos = xs.length-1
+ def hasNext: Boolean = pos >= 0
+ def next(): A = {
+ if (pos < 0) Iterator.empty.next()
+ val r = xs(pos)
+ pos -= 1
+ r
+ }
+
+ override def drop(n: Int): Iterator[A] = {
+ if (n > 0) pos = Math.max( -1, pos - n)
+ this
+ }
+ }
+
+ @SerialVersionUID(3L)
+ private final class GroupedIterator[A](xs: Array[A], groupSize: Int) extends AbstractIterator[Array[A]] with Serializable {
+ private[this] var pos = 0
+ def hasNext: Boolean = pos < xs.length
+ def next(): Array[A] = {
+ if(pos >= xs.length) throw new NoSuchElementException
+ val r = new ArrayOps(xs).slice(pos, pos+groupSize)
+ pos += groupSize
+ r
+ }
+ }
+
+ /** The cut-off point for the array size after which we switch from `Sorting.stableSort` to
+ * an implementation that copies the data to a boxed representation for use with `Arrays.sort`.
+ */
+ private final val MaxStableSortLength = 300
+
+ /** Avoid an allocation in [[collect]]. */
+ private val fallback: Any => Any = _ => fallback
+}
+
+/** This class serves as a wrapper for `Array`s with many of the operations found in
+ * indexed sequences. Where needed, instances of arrays are implicitly converted
+ * into this class. There is generally no reason to create an instance explicitly or use
+ * an `ArrayOps` type. It is better to work with plain `Array` types instead and rely on
+ * the implicit conversion to `ArrayOps` when calling a method (which does not actually
+ * allocate an instance of `ArrayOps` because it is a value class).
+ *
+ * Neither `Array` nor `ArrayOps` are proper collection types
+ * (i.e. they do not extend `Iterable` or even `IterableOnce`). `mutable.ArraySeq` and
+ * `immutable.ArraySeq` serve this purpose.
+ *
+ * The difference between this class and `ArraySeq`s is that calling transformer methods such as
+ * `filter` and `map` will yield an array, whereas an `ArraySeq` will remain an `ArraySeq`.
+ *
+ * @tparam A type of the elements contained in this array.
+ */
+final class ArrayOps[A](private val xs: Array[A]) extends AnyVal {
+
+ @`inline` private[this] implicit def elemTag: ClassTag[A] = ClassTag(xs.getClass.getComponentType)
+
+ /** The size of this array.
+ *
+ * @return the number of elements in this array.
+ */
+ @`inline` def size: Int = xs.length
+
+ /** The size of this array.
+ *
+ * @return the number of elements in this array.
+ */
+ @`inline` def knownSize: Int = xs.length
+
+ /** Tests whether the array is empty.
+ *
+ * @return `true` if the array contains no elements, `false` otherwise.
+ */
+ @`inline` def isEmpty: Boolean = xs.length == 0
+
+ /** Tests whether the array is not empty.
+ *
+ * @return `true` if the array contains at least one element, `false` otherwise.
+ */
+ @`inline` def nonEmpty: Boolean = xs.length != 0
+
+ /** Selects the first element of this array.
+ *
+ * @return the first element of this array.
+ * @throws NoSuchElementException if the array is empty.
+ */
+ def head: A = if (nonEmpty) xs.apply(0) else throw new NoSuchElementException("head of empty array")
+
+ /** Selects the last element.
+ *
+ * @return The last element of this array.
+ * @throws NoSuchElementException If the array is empty.
+ */
+ def last: A = if (nonEmpty) xs.apply(xs.length-1) else throw new NoSuchElementException("last of empty array")
+
+ /** Optionally selects the first element.
+ *
+ * @return the first element of this array if it is nonempty,
+ * `None` if it is empty.
+ */
+ def headOption: Option[A] = if(isEmpty) None else Some(head)
+
+ /** Optionally selects the last element.
+ *
+ * @return the last element of this array$ if it is nonempty,
+ * `None` if it is empty.
+ */
+ def lastOption: Option[A] = if(isEmpty) None else Some(last)
+
+ /** Compares the size of this array to a test value.
+ *
+ * @param otherSize the test value that gets compared with the size.
+ * @return A value `x` where
+ * {{{
+ * x < 0 if this.size < otherSize
+ * x == 0 if this.size == otherSize
+ * x > 0 if this.size > otherSize
+ * }}}
+ */
+ def sizeCompare(otherSize: Int): Int = Integer.compare(xs.length, otherSize)
+
+ /** Compares the length of this array to a test value.
+ *
+ * @param len the test value that gets compared with the length.
+ * @return A value `x` where
+ * {{{
+ * x < 0 if this.length < len
+ * x == 0 if this.length == len
+ * x > 0 if this.length > len
+ * }}}
+ */
+ def lengthCompare(len: Int): Int = Integer.compare(xs.length, len)
+
+ /** Method mirroring [[SeqOps.sizeIs]] for consistency, except it returns an `Int`
+ * because `size` is known and comparison is constant-time.
+ *
+ * These operations are equivalent to [[sizeCompare(Int) `sizeCompare(Int)`]], and
+ * allow the following more readable usages:
+ *
+ * {{{
+ * this.sizeIs < size // this.sizeCompare(size) < 0
+ * this.sizeIs <= size // this.sizeCompare(size) <= 0
+ * this.sizeIs == size // this.sizeCompare(size) == 0
+ * this.sizeIs != size // this.sizeCompare(size) != 0
+ * this.sizeIs >= size // this.sizeCompare(size) >= 0
+ * this.sizeIs > size // this.sizeCompare(size) > 0
+ * }}}
+ */
+ def sizeIs: Int = xs.length
+
+ /** Method mirroring [[SeqOps.lengthIs]] for consistency, except it returns an `Int`
+ * because `length` is known and comparison is constant-time.
+ *
+ * These operations are equivalent to [[lengthCompare(Int) `lengthCompare(Int)`]], and
+ * allow the following more readable usages:
+ *
+ * {{{
+ * this.lengthIs < len // this.lengthCompare(len) < 0
+ * this.lengthIs <= len // this.lengthCompare(len) <= 0
+ * this.lengthIs == len // this.lengthCompare(len) == 0
+ * this.lengthIs != len // this.lengthCompare(len) != 0
+ * this.lengthIs >= len // this.lengthCompare(len) >= 0
+ * this.lengthIs > len // this.lengthCompare(len) > 0
+ * }}}
+ */
+ def lengthIs: Int = xs.length
+
+ /** Selects an interval of elements. The returned array is made up
+ * of all elements `x` which satisfy the invariant:
+ * {{{
+ * from <= indexOf(x) < until
+ * }}}
+ *
+ * @param from the lowest index to include from this array.
+ * @param until the lowest index to EXCLUDE from this array.
+ * @return an array containing the elements greater than or equal to
+ * index `from` extending up to (but not including) index `until`
+ * of this array.
+ */
+ def slice(from: Int, until: Int): Array[A] = {
+ import java.util.Arrays.copyOfRange
+ val lo = max(from, 0)
+ val hi = min(until, xs.length)
+ if (hi > lo) {
+ (((xs: Array[_]): @unchecked) match {
+ case x: Array[AnyRef] => copyOfRange(x, lo, hi)
+ case x: Array[Int] => copyOfRange(x, lo, hi)
+ case x: Array[Double] => copyOfRange(x, lo, hi)
+ case x: Array[Long] => copyOfRange(x, lo, hi)
+ case x: Array[Float] => copyOfRange(x, lo, hi)
+ case x: Array[Char] => copyOfRange(x, lo, hi)
+ case x: Array[Byte] => copyOfRange(x, lo, hi)
+ case x: Array[Short] => copyOfRange(x, lo, hi)
+ case x: Array[Boolean] => copyOfRange(x, lo, hi)
+ }).asInstanceOf[Array[A]]
+ } else new Array[A](0)
+ }
+
+ /** The rest of the array without its first element. */
+ def tail: Array[A] =
+ if(xs.length == 0) throw new UnsupportedOperationException("tail of empty array") else slice(1, xs.length)
+
+ /** The initial part of the array without its last element. */
+ def init: Array[A] =
+ if(xs.length == 0) throw new UnsupportedOperationException("init of empty array") else slice(0, xs.length-1)
+
+ /** Iterates over the tails of this array. The first value will be this
+ * array and the final one will be an empty array, with the intervening
+ * values the results of successive applications of `tail`.
+ *
+ * @return an iterator over all the tails of this array
+ */
+ def tails: Iterator[Array[A]] = iterateUntilEmpty(xs => new ArrayOps(xs).tail)
+
+ /** Iterates over the inits of this array. The first value will be this
+ * array and the final one will be an empty array, with the intervening
+ * values the results of successive applications of `init`.
+ *
+ * @return an iterator over all the inits of this array
+ */
+ def inits: Iterator[Array[A]] = iterateUntilEmpty(xs => new ArrayOps(xs).init)
+
+ // A helper for tails and inits.
+ private[this] def iterateUntilEmpty(f: Array[A] => Array[A]): Iterator[Array[A]] =
+ Iterator.iterate(xs)(f).takeWhile(x => x.length != 0) ++ Iterator.single(Array.empty[A])
+
+ /** An array containing the first `n` elements of this array. */
+ def take(n: Int): Array[A] = slice(0, n)
+
+ /** The rest of the array without its `n` first elements. */
+ def drop(n: Int): Array[A] = slice(n, xs.length)
+
+ /** An array containing the last `n` elements of this array. */
+ def takeRight(n: Int): Array[A] = drop(xs.length - max(n, 0))
+
+ /** The rest of the array without its `n` last elements. */
+ def dropRight(n: Int): Array[A] = take(xs.length - max(n, 0))
+
+ /** Takes longest prefix of elements that satisfy a predicate.
+ *
+ * @param p The predicate used to test elements.
+ * @return the longest prefix of this array whose elements all satisfy
+ * the predicate `p`.
+ */
+ def takeWhile(p: A => Boolean): Array[A] = {
+ val i = indexWhere(x => !p(x))
+ val hi = if(i < 0) xs.length else i
+ slice(0, hi)
+ }
+
+ /** Drops longest prefix of elements that satisfy a predicate.
+ *
+ * @param p The predicate used to test elements.
+ * @return the longest suffix of this array whose first element
+ * does not satisfy the predicate `p`.
+ */
+ def dropWhile(p: A => Boolean): Array[A] = {
+ val i = indexWhere(x => !p(x))
+ val lo = if(i < 0) xs.length else i
+ slice(lo, xs.length)
+ }
+
+ def iterator: Iterator[A] =
+ ((xs: Any @unchecked) match {
+ case xs: Array[AnyRef] => new ArrayOps.ArrayIterator(xs)
+ case xs: Array[Int] => new ArrayOps.ArrayIterator(xs)
+ case xs: Array[Double] => new ArrayOps.ArrayIterator(xs)
+ case xs: Array[Long] => new ArrayOps.ArrayIterator(xs)
+ case xs: Array[Float] => new ArrayOps.ArrayIterator(xs)
+ case xs: Array[Char] => new ArrayOps.ArrayIterator(xs)
+ case xs: Array[Byte] => new ArrayOps.ArrayIterator(xs)
+ case xs: Array[Short] => new ArrayOps.ArrayIterator(xs)
+ case xs: Array[Boolean] => new ArrayOps.ArrayIterator(xs)
+ case xs: Array[Unit] => new ArrayOps.ArrayIterator(xs)
+ case null => throw new NullPointerException
+ }).asInstanceOf[Iterator[A]]
+
+ def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit = {
+ import convert.impl._
+ val s = (shape.shape: @unchecked) match {
+ case StepperShape.ReferenceShape => (xs: Any) match {
+ case bs: Array[Boolean] => new BoxedBooleanArrayStepper(bs, 0, xs.length)
+ case _ => new ObjectArrayStepper[AnyRef](xs.asInstanceOf[Array[AnyRef ]], 0, xs.length)
+ }
+ case StepperShape.IntShape => new IntArrayStepper (xs.asInstanceOf[Array[Int ]], 0, xs.length)
+ case StepperShape.LongShape => new LongArrayStepper (xs.asInstanceOf[Array[Long ]], 0, xs.length)
+ case StepperShape.DoubleShape => new DoubleArrayStepper (xs.asInstanceOf[Array[Double ]], 0, xs.length)
+ case StepperShape.ByteShape => new WidenedByteArrayStepper (xs.asInstanceOf[Array[Byte ]], 0, xs.length)
+ case StepperShape.ShortShape => new WidenedShortArrayStepper (xs.asInstanceOf[Array[Short ]], 0, xs.length)
+ case StepperShape.CharShape => new WidenedCharArrayStepper (xs.asInstanceOf[Array[Char ]], 0, xs.length)
+ case StepperShape.FloatShape => new WidenedFloatArrayStepper (xs.asInstanceOf[Array[Float ]], 0, xs.length)
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ /** Partitions elements in fixed size arrays.
+ * @see [[scala.collection.Iterator]], method `grouped`
+ *
+ * @param size the number of elements per group
+ * @return An iterator producing arrays of size `size`, except the
+ * last will be less than size `size` if the elements don't divide evenly.
+ */
+ def grouped(size: Int): Iterator[Array[A]] = new ArrayOps.GroupedIterator[A](xs, size)
+
+ /** Splits this array into a prefix/suffix pair according to a predicate.
+ *
+ * Note: `c span p` is equivalent to (but more efficient than)
+ * `(c takeWhile p, c dropWhile p)`, provided the evaluation of the
+ * predicate `p` does not cause any side-effects.
+ *
+ * @param p the test predicate
+ * @return a pair consisting of the longest prefix of this array whose
+ * elements all satisfy `p`, and the rest of this array.
+ */
+ def span(p: A => Boolean): (Array[A], Array[A]) = {
+ val i = indexWhere(x => !p(x))
+ val idx = if(i < 0) xs.length else i
+ (slice(0, idx), slice(idx, xs.length))
+ }
+
+ /** Splits this array into two at a given position.
+ * Note: `c splitAt n` is equivalent to `(c take n, c drop n)`.
+ *
+ * @param n the position at which to split.
+ * @return a pair of arrays consisting of the first `n`
+ * elements of this array, and the other elements.
+ */
+ def splitAt(n: Int): (Array[A], Array[A]) = (take(n), drop(n))
+
+ /** A pair of, first, all elements that satisfy predicate `p` and, second, all elements that do not. */
+ def partition(p: A => Boolean): (Array[A], Array[A]) = {
+ val res1, res2 = ArrayBuilder.make[A]
+ var i = 0
+ while(i < xs.length) {
+ val x = xs(i)
+ (if(p(x)) res1 else res2) += x
+ i += 1
+ }
+ (res1.result(), res2.result())
+ }
+
+ /** Applies a function `f` to each element of the array and returns a pair of arrays: the first one
+ * made of those values returned by `f` that were wrapped in [[scala.util.Left]], and the second
+ * one made of those wrapped in [[scala.util.Right]].
+ *
+ * Example:
+ * {{{
+ * val xs = Array(1, "one", 2, "two", 3, "three") partitionMap {
+ * case i: Int => Left(i)
+ * case s: String => Right(s)
+ * }
+ * // xs == (Array(1, 2, 3),
+ * // Array(one, two, three))
+ * }}}
+ *
+ * @tparam A1 the element type of the first resulting collection
+ * @tparam A2 the element type of the second resulting collection
+ * @param f the 'split function' mapping the elements of this array to an [[scala.util.Either]]
+ *
+ * @return a pair of arrays: the first one made of those values returned by `f` that were wrapped in [[scala.util.Left]],
+ * and the second one made of those wrapped in [[scala.util.Right]]. */
+ def partitionMap[A1: ClassTag, A2: ClassTag](f: A => Either[A1, A2]): (Array[A1], Array[A2]) = {
+ val res1 = ArrayBuilder.make[A1]
+ val res2 = ArrayBuilder.make[A2]
+ var i = 0
+ while(i < xs.length) {
+ f(xs(i)) match {
+ case Left(x) => res1 += x
+ case Right(x) => res2 += x
+ }
+ i += 1
+ }
+ (res1.result(), res2.result())
+ }
+
+ /** Returns a new array with the elements in reversed order. */
+ @inline def reverse: Array[A] = {
+ val len = xs.length
+ val res = new Array[A](len)
+ var i = 0
+ while(i < len) {
+ res(len-i-1) = xs(i)
+ i += 1
+ }
+ res
+ }
+
+ /** An iterator yielding elements in reversed order.
+ *
+ * Note: `xs.reverseIterator` is the same as `xs.reverse.iterator` but implemented more efficiently.
+ *
+ * @return an iterator yielding the elements of this array in reversed order
+ */
+ def reverseIterator: Iterator[A] =
+ ((xs: Any @unchecked) match {
+ case xs: Array[AnyRef] => new ArrayOps.ReverseIterator(xs)
+ case xs: Array[Int] => new ArrayOps.ReverseIterator(xs)
+ case xs: Array[Double] => new ArrayOps.ReverseIterator(xs)
+ case xs: Array[Long] => new ArrayOps.ReverseIterator(xs)
+ case xs: Array[Float] => new ArrayOps.ReverseIterator(xs)
+ case xs: Array[Char] => new ArrayOps.ReverseIterator(xs)
+ case xs: Array[Byte] => new ArrayOps.ReverseIterator(xs)
+ case xs: Array[Short] => new ArrayOps.ReverseIterator(xs)
+ case xs: Array[Boolean] => new ArrayOps.ReverseIterator(xs)
+ case xs: Array[Unit] => new ArrayOps.ReverseIterator(xs)
+ case null => throw new NullPointerException
+ }).asInstanceOf[Iterator[A]]
+
+ /** Selects all elements of this array which satisfy a predicate.
+ *
+ * @param p the predicate used to test elements.
+ * @return a new array consisting of all elements of this array that satisfy the given predicate `p`.
+ */
+ def filter(p: A => Boolean): Array[A] = {
+ val res = ArrayBuilder.make[A]
+ var i = 0
+ while(i < xs.length) {
+ val x = xs(i)
+ if(p(x)) res += x
+ i += 1
+ }
+ res.result()
+ }
+
+ /** Selects all elements of this array which do not satisfy a predicate.
+ *
+ * @param p the predicate used to test elements.
+ * @return a new array consisting of all elements of this array that do not satisfy the given predicate `p`.
+ */
+ def filterNot(p: A => Boolean): Array[A] = filter(x => !p(x))
+
+ /** Sorts this array according to an Ordering.
+ *
+ * The sort is stable. That is, elements that are equal (as determined by
+ * `lt`) appear in the same order in the sorted sequence as in the original.
+ *
+ * @see [[scala.math.Ordering]]
+ *
+ * @param ord the ordering to be used to compare elements.
+ * @return an array consisting of the elements of this array
+ * sorted according to the ordering `ord`.
+ */
+ def sorted[B >: A](implicit ord: Ordering[B]): Array[A] = {
+ val len = xs.length
+ def boxed = if(len < ArrayOps.MaxStableSortLength) {
+ val a = xs.clone()
+ Sorting.stableSort(a)(using ord.asInstanceOf[Ordering[A]])
+ a
+ } else {
+ val a = Array.copyAs[AnyRef](xs, len)(ClassTag.AnyRef)
+ Arrays.sort(a, ord.asInstanceOf[Ordering[AnyRef]])
+ Array.copyAs[A](a, len)
+ }
+ if(len <= 1) xs.clone()
+ else ((xs: Array[_]) match {
+ case xs: Array[AnyRef] =>
+ val a = Arrays.copyOf(xs, len); Arrays.sort(a, ord.asInstanceOf[Ordering[AnyRef]]); a
+ case xs: Array[Int] =>
+ if(ord eq Ordering.Int) { val a = Arrays.copyOf(xs, len); Arrays.sort(a); a }
+ else boxed
+ case xs: Array[Long] =>
+ if(ord eq Ordering.Long) { val a = Arrays.copyOf(xs, len); Arrays.sort(a); a }
+ else boxed
+ case xs: Array[Char] =>
+ if(ord eq Ordering.Char) { val a = Arrays.copyOf(xs, len); Arrays.sort(a); a }
+ else boxed
+ case xs: Array[Byte] =>
+ if(ord eq Ordering.Byte) { val a = Arrays.copyOf(xs, len); Arrays.sort(a); a }
+ else boxed
+ case xs: Array[Short] =>
+ if(ord eq Ordering.Short) { val a = Arrays.copyOf(xs, len); Arrays.sort(a); a }
+ else boxed
+ case xs: Array[Boolean] =>
+ if(ord eq Ordering.Boolean) { val a = Arrays.copyOf(xs, len); Sorting.stableSort(a); a }
+ else boxed
+ case xs => boxed
+ }).asInstanceOf[Array[A]]
+ }
+
+ /** Sorts this array according to a comparison function.
+ *
+ * The sort is stable. That is, elements that are equal (as determined by
+ * `lt`) appear in the same order in the sorted sequence as in the original.
+ *
+ * @param lt the comparison function which tests whether
+ * its first argument precedes its second argument in
+ * the desired ordering.
+ * @return an array consisting of the elements of this array
+ * sorted according to the comparison function `lt`.
+ */
+ def sortWith(lt: (A, A) => Boolean): Array[A] = sorted(Ordering.fromLessThan(lt))
+
+ /** Sorts this array according to the Ordering which results from transforming
+ * an implicitly given Ordering with a transformation function.
+ *
+ * @see [[scala.math.Ordering]]
+ * @param f the transformation function mapping elements
+ * to some other domain `B`.
+ * @param ord the ordering assumed on domain `B`.
+ * @tparam B the target type of the transformation `f`, and the type where
+ * the ordering `ord` is defined.
+ * @return an array consisting of the elements of this array
+ * sorted according to the ordering where `x < y` if
+ * `ord.lt(f(x), f(y))`.
+ */
+ def sortBy[B](f: A => B)(implicit ord: Ordering[B]): Array[A] = sorted(ord on f)
+
+ /** Creates a non-strict filter of this array.
+ *
+ * Note: the difference between `c filter p` and `c withFilter p` is that
+ * the former creates a new array, whereas the latter only
+ * restricts the domain of subsequent `map`, `flatMap`, `foreach`,
+ * and `withFilter` operations.
+ *
+ * @param p the predicate used to test elements.
+ * @return an object of class `ArrayOps.WithFilter`, which supports
+ * `map`, `flatMap`, `foreach`, and `withFilter` operations.
+ * All these operations apply to those elements of this array
+ * which satisfy the predicate `p`.
+ */
+ def withFilter(p: A => Boolean): ArrayOps.WithFilter[A] = new ArrayOps.WithFilter[A](p, xs)
+
+ /** Finds index of first occurrence of some value in this array after or at some start index.
+ *
+ * @param elem the element value to search for.
+ * @param from the start index
+ * @return the index `>= from` of the first element of this array that is equal (as determined by `==`)
+ * to `elem`, or `-1`, if none exists.
+ */
+ def indexOf(elem: A, from: Int = 0): Int = {
+ var i = from
+ while(i < xs.length) {
+ if(elem == xs(i)) return i
+ i += 1
+ }
+ -1
+ }
+
+ /** Finds index of the first element satisfying some predicate after or at some start index.
+ *
+ * @param p the predicate used to test elements.
+ * @param from the start index
+ * @return the index `>= from` of the first element of this array that satisfies the predicate `p`,
+ * or `-1`, if none exists.
+ */
+ def indexWhere(@deprecatedName("f", "2.13.3") p: A => Boolean, from: Int = 0): Int = {
+ var i = from
+ while(i < xs.length) {
+ if(p(xs(i))) return i
+ i += 1
+ }
+ -1
+ }
+
+ /** Finds index of last occurrence of some value in this array before or at a given end index.
+ *
+ * @param elem the element value to search for.
+ * @param end the end index.
+ * @return the index `<= end` of the last element of this array that is equal (as determined by `==`)
+ * to `elem`, or `-1`, if none exists.
+ */
+ def lastIndexOf(elem: A, end: Int = xs.length - 1): Int = {
+ var i = min(end, xs.length-1)
+ while(i >= 0) {
+ if(elem == xs(i)) return i
+ i -= 1
+ }
+ -1
+ }
+
+ /** Finds index of last element satisfying some predicate before or at given end index.
+ *
+ * @param p the predicate used to test elements.
+ * @return the index `<= end` of the last element of this array that satisfies the predicate `p`,
+ * or `-1`, if none exists.
+ */
+ def lastIndexWhere(p: A => Boolean, end: Int = xs.length - 1): Int = {
+ var i = min(end, xs.length-1)
+ while(i >= 0) {
+ if(p(xs(i))) return i
+ i -= 1
+ }
+ -1
+ }
+
+ /** Finds the first element of the array satisfying a predicate, if any.
+ *
+ * @param p the predicate used to test elements.
+ * @return an option value containing the first element in the array
+ * that satisfies `p`, or `None` if none exists.
+ */
+ def find(@deprecatedName("f", "2.13.3") p: A => Boolean): Option[A] = {
+ val idx = indexWhere(p)
+ if(idx == -1) None else Some(xs(idx))
+ }
+
+ /** Tests whether a predicate holds for at least one element of this array.
+ *
+ * @param p the predicate used to test elements.
+ * @return `true` if the given predicate `p` is satisfied by at least one element of this array, otherwise `false`
+ */
+ def exists(@deprecatedName("f", "2.13.3") p: A => Boolean): Boolean = indexWhere(p) >= 0
+
+ /** Tests whether a predicate holds for all elements of this array.
+ *
+ * @param p the predicate used to test elements.
+ * @return `true` if this array is empty or the given predicate `p`
+ * holds for all elements of this array, otherwise `false`.
+ */
+ def forall(@deprecatedName("f", "2.13.3") p: A => Boolean): Boolean = {
+ var i = 0
+ while(i < xs.length) {
+ if(!p(xs(i))) return false
+ i += 1
+ }
+ true
+ }
+
+ /** 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
+ var v: Any = z
+ var i = 0
+ while(i < length) {
+ v = op(v, xs(i))
+ i += 1
+ }
+ v
+ }
+ ((xs: Any @unchecked) match {
+ case null => throw new NullPointerException // null-check first helps static analysis of instanceOf
+ case xs: Array[AnyRef] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Int] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Double] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Long] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Float] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Char] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Byte] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Short] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Boolean] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Unit] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ }).asInstanceOf[B]
+ }
+
+ /** Produces an array containing cumulative results of applying the binary
+ * operator going left to right.
+ *
+ * @param z the start value.
+ * @param op the binary operator.
+ * @tparam B the result type of the binary operator.
+ * @return array with intermediate values.
+ *
+ * Example:
+ * {{{
+ * Array(1, 2, 3, 4).scanLeft(0)(_ + _) == Array(0, 1, 3, 6, 10)
+ * }}}
+ *
+ */
+ def scanLeft[ B : ClassTag ](z: B)(op: (B, A) => B): Array[B] = {
+ var v = z
+ var i = 0
+ val res = new Array[B](xs.length + 1)
+ while(i < xs.length) {
+ res(i) = v
+ v = op(v, xs(i))
+ i += 1
+ }
+ res(i) = v
+ res
+ }
+
+ /** Computes a prefix scan of the elements of the array.
+ *
+ * Note: The neutral element `z` may be applied more than once.
+ *
+ * @tparam B element type of the resulting array
+ * @param z neutral element for the operator `op`
+ * @param op the associative operator for the scan
+ *
+ * @return a new array containing the prefix scan of the elements in this array
+ */
+ def scan[B >: A : ClassTag](z: B)(op: (B, B) => B): Array[B] = scanLeft(z)(op)
+
+ /** Produces an array containing cumulative results of applying the binary
+ * operator going right to left.
+ *
+ * @param z the start value.
+ * @param op the binary operator.
+ * @tparam B the result type of the binary operator.
+ * @return array with intermediate values.
+ *
+ * Example:
+ * {{{
+ * Array(4, 3, 2, 1).scanRight(0)(_ + _) == Array(10, 6, 3, 1, 0)
+ * }}}
+ *
+ */
+ def scanRight[ B : ClassTag ](z: B)(op: (A, B) => B): Array[B] = {
+ var v = z
+ var i = xs.length - 1
+ val res = new Array[B](xs.length + 1)
+ res(xs.length) = z
+ while(i >= 0) {
+ v = op(xs(i), v)
+ res(i) = v
+ i -= 1
+ }
+ res
+ }
+
+ /** 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
+ var i = xs.length - 1
+ while(i >= 0) {
+ v = op(xs(i), v)
+ i -= 1
+ }
+ v
+ }
+ ((xs: Any @unchecked) match {
+ case null => throw new NullPointerException
+ case xs: Array[AnyRef] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Int] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Double] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Long] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Float] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Char] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Byte] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Short] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Boolean] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ case xs: Array[Unit] => f(xs, op.asInstanceOf[(Any, Any) => Any], z)
+ }).asInstanceOf[B]
+
+ }
+
+ /** 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.
+ *
+ * @param f the function to apply to each element.
+ * @tparam B the element type of the returned array.
+ * @return a new array resulting from applying the given function
+ * `f` to each element of this array and collecting the results.
+ */
+ def map[B](f: A => B)(implicit ct: ClassTag[B]): Array[B] = {
+ val len = xs.length
+ val ys = new Array[B](len)
+ if(len > 0) {
+ var i = 0
+ (xs: Any @unchecked) match {
+ case xs: Array[AnyRef] => while (i < len) { ys(i) = f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Int] => while (i < len) { ys(i) = f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Double] => while (i < len) { ys(i) = f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Long] => while (i < len) { ys(i) = f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Float] => while (i < len) { ys(i) = f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Char] => while (i < len) { ys(i) = f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Byte] => while (i < len) { ys(i) = f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Short] => while (i < len) { ys(i) = f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Boolean] => while (i < len) { ys(i) = f(xs(i).asInstanceOf[A]); i = i+1 }
+ }
+ }
+ ys
+ }
+
+ def mapInPlace(f: A => A): Array[A] = {
+ var i = 0
+ while (i < xs.length) {
+ xs.update(i, f(xs(i)))
+ i = i + 1
+ }
+ xs
+ }
+
+ /** Builds a new array by applying a function to all elements of this array
+ * and using the elements of the resulting collections.
+ *
+ * @param f the function to apply to each element.
+ * @tparam B the element type of the returned array.
+ * @return a new array resulting from applying the given collection-valued function
+ * `f` to each element of this array and concatenating the results.
+ */
+ def flatMap[B : ClassTag](f: A => IterableOnce[B]): Array[B] = {
+ val b = ArrayBuilder.make[B]
+ var i = 0
+ while(i < xs.length) {
+ b ++= f(xs(i))
+ i += 1
+ }
+ b.result()
+ }
+
+ def flatMap[BS, B](f: A => BS)(implicit asIterable: BS => Iterable[B], m: ClassTag[B]): Array[B] =
+ flatMap[B](x => asIterable(f(x)))
+
+ /** Flattens a two-dimensional array by concatenating all its rows
+ * into a single array.
+ *
+ * @tparam B Type of row elements.
+ * @param asIterable A function that converts elements of this array to rows - Iterables of type `B`.
+ * @return An array obtained by concatenating rows of this array.
+ */
+ def flatten[B](implicit asIterable: A => IterableOnce[B], m: ClassTag[B]): Array[B] = {
+ val b = ArrayBuilder.make[B]
+ val len = xs.length
+ var size = 0
+ var i = 0
+ while(i < len) {
+ xs(i) match {
+ case it: IterableOnce[_] =>
+ val k = it.knownSize
+ if(k > 0) size += k
+ case a: Array[_] => size += a.length
+ case _ =>
+ }
+ i += 1
+ }
+ if(size > 0) b.sizeHint(size)
+ i = 0
+ while(i < len) {
+ b ++= asIterable(xs(i))
+ i += 1
+ }
+ b.result()
+ }
+
+ /** Builds a new array by applying a partial function to all elements of this array
+ * on which the function is defined.
+ *
+ * @param pf the partial function which filters and maps the array.
+ * @tparam B the element type of the returned array.
+ * @return a new array resulting from applying the given partial function
+ * `pf` to each element on which it is defined and collecting the results.
+ * The order of the elements is preserved.
+ */
+ def collect[B: ClassTag](pf: PartialFunction[A, B]): Array[B] = {
+ val fallback: Any => Any = ArrayOps.fallback
+ val b = ArrayBuilder.make[B]
+ var i = 0
+ while (i < xs.length) {
+ val v = pf.applyOrElse(xs(i), fallback)
+ if (v.asInstanceOf[AnyRef] ne fallback) b.addOne(v.asInstanceOf[B])
+ i += 1
+ }
+ b.result()
+ }
+
+ /** Finds the first element of the array for which the given partial function is defined, and applies the
+ * partial function to it. */
+ def collectFirst[B](@deprecatedName("f","2.13.9") pf: PartialFunction[A, B]): Option[B] = {
+ val fallback: Any => Any = ArrayOps.fallback
+ var i = 0
+ while (i < xs.length) {
+ val v = pf.applyOrElse(xs(i), fallback)
+ if (v.asInstanceOf[AnyRef] ne fallback) return Some(v.asInstanceOf[B])
+ i += 1
+ }
+ None
+ }
+
+ /** Returns an array formed from this array and another iterable collection
+ * by combining corresponding elements in pairs.
+ * If one of the two collections is longer than the other, its remaining elements are ignored.
+ *
+ * @param that The iterable providing the second half of each result pair
+ * @tparam B the type of the second half of the returned pairs
+ * @return a new array containing pairs consisting of corresponding elements of this array and `that`.
+ * The length of the returned array is the minimum of the lengths of this array and `that`.
+ */
+ def zip[B](that: IterableOnce[B]): Array[(A, B)] = {
+ val b = new ArrayBuilder.ofRef[(A, B)]()
+ val k = that.knownSize
+ b.sizeHint(if(k >= 0) min(k, xs.length) else xs.length)
+ var i = 0
+ val it = that.iterator
+ while(i < xs.length && it.hasNext) {
+ b += ((xs(i), it.next()))
+ i += 1
+ }
+ b.result()
+ }
+
+ /** Analogous to `zip` except that the elements in each collection are not consumed until a strict operation is
+ * invoked on the returned `LazyZip2` decorator.
+ *
+ * Calls to `lazyZip` can be chained to support higher arities (up to 4) without incurring the expense of
+ * constructing and deconstructing intermediary tuples.
+ *
+ * {{{
+ * val xs = List(1, 2, 3)
+ * val res = (xs lazyZip xs lazyZip xs lazyZip xs).map((a, b, c, d) => a + b + c + d)
+ * // res == List(4, 8, 12)
+ * }}}
+ *
+ * @param that the iterable providing the second element of each eventual pair
+ * @tparam B the type of the second element in each eventual pair
+ * @return a decorator `LazyZip2` that allows strict operations to be performed on the lazily evaluated pairs
+ * or chained calls to `lazyZip`. Implicit conversion to `Iterable[(A, B)]` is also supported.
+ */
+ def lazyZip[B](that: Iterable[B]): LazyZip2[A, B, Array[A]] = new LazyZip2(xs, immutable.ArraySeq.unsafeWrapArray(xs), that)
+
+ /** Returns an array formed from this array and another iterable collection
+ * by combining corresponding elements in pairs.
+ * If one of the two collections is shorter than the other,
+ * placeholder elements are used to extend the shorter collection to the length of the longer.
+ *
+ * @param that the iterable providing the second half of each result pair
+ * @param thisElem the element to be used to fill up the result if this array is shorter than `that`.
+ * @param thatElem the element to be used to fill up the result if `that` is shorter than this array.
+ * @return a new array containing pairs consisting of corresponding elements of this array and `that`.
+ * The length of the returned array is the maximum of the lengths of this array and `that`.
+ * If this array is shorter than `that`, `thisElem` values are used to pad the result.
+ * If `that` is shorter than this array, `thatElem` values are used to pad the result.
+ */
+ def zipAll[A1 >: A, B](that: Iterable[B], thisElem: A1, thatElem: B): Array[(A1, B)] = {
+ val b = new ArrayBuilder.ofRef[(A1, B)]()
+ val k = that.knownSize
+ b.sizeHint(max(k, xs.length))
+ var i = 0
+ val it = that.iterator
+ while(i < xs.length && it.hasNext) {
+ b += ((xs(i), it.next()))
+ i += 1
+ }
+ while(it.hasNext) {
+ b += ((thisElem, it.next()))
+ i += 1
+ }
+ while(i < xs.length) {
+ b += ((xs(i), thatElem))
+ i += 1
+ }
+ b.result()
+ }
+
+ /** Zips this array with its indices.
+ *
+ * @return A new array containing pairs consisting of all elements of this array paired with their index.
+ * Indices start at `0`.
+ */
+ def zipWithIndex: Array[(A, Int)] = {
+ val b = new Array[(A, Int)](xs.length)
+ var i = 0
+ while(i < xs.length) {
+ b(i) = ((xs(i), i))
+ i += 1
+ }
+ b
+ }
+
+ /** A copy of this array with an element appended. */
+ def appended[B >: A : ClassTag](x: B): Array[B] = {
+ val dest = Array.copyAs[B](xs, xs.length+1)
+ dest(xs.length) = x
+ dest
+ }
+
+ @`inline` final def :+ [B >: A : ClassTag](x: B): Array[B] = appended(x)
+
+ /** A copy of this array with an element prepended. */
+ def prepended[B >: A : ClassTag](x: B): Array[B] = {
+ val dest = new Array[B](xs.length + 1)
+ dest(0) = x
+ Array.copy(xs, 0, dest, 1, xs.length)
+ dest
+ }
+
+ @`inline` final def +: [B >: A : ClassTag](x: B): Array[B] = prepended(x)
+
+ /** A copy of this array with all elements of a collection prepended. */
+ def prependedAll[B >: A : ClassTag](prefix: IterableOnce[B]): Array[B] = {
+ val b = ArrayBuilder.make[B]
+ val k = prefix.knownSize
+ if(k >= 0) b.sizeHint(k + xs.length)
+ b.addAll(prefix)
+ if(k < 0) b.sizeHint(b.length + xs.length)
+ b.addAll(xs)
+ b.result()
+ }
+
+ /** A copy of this array with all elements of an array prepended. */
+ def prependedAll[B >: A : ClassTag](prefix: Array[_ <: B]): Array[B] = {
+ val dest = Array.copyAs[B](prefix, prefix.length+xs.length)
+ Array.copy(xs, 0, dest, prefix.length, xs.length)
+ dest
+ }
+
+ @`inline` final def ++: [B >: A : ClassTag](prefix: IterableOnce[B]): Array[B] = prependedAll(prefix)
+
+ @`inline` final def ++: [B >: A : ClassTag](prefix: Array[_ <: B]): Array[B] = prependedAll(prefix)
+
+ /** 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]
+ b.sizeHint(suffix, delta = xs.length)
+ b.addAll(xs)
+ b.addAll(suffix)
+ b.result()
+ }
+
+ /** A copy of this array with all elements of an array appended. */
+ def appendedAll[B >: A : ClassTag](suffix: Array[_ <: B]): Array[B] = {
+ val dest = Array.copyAs[B](xs, xs.length+suffix.length)
+ Array.copy(suffix, 0, dest, xs.length, suffix.length)
+ dest
+ }
+
+ @`inline` final def :++ [B >: A : ClassTag](suffix: IterableOnce[B]): Array[B] = appendedAll(suffix)
+
+ @`inline` final def :++ [B >: A : ClassTag](suffix: Array[_ <: B]): Array[B] = appendedAll(suffix)
+
+ @`inline` final def concat[B >: A : ClassTag](suffix: IterableOnce[B]): Array[B] = appendedAll(suffix)
+
+ @`inline` final def concat[B >: A : ClassTag](suffix: Array[_ <: B]): Array[B] = appendedAll(suffix)
+
+ @`inline` final def ++[B >: A : ClassTag](xs: IterableOnce[B]): Array[B] = appendedAll(xs)
+
+ @`inline` final def ++[B >: A : ClassTag](xs: Array[_ <: B]): Array[B] = appendedAll(xs)
+
+ /** Tests whether this array contains a given value as an element.
+ *
+ * @param elem the element to test.
+ * @return `true` if this array has an element that is equal (as
+ * determined by `==`) to `elem`, `false` otherwise.
+ */
+ def contains(elem: A): Boolean = exists (_ == elem)
+
+ /** Returns a copy of this array with patched values.
+ * Patching at negative indices is the same as patching starting at 0.
+ * Patching at indices at or larger than the length of the original array appends the patch to the end.
+ * If more values are replaced than actually exist, the excess is ignored.
+ *
+ * @param from The start index from which to patch
+ * @param other The patch values
+ * @param replaced The number of values in the original array that are replaced by the patch.
+ */
+ def patch[B >: A : ClassTag](from: Int, other: IterableOnce[B], replaced: Int): Array[B] = {
+ val b = ArrayBuilder.make[B]
+ val k = other.knownSize
+ val r = if(replaced < 0) 0 else replaced
+ if(k >= 0) b.sizeHint(xs.length + k - r)
+ val chunk1 = if(from > 0) min(from, xs.length) else 0
+ if(chunk1 > 0) b.addAll(xs, 0, chunk1)
+ b ++= other
+ val remaining = xs.length - chunk1 - r
+ if(remaining > 0) b.addAll(xs, xs.length - remaining, remaining)
+ b.result()
+ }
+
+ /** Converts an array of pairs into an array of first elements and an array of second elements.
+ *
+ * @tparam A1 the type of the first half of the element pairs
+ * @tparam A2 the type of the second half of the element pairs
+ * @param asPair an implicit conversion which asserts that the element type
+ * of this Array is a pair.
+ * @param ct1 a class tag for `A1` type parameter that is required to create an instance
+ * of `Array[A1]`
+ * @param ct2 a class tag for `A2` type parameter that is required to create an instance
+ * of `Array[A2]`
+ * @return a pair of Arrays, containing, respectively, the first and second half
+ * of each element pair of this Array.
+ */
+ def unzip[A1, A2](implicit asPair: A => (A1, A2), ct1: ClassTag[A1], ct2: ClassTag[A2]): (Array[A1], Array[A2]) = {
+ val a1 = new Array[A1](xs.length)
+ val a2 = new Array[A2](xs.length)
+ var i = 0
+ while (i < xs.length) {
+ val e = asPair(xs(i))
+ a1(i) = e._1
+ a2(i) = e._2
+ i += 1
+ }
+ (a1, a2)
+ }
+
+ /** Converts an array of triples into three arrays, one containing the elements from each position of the triple.
+ *
+ * @tparam A1 the type of the first of three elements in the triple
+ * @tparam A2 the type of the second of three elements in the triple
+ * @tparam A3 the type of the third of three elements in the triple
+ * @param asTriple an implicit conversion which asserts that the element type
+ * of this Array is a triple.
+ * @param ct1 a class tag for T1 type parameter that is required to create an instance
+ * of Array[T1]
+ * @param ct2 a class tag for T2 type parameter that is required to create an instance
+ * of Array[T2]
+ * @param ct3 a class tag for T3 type parameter that is required to create an instance
+ * of Array[T3]
+ * @return a triple of Arrays, containing, respectively, the first, second, and third
+ * elements from each element triple of this Array.
+ */
+ def unzip3[A1, A2, A3](implicit asTriple: A => (A1, A2, A3), ct1: ClassTag[A1], ct2: ClassTag[A2],
+ ct3: ClassTag[A3]): (Array[A1], Array[A2], Array[A3]) = {
+ val a1 = new Array[A1](xs.length)
+ val a2 = new Array[A2](xs.length)
+ val a3 = new Array[A3](xs.length)
+ var i = 0
+ while (i < xs.length) {
+ val e = asTriple(xs(i))
+ a1(i) = e._1
+ a2(i) = e._2
+ a3(i) = e._3
+ i += 1
+ }
+ (a1, a2, a3)
+ }
+
+ /** Transposes a two dimensional array.
+ *
+ * @tparam B Type of row elements.
+ * @param asArray A function that converts elements of this array to rows - arrays of type `B`.
+ * @return An array obtained by replacing elements of this arrays with rows the represent.
+ */
+ def transpose[B](implicit asArray: A => Array[B]): Array[Array[B]] = {
+ val aClass = xs.getClass.getComponentType
+ val bb = new ArrayBuilder.ofRef[Array[B]]()(ClassTag[Array[B]](aClass))
+ if (xs.length == 0) bb.result()
+ else {
+ def mkRowBuilder() = ArrayBuilder.make[B](using ClassTag[B](aClass.getComponentType))
+ val bs = new ArrayOps(asArray(xs(0))).map((x: B) => mkRowBuilder())
+ for (xs <- this) {
+ var i = 0
+ for (x <- new ArrayOps(asArray(xs))) {
+ bs(i) += x
+ i += 1
+ }
+ }
+ for (b <- new ArrayOps(bs)) bb += b.result()
+ bb.result()
+ }
+ }
+
+ /** Apply `f` to each element for its side effects.
+ * Note: [U] parameter needed to help scalac's type inference.
+ */
+ def foreach[U](f: A => U): Unit = {
+ val len = xs.length
+ var i = 0
+ (xs: Any @unchecked) match {
+ case xs: Array[AnyRef] => while (i < len) { f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Int] => while (i < len) { f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Double] => while (i < len) { f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Long] => while (i < len) { f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Float] => while (i < len) { f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Char] => while (i < len) { f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Byte] => while (i < len) { f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Short] => while (i < len) { f(xs(i).asInstanceOf[A]); i = i+1 }
+ case xs: Array[Boolean] => while (i < len) { f(xs(i).asInstanceOf[A]); i = i+1 }
+ }
+ }
+
+ /** Selects all the elements of this array ignoring the duplicates.
+ *
+ * @return a new array consisting of all the elements of this array without duplicates.
+ */
+ def distinct: Array[A] = distinctBy(identity)
+
+ /** Selects all the elements of this array ignoring the duplicates as determined by `==` after applying
+ * the transforming function `f`.
+ *
+ * @param f The transforming function whose result is used to determine the uniqueness of each element
+ * @tparam B the type of the elements after being transformed by `f`
+ * @return a new array consisting of all the elements of this array without duplicates.
+ */
+ def distinctBy[B](f: A => B): Array[A] =
+ ArrayBuilder.make[A].addAll(iterator.distinctBy(f)).result()
+
+ /** A copy of this array with an element value appended until a given target length is reached.
+ *
+ * @param len the target length
+ * @param elem the padding value
+ * @tparam B the element type of the returned array.
+ * @return a new array consisting of
+ * all elements of this array followed by the minimal number of occurrences of `elem` so
+ * that the resulting collection has a length of at least `len`.
+ */
+ def padTo[B >: A : ClassTag](len: Int, elem: B): Array[B] = {
+ var i = xs.length
+ val newlen = max(i, len)
+ val dest = Array.copyAs[B](xs, newlen)
+ while(i < newlen) {
+ dest(i) = elem
+ i += 1
+ }
+ dest
+ }
+
+ /** Produces the range of all indices of this sequence.
+ *
+ * @return a `Range` value from `0` to one less than the length of this array.
+ */
+ def indices: Range = Range(0, xs.length)
+
+ /** Partitions this array into a map of arrays according to some discriminator function.
+ *
+ * @param f the discriminator function.
+ * @tparam K the type of keys returned by the discriminator function.
+ * @return A map from keys to arrays such that the following invariant holds:
+ * {{{
+ * (xs groupBy f)(k) = xs filter (x => f(x) == k)
+ * }}}
+ * That is, every key `k` is bound to an array of those elements `x`
+ * for which `f(x)` equals `k`.
+ */
+ def groupBy[K](f: A => K): immutable.Map[K, Array[A]] = {
+ val m = mutable.Map.empty[K, ArrayBuilder[A]]
+ val len = xs.length
+ var i = 0
+ while(i < len) {
+ val elem = xs(i)
+ val key = f(elem)
+ val bldr = m.getOrElseUpdate(key, ArrayBuilder.make[A])
+ bldr += elem
+ i += 1
+ }
+ m.view.mapValues(_.result()).toMap
+ }
+
+ /**
+ * Partitions this array into a map of arrays according to a discriminator function `key`.
+ * Each element in a group is transformed into a value of type `B` using the `value` function.
+ *
+ * It is equivalent to `groupBy(key).mapValues(_.map(f))`, but more efficient.
+ *
+ * {{{
+ * case class User(name: String, age: Int)
+ *
+ * def namesByAge(users: Array[User]): Map[Int, Array[String]] =
+ * users.groupMap(_.age)(_.name)
+ * }}}
+ *
+ * @param key the discriminator function
+ * @param f the element transformation function
+ * @tparam K the type of keys returned by the discriminator function
+ * @tparam B the type of values returned by the transformation function
+ */
+ def groupMap[K, B : ClassTag](key: A => K)(f: A => B): immutable.Map[K, Array[B]] = {
+ val m = mutable.Map.empty[K, ArrayBuilder[B]]
+ val len = xs.length
+ var i = 0
+ while(i < len) {
+ val elem = xs(i)
+ val k = key(elem)
+ val bldr = m.getOrElseUpdate(k, ArrayBuilder.make[B])
+ bldr += f(elem)
+ i += 1
+ }
+ m.view.mapValues(_.result()).toMap
+ }
+
+ @`inline` final def toSeq: immutable.Seq[A] = toIndexedSeq
+
+ def toIndexedSeq: immutable.IndexedSeq[A] =
+ immutable.ArraySeq.unsafeWrapArray(Array.copyOf(xs, xs.length))
+
+ /** Copy elements of this array to another array.
+ * Fills the given array `xs` starting at index 0.
+ * Copying will stop once either all the elements of this array have been copied,
+ * or the end of the array is reached.
+ *
+ * @param xs the array to fill.
+ * @tparam B the type of the elements of the array.
+ */
+ def copyToArray[B >: A](xs: Array[B]): Int = copyToArray(xs, 0)
+
+ /** Copy elements of this array to another array.
+ * Fills the given array `xs` starting at index `start`.
+ * Copying will stop once either all the elements of this array have been copied,
+ * or the end of the array is reached.
+ *
+ * @param xs the array to fill.
+ * @param start the starting index within the destination array.
+ * @tparam B the type of the elements of the array.
+ */
+ def copyToArray[B >: A](xs: Array[B], start: Int): Int = copyToArray(xs, start, Int.MaxValue)
+
+ /** Copy elements of this array to another array.
+ * Fills the given array `xs` starting at index `start` with at most `len` values.
+ * Copying will stop once either all the elements of this array have been copied,
+ * or the end of the array is reached, or `len` elements have been copied.
+ *
+ * @param xs the array to fill.
+ * @param start the starting index within the destination array.
+ * @param len the maximal number of elements to copy.
+ * @tparam B the type of the elements of the array.
+ */
+ def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = {
+ val copied = IterableOnce.elemsToCopyToArray(this.xs.length, xs.length, start, len)
+ if (copied > 0) {
+ Array.copy(this.xs, 0, xs, start, copied)
+ }
+ copied
+ }
+
+ /** Create a copy of this array with the specified element type. */
+ def toArray[B >: A: ClassTag]: Array[B] = {
+ val destination = new Array[B](xs.length)
+ @annotation.unused val copied = copyToArray(destination, 0)
+ //assert(copied == xs.length)
+ destination
+ }
+
+ /** Counts the number of elements in this array which satisfy a predicate */
+ def count(p: A => Boolean): Int = {
+ var i, res = 0
+ val len = xs.length
+ while(i < len) {
+ if(p(xs(i))) res += 1
+ i += 1
+ }
+ res
+ }
+
+ // can't use a default arg because we already have another overload with a default arg
+ /** Tests whether this array starts with the given array. */
+ @`inline` def startsWith[B >: A](that: Array[B]): Boolean = startsWith(that, 0)
+
+ /** Tests whether this array contains the given array at a given index.
+ *
+ * @param that the array to test
+ * @param offset the index where the array is searched.
+ * @return `true` if the array `that` is contained in this array at
+ * index `offset`, otherwise `false`.
+ */
+ def startsWith[B >: A](that: Array[B], offset: Int): Boolean = {
+ val safeOffset = offset.max(0)
+ val thatl = that.length
+ if(thatl > xs.length-safeOffset) thatl == 0
+ else {
+ var i = 0
+ while(i < thatl) {
+ if(xs(i+safeOffset) != that(i)) return false
+ i += 1
+ }
+ true
+ }
+ }
+
+ /** Tests whether this array ends with the given array.
+ *
+ * @param that the array to test
+ * @return `true` if this array has `that` as a suffix, `false` otherwise.
+ */
+ def endsWith[B >: A](that: Array[B]): Boolean = {
+ val thatl = that.length
+ val off = xs.length - thatl
+ if(off < 0) false
+ else {
+ var i = 0
+ while(i < thatl) {
+ if(xs(i+off) != that(i)) return false
+ i += 1
+ }
+ true
+ }
+ }
+
+ /** A copy of this array with one single replaced element.
+ * @param index the position of the replacement
+ * @param elem the replacing element
+ * @return a new array which is a copy of this array with the element at position `index` replaced by `elem`.
+ * @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 CommonErrors.indexOutOfBounds(index = index, max = xs.length-1)
+ val dest = toArray[B]
+ dest(index) = elem
+ dest
+ }
+
+ @`inline` def view: IndexedSeqView[A] = new ArrayOps.ArrayView[A](xs)
+
+
+ /* ************************************************************************************************************
+ The remaining methods are provided for completeness but they delegate to mutable.ArraySeq implementations which
+ may not provide the best possible performance. We need them in `ArrayOps` because their return type
+ mentions `C` (which is `Array[A]` in `StringOps` and `mutable.ArraySeq[A]` in `mutable.ArraySeq`).
+ ************************************************************************************************************ */
+
+
+ /** Computes the multiset difference between this array and another sequence.
+ *
+ * @param that the sequence of elements to remove
+ * @return a new array which contains all elements of this array
+ * except some of occurrences of elements that also appear in `that`.
+ * If an element value `x` appears
+ * ''n'' times in `that`, then the first ''n'' occurrences of `x` will not form
+ * part of the result, but any following occurrences will.
+ */
+ def diff[B >: A](that: Seq[B]): Array[A] = mutable.ArraySeq.make(xs).diff(that).toArray[A]
+
+ /** Computes the multiset intersection between this array and another sequence.
+ *
+ * @param that the sequence of elements to intersect with.
+ * @return a new array which contains all elements of this array
+ * which also appear in `that`.
+ * If an element value `x` appears
+ * ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained
+ * in the result, but any following occurrences will be omitted.
+ */
+ def intersect[B >: A](that: Seq[B]): Array[A] = mutable.ArraySeq.make(xs).intersect(that).toArray[A]
+
+ /** Groups elements in fixed size blocks by passing a "sliding window"
+ * over them (as opposed to partitioning them, as is done in grouped.)
+ * @see [[scala.collection.Iterator]], method `sliding`
+ *
+ * @param size the number of elements per group
+ * @param step the distance between the first elements of successive groups
+ * @return An iterator producing arrays of size `size`, except the
+ * last element (which may be the only element) will be truncated
+ * if there are fewer than `size` elements remaining to be grouped.
+ */
+ def sliding(size: Int, step: Int = 1): Iterator[Array[A]] = mutable.ArraySeq.make(xs).sliding(size, step).map(_.toArray[A])
+
+ /** Iterates over combinations of elements.
+ *
+ * A '''combination''' of length `n` is a sequence of `n` elements selected in order of their first index in this sequence.
+ *
+ * For example, `"xyx"` has two combinations of length 2. The `x` is selected first: `"xx"`, `"xy"`.
+ * The sequence `"yx"` is not returned as a combination because it is subsumed by `"xy"`.
+ *
+ * If there is more than one way to generate the same combination, only one will be returned.
+ *
+ * For example, the result `"xy"` arbitrarily selected one of the `x` elements.
+ *
+ * As a further illustration, `"xyxx"` has three different ways to generate `"xy"` because there are three elements `x`
+ * to choose from. Moreover, there are three unordered pairs `"xx"` but only one is returned.
+ *
+ * It is not specified which of these equal combinations is returned. It is an implementation detail
+ * that should not be relied on. For example, the combination `"xx"` does not necessarily contain
+ * the first `x` in this sequence. This behavior is observable if the elements compare equal
+ * but are not identical.
+ *
+ * As a consequence, `"xyx".combinations(3).next()` is `"xxy"`: the combination does not reflect the order
+ * of the original sequence, but the order in which elements were selected, by "first index";
+ * the order of each `x` element is also arbitrary.
+ *
+ * @return An Iterator which traverses the n-element combinations of this array
+ * @example {{{
+ * Array('a', 'b', 'b', 'b', 'c').combinations(2).map(runtime.ScalaRunTime.stringOf).foreach(println)
+ * // Array(a, b)
+ * // Array(a, c)
+ * // Array(b, b)
+ * // Array(b, c)
+ * Array('b', 'a', 'b').combinations(2).map(runtime.ScalaRunTime.stringOf).foreach(println)
+ * // Array(b, b)
+ * // Array(b, a)
+ * }}}
+ */
+ def combinations(n: Int): Iterator[Array[A]] = mutable.ArraySeq.make(xs).combinations(n).map(_.toArray[A])
+
+ /** Iterates over distinct permutations of elements.
+ *
+ * @return An Iterator which traverses the distinct permutations of this array.
+ * @example {{{
+ * Array('a', 'b', 'b').permutations.map(runtime.ScalaRunTime.stringOf).foreach(println)
+ * // Array(a, b, b)
+ * // Array(b, a, b)
+ * // Array(b, b, a)
+ * }}}
+ */
+ def permutations: Iterator[Array[A]] = mutable.ArraySeq.make(xs).permutations.map(_.toArray[A])
+
+ // we have another overload here, so we need to duplicate this method
+ /** Tests whether this array contains the given sequence at a given index.
+ *
+ * @param that the sequence to test
+ * @param offset the index where the sequence is searched.
+ * @return `true` if the sequence `that` is contained in this array at
+ * index `offset`, otherwise `false`.
+ */
+ def startsWith[B >: A](that: IterableOnce[B], offset: Int = 0): Boolean = mutable.ArraySeq.make(xs).startsWith(that, offset)
+
+ // we have another overload here, so we need to duplicate this method
+ /** Tests whether this array ends with the given sequence.
+ *
+ * @param that the sequence to test
+ * @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)
+}
diff --git a/library/src/scala/collection/BitSet.scala b/library/src/scala/collection/BitSet.scala
new file mode 100644
index 000000000000..a2da58ea3b9b
--- /dev/null
+++ b/library/src/scala/collection/BitSet.scala
@@ -0,0 +1,348 @@
+/*
+ * 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 collection
+
+import java.io.{ObjectInputStream, ObjectOutputStream}
+
+import scala.annotation.nowarn
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.mutable.Builder
+
+
+/** Base type of bitsets.
+ *
+ * This trait provides most of the operations of a `BitSet` independently of its representation.
+ * It is inherited by all concrete implementations of bitsets.
+ *
+ * @define bitsetinfo
+ * Bitsets are sets of non-negative integers which are represented as
+ * variable-size arrays of bits packed into 64-bit words. The lower bound of memory footprint of a bitset is
+ * determined by the largest number stored in it.
+ * @define coll bitset
+ * @define Coll `BitSet`
+ */
+trait BitSet extends SortedSet[Int] with BitSetOps[BitSet] {
+ override protected def fromSpecific(coll: IterableOnce[Int]): BitSet = bitSetFactory.fromSpecific(coll)
+ override protected def newSpecificBuilder: Builder[Int, BitSet] = bitSetFactory.newBuilder
+ override def empty: BitSet = bitSetFactory.empty
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix = "BitSet"
+ override def unsorted: Set[Int] = this
+}
+
+@SerialVersionUID(3L)
+object BitSet extends SpecificIterableFactory[Int, BitSet] {
+ private[collection] final val ordMsg = "No implicit Ordering[${B}] found to build a SortedSet[${B}]. You may want to upcast to a Set[Int] first by calling `unsorted`."
+ private[collection] final val zipOrdMsg = "No implicit Ordering[${B}] found to build a SortedSet[(Int, ${B})]. You may want to upcast to a Set[Int] first by calling `unsorted`."
+
+ def empty: BitSet = immutable.BitSet.empty
+ def newBuilder: Builder[Int, BitSet] = immutable.BitSet.newBuilder
+ def fromSpecific(it: IterableOnce[Int]): BitSet = immutable.BitSet.fromSpecific(it)
+
+ @SerialVersionUID(3L)
+ private[collection] abstract class SerializationProxy(@transient protected val coll: BitSet) extends Serializable {
+
+ @transient protected var elems: Array[Long] = _
+
+ private[this] def writeObject(out: ObjectOutputStream): Unit = {
+ out.defaultWriteObject()
+ val nwords = coll.nwords
+ out.writeInt(nwords)
+ var i = 0
+ while(i < nwords) {
+ out.writeLong(coll.word(i))
+ i += 1
+ }
+ }
+
+ private[this] def readObject(in: ObjectInputStream): Unit = {
+ in.defaultReadObject()
+ val nwords = in.readInt()
+ elems = new Array[Long](nwords)
+ var i = 0
+ while(i < nwords) {
+ elems(i) = in.readLong()
+ i += 1
+ }
+ }
+
+ protected[this] def readResolve(): Any
+ }
+}
+
+/** Base implementation type of bitsets */
+trait BitSetOps[+C <: BitSet with BitSetOps[C]]
+ extends SortedSetOps[Int, SortedSet, C] { self =>
+ import BitSetOps._
+
+ def bitSetFactory: SpecificIterableFactory[Int, C]
+
+ def unsorted: Set[Int]
+
+ final def ordering: Ordering[Int] = Ordering.Int
+
+ /** The number of words (each with 64 bits) making up the set */
+ protected[collection] def nwords: Int
+
+ /** The words at index `idx`, or 0L if outside the range of the set
+ * '''Note:''' requires `idx >= 0`
+ */
+ protected[collection] def word(idx: Int): Long
+
+ /** Creates a new set of this kind from an array of longs
+ */
+ protected[collection] def fromBitMaskNoCopy(elems: Array[Long]): C
+
+ def contains(elem: Int): Boolean =
+ 0 <= elem && (word(elem >> LogWL) & (1L << elem)) != 0L
+
+ def iterator: Iterator[Int] = iteratorFrom(0)
+
+ def iteratorFrom(start: Int): Iterator[Int] = new AbstractIterator[Int] {
+ private[this] var currentPos = if (start > 0) start >> LogWL else 0
+ private[this] var currentWord = if (start > 0) word(currentPos) & (-1L << (start & (WordLength - 1))) else word(0)
+ final override def hasNext: Boolean = {
+ while (currentWord == 0) {
+ if (currentPos + 1 >= nwords) return false
+ currentPos += 1
+ currentWord = word(currentPos)
+ }
+ true
+ }
+ final override def next(): Int = {
+ if (hasNext) {
+ val bitPos = java.lang.Long.numberOfTrailingZeros(currentWord)
+ currentWord &= currentWord - 1
+ (currentPos << LogWL) + bitPos
+ } else Iterator.empty.next()
+ }
+ }
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Int, S]): S with EfficientSplit = {
+ val st = scala.collection.convert.impl.BitSetStepper.from(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]
+ }
+
+ override def size: Int = {
+ var s = 0
+ var i = nwords
+ while (i > 0) {
+ i -= 1
+ s += java.lang.Long.bitCount(word(i))
+ }
+ s
+ }
+
+ override def isEmpty: Boolean = 0 until nwords forall (i => word(i) == 0)
+
+ @inline private[this] def smallestInt: Int = {
+ val thisnwords = nwords
+ var i = 0
+ while(i < thisnwords) {
+ val currentWord = word(i)
+ if (currentWord != 0L) {
+ return java.lang.Long.numberOfTrailingZeros(currentWord) + (i * WordLength)
+ }
+ i += 1
+ }
+ throw new UnsupportedOperationException("empty.smallestInt")
+ }
+
+ @inline private[this] def largestInt: Int = {
+ var i = nwords - 1
+ while(i >= 0) {
+ val currentWord = word(i)
+ if (currentWord != 0L) {
+ return ((i + 1) * WordLength) - java.lang.Long.numberOfLeadingZeros(currentWord) - 1
+ }
+ i -= 1
+ }
+ throw new UnsupportedOperationException("empty.largestInt")
+ }
+
+ override def max[B >: Int](implicit ord: Ordering[B]): Int =
+ if (Ordering.Int eq ord) largestInt
+ else if (Ordering.Int isReverseOf ord) smallestInt
+ else super.max(ord)
+
+
+ override def min[B >: Int](implicit ord: Ordering[B]): Int =
+ if (Ordering.Int eq ord) smallestInt
+ else if (Ordering.Int isReverseOf ord) largestInt
+ else super.min(ord)
+
+ override def foreach[U](f: Int => U): Unit = {
+ /* NOTE: while loops are significantly faster as of 2.11 and
+ one major use case of bitsets is performance. Also, there
+ is nothing to do when all bits are clear, so use that as
+ the inner loop condition. */
+ var i = 0
+ while (i < nwords) {
+ var w = word(i)
+ var j = i * WordLength
+ while (w != 0L) {
+ if ((w&1L) == 1L) f(j)
+ w = w >>> 1
+ j += 1
+ }
+ i += 1
+ }
+ }
+
+ /** Creates a bit mask for this set as a new array of longs
+ */
+ def toBitMask: Array[Long] = {
+ val a = new Array[Long](nwords)
+ var i = a.length
+ while(i > 0) {
+ i -= 1
+ a(i) = word(i)
+ }
+ a
+ }
+
+ def rangeImpl(from: Option[Int], until: Option[Int]): C = {
+ val a = coll.toBitMask
+ val len = a.length
+ if (from.isDefined) {
+ val f = from.get
+ val w = f >> LogWL
+ val b = f & (WordLength - 1)
+ if (w >= 0) {
+ java.util.Arrays.fill(a, 0, math.min(w, len), 0)
+ if (b > 0 && w < len) a(w) &= ~((1L << b) - 1)
+ }
+ }
+ if (until.isDefined) {
+ val u = until.get
+ val w = u >> LogWL
+ val b = u & (WordLength - 1)
+ if (w < len) {
+ java.util.Arrays.fill(a, math.max(w + 1, 0), len, 0)
+ if (w >= 0) a(w) &= (1L << b) - 1
+ }
+ }
+ coll.fromBitMaskNoCopy(a)
+ }
+
+ override def concat(other: collection.IterableOnce[Int]): C = other match {
+ case otherBitset: BitSet =>
+ val len = coll.nwords max otherBitset.nwords
+ val words = new Array[Long](len)
+ for (idx <- 0 until len)
+ words(idx) = this.word(idx) | otherBitset.word(idx)
+ fromBitMaskNoCopy(words)
+ case _ => super.concat(other)
+ }
+
+ override def intersect(other: Set[Int]): C = other match {
+ case otherBitset: BitSet =>
+ val len = coll.nwords min otherBitset.nwords
+ val words = new Array[Long](len)
+ for (idx <- 0 until len)
+ words(idx) = this.word(idx) & otherBitset.word(idx)
+ fromBitMaskNoCopy(words)
+ case _ => super.intersect(other)
+ }
+
+ abstract override def diff(other: Set[Int]): C = other match {
+ case otherBitset: BitSet =>
+ val len = coll.nwords
+ val words = new Array[Long](len)
+ for (idx <- 0 until len)
+ words(idx) = this.word(idx) & ~otherBitset.word(idx)
+ fromBitMaskNoCopy(words)
+ case _ => super.diff(other)
+ }
+
+ /** Computes the symmetric difference of this bitset and another bitset by performing
+ * a bitwise "exclusive-or".
+ *
+ * @param other the other bitset to take part in the symmetric difference.
+ * @return a bitset containing those bits of this
+ * bitset or the other bitset that are not contained in both bitsets.
+ */
+ def xor(other: BitSet): C = {
+ val len = coll.nwords max other.nwords
+ val words = new Array[Long](len)
+ for (idx <- 0 until len)
+ words(idx) = coll.word(idx) ^ other.word(idx)
+ coll.fromBitMaskNoCopy(words)
+ }
+
+ @`inline` final def ^ (other: BitSet): C = xor(other)
+
+ /**
+ * Builds a new bitset by applying a function to all elements of this bitset
+ * @param f the function to apply to each element.
+ * @return a new bitset resulting from applying the given function ''f'' to
+ * each element of this bitset and collecting the results
+ */
+ def map(f: Int => Int): C = fromSpecific(new View.Map(this, f))
+
+ def flatMap(f: Int => IterableOnce[Int]): C = fromSpecific(new View.FlatMap(this, f))
+
+ def collect(pf: PartialFunction[Int, Int]): C = fromSpecific(super[SortedSetOps].collect(pf))
+
+ override def partition(p: Int => Boolean): (C, C) = {
+ val left = filter(p)
+ (left, this &~ left)
+ }
+}
+
+object BitSetOps {
+
+ /* Final vals can sometimes be inlined as constants (faster) */
+ private[collection] final val LogWL = 6
+ private[collection] final val WordLength = 64
+ private[collection] final val MaxSize = (Int.MaxValue >> LogWL) + 1
+
+ private[collection] def updateArray(elems: Array[Long], idx: Int, w: Long): Array[Long] = {
+ var len = elems.length
+ while (len > 0 && (elems(len - 1) == 0L || w == 0L && idx == len - 1)) len -= 1
+ var newlen = len
+ if (idx >= newlen && w != 0L) newlen = idx + 1
+ val newelems = new Array[Long](newlen)
+ Array.copy(elems, 0, newelems, 0, len)
+ if (idx < newlen) newelems(idx) = w
+ else assert(w == 0L)
+ newelems
+ }
+
+ private[collection] def computeWordForFilter(pred: Int => Boolean, isFlipped: Boolean, oldWord: Long, wordIndex: Int): Long =
+ if (oldWord == 0L) 0L else {
+ var w = oldWord
+ val trailingZeroes = java.lang.Long.numberOfTrailingZeros(w)
+ var jmask = 1L << trailingZeroes
+ var j = wordIndex * BitSetOps.WordLength + trailingZeroes
+ val maxJ = (wordIndex + 1) * BitSetOps.WordLength - java.lang.Long.numberOfLeadingZeros(w)
+ while (j != maxJ) {
+ if ((w & jmask) != 0L) {
+ if (pred(j) == isFlipped) {
+ // j did not pass the filter here
+ w = w & ~jmask
+ }
+ }
+ jmask = jmask << 1
+ j += 1
+ }
+ w
+ }
+}
diff --git a/library/src/scala/collection/BufferedIterator.scala b/library/src/scala/collection/BufferedIterator.scala
new file mode 100644
index 000000000000..b5a7f9658422
--- /dev/null
+++ b/library/src/scala/collection/BufferedIterator.scala
@@ -0,0 +1,32 @@
+/*
+ * 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
+
+
+/** Buffered iterators are iterators which provide a method `head`
+ * that inspects the next element without discarding it.
+ */
+trait BufferedIterator[+A] extends Iterator[A] {
+
+ /** Returns next element of iterator without advancing beyond it.
+ */
+ def head: A
+
+ /** Returns an option of the next element of an iterator without advancing beyond it.
+ * @return the next element of this iterator if it has a next element
+ * `None` if it does not
+ */
+ def headOption : Option[A] = if (hasNext) Some(head) else None
+
+ override def buffered: this.type = this
+}
diff --git a/library/src/scala/collection/BuildFrom.scala b/library/src/scala/collection/BuildFrom.scala
new file mode 100644
index 000000000000..0530e4445bd5
--- /dev/null
+++ b/library/src/scala/collection/BuildFrom.scala
@@ -0,0 +1,122 @@
+/*
+ * 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 scala.annotation.implicitNotFound
+import scala.collection.mutable.Builder
+import scala.collection.immutable.WrappedString
+import scala.reflect.ClassTag
+
+/** Builds a collection of type `C` from elements of type `A` when a source collection of type `From` is available.
+ * Implicit instances of `BuildFrom` are available for all collection types.
+ *
+ * @tparam From Type of source collection
+ * @tparam A Type of elements (e.g. `Int`, `Boolean`, etc.)
+ * @tparam C Type of collection (e.g. `List[Int]`, `TreeMap[Int, String]`, etc.)
+ */
+@implicitNotFound(msg = "Cannot construct a collection of type ${C} with elements of type ${A} based on a collection of type ${From}.")
+trait BuildFrom[-From, -A, +C] extends Any { self =>
+ def fromSpecific(from: From)(it: IterableOnce[A]): C
+
+ /** Get a Builder for the collection. For non-strict collection types this will use an intermediate buffer.
+ * Building collections with `fromSpecific` is preferred because it can be lazy for lazy collections. */
+ def newBuilder(from: From): Builder[A, C]
+
+ @deprecated("Use newBuilder() instead of apply()", "2.13.0")
+ @`inline` def apply(from: From): Builder[A, C] = newBuilder(from)
+
+ /** Partially apply a BuildFrom to a Factory */
+ def toFactory(from: From): Factory[A, C] = new Factory[A, C] {
+ def fromSpecific(it: IterableOnce[A]): C = self.fromSpecific(from)(it)
+ def newBuilder: Builder[A, C] = self.newBuilder(from)
+ }
+}
+
+object BuildFrom extends BuildFromLowPriority1 {
+
+ /** Build the source collection type from a MapOps */
+ implicit def buildFromMapOps[CC[X, Y] <: Map[X, Y] with MapOps[X, Y, CC, _], K0, V0, K, V]: BuildFrom[CC[K0, V0] with Map[K0, V0], (K, V), CC[K, V] with Map[K, V]] = new BuildFrom[CC[K0, V0], (K, V), CC[K, V]] {
+ //TODO: Reuse a prototype instance
+ def newBuilder(from: CC[K0, V0]): Builder[(K, V), CC[K, V]] = (from: MapOps[K0, V0, CC, _]).mapFactory.newBuilder[K, V]
+ def fromSpecific(from: CC[K0, V0])(it: IterableOnce[(K, V)]): CC[K, V] = (from: MapOps[K0, V0, CC, _]).mapFactory.from(it)
+ }
+
+ /** Build the source collection type from a SortedMapOps */
+ implicit def buildFromSortedMapOps[CC[X, Y] <: SortedMap[X, Y] with SortedMapOps[X, Y, CC, _], K0, V0, K : Ordering, V]: BuildFrom[CC[K0, V0] with SortedMap[K0, V0], (K, V), CC[K, V] with SortedMap[K, V]] = new BuildFrom[CC[K0, V0], (K, V), CC[K, V]] {
+ def newBuilder(from: CC[K0, V0]): Builder[(K, V), CC[K, V]] = (from: SortedMapOps[K0, V0, CC, _]).sortedMapFactory.newBuilder[K, V]
+ def fromSpecific(from: CC[K0, V0])(it: IterableOnce[(K, V)]): CC[K, V] = (from: SortedMapOps[K0, V0, CC, _]).sortedMapFactory.from(it)
+ }
+
+ implicit def buildFromBitSet[C <: BitSet with BitSetOps[C]]: BuildFrom[C, Int, C] =
+ new BuildFrom[C, Int, C] {
+ def fromSpecific(from: C)(it: IterableOnce[Int]): C = from.bitSetFactory.fromSpecific(it)
+ def newBuilder(from: C): Builder[Int, C] = from.bitSetFactory.newBuilder
+ }
+
+ implicit val buildFromString: BuildFrom[String, Char, String] =
+ new BuildFrom[String, Char, String] {
+ def fromSpecific(from: String)(it: IterableOnce[Char]): String = Factory.stringFactory.fromSpecific(it)
+ def newBuilder(from: String): Builder[Char, String] = Factory.stringFactory.newBuilder
+ }
+
+ implicit val buildFromWrappedString: BuildFrom[WrappedString, Char, WrappedString] =
+ new BuildFrom[WrappedString, Char, WrappedString] {
+ def fromSpecific(from: WrappedString)(it: IterableOnce[Char]): WrappedString = WrappedString.fromSpecific(it)
+ def newBuilder(from: WrappedString): mutable.Builder[Char, WrappedString] = WrappedString.newBuilder
+ }
+
+ implicit def buildFromArray[A : ClassTag]: BuildFrom[Array[_], A, Array[A]] =
+ new BuildFrom[Array[_], A, Array[A]] {
+ def fromSpecific(from: Array[_])(it: IterableOnce[A]): Array[A] = Factory.arrayFactory[A].fromSpecific(it)
+ def newBuilder(from: Array[_]): Builder[A, Array[A]] = Factory.arrayFactory[A].newBuilder
+ }
+
+ implicit def buildFromView[A, B]: BuildFrom[View[A], B, View[B]] =
+ new BuildFrom[View[A], B, View[B]] {
+ def fromSpecific(from: View[A])(it: IterableOnce[B]): View[B] = View.from(it)
+ def newBuilder(from: View[A]): Builder[B, View[B]] = View.newBuilder
+ }
+
+}
+
+trait BuildFromLowPriority1 extends BuildFromLowPriority2 {
+
+ /** Build the source collection type from an Iterable with SortedOps */
+ // Restating the upper bound of CC in the result type seems redundant, but it serves to prune the
+ // implicit search space for faster compilation and reduced change of divergence. See the compilation
+ // test in test/junit/scala/collection/BuildFromTest.scala and discussion in https://github.com/scala/scala/pull/10209
+ implicit def buildFromSortedSetOps[CC[X] <: SortedSet[X] with SortedSetOps[X, CC, _], A0, A : Ordering]: BuildFrom[CC[A0] with SortedSet[A0], A, CC[A] with SortedSet[A]] = new BuildFrom[CC[A0], A, CC[A]] {
+ def newBuilder(from: CC[A0]): Builder[A, CC[A]] = (from: SortedSetOps[A0, CC, _]).sortedIterableFactory.newBuilder[A]
+ def fromSpecific(from: CC[A0])(it: IterableOnce[A]): CC[A] = (from: SortedSetOps[A0, CC, _]).sortedIterableFactory.from(it)
+ }
+
+ implicit def fallbackStringCanBuildFrom[A]: BuildFrom[String, A, immutable.IndexedSeq[A]] =
+ new BuildFrom[String, A, immutable.IndexedSeq[A]] {
+ def fromSpecific(from: String)(it: IterableOnce[A]): immutable.IndexedSeq[A] = immutable.IndexedSeq.from(it)
+ def newBuilder(from: String): Builder[A, immutable.IndexedSeq[A]] = immutable.IndexedSeq.newBuilder[A]
+ }
+}
+
+trait BuildFromLowPriority2 {
+ /** Build the source collection type from an IterableOps */
+ implicit def buildFromIterableOps[CC[X] <: Iterable[X] with IterableOps[X, CC, _], A0, A]: BuildFrom[CC[A0], A, CC[A]] = new BuildFrom[CC[A0], A, CC[A]] {
+ //TODO: Reuse a prototype instance
+ def newBuilder(from: CC[A0]): Builder[A, CC[A]] = (from: IterableOps[A0, CC, _]).iterableFactory.newBuilder[A]
+ def fromSpecific(from: CC[A0])(it: IterableOnce[A]): CC[A] = (from: IterableOps[A0, CC, _]).iterableFactory.from(it)
+ }
+
+ implicit def buildFromIterator[A]: BuildFrom[Iterator[_], A, Iterator[A]] = new BuildFrom[Iterator[_], A, Iterator[A]] {
+ def newBuilder(from: Iterator[_]): mutable.Builder[A, Iterator[A]] = Iterator.newBuilder
+ def fromSpecific(from: Iterator[_])(it: IterableOnce[A]): Iterator[A] = Iterator.from(it)
+ }
+}
diff --git a/library/src/scala/collection/DefaultMap.scala b/library/src/scala/collection/DefaultMap.scala
new file mode 100644
index 000000000000..ca7d2a67f757
--- /dev/null
+++ b/library/src/scala/collection/DefaultMap.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
+package collection
+
+
+/** A default map which builds a default `immutable.Map` implementation for all
+ * transformations.
+ */
+@deprecated("DefaultMap is no longer necessary; extend Map directly", "2.13.0")
+trait DefaultMap[K, +V] extends Map[K, V]
diff --git a/library/src/scala/collection/Factory.scala b/library/src/scala/collection/Factory.scala
new file mode 100644
index 000000000000..7f56c20f7c9c
--- /dev/null
+++ b/library/src/scala/collection/Factory.scala
@@ -0,0 +1,784 @@
+/*
+ * 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 collection
+
+import scala.collection.immutable.NumericRange
+import scala.language.implicitConversions
+import scala.collection.mutable.Builder
+import scala.annotation.unchecked.uncheckedVariance
+import scala.reflect.ClassTag
+
+/**
+ * A factory that builds a collection of type `C` with elements of type `A`.
+ *
+ * This is a general form of any factory ([[IterableFactory]],
+ * [[SortedIterableFactory]], [[MapFactory]] and [[SortedMapFactory]]) whose
+ * element type is fixed.
+ *
+ * @tparam A Type of elements (e.g. `Int`, `Boolean`, etc.)
+ * @tparam C Type of collection (e.g. `List[Int]`, `TreeMap[Int, String]`, etc.)
+ */
+trait Factory[-A, +C] extends Any {
+
+ /**
+ * @return A collection of type `C` containing the same elements
+ * as the source collection `it`.
+ * @param it Source collection
+ */
+ def fromSpecific(it: IterableOnce[A]): C
+
+ /** Get a Builder for the collection. For non-strict collection types this will use an intermediate buffer.
+ * Building collections with `fromSpecific` is preferred because it can be lazy for lazy collections. */
+ def newBuilder: Builder[A, C]
+}
+
+object Factory {
+
+ implicit val stringFactory: Factory[Char, String] = new StringFactory
+ @SerialVersionUID(3L)
+ private class StringFactory extends Factory[Char, String] with Serializable {
+ def fromSpecific(it: IterableOnce[Char]): String = {
+ val b = new mutable.StringBuilder(scala.math.max(0, it.knownSize))
+ b ++= it
+ b.result()
+ }
+ def newBuilder: Builder[Char, String] = new mutable.StringBuilder()
+ }
+
+ implicit def arrayFactory[A: ClassTag]: Factory[A, Array[A]] = new ArrayFactory[A]
+ @SerialVersionUID(3L)
+ private class ArrayFactory[A: ClassTag] extends Factory[A, Array[A]] with Serializable {
+ def fromSpecific(it: IterableOnce[A]): Array[A] = {
+ val b = newBuilder
+ b.sizeHint(it, delta = 0)
+ b ++= it
+ b.result()
+ }
+ def newBuilder: Builder[A, Array[A]] = mutable.ArrayBuilder.make[A]
+ }
+
+}
+
+/** Base trait for companion objects of unconstrained collection types that may require
+ * multiple traversals of a source collection to build a target collection `CC`.
+ *
+ * @tparam CC Collection type constructor (e.g. `List`)
+ * @define factoryInfo
+ * This object provides a set of operations to create $Coll values.
+ *
+ * @define coll collection
+ * @define Coll `Iterable`
+ */
+trait IterableFactory[+CC[_]] extends Serializable {
+
+ /** Creates a target $coll from an existing source collection
+ *
+ * @param source Source collection
+ * @tparam A the type of the collection’s elements
+ * @return a new $coll with the elements of `source`
+ */
+ def from[A](source: IterableOnce[A]): CC[A]
+
+ /** An empty collection
+ * @tparam A the type of the ${coll}'s elements
+ */
+ def empty[A]: CC[A]
+
+ /** Creates a $coll with the specified elements.
+ * @tparam A the type of the ${coll}'s elements
+ * @param elems the elements of the created $coll
+ * @return a new $coll with elements `elems`
+ */
+ def apply[A](elems: A*): CC[A] = from(elems)
+
+ /** Produces a $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 a $coll with `len` values in the sequence `start, f(start), f(f(start)), ...`
+ */
+ def iterate[A](start: A, len: Int)(f: A => A): CC[A] = from(new View.Iterate(start, len)(f))
+
+ /** Produces a $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
+ * @return a $coll that produces elements using `f` until `f` returns `None`
+ */
+ def unfold[A, S](init: S)(f: S => Option[(A, S)]): CC[A] = from(new View.Unfold(init)(f))
+
+ /** Produces a $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 a $coll with values `start, start + 1, ..., end - 1`
+ */
+ def range[A : Integral](start: A, end: A): CC[A] = from(NumericRange(start, end, implicitly[Integral[A]].one))
+
+ /** Produces a $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 a $coll with values `start, start + step, ...` up to, but excluding `end`
+ */
+ def range[A : Integral](start: A, end: A, step: A): CC[A] = from(NumericRange(start, end, step))
+
+ /**
+ * @return A builder for $Coll objects.
+ * @tparam A the type of the ${coll}’s elements
+ */
+ def newBuilder[A]: Builder[A, CC[A]]
+
+ /** Produces a $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 A $coll that contains the results of `n` evaluations of `elem`.
+ */
+ def fill[A](n: Int)(elem: => A): CC[A] = from(new 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 A $coll that contains the results of `n1 x n2` evaluations of `elem`.
+ */
+ def fill[A](n1: Int, n2: Int)(elem: => A): CC[CC[A] @uncheckedVariance] = fill(n1)(fill(n2)(elem))
+
+ /** 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 A $coll that contains the results of `n1 x n2 x n3` evaluations of `elem`.
+ */
+ def fill[A](n1: Int, n2: Int, n3: Int)(elem: => A): CC[CC[CC[A]] @uncheckedVariance] = fill(n1)(fill(n2, n3)(elem))
+
+ /** 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 A $coll that contains the results of `n1 x n2 x n3 x n4` evaluations of `elem`.
+ */
+ def fill[A](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => A): CC[CC[CC[CC[A]]] @uncheckedVariance] =
+ fill(n1)(fill(n2, n3, n4)(elem))
+
+ /** 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 A $coll that contains the results of `n1 x n2 x n3 x n4 x n5` evaluations of `elem`.
+ */
+ def fill[A](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => A): CC[CC[CC[CC[CC[A]]]] @uncheckedVariance] =
+ fill(n1)(fill(n2, n3, n4, n5)(elem))
+
+ /** Produces a $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 A $coll consisting of elements `f(0), ..., f(n -1)`
+ */
+ def tabulate[A](n: Int)(f: Int => A): CC[A] = from(new 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 A $coll consisting of elements `f(i1, i2)`
+ * for `0 <= i1 < n1` and `0 <= i2 < n2`.
+ */
+ def tabulate[A](n1: Int, n2: Int)(f: (Int, Int) => A): CC[CC[A] @uncheckedVariance] =
+ tabulate(n1)(i1 => tabulate(n2)(f(i1, _)))
+
+ /** 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 A $coll consisting of elements `f(i1, i2, i3)`
+ * for `0 <= i1 < n1`, `0 <= i2 < n2`, and `0 <= i3 < n3`.
+ */
+ def tabulate[A](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => A): CC[CC[CC[A]] @uncheckedVariance] =
+ tabulate(n1)(i1 => tabulate(n2, n3)(f(i1, _, _)))
+
+ /** 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 A $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](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => A): CC[CC[CC[CC[A]]] @uncheckedVariance] =
+ tabulate(n1)(i1 => tabulate(n2, n3, n4)(f(i1, _, _, _)))
+
+ /** 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 A $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](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(f: (Int, Int, Int, Int, Int) => A): CC[CC[CC[CC[CC[A]]]] @uncheckedVariance] =
+ tabulate(n1)(i1 => tabulate(n2, n3, n4, n5)(f(i1, _, _, _, _)))
+
+ /** 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](xss: Iterable[A]*): CC[A] = {
+ from(xss.foldLeft(View.empty[A])(_ ++ _))
+ }
+
+ implicit def iterableFactory[A]: Factory[A, CC[A]] = IterableFactory.toFactory(this)
+}
+
+object IterableFactory {
+
+ /**
+ * Fixes the element type of `factory` to `A`
+ * @param factory The factory to fix the element type
+ * @tparam A Type of elements
+ * @tparam CC Collection type constructor of the factory (e.g. `Seq`, `List`)
+ * @return A [[Factory]] that uses the given `factory` to build a collection of elements
+ * of type `A`
+ */
+ implicit def toFactory[A, CC[_]](factory: IterableFactory[CC]): Factory[A, CC[A]] = new ToFactory[A, CC](factory)
+
+ @SerialVersionUID(3L)
+ private[this] class ToFactory[A, CC[_]](factory: IterableFactory[CC]) extends Factory[A, CC[A]] with Serializable {
+ def fromSpecific(it: IterableOnce[A]): CC[A] = factory.from[A](it)
+ def newBuilder: Builder[A, CC[A]] = factory.newBuilder[A]
+ }
+
+ implicit def toBuildFrom[A, CC[_]](factory: IterableFactory[CC]): BuildFrom[Any, A, CC[A]] =
+ new BuildFrom[Any, A, CC[A]] {
+ def fromSpecific(from: Any)(it: IterableOnce[A]) = factory.from(it)
+ def newBuilder(from: Any) = factory.newBuilder
+ }
+
+ @SerialVersionUID(3L)
+ class Delegate[CC[_]](delegate: IterableFactory[CC]) extends IterableFactory[CC] {
+ override def apply[A](elems: A*): CC[A] = delegate.apply(elems: _*)
+ def empty[A]: CC[A] = delegate.empty
+ def from[E](it: IterableOnce[E]): CC[E] = delegate.from(it)
+ def newBuilder[A]: Builder[A, CC[A]] = delegate.newBuilder[A]
+ }
+}
+
+/**
+ * @tparam CC Collection type constructor (e.g. `List`)
+ */
+trait SeqFactory[+CC[A] <: SeqOps[A, Seq, Seq[A]]] extends IterableFactory[CC] {
+ import SeqFactory.UnapplySeqWrapper
+ final def unapplySeq[A](x: CC[A] @uncheckedVariance): UnapplySeqWrapper[A] = new UnapplySeqWrapper(x) // TODO is uncheckedVariance sound here?
+}
+
+object SeqFactory {
+ @SerialVersionUID(3L)
+ class Delegate[CC[A] <: SeqOps[A, Seq, Seq[A]]](delegate: SeqFactory[CC]) extends SeqFactory[CC] {
+ override def apply[A](elems: A*): CC[A] = delegate.apply(elems: _*)
+ def empty[A]: CC[A] = delegate.empty
+ def from[E](it: IterableOnce[E]): CC[E] = delegate.from(it)
+ def newBuilder[A]: Builder[A, CC[A]] = delegate.newBuilder[A]
+ }
+
+ final class UnapplySeqWrapper[A](private val c: SeqOps[A, Seq, Seq[A]]) extends AnyVal {
+ def isEmpty: false = false
+ def get: UnapplySeqWrapper[A] = this
+ def lengthCompare(len: Int): Int = c.lengthCompare(len)
+ def apply(i: Int): A = c(i)
+ def drop(n: Int): scala.Seq[A] = c match {
+ case seq: scala.Seq[A] => seq.drop(n)
+ case _ => c.view.drop(n).toSeq
+ }
+ def toSeq: scala.Seq[A] = c.toSeq
+ }
+}
+
+trait StrictOptimizedSeqFactory[+CC[A] <: SeqOps[A, Seq, Seq[A]]] extends SeqFactory[CC] {
+
+ override def fill[A](n: Int)(elem: => A): CC[A] = {
+ val b = newBuilder[A]
+ b.sizeHint(n)
+ var i = 0
+ while (i < n) {
+ b += elem
+ i += 1
+ }
+ b.result()
+ }
+
+ override def tabulate[A](n: Int)(f: Int => A): CC[A] = {
+ val b = newBuilder[A]
+ b.sizeHint(n)
+ var i = 0
+ while (i < n) {
+ b += f(i)
+ i += 1
+ }
+ b.result()
+ }
+
+ override def concat[A](xss: Iterable[A]*): CC[A] = {
+ val b = newBuilder[A]
+ val knownSizes = xss.view.map(_.knownSize)
+ if (knownSizes forall (_ >= 0)) {
+ b.sizeHint(knownSizes.sum)
+ }
+ for (xs <- xss) b ++= xs
+ b.result()
+ }
+
+}
+
+/**
+ * @tparam A Type of elements (e.g. `Int`, `Boolean`, etc.)
+ * @tparam C Type of collection (e.g. `List[Int]`, `TreeMap[Int, String]`, etc.)
+ * @define factoryInfo
+ * This object provides a set of operations to create $Coll values.
+ *
+ * @define coll collection
+ * @define Coll `Iterable`
+ */
+trait SpecificIterableFactory[-A, +C] extends Factory[A, C] {
+ def empty: C
+ def apply(xs: A*): C = fromSpecific(xs)
+ def fill(n: Int)(elem: => A): C = fromSpecific(new View.Fill(n)(elem))
+ def newBuilder: Builder[A, C]
+
+ implicit def specificIterableFactory: Factory[A, C] = this
+}
+
+/**
+ * @define factoryInfo
+ * This object provides a set of operations to create $Coll values.
+ *
+ * @define coll collection
+ * @define Coll `Iterable`
+ */
+trait MapFactory[+CC[_, _]] extends Serializable {
+
+ /**
+ * An empty Map
+ */
+ def empty[K, V]: CC[K, V]
+
+ /**
+ * A collection of type Map generated from given iterable object.
+ */
+ def from[K, V](it: IterableOnce[(K, V)]): CC[K, V]
+
+ /**
+ * A collection of type Map that contains given key/value bindings.
+ */
+ def apply[K, V](elems: (K, V)*): CC[K, V] = from(elems)
+
+ /**
+ * The default builder for Map objects.
+ */
+ def newBuilder[K, V]: Builder[(K, V), CC[K, V]]
+
+ /**
+ * The default Factory instance for maps.
+ */
+ implicit def mapFactory[K, V]: Factory[(K, V), CC[K, V]] = MapFactory.toFactory(this)
+}
+
+object MapFactory {
+
+ /**
+ * Fixes the key and value types of `factory` to `K` and `V`, respectively
+ * @param factory The factory to fix the key and value types
+ * @tparam K Type of keys
+ * @tparam V Type of values
+ * @tparam CC Collection type constructor of the factory (e.g. `Map`, `HashMap`, etc.)
+ * @return A [[Factory]] that uses the given `factory` to build a map with keys of type `K`
+ * and values of type `V`
+ */
+ implicit def toFactory[K, V, CC[_, _]](factory: MapFactory[CC]): Factory[(K, V), CC[K, V]] = new ToFactory[K, V, CC](factory)
+
+ @SerialVersionUID(3L)
+ private[this] class ToFactory[K, V, CC[_, _]](factory: MapFactory[CC]) extends Factory[(K, V), CC[K, V]] with Serializable {
+ def fromSpecific(it: IterableOnce[(K, V)]): CC[K, V] = factory.from[K, V](it)
+ def newBuilder: Builder[(K, V), CC[K, V]] = factory.newBuilder[K, V]
+ }
+
+ implicit def toBuildFrom[K, V, CC[_, _]](factory: MapFactory[CC]): BuildFrom[Any, (K, V), CC[K, V]] =
+ new BuildFrom[Any, (K, V), CC[K, V]] {
+ def fromSpecific(from: Any)(it: IterableOnce[(K, V)]) = factory.from(it)
+ def newBuilder(from: Any) = factory.newBuilder[K, V]
+ }
+
+ @SerialVersionUID(3L)
+ class Delegate[C[_, _]](delegate: MapFactory[C]) extends MapFactory[C] {
+ override def apply[K, V](elems: (K, V)*): C[K, V] = delegate.apply(elems: _*)
+ def from[K, V](it: IterableOnce[(K, V)]): C[K, V] = delegate.from(it)
+ def empty[K, V]: C[K, V] = delegate.empty
+ def newBuilder[K, V]: Builder[(K, V), C[K, V]] = delegate.newBuilder
+ }
+}
+
+/** Base trait for companion objects of collections that require an implicit evidence.
+ * @tparam CC Collection type constructor (e.g. `ArraySeq`)
+ * @tparam Ev Unary type constructor for the implicit evidence required for an element type
+ * (typically `Ordering` or `ClassTag`)
+ *
+ * @define factoryInfo
+ * This object provides a set of operations to create $Coll values.
+ *
+ * @define coll collection
+ * @define Coll `Iterable`
+ */
+trait EvidenceIterableFactory[+CC[_], Ev[_]] extends Serializable {
+
+ def from[E : Ev](it: IterableOnce[E]): CC[E]
+
+ def empty[A : Ev]: CC[A]
+
+ def apply[A : Ev](xs: A*): CC[A] = from(xs)
+
+ /** Produces a $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 A $coll that contains the results of `n` evaluations of `elem`.
+ */
+ def fill[A : Ev](n: Int)(elem: => A): CC[A] = from(new View.Fill(n)(elem))
+
+ /** Produces a $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 A $coll consisting of elements `f(0), ..., f(n -1)`
+ */
+ def tabulate[A : Ev](n: Int)(f: Int => A): CC[A] = from(new View.Tabulate(n)(f))
+
+ /** Produces a $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 a $coll with `len` values in the sequence `start, f(start), f(f(start)), ...`
+ */
+ def iterate[A : Ev](start: A, len: Int)(f: A => A): CC[A] = from(new View.Iterate(start, len)(f))
+
+ /** Produces a $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
+ * @return a $coll that produces elements using `f` until `f` returns `None`
+ */
+ def unfold[A : Ev, S](init: S)(f: S => Option[(A, S)]): CC[A] = from(new View.Unfold(init)(f))
+
+ def newBuilder[A : Ev]: Builder[A, CC[A]]
+
+ implicit def evidenceIterableFactory[A : Ev]: Factory[A, CC[A]] = EvidenceIterableFactory.toFactory(this)
+}
+
+object EvidenceIterableFactory {
+
+ /**
+ * Fixes the element type of `factory` to `A`
+ * @param factory The factory to fix the element type
+ * @tparam A Type of elements
+ * @tparam CC Collection type constructor of the factory (e.g. `TreeSet`)
+ * @tparam Ev Type constructor of the evidence (usually `Ordering` or `ClassTag`)
+ * @return A [[Factory]] that uses the given `factory` to build a collection of elements
+ * of type `A`
+ */
+ implicit def toFactory[Ev[_], A: Ev, CC[_]](factory: EvidenceIterableFactory[CC, Ev]): Factory[A, CC[A]] = new ToFactory[Ev, A, CC](factory)
+
+ @SerialVersionUID(3L)
+ private[this] class ToFactory[Ev[_], A: Ev, CC[_]](factory: EvidenceIterableFactory[CC, Ev]) extends Factory[A, CC[A]] with Serializable {
+ def fromSpecific(it: IterableOnce[A]): CC[A] = factory.from[A](it)
+ def newBuilder: Builder[A, CC[A]] = factory.newBuilder[A]
+ }
+
+ implicit def toBuildFrom[Ev[_], A: Ev, CC[_]](factory: EvidenceIterableFactory[CC, Ev]): BuildFrom[Any, A, CC[A]] = new EvidenceIterableFactoryToBuildFrom(factory)
+ private class EvidenceIterableFactoryToBuildFrom[Ev[_], A: Ev, CC[_]](factory: EvidenceIterableFactory[CC, Ev]) extends BuildFrom[Any, A, CC[A]] {
+ def fromSpecific(from: Any)(it: IterableOnce[A]): CC[A] = factory.from[A](it)
+ def newBuilder(from: Any): Builder[A, CC[A]] = factory.newBuilder[A]
+ }
+
+ @SerialVersionUID(3L)
+ class Delegate[CC[_], Ev[_]](delegate: EvidenceIterableFactory[CC, Ev]) extends EvidenceIterableFactory[CC, Ev] {
+ override def apply[A: Ev](xs: A*): CC[A] = delegate.apply(xs: _*)
+ def empty[A : Ev]: CC[A] = delegate.empty
+ def from[E : Ev](it: IterableOnce[E]): CC[E] = delegate.from(it)
+ def newBuilder[A : Ev]: Builder[A, CC[A]] = delegate.newBuilder[A]
+ }
+}
+
+/** Base trait for companion objects of collections that require an implicit `Ordering`.
+ * @tparam CC Collection type constructor (e.g. `SortedSet`)
+ */
+trait SortedIterableFactory[+CC[_]] extends EvidenceIterableFactory[CC, Ordering]
+
+object SortedIterableFactory {
+ @SerialVersionUID(3L)
+ class Delegate[CC[_]](delegate: EvidenceIterableFactory[CC, Ordering])
+ extends EvidenceIterableFactory.Delegate[CC, Ordering](delegate) with SortedIterableFactory[CC]
+}
+
+/** Base trait for companion objects of collections that require an implicit `ClassTag`.
+ * @tparam CC Collection type constructor (e.g. `ArraySeq`)
+ */
+trait ClassTagIterableFactory[+CC[_]] extends EvidenceIterableFactory[CC, ClassTag] {
+
+ @`inline` private[this] implicit def ccClassTag[X]: ClassTag[CC[X]] =
+ ClassTag.AnyRef.asInstanceOf[ClassTag[CC[X]]] // Good enough for boxed vs primitive arrays
+
+ /** Produces a $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 a $coll with values `start, start + 1, ..., end - 1`
+ */
+ def range[A : Integral : ClassTag](start: A, end: A): CC[A] = from(NumericRange(start, end, implicitly[Integral[A]].one))
+
+ /** Produces a $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 a $coll with values `start, start + step, ...` up to, but excluding `end`
+ */
+ def range[A : Integral : ClassTag](start: A, end: A, step: A): CC[A] = from(NumericRange(start, end, step))
+
+ /** 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 A $coll that contains the results of `n1 x n2` evaluations of `elem`.
+ */
+ def fill[A : ClassTag](n1: Int, n2: Int)(elem: => A): CC[CC[A] @uncheckedVariance] = fill(n1)(fill(n2)(elem))
+
+ /** 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 A $coll that contains the results of `n1 x n2 x n3` evaluations of `elem`.
+ */
+ def fill[A : ClassTag](n1: Int, n2: Int, n3: Int)(elem: => A): CC[CC[CC[A]] @uncheckedVariance] = fill(n1)(fill(n2, n3)(elem))
+
+ /** 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 A $coll that contains the results of `n1 x n2 x n3 x n4` evaluations of `elem`.
+ */
+ def fill[A : ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => A): CC[CC[CC[CC[A]]] @uncheckedVariance] =
+ fill(n1)(fill(n2, n3, n4)(elem))
+
+ /** 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 A $coll that contains the results of `n1 x n2 x n3 x n4 x n5` evaluations of `elem`.
+ */
+ def fill[A : ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => A): CC[CC[CC[CC[CC[A]]]] @uncheckedVariance] =
+ fill(n1)(fill(n2, n3, n4, n5)(elem))
+
+ /** 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 A $coll consisting of elements `f(i1, i2)`
+ * for `0 <= i1 < n1` and `0 <= i2 < n2`.
+ */
+ def tabulate[A : ClassTag](n1: Int, n2: Int)(f: (Int, Int) => A): CC[CC[A] @uncheckedVariance] =
+ tabulate(n1)(i1 => tabulate(n2)(f(i1, _)))
+
+ /** 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 A $coll consisting of elements `f(i1, i2, i3)`
+ * for `0 <= i1 < n1`, `0 <= i2 < n2`, and `0 <= i3 < n3`.
+ */
+ def tabulate[A : ClassTag](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => A): CC[CC[CC[A]] @uncheckedVariance] =
+ tabulate(n1)(i1 => tabulate(n2, n3)(f(i1, _, _)))
+
+ /** 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 A $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 : ClassTag](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => A): CC[CC[CC[CC[A]]] @uncheckedVariance] =
+ tabulate(n1)(i1 => tabulate(n2, n3, n4)(f(i1, _, _, _)))
+
+ /** 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 A $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 : ClassTag](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(f: (Int, Int, Int, Int, Int) => A): CC[CC[CC[CC[CC[A]]]] @uncheckedVariance] =
+ tabulate(n1)(i1 => tabulate(n2, n3, n4, n5)(f(i1, _, _, _, _)))
+}
+
+object ClassTagIterableFactory {
+ @SerialVersionUID(3L)
+ class Delegate[CC[_]](delegate: EvidenceIterableFactory[CC, ClassTag])
+ extends EvidenceIterableFactory.Delegate[CC, ClassTag](delegate) with ClassTagIterableFactory[CC]
+
+ /** An IterableFactory that uses ClassTag.Any as the evidence for every element type. This may or may not be
+ * sound depending on the use of the `ClassTag` by the collection implementation. */
+ @SerialVersionUID(3L)
+ class AnyIterableDelegate[CC[_]](delegate: ClassTagIterableFactory[CC]) extends IterableFactory[CC] {
+ def empty[A]: CC[A] = delegate.empty(using ClassTag.Any).asInstanceOf[CC[A]]
+ def from[A](it: IterableOnce[A]): CC[A] = delegate.from[Any](it)(using ClassTag.Any).asInstanceOf[CC[A]]
+ def newBuilder[A]: Builder[A, CC[A]] = delegate.newBuilder(using ClassTag.Any).asInstanceOf[Builder[A, CC[A]]]
+ override def apply[A](elems: A*): CC[A] = delegate.apply[Any](elems: _*)(using ClassTag.Any).asInstanceOf[CC[A]]
+ override def iterate[A](start: A, len: Int)(f: A => A): CC[A] = delegate.iterate[A](start, len)(f)(using ClassTag.Any.asInstanceOf[ClassTag[A]])
+ override def unfold[A, S](init: S)(f: S => Option[(A, S)]): CC[A] = delegate.unfold[A, S](init)(f)(using ClassTag.Any.asInstanceOf[ClassTag[A]])
+ override def range[A](start: A, end: A)(implicit i: Integral[A]): CC[A] = delegate.range[A](start, end)(using i, ClassTag.Any.asInstanceOf[ClassTag[A]])
+ override def range[A](start: A, end: A, step: A)(implicit i: Integral[A]): CC[A] = delegate.range[A](start, end, step)(using i, ClassTag.Any.asInstanceOf[ClassTag[A]])
+ override def fill[A](n: Int)(elem: => A): CC[A] = delegate.fill[Any](n)(elem)(using ClassTag.Any).asInstanceOf[CC[A]]
+ override def tabulate[A](n: Int)(f: Int => A): CC[A] = delegate.tabulate[Any](n)(f)(using ClassTag.Any).asInstanceOf[CC[A]]
+ }
+}
+
+/**
+ * @tparam CC Collection type constructor (e.g. `ArraySeq`)
+ */
+trait ClassTagSeqFactory[+CC[A] <: SeqOps[A, Seq, Seq[A]]] extends ClassTagIterableFactory[CC] {
+ import SeqFactory.UnapplySeqWrapper
+ final def unapplySeq[A](x: CC[A] @uncheckedVariance): UnapplySeqWrapper[A] = new UnapplySeqWrapper(x) // TODO is uncheckedVariance sound here?
+}
+
+object ClassTagSeqFactory {
+ @SerialVersionUID(3L)
+ class Delegate[CC[A] <: SeqOps[A, Seq, Seq[A]]](delegate: ClassTagSeqFactory[CC])
+ extends ClassTagIterableFactory.Delegate[CC](delegate) with ClassTagSeqFactory[CC]
+
+ /** A SeqFactory that uses ClassTag.Any as the evidence for every element type. This may or may not be
+ * sound depending on the use of the `ClassTag` by the collection implementation. */
+ @SerialVersionUID(3L)
+ class AnySeqDelegate[CC[A] <: SeqOps[A, Seq, Seq[A]]](delegate: ClassTagSeqFactory[CC])
+ extends ClassTagIterableFactory.AnyIterableDelegate[CC](delegate) with SeqFactory[CC]
+}
+
+trait StrictOptimizedClassTagSeqFactory[+CC[A] <: SeqOps[A, Seq, Seq[A]]] extends ClassTagSeqFactory[CC] {
+
+ override def fill[A : ClassTag](n: Int)(elem: => A): CC[A] = {
+ val b = newBuilder[A]
+ b.sizeHint(n)
+ var i = 0
+ while (i < n) {
+ b += elem
+ i += 1
+ }
+ b.result()
+ }
+
+ override def tabulate[A : ClassTag](n: Int)(f: Int => A): CC[A] = {
+ val b = newBuilder[A]
+ b.sizeHint(n)
+ var i = 0
+ while (i < n) {
+ b += f(i)
+ i += 1
+ }
+ b.result()
+ }
+
+}
+
+/**
+ * @define factoryInfo
+ * This object provides a set of operations to create $Coll values.
+ *
+ * @define coll collection
+ * @define Coll `Iterable`
+ */
+trait SortedMapFactory[+CC[_, _]] extends Serializable {
+
+ def empty[K : Ordering, V]: CC[K, V]
+
+ def from[K : Ordering, V](it: IterableOnce[(K, V)]): CC[K, V]
+
+ def apply[K : Ordering, V](elems: (K, V)*): CC[K, V] = from(elems)
+
+ def newBuilder[K : Ordering, V]: Builder[(K, V), CC[K, V]]
+
+ implicit def sortedMapFactory[K : Ordering, V]: Factory[(K, V), CC[K, V]] = SortedMapFactory.toFactory(this)
+
+}
+
+object SortedMapFactory {
+
+ /**
+ * Implicit conversion that fixes the key and value types of `factory` to `K` and `V`,
+ * respectively.
+ *
+ * @param factory The factory to fix the key and value types
+ * @tparam K Type of keys
+ * @tparam V Type of values
+ * @tparam CC Collection type constructor of the factory (e.g. `TreeMap`)
+ * @return A [[Factory]] that uses the given `factory` to build a map with keys of
+ * type `K` and values of type `V`
+ */
+ implicit def toFactory[K : Ordering, V, CC[_, _]](factory: SortedMapFactory[CC]): Factory[(K, V), CC[K, V]] = new ToFactory[K, V, CC](factory)
+
+ @SerialVersionUID(3L)
+ private[this] class ToFactory[K : Ordering, V, CC[_, _]](factory: SortedMapFactory[CC]) extends Factory[(K, V), CC[K, V]] with Serializable {
+ def fromSpecific(it: IterableOnce[(K, V)]): CC[K, V] = factory.from[K, V](it)
+ def newBuilder: Builder[(K, V), CC[K, V]] = factory.newBuilder[K, V]
+ }
+
+ implicit def toBuildFrom[K : Ordering, V, CC[_, _]](factory: SortedMapFactory[CC]): BuildFrom[Any, (K, V), CC[K, V]] = new SortedMapFactoryToBuildFrom(factory)
+ private class SortedMapFactoryToBuildFrom[K : Ordering, V, CC[_, _]](factory: SortedMapFactory[CC]) extends BuildFrom[Any, (K, V), CC[K, V]] {
+ def fromSpecific(from: Any)(it: IterableOnce[(K, V)]) = factory.from(it)
+ def newBuilder(from: Any) = factory.newBuilder[K, V]
+ }
+
+ @SerialVersionUID(3L)
+ class Delegate[CC[_, _]](delegate: SortedMapFactory[CC]) extends SortedMapFactory[CC] {
+ override def apply[K: Ordering, V](elems: (K, V)*): CC[K, V] = delegate.apply(elems: _*)
+ def from[K : Ordering, V](it: IterableOnce[(K, V)]): CC[K, V] = delegate.from(it)
+ def empty[K : Ordering, V]: CC[K, V] = delegate.empty
+ def newBuilder[K : Ordering, V]: Builder[(K, V), CC[K, V]] = delegate.newBuilder
+ }
+}
diff --git a/library/src/scala/collection/Hashing.scala b/library/src/scala/collection/Hashing.scala
new file mode 100644
index 000000000000..7d3702d26e43
--- /dev/null
+++ b/library/src/scala/collection/Hashing.scala
@@ -0,0 +1,62 @@
+/*
+ * 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 collection
+
+
+protected[collection] object Hashing {
+
+ def elemHashCode(key: Any): Int = key.##
+
+ def improve(hcode: Int): Int = {
+ var h: Int = hcode + ~(hcode << 9)
+ h = h ^ (h >>> 14)
+ h = h + (h << 4)
+ h ^ (h >>> 10)
+ }
+
+ def computeHash(key: Any): Int =
+ improve(elemHashCode(key))
+
+ /**
+ * Utility method to keep a subset of all bits in a given bitmap
+ *
+ * Example
+ * bitmap (binary): 00000001000000010000000100000001
+ * keep (binary): 1010
+ * result (binary): 00000001000000000000000100000000
+ *
+ * @param bitmap the bitmap
+ * @param keep a bitmask containing which bits to keep
+ * @return the original bitmap with all bits where keep is not 1 set to 0
+ */
+ def keepBits(bitmap: Int, keep: Int): Int = {
+ var result = 0
+ var current = bitmap
+ var kept = keep
+ while (kept != 0) {
+ // lowest remaining bit in current
+ val lsb = current ^ (current & (current - 1))
+ if ((kept & 1) != 0) {
+ // mark bit in result bitmap
+ result |= lsb
+ }
+ // clear lowest remaining one bit in abm
+ current &= ~lsb
+ // look at the next kept bit
+ kept >>>= 1
+ }
+ result
+ }
+
+}
diff --git a/library/src/scala/collection/IndexedSeq.scala b/library/src/scala/collection/IndexedSeq.scala
new file mode 100644
index 000000000000..b4e8012ab63e
--- /dev/null
+++ b/library/src/scala/collection/IndexedSeq.scala
@@ -0,0 +1,147 @@
+/*
+ * 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 collection
+
+import scala.annotation.{nowarn, tailrec}
+import scala.collection.Searching.{Found, InsertionPoint, SearchResult}
+import scala.collection.Stepper.EfficientSplit
+import scala.math.Ordering
+
+/** Base trait for indexed sequences that have efficient `apply` and `length` */
+trait IndexedSeq[+A] extends Seq[A]
+ with IndexedSeqOps[A, IndexedSeq, IndexedSeq[A]]
+ with IterableFactoryDefaults[A, IndexedSeq] {
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix: String = "IndexedSeq"
+
+ override def iterableFactory: SeqFactory[IndexedSeq] = IndexedSeq
+}
+
+@SerialVersionUID(3L)
+object IndexedSeq extends SeqFactory.Delegate[IndexedSeq](immutable.IndexedSeq)
+
+/** Base trait for indexed Seq operations */
+trait IndexedSeqOps[+A, +CC[_], +C] extends Any with SeqOps[A, CC, C] { self =>
+
+ def iterator: Iterator[A] = view.iterator
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit = {
+ import convert.impl._
+ val s = shape.shape match {
+ case StepperShape.IntShape => new IntIndexedSeqStepper (this.asInstanceOf[IndexedSeqOps[Int, AnyConstr, _]], 0, length)
+ case StepperShape.LongShape => new LongIndexedSeqStepper (this.asInstanceOf[IndexedSeqOps[Long, AnyConstr, _]], 0, length)
+ case StepperShape.DoubleShape => new DoubleIndexedSeqStepper(this.asInstanceOf[IndexedSeqOps[Double, AnyConstr, _]], 0, length)
+ case _ => shape.parUnbox(new AnyIndexedSeqStepper[A](this, 0, length))
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ override def reverseIterator: Iterator[A] = view.reverseIterator
+
+ /* TODO 2.14+ uncomment and delete related code in IterableOnce
+ @tailrec private def foldl[B](start: Int, end: Int, z: B, op: (B, A) => B): B =
+ if (start == end) z
+ else foldl(start + 1, end, op(z, apply(start)), op)
+ */
+
+ @tailrec private def foldr[B](start: Int, end: Int, z: B, op: (A, B) => B): B =
+ if (start == end) z
+ else foldr(start, end - 1, op(apply(end - 1), z), op)
+
+ //override def foldLeft[B](z: B)(op: (B, A) => B): B = foldl(0, length, z, op)
+
+ override def foldRight[B](z: B)(op: (A, B) => B): B = foldr(0, length, z, op)
+
+ //override def reduceLeft[B >: A](op: (B, A) => B): B = if (length > 0) foldl(1, length, apply(0), op) else super.reduceLeft(op)
+
+ //override def reduceRight[B >: A](op: (A, B) => B): B = if (length > 0) foldr(0, length - 1, apply(length - 1), op) else super.reduceRight(op)
+
+ override def view: IndexedSeqView[A] = new IndexedSeqView.Id[A](this)
+
+ @deprecated("Use .view.slice(from, until) instead of .view(from, until)", "2.13.0")
+ override def view(from: Int, until: Int): IndexedSeqView[A] = view.slice(from, until)
+
+ override protected def reversed: Iterable[A] = new IndexedSeqView.Reverse(this)
+
+ // Override transformation operations to use more efficient views than the default ones
+ override def prepended[B >: A](elem: B): CC[B] = iterableFactory.from(new IndexedSeqView.Prepended(elem, this))
+
+ override def take(n: Int): C = fromSpecific(new IndexedSeqView.Take(this, n))
+
+ override def takeRight(n: Int): C = fromSpecific(new IndexedSeqView.TakeRight(this, n))
+
+ override def drop(n: Int): C = fromSpecific(new IndexedSeqView.Drop(this, n))
+
+ override def dropRight(n: Int): C = fromSpecific(new IndexedSeqView.DropRight(this, n))
+
+ override def map[B](f: A => B): CC[B] = iterableFactory.from(new IndexedSeqView.Map(this, f))
+
+ override def reverse: C = fromSpecific(new IndexedSeqView.Reverse(this))
+
+ override def slice(from: Int, until: Int): C = fromSpecific(new IndexedSeqView.Slice(this, from, until))
+
+ override def head: A =
+ if (!isEmpty) apply(0)
+ else throw new NoSuchElementException(s"head of empty ${
+ self match {
+ case self: IndexedSeq[_] => self.collectionClassName
+ case _ => toString
+ }
+ }")
+
+ override def headOption: Option[A] = if (isEmpty) None else Some(head)
+
+ override def last: A =
+ if (!isEmpty) apply(length - 1)
+ else throw new NoSuchElementException(s"last of empty ${
+ self match {
+ case self: IndexedSeq[_] => self.collectionClassName
+ case _ => toString
+ }
+ }")
+
+ // We already inherit an efficient `lastOption = if (isEmpty) None else Some(last)`
+
+ override final def lengthCompare(len: Int): Int = Integer.compare(length, len)
+
+ override def knownSize: Int = length
+
+ override final def lengthCompare(that: Iterable[_]): Int = {
+ val res = that.sizeCompare(length)
+ // can't just invert the result, because `-Int.MinValue == Int.MinValue`
+ if (res == Int.MinValue) 1 else -res
+ }
+
+ override def search[B >: A](elem: B)(implicit ord: Ordering[B]): SearchResult =
+ binarySearch(elem, 0, length)(ord)
+
+ override def search[B >: A](elem: B, from: Int, to: Int)(implicit ord: Ordering[B]): SearchResult =
+ binarySearch(elem, from, to)(ord)
+
+ @tailrec
+ private[this] def binarySearch[B >: A](elem: B, from: Int, to: Int)
+ (implicit ord: Ordering[B]): SearchResult = {
+ if (from < 0) binarySearch(elem, 0, to)
+ else if (to > length) binarySearch(elem, from, length)
+ else if (to <= from) InsertionPoint(from)
+ else {
+ val idx = from + (to - from - 1) / 2
+ math.signum(ord.compare(elem, apply(idx))) match {
+ case -1 => binarySearch(elem, from, idx)(ord)
+ case 1 => binarySearch(elem, idx + 1, to)(ord)
+ case _ => Found(idx)
+ }
+ }
+ }
+}
diff --git a/library/src/scala/collection/IndexedSeqView.scala b/library/src/scala/collection/IndexedSeqView.scala
new file mode 100644
index 000000000000..4fd99c1080af
--- /dev/null
+++ b/library/src/scala/collection/IndexedSeqView.scala
@@ -0,0 +1,180 @@
+/*
+ * 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 collection
+
+import scala.annotation.nowarn
+
+
+/** View defined in terms of indexing a range */
+trait IndexedSeqView[+A] extends IndexedSeqOps[A, View, View[A]] with SeqView[A] { self =>
+
+ override def view: IndexedSeqView[A] = this
+
+ @deprecated("Use .view.slice(from, until) instead of .view(from, until)", "2.13.0")
+ override def view(from: Int, until: Int): IndexedSeqView[A] = view.slice(from, until)
+
+ override def iterator: Iterator[A] = new IndexedSeqView.IndexedSeqViewIterator(this)
+ override def reverseIterator: Iterator[A] = new IndexedSeqView.IndexedSeqViewReverseIterator(this)
+
+ override def appended[B >: A](elem: B): IndexedSeqView[B] = new IndexedSeqView.Appended(this, elem)
+ override def prepended[B >: A](elem: B): IndexedSeqView[B] = new IndexedSeqView.Prepended(elem, this)
+ override def take(n: Int): IndexedSeqView[A] = new IndexedSeqView.Take(this, n)
+ override def takeRight(n: Int): IndexedSeqView[A] = new IndexedSeqView.TakeRight(this, n)
+ override def drop(n: Int): IndexedSeqView[A] = new IndexedSeqView.Drop(this, n)
+ override def dropRight(n: Int): IndexedSeqView[A] = new IndexedSeqView.DropRight(this, n)
+ override def map[B](f: A => B): IndexedSeqView[B] = new IndexedSeqView.Map(this, f)
+ override def reverse: IndexedSeqView[A] = new IndexedSeqView.Reverse(this)
+ override def slice(from: Int, until: Int): IndexedSeqView[A] = new IndexedSeqView.Slice(this, from, until)
+ override def tapEach[U](f: A => U): IndexedSeqView[A] = new IndexedSeqView.Map(this, { (a: A) => f(a); a})
+
+ def concat[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new IndexedSeqView.Concat(this, suffix)
+ def appendedAll[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new IndexedSeqView.Concat(this, suffix)
+ def prependedAll[B >: A](prefix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new IndexedSeqView.Concat(prefix, this)
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix: String = "IndexedSeqView"
+}
+
+object IndexedSeqView {
+
+ @SerialVersionUID(3L)
+ private[collection] class IndexedSeqViewIterator[A](self: IndexedSeqView[A]) extends AbstractIterator[A] with Serializable {
+ private[this] var current = 0
+ private[this] var remainder = self.length
+ override def knownSize: Int = remainder
+ @inline private[this] def _hasNext: Boolean = remainder > 0
+ def hasNext: Boolean = _hasNext
+ def next(): A =
+ if (_hasNext) {
+ val r = self(current)
+ current += 1
+ remainder -= 1
+ r
+ } else Iterator.empty.next()
+
+ override def drop(n: Int): Iterator[A] = {
+ if (n > 0) {
+ current += n
+ remainder = Math.max(0, remainder - n)
+ }
+ this
+ }
+
+ override protected def sliceIterator(from: Int, until: Int): Iterator[A] = {
+
+ def formatRange(value : Int) : Int = if (value < 0) 0 else if (value > remainder) remainder else value
+
+ val formatFrom = formatRange(from)
+ val formatUntil = formatRange(until)
+ remainder = Math.max(0, formatUntil - formatFrom)
+ current = current + formatFrom
+ this
+ }
+ }
+ @SerialVersionUID(3L)
+ private[collection] class IndexedSeqViewReverseIterator[A](self: IndexedSeqView[A]) extends AbstractIterator[A] with Serializable {
+ private[this] var remainder = self.length
+ private[this] var pos = remainder - 1
+ @inline private[this] def _hasNext: Boolean = remainder > 0
+ def hasNext: Boolean = _hasNext
+ def next(): A =
+ if (_hasNext) {
+ val r = self(pos)
+ pos -= 1
+ remainder -= 1
+ r
+ } else Iterator.empty.next()
+
+ // from < 0 means don't move pos, until < 0 means don't limit remainder
+ //
+ override protected def sliceIterator(from: Int, until: Int): Iterator[A] = {
+ if (_hasNext) {
+ if (remainder <= from) remainder = 0 // exhausted by big skip
+ else if (from <= 0) { // no skip, pos is same
+ if (until >= 0 && until < remainder) remainder = until // ...limited by until
+ }
+ else {
+ pos -= from // skip ahead
+ if (until >= 0 && until < remainder) { // ...limited by until
+ if (until <= from) remainder = 0 // ...exhausted if limit is smaller than skip
+ else remainder = until - from // ...limited by until, less the skip
+ }
+ else remainder -= from // ...otherwise just less the skip
+ }
+ }
+ this
+ }
+ }
+
+ /** An `IndexedSeqOps` whose collection type and collection type constructor are unknown */
+ type SomeIndexedSeqOps[A] = IndexedSeqOps[A, AnyConstr, _]
+
+ @SerialVersionUID(3L)
+ class Id[+A](underlying: SomeIndexedSeqOps[A])
+ extends SeqView.Id(underlying) with IndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class Appended[+A](underlying: SomeIndexedSeqOps[A], elem: A)
+ extends SeqView.Appended(underlying, elem) with IndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class Prepended[+A](elem: A, underlying: SomeIndexedSeqOps[A])
+ extends SeqView.Prepended(elem, underlying) with IndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class Concat[A](prefix: SomeIndexedSeqOps[A], suffix: SomeIndexedSeqOps[A])
+ extends SeqView.Concat[A](prefix, suffix) with IndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class Take[A](underlying: SomeIndexedSeqOps[A], n: Int)
+ extends SeqView.Take(underlying, n) with IndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class TakeRight[A](underlying: SomeIndexedSeqOps[A], n: Int)
+ extends SeqView.TakeRight(underlying, n) with IndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class Drop[A](underlying: SomeIndexedSeqOps[A], n: Int)
+ extends SeqView.Drop[A](underlying, n) with IndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class DropRight[A](underlying: SomeIndexedSeqOps[A], n: Int)
+ extends SeqView.DropRight[A](underlying, n) with IndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class Map[A, B](underlying: SomeIndexedSeqOps[A], f: A => B)
+ extends SeqView.Map(underlying, f) with IndexedSeqView[B]
+
+ @SerialVersionUID(3L)
+ class Reverse[A](underlying: SomeIndexedSeqOps[A]) extends SeqView.Reverse[A](underlying) with IndexedSeqView[A] {
+ override def reverse: IndexedSeqView[A] = underlying match {
+ case x: IndexedSeqView[A] => x
+ case _ => super.reverse
+ }
+ }
+
+ @SerialVersionUID(3L)
+ class Slice[A](underlying: SomeIndexedSeqOps[A], from: Int, until: Int) extends AbstractIndexedSeqView[A] {
+ protected val lo = from max 0
+ protected val hi = (until max 0) min underlying.length
+ protected val len = (hi - lo) max 0
+ @throws[IndexOutOfBoundsException]
+ def apply(i: Int): A = underlying(lo + i)
+ def length: Int = len
+ }
+}
+
+/** Explicit instantiation of the `IndexedSeqView` trait to reduce class file size in subclasses. */
+@SerialVersionUID(3L)
+abstract class AbstractIndexedSeqView[+A] extends AbstractSeqView[A] with IndexedSeqView[A]
diff --git a/library/src/scala/collection/Iterable.scala b/library/src/scala/collection/Iterable.scala
new file mode 100644
index 000000000000..bec0a1211e28
--- /dev/null
+++ b/library/src/scala/collection/Iterable.scala
@@ -0,0 +1,1045 @@
+/*
+ * 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 collection
+
+import scala.annotation.nowarn
+import scala.annotation.unchecked.uncheckedVariance
+import scala.collection.mutable.Builder
+import scala.collection.View.{LeftPartitionMapped, RightPartitionMapped}
+
+/** Base trait for generic collections.
+ *
+ * @tparam A the element type of the collection
+ *
+ * @define Coll `Iterable`
+ * @define coll iterable collection
+ */
+trait Iterable[+A] extends IterableOnce[A]
+ with IterableOps[A, Iterable, Iterable[A]]
+ with IterableFactoryDefaults[A, Iterable] {
+
+ // The collection itself
+ @deprecated("toIterable is internal and will be made protected; its name is similar to `toList` or `toSeq`, but it doesn't copy non-immutable collections", "2.13.7")
+ final def toIterable: this.type = this
+
+ final protected def coll: this.type = this
+
+ def iterableFactory: IterableFactory[Iterable] = Iterable
+
+ @deprecated("Iterable.seq always returns the iterable itself", "2.13.0")
+ def seq: this.type = this
+
+ /** Defines the prefix of this object's `toString` representation.
+ *
+ * It is recommended to return the name of the concrete collection type, but
+ * not implementation subclasses. For example, for `ListMap` this method should
+ * return `"ListMap"`, not `"Map"` (the supertype) or `"Node"` (an implementation
+ * subclass).
+ *
+ * The default implementation returns "Iterable". It is overridden for the basic
+ * collection kinds "Seq", "IndexedSeq", "LinearSeq", "Buffer", "Set", "Map",
+ * "SortedSet", "SortedMap" and "View".
+ *
+ * @return a string representation which starts the result of `toString`
+ * applied to this $coll. By default the string prefix is the
+ * simple name of the collection class $coll.
+ */
+ protected[this] def className: String = stringPrefix
+
+ /** Forwarder to `className` for use in `scala.runtime.ScalaRunTime`.
+ *
+ * This allows the proper visibility for `className` to be
+ * published, but provides the exclusive access needed by
+ * `scala.runtime.ScalaRunTime.stringOf` (and a few tests in
+ * the test suite).
+ */
+ private[scala] final def collectionClassName: String = className
+
+ @deprecatedOverriding("Override className instead", "2.13.0")
+ protected[this] def stringPrefix: String = "Iterable"
+
+ /** Converts this $coll to a string.
+ *
+ * @return a string representation of this collection. By default this
+ * string consists of the `className` of this $coll, followed
+ * by all elements separated by commas and enclosed in parentheses.
+ */
+ override def toString = mkString(className + "(", ", ", ")")
+
+ /** Analogous to `zip` except that the elements in each collection are not consumed until a strict operation is
+ * invoked on the returned `LazyZip2` decorator.
+ *
+ * Calls to `lazyZip` can be chained to support higher arities (up to 4) without incurring the expense of
+ * constructing and deconstructing intermediary tuples.
+ *
+ * {{{
+ * val xs = List(1, 2, 3)
+ * val res = (xs lazyZip xs lazyZip xs lazyZip xs).map((a, b, c, d) => a + b + c + d)
+ * // res == List(4, 8, 12)
+ * }}}
+ *
+ * @param that the iterable providing the second element of each eventual pair
+ * @tparam B the type of the second element in each eventual pair
+ * @return a decorator `LazyZip2` that allows strict operations to be performed on the lazily evaluated pairs
+ * or chained calls to `lazyZip`. Implicit conversion to `Iterable[(A, B)]` is also supported.
+ */
+ def lazyZip[B](that: Iterable[B]): LazyZip2[A, B, this.type] = new LazyZip2(this, this, that)
+}
+
+/** Base trait for Iterable operations
+ *
+ * =VarianceNote=
+ *
+ * We require that for all child classes of Iterable the variance of
+ * the child class and the variance of the `C` parameter passed to `IterableOps`
+ * are the same. We cannot express this since we lack variance polymorphism. That's
+ * why we have to resort at some places to write `C[A @uncheckedVariance]`.
+ *
+ * @tparam CC type constructor of the collection (e.g. `List`, `Set`). Operations returning a collection
+ * with a different type of element `B` (e.g. `map`) return a `CC[B]`.
+ * @tparam C type of the collection (e.g. `List[Int]`, `String`, `BitSet`). Operations returning a collection
+ * with the same type of element (e.g. `drop`, `filter`) return a `C`.
+ *
+ * @define Coll Iterable
+ * @define coll iterable collection
+ * @define orderDependent
+ *
+ * Note: might return different results for different runs, unless the underlying collection type is ordered.
+ * @define orderDependentFold
+ *
+ * Note: might return different results for different runs, unless the
+ * underlying collection type is ordered or the operator is associative
+ * and commutative.
+ * @define mayNotTerminateInf
+ *
+ * Note: may not terminate for infinite-sized collections.
+ * @define willNotTerminateInf
+ *
+ * Note: will not terminate for infinite-sized collections.
+ * @define undefinedorder
+ * The order in which operations are performed on elements is unspecified
+ * and may be nondeterministic.
+ */
+trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] with IterableOnceOps[A, CC, C] {
+ /**
+ * @return This collection as an `Iterable[A]`. No new collection will be built if `this` is already an `Iterable[A]`.
+ */
+ // Should be `protected def asIterable`, or maybe removed altogether if it's not needed
+ @deprecated("toIterable is internal and will be made protected; its name is similar to `toList` or `toSeq`, but it doesn't copy non-immutable collections", "2.13.7")
+ def toIterable: Iterable[A]
+
+ /** Converts this $coll to an unspecified Iterable. Will return
+ * the same collection if this instance is already Iterable.
+ * @return An Iterable containing all elements of this $coll.
+ */
+ @deprecated("toTraversable is internal and will be made protected; its name is similar to `toList` or `toSeq`, but it doesn't copy non-immutable collections", "2.13.0")
+ final def toTraversable: Traversable[A] = toIterable
+
+ override def isTraversableAgain: Boolean = true
+
+ /**
+ * @return This collection as a `C`.
+ */
+ protected def coll: C
+
+ @deprecated("Use coll instead of repr in a collection implementation, use the collection value itself from the outside", "2.13.0")
+ final def repr: C = coll
+
+ /**
+ * Defines how to turn a given `Iterable[A]` into a collection of type `C`.
+ *
+ * This process can be done in a strict way or a non-strict way (ie. without evaluating
+ * the elements of the resulting collections). In other words, this methods defines
+ * the evaluation model of the collection.
+ *
+ * @note When implementing a custom collection type and refining `C` to the new type, this
+ * method needs to be overridden (the compiler will issue an error otherwise). In the
+ * common case where `C =:= CC[A]`, this can be done by mixing in the
+ * [[scala.collection.IterableFactoryDefaults]] trait, which implements the method using
+ * [[iterableFactory]].
+ *
+ * @note As witnessed by the `@uncheckedVariance` annotation, using this method
+ * might be unsound. However, as long as it is called with an
+ * `Iterable[A]` obtained from `this` collection (as it is the case in the
+ * implementations of operations where we use a `View[A]`), it is safe.
+ */
+ protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]): C
+
+ /** The companion object of this ${coll}, providing various factory methods.
+ *
+ * @note When implementing a custom collection type and refining `CC` to the new type, this
+ * method needs to be overridden to return a factory for the new type (the compiler will
+ * issue an error otherwise).
+ */
+ def iterableFactory: IterableFactory[CC]
+
+ @deprecated("Use iterableFactory instead", "2.13.0")
+ @deprecatedOverriding("Use iterableFactory instead", "2.13.0")
+ @`inline` def companion: IterableFactory[CC] = iterableFactory
+
+ /**
+ * @return a strict builder for the same collection type.
+ *
+ * Note that in the case of lazy collections (e.g. [[scala.collection.View]] or [[scala.collection.immutable.LazyList]]),
+ * it is possible to implement this method but the resulting `Builder` will break laziness.
+ * As a consequence, operations should preferably be implemented with `fromSpecific`
+ * instead of this method.
+ *
+ * @note When implementing a custom collection type and refining `C` to the new type, this
+ * method needs to be overridden (the compiler will issue an error otherwise). In the
+ * common case where `C =:= CC[A]`, this can be done by mixing in the
+ * [[scala.collection.IterableFactoryDefaults]] trait, which implements the method using
+ * [[iterableFactory]].
+ *
+ * @note As witnessed by the `@uncheckedVariance` annotation, using this method might
+ * be unsound. However, as long as the returned builder is only fed
+ * with `A` values taken from `this` instance, it is safe.
+ */
+ protected def newSpecificBuilder: Builder[A @uncheckedVariance, C]
+
+ /** The empty iterable of the same type as this iterable.
+ *
+ * @return an empty iterable of type `C`.
+ */
+ def empty: C = fromSpecific(Nil)
+
+ /** Selects the first element of this $coll.
+ * $orderDependent
+ * @return the first element of this $coll.
+ * @throws NoSuchElementException if the $coll is empty.
+ */
+ def head: A = iterator.next()
+
+ /** Optionally selects the first element.
+ * $orderDependent
+ * @return the first element of this $coll if it is nonempty,
+ * `None` if it is empty.
+ */
+ def headOption: Option[A] = {
+ val it = iterator
+ if (it.hasNext) Some(it.next()) else None
+ }
+
+ /** Selects the last element.
+ * $orderDependent
+ * @return The last element of this $coll.
+ * @throws NoSuchElementException If the $coll is empty.
+ */
+ def last: A = {
+ val it = iterator
+ var lst = it.next()
+ while (it.hasNext) lst = it.next()
+ lst
+ }
+
+ /** Optionally selects the last element.
+ * $orderDependent
+ * @return the last element of this $coll$ if it is nonempty,
+ * `None` if it is empty.
+ */
+ def lastOption: Option[A] = if (isEmpty) None else Some(last)
+
+ /** A view over the elements of this collection. */
+ def view: View[A] = View.fromIteratorProvider(() => iterator)
+
+ /** Compares the size of this $coll to a test value.
+ *
+ * @param otherSize the test value that gets compared with the size.
+ * @return A value `x` where
+ * {{{
+ * x < 0 if this.size < otherSize
+ * x == 0 if this.size == otherSize
+ * x > 0 if this.size > otherSize
+ * }}}
+ *
+ * The method as implemented here does not call `size` directly; its running time
+ * is `O(size min otherSize)` instead of `O(size)`. The method should be overridden
+ * if computing `size` is cheap and `knownSize` returns `-1`.
+ *
+ * @see [[sizeIs]]
+ */
+ def sizeCompare(otherSize: Int): Int = {
+ if (otherSize < 0) 1
+ else {
+ val known = knownSize
+ if (known >= 0) Integer.compare(known, otherSize)
+ else {
+ var i = 0
+ val it = iterator
+ while (it.hasNext) {
+ if (i == otherSize) return 1
+ it.next()
+ i += 1
+ }
+ i - otherSize
+ }
+ }
+ }
+
+ /** Returns a value class containing operations for comparing the size of this $coll to a test value.
+ *
+ * These operations are implemented in terms of [[sizeCompare(Int) `sizeCompare(Int)`]], and
+ * allow the following more readable usages:
+ *
+ * {{{
+ * this.sizeIs < size // this.sizeCompare(size) < 0
+ * this.sizeIs <= size // this.sizeCompare(size) <= 0
+ * this.sizeIs == size // this.sizeCompare(size) == 0
+ * this.sizeIs != size // this.sizeCompare(size) != 0
+ * this.sizeIs >= size // this.sizeCompare(size) >= 0
+ * this.sizeIs > size // this.sizeCompare(size) > 0
+ * }}}
+ */
+ @inline final def sizeIs: IterableOps.SizeCompareOps = new IterableOps.SizeCompareOps(this)
+
+ /** Compares the size of this $coll to the size of another `Iterable`.
+ *
+ * @param that the `Iterable` whose size is compared with this $coll's size.
+ * @return A value `x` where
+ * {{{
+ * x < 0 if this.size < that.size
+ * x == 0 if this.size == that.size
+ * x > 0 if this.size > that.size
+ * }}}
+ *
+ * The method as implemented here does not call `size` directly; its running time
+ * is `O(this.size min that.size)` instead of `O(this.size + that.size)`.
+ * The method should be overridden if computing `size` is cheap and `knownSize` returns `-1`.
+ */
+ def sizeCompare(that: Iterable[_]): Int = {
+ val thatKnownSize = that.knownSize
+
+ if (thatKnownSize >= 0) this sizeCompare thatKnownSize
+ else {
+ val thisKnownSize = this.knownSize
+
+ if (thisKnownSize >= 0) {
+ val res = that sizeCompare thisKnownSize
+ // can't just invert the result, because `-Int.MinValue == Int.MinValue`
+ if (res == Int.MinValue) 1 else -res
+ } else {
+ val thisIt = this.iterator
+ val thatIt = that.iterator
+ while (thisIt.hasNext && thatIt.hasNext) {
+ thisIt.next()
+ thatIt.next()
+ }
+ java.lang.Boolean.compare(thisIt.hasNext, thatIt.hasNext)
+ }
+ }
+ }
+
+ /** A view over a slice of the elements of this collection. */
+ @deprecated("Use .view.slice(from, until) instead of .view(from, until)", "2.13.0")
+ def view(from: Int, until: Int): View[A] = view.slice(from, until)
+
+ /** Transposes this $coll of iterable collections into
+ * a $coll of ${coll}s.
+ *
+ * The resulting collection's type will be guided by the
+ * static type of $coll. For example:
+ *
+ * {{{
+ * val xs = List(
+ * Set(1, 2, 3),
+ * Set(4, 5, 6)).transpose
+ * // xs == List(
+ * // List(1, 4),
+ * // List(2, 5),
+ * // List(3, 6))
+ *
+ * val ys = Vector(
+ * List(1, 2, 3),
+ * List(4, 5, 6)).transpose
+ * // ys == Vector(
+ * // Vector(1, 4),
+ * // Vector(2, 5),
+ * // Vector(3, 6))
+ * }}}
+ *
+ * $willForceEvaluation
+ *
+ * @tparam B the type of the elements of each iterable collection.
+ * @param asIterable an implicit conversion which asserts that the
+ * element type of this $coll is an `Iterable`.
+ * @return a two-dimensional $coll of ${coll}s which has as ''n''th row
+ * the ''n''th column of this $coll.
+ * @throws IllegalArgumentException if all collections in this $coll
+ * are not of the same size.
+ */
+ def transpose[B](implicit asIterable: A => /*<:= headSize) fail
+ bs(i) += x
+ i += 1
+ }
+ if (i != headSize)
+ fail
+ }
+ iterableFactory.from(bs.map(_.result()))
+ }
+
+ def filter(pred: A => Boolean): C = fromSpecific(new View.Filter(this, pred, isFlipped = false))
+
+ def filterNot(pred: A => Boolean): C = fromSpecific(new View.Filter(this, pred, isFlipped = true))
+
+ /** Creates a non-strict filter of this $coll.
+ *
+ * Note: the difference between `c filter p` and `c withFilter p` is that
+ * the former creates a new collection, whereas the latter only
+ * restricts the domain of subsequent `map`, `flatMap`, `foreach`,
+ * and `withFilter` operations.
+ * $orderDependent
+ *
+ * @param p the predicate used to test elements.
+ * @return an object of class `WithFilter`, which supports
+ * `map`, `flatMap`, `foreach`, and `withFilter` operations.
+ * All these operations apply to those elements of this $coll
+ * which satisfy the predicate `p`.
+ */
+ def withFilter(p: A => Boolean): collection.WithFilter[A, CC] = new IterableOps.WithFilter(this, p)
+
+ /** A pair of, first, all elements that satisfy predicate `p` and, second,
+ * all elements that do not.
+ *
+ * The two $coll correspond to the result of [[filter]] and [[filterNot]], respectively.
+ *
+ * The default implementation provided here needs to traverse the collection twice.
+ * Strict collections have an overridden version of `partition` in `StrictOptimizedIterableOps`,
+ * which requires only a single traversal.
+ */
+ def partition(p: A => Boolean): (C, C) = {
+ val first = new View.Filter(this, p, isFlipped = false)
+ val second = new View.Filter(this, p, isFlipped = true)
+ (fromSpecific(first), fromSpecific(second))
+ }
+
+ override def splitAt(n: Int): (C, C) = (take(n), drop(n))
+
+ def take(n: Int): C = fromSpecific(new View.Take(this, n))
+
+ /** Selects the last ''n'' elements.
+ * $orderDependent
+ * @param n the number of elements to take from this $coll.
+ * @return a $coll consisting only of the last `n` elements of this $coll,
+ * or else the whole $coll, if it has less than `n` elements.
+ * If `n` is negative, returns an empty $coll.
+ */
+ def takeRight(n: Int): C = fromSpecific(new View.TakeRight(this, n))
+
+ /** Takes longest prefix of elements that satisfy a predicate.
+ * $orderDependent
+ * @param p The predicate used to test elements.
+ * @return the longest prefix of this $coll whose elements all satisfy
+ * the predicate `p`.
+ */
+ def takeWhile(p: A => Boolean): C = fromSpecific(new View.TakeWhile(this, p))
+
+ def span(p: A => Boolean): (C, C) = (takeWhile(p), dropWhile(p))
+
+ def drop(n: Int): C = fromSpecific(new View.Drop(this, n))
+
+ /** Selects all elements except last ''n'' ones.
+ * $orderDependent
+ * @param n the number of elements to drop from this $coll.
+ * @return a $coll consisting of all elements of this $coll except the last `n` ones, or else the
+ * empty $coll, if this $coll has less than `n` elements.
+ * If `n` is negative, don't drop any elements.
+ */
+ def dropRight(n: Int): C = fromSpecific(new View.DropRight(this, n))
+
+ def dropWhile(p: A => Boolean): C = fromSpecific(new View.DropWhile(this, p))
+
+ /** Partitions elements in fixed size ${coll}s.
+ * @see [[scala.collection.Iterator]], method `grouped`
+ *
+ * @param size the number of elements per group
+ * @return An iterator producing ${coll}s of size `size`, except the
+ * last will be less than size `size` if the elements don't divide evenly.
+ */
+ def grouped(size: Int): Iterator[C] =
+ iterator.grouped(size).map(fromSpecific)
+
+ /** Groups elements in fixed size blocks by passing a "sliding window"
+ * over them (as opposed to partitioning them, as is done in `grouped`).
+ *
+ * An empty collection returns an empty iterator, and a non-empty
+ * collection containing fewer elements than the window size returns
+ * an iterator that will produce the original collection as its only
+ * element.
+ * @see [[scala.collection.Iterator]], method `sliding`
+ *
+ * @param size the number of elements per group
+ * @return An iterator producing ${coll}s of size `size`, except for a
+ * non-empty collection with less than `size` elements, which
+ * returns an iterator that produces the source collection itself
+ * as its only element.
+ * @example `List().sliding(2) = empty iterator`
+ * @example `List(1).sliding(2) = Iterator(List(1))`
+ * @example `List(1, 2).sliding(2) = Iterator(List(1, 2))`
+ * @example `List(1, 2, 3).sliding(2) = Iterator(List(1, 2), List(2, 3))`
+ */
+ def sliding(size: Int): Iterator[C] = sliding(size, 1)
+
+ /** Groups elements in fixed size blocks by passing a "sliding window"
+ * over them (as opposed to partitioning them, as is done in `grouped`).
+ *
+ * The returned iterator will be empty when called on an empty collection.
+ * The last element the iterator produces may be smaller than the window
+ * size when the original collection isn't exhausted by the window before
+ * it and its last element isn't skipped by the step before it.
+ *
+ * @see [[scala.collection.Iterator]], method `sliding`
+ *
+ * @param size the number of elements per group
+ * @param step the distance between the first elements of successive
+ * groups
+ * @return An iterator producing ${coll}s of size `size`, except the last
+ * element (which may be the only element) will be smaller
+ * if there are fewer than `size` elements remaining to be grouped.
+ * @example `List(1, 2, 3, 4, 5).sliding(2, 2) = Iterator(List(1, 2), List(3, 4), List(5))`
+ * @example `List(1, 2, 3, 4, 5, 6).sliding(2, 3) = Iterator(List(1, 2), List(4, 5))`
+ */
+ def sliding(size: Int, step: Int): Iterator[C] =
+ iterator.sliding(size, step).map(fromSpecific)
+
+ /** The rest of the collection without its first element. */
+ def tail: C = {
+ if (isEmpty) throw new UnsupportedOperationException
+ drop(1)
+ }
+
+ /** The initial part of the collection without its last element.
+ * $willForceEvaluation
+ */
+ def init: C = {
+ if (isEmpty) throw new UnsupportedOperationException
+ dropRight(1)
+ }
+
+ def slice(from: Int, until: Int): C =
+ fromSpecific(new View.Drop(new View.Take(this, until), from))
+
+ /** Partitions this $coll into a map of ${coll}s according to some discriminator function.
+ *
+ * $willForceEvaluation
+ *
+ * @param f the discriminator function.
+ * @tparam K the type of keys returned by the discriminator function.
+ * @return A map from keys to ${coll}s such that the following invariant holds:
+ * {{{
+ * (xs groupBy f)(k) = xs filter (x => f(x) == k)
+ * }}}
+ * That is, every key `k` is bound to a $coll of those elements `x`
+ * for which `f(x)` equals `k`.
+ *
+ */
+ def groupBy[K](f: A => K): immutable.Map[K, C] = {
+ val m = mutable.Map.empty[K, Builder[A, C]]
+ val it = iterator
+ while (it.hasNext) {
+ val elem = it.next()
+ val key = f(elem)
+ val bldr = m.getOrElseUpdate(key, newSpecificBuilder)
+ bldr += elem
+ }
+ var result = immutable.HashMap.empty[K, C]
+ val mapIt = m.iterator
+ while (mapIt.hasNext) {
+ val (k, v) = mapIt.next()
+ result = result.updated(k, v.result())
+ }
+ result
+ }
+
+ /**
+ * Partitions this $coll into a map of ${coll}s according to a discriminator function `key`.
+ * Each element in a group is transformed into a value of type `B` using the `value` function.
+ *
+ * It is equivalent to `groupBy(key).mapValues(_.map(f))`, but more efficient.
+ *
+ * {{{
+ * case class User(name: String, age: Int)
+ *
+ * def namesByAge(users: Seq[User]): Map[Int, Seq[String]] =
+ * users.groupMap(_.age)(_.name)
+ * }}}
+ *
+ * $willForceEvaluation
+ *
+ * @param key the discriminator function
+ * @param f the element transformation function
+ * @tparam K the type of keys returned by the discriminator function
+ * @tparam B the type of values returned by the transformation function
+ */
+ def groupMap[K, B](key: A => K)(f: A => B): immutable.Map[K, CC[B]] = {
+ val m = mutable.Map.empty[K, Builder[B, CC[B]]]
+ for (elem <- this) {
+ val k = key(elem)
+ val bldr = m.getOrElseUpdate(k, iterableFactory.newBuilder[B])
+ bldr += f(elem)
+ }
+ class Result extends runtime.AbstractFunction1[(K, Builder[B, CC[B]]), Unit] {
+ var built = immutable.Map.empty[K, CC[B]]
+ def apply(kv: (K, Builder[B, CC[B]])) =
+ built = built.updated(kv._1, kv._2.result())
+ }
+ val result = new Result
+ m.foreach(result)
+ result.built
+ }
+
+ /**
+ * Partitions this $coll into a map according to a discriminator function `key`. All the values that
+ * have the same discriminator are then transformed by the `f` function and then reduced into a
+ * single value with the `reduce` function.
+ *
+ * It is equivalent to `groupBy(key).mapValues(_.map(f).reduce(reduce))`, but more efficient.
+ *
+ * {{{
+ * def occurrences[A](as: Seq[A]): Map[A, Int] =
+ * as.groupMapReduce(identity)(_ => 1)(_ + _)
+ * }}}
+ *
+ * $willForceEvaluation
+ */
+ def groupMapReduce[K, B](key: A => K)(f: A => B)(reduce: (B, B) => B): immutable.Map[K, B] = {
+ val m = mutable.Map.empty[K, B]
+ for (elem <- this) {
+ val k = key(elem)
+ val v =
+ m.get(k) match {
+ case Some(b) => reduce(b, f(elem))
+ case None => f(elem)
+ }
+ m.put(k, v)
+ }
+ m.to(immutable.Map)
+ }
+
+ /** Computes a prefix scan of the elements of the collection.
+ *
+ * Note: The neutral element `z` may be applied more than once.
+ *
+ * @tparam B element type of the resulting collection
+ * @param z neutral element for the operator `op`
+ * @param op the associative operator for the scan
+ *
+ * @return a new $coll containing the prefix scan of the elements in this $coll
+ */
+ def scan[B >: A](z: B)(op: (B, B) => B): CC[B] = scanLeft(z)(op)
+
+ def scanLeft[B](z: B)(op: (B, A) => B): CC[B] = iterableFactory.from(new View.ScanLeft(this, z, op))
+
+ /** Produces a collection containing cumulative results of applying the operator going right to left.
+ * The head of the collection is the last cumulative result.
+ * $willNotTerminateInf
+ * $orderDependent
+ * $willForceEvaluation
+ *
+ * Example:
+ * {{{
+ * List(1, 2, 3, 4).scanRight(0)(_ + _) == List(10, 9, 7, 4, 0)
+ * }}}
+ *
+ * @tparam B the type of the elements in the resulting collection
+ * @param z the initial value
+ * @param op the binary operator applied to the intermediate result and the element
+ * @return collection with intermediate results
+ */
+ def scanRight[B](z: B)(op: (A, B) => B): CC[B] = {
+ class Scanner extends runtime.AbstractFunction1[A, Unit] {
+ var acc = z
+ var scanned = acc :: immutable.Nil
+ def apply(x: A) = {
+ acc = op(x, acc)
+ scanned ::= acc
+ }
+ }
+ val scanner = new Scanner
+ reversed.foreach(scanner)
+ iterableFactory.from(scanner.scanned)
+ }
+
+ def map[B](f: A => B): CC[B] = iterableFactory.from(new View.Map(this, f))
+
+ def flatMap[B](f: A => IterableOnce[B]): CC[B] = iterableFactory.from(new View.FlatMap(this, f))
+
+ def flatten[B](implicit asIterable: A => IterableOnce[B]): CC[B] = flatMap(asIterable)
+
+ def collect[B](pf: PartialFunction[A, B]): CC[B] =
+ iterableFactory.from(new View.Collect(this, pf))
+
+ /** Applies a function `f` to each element of the $coll and returns a pair of ${coll}s: the first one
+ * made of those values returned by `f` that were wrapped in [[scala.util.Left]], and the second
+ * one made of those wrapped in [[scala.util.Right]].
+ *
+ * Example:
+ * {{{
+ * val xs = $Coll(1, "one", 2, "two", 3, "three") partitionMap {
+ * case i: Int => Left(i)
+ * case s: String => Right(s)
+ * }
+ * // xs == ($Coll(1, 2, 3),
+ * // $Coll(one, two, three))
+ * }}}
+ *
+ * @tparam A1 the element type of the first resulting collection
+ * @tparam A2 the element type of the second resulting collection
+ * @param f the 'split function' mapping the elements of this $coll to an [[scala.util.Either]]
+ *
+ * @return a pair of ${coll}s: the first one made of those values returned by `f` that were wrapped in [[scala.util.Left]],
+ * and the second one made of those wrapped in [[scala.util.Right]].
+ */
+ def partitionMap[A1, A2](f: A => Either[A1, A2]): (CC[A1], CC[A2]) = {
+ val left: View[A1] = new LeftPartitionMapped(this, f)
+ val right: View[A2] = new RightPartitionMapped(this, f)
+ (iterableFactory.from(left), iterableFactory.from(right))
+ }
+
+ /** Returns a new $coll containing the elements from the left hand operand followed by the elements from the
+ * right hand operand. The element type of the $coll is the most specific superclass encompassing
+ * the element types of the two operands.
+ *
+ * @param suffix the iterable to append.
+ * @tparam B the element type of the returned collection.
+ * @return a new $coll which contains all elements
+ * of this $coll followed by all elements of `suffix`.
+ */
+ def concat[B >: A](suffix: IterableOnce[B]): CC[B] = iterableFactory.from(suffix match {
+ case xs: Iterable[B] => new View.Concat(this, xs)
+ case xs => iterator ++ suffix.iterator
+ })
+
+ /** Alias for `concat` */
+ @`inline` final def ++ [B >: A](suffix: IterableOnce[B]): CC[B] = concat(suffix)
+
+ /** Returns a $coll formed from this $coll and another iterable collection
+ * by combining corresponding elements in pairs.
+ * If one of the two collections is longer than the other, its remaining elements are ignored.
+ *
+ * @param that The iterable providing the second half of each result pair
+ * @tparam B the type of the second half of the returned pairs
+ * @return a new $coll containing pairs consisting of corresponding elements of this $coll and `that`.
+ * The length of the returned collection is the minimum of the lengths of this $coll and `that`.
+ */
+ def zip[B](that: IterableOnce[B]): CC[(A @uncheckedVariance, B)] = iterableFactory.from(that match { // sound bcs of VarianceNote
+ case that: Iterable[B] => new View.Zip(this, that)
+ case _ => iterator.zip(that)
+ })
+
+ def zipWithIndex: CC[(A @uncheckedVariance, Int)] = iterableFactory.from(new View.ZipWithIndex(this))
+
+ /** Returns a $coll formed from this $coll and another iterable collection
+ * by combining corresponding elements in pairs.
+ * If one of the two collections is shorter than the other,
+ * placeholder elements are used to extend the shorter collection to the length of the longer.
+ *
+ * @param that the iterable providing the second half of each result pair
+ * @param thisElem the element to be used to fill up the result if this $coll is shorter than `that`.
+ * @param thatElem the element to be used to fill up the result if `that` is shorter than this $coll.
+ * @return a new $coll containing pairs consisting of
+ * corresponding elements of this $coll and `that`. The length
+ * of the returned collection is the maximum of the lengths of this $coll and `that`.
+ * If this $coll is shorter than `that`, `thisElem` values are used to pad the result.
+ * If `that` is shorter than this $coll, `thatElem` values are used to pad the result.
+ */
+ def zipAll[A1 >: A, B](that: Iterable[B], thisElem: A1, thatElem: B): CC[(A1, B)] = iterableFactory.from(new View.ZipAll(this, that, thisElem, thatElem))
+
+ /** Converts this $coll of pairs into two collections of the first and second
+ * half of each pair.
+ *
+ * {{{
+ * val xs = $Coll(
+ * (1, "one"),
+ * (2, "two"),
+ * (3, "three")).unzip
+ * // xs == ($Coll(1, 2, 3),
+ * // $Coll(one, two, three))
+ * }}}
+ *
+ * @tparam A1 the type of the first half of the element pairs
+ * @tparam A2 the type of the second half of the element pairs
+ * @param asPair an implicit conversion which asserts that the element type
+ * of this $coll is a pair.
+ * @return a pair of ${coll}s, containing the first, respectively second
+ * half of each element pair of this $coll.
+ */
+ def unzip[A1, A2](implicit asPair: A => (A1, A2)): (CC[A1], CC[A2]) = {
+ val first: View[A1] = new View.Map[A, A1](this, asPair(_)._1)
+ val second: View[A2] = new View.Map[A, A2](this, asPair(_)._2)
+ (iterableFactory.from(first), iterableFactory.from(second))
+ }
+
+ /** Converts this $coll of triples into three collections of the first, second,
+ * and third element of each triple.
+ *
+ * {{{
+ * val xs = $Coll(
+ * (1, "one", '1'),
+ * (2, "two", '2'),
+ * (3, "three", '3')).unzip3
+ * // xs == ($Coll(1, 2, 3),
+ * // $Coll(one, two, three),
+ * // $Coll(1, 2, 3))
+ * }}}
+ *
+ * @tparam A1 the type of the first member of the element triples
+ * @tparam A2 the type of the second member of the element triples
+ * @tparam A3 the type of the third member of the element triples
+ * @param asTriple an implicit conversion which asserts that the element type
+ * of this $coll is a triple.
+ * @return a triple of ${coll}s, containing the first, second, respectively
+ * third member of each element triple of this $coll.
+ */
+ def unzip3[A1, A2, A3](implicit asTriple: A => (A1, A2, A3)): (CC[A1], CC[A2], CC[A3]) = {
+ val first: View[A1] = new View.Map[A, A1](this, asTriple(_)._1)
+ val second: View[A2] = new View.Map[A, A2](this, asTriple(_)._2)
+ val third: View[A3] = new View.Map[A, A3](this, asTriple(_)._3)
+ (iterableFactory.from(first), iterableFactory.from(second), iterableFactory.from(third))
+ }
+
+ /** Iterates over the tails of this $coll. The first value will be this
+ * $coll and the final one will be an empty $coll, with the intervening
+ * values the results of successive applications of `tail`.
+ *
+ * @return an iterator over all the tails of this $coll
+ * @example `List(1,2,3).tails = Iterator(List(1,2,3), List(2,3), List(3), Nil)`
+ */
+ def tails: Iterator[C] = iterateUntilEmpty(_.tail)
+
+ /** Iterates over the inits of this $coll. The first value will be this
+ * $coll and the final one will be an empty $coll, with the intervening
+ * values the results of successive applications of `init`.
+ *
+ * $willForceEvaluation
+ *
+ * @return an iterator over all the inits of this $coll
+ * @example `List(1,2,3).inits = Iterator(List(1,2,3), List(1,2), List(1), Nil)`
+ */
+ def inits: Iterator[C] = iterateUntilEmpty(_.init)
+
+ override def tapEach[U](f: A => U): C = fromSpecific(new View.Map(this, { (a: A) => f(a); a }))
+
+ // A helper for tails and inits.
+ private[this] def iterateUntilEmpty(f: Iterable[A] => Iterable[A]): Iterator[C] = {
+ // toIterable ties the knot between `this: IterableOnceOps[A, CC, C]` and `this.tail: C`
+ // `this.tail.tail` doesn't compile as `C` is unbounded
+ // `Iterable.from(this)` would eagerly copy non-immutable collections
+ val it = Iterator.iterate(toIterable: @nowarn("cat=deprecation"))(f).takeWhile(_.nonEmpty)
+ (it ++ Iterator.single(Iterable.empty)).map(fromSpecific)
+ }
+
+ @deprecated("Use ++ instead of ++: for collections of type Iterable", "2.13.0")
+ def ++:[B >: A](that: IterableOnce[B]): CC[B] = iterableFactory.from(that match {
+ case xs: Iterable[B] => new View.Concat(xs, this)
+ case _ => that.iterator ++ iterator
+ })
+}
+
+object IterableOps {
+
+ /** Operations for comparing the size of a collection to a test value.
+ *
+ * These operations are implemented in terms of
+ * [[scala.collection.IterableOps.sizeCompare(Int) `sizeCompare(Int)`]].
+ */
+ final class SizeCompareOps private[collection](val it: IterableOps[_, AnyConstr, _]) extends AnyVal {
+ /** Tests if the size of the collection is less than some value. */
+ @inline def <(size: Int): Boolean = it.sizeCompare(size) < 0
+ /** Tests if the size of the collection is less than or equal to some value. */
+ @inline def <=(size: Int): Boolean = it.sizeCompare(size) <= 0
+ /** Tests if the size of the collection is equal to some value. */
+ @inline def ==(size: Int): Boolean = it.sizeCompare(size) == 0
+ /** Tests if the size of the collection is not equal to some value. */
+ @inline def !=(size: Int): Boolean = it.sizeCompare(size) != 0
+ /** Tests if the size of the collection is greater than or equal to some value. */
+ @inline def >=(size: Int): Boolean = it.sizeCompare(size) >= 0
+ /** Tests if the size of the collection is greater than some value. */
+ @inline def >(size: Int): Boolean = it.sizeCompare(size) > 0
+ }
+
+ /** A trait that contains just the `map`, `flatMap`, `foreach` and `withFilter` methods
+ * of trait `Iterable`.
+ *
+ * @tparam A Element type (e.g. `Int`)
+ * @tparam CC Collection type constructor (e.g. `List`)
+ *
+ * @define coll collection
+ */
+ @SerialVersionUID(3L)
+ class WithFilter[+A, +CC[_]](
+ self: IterableOps[A, CC, _],
+ p: A => Boolean
+ ) extends collection.WithFilter[A, CC] with Serializable {
+
+ protected def filtered: Iterable[A] =
+ new View.Filter(self, p, isFlipped = false)
+
+ def map[B](f: A => B): CC[B] =
+ self.iterableFactory.from(new View.Map(filtered, f))
+
+ def flatMap[B](f: A => IterableOnce[B]): CC[B] =
+ self.iterableFactory.from(new View.FlatMap(filtered, f))
+
+ def foreach[U](f: A => U): Unit = filtered.foreach(f)
+
+ def withFilter(q: A => Boolean): WithFilter[A, CC] =
+ new WithFilter(self, (a: A) => p(a) && q(a))
+
+ }
+
+}
+
+@SerialVersionUID(3L)
+object Iterable extends IterableFactory.Delegate[Iterable](immutable.Iterable) {
+
+ def single[A](a: A): Iterable[A] = new AbstractIterable[A] {
+ override def iterator = Iterator.single(a)
+ override def knownSize = 1
+ override def head = a
+ override def headOption: Some[A] = Some(a)
+ override def last = a
+ override def lastOption: Some[A] = Some(a)
+ override def view: View.Single[A] = new View.Single(a)
+ override def take(n: Int) = if (n > 0) this else Iterable.empty
+ override def takeRight(n: Int) = if (n > 0) this else Iterable.empty
+ override def drop(n: Int) = if (n > 0) Iterable.empty else this
+ override def dropRight(n: Int) = if (n > 0) Iterable.empty else this
+ override def tail: Iterable[Nothing] = Iterable.empty
+ override def init: Iterable[Nothing] = Iterable.empty
+ }
+}
+
+/** Explicit instantiation of the `Iterable` trait to reduce class file size in subclasses. */
+abstract class AbstractIterable[+A] extends Iterable[A]
+
+/** This trait provides default implementations for the factory methods `fromSpecific` and
+ * `newSpecificBuilder` that need to be refined when implementing a collection type that refines
+ * the `CC` and `C` type parameters.
+ *
+ * The default implementations in this trait can be used in the common case when `CC[A]` is the
+ * same as `C`.
+ */
+trait IterableFactoryDefaults[+A, +CC[x] <: IterableOps[x, CC, CC[x]]] extends IterableOps[A, CC, CC[A @uncheckedVariance]] {
+ protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]): CC[A @uncheckedVariance] = iterableFactory.from(coll)
+ protected def newSpecificBuilder: Builder[A @uncheckedVariance, CC[A @uncheckedVariance]] = iterableFactory.newBuilder[A]
+
+ // overridden for efficiency, since we know CC[A] =:= C
+ override def empty: CC[A @uncheckedVariance] = iterableFactory.empty
+}
+
+/** This trait provides default implementations for the factory methods `fromSpecific` and
+ * `newSpecificBuilder` that need to be refined when implementing a collection type that refines
+ * the `CC` and `C` type parameters. It is used for collections that have an additional constraint,
+ * expressed by the `evidenceIterableFactory` method.
+ *
+ * The default implementations in this trait can be used in the common case when `CC[A]` is the
+ * same as `C`.
+ */
+trait EvidenceIterableFactoryDefaults[+A, +CC[x] <: IterableOps[x, CC, CC[x]], Ev[_]] extends IterableOps[A, CC, CC[A @uncheckedVariance]] {
+ protected def evidenceIterableFactory: EvidenceIterableFactory[CC, Ev]
+ implicit protected def iterableEvidence: Ev[A @uncheckedVariance]
+ override protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]): CC[A @uncheckedVariance] = evidenceIterableFactory.from(coll)
+ override protected def newSpecificBuilder: Builder[A @uncheckedVariance, CC[A @uncheckedVariance]] = evidenceIterableFactory.newBuilder[A]
+ override def empty: CC[A @uncheckedVariance] = evidenceIterableFactory.empty
+}
+
+/** This trait provides default implementations for the factory methods `fromSpecific` and
+ * `newSpecificBuilder` that need to be refined when implementing a collection type that refines
+ * the `CC` and `C` type parameters. It is used for sorted sets.
+ *
+ * Note that in sorted sets, the `CC` type of the set is not the same as the `CC` type for the
+ * underlying iterable (which is fixed to `Set` in [[SortedSetOps]]). This trait has therefore
+ * two type parameters `CC` and `WithFilterCC`. The `withFilter` method inherited from
+ * `IterableOps` is overridden with a compatible default implementation.
+ *
+ * The default implementations in this trait can be used in the common case when `CC[A]` is the
+ * same as `C`.
+ */
+trait SortedSetFactoryDefaults[+A,
+ +CC[X] <: SortedSet[X] with SortedSetOps[X, CC, CC[X]],
+ +WithFilterCC[x] <: IterableOps[x, WithFilterCC, WithFilterCC[x]] with Set[x]] extends SortedSetOps[A @uncheckedVariance, CC, CC[A @uncheckedVariance]] {
+ self: IterableOps[A, WithFilterCC, _] =>
+
+ override protected def fromSpecific(coll: IterableOnce[A @uncheckedVariance]): CC[A @uncheckedVariance] = sortedIterableFactory.from(coll)(using ordering)
+ override protected def newSpecificBuilder: mutable.Builder[A @uncheckedVariance, CC[A @uncheckedVariance]] = sortedIterableFactory.newBuilder[A](using ordering)
+ override def empty: CC[A @uncheckedVariance] = sortedIterableFactory.empty(using ordering)
+
+ override def withFilter(p: A => Boolean): SortedSetOps.WithFilter[A, WithFilterCC, CC] =
+ new SortedSetOps.WithFilter[A, WithFilterCC, CC](this, p)
+}
+
+
+/** This trait provides default implementations for the factory methods `fromSpecific` and
+ * `newSpecificBuilder` that need to be refined when implementing a collection type that refines
+ * the `CC` and `C` type parameters. It is used for maps.
+ *
+ * Note that in maps, the `CC` type of the map is not the same as the `CC` type for the
+ * underlying iterable (which is fixed to `Map` in [[MapOps]]). This trait has therefore
+ * two type parameters `CC` and `WithFilterCC`. The `withFilter` method inherited from
+ * `IterableOps` is overridden with a compatible default implementation.
+ *
+ * The default implementations in this trait can be used in the common case when `CC[A]` is the
+ * same as `C`.
+ */
+trait MapFactoryDefaults[K, +V,
+ +CC[x, y] <: IterableOps[(x, y), Iterable, Iterable[(x, y)]],
+ +WithFilterCC[x] <: IterableOps[x, WithFilterCC, WithFilterCC[x]] with Iterable[x]] extends MapOps[K, V, CC, CC[K, V @uncheckedVariance]] with IterableOps[(K, V), WithFilterCC, CC[K, V @uncheckedVariance]] {
+ override protected def fromSpecific(coll: IterableOnce[(K, V @uncheckedVariance)]): CC[K, V @uncheckedVariance] = mapFactory.from(coll)
+ override protected def newSpecificBuilder: mutable.Builder[(K, V @uncheckedVariance), CC[K, V @uncheckedVariance]] = mapFactory.newBuilder[K, V]
+ override def empty: CC[K, V @uncheckedVariance] = (this: AnyRef) match {
+ // Implemented here instead of in TreeSeqMap since overriding empty in TreeSeqMap is not forwards compatible (should be moved)
+ case self: immutable.TreeSeqMap[_, _] => immutable.TreeSeqMap.empty(self.orderedBy).asInstanceOf[CC[K, V]]
+ case _ => mapFactory.empty
+ }
+
+ override def withFilter(p: ((K, V)) => Boolean): MapOps.WithFilter[K, V, WithFilterCC, CC] =
+ new MapOps.WithFilter[K, V, WithFilterCC, CC](this, p)
+}
+
+/** This trait provides default implementations for the factory methods `fromSpecific` and
+ * `newSpecificBuilder` that need to be refined when implementing a collection type that refines
+ * the `CC` and `C` type parameters. It is used for sorted maps.
+ *
+ * Note that in sorted maps, the `CC` type of the map is not the same as the `CC` type for the
+ * underlying map (which is fixed to `Map` in [[SortedMapOps]]). This trait has therefore
+ * three type parameters `CC`, `WithFilterCC` and `UnsortedCC`. The `withFilter` method inherited
+ * from `IterableOps` is overridden with a compatible default implementation.
+ *
+ * The default implementations in this trait can be used in the common case when `CC[A]` is the
+ * same as `C`.
+ */
+trait SortedMapFactoryDefaults[K, +V,
+ +CC[x, y] <: Map[x, y] with SortedMapOps[x, y, CC, CC[x, y]] with UnsortedCC[x, y],
+ +WithFilterCC[x] <: IterableOps[x, WithFilterCC, WithFilterCC[x]] with Iterable[x],
+ +UnsortedCC[x, y] <: Map[x, y]] extends SortedMapOps[K, V, CC, CC[K, V @uncheckedVariance]] with MapOps[K, V, UnsortedCC, CC[K, V @uncheckedVariance]] {
+ self: IterableOps[(K, V), WithFilterCC, _] =>
+
+ override def empty: CC[K, V @uncheckedVariance] = sortedMapFactory.empty(using ordering)
+ override protected def fromSpecific(coll: IterableOnce[(K, V @uncheckedVariance)]): CC[K, V @uncheckedVariance] = sortedMapFactory.from(coll)(using ordering)
+ override protected def newSpecificBuilder: mutable.Builder[(K, V @uncheckedVariance), CC[K, V @uncheckedVariance]] = sortedMapFactory.newBuilder[K, V](using ordering)
+
+ override def withFilter(p: ((K, V)) => Boolean): collection.SortedMapOps.WithFilter[K, V, WithFilterCC, UnsortedCC, CC] =
+ new collection.SortedMapOps.WithFilter[K, V, WithFilterCC, UnsortedCC, CC](this, p)
+}
diff --git a/library/src/scala/collection/IterableOnce.scala b/library/src/scala/collection/IterableOnce.scala
new file mode 100644
index 000000000000..fc0f73ae7d7f
--- /dev/null
+++ b/library/src/scala/collection/IterableOnce.scala
@@ -0,0 +1,1514 @@
+/*
+ * 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 collection
+
+import scala.annotation.tailrec
+import scala.annotation.unchecked.uncheckedVariance
+import scala.collection.mutable.StringBuilder
+import scala.language.implicitConversions
+import scala.math.{Numeric, Ordering}
+import scala.reflect.ClassTag
+import scala.runtime.{AbstractFunction1, AbstractFunction2}
+
+/**
+ * A template trait for collections which can be traversed either once only
+ * or one or more times.
+ *
+ * Note: `IterableOnce` does not extend [[IterableOnceOps]]. This is different than the general
+ * design of the collections library, which uses the following pattern:
+ * {{{
+ * trait Seq extends Iterable with SeqOps
+ * trait SeqOps extends IterableOps
+ *
+ * trait IndexedSeq extends Seq with IndexedSeqOps
+ * trait IndexedSeqOps extends SeqOps
+ * }}}
+ *
+ * The goal is to provide a minimal interface without any sequential operations. This allows
+ * third-party extension like Scala parallel collections to integrate at the level of IterableOnce
+ * without inheriting unwanted implementations.
+ *
+ * @define coll collection
+ */
+trait IterableOnce[+A] extends Any {
+
+ /** An [[scala.collection.Iterator]] over the elements of this $coll.
+ *
+ * If an `IterableOnce` object is in fact an [[scala.collection.Iterator]], this method always returns itself,
+ * in its current state, but if it is an [[scala.collection.Iterable]], this method always returns a new
+ * [[scala.collection.Iterator]].
+ */
+ def iterator: Iterator[A]
+
+ /** Returns a [[scala.collection.Stepper]] for the elements of this collection.
+ *
+ * The Stepper enables creating a Java stream to operate on the collection, see
+ * [[scala.jdk.StreamConverters]]. For collections holding primitive values, the Stepper can be
+ * used as an iterator which doesn't box the elements.
+ *
+ * The implicit [[scala.collection.StepperShape]] parameter defines the resulting Stepper type according to the
+ * element type of this collection.
+ *
+ * - For collections of `Int`, `Short`, `Byte` or `Char`, an [[scala.collection.IntStepper]] is returned
+ * - For collections of `Double` or `Float`, a [[scala.collection.DoubleStepper]] is returned
+ * - For collections of `Long` a [[scala.collection.LongStepper]] is returned
+ * - For any other element type, an [[scala.collection.AnyStepper]] is returned
+ *
+ * Note that this method is overridden in subclasses and the return type is refined to
+ * `S with EfficientSplit`, for example [[scala.collection.IndexedSeqOps.stepper]]. For Steppers marked with
+ * [[scala.collection.Stepper.EfficientSplit]], the converters in [[scala.jdk.StreamConverters]]
+ * allow creating parallel streams, whereas bare Steppers can be converted only to sequential
+ * streams.
+ */
+ def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S = {
+ import convert.impl._
+ val s = shape.shape match {
+ case StepperShape.IntShape => new IntIteratorStepper (iterator.asInstanceOf[Iterator[Int]])
+ case StepperShape.LongShape => new LongIteratorStepper (iterator.asInstanceOf[Iterator[Long]])
+ case StepperShape.DoubleShape => new DoubleIteratorStepper(iterator.asInstanceOf[Iterator[Double]])
+ case _ => shape.seqUnbox(new AnyIteratorStepper[A](iterator))
+ }
+ s.asInstanceOf[S]
+ }
+
+ /** The number of elements in this $coll, if it can be cheaply computed,
+ * -1 otherwise. Cheaply usually means: Not requiring a collection traversal.
+ */
+ def knownSize: Int = -1
+}
+
+final class IterableOnceExtensionMethods[A](private val it: IterableOnce[A]) extends AnyVal {
+ @deprecated("Use .iterator.withFilter(...) instead", "2.13.0")
+ def withFilter(f: A => Boolean): Iterator[A] = it.iterator.withFilter(f)
+
+ @deprecated("Use .iterator.reduceLeftOption(...) instead", "2.13.0")
+ def reduceLeftOption(f: (A, A) => A): Option[A] = it.iterator.reduceLeftOption(f)
+
+ @deprecated("Use .iterator.min instead", "2.13.0")
+ def min(implicit ord: Ordering[A]): A = it.iterator.min
+
+ @deprecated("Use .iterator.nonEmpty instead", "2.13.0")
+ def nonEmpty: Boolean = it.iterator.nonEmpty
+
+ @deprecated("Use .iterator.max instead", "2.13.0")
+ def max(implicit ord: Ordering[A]): A = it.iterator.max
+
+ @deprecated("Use .iterator.reduceRight(...) instead", "2.13.0")
+ def reduceRight(f: (A, A) => A): A = it.iterator.reduceRight(f)
+
+ @deprecated("Use .iterator.maxBy(...) instead", "2.13.0")
+ def maxBy[B](f: A => B)(implicit cmp: Ordering[B]): A = it.iterator.maxBy(f)
+
+ @deprecated("Use .iterator.reduceLeft(...) instead", "2.13.0")
+ def reduceLeft(f: (A, A) => A): A = it.iterator.reduceLeft(f)
+
+ @deprecated("Use .iterator.sum instead", "2.13.0")
+ def sum(implicit num: Numeric[A]): A = it.iterator.sum
+
+ @deprecated("Use .iterator.product instead", "2.13.0")
+ def product(implicit num: Numeric[A]): A = it.iterator.product
+
+ @deprecated("Use .iterator.count(...) instead", "2.13.0")
+ def count(f: A => Boolean): Int = it.iterator.count(f)
+
+ @deprecated("Use .iterator.reduceOption(...) instead", "2.13.0")
+ def reduceOption(f: (A, A) => A): Option[A] = it.iterator.reduceOption(f)
+
+ @deprecated("Use .iterator.minBy(...) instead", "2.13.0")
+ def minBy[B](f: A => B)(implicit cmp: Ordering[B]): A = it.iterator.minBy(f)
+
+ @deprecated("Use .iterator.size instead", "2.13.0")
+ def size: Int = it.iterator.size
+
+ @deprecated("Use .iterator.forall(...) instead", "2.13.0")
+ def forall(f: A => Boolean): Boolean = it.iterator.forall(f)
+
+ @deprecated("Use .iterator.collectFirst(...) instead", "2.13.0")
+ def collectFirst[B](f: PartialFunction[A, B]): Option[B] = it.iterator.collectFirst(f)
+
+ @deprecated("Use .iterator.filter(...) instead", "2.13.0")
+ def filter(f: A => Boolean): Iterator[A] = it.iterator.filter(f)
+
+ @deprecated("Use .iterator.exists(...) instead", "2.13.0")
+ def exists(f: A => Boolean): Boolean = it.iterator.exists(f)
+
+ @deprecated("Use .iterator.copyToBuffer(...) instead", "2.13.0")
+ def copyToBuffer(dest: mutable.Buffer[A]): Unit = it.iterator.copyToBuffer(dest)
+
+ @deprecated("Use .iterator.reduce(...) instead", "2.13.0")
+ def reduce(f: (A, A) => A): A = it.iterator.reduce(f)
+
+ @deprecated("Use .iterator.reduceRightOption(...) instead", "2.13.0")
+ def reduceRightOption(f: (A, A) => A): Option[A] = it.iterator.reduceRightOption(f)
+
+ @deprecated("Use .iterator.toIndexedSeq instead", "2.13.0")
+ def toIndexedSeq: IndexedSeq[A] = it.iterator.toIndexedSeq
+
+ @deprecated("Use .iterator.foreach(...) instead", "2.13.0")
+ @`inline` def foreach[U](f: A => U): Unit = it match {
+ case it: Iterable[A] => it.foreach(f)
+ case _ => it.iterator.foreach(f)
+ }
+
+ @deprecated("Use .iterator.to(factory) instead", "2.13.0")
+ def to[C1](factory: Factory[A, C1]): C1 = factory.fromSpecific(it)
+
+ @deprecated("Use .iterator.to(ArrayBuffer) instead", "2.13.0")
+ def toBuffer[B >: A]: mutable.Buffer[B] = mutable.ArrayBuffer.from(it)
+
+ @deprecated("Use .iterator.toArray", "2.13.0")
+ def toArray[B >: A: ClassTag]: Array[B] = it match {
+ case it: Iterable[B] => it.toArray[B]
+ case _ => it.iterator.toArray[B]
+ }
+
+ @deprecated("Use .iterator.to(List) instead", "2.13.0")
+ def toList: immutable.List[A] = immutable.List.from(it)
+
+ @deprecated("Use .iterator.to(Set) instead", "2.13.0")
+ @`inline` def toSet[B >: A]: immutable.Set[B] = immutable.Set.from(it)
+
+ @deprecated("Use .iterator.to(Iterable) instead", "2.13.0")
+ @`inline` final def toTraversable: Traversable[A] = toIterable
+
+ @deprecated("Use .iterator.to(Iterable) instead", "2.13.0")
+ @`inline` final def toIterable: Iterable[A] = Iterable.from(it)
+
+ @deprecated("Use .iterator.to(Seq) instead", "2.13.0")
+ @`inline` def toSeq: immutable.Seq[A] = immutable.Seq.from(it)
+
+ @deprecated("Use .iterator.to(LazyList) instead", "2.13.0")
+ @`inline` def toStream: immutable.Stream[A] = immutable.Stream.from(it)
+
+ @deprecated("Use .iterator.to(Vector) instead", "2.13.0")
+ @`inline` def toVector: immutable.Vector[A] = immutable.Vector.from(it)
+
+ @deprecated("Use .iterator.to(Map) instead", "2.13.0")
+ def toMap[K, V](implicit ev: A <:< (K, V)): immutable.Map[K, V] =
+ immutable.Map.from(it.asInstanceOf[IterableOnce[(K, V)]])
+
+ @deprecated("Use .iterator instead", "2.13.0")
+ @`inline` def toIterator: Iterator[A] = it.iterator
+
+ @deprecated("Use .iterator.isEmpty instead", "2.13.0")
+ def isEmpty: Boolean = it match {
+ case it: Iterable[A] => it.isEmpty
+ case _ => it.iterator.isEmpty
+ }
+
+ @deprecated("Use .iterator.mkString instead", "2.13.0")
+ def mkString(start: String, sep: String, end: String): String = it match {
+ case it: Iterable[A] => it.mkString(start, sep, end)
+ case _ => it.iterator.mkString(start, sep, end)
+ }
+
+ @deprecated("Use .iterator.mkString instead", "2.13.0")
+ def mkString(sep: String): String = it match {
+ case it: Iterable[A] => it.mkString(sep)
+ case _ => it.iterator.mkString(sep)
+ }
+
+ @deprecated("Use .iterator.mkString instead", "2.13.0")
+ def mkString: String = it match {
+ case it: Iterable[A] => it.mkString
+ case _ => it.iterator.mkString
+ }
+
+ @deprecated("Use .iterator.find instead", "2.13.0")
+ def find(p: A => Boolean): Option[A] = it.iterator.find(p)
+
+ @deprecated("Use .iterator.foldLeft instead", "2.13.0")
+ @`inline` def foldLeft[B](z: B)(op: (B, A) => B): B = it.iterator.foldLeft(z)(op)
+
+ @deprecated("Use .iterator.foldRight instead", "2.13.0")
+ @`inline` def foldRight[B](z: B)(op: (A, B) => B): B = it.iterator.foldRight(z)(op)
+
+ @deprecated("Use .iterator.fold instead", "2.13.0")
+ def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = it.iterator.fold(z)(op)
+
+ @deprecated("Use .iterator.foldLeft instead", "2.13.0")
+ @`inline` def /: [B](z: B)(op: (B, A) => B): B = foldLeft[B](z)(op)
+
+ @deprecated("Use .iterator.foldRight instead", "2.13.0")
+ @`inline` def :\ [B](z: B)(op: (A, B) => B): B = foldRight[B](z)(op)
+
+ @deprecated("Use .iterator.map instead or consider requiring an Iterable", "2.13.0")
+ def map[B](f: A => B): IterableOnce[B] = it match {
+ case it: Iterable[A] => it.map(f)
+ case _ => it.iterator.map(f)
+ }
+
+ @deprecated("Use .iterator.flatMap instead or consider requiring an Iterable", "2.13.0")
+ def flatMap[B](f: A => IterableOnce[B]): IterableOnce[B] = it match {
+ case it: Iterable[A] => it.flatMap(f)
+ case _ => it.iterator.flatMap(f)
+ }
+
+ @deprecated("Use .iterator.sameElements instead", "2.13.0")
+ def sameElements[B >: A](that: IterableOnce[B]): Boolean = it.iterator.sameElements(that)
+}
+
+object IterableOnce {
+ @inline implicit def iterableOnceExtensionMethods[A](it: IterableOnce[A]): IterableOnceExtensionMethods[A] =
+ new IterableOnceExtensionMethods[A](it)
+
+ /** Computes the number of elements to copy to an array from a source IterableOnce
+ *
+ * @param srcLen the length of the source collection
+ * @param destLen the length of the destination array
+ * @param start the index in the destination array at which to start copying elements to
+ * @param len the requested number of elements to copy (we may only be able to copy less than this)
+ * @return the number of elements that will be copied to the destination array
+ */
+ @inline private[collection] def elemsToCopyToArray(srcLen: Int, destLen: Int, start: Int, len: Int): Int =
+ math.max(math.min(math.min(len, srcLen), destLen - start), 0)
+
+ /** Calls `copyToArray` on the given collection, regardless of whether or not it is an `Iterable`. */
+ @inline private[collection] def copyElemsToArray[A, B >: A](elems: IterableOnce[A],
+ xs: Array[B],
+ start: Int = 0,
+ len: Int = Int.MaxValue): Int =
+ elems match {
+ case src: Iterable[A] => src.copyToArray[B](xs, start, len)
+ case src => src.iterator.copyToArray[B](xs, start, len)
+ }
+}
+
+/** This implementation trait can be mixed into an `IterableOnce` to get the basic methods that are shared between
+ * `Iterator` and `Iterable`. The `IterableOnce` must support multiple calls to `iterator` but may or may not
+ * return the same `Iterator` every time.
+ *
+ * @define orderDependent
+ *
+ * Note: might return different results for different runs, unless the underlying collection type is ordered.
+ * @define orderDependentReduce
+ *
+ * Note: might return different results for different runs, unless the
+ * underlying collection type is ordered or the operator is associative
+ * and commutative.
+ * @define orderIndependentReduce
+ *
+ * Note: might return different results for different runs, unless either
+ * of the following conditions is met: (1) the operator is associative,
+ * and the underlying collection type is ordered; or (2) the operator is
+ * associative and commutative.
+ * @define mayNotTerminateInf
+ *
+ * Note: may not terminate for infinite-sized collections.
+ * @define willNotTerminateInf
+ *
+ * Note: will not terminate for infinite-sized collections.
+ * @define willForceEvaluation
+ * Note: Even when applied to a view or a lazy collection it will always force the elements.
+ * @define consumesIterator
+ * After calling this method, one should discard the iterator it was called
+ * on. Using it is undefined and subject to change.
+ * @define undefinedOrder
+ * The order of applications of the operator is unspecified and may be nondeterministic.
+ * @define exactlyOnce
+ * Each element appears exactly once in the computation.
+ * @define coll collection
+ *
+ */
+trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A] =>
+ /////////////////////////////////////////////////////////////// Abstract methods that must be implemented
+
+ /** Produces a $coll containing cumulative results of applying the
+ * operator going left to right, including the initial value.
+ *
+ * $willNotTerminateInf
+ * $orderDependent
+ *
+ * @tparam B the type of the elements in the resulting collection
+ * @param z the initial value
+ * @param op the binary operator applied to the intermediate result and the element
+ * @return collection with intermediate results
+ */
+ def scanLeft[B](z: B)(op: (B, A) => B): CC[B]
+
+ /** Selects all elements of this $coll which satisfy a predicate.
+ *
+ * @param p the predicate used to test elements.
+ * @return a new $coll consisting of all elements of this $coll that satisfy the given
+ * predicate `p`. The order of the elements is preserved.
+ */
+ def filter(p: A => Boolean): C
+
+ /** Selects all elements of this $coll which do not satisfy a predicate.
+ *
+ * @param pred the predicate used to test elements.
+ * @return a new $coll consisting of all elements of this $coll that do not satisfy the given
+ * predicate `pred`. Their order may not be preserved.
+ */
+ def filterNot(pred: A => Boolean): C
+
+ /** Selects the first `n` elements.
+ * $orderDependent
+ * @param n the number of elements to take from this $coll.
+ * @return a $coll consisting only of the first `n` elements of this $coll,
+ * or else the whole $coll, if it has less than `n` elements.
+ * If `n` is negative, returns an empty $coll.
+ */
+ def take(n: Int): C
+
+ /** Selects the longest prefix of elements that satisfy a predicate.
+ *
+ * The matching prefix starts with the first element of this $coll,
+ * and the element following the prefix is the first element that
+ * does not satisfy the predicate. The matching prefix may empty,
+ * so that this method returns an empty $coll.
+ *
+ * Example:
+ *
+ * {{{
+ * scala> List(1, 2, 3, 100, 4).takeWhile(n => n < 10)
+ * val res0: List[Int] = List(1, 2, 3)
+ *
+ * scala> List(1, 2, 3, 100, 4).takeWhile(n => n == 0)
+ * val res1: List[Int] = List()
+ * }}}
+ *
+ * Use [[span]] to obtain both the prefix and suffix.
+ * Use [[filter]] to retain only those elements from the entire $coll that satisfy the predicate.
+ * $orderDependent
+ * @param p The predicate used to test elements.
+ * @return the longest prefix of this $coll whose elements all satisfy
+ * the predicate `p`.
+ */
+ def takeWhile(p: A => Boolean): C
+
+ /** Selects all elements except the first `n` ones.
+ * $orderDependent
+ * @param n the number of elements to drop from this $coll.
+ * @return a $coll consisting of all elements of this $coll except the first `n` ones, or else the
+ * empty $coll, if this $coll has less than `n` elements.
+ * If `n` is negative, don't drop any elements.
+ */
+ def drop(n: Int): C
+
+ /** Selects all elements except the longest prefix that satisfies a predicate.
+ *
+ * The matching prefix starts with the first element of this $coll,
+ * and the element following the prefix is the first element that
+ * does not satisfy the predicate. The matching prefix may be empty,
+ * so that this method returns the entire $coll.
+ *
+ * Example:
+ *
+ * {{{
+ * scala> List(1, 2, 3, 100, 4).dropWhile(n => n < 10)
+ * val res0: List[Int] = List(100, 4)
+ *
+ * scala> List(1, 2, 3, 100, 4).dropWhile(n => n == 0)
+ * val res1: List[Int] = List(1, 2, 3, 100, 4)
+ * }}}
+ *
+ * Use [[span]] to obtain both the prefix and suffix.
+ * Use [[filterNot]] to drop all elements that satisfy the predicate.
+ *
+ * $orderDependent
+ * @param p The predicate used to test elements.
+ * @return the longest suffix of this $coll whose first element
+ * does not satisfy the predicate `p`.
+ */
+ def dropWhile(p: A => Boolean): C
+
+ /** Selects an interval of elements. The returned $coll is made up
+ * of all elements `x` which satisfy the invariant:
+ * {{{
+ * from <= indexOf(x) < until
+ * }}}
+ * $orderDependent
+ *
+ * @param from the lowest index to include from this $coll.
+ * @param until the lowest index to EXCLUDE from this $coll.
+ * @return a $coll containing the elements greater than or equal to
+ * index `from` extending up to (but not including) index `until`
+ * of this $coll.
+ */
+ def slice(from: Int, until: Int): C
+
+ /** Builds a new $coll by applying a function to all elements of this $coll.
+ *
+ * @param f the function to apply to each element.
+ * @tparam B the element type of the returned $coll.
+ * @return a new $coll resulting from applying the given function
+ * `f` to each element of this $coll and collecting the results.
+ */
+ def map[B](f: A => B): CC[B]
+
+ /** Builds a new $coll by applying a function to all elements of this $coll
+ * and using the elements of the resulting collections.
+ *
+ * For example:
+ *
+ * {{{
+ * def getWords(lines: Seq[String]): Seq[String] = lines flatMap (line => line split "\\W+")
+ * }}}
+ *
+ * The type of the resulting collection is guided by the static type of $coll. This might
+ * cause unexpected results sometimes. For example:
+ *
+ * {{{
+ * // lettersOf will return a Seq[Char] of likely repeated letters, instead of a Set
+ * def lettersOf(words: Seq[String]) = words flatMap (word => word.toSet)
+ *
+ * // lettersOf will return a Set[Char], not a Seq
+ * def lettersOf(words: Seq[String]) = words.toSet flatMap ((word: String) => word.toSeq)
+ *
+ * // xs will be an Iterable[Int]
+ * val xs = Map("a" -> List(11,111), "b" -> List(22,222)).flatMap(_._2)
+ *
+ * // ys will be a Map[Int, Int]
+ * val ys = Map("a" -> List(1 -> 11,1 -> 111), "b" -> List(2 -> 22,2 -> 222)).flatMap(_._2)
+ * }}}
+ *
+ * @param f the function to apply to each element.
+ * @tparam B the element type of the returned collection.
+ * @return a new $coll resulting from applying the given collection-valued function
+ * `f` to each element of this $coll and concatenating the results.
+ */
+ def flatMap[B](f: A => IterableOnce[B]): CC[B]
+
+ /** Converts this $coll of iterable collections into
+ * a $coll formed by the elements of these iterable
+ * collections.
+ *
+ * The resulting collection's type will be guided by the
+ * type of $coll. For example:
+ *
+ * {{{
+ * val xs = List(
+ * Set(1, 2, 3),
+ * Set(1, 2, 3)
+ * ).flatten
+ * // xs == List(1, 2, 3, 1, 2, 3)
+ *
+ * val ys = Set(
+ * List(1, 2, 3),
+ * List(3, 2, 1)
+ * ).flatten
+ * // ys == Set(1, 2, 3)
+ * }}}
+ *
+ * @tparam B the type of the elements of each iterable collection.
+ * @param asIterable an implicit conversion which asserts that the element
+ * type of this $coll is an `Iterable`.
+ * @return a new $coll resulting from concatenating all element ${coll}s.
+ */
+ def flatten[B](implicit asIterable: A => IterableOnce[B]): CC[B]
+
+ /** Builds a new $coll by applying a partial function to all elements of this $coll
+ * on which the function is defined.
+ *
+ * @param pf the partial function which filters and maps the $coll.
+ * @tparam B the element type of the returned $coll.
+ * @return a new $coll resulting from applying the given partial function
+ * `pf` to each element on which it is defined and collecting the results.
+ * The order of the elements is preserved.
+ */
+ def collect[B](pf: PartialFunction[A, B]): CC[B]
+
+ /** Zips this $coll with its indices.
+ *
+ * @return A new $coll containing pairs consisting of all elements of this $coll paired with their index.
+ * Indices start at `0`.
+ * @example
+ * `List("a", "b", "c").zipWithIndex == List(("a", 0), ("b", 1), ("c", 2))`
+ */
+ def zipWithIndex: CC[(A @uncheckedVariance, Int)]
+
+ /** Splits this $coll into a prefix/suffix pair according to a predicate.
+ *
+ * Note: `c span p` is equivalent to (but possibly more efficient than)
+ * `(c takeWhile p, c dropWhile p)`, provided the evaluation of the
+ * predicate `p` does not cause any side-effects.
+ * $orderDependent
+ *
+ * @param p the test predicate
+ * @return a pair consisting of the longest prefix of this $coll whose
+ * elements all satisfy `p`, and the rest of this $coll.
+ */
+ def span(p: A => Boolean): (C, C)
+
+ /** Splits this $coll into a prefix/suffix pair at a given position.
+ *
+ * Note: `c splitAt n` is equivalent to (but possibly more efficient than)
+ * `(c take n, c drop n)`.
+ * $orderDependent
+ *
+ * @param n the position at which to split.
+ * @return a pair of ${coll}s consisting of the first `n`
+ * elements of this $coll, and the other elements.
+ */
+ def splitAt(n: Int): (C, C) = {
+ class Spanner extends runtime.AbstractFunction1[A, Boolean] {
+ var i = 0
+ def apply(a: A) = i < n && { i += 1 ; true }
+ }
+ val spanner = new Spanner
+ span(spanner)
+ }
+
+ /** Applies a side-effecting function to each element in this collection.
+ * Strict collections will apply `f` to their elements immediately, while lazy collections
+ * like Views and LazyLists will only apply `f` on each element if and when that element
+ * is evaluated, and each time that element is evaluated.
+ *
+ * @param f a function to apply to each element in this $coll
+ * @tparam U the return type of f
+ * @return The same logical collection as this
+ */
+ def tapEach[U](f: A => U): C
+
+ /////////////////////////////////////////////////////////////// Concrete methods based on iterator
+
+ /** Tests whether this $coll is known to have a finite size.
+ * All strict collections are known to have finite size. For a non-strict
+ * collection such as `Stream`, the predicate returns `'''true'''` if all
+ * elements have been computed. It returns `'''false'''` if the stream is
+ * not yet evaluated to the end. Non-empty Iterators usually return
+ * `'''false'''` even if they were created from a collection with a known
+ * finite size.
+ *
+ * Note: many collection methods will not work on collections of infinite sizes.
+ * The typical failure mode is an infinite loop. These methods always attempt a
+ * traversal without checking first that `hasDefiniteSize` returns `'''true'''`.
+ * However, checking `hasDefiniteSize` can provide an assurance that size is
+ * well-defined and non-termination is not a concern.
+ *
+ * @deprecated This method is deprecated in 2.13 because it does not provide any
+ * actionable information. As noted above, even the collection library itself
+ * does not use it. When there is no guarantee that a collection is finite, it
+ * is generally best to attempt a computation anyway and document that it will
+ * not terminate for infinite collections rather than backing out because this
+ * would prevent performing the computation on collections that are in fact
+ * finite even though `hasDefiniteSize` returns `false`.
+ *
+ * @see method `knownSize` for a more useful alternative
+ *
+ * @return `'''true'''` if this collection is known to have finite size,
+ * `'''false'''` otherwise.
+ */
+ @deprecated("Check .knownSize instead of .hasDefiniteSize for more actionable information (see scaladoc for details)", "2.13.0")
+ def hasDefiniteSize: Boolean = true
+
+ /** Tests whether this $coll can be repeatedly traversed. Always
+ * true for Iterables and false for Iterators unless overridden.
+ *
+ * @return `true` if it is repeatedly traversable, `false` otherwise.
+ */
+ def isTraversableAgain: Boolean = false
+
+ /** Applies `f` to each element for its side effects.
+ * Note: `U` parameter needed to help scalac's type inference.
+ */
+ def foreach[U](f: A => U): Unit = {
+ val it = iterator
+ while(it.hasNext) f(it.next())
+ }
+
+ /** Tests whether a predicate holds for all elements of this $coll.
+ *
+ * $mayNotTerminateInf
+ *
+ * @param p the predicate used to test elements.
+ * @return `true` if this $coll is empty or the given predicate `p`
+ * holds for all elements of this $coll, otherwise `false`.
+ */
+ def forall(p: A => Boolean): Boolean = {
+ var res = true
+ val it = iterator
+ while (res && it.hasNext) res = p(it.next())
+ res
+ }
+
+ /** Tests whether a predicate holds for at least one element of this $coll.
+ *
+ * $mayNotTerminateInf
+ *
+ * @param p the predicate used to test elements.
+ * @return `true` if the given predicate `p` is satisfied by at least one element of this $coll, otherwise `false`
+ */
+ def exists(p: A => Boolean): Boolean = {
+ var res = false
+ val it = iterator
+ while (!res && it.hasNext) res = p(it.next())
+ res
+ }
+
+ /** Counts the number of elements in the $coll which satisfy a predicate.
+ *
+ * $willNotTerminateInf
+ *
+ * @param p the predicate used to test elements.
+ * @return the number of elements satisfying the predicate `p`.
+ */
+ def count(p: A => Boolean): Int = {
+ var res = 0
+ val it = iterator
+ while (it.hasNext) if (p(it.next())) res += 1
+ res
+ }
+
+ /** Finds the first element of the $coll satisfying a predicate, if any.
+ *
+ * $mayNotTerminateInf
+ * $orderDependent
+ *
+ * @param p the predicate used to test elements.
+ * @return an option value containing the first element in the $coll
+ * that satisfies `p`, or `None` if none exists.
+ */
+ def find(p: A => Boolean): Option[A] = {
+ val it = iterator
+ while (it.hasNext) {
+ val a = it.next()
+ if (p(a)) return Some(a)
+ }
+ None
+ }
+
+ // in future, move to IndexedSeqOps
+ private def foldl[X >: A, B](seq: IndexedSeq[X], start: Int, z: B, op: (B, X) => B): B = {
+ @tailrec def loop(at: Int, end: Int, acc: B): B =
+ if (at == end) acc
+ else loop(at + 1, end, op(acc, seq(at)))
+ loop(start, seq.length, z)
+ }
+
+ private def foldr[X >: A, B >: X](seq: IndexedSeq[X], op: (X, B) => B): B = {
+ @tailrec def loop(at: Int, acc: B): B =
+ if (at == 0) acc
+ else loop(at - 1, op(seq(at - 1), acc))
+ loop(seq.length - 1, seq(seq.length - 1))
+ }
+
+ /** Applies the given binary operator `op` to the given initial value `z` and all
+ * elements of this $coll, going left to right. Returns the initial value if this $coll
+ * is empty.
+ *
+ * "Going left to right" only makes sense if this collection is ordered: then if
+ * `x,,1,,`, `x,,2,,`, ..., `x,,n,,` are the elements of this $coll, the result is
+ * `op( op( ... op( op(z, x,,1,,), x,,2,,) ... ), x,,n,,)`.
+ *
+ * If this collection is not ordered, then for each application of the operator, each
+ * right operand is an element. In addition, the leftmost operand is the initial
+ * value, and each other left operand is itself an application of the operator. The
+ * elements of this $coll and the initial value all appear exactly once in the
+ * computation.
+ *
+ * $orderDependent
+ * $willNotTerminateInf
+ *
+ * @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 $coll,
+ * going left to right. Returns `z` if this $coll is empty.
+ */
+ def foldLeft[B](z: B)(op: (B, A) => B): B = this match {
+ case seq: IndexedSeq[A @unchecked] => foldl[A, B](seq, 0, z, op)
+ case _ =>
+ var result = z
+ val it = iterator
+ while (it.hasNext) {
+ result = op(result, it.next())
+ }
+ result
+ }
+
+ /** Applies the given binary operator `op` to all elements of this $coll and the given
+ * initial value `z`, going right to left. Returns the initial value if this $coll is
+ * empty.
+ *
+ * "Going right to left" only makes sense if this collection is ordered: then if
+ * `x,,1,,`, `x,,2,,`, ..., `x,,n,,` are the elements of this $coll, the result is
+ * `op(x,,1,,, op(x,,2,,, op( ... op(x,,n,,, z) ... )))`.
+ *
+ * If this collection is not ordered, then for each application of the operator, each
+ * left operand is an element. In addition, the rightmost operand is the initial
+ * value, and each other right operand is itself an application of the operator. The
+ * elements of this $coll and the initial value all appear exactly once in the
+ * computation.
+ *
+ * $orderDependent
+ * $willNotTerminateInf
+ *
+ * @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 $coll and `z`,
+ * going right to left. Returns `z` if this $coll is empty.
+ */
+ def foldRight[B](z: B)(op: (A, B) => B): B = reversed.foldLeft(z)((b, a) => op(a, b))
+
+ @deprecated("Use foldLeft instead of /:", "2.13.0")
+ @`inline` final def /: [B](z: B)(op: (B, A) => B): B = foldLeft[B](z)(op)
+
+ @deprecated("Use foldRight instead of :\\", "2.13.0")
+ @`inline` final def :\ [B](z: B)(op: (A, B) => B): B = foldRight[B](z)(op)
+
+ /** Applies the given binary operator `op` to the given initial value `z` and all
+ * elements of this $coll.
+ *
+ * For each application of the operator, each operand is either an element of this
+ * $coll, the initial value, or another such application of the operator.
+ * $undefinedOrder $exactlyOnce The initial value may be used an arbitrary number of
+ * times, but at least once.
+ *
+ * If this collection is ordered, then for any application of the operator, the
+ * element(s) appearing in the left operand will precede those in the right.
+ *
+ * $orderIndependentReduce In either case, it is also necessary that the initial value
+ * be a neutral value for the operator, e.g. `Nil` for `List` concatenation or `1` for
+ * multiplication.
+ *
+ * The default implementation in `IterableOnce` is equivalent to `foldLeft` but may be
+ * overridden for more efficient traversal orders.
+ *
+ * $willNotTerminateInf
+ *
+ * @tparam A1 The type parameter for the binary operator, a supertype of `A`.
+ * @param z An initial value; may be used an arbitrary number of times in the
+ * computation of the result; must be a neutral value for `op` for the
+ * result to always be the same across runs.
+ * @param op A binary operator; must be associative for the result to always be the
+ * same across runs.
+ * @return The result of applying `op` between all the elements and `z`, or `z`
+ * if this $coll is empty.
+ */
+ def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)
+
+ /** Applies the given binary operator `op` to all elements of this $coll.
+ *
+ * For each application of the operator, each operand is either an element of this
+ * $coll or another such application of the operator. $undefinedOrder $exactlyOnce
+ *
+ * If this collection is ordered, then for any application of the operator, the
+ * element(s) appearing in the left operand will precede those in the right.
+ *
+ * $orderIndependentReduce
+ * $willNotTerminateInf
+ *
+ * @tparam B The type parameter for the binary operator, a supertype of `A`.
+ * @param op A binary operator; must be associative for the result to always be the
+ * same across runs.
+ * @return The result of applying `op` between all the elements if the $coll is
+ * nonempty.
+ * @throws UnsupportedOperationException if this $coll is empty.
+ */
+ def reduce[B >: A](op: (B, B) => B): B = reduceLeft(op)
+
+ /** If this $coll is nonempty, reduces it with the given binary operator `op`.
+ *
+ * The behavior is the same as [[reduce]] except that the value is `None` if the $coll
+ * is empty. $undefinedOrder $exactlyOnce
+ *
+ * $orderIndependentReduce
+ * $willNotTerminateInf
+ *
+ * @tparam B A type parameter for the binary operator, a supertype of `A`.
+ * @param op A binary operator; must be associative for the result to always be the
+ * same across runs.
+ * @return The result of reducing this $coll with `op` if the $coll is nonempty,
+ * inside a `Some`, and `None` otherwise.
+ */
+ def reduceOption[B >: A](op: (B, B) => B): Option[B] = reduceLeftOption(op)
+
+ /** Applies the given binary operator `op` to all elements of this $coll, going left to
+ * right.
+ *
+ * "Going left to right" only makes sense if this collection is ordered: then if
+ * `x,,1,,`, `x,,2,,`, ..., `x,,n,,` are the elements of this $coll, the result is
+ * `op( op( op( ... op(x,,1,,, x,,2,,) ... ), x,,n-1,,), x,,n,,)`.
+ *
+ * If this collection is not ordered, then for each application of the operator, each
+ * right operand is an element. In addition, the leftmost operand is the first element
+ * of this $coll and each other left operand is itself an application of the
+ * operator. $exactlyOnce
+ *
+ * $orderDependentReduce
+ * $willNotTerminateInf
+ *
+ * @param op A binary operator.
+ * @tparam B The result type of the binary operator, a supertype of `A`.
+ * @return The result of applying `op` to all elements of this $coll, going
+ * left to right.
+ * @throws UnsupportedOperationException if this $coll is empty.
+ */
+ def reduceLeft[B >: A](op: (B, A) => B): B = this match {
+ case seq: IndexedSeq[A @unchecked] if seq.length > 0 => foldl(seq, 1, seq(0), op)
+ case _ if knownSize == 0 => throw new UnsupportedOperationException("empty.reduceLeft")
+ case _ => reduceLeftIterator[B](throw new UnsupportedOperationException("empty.reduceLeft"))(op)
+ }
+ private final def reduceLeftIterator[B >: A](onEmpty: => B)(op: (B, A) => B): B = {
+ val it = iterator
+ if (it.hasNext) {
+ var acc: B = it.next()
+ while (it.hasNext)
+ acc = op(acc, it.next())
+ acc
+ }
+ else onEmpty
+ }
+
+ /** Applies the given binary operator `op` to all elements of this $coll, going right to
+ * left.
+ *
+ * "Going right to left" only makes sense if this collection is ordered: then if
+ * `x,,1,,`, `x,,2,,`, ..., `x,,n,,` are the elements of this $coll, the result is
+ * `op(x,,1,,, op(x,,2,,, op( ... op(x,,n-1,,, x,,n,,) ... )))`.
+ *
+ * If this collection is not ordered, then for each application of the operator, each
+ * left operand is an element. In addition, the rightmost operand is the last element
+ * of this $coll and each other right operand is itself an application of the
+ * operator. $exactlyOnce
+ *
+ * $orderDependentReduce
+ * $willNotTerminateInf
+ *
+ * @param op A binary operator.
+ * @tparam B The result type of the binary operator, a supertype of `A`.
+ * @return The result of applying `op` to all elements of this $coll, going
+ * right to left.
+ * @throws UnsupportedOperationException if this $coll is empty.
+ */
+ def reduceRight[B >: A](op: (A, B) => B): B = this match {
+ case seq: IndexedSeq[A @unchecked] if seq.length > 0 => foldr[A, B](seq, op)
+ case _ if knownSize == 0 => throw new UnsupportedOperationException("empty.reduceRight")
+ case _ => reversed.reduceLeft[B]((x, y) => op(y, x)) // reduceLeftIterator
+ }
+
+ /** If this $coll is nonempty, reduces it with the given binary operator `op`, going
+ * left to right.
+ *
+ * The behavior is the same as [[reduceLeft]] except that the value is `None` if the
+ * $coll is empty. $exactlyOnce
+ *
+ * $orderDependentReduce
+ * $willNotTerminateInf
+ *
+ * @param op A binary operator.
+ * @tparam B The result type of the binary operator, a supertype of `A`.
+ * @return The result of reducing this $coll with `op` going left to right if
+ * the $coll is nonempty, inside a `Some`, and `None` otherwise.
+ */
+ def reduceLeftOption[B >: A](op: (B, A) => B): Option[B] =
+ knownSize match {
+ case -1 => reduceLeftOptionIterator[B](op)
+ case 0 => None
+ case _ => Some(reduceLeft(op))
+ }
+ private final def reduceLeftOptionIterator[B >: A](op: (B, A) => B): Option[B] = reduceOptionIterator[A, B](iterator)(op)
+ private final def reduceOptionIterator[X >: A, B >: X](it: Iterator[X])(op: (B, X) => B): Option[B] = {
+ if (it.hasNext) {
+ var acc: B = it.next()
+ while (it.hasNext)
+ acc = op(acc, it.next())
+ Some(acc)
+ }
+ else None
+ }
+
+ /** If this $coll is nonempty, reduces it with the given binary operator `op`, going
+ * right to left.
+ *
+ * The behavior is the same as [[reduceRight]] except that the value is `None` if the
+ * $coll is empty. $exactlyOnce
+ *
+ * $orderDependentReduce
+ * $willNotTerminateInf
+ *
+ * @param op A binary operator.
+ * @tparam B The result type of the binary operator, a supertype of `A`.
+ * @return The result of reducing this $coll with `op` going right to left if
+ * the $coll is nonempty, inside a `Some`, and `None` otherwise.
+ */
+ def reduceRightOption[B >: A](op: (A, B) => B): Option[B] =
+ knownSize match {
+ case -1 => reduceOptionIterator[A, B](reversed.iterator)((x, y) => op(y, x))
+ case 0 => None
+ case _ => Some(reduceRight(op))
+ }
+
+ /** Tests whether the $coll is empty.
+ *
+ * Note: The default implementation creates and discards an iterator.
+ *
+ * Note: Implementations in subclasses that are not repeatedly iterable must take
+ * care not to consume any elements when `isEmpty` is called.
+ *
+ * @return `true` if the $coll contains no elements, `false` otherwise.
+ */
+ def isEmpty: Boolean =
+ knownSize match {
+ case -1 => !iterator.hasNext
+ case 0 => true
+ case _ => false
+ }
+
+ /** Tests whether the $coll is not empty.
+ *
+ * @return `true` if the $coll contains at least one element, `false` otherwise.
+ */
+ @deprecatedOverriding("nonEmpty is defined as !isEmpty; override isEmpty instead", "2.13.0")
+ def nonEmpty: Boolean = !isEmpty
+
+ /** The size of this $coll.
+ *
+ * $willNotTerminateInf
+ *
+ * @return the number of elements in this $coll.
+ */
+ def size: Int =
+ if (knownSize >= 0) knownSize
+ else {
+ val it = iterator
+ var len = 0
+ while (it.hasNext) { len += 1; it.next() }
+ len
+ }
+
+ @deprecated("Use `dest ++= coll` instead", "2.13.0")
+ @inline final def copyToBuffer[B >: A](dest: mutable.Buffer[B]): Unit = dest ++= this
+
+ /** Copies elements to an array, returning the number of elements written.
+ *
+ * Fills the given array `xs` starting at index `start` with values of this $coll.
+ *
+ * Copying will stop once either all the elements of this $coll have been copied,
+ * or the end of the array is reached.
+ *
+ * @param xs the array to fill.
+ * @tparam B the type of the elements of the array.
+ * @return the number of elements written to the array
+ *
+ * @note Reuse: $consumesIterator
+ */
+ @deprecatedOverriding("This should always forward to the 3-arg version of this method", since = "2.13.4")
+ def copyToArray[B >: A](xs: Array[B]): Int = copyToArray(xs, 0, Int.MaxValue)
+
+ /** Copies elements to an array, returning the number of elements written.
+ *
+ * Fills the given array `xs` starting at index `start` with values of this $coll.
+ *
+ * Copying will stop once either all the elements of this $coll have been copied,
+ * or the end of the array is reached.
+ *
+ * @param xs the array to fill.
+ * @param start the starting index of xs.
+ * @tparam B the type of the elements of the array.
+ * @return the number of elements written to the array
+ *
+ * @note Reuse: $consumesIterator
+ */
+ @deprecatedOverriding("This should always forward to the 3-arg version of this method", since = "2.13.4")
+ def copyToArray[B >: A](xs: Array[B], start: Int): Int = copyToArray(xs, start, Int.MaxValue)
+
+ /** Copy elements to an array, returning the number of elements written.
+ *
+ * Fills the given array `xs` starting at index `start` with at most `len` elements of this $coll.
+ *
+ * Copying will stop once either all the elements of this $coll have been copied,
+ * or the end of the array is reached, or `len` elements have been copied.
+ *
+ * @param xs the array to fill.
+ * @param start the starting index of xs.
+ * @param len the maximal number of elements to copy.
+ * @tparam B the type of the elements of the array.
+ * @return the number of elements written to the array
+ *
+ * @note Reuse: $consumesIterator
+ */
+ def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = {
+ val it = iterator
+ var i = start
+ val end = start + math.min(len, xs.length - start)
+ while (i < end && it.hasNext) {
+ xs(i) = it.next()
+ i += 1
+ }
+ i - start
+ }
+
+ /** Sums the elements of this collection.
+ *
+ * The default implementation uses `reduce` for a known non-empty collection, `foldLeft` otherwise.
+ *
+ * $willNotTerminateInf
+ *
+ * @param num an implicit parameter defining a set of numeric operations
+ * which includes the `+` operator to be used in forming the sum.
+ * @tparam B the result type of the `+` operator.
+ * @return the sum of all elements of this $coll with respect to the `+` operator in `num`.
+ */
+ def sum[B >: A](implicit num: Numeric[B]): B =
+ knownSize match {
+ case -1 => foldLeft(num.zero)(num.plus)
+ case 0 => num.zero
+ case _ => reduce(num.plus)
+ }
+
+ /** Multiplies together the elements of this collection.
+ *
+ * The default implementation uses `reduce` for a known non-empty collection, `foldLeft` otherwise.
+ *
+ * $willNotTerminateInf
+ *
+ * @param num an implicit parameter defining a set of numeric operations
+ * which includes the `*` operator to be used in forming the product.
+ * @tparam B the result type of the `*` operator.
+ * @return the product of all elements of this $coll with respect to the `*` operator in `num`.
+ */
+ def product[B >: A](implicit num: Numeric[B]): B =
+ knownSize match {
+ case -1 => foldLeft(num.one)(num.times)
+ case 0 => num.one
+ case _ => reduce(num.times)
+ }
+
+ /** Finds the smallest element.
+ *
+ * $willNotTerminateInf
+ *
+ * @param ord An ordering to be used for comparing elements.
+ * @tparam B The type over which the ordering is defined.
+ * @throws UnsupportedOperationException if this $coll is empty.
+ * @return the smallest element of this $coll with respect to the ordering `ord`.
+ *
+ */
+ def min[B >: A](implicit ord: Ordering[B]): A =
+ knownSize match {
+ case -1 => reduceLeftIterator[A](throw new UnsupportedOperationException("empty.min"))(ord.min)
+ case 0 => throw new UnsupportedOperationException("empty.min")
+ case _ => reduceLeft(ord.min)
+ }
+
+ /** Finds the smallest element.
+ *
+ * $willNotTerminateInf
+ *
+ * @param ord An ordering to be used for comparing elements.
+ * @tparam B The type over which the ordering is defined.
+ * @return an option value containing the smallest element of this $coll
+ * with respect to the ordering `ord`.
+ */
+ def minOption[B >: A](implicit ord: Ordering[B]): Option[A] =
+ knownSize match {
+ case -1 => reduceLeftOptionIterator[A](ord.min)
+ case 0 => None
+ case _ => Some(reduceLeft(ord.min))
+ }
+
+ /** Finds the largest element.
+ *
+ * $willNotTerminateInf
+ *
+ * @param ord An ordering to be used for comparing elements.
+ * @tparam B The type over which the ordering is defined.
+ * @throws UnsupportedOperationException if this $coll is empty.
+ * @return the largest element of this $coll with respect to the ordering `ord`.
+ */
+ def max[B >: A](implicit ord: Ordering[B]): A =
+ knownSize match {
+ case -1 => reduceLeftIterator[A](throw new UnsupportedOperationException("empty.max"))(ord.max)
+ case 0 => throw new UnsupportedOperationException("empty.max")
+ case _ => reduceLeft(ord.max)
+ }
+
+ /** Finds the largest element.
+ *
+ * $willNotTerminateInf
+ *
+ * @param ord An ordering to be used for comparing elements.
+ * @tparam B The type over which the ordering is defined.
+ * @return an option value containing the largest element of this $coll with
+ * respect to the ordering `ord`.
+ */
+ def maxOption[B >: A](implicit ord: Ordering[B]): Option[A] =
+ knownSize match {
+ case -1 => reduceLeftOptionIterator[A](ord.max)
+ case 0 => None
+ case _ => Some(reduceLeft(ord.max))
+ }
+
+ /** Finds the first element which yields the largest value measured by function `f`.
+ *
+ * $willNotTerminateInf
+ *
+ * @param cmp An ordering to be used for comparing elements.
+ * @tparam B The result type of the function `f`.
+ * @param f The measuring function.
+ * @throws UnsupportedOperationException if this $coll is empty.
+ * @return the first element of this $coll with the largest value measured by function `f`
+ * with respect to the ordering `cmp`.
+ */
+ def maxBy[B](f: A => B)(implicit ord: Ordering[B]): A =
+ knownSize match {
+ case 0 => throw new UnsupportedOperationException("empty.maxBy")
+ case _ => foldLeft(new Maximized[A, B]("maxBy")(f)(ord.gt))((m, a) => m(m, a)).result
+ }
+
+ private class Maximized[X, B](descriptor: String)(f: X => B)(cmp: (B, B) => Boolean) extends AbstractFunction2[Maximized[X, B], X, Maximized[X, B]] {
+ var maxElem: X = null.asInstanceOf[X]
+ var maxF: B = null.asInstanceOf[B]
+ var nonEmpty = false
+ def toOption: Option[X] = if (nonEmpty) Some(maxElem) else None
+ def result: X = if (nonEmpty) maxElem else throw new UnsupportedOperationException(s"empty.$descriptor")
+ def apply(m: Maximized[X, B], a: X): Maximized[X, B] =
+ if (m.nonEmpty) {
+ val fa = f(a)
+ if (cmp(fa, maxF)) {
+ maxF = fa
+ maxElem = a
+ }
+ m
+ }
+ else {
+ m.nonEmpty = true
+ m.maxElem = a
+ m.maxF = f(a)
+ m
+ }
+ }
+
+ /** Finds the first element which yields the largest value measured by function `f`.
+ *
+ * $willNotTerminateInf
+ *
+ * @param cmp An ordering to be used for comparing elements.
+ * @tparam B The result type of the function `f`.
+ * @param f The measuring function.
+ * @return an option value containing the first element of this $coll with the
+ * largest value measured by function `f` with respect to the ordering `cmp`.
+ */
+ def maxByOption[B](f: A => B)(implicit ord: Ordering[B]): Option[A] =
+ knownSize match {
+ case 0 => None
+ case _ => foldLeft(new Maximized[A, B]("maxBy")(f)(ord.gt))((m, a) => m(m, a)).toOption
+ }
+
+ /** Finds the first element which yields the smallest value measured by function `f`.
+ *
+ * $willNotTerminateInf
+ *
+ * @param cmp An ordering to be used for comparing elements.
+ * @tparam B The result type of the function `f`.
+ * @param f The measuring function.
+ * @throws UnsupportedOperationException if this $coll is empty.
+ * @return the first element of this $coll with the smallest value measured by function `f`
+ * with respect to the ordering `cmp`.
+ */
+ def minBy[B](f: A => B)(implicit ord: Ordering[B]): A =
+ knownSize match {
+ case 0 => throw new UnsupportedOperationException("empty.minBy")
+ case _ => foldLeft(new Maximized[A, B]("minBy")(f)(ord.lt))((m, a) => m(m, a)).result
+ }
+
+ /** Finds the first element which yields the smallest value measured by function `f`.
+ *
+ * $willNotTerminateInf
+ *
+ * @param cmp An ordering to be used for comparing elements.
+ * @tparam B The result type of the function `f`.
+ * @param f The measuring function.
+ * @return an option value containing the first element of this $coll
+ * with the smallest value measured by function `f`
+ * with respect to the ordering `cmp`.
+ */
+ def minByOption[B](f: A => B)(implicit ord: Ordering[B]): Option[A] =
+ knownSize match {
+ case 0 => None
+ case _ => foldLeft(new Maximized[A, B]("minBy")(f)(ord.lt))((m, a) => m(m, a)).toOption
+ }
+
+ /** Finds the first element of the $coll for which the given partial
+ * function is defined, and applies the partial function to it.
+ *
+ * $mayNotTerminateInf
+ * $orderDependent
+ *
+ * @param pf the partial function
+ * @return an option value containing pf applied to the first
+ * value for which it is defined, or `None` if none exists.
+ * @example `Seq("a", 1, 5L).collectFirst({ case x: Int => x*10 }) = Some(10)`
+ */
+ def collectFirst[B](pf: PartialFunction[A, B]): Option[B] = {
+ // Presumably the fastest way to get in and out of a partial function is for a sentinel function to return itself
+ // (Tested to be lower-overhead than runWith. Would be better yet to not need to (formally) allocate it)
+ val sentinel: scala.Function1[A, Any] = new AbstractFunction1[A, Any] {
+ def apply(a: A): AbstractFunction1[A, Any] = this
+ }
+ val it = iterator
+ while (it.hasNext) {
+ val x = pf.applyOrElse(it.next(), sentinel)
+ if (x.asInstanceOf[AnyRef] ne sentinel) return Some(x.asInstanceOf[B])
+ }
+ None
+ }
+
+ /** Aggregates the results of applying an operator to subsequent elements.
+ *
+ * Since this method degenerates to `foldLeft` for sequential (non-parallel) collections,
+ * where the combining operation is ignored, it is advisable to prefer `foldLeft` for that case.
+ *
+ * For [[https://github.com/scala/scala-parallel-collections parallel collections]],
+ * use the `aggregate` method specified by `scala.collection.parallel.ParIterableLike`.
+ *
+ * @param z the start value, a neutral element for `seqop`.
+ * @param seqop the binary operator used to accumulate the result.
+ * @param combop an associative operator for combining sequential results, unused for sequential collections.
+ * @tparam B the result type, produced by `seqop`, `combop`, and by this function as a final result.
+ */
+ @deprecated("For sequential collections, prefer `foldLeft(z)(seqop)`. For parallel collections, use `ParIterableLike#aggregate`.", "2.13.0")
+ def aggregate[B](z: => B)(seqop: (B, A) => B, combop: (B, B) => B): B = foldLeft(z)(seqop)
+
+ /** Tests whether every element of this collection's iterator relates to the
+ * corresponding element of another collection by satisfying a test predicate.
+ *
+ * $willNotTerminateInf
+ *
+ * @param that the other collection
+ * @param p the test predicate, which relates elements from both collections
+ * @tparam B the type of the elements of `that`
+ * @return `true` if both collections have the same length and
+ * `p(x, y)` is `true` for all corresponding elements `x` of this iterator
+ * and `y` of `that`, otherwise `false`
+ */
+ def corresponds[B](that: IterableOnce[B])(p: (A, B) => Boolean): Boolean = {
+ val a = iterator
+ val b = that.iterator
+
+ while (a.hasNext && b.hasNext) {
+ if (!p(a.next(), b.next())) return false
+ }
+
+ a.hasNext == b.hasNext
+ }
+
+ /** Displays all elements of this $coll in a string using start, end, and separator strings.
+ *
+ * Delegates to addString, which can be overridden.
+ *
+ * @param start the starting string.
+ * @param sep the separator string.
+ * @param end the ending string.
+ * @return a string representation of this $coll. The resulting string
+ * begins with the string `start` and ends with the string
+ * `end`. Inside, the string representations (w.r.t. the method
+ * `toString`) of all elements of this $coll are separated by
+ * the string `sep`.
+ *
+ * @example `List(1, 2, 3).mkString("(", "; ", ")") = "(1; 2; 3)"`
+ */
+ final def mkString(start: String, sep: String, end: String): String =
+ if (knownSize == 0) start + end
+ else addString(new StringBuilder(), start, sep, end).result()
+
+ /** Displays all elements of this $coll in a string using a separator string.
+ *
+ * Delegates to addString, which can be overridden.
+ *
+ * @param sep the separator string.
+ * @return a string representation of this $coll. In the resulting string
+ * the string representations (w.r.t. the method `toString`)
+ * of all elements of this $coll are separated by the string `sep`.
+ *
+ * @example `List(1, 2, 3).mkString("|") = "1|2|3"`
+ */
+ @inline final def mkString(sep: String): String = mkString("", sep, "")
+
+ /** Displays all elements of this $coll in a string.
+ *
+ * Delegates to addString, which can be overridden.
+ *
+ * @return a string representation of this $coll. In the resulting string
+ * the string representations (w.r.t. the method `toString`)
+ * of all elements of this $coll follow each other without any
+ * separator string.
+ */
+ @inline final def mkString: String = mkString("")
+
+ /** Appends all elements of this $coll to a string builder using start, end, and separator strings.
+ * The written text begins with the string `start` and ends with the string `end`.
+ * Inside, the string representations (w.r.t. the method `toString`)
+ * of all elements of this $coll are separated by the string `sep`.
+ *
+ * Example:
+ *
+ * {{{
+ * scala> val a = List(1,2,3,4)
+ * a: List[Int] = List(1, 2, 3, 4)
+ *
+ * scala> val b = new StringBuilder()
+ * b: StringBuilder =
+ *
+ * scala> a.addString(b , "List(" , ", " , ")")
+ * res5: StringBuilder = List(1, 2, 3, 4)
+ * }}}
+ *
+ * @param b the string builder to which elements are appended.
+ * @param start the starting string.
+ * @param sep the separator string.
+ * @param end the ending string.
+ * @return the string builder `b` to which elements were appended.
+ */
+ def addString(b: StringBuilder, start: String, sep: String, end: String): b.type = {
+ val jsb = b.underlying
+ if (start.length != 0) jsb.append(start)
+ val it = iterator
+ if (it.hasNext) {
+ jsb.append(it.next())
+ while (it.hasNext) {
+ jsb.append(sep)
+ jsb.append(it.next())
+ }
+ }
+ if (end.length != 0) jsb.append(end)
+ b
+ }
+
+ /** Appends all elements of this $coll to a string builder using a separator string.
+ * The written text consists of the string representations (w.r.t. the method `toString`)
+ * of all elements of this $coll, separated by the string `sep`.
+ *
+ * Example:
+ *
+ * {{{
+ * scala> val a = List(1,2,3,4)
+ * a: List[Int] = List(1, 2, 3, 4)
+ *
+ * scala> val b = new StringBuilder()
+ * b: StringBuilder =
+ *
+ * scala> a.addString(b, ", ")
+ * res0: StringBuilder = 1, 2, 3, 4
+ * }}}
+ *
+ * @param b the string builder to which elements are appended.
+ * @param sep the separator string.
+ * @return the string builder `b` to which elements were appended.
+ */
+ @inline final def addString(b: StringBuilder, sep: String): b.type = addString(b, "", sep, "")
+
+ /** Appends all elements of this $coll to a string builder.
+ * The written text consists of the string representations (w.r.t. the method
+ * `toString`) of all elements of this $coll without any separator string.
+ *
+ * Example:
+ *
+ * {{{
+ * scala> val a = List(1,2,3,4)
+ * a: List[Int] = List(1, 2, 3, 4)
+ *
+ * scala> val b = new StringBuilder()
+ * b: StringBuilder =
+ *
+ * scala> val h = a.addString(b)
+ * h: StringBuilder = 1234
+ * }}}
+ *
+ * @param b the string builder to which elements are appended.
+ * @return the string builder `b` to which elements were appended.
+ */
+ @inline final def addString(b: StringBuilder): b.type = addString(b, "")
+
+ /** Given a collection factory `factory`, converts this $coll to the appropriate
+ * representation for the current element type `A`. Example uses:
+ *
+ * {{{
+ * xs.to(List)
+ * xs.to(ArrayBuffer)
+ * xs.to(BitSet) // for xs: Iterable[Int]
+ * }}}
+ */
+ def to[C1](factory: Factory[A, C1]): C1 = factory.fromSpecific(this)
+
+ @deprecated("Use .iterator instead of .toIterator", "2.13.0")
+ @`inline` final def toIterator: Iterator[A] = iterator
+
+ /** Converts this $coll to a `List`.
+ *
+ * @return This $coll as a `List[A]`.
+ */
+ def toList: immutable.List[A] = immutable.List.from(this)
+
+ /** Converts this $coll to a `Vector`.
+ *
+ * @return This $coll as a `Vector[A]`.
+ */
+ def toVector: immutable.Vector[A] = immutable.Vector.from(this)
+
+ /** Converts this $coll to a `Map`, given an implicit coercion from the $coll's type to a key-value tuple.
+ *
+ * @tparam K The key type for the resulting map.
+ * @tparam V The value type for the resulting map.
+ * @param ev An implicit coercion from `A` to `[K, V]`.
+ * @return This $coll as a `Map[K, V]`.
+ */
+ def toMap[K, V](implicit ev: A <:< (K, V)): immutable.Map[K, V] =
+ immutable.Map.from(this.asInstanceOf[IterableOnce[(K, V)]])
+
+ /** Converts this $coll to a `Set`.
+ *
+ * @tparam B The type of elements of the result, a supertype of `A`.
+ * @return This $coll as a `Set[B]`.
+ */
+ def toSet[B >: A]: immutable.Set[B] = immutable.Set.from(this)
+
+ /** @return This $coll as a `Seq[A]`. This is equivalent to `to(Seq)` but might be faster.
+ */
+ def toSeq: immutable.Seq[A] = immutable.Seq.from(this)
+
+ /** Converts this $coll to an `IndexedSeq`.
+ *
+ * @return This $coll as an `IndexedSeq[A]`.
+ */
+ def toIndexedSeq: immutable.IndexedSeq[A] = immutable.IndexedSeq.from(this)
+
+ @deprecated("Use .to(LazyList) instead of .toStream", "2.13.0")
+ @inline final def toStream: immutable.Stream[A] = to(immutable.Stream)
+
+ /** Converts this $coll to a `Buffer`.
+ *
+ * @tparam B The type of elements of the result, a supertype of `A`.
+ * @return This $coll as a `Buffer[B]`.
+ */
+ @inline final def toBuffer[B >: A]: mutable.Buffer[B] = mutable.Buffer.from(this)
+
+ /** Converts this $coll to an `Array`.
+ *
+ * Implementation note: DO NOT call [[Array.from]] from this method.
+ *
+ * @tparam B The type of elements of the result, a supertype of `A`.
+ * @return This $coll as an `Array[B]`.
+ */
+ def toArray[B >: A: ClassTag]: Array[B] =
+ if (knownSize >= 0) {
+ val destination = new Array[B](knownSize)
+ @annotation.unused val copied = copyToArray(destination, 0)
+ //assert(copied == destination.length)
+ destination
+ }
+ else mutable.ArrayBuilder.make[B].addAll(this).result()
+
+ // For internal use
+ protected def reversed: Iterable[A] = {
+ var xs: immutable.List[A] = immutable.Nil
+ val it = iterator
+ while (it.hasNext) xs = it.next() :: xs
+ xs
+ }
+}
diff --git a/library/src/scala/collection/Iterator.scala b/library/src/scala/collection/Iterator.scala
new file mode 100644
index 000000000000..7b402241af73
--- /dev/null
+++ b/library/src/scala/collection/Iterator.scala
@@ -0,0 +1,1306 @@
+/*
+ * 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 scala.collection.mutable.{ArrayBuffer, ArrayBuilder, Builder, ImmutableBuilder}
+import scala.annotation.tailrec
+import scala.annotation.unchecked.uncheckedVariance
+import scala.runtime.Statics
+
+/** Iterators are data structures that allow to iterate over a sequence
+ * of elements. They have a `hasNext` method for checking
+ * if there is a next element available, and a `next` method
+ * which returns the next element and advances the iterator.
+ *
+ * An iterator is mutable: most operations on it change its state. While it is often used
+ * to iterate through the elements of a collection, it can also be used without
+ * being backed by any collection (see constructors on the companion object).
+ *
+ * It is of particular importance to note that, unless stated otherwise, ''one should never
+ * use an iterator after calling a method on it''. The two most important exceptions
+ * are also the sole abstract methods: `next` and `hasNext`.
+ *
+ * Both these methods can be called any number of times without having to discard the
+ * iterator. Note that even `hasNext` may cause mutation -- such as when iterating
+ * from an input stream, where it will block until the stream is closed or some
+ * input becomes available.
+ *
+ * Consider this example for safe and unsafe use:
+ *
+ * {{{
+ * def f[A](it: Iterator[A]) = {
+ * if (it.hasNext) { // Safe to reuse "it" after "hasNext"
+ * it.next() // Safe to reuse "it" after "next"
+ * val remainder = it.drop(2) // it is *not* safe to use "it" again after this line!
+ * remainder.take(2) // it is *not* safe to use "remainder" after this line!
+ * } else it
+ * }
+ * }}}
+ *
+ * @define mayNotTerminateInf
+ * Note: may not terminate for infinite iterators.
+ * @define preservesIterator
+ * The iterator remains valid for further use whatever result is returned.
+ * @define consumesIterator
+ * After calling this method, one should discard the iterator it was called
+ * on. Using it is undefined and subject to change.
+ * @define consumesAndProducesIterator
+ * After calling this method, one should discard the iterator it was called
+ * on, and use only the iterator that was returned. Using the old iterator
+ * is undefined, subject to change, and may result in changes to the new
+ * iterator as well.
+ * @define consumesTwoAndProducesOneIterator
+ * After calling this method, one should discard the iterator it was called
+ * on, as well as the one passed as a parameter, and use only the iterator
+ * that was returned. Using the old iterators is undefined, subject to change,
+ * and may result in changes to the new iterator as well.
+ * @define consumesOneAndProducesTwoIterators
+ * After calling this method, one should discard the iterator it was called
+ * on, and use only the iterators that were returned. Using the old iterator
+ * is undefined, subject to change, and may result in changes to the new
+ * iterators as well.
+ * @define coll iterator
+ */
+trait Iterator[+A] extends IterableOnce[A] with IterableOnceOps[A, Iterator, Iterator[A]] { self =>
+
+ /** Check if there is a next element available.
+ *
+ * @return `true` if there is a next element, `false` otherwise
+ * @note Reuse: $preservesIterator
+ */
+ def hasNext: Boolean
+
+ @deprecated("hasDefiniteSize on Iterator is the same as isEmpty", "2.13.0")
+ @`inline` override final def hasDefiniteSize = isEmpty
+
+ /** Return the next element and advance the iterator.
+ *
+ * @throws NoSuchElementException if there is no next element.
+ * @return the next element.
+ * @note Reuse: Advances the iterator, which may exhaust the elements. It is valid to
+ * make additional calls on the iterator.
+ */
+ @throws[NoSuchElementException]
+ def next(): A
+
+ @inline final def iterator = this
+
+ /** Wraps the value of `next()` in an option.
+ *
+ * @return `Some(next)` if a next element exists, `None` otherwise.
+ */
+ def nextOption(): Option[A] = if (hasNext) Some(next()) else None
+
+ /** Tests whether this iterator contains a given value as an element.
+ * $mayNotTerminateInf
+ *
+ * @param elem the element to test.
+ * @return `true` if this iterator produces some value that is
+ * is equal (as determined by `==`) to `elem`, `false` otherwise.
+ * @note Reuse: $consumesIterator
+ */
+ def contains(elem: Any): Boolean = exists(_ == elem) // Note--this seems faster than manual inlining!
+
+ /** Creates a buffered iterator from this iterator.
+ *
+ * @see [[scala.collection.BufferedIterator]]
+ * @return a buffered iterator producing the same values as this iterator.
+ * @note Reuse: $consumesAndProducesIterator
+ */
+ def buffered: BufferedIterator[A] = new AbstractIterator[A] with BufferedIterator[A] {
+ private[this] var hd: A = _
+ private[this] var hdDefined: Boolean = false
+
+ def head: A = {
+ if (!hdDefined) {
+ hd = next()
+ hdDefined = true
+ }
+ hd
+ }
+
+ override def knownSize = {
+ val thisSize = self.knownSize
+ if (thisSize >= 0 && hdDefined) thisSize + 1
+ else thisSize
+ }
+
+ def hasNext =
+ hdDefined || self.hasNext
+
+ def next() =
+ if (hdDefined) {
+ hdDefined = false
+ hd
+ } else self.next()
+ }
+
+ /** A flexible iterator for transforming an `Iterator[A]` into an
+ * `Iterator[Seq[A]]`, with configurable sequence size, step, and
+ * strategy for dealing with remainder elements which don't fit evenly
+ * into the last group.
+ *
+ * A `GroupedIterator` is yielded by `grouped` and by `sliding`,
+ * where the `step` may differ from the group `size`.
+ */
+ class GroupedIterator[B >: A](self: Iterator[B], size: Int, step: Int) extends AbstractIterator[immutable.Seq[B]] {
+
+ require(size >= 1 && step >= 1, f"size=$size%d and step=$step%d, but both must be positive")
+
+ private[this] var buffer: Array[B] = null // current result
+ private[this] var prev: Array[B] = null // if sliding, overlap from previous result
+ private[this] var first = true // if !first, advancing may skip ahead
+ private[this] var filled = false // whether the buffer is "hot"
+ private[this] var partial = true // whether to emit partial sequence
+ private[this] var padding: () => B = null // what to pad short sequences with
+ private[this] def pad = padding != null // irrespective of partial flag
+ private[this] def newBuilder = {
+ val b = ArrayBuilder.make[Any]
+ val k = self.knownSize
+ if (k > 0) b.sizeHint(k min size) // if k < size && !partial, buffer will grow on padding
+ b
+ }
+
+ /** Specifies a fill element used to pad a partial segment
+ * so that all segments have the same size.
+ *
+ * Any previous setting of `withPartial` is ignored,
+ * as the last group will always be padded to `size` elements.
+ *
+ * The by-name argument is evaluated for each fill element.
+ *
+ * @param x The element that will be appended to the last segment, if necessary.
+ * @return The same iterator, and ''not'' a new iterator.
+ * @note This method mutates the iterator it is called on, which can be safely used afterwards.
+ * @note This method is mutually exclusive with `withPartial`.
+ * @group Configuration
+ */
+ def withPadding(x: => B): this.type = {
+ padding = () => x
+ partial = true // redundant, as padding always results in complete segment
+ this
+ }
+ /** Specify whether to drop the last segment if it has less than `size` elements.
+ *
+ * If this flag is `false`, elements of a partial segment at the end of the iterator
+ * are not returned.
+ *
+ * The flag defaults to `true`.
+ *
+ * Any previous setting of `withPadding` is ignored,
+ * as the last group will never be padded.
+ * A partial segment is either retained or dropped, per the flag.
+ *
+ * @param x `true` if partial segments may be returned, `false` otherwise.
+ * @return The same iterator, and ''not'' a new iterator.
+ * @note This method mutates the iterator it is called on, which can be safely used afterwards.
+ * @note This method is mutually exclusive with `withPadding`.
+ * @group Configuration
+ */
+ def withPartial(x: Boolean): this.type = {
+ partial = x
+ padding = null
+ this
+ }
+
+ /** Eagerly fetch `size` elements to buffer.
+ *
+ * If buffer is dirty and stepping, copy prefix.
+ * If skipping, skip ahead.
+ * Fetch remaining elements.
+ * If unable to deliver size, then pad if padding enabled, otherwise drop segment.
+ * Returns true if successful in delivering `count` elements,
+ * or padded segment, or partial segment.
+ */
+ private def fulfill(): Boolean = {
+ val builder = newBuilder
+ var done = false
+ // keep prefix of previous buffer if stepping
+ if (prev != null) builder.addAll(prev)
+ // skip ahead
+ if (!first && step > size) {
+ var dropping = step - size
+ while (dropping > 0 && self.hasNext) {
+ self.next(): Unit
+ dropping -= 1
+ }
+ done = dropping > 0 // skip failed
+ }
+ var index = builder.length
+ if (!done) {
+ // advance to rest of segment if possible
+ while (index < size && self.hasNext) {
+ builder.addOne(self.next())
+ index += 1
+ }
+ // if unable to complete segment, pad if possible
+ if (index < size && pad) {
+ builder.sizeHint(size)
+ while (index < size) {
+ builder.addOne(padding())
+ index += 1
+ }
+ }
+ }
+ // segment must have data, and must be complete unless they allow partial
+ val ok = index > 0 && (partial || index == size)
+ if (ok) buffer = builder.result().asInstanceOf[Array[B]]
+ else prev = null
+ ok
+ }
+
+ // fill() returns false if no more sequences can be produced
+ private def fill(): Boolean = filled || { filled = self.hasNext && fulfill() ; filled }
+
+ def hasNext = fill()
+
+ @throws[NoSuchElementException]
+ def next(): immutable.Seq[B] =
+ if (!fill()) Iterator.empty.next()
+ else {
+ filled = false
+ // if stepping, retain overlap in prev
+ if (step < size) {
+ if (first) prev = buffer.drop(step)
+ else if (buffer.length == size) Array.copy(src = buffer, srcPos = step, dest = prev, destPos = 0, length = size - step)
+ else prev = null
+ }
+ val res = immutable.ArraySeq.unsafeWrapArray(buffer).asInstanceOf[immutable.ArraySeq[B]]
+ buffer = null
+ first = false
+ res
+ }
+ }
+
+ /** A copy of this $coll with an element value appended until a given target length is reached.
+ *
+ * @param len the target length
+ * @param elem the padding value
+ * @tparam B the element type of the returned $coll.
+ * @return a new $coll consisting of
+ * all elements of this $coll followed by the minimal number of occurrences of `elem` so
+ * that the resulting collection has a length of at least `len`.
+ */
+ def padTo[B >: A](len: Int, elem: B): Iterator[B] = new AbstractIterator[B] {
+ private[this] var i = 0
+
+ override def knownSize: Int = {
+ val thisSize = self.knownSize
+ if (thisSize < 0) -1
+ else thisSize max (len - i)
+ }
+
+ def next(): B = {
+ val b =
+ if (self.hasNext) self.next()
+ else if (i < len) elem
+ else Iterator.empty.next()
+ i += 1
+ b
+ }
+
+ def hasNext: Boolean = self.hasNext || i < len
+ }
+
+ /** Partitions this iterator in two iterators according to a predicate.
+ *
+ * @param p the predicate on which to partition
+ * @return a pair of iterators: the iterator that satisfies the predicate
+ * `p` and the iterator that does not.
+ * The relative order of the elements in the resulting iterators
+ * is the same as in the original iterator.
+ * @note Reuse: $consumesOneAndProducesTwoIterators
+ */
+ def partition(p: A => Boolean): (Iterator[A], Iterator[A]) = {
+ val (a, b) = duplicate
+ (a filter p, b filterNot p)
+ }
+
+ /** Returns an iterator which groups this iterator into fixed size
+ * blocks. Example usages:
+ * {{{
+ * // Returns List(List(1, 2, 3), List(4, 5, 6), List(7)))
+ * (1 to 7).iterator.grouped(3).toList
+ * // Returns List(List(1, 2, 3), List(4, 5, 6))
+ * (1 to 7).iterator.grouped(3).withPartial(false).toList
+ * // Returns List(List(1, 2, 3), List(4, 5, 6), List(7, 20, 25)
+ * // Illustrating that withPadding's argument is by-name.
+ * val it2 = Iterator.iterate(20)(_ + 5)
+ * (1 to 7).iterator.grouped(3).withPadding(it2.next).toList
+ * }}}
+ *
+ * @note Reuse: $consumesAndProducesIterator
+ */
+ def grouped[B >: A](size: Int): GroupedIterator[B] =
+ new GroupedIterator[B](self, size, size)
+
+ /** Returns an iterator which presents a "sliding window" view of
+ * this iterator. The first argument is the window size, and
+ * the second argument `step` is how far to advance the window
+ * on each iteration. The `step` defaults to `1`.
+ *
+ * The returned `GroupedIterator` can be configured to either
+ * pad a partial result to size `size` or suppress the partial
+ * result entirely.
+ *
+ * Example usages:
+ * {{{
+ * // Returns List(ArraySeq(1, 2, 3), ArraySeq(2, 3, 4), ArraySeq(3, 4, 5))
+ * (1 to 5).iterator.sliding(3).toList
+ * // Returns List(ArraySeq(1, 2, 3, 4), ArraySeq(4, 5))
+ * (1 to 5).iterator.sliding(4, 3).toList
+ * // Returns List(ArraySeq(1, 2, 3, 4))
+ * (1 to 5).iterator.sliding(4, 3).withPartial(false).toList
+ * // Returns List(ArraySeq(1, 2, 3, 4), ArraySeq(4, 5, 20, 25))
+ * // Illustrating that withPadding's argument is by-name.
+ * val it2 = Iterator.iterate(20)(_ + 5)
+ * (1 to 5).iterator.sliding(4, 3).withPadding(it2.next).toList
+ * }}}
+ *
+ * @param size the number of elements per group
+ * @param step the distance between the first elements of successive
+ * groups
+ * @return A `GroupedIterator` producing `Seq[B]`s of size `size`, except the
+ * last element (which may be the only element) will be truncated
+ * if there are fewer than `size` elements remaining to be grouped.
+ * This behavior can be configured.
+ *
+ * @note Reuse: $consumesAndProducesIterator
+ */
+ def sliding[B >: A](size: Int, step: Int = 1): GroupedIterator[B] =
+ new GroupedIterator[B](self, size, step)
+
+ def scanLeft[B](z: B)(op: (B, A) => B): Iterator[B] = new AbstractIterator[B] {
+ // We use an intermediate iterator that iterates through the first element `z`
+ // and then that will be modified to iterate through the collection
+ private[this] var current: Iterator[B] =
+ new AbstractIterator[B] {
+ override def knownSize = {
+ val thisSize = self.knownSize
+
+ if (thisSize < 0) -1
+ else thisSize + 1
+ }
+ def hasNext: Boolean = true
+ def next(): B = {
+ // Here we change our self-reference to a new iterator that iterates through `self`
+ current = new AbstractIterator[B] {
+ private[this] var acc = z
+ def next(): B = {
+ acc = op(acc, self.next())
+ acc
+ }
+ def hasNext: Boolean = self.hasNext
+ override def knownSize = self.knownSize
+ }
+ z
+ }
+ }
+ override def knownSize = current.knownSize
+ def next(): B = current.next()
+ def hasNext: Boolean = current.hasNext
+ }
+
+ @deprecated("Call scanRight on an Iterable instead.", "2.13.0")
+ def scanRight[B](z: B)(op: (A, B) => B): Iterator[B] = ArrayBuffer.from(this).scanRight(z)(op).iterator
+
+ def indexWhere(p: A => Boolean, from: Int = 0): Int = {
+ var i = math.max(from, 0)
+ val dropped = drop(from)
+ while (dropped.hasNext) {
+ if (p(dropped.next())) return i
+ i += 1
+ }
+ -1
+ }
+
+ /** Returns the index of the first occurrence of the specified
+ * object in this iterable object.
+ * $mayNotTerminateInf
+ *
+ * @param elem element to search for.
+ * @return the index of the first occurrence of `elem` in the values produced by this iterator,
+ * or -1 if such an element does not exist until the end of the iterator is reached.
+ * @note Reuse: $consumesIterator
+ */
+ def indexOf[B >: A](elem: B): Int = indexOf(elem, 0)
+
+ /** Returns the index of the first occurrence of the specified object in this iterable object
+ * after or at some start index.
+ * $mayNotTerminateInf
+ *
+ * @param elem element to search for.
+ * @param from the start index
+ * @return the index `>= from` of the first occurrence of `elem` in the values produced by this
+ * iterator, or -1 if such an element does not exist until the end of the iterator is
+ * reached.
+ * @note Reuse: $consumesIterator
+ */
+ def indexOf[B >: A](elem: B, from: Int): Int = {
+ var i = 0
+ while (i < from && hasNext) {
+ next()
+ i += 1
+ }
+
+ while (hasNext) {
+ if (next() == elem) return i
+ i += 1
+ }
+ -1
+ }
+
+ @inline final def length: Int = size
+
+ @deprecatedOverriding("isEmpty is defined as !hasNext; override hasNext instead", "2.13.0")
+ override def isEmpty: Boolean = !hasNext
+
+ def filter(p: A => Boolean): Iterator[A] = filterImpl(p, isFlipped = false)
+
+ def filterNot(p: A => Boolean): Iterator[A] = filterImpl(p, isFlipped = true)
+
+ private[collection] def filterImpl(p: A => Boolean, isFlipped: Boolean): Iterator[A] = new AbstractIterator[A] {
+ private[this] var hd: A = _
+ private[this] var hdDefined: Boolean = false
+
+ def hasNext: Boolean = hdDefined || {
+ if (!self.hasNext) return false
+ hd = self.next()
+ while (p(hd) == isFlipped) {
+ if (!self.hasNext) return false
+ hd = self.next()
+ }
+ hdDefined = true
+ true
+ }
+
+ def next() =
+ if (hasNext) {
+ hdDefined = false
+ hd
+ }
+ else Iterator.empty.next()
+ }
+
+ /** Creates an iterator over all the elements of this iterator that
+ * satisfy the predicate `p`. The order of the elements
+ * is preserved.
+ *
+ * '''Note:''' `withFilter` is the same as `filter` on iterators. It exists so that
+ * for-expressions with filters work over iterators.
+ *
+ * @param p the predicate used to test values.
+ * @return an iterator which produces those values of this iterator which satisfy the predicate `p`.
+ * @note Reuse: $consumesAndProducesIterator
+ */
+ def withFilter(p: A => Boolean): Iterator[A] = filter(p)
+
+ def collect[B](pf: PartialFunction[A, B]): Iterator[B] = new AbstractIterator[B] with (A => B) {
+ // Manually buffer to avoid extra layer of wrapping with buffered
+ private[this] var hd: B = _
+
+ // Little state machine to keep track of where we are
+ // Seek = 0; Found = 1; Empty = -1
+ // Not in vals because scalac won't make them static (@inline def only works with -optimize)
+ // BE REALLY CAREFUL TO KEEP COMMENTS AND NUMBERS IN SYNC!
+ private[this] var status = 0/*Seek*/
+
+ def apply(value: A): B = Statics.pfMarker.asInstanceOf[B]
+
+ def hasNext = {
+ val marker = Statics.pfMarker
+ while (status == 0/*Seek*/) {
+ if (self.hasNext) {
+ val x = self.next()
+ val v = pf.applyOrElse(x, this)
+ if (marker ne v.asInstanceOf[AnyRef]) {
+ hd = v
+ status = 1/*Found*/
+ }
+ }
+ else status = -1/*Empty*/
+ }
+ status == 1/*Found*/
+ }
+ def next() = if (hasNext) { status = 0/*Seek*/; hd } else Iterator.empty.next()
+ }
+
+ /**
+ * Builds a new iterator from this one without any duplicated elements on it.
+ * @return iterator with distinct elements
+ *
+ * @note Reuse: $consumesIterator
+ */
+ def distinct: Iterator[A] = distinctBy(identity)
+
+ /**
+ * Builds a new iterator from this one without any duplicated elements as determined by `==` after applying
+ * the transforming function `f`.
+ *
+ * @param f The transforming function whose result is used to determine the uniqueness of each element
+ * @tparam B the type of the elements after being transformed by `f`
+ * @return iterator with distinct elements
+ *
+ * @note Reuse: $consumesIterator
+ */
+ def distinctBy[B](f: A => B): Iterator[A] = new AbstractIterator[A] {
+
+ private[this] val traversedValues = mutable.HashSet.empty[B]
+ private[this] var nextElementDefined: Boolean = false
+ private[this] var nextElement: A = _
+
+ def hasNext: Boolean = nextElementDefined || (self.hasNext && {
+ val a = self.next()
+ if (traversedValues.add(f(a))) {
+ nextElement = a
+ nextElementDefined = true
+ true
+ }
+ else hasNext
+ })
+
+ def next(): A =
+ if (hasNext) {
+ nextElementDefined = false
+ nextElement
+ } else {
+ Iterator.empty.next()
+ }
+ }
+
+ def map[B](f: A => B): Iterator[B] = new AbstractIterator[B] {
+ override def knownSize = self.knownSize
+ def hasNext = self.hasNext
+ def next() = f(self.next())
+ }
+
+ def flatMap[B](f: A => IterableOnce[B]): Iterator[B] = new AbstractIterator[B] {
+ private[this] var cur: Iterator[B] = Iterator.empty
+ /** Trillium logic boolean: -1 = unknown, 0 = false, 1 = true */
+ private[this] var _hasNext: Int = -1
+
+ def nextCur(): Unit = {
+ cur = Iterator.empty
+ cur = f(self.next()).iterator
+ _hasNext = -1
+ }
+
+ def hasNext: Boolean = {
+ if (_hasNext == -1) {
+ while (!cur.hasNext) {
+ if (!self.hasNext) {
+ _hasNext = 0
+ // since we know we are exhausted, we can release cur for gc, and as well replace with
+ // static Iterator.empty which will support efficient subsequent `hasNext`/`next` calls
+ cur = Iterator.empty
+ return false
+ }
+ nextCur()
+ }
+ _hasNext = 1
+ true
+ } else _hasNext == 1
+ }
+ def next(): B = {
+ if (hasNext) {
+ _hasNext = -1
+ }
+ cur.next()
+ }
+ }
+
+ def flatten[B](implicit ev: A => IterableOnce[B]): Iterator[B] =
+ flatMap[B](ev)
+
+ def concat[B >: A](xs: => IterableOnce[B]): Iterator[B] = new Iterator.ConcatIterator[B](self).concat(xs)
+
+ @`inline` final def ++ [B >: A](xs: => IterableOnce[B]): Iterator[B] = concat(xs)
+
+ def take(n: Int): Iterator[A] = sliceIterator(0, n max 0)
+
+ def takeWhile(p: A => Boolean): Iterator[A] = new AbstractIterator[A] {
+ private[this] var hd: A = _
+ private[this] var hdDefined: Boolean = false
+ private[this] var tail: Iterator[A] = self
+
+ def hasNext = hdDefined || tail.hasNext && {
+ hd = tail.next()
+ if (p(hd)) hdDefined = true
+ else tail = Iterator.empty
+ hdDefined
+ }
+ def next() = if (hasNext) { hdDefined = false; hd } else Iterator.empty.next()
+ }
+
+ def drop(n: Int): Iterator[A] = sliceIterator(n, -1)
+
+ def dropWhile(p: A => Boolean): Iterator[A] = new AbstractIterator[A] {
+ // Magic value: -1 = hasn't dropped, 0 = found first, 1 = defer to parent iterator
+ private[this] var status = -1
+ // Local buffering to avoid double-wrap with .buffered
+ private[this] var fst: A = _
+ def hasNext: Boolean =
+ if (status == 1) self.hasNext
+ else if (status == 0) true
+ else {
+ while (self.hasNext) {
+ val a = self.next()
+ if (!p(a)) {
+ fst = a
+ status = 0
+ return true
+ }
+ }
+ status = 1
+ false
+ }
+ def next() =
+ if (hasNext) {
+ if (status == 1) self.next()
+ else {
+ status = 1
+ fst
+ }
+ }
+ else Iterator.empty.next()
+ }
+
+ /**
+ * @inheritdoc
+ *
+ * @note Reuse: $consumesOneAndProducesTwoIterators
+ */
+ def span(p: A => Boolean): (Iterator[A], Iterator[A]) = {
+ /*
+ * Giving a name to following iterator (as opposed to trailing) because
+ * anonymous class is represented as a structural type that trailing
+ * iterator is referring (the finish() method) and thus triggering
+ * handling of structural calls. It's not what's intended here.
+ */
+ final class Leading extends AbstractIterator[A] {
+ private[this] var lookahead: mutable.Queue[A] = null
+ private[this] var hd: A = _
+ /* Status is kept with magic numbers
+ * 1 means next element is in hd and we're still reading into this iterator
+ * 0 means we're still reading but haven't found a next element
+ * -1 means we are done reading into the iterator, so we must rely on lookahead
+ * -2 means we are done but have saved hd for the other iterator to use as its first element
+ */
+ private[this] var status = 0
+ private def store(a: A): Unit = {
+ if (lookahead == null) lookahead = new mutable.Queue[A]
+ lookahead += a
+ }
+ def hasNext = {
+ if (status < 0) (lookahead ne null) && lookahead.nonEmpty
+ else if (status > 0) true
+ else {
+ if (self.hasNext) {
+ hd = self.next()
+ status = if (p(hd)) 1 else -2
+ }
+ else status = -1
+ status > 0
+ }
+ }
+ def next() = {
+ if (hasNext) {
+ if (status == 1) { status = 0; hd }
+ else lookahead.dequeue()
+ }
+ else Iterator.empty.next()
+ }
+ @tailrec
+ def finish(): Boolean = status match {
+ case -2 => status = -1 ; true
+ case -1 => false
+ case 1 => store(hd) ; status = 0 ; finish()
+ case 0 =>
+ status = -1
+ while (self.hasNext) {
+ val a = self.next()
+ if (p(a)) store(a)
+ else {
+ hd = a
+ return true
+ }
+ }
+ false
+ }
+ def trailer: A = hd
+ }
+
+ val leading = new Leading
+
+ val trailing = new AbstractIterator[A] {
+ private[this] var myLeading = leading
+ /* Status flag meanings:
+ * -1 not yet accessed
+ * 0 single element waiting in leading
+ * 1 defer to self
+ * 2 self.hasNext already
+ * 3 exhausted
+ */
+ private[this] var status = -1
+ def hasNext = status match {
+ case 3 => false
+ case 2 => true
+ case 1 => if (self.hasNext) { status = 2 ; true } else { status = 3 ; false }
+ case 0 => true
+ case _ =>
+ if (myLeading.finish()) { status = 0 ; true } else { status = 1 ; myLeading = null ; hasNext }
+ }
+ def next() = {
+ if (hasNext) {
+ if (status == 0) {
+ status = 1
+ val res = myLeading.trailer
+ myLeading = null
+ res
+ } else {
+ status = 1
+ self.next()
+ }
+ }
+ else Iterator.empty.next()
+ }
+ }
+
+ (leading, trailing)
+ }
+
+ def slice(from: Int, until: Int): Iterator[A] = sliceIterator(from, until max 0)
+
+ /** Creates an optionally bounded slice, unbounded if `until` is negative. */
+ protected def sliceIterator(from: Int, until: Int): Iterator[A] = {
+ val lo = from max 0
+ val rest =
+ if (until < 0) -1 // unbounded
+ else if (until <= lo) 0 // empty
+ else until - lo // finite
+
+ if (rest == 0) Iterator.empty
+ else new Iterator.SliceIterator(this, lo, rest)
+ }
+
+ def zip[B](that: IterableOnce[B]): Iterator[(A, B)] = new AbstractIterator[(A, B)] {
+ val thatIterator = that.iterator
+ override def knownSize = self.knownSize min thatIterator.knownSize
+ def hasNext = self.hasNext && thatIterator.hasNext
+ def next() = (self.next(), thatIterator.next())
+ }
+
+ def zipAll[A1 >: A, B](that: IterableOnce[B], thisElem: A1, thatElem: B): Iterator[(A1, B)] = new AbstractIterator[(A1, B)] {
+ val thatIterator = that.iterator
+ override def knownSize = {
+ val thisSize = self.knownSize
+ val thatSize = thatIterator.knownSize
+ if (thisSize < 0 || thatSize < 0) -1
+ else thisSize max thatSize
+ }
+ def hasNext = self.hasNext || thatIterator.hasNext
+ def next(): (A1, B) = {
+ val next1 = self.hasNext
+ val next2 = thatIterator.hasNext
+ if(!(next1 || next2)) throw new NoSuchElementException
+ (if(next1) self.next() else thisElem, if(next2) thatIterator.next() else thatElem)
+ }
+ }
+
+ def zipWithIndex: Iterator[(A, Int)] = new AbstractIterator[(A, Int)] {
+ var idx = 0
+ override def knownSize = self.knownSize
+ def hasNext = self.hasNext
+ def next() = {
+ val ret = (self.next(), idx)
+ idx += 1
+ ret
+ }
+ }
+
+ /** Checks whether corresponding elements of the given iterable collection
+ * compare equal (with respect to `==`) to elements of this $coll.
+ *
+ * @param that the collection to compare
+ * @tparam B the type of the elements of collection `that`.
+ * @return `true` if both collections contain equal elements in the same order, `false` otherwise.
+ *
+ * @inheritdoc
+ */
+ def sameElements[B >: A](that: IterableOnce[B]): Boolean = {
+ val those = that.iterator
+ while (hasNext && those.hasNext)
+ if (next() != those.next())
+ return false
+ // At that point we know that *at least one* iterator has no next element
+ // If *both* of them have no elements then the collections are the same
+ hasNext == those.hasNext
+ }
+
+ /** Creates two new iterators that both iterate over the same elements
+ * as this iterator (in the same order). The duplicate iterators are
+ * considered equal if they are positioned at the same element.
+ *
+ * Given that most methods on iterators will make the original iterator
+ * unfit for further use, this methods provides a reliable way of calling
+ * multiple such methods on an iterator.
+ *
+ * @return a pair of iterators
+ * @note The implementation may allocate temporary storage for elements
+ * iterated by one iterator but not yet by the other.
+ * @note Reuse: $consumesOneAndProducesTwoIterators
+ */
+ def duplicate: (Iterator[A], Iterator[A]) = {
+ val gap = new scala.collection.mutable.Queue[A]
+ var ahead: Iterator[A] = null
+ class Partner extends AbstractIterator[A] {
+ override def knownSize: Int = self.synchronized {
+ val thisSize = self.knownSize
+
+ if (this eq ahead) thisSize
+ else if (thisSize < 0 || gap.knownSize < 0) -1
+ else thisSize + gap.knownSize
+ }
+ def hasNext: Boolean = self.synchronized {
+ (this ne ahead) && !gap.isEmpty || self.hasNext
+ }
+ def next(): A = self.synchronized {
+ if (gap.isEmpty) ahead = this
+ if (this eq ahead) {
+ val e = self.next()
+ gap enqueue e
+ e
+ } else gap.dequeue()
+ }
+ // to verify partnerhood we use reference equality on gap because
+ // type testing does not discriminate based on origin.
+ private def compareGap(queue: scala.collection.mutable.Queue[A]) = gap eq queue
+ override def hashCode = gap.hashCode()
+ override def equals(other: Any) = other match {
+ case x: Partner => x.compareGap(gap) && gap.isEmpty
+ case _ => super.equals(other)
+ }
+ }
+ (new Partner, new Partner)
+ }
+
+ /** Returns this iterator with patched values.
+ * Patching at negative indices is the same as patching starting at 0.
+ * Patching at indices at or larger than the length of the original iterator appends the patch to the end.
+ * If more values are replaced than actually exist, the excess is ignored.
+ *
+ * @param from The start index from which to patch
+ * @param patchElems The iterator of patch values
+ * @param replaced The number of values in the original iterator that are replaced by the patch.
+ * @note Reuse: $consumesTwoAndProducesOneIterator
+ */
+ def patch[B >: A](from: Int, patchElems: Iterator[B], replaced: Int): Iterator[B] =
+ new AbstractIterator[B] {
+ private[this] var origElems = self
+ // > 0 => that many more elems from `origElems` before switching to `patchElems`
+ // 0 => need to drop elems from `origElems` and start using `patchElems`
+ // -1 => have dropped elems from `origElems`, will be using `patchElems` until it's empty
+ // and then using what's left of `origElems` after the drop
+ private[this] var state = if (from > 0) from else 0
+
+ // checks state and handles 0 => -1
+ @inline private[this] def switchToPatchIfNeeded(): Unit =
+ if (state == 0) {
+ origElems = origElems drop replaced
+ state = -1
+ }
+
+ def hasNext: Boolean = {
+ switchToPatchIfNeeded()
+ origElems.hasNext || patchElems.hasNext
+ }
+
+ def next(): B = {
+ switchToPatchIfNeeded()
+ if (state < 0 /* == -1 */) {
+ if (patchElems.hasNext) patchElems.next()
+ else origElems.next()
+ }
+ else {
+ if (origElems.hasNext) {
+ state -= 1
+ origElems.next()
+ }
+ else {
+ state = -1
+ patchElems.next()
+ }
+ }
+ }
+ }
+
+ override def tapEach[U](f: A => U): Iterator[A] = new AbstractIterator[A] {
+ override def knownSize = self.knownSize
+ override def hasNext = self.hasNext
+ override def next() = {
+ val _next = self.next()
+ f(_next)
+ _next
+ }
+ }
+
+ /** Converts this iterator to a string.
+ *
+ * @return `""`
+ * @note Reuse: $preservesIterator
+ */
+ override def toString = ""
+
+ @deprecated("Iterator.seq always returns the iterator itself", "2.13.0")
+ def seq: this.type = this
+}
+
+@SerialVersionUID(3L)
+object Iterator extends IterableFactory[Iterator] {
+
+ private[this] val _empty: Iterator[Nothing] = new AbstractIterator[Nothing] {
+ def hasNext = false
+ def next() = throw new NoSuchElementException("next on empty iterator")
+ override def knownSize: Int = 0
+ override protected def sliceIterator(from: Int, until: Int): AbstractIterator[Nothing] = this
+ }
+
+ /** Creates a target $coll from an existing source collection
+ *
+ * @param source Source collection
+ * @tparam A the type of the collection’s elements
+ * @return a new $coll with the elements of `source`
+ */
+ override def from[A](source: IterableOnce[A]): Iterator[A] = source.iterator
+
+ /** The iterator which produces no values. */
+ @`inline` final def empty[T]: Iterator[T] = _empty
+
+ def single[A](a: A): Iterator[A] = new AbstractIterator[A] {
+ private[this] var consumed: Boolean = false
+ def hasNext = !consumed
+ def next() = if (consumed) empty.next() else { consumed = true; a }
+ override protected def sliceIterator(from: Int, until: Int) =
+ if (consumed || from > 0 || until == 0) empty
+ else this
+ }
+
+ override def apply[A](xs: A*): Iterator[A] = xs.iterator
+
+ /**
+ * @return A builder for $Coll objects.
+ * @tparam A the type of the ${coll}’s elements
+ */
+ def newBuilder[A]: Builder[A, Iterator[A]] =
+ new ImmutableBuilder[A, Iterator[A]](empty[A]) {
+ override def addOne(elem: A): this.type = { elems = elems ++ single(elem); this }
+ }
+
+ /** Creates iterator that produces the results of some element computation a number of times.
+ *
+ * @param len the number of elements returned by the iterator.
+ * @param elem the element computation
+ * @return An iterator that produces the results of `n` evaluations of `elem`.
+ */
+ override def fill[A](len: Int)(elem: => A): Iterator[A] = new AbstractIterator[A] {
+ private[this] var i = 0
+ override def knownSize: Int = (len - i) max 0
+ def hasNext: Boolean = i < len
+ def next(): A =
+ if (hasNext) { i += 1; elem }
+ else empty.next()
+ }
+
+ /** Creates an iterator producing the values of a given function over a range of integer values starting from 0.
+ *
+ * @param end The number of elements returned by the iterator
+ * @param f The function computing element values
+ * @return An iterator that produces the values `f(0), ..., f(n -1)`.
+ */
+ override def tabulate[A](end: Int)(f: Int => A): Iterator[A] = new AbstractIterator[A] {
+ private[this] var i = 0
+ override def knownSize: Int = (end - i) max 0
+ def hasNext: Boolean = i < end
+ def next(): A =
+ if (hasNext) { val result = f(i); i += 1; result }
+ else empty.next()
+ }
+
+ /** Creates an infinite-length iterator which returns successive values from some start value.
+
+ * @param start the start value of the iterator
+ * @return the iterator producing the infinite sequence of values `start, start + 1, start + 2, ...`
+ */
+ def from(start: Int): Iterator[Int] = from(start, 1)
+
+ /** Creates an infinite-length iterator returning values equally spaced apart.
+ *
+ * @param start the start value of the iterator
+ * @param step the increment between successive values
+ * @return the iterator producing the infinite sequence of values `start, start + 1 * step, start + 2 * step, ...`
+ */
+ def from(start: Int, step: Int): Iterator[Int] = new AbstractIterator[Int] {
+ private[this] var i = start
+ def hasNext: Boolean = true
+ def next(): Int = { val result = i; i += step; result }
+ }
+
+ /** Creates nn iterator returning successive values in some integer interval.
+ *
+ * @param start the start value of the iterator
+ * @param end the end value of the iterator (the first value NOT returned)
+ * @return the iterator producing values `start, start + 1, ..., end - 1`
+ */
+ def range(start: Int, end: Int): Iterator[Int] = range(start, end, 1)
+
+ /** An iterator producing equally spaced values in some integer interval.
+ *
+ * @param start the start value of the iterator
+ * @param end the end value of the iterator (the first value NOT returned)
+ * @param step the increment value of the iterator (must be positive or negative)
+ * @return the iterator producing values `start, start + step, ...` up to, but excluding `end`
+ */
+ def range(start: Int, end: Int, step: Int): Iterator[Int] = new AbstractIterator[Int] {
+ if (step == 0) throw new IllegalArgumentException("zero step")
+ private[this] var i = start
+ private[this] var hasOverflowed = false
+ override def knownSize: Int = {
+ val size = math.ceil((end.toLong - i.toLong) / step.toDouble)
+ if (size < 0) 0
+ else if (size > Int.MaxValue) -1
+ else size.toInt
+ }
+ def hasNext: Boolean = {
+ (step <= 0 || i < end) && (step >= 0 || i > end) && !hasOverflowed
+ }
+ def next(): Int =
+ if (hasNext) {
+ val result = i
+ val nextValue = i + step
+ hasOverflowed = (step > 0) == nextValue < i
+ i = nextValue
+ result
+ }
+ else empty.next()
+ }
+
+ /** Creates an infinite iterator that repeatedly applies a given function to the previous result.
+ *
+ * @param start the start value of the iterator
+ * @param f the function that's repeatedly applied
+ * @return the iterator producing the infinite sequence of values `start, f(start), f(f(start)), ...`
+ */
+ def iterate[T](start: T)(f: T => T): Iterator[T] = new AbstractIterator[T] {
+ private[this] var first = true
+ private[this] var acc = start
+ def hasNext: Boolean = true
+ def next(): T = {
+ if (first) first = false
+ else acc = f(acc)
+
+ acc
+ }
+ }
+
+ /** Creates an Iterator 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
+ * @return an Iterator that produces elements using `f` until `f` returns `None`
+ */
+ override def unfold[A, S](init: S)(f: S => Option[(A, S)]): Iterator[A] = new UnfoldIterator(init)(f)
+
+ /** Creates an infinite-length iterator returning the results of evaluating an expression.
+ * The expression is recomputed for every element.
+ *
+ * @param elem the element computation.
+ * @return the iterator containing an infinite number of results of evaluating `elem`.
+ */
+ def continually[A](elem: => A): Iterator[A] = new AbstractIterator[A] {
+ def hasNext = true
+ def next() = elem
+ }
+
+ /** Creates an iterator to which other iterators can be appended efficiently.
+ * Nested ConcatIterators are merged to avoid blowing the stack.
+ */
+ private final class ConcatIterator[+A](private var current: Iterator[A @uncheckedVariance]) extends AbstractIterator[A] {
+ private var tail: ConcatIteratorCell[A @uncheckedVariance] = null
+ private var last: ConcatIteratorCell[A @uncheckedVariance] = null
+ private var currentHasNextChecked = false
+
+ def hasNext =
+ if (currentHasNextChecked) true
+ else if (current == null) false
+ else if (current.hasNext) {
+ currentHasNextChecked = true
+ true
+ }
+ else {
+ // If we advanced the current iterator to a ConcatIterator, merge it into this one
+ @tailrec def merge(): Unit =
+ if (current.isInstanceOf[ConcatIterator[_]]) {
+ val c = current.asInstanceOf[ConcatIterator[A]]
+ current = c.current
+ currentHasNextChecked = c.currentHasNextChecked
+ if (c.tail != null) {
+ if (last == null) last = c.last
+ c.last.tail = tail
+ tail = c.tail
+ }
+ merge()
+ }
+
+ // Advance current to the next non-empty iterator
+ // current is set to null when all iterators are exhausted
+ @tailrec def advance(): Boolean =
+ if (tail == null) {
+ current = null
+ last = null
+ false
+ }
+ else {
+ current = tail.headIterator
+ if (last eq tail) last = last.tail
+ tail = tail.tail
+ merge()
+ if (currentHasNextChecked) true
+ else if (current != null && current.hasNext) {
+ currentHasNextChecked = true
+ true
+ } else advance()
+ }
+
+ advance()
+ }
+
+ def next() =
+ if (hasNext) {
+ currentHasNextChecked = false
+ current.next()
+ } else Iterator.empty.next()
+
+ override def concat[B >: A](that: => IterableOnce[B]): Iterator[B] = {
+ val c = new ConcatIteratorCell[B](that, null).asInstanceOf[ConcatIteratorCell[A]]
+ if (tail == null) {
+ tail = c
+ last = c
+ }
+ else {
+ last.tail = c
+ last = c
+ }
+ if (current == null) current = Iterator.empty
+ this
+ }
+ }
+
+ private[this] final class ConcatIteratorCell[A](head: => IterableOnce[A], var tail: ConcatIteratorCell[A]) {
+ def headIterator: Iterator[A] = head.iterator
+ }
+
+ /** Creates a delegating iterator capped by a limit count. Negative limit means unbounded.
+ * Lazily skip to start on first evaluation. Avoids daisy-chained iterators due to slicing.
+ */
+ private[scala] final class SliceIterator[A](val underlying: Iterator[A], start: Int, limit: Int) extends AbstractIterator[A] {
+ private[this] var remaining = limit
+ private[this] var dropping = start
+ @inline private def unbounded = remaining < 0
+ private def skip(): Unit =
+ while (dropping > 0) {
+ if (underlying.hasNext) {
+ underlying.next()
+ dropping -= 1
+ } else
+ dropping = 0
+ }
+ override def knownSize: Int = {
+ val size = underlying.knownSize
+ if (size < 0) -1
+ else {
+ val dropSize = 0 max (size - dropping)
+ if (unbounded) dropSize
+ else remaining min dropSize
+ }
+ }
+ def hasNext = { skip(); remaining != 0 && underlying.hasNext }
+ def next() = {
+ skip()
+ if (remaining > 0) {
+ remaining -= 1
+ underlying.next()
+ }
+ else if (unbounded) underlying.next()
+ else empty.next()
+ }
+ override protected def sliceIterator(from: Int, until: Int): Iterator[A] = {
+ val lo = from max 0
+ def adjustedBound =
+ if (unbounded) -1
+ else 0 max (remaining - lo)
+ val rest =
+ if (until < 0) adjustedBound // respect current bound, if any
+ else if (until <= lo) 0 // empty
+ else if (unbounded) until - lo // now finite
+ else adjustedBound min (until - lo) // keep lesser bound
+ val sum = dropping + lo
+ if (rest == 0) empty
+ else if (sum < 0) {
+ dropping = Int.MaxValue
+ remaining = 0
+ this.concat(new SliceIterator(underlying, start = sum - Int.MaxValue, limit = rest))
+ }
+ else {
+ dropping = sum
+ remaining = rest
+ this
+ }
+ }
+ }
+
+ /** Creates an iterator that uses a function `f` to produce elements of
+ * type `A` and update an internal state of type `S`.
+ */
+ private final class UnfoldIterator[A, S](init: S)(f: S => Option[(A, S)]) extends AbstractIterator[A] {
+ private[this] var state: S = init
+ private[this] var nextResult: Option[(A, S)] = null
+
+ override def hasNext: Boolean = {
+ if (nextResult eq null) {
+ nextResult = {
+ val res = f(state)
+ if (res eq null) throw new NullPointerException("null during unfold")
+ res
+ }
+ state = null.asInstanceOf[S] // allow GC
+ }
+ nextResult.isDefined
+ }
+
+ override def next(): A = {
+ if (hasNext) {
+ val (value, newState) = nextResult.get
+ state = newState
+ nextResult = null
+ value
+ } else Iterator.empty.next()
+ }
+ }
+}
+
+/** Explicit instantiation of the `Iterator` trait to reduce class file size in subclasses. */
+abstract class AbstractIterator[+A] extends Iterator[A]
diff --git a/library/src/scala/collection/JavaConverters.scala b/library/src/scala/collection/JavaConverters.scala
new file mode 100644
index 000000000000..7a803a685d3e
--- /dev/null
+++ b/library/src/scala/collection/JavaConverters.scala
@@ -0,0 +1,335 @@
+/*
+ * 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.{concurrent => juc}
+import java.{lang => jl, util => ju}
+
+import scala.collection.convert._
+import scala.language.implicitConversions
+
+/** A variety of decorators that enable converting between
+ * Scala and Java collections using extension methods, `asScala` and `asJava`.
+ *
+ * The extension methods return adapters for the corresponding API.
+ *
+ * The following conversions are supported via `asScala` and `asJava`:
+ *{{{
+ * scala.collection.Iterable <=> java.lang.Iterable
+ * scala.collection.Iterator <=> java.util.Iterator
+ * scala.collection.mutable.Buffer <=> java.util.List
+ * scala.collection.mutable.Set <=> java.util.Set
+ * scala.collection.mutable.Map <=> java.util.Map
+ * scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap
+ *}}}
+ * The following conversions are supported via `asScala` and through
+ * specially-named extension methods to convert to Java collections, as shown:
+ *{{{
+ * scala.collection.Iterable <=> java.util.Collection (via asJavaCollection)
+ * scala.collection.Iterator <=> java.util.Enumeration (via asJavaEnumeration)
+ * scala.collection.mutable.Map <=> java.util.Dictionary (via asJavaDictionary)
+ *}}}
+ * In addition, the following one-way conversions are provided via `asJava`:
+ *{{{
+ * scala.collection.Seq => java.util.List
+ * scala.collection.mutable.Seq => java.util.List
+ * scala.collection.Set => java.util.Set
+ * scala.collection.Map => java.util.Map
+ *}}}
+ * The following one way conversion is provided via `asScala`:
+ *{{{
+ * java.util.Properties => scala.collection.mutable.Map
+ *}}}
+ * In all cases, converting from a source type to a target type and back
+ * again will return the original source object. For example:
+ * {{{
+ * import scala.collection.JavaConverters._
+ *
+ * val source = new scala.collection.mutable.ListBuffer[Int]
+ * val target: java.util.List[Int] = source.asJava
+ * val other: scala.collection.mutable.Buffer[Int] = target.asScala
+ * assert(source eq other)
+ * }}}
+ * Alternatively, the conversion methods have descriptive names and can be invoked explicitly.
+ * {{{
+ * scala> val vs = java.util.Arrays.asList("hi", "bye")
+ * vs: java.util.List[String] = [hi, bye]
+ *
+ * scala> val ss = asScalaIterator(vs.iterator)
+ * ss: Iterator[String] =
+ *
+ * scala> .toList
+ * res0: List[String] = List(hi, bye)
+ *
+ * scala> val ss = asScalaBuffer(vs)
+ * ss: scala.collection.mutable.Buffer[String] = Buffer(hi, bye)
+ * }}}
+ */
+@deprecated("Use `scala.jdk.CollectionConverters` instead", "2.13.0")
+object JavaConverters extends AsJavaConverters with AsScalaConverters {
+ @deprecated("Use `asJava` instead", "2.13.0")
+ def asJavaIterator[A](i: Iterator[A]): ju.Iterator[A] = asJava(i)
+
+ @deprecated("Use `asJava` instead", "2.13.0")
+ def asJavaIterable[A](i: Iterable[A]): jl.Iterable[A] = asJava(i)
+
+ @deprecated("Use `asJava` instead", "2.13.0")
+ def bufferAsJavaList[A](b: mutable.Buffer[A]): ju.List[A] = asJava(b)
+
+ @deprecated("Use `asJava` instead", "2.13.0")
+ def mutableSeqAsJavaList[A](s: mutable.Seq[A]): ju.List[A] = asJava(s)
+
+ @deprecated("Use `asJava` instead", "2.13.0")
+ def seqAsJavaList[A](s: Seq[A]): ju.List[A] = asJava(s)
+
+ @deprecated("Use `asJava` instead", "2.13.0")
+ def mutableSetAsJavaSet[A](s: mutable.Set[A]): ju.Set[A] = asJava(s)
+
+ @deprecated("Use `asJava` instead", "2.13.0")
+ def setAsJavaSet[A](s: Set[A]): ju.Set[A] = asJava(s)
+
+ @deprecated("Use `asJava` instead", "2.13.0")
+ def mutableMapAsJavaMap[K, V](m: mutable.Map[K, V]): ju.Map[K, V] = asJava(m)
+
+ @deprecated("Use `asJava` instead", "2.13.0")
+ def mapAsJavaMap[K, V](m: Map[K, V]): ju.Map[K, V] = asJava(m)
+
+ @deprecated("Use `asJava` instead", "2.13.0")
+ def mapAsJavaConcurrentMap[K, V](m: concurrent.Map[K, V]): juc.ConcurrentMap[K, V] = asJava(m)
+
+
+ @deprecated("Use `asScala` instead", "2.13.0")
+ def asScalaIterator[A](i: ju.Iterator[A]): Iterator[A] = asScala(i)
+
+ @deprecated("Use `asScala` instead", "2.13.0")
+ def enumerationAsScalaIterator[A](i: ju.Enumeration[A]): Iterator[A] = asScala(i)
+
+ @deprecated("Use `asScala` instead", "2.13.0")
+ def iterableAsScalaIterable[A](i: jl.Iterable[A]): Iterable[A] = asScala(i)
+
+ @deprecated("Use `asScala` instead", "2.13.0")
+ def collectionAsScalaIterable[A](i: ju.Collection[A]): Iterable[A] = asScala(i)
+
+ @deprecated("Use `asScala` instead", "2.13.0")
+ def asScalaBuffer[A](l: ju.List[A]): mutable.Buffer[A] = asScala(l)
+
+ @deprecated("Use `asScala` instead", "2.13.0")
+ def asScalaSet[A](s: ju.Set[A]): mutable.Set[A] = asScala(s)
+
+ @deprecated("Use `asScala` instead", "2.13.0")
+ def mapAsScalaMap[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = asScala(m)
+
+ @deprecated("Use `asScala` instead", "2.13.0")
+ def mapAsScalaConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = asScala(m)
+
+ @deprecated("Use `asScala` instead", "2.13.0")
+ def dictionaryAsScalaMap[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = asScala(p)
+
+ @deprecated("Use `asScala` instead", "2.13.0")
+ def propertiesAsScalaMap(p: ju.Properties): mutable.Map[String, String] = asScala(p)
+
+ // Deprecated implicit conversions for code that directly imports them
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala `Iterator` to a Java `Iterator`.
+ * @see [[asJavaIterator]]
+ */
+ implicit def asJavaIteratorConverter[A](i : Iterator[A]): AsJava[ju.Iterator[A]] =
+ new AsJava(asJavaIterator(i))
+
+ /**
+ * Adds an `asJavaEnumeration` method that implicitly converts a Scala `Iterator` to a Java `Enumeration`.
+ * @see [[asJavaEnumeration]]
+ */
+ implicit def asJavaEnumerationConverter[A](i : Iterator[A]): AsJavaEnumeration[A] =
+ new AsJavaEnumeration(i)
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala `Iterable` to a Java `Iterable`.
+ * @see [[asJavaIterable]]
+ */
+ implicit def asJavaIterableConverter[A](i : Iterable[A]): AsJava[jl.Iterable[A]] =
+ new AsJava(asJavaIterable(i))
+
+ /**
+ * Adds an `asJavaCollection` method that implicitly converts a Scala `Iterable` to an immutable Java `Collection`.
+ * @see [[asJavaCollection]]
+ */
+ implicit def asJavaCollectionConverter[A](i : Iterable[A]): AsJavaCollection[A] =
+ new AsJavaCollection(i)
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala mutable `Buffer` to a Java `List`.
+ * @see [[bufferAsJavaList]]
+ */
+ implicit def bufferAsJavaListConverter[A](b : mutable.Buffer[A]): AsJava[ju.List[A]] =
+ new AsJava(bufferAsJavaList(b))
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala mutable `Seq` to a Java `List`.
+ * @see [[mutableSeqAsJavaList]]
+ */
+ implicit def mutableSeqAsJavaListConverter[A](b : mutable.Seq[A]): AsJava[ju.List[A]] =
+ new AsJava(mutableSeqAsJavaList(b))
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala `Seq` to a Java `List`.
+ * @see [[seqAsJavaList]]
+ */
+ implicit def seqAsJavaListConverter[A](b : Seq[A]): AsJava[ju.List[A]] =
+ new AsJava(seqAsJavaList(b))
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala mutable `Set` to a Java `Set`.
+ * @see [[mutableSetAsJavaSet]]
+ */
+ implicit def mutableSetAsJavaSetConverter[A](s : mutable.Set[A]): AsJava[ju.Set[A]] =
+ new AsJava(mutableSetAsJavaSet(s))
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala `Set` to a Java `Set`.
+ * @see [[setAsJavaSet]]
+ */
+ implicit def setAsJavaSetConverter[A](s : Set[A]): AsJava[ju.Set[A]] =
+ new AsJava(setAsJavaSet(s))
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala mutable `Map` to a Java `Map`.
+ * @see [[mutableMapAsJavaMap]]
+ */
+ implicit def mutableMapAsJavaMapConverter[K, V](m : mutable.Map[K, V]): AsJava[ju.Map[K, V]] =
+ new AsJava(mutableMapAsJavaMap(m))
+
+ /**
+ * Adds an `asJavaDictionary` method that implicitly converts a Scala mutable `Map` to a Java `Dictionary`.
+ * @see [[asJavaDictionary]]
+ */
+ implicit def asJavaDictionaryConverter[K, V](m : mutable.Map[K, V]): AsJavaDictionary[K, V] =
+ new AsJavaDictionary(m)
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala `Map` to a Java `Map`.
+ * @see [[mapAsJavaMap]]
+ */
+ implicit def mapAsJavaMapConverter[K, V](m : Map[K, V]): AsJava[ju.Map[K, V]] =
+ new AsJava(mapAsJavaMap(m))
+
+ /**
+ * Adds an `asJava` method that implicitly converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`.
+ * @see [[mapAsJavaConcurrentMap]].
+ */
+ implicit def mapAsJavaConcurrentMapConverter[K, V](m: concurrent.Map[K, V]): AsJava[juc.ConcurrentMap[K, V]] =
+ new AsJava(mapAsJavaConcurrentMap(m))
+
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Iterator` to a Scala `Iterator`.
+ * @see [[asScalaIterator]]
+ */
+ implicit def asScalaIteratorConverter[A](i : ju.Iterator[A]): AsScala[Iterator[A]] =
+ new AsScala(asScalaIterator(i))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Enumeration` to a Scala `Iterator`.
+ * @see [[enumerationAsScalaIterator]]
+ */
+ implicit def enumerationAsScalaIteratorConverter[A](i : ju.Enumeration[A]): AsScala[Iterator[A]] =
+ new AsScala(enumerationAsScalaIterator(i))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Iterable` to a Scala `Iterable`.
+ * @see [[iterableAsScalaIterable]]
+ */
+ implicit def iterableAsScalaIterableConverter[A](i : jl.Iterable[A]): AsScala[Iterable[A]] =
+ new AsScala(iterableAsScalaIterable(i))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Collection` to an Scala `Iterable`.
+ * @see [[collectionAsScalaIterable]]
+ */
+ implicit def collectionAsScalaIterableConverter[A](i : ju.Collection[A]): AsScala[Iterable[A]] =
+ new AsScala(collectionAsScalaIterable(i))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `List` to a Scala mutable `Buffer`.
+ * @see [[asScalaBuffer]]
+ */
+ implicit def asScalaBufferConverter[A](l : ju.List[A]): AsScala[mutable.Buffer[A]] =
+ new AsScala(asScalaBuffer(l))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Set` to a Scala mutable `Set`.
+ * @see [[asScalaSet]]
+ */
+ implicit def asScalaSetConverter[A](s : ju.Set[A]): AsScala[mutable.Set[A]] =
+ new AsScala(asScalaSet(s))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Map` to a Scala mutable `Map`.
+ * @see [[mapAsScalaMap]]
+ */
+ implicit def mapAsScalaMapConverter[K, V](m : ju.Map[K, V]): AsScala[mutable.Map[K, V]] =
+ new AsScala(mapAsScalaMap(m))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `ConcurrentMap` to a Scala mutable `concurrent.Map`.
+ * @see [[mapAsScalaConcurrentMap]]
+ */
+ implicit def mapAsScalaConcurrentMapConverter[K, V](m: juc.ConcurrentMap[K, V]): AsScala[concurrent.Map[K, V]] =
+ new AsScala(mapAsScalaConcurrentMap(m))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Dictionary` to a Scala mutable `Map`.
+ * @see [[dictionaryAsScalaMap]]
+ */
+ implicit def dictionaryAsScalaMapConverter[K, V](p: ju.Dictionary[K, V]): AsScala[mutable.Map[K, V]] =
+ new AsScala(dictionaryAsScalaMap(p))
+
+ /**
+ * Adds an `asScala` method that implicitly converts a Java `Properties` to a Scala mutable `Map[String, String]`.
+ * @see [[propertiesAsScalaMap]]
+ */
+ implicit def propertiesAsScalaMapConverter(p: ju.Properties): AsScala[mutable.Map[String, String]] =
+ new AsScala(propertiesAsScalaMap(p))
+
+
+ /** Generic class containing the `asJava` converter method */
+ class AsJava[A](op: => A) {
+ /** Converts a Scala collection to the corresponding Java collection */
+ def asJava: A = op
+ }
+
+ /** Generic class containing the `asScala` converter method */
+ class AsScala[A](op: => A) {
+ /** Converts a Java collection to the corresponding Scala collection */
+ def asScala: A = op
+ }
+
+ /** Generic class containing the `asJavaCollection` converter method */
+ class AsJavaCollection[A](i: Iterable[A]) {
+ /** Converts a Scala `Iterable` to a Java `Collection` */
+ def asJavaCollection: ju.Collection[A] = JavaConverters.asJavaCollection(i)
+ }
+
+ /** Generic class containing the `asJavaEnumeration` converter method */
+ class AsJavaEnumeration[A](i: Iterator[A]) {
+ /** Converts a Scala `Iterator` to a Java `Enumeration` */
+ def asJavaEnumeration: ju.Enumeration[A] = JavaConverters.asJavaEnumeration(i)
+ }
+
+ /** Generic class containing the `asJavaDictionary` converter method */
+ class AsJavaDictionary[K, V](m : mutable.Map[K, V]) {
+ /** Converts a Scala `Map` to a Java `Dictionary` */
+ def asJavaDictionary: ju.Dictionary[K, V] = JavaConverters.asJavaDictionary(m)
+ }
+}
diff --git a/library/src/scala/collection/LazyZipOps.scala b/library/src/scala/collection/LazyZipOps.scala
new file mode 100644
index 000000000000..a7a72ce882a8
--- /dev/null
+++ b/library/src/scala/collection/LazyZipOps.scala
@@ -0,0 +1,422 @@
+/*
+ * 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 scala.language.implicitConversions
+
+/** Decorator representing lazily zipped pairs.
+ *
+ * @define coll pair
+ * @define willNotTerminateInf
+ *
+ * Note: will not terminate for infinite-sized collections.
+ */
+final class LazyZip2[+El1, +El2, C1] private[collection](src: C1, coll1: Iterable[El1], coll2: Iterable[El2]) {
+
+ /** Zips `that` iterable collection with an existing `LazyZip2`. The elements in each collection are
+ * not consumed until a strict operation is invoked on the returned `LazyZip3` decorator.
+ *
+ * @param that the iterable providing the third element of each eventual triple
+ * @tparam B the type of the third element in each eventual triple
+ * @return a decorator `LazyZip3` that allows strict operations to be performed on the lazily evaluated tuples or
+ * chained calls to `lazyZip`. Implicit conversion to `Iterable[(El1, El2, B)]` is also supported.
+ */
+ def lazyZip[B](that: Iterable[B]): LazyZip3[El1, El2, B, C1] = new LazyZip3(src, coll1, coll2, that)
+
+ def map[B, C](f: (El1, El2) => B)(implicit bf: BuildFrom[C1, B, C]): C = {
+ bf.fromSpecific(src)(new AbstractView[B] {
+ def iterator: AbstractIterator[B] = new AbstractIterator[B] {
+ private[this] val elems1 = coll1.iterator
+ private[this] val elems2 = coll2.iterator
+ def hasNext = elems1.hasNext && elems2.hasNext
+ def next() = f(elems1.next(), elems2.next())
+ }
+ override def knownSize: Int = zipKnownSize
+ override def isEmpty: Boolean = coll1.isEmpty || coll2.isEmpty
+ })
+ }
+
+ def flatMap[B, C](f: (El1, El2) => Iterable[B])(implicit bf: BuildFrom[C1, B, C]): C = {
+ bf.fromSpecific(src)(new AbstractView[B] {
+ def iterator: AbstractIterator[B] = new AbstractIterator[B] {
+ private[this] val elems1 = coll1.iterator
+ private[this] val elems2 = coll2.iterator
+ private[this] var _current: Iterator[B] = Iterator.empty
+ private def current = {
+ while (!_current.hasNext && elems1.hasNext && elems2.hasNext)
+ _current = f(elems1.next(), elems2.next()).iterator
+ _current
+ }
+ def hasNext = current.hasNext
+ def next() = current.next()
+ }
+ override def knownSize: Int = if (coll1.knownSize == 0 || coll2.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = coll1.isEmpty || coll2.isEmpty
+ })
+ }
+
+ def filter[C](p: (El1, El2) => Boolean)(implicit bf: BuildFrom[C1, (El1, El2), C]): C = {
+ bf.fromSpecific(src)(new AbstractView[(El1, El2)] {
+ def iterator: AbstractIterator[(El1, El2)] = new AbstractIterator[(El1, El2)] {
+ private[this] val elems1 = coll1.iterator
+ private[this] val elems2 = coll2.iterator
+ private[this] var _current: (El1, El2) = _
+ private def current = {
+ while ((_current eq null) && elems1.hasNext && elems2.hasNext) {
+ val e1 = elems1.next()
+ val e2 = elems2.next()
+ if (p(e1, e2)) _current = (e1, e2)
+ }
+ _current
+ }
+ def hasNext = current ne null
+ def next() = {
+ val c = current
+ if (c ne null) {
+ _current = null
+ c
+ } else Iterator.empty.next()
+ }
+ }
+ override def knownSize: Int = if (coll1.knownSize == 0 || coll2.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = iterator.hasNext
+ })
+ }
+
+ def exists(p: (El1, El2) => Boolean): Boolean = {
+ val elems1 = coll1.iterator
+ val elems2 = coll2.iterator
+ var res = false
+
+ while (!res && elems1.hasNext && elems2.hasNext) res = p(elems1.next(), elems2.next())
+
+ res
+ }
+
+ def forall(p: (El1, El2) => Boolean): Boolean = !exists((el1, el2) => !p(el1, el2))
+
+ def foreach[U](f: (El1, El2) => U): Unit = {
+ val elems1 = coll1.iterator
+ val elems2 = coll2.iterator
+
+ while (elems1.hasNext && elems2.hasNext) f(elems1.next(), elems2.next())
+ }
+
+ private def toIterable: View[(El1, El2)] = new AbstractView[(El1, El2)] {
+ def iterator: AbstractIterator[(El1, El2)] = new AbstractIterator[(El1, El2)] {
+ private[this] val elems1 = coll1.iterator
+ private[this] val elems2 = coll2.iterator
+ def hasNext = elems1.hasNext && elems2.hasNext
+ def next() = (elems1.next(), elems2.next())
+ }
+ override def knownSize: Int = zipKnownSize
+ override def isEmpty: Boolean = coll1.isEmpty || coll2.isEmpty
+ }
+
+ private def zipKnownSize: Int = {
+ val s1 = coll1.knownSize
+ if (s1 == 0) 0 else {
+ val s2 = coll2.knownSize
+ if (s2 == 0) 0 else s1 min s2
+ }
+ }
+
+ override def toString = s"$coll1.lazyZip($coll2)"
+}
+
+object LazyZip2 {
+ implicit def lazyZip2ToIterable[El1, El2](zipped2: LazyZip2[El1, El2, _]): View[(El1, El2)] = zipped2.toIterable
+}
+
+
+/** Decorator representing lazily zipped triples.
+ *
+ * @define coll triple
+ * @define willNotTerminateInf
+ *
+ * Note: will not terminate for infinite-sized collections.
+ */
+final class LazyZip3[+El1, +El2, +El3, C1] private[collection](src: C1,
+ coll1: Iterable[El1],
+ coll2: Iterable[El2],
+ coll3: Iterable[El3]) {
+
+ /** Zips `that` iterable collection with an existing `LazyZip3`. The elements in each collection are
+ * not consumed until a strict operation is invoked on the returned `LazyZip4` decorator.
+ *
+ * @param that the iterable providing the fourth element of each eventual 4-tuple
+ * @tparam B the type of the fourth element in each eventual 4-tuple
+ * @return a decorator `LazyZip4` that allows strict operations to be performed on the lazily evaluated tuples.
+ * Implicit conversion to `Iterable[(El1, El2, El3, B)]` is also supported.
+ */
+ def lazyZip[B](that: Iterable[B]): LazyZip4[El1, El2, El3, B, C1] = new LazyZip4(src, coll1, coll2, coll3, that)
+
+ def map[B, C](f: (El1, El2, El3) => B)(implicit bf: BuildFrom[C1, B, C]): C = {
+ bf.fromSpecific(src)(new AbstractView[B] {
+ def iterator: AbstractIterator[B] = new AbstractIterator[B] {
+ private[this] val elems1 = coll1.iterator
+ private[this] val elems2 = coll2.iterator
+ private[this] val elems3 = coll3.iterator
+ def hasNext = elems1.hasNext && elems2.hasNext && elems3.hasNext
+ def next() = f(elems1.next(), elems2.next(), elems3.next())
+ }
+ override def knownSize: Int = zipKnownSize
+ override def isEmpty: Boolean = coll1.isEmpty || coll2.isEmpty || coll3.isEmpty
+ })
+ }
+
+ def flatMap[B, C](f: (El1, El2, El3) => Iterable[B])(implicit bf: BuildFrom[C1, B, C]): C = {
+ bf.fromSpecific(src)(new AbstractView[B] {
+ def iterator: AbstractIterator[B] = new AbstractIterator[B] {
+ private[this] val elems1 = coll1.iterator
+ private[this] val elems2 = coll2.iterator
+ private[this] val elems3 = coll3.iterator
+ private[this] var _current: Iterator[B] = Iterator.empty
+ private def current = {
+ while (!_current.hasNext && elems1.hasNext && elems2.hasNext && elems3.hasNext)
+ _current = f(elems1.next(), elems2.next(), elems3.next()).iterator
+ _current
+ }
+ def hasNext = current.hasNext
+ def next() = current.next()
+ }
+ override def knownSize: Int = if (coll1.knownSize == 0 || coll2.knownSize == 0 || coll3.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = iterator.isEmpty
+ })
+ }
+
+ def filter[C](p: (El1, El2, El3) => Boolean)(implicit bf: BuildFrom[C1, (El1, El2, El3), C]): C = {
+ bf.fromSpecific(src)(new AbstractView[(El1, El2, El3)] {
+ def iterator: AbstractIterator[(El1, El2, El3)] = new AbstractIterator[(El1, El2, El3)] {
+ private[this] val elems1 = coll1.iterator
+ private[this] val elems2 = coll2.iterator
+ private[this] val elems3 = coll3.iterator
+ private[this] var _current: (El1, El2, El3) = _
+ private def current = {
+ while ((_current eq null) && elems1.hasNext && elems2.hasNext && elems3.hasNext) {
+ val e1 = elems1.next()
+ val e2 = elems2.next()
+ val e3 = elems3.next()
+ if (p(e1, e2, e3)) _current = (e1, e2, e3)
+ }
+ _current
+ }
+ def hasNext = current ne null
+ def next() = {
+ val c = current
+ if (c ne null) {
+ _current = null
+ c
+ } else Iterator.empty.next()
+ }
+ }
+ override def knownSize: Int = if (coll1.knownSize == 0 || coll2.knownSize == 0 || coll3.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = iterator.isEmpty
+ })
+ }
+
+ def exists(p: (El1, El2, El3) => Boolean): Boolean = {
+ val elems1 = coll1.iterator
+ val elems2 = coll2.iterator
+ val elems3 = coll3.iterator
+ var res = false
+
+ while (!res && elems1.hasNext && elems2.hasNext && elems3.hasNext)
+ res = p(elems1.next(), elems2.next(), elems3.next())
+
+ res
+ }
+
+ def forall(p: (El1, El2, El3) => Boolean): Boolean = !exists((el1, el2, el3) => !p(el1, el2, el3))
+
+ def foreach[U](f: (El1, El2, El3) => U): Unit = {
+ val elems1 = coll1.iterator
+ val elems2 = coll2.iterator
+ val elems3 = coll3.iterator
+
+ while (elems1.hasNext && elems2.hasNext && elems3.hasNext)
+ f(elems1.next(), elems2.next(), elems3.next())
+ }
+
+ private def toIterable: View[(El1, El2, El3)] = new AbstractView[(El1, El2, El3)] {
+ def iterator: AbstractIterator[(El1, El2, El3)] = new AbstractIterator[(El1, El2, El3)] {
+ private[this] val elems1 = coll1.iterator
+ private[this] val elems2 = coll2.iterator
+ private[this] val elems3 = coll3.iterator
+ def hasNext = elems1.hasNext && elems2.hasNext && elems3.hasNext
+ def next() = (elems1.next(), elems2.next(), elems3.next())
+ }
+ override def knownSize: Int = zipKnownSize
+ override def isEmpty: Boolean = coll1.isEmpty || coll2.isEmpty || coll3.isEmpty
+ }
+
+ private def zipKnownSize: Int = {
+ val s1 = coll1.knownSize
+ if (s1 == 0) 0 else {
+ val s2 = coll2.knownSize
+ if (s2 == 0) 0 else {
+ val s3 = coll3.knownSize
+ if (s3 == 0) 0 else s1 min s2 min s3
+ }
+ }
+ }
+
+ override def toString = s"$coll1.lazyZip($coll2).lazyZip($coll3)"
+}
+
+object LazyZip3 {
+ implicit def lazyZip3ToIterable[El1, El2, El3](zipped3: LazyZip3[El1, El2, El3, _]): View[(El1, El2, El3)] = zipped3.toIterable
+}
+
+
+
+/** Decorator representing lazily zipped 4-tuples.
+ *
+ * @define coll tuple
+ * @define willNotTerminateInf
+ *
+ * Note: will not terminate for infinite-sized collections.
+ */
+final class LazyZip4[+El1, +El2, +El3, +El4, C1] private[collection](src: C1,
+ coll1: Iterable[El1],
+ coll2: Iterable[El2],
+ coll3: Iterable[El3],
+ coll4: Iterable[El4]) {
+
+ def map[B, C](f: (El1, El2, El3, El4) => B)(implicit bf: BuildFrom[C1, B, C]): C = {
+ bf.fromSpecific(src)(new AbstractView[B] {
+ def iterator: AbstractIterator[B] = new AbstractIterator[B] {
+ private[this] val elems1 = coll1.iterator
+ private[this] val elems2 = coll2.iterator
+ private[this] val elems3 = coll3.iterator
+ private[this] val elems4 = coll4.iterator
+ def hasNext = elems1.hasNext && elems2.hasNext && elems3.hasNext && elems4.hasNext
+ def next() = f(elems1.next(), elems2.next(), elems3.next(), elems4.next())
+ }
+ override def knownSize: Int = zipKnownSize
+ override def isEmpty: Boolean = coll1.isEmpty || coll2.isEmpty || coll3.isEmpty || coll4.isEmpty
+ })
+ }
+
+ def flatMap[B, C](f: (El1, El2, El3, El4) => Iterable[B])(implicit bf: BuildFrom[C1, B, C]): C = {
+ bf.fromSpecific(src)(new AbstractView[B] {
+ def iterator: AbstractIterator[B] = new AbstractIterator[B] {
+ private[this] val elems1 = coll1.iterator
+ private[this] val elems2 = coll2.iterator
+ private[this] val elems3 = coll3.iterator
+ private[this] val elems4 = coll4.iterator
+ private[this] var _current: Iterator[B] = Iterator.empty
+ private def current = {
+ while (!_current.hasNext && elems1.hasNext && elems2.hasNext && elems3.hasNext && elems4.hasNext)
+ _current = f(elems1.next(), elems2.next(), elems3.next(), elems4.next()).iterator
+ _current
+ }
+ def hasNext = current.hasNext
+ def next() = current.next()
+ }
+ override def knownSize: Int = if (coll1.knownSize == 0 || coll2.knownSize == 0 || coll3.knownSize == 0 || coll4.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = iterator.isEmpty
+ })
+ }
+
+ def filter[C](p: (El1, El2, El3, El4) => Boolean)(implicit bf: BuildFrom[C1, (El1, El2, El3, El4), C]): C = {
+ bf.fromSpecific(src)(new AbstractView[(El1, El2, El3, El4)] {
+ def iterator: AbstractIterator[(El1, El2, El3, El4)] = new AbstractIterator[(El1, El2, El3, El4)] {
+ private[this] val elems1 = coll1.iterator
+ private[this] val elems2 = coll2.iterator
+ private[this] val elems3 = coll3.iterator
+ private[this] val elems4 = coll4.iterator
+ private[this] var _current: (El1, El2, El3, El4) = _
+ private def current = {
+ while ((_current eq null) && elems1.hasNext && elems2.hasNext && elems3.hasNext && elems4.hasNext) {
+ val e1 = elems1.next()
+ val e2 = elems2.next()
+ val e3 = elems3.next()
+ val e4 = elems4.next()
+ if (p(e1, e2, e3, e4)) _current = (e1, e2, e3, e4)
+ }
+ _current
+ }
+ def hasNext = current ne null
+ def next() = {
+ val c = current
+ if (c ne null) {
+ _current = null
+ c
+ } else Iterator.empty.next()
+ }
+ }
+ override def knownSize: Int = if (coll1.knownSize == 0 || coll2.knownSize == 0 || coll3.knownSize == 0 || coll4.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = iterator.isEmpty
+ })
+ }
+
+ def exists(p: (El1, El2, El3, El4) => Boolean): Boolean = {
+ val elems1 = coll1.iterator
+ val elems2 = coll2.iterator
+ val elems3 = coll3.iterator
+ val elems4 = coll4.iterator
+ var res = false
+
+ while (!res && elems1.hasNext && elems2.hasNext && elems3.hasNext && elems4.hasNext)
+ res = p(elems1.next(), elems2.next(), elems3.next(), elems4.next())
+
+ res
+ }
+
+ def forall(p: (El1, El2, El3, El4) => Boolean): Boolean = !exists((el1, el2, el3, el4) => !p(el1, el2, el3, el4))
+
+ def foreach[U](f: (El1, El2, El3, El4) => U): Unit = {
+ val elems1 = coll1.iterator
+ val elems2 = coll2.iterator
+ val elems3 = coll3.iterator
+ val elems4 = coll4.iterator
+
+ while (elems1.hasNext && elems2.hasNext && elems3.hasNext && elems4.hasNext)
+ f(elems1.next(), elems2.next(), elems3.next(), elems4.next())
+ }
+
+ private def toIterable: View[(El1, El2, El3, El4)] = new AbstractView[(El1, El2, El3, El4)] {
+ def iterator: AbstractIterator[(El1, El2, El3, El4)] = new AbstractIterator[(El1, El2, El3, El4)] {
+ private[this] val elems1 = coll1.iterator
+ private[this] val elems2 = coll2.iterator
+ private[this] val elems3 = coll3.iterator
+ private[this] val elems4 = coll4.iterator
+ def hasNext = elems1.hasNext && elems2.hasNext && elems3.hasNext && elems4.hasNext
+ def next() = (elems1.next(), elems2.next(), elems3.next(), elems4.next())
+ }
+ override def knownSize: Int = zipKnownSize
+ override def isEmpty: Boolean = coll1.isEmpty || coll2.isEmpty || coll3.isEmpty || coll4.isEmpty
+ }
+
+ private def zipKnownSize: Int = {
+ val s1 = coll1.knownSize
+ if (s1 == 0) 0 else {
+ val s2 = coll2.knownSize
+ if (s2 == 0) 0 else {
+ val s3 = coll3.knownSize
+ if (s3 == 0) 0 else {
+ val s4 = coll4.knownSize
+ if (s4 == 0) 0 else s1 min s2 min s3 min s4
+ }
+ }
+ }
+ }
+
+ override def toString = s"$coll1.lazyZip($coll2).lazyZip($coll3).lazyZip($coll4)"
+}
+
+object LazyZip4 {
+ implicit def lazyZip4ToIterable[El1, El2, El3, El4](zipped4: LazyZip4[El1, El2, El3, El4, _]): View[(El1, El2, El3, El4)] =
+ zipped4.toIterable
+}
diff --git a/library/src/scala/collection/LinearSeq.scala b/library/src/scala/collection/LinearSeq.scala
new file mode 100644
index 000000000000..965edecdadc7
--- /dev/null
+++ b/library/src/scala/collection/LinearSeq.scala
@@ -0,0 +1,310 @@
+/*
+ * 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 collection
+
+import scala.annotation.{nowarn, tailrec}
+
+/** Base trait for linearly accessed sequences that have efficient `head` and
+ * `tail` operations.
+ * Known subclasses: List, LazyList
+ */
+trait LinearSeq[+A] extends Seq[A]
+ with LinearSeqOps[A, LinearSeq, LinearSeq[A]]
+ with IterableFactoryDefaults[A, LinearSeq] {
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix: String = "LinearSeq"
+
+ override def iterableFactory: SeqFactory[LinearSeq] = LinearSeq
+}
+
+@SerialVersionUID(3L)
+object LinearSeq extends SeqFactory.Delegate[LinearSeq](immutable.LinearSeq)
+
+/** Base trait for linear Seq operations */
+trait LinearSeqOps[+A, +CC[X] <: LinearSeq[X], +C <: LinearSeq[A] with LinearSeqOps[A, CC, C]] extends Any with SeqOps[A, CC, C] {
+
+ /** @inheritdoc
+ *
+ * Note: *Must* be overridden in subclasses. The default implementation that is inherited from [[SeqOps]]
+ * uses `lengthCompare`, which is defined here to use `isEmpty`.
+ */
+ override def isEmpty: Boolean
+
+ /** @inheritdoc
+ *
+ * Note: *Must* be overridden in subclasses. The default implementation is inherited from [[IterableOps]].
+ */
+ def head: A
+
+ /** @inheritdoc
+ *
+ * Note: *Must* be overridden in subclasses. The default implementation is inherited from [[IterableOps]].
+ */
+ def tail: C
+
+ override def headOption: Option[A] =
+ if (isEmpty) None else Some(head)
+
+ def iterator: Iterator[A] =
+ if (knownSize == 0) Iterator.empty
+ else new LinearSeqIterator[A](this)
+
+ def length: Int = {
+ var these = coll
+ var len = 0
+ while (these.nonEmpty) {
+ len += 1
+ these = these.tail
+ }
+ len
+ }
+
+ override def last: A = {
+ if (isEmpty) throw new NoSuchElementException("LinearSeq.last")
+ else {
+ var these = coll
+ var scout = tail
+ while (scout.nonEmpty) {
+ these = scout
+ scout = scout.tail
+ }
+ these.head
+ }
+ }
+
+ override def lengthCompare(len: Int): Int = {
+ @tailrec def loop(i: Int, xs: LinearSeq[A]): Int = {
+ if (i == len)
+ if (xs.isEmpty) 0 else 1
+ else if (xs.isEmpty)
+ -1
+ else
+ loop(i + 1, xs.tail)
+ }
+ if (len < 0) 1
+ else loop(0, coll)
+ }
+
+ override def lengthCompare(that: Iterable[_]): Int = {
+ val thatKnownSize = that.knownSize
+
+ if (thatKnownSize >= 0) this lengthCompare thatKnownSize
+ else that match {
+ case that: LinearSeq[_] =>
+ var thisSeq = this
+ var thatSeq = that
+ while (thisSeq.nonEmpty && thatSeq.nonEmpty) {
+ thisSeq = thisSeq.tail
+ thatSeq = thatSeq.tail
+ }
+ java.lang.Boolean.compare(thisSeq.nonEmpty, thatSeq.nonEmpty)
+ case _ =>
+ var thisSeq = this
+ val thatIt = that.iterator
+ while (thisSeq.nonEmpty && thatIt.hasNext) {
+ thisSeq = thisSeq.tail
+ thatIt.next()
+ }
+ java.lang.Boolean.compare(thisSeq.nonEmpty, thatIt.hasNext)
+ }
+ }
+
+ override def isDefinedAt(x: Int): Boolean = x >= 0 && lengthCompare(x) > 0
+
+ // `apply` is defined in terms of `drop`, which is in turn defined in
+ // terms of `tail`.
+ @throws[IndexOutOfBoundsException]
+ override def apply(n: Int): A = {
+ if (n < 0) throw new IndexOutOfBoundsException(n.toString)
+ val skipped = drop(n)
+ if (skipped.isEmpty) throw new IndexOutOfBoundsException(n.toString)
+ skipped.head
+ }
+
+ override def foreach[U](f: A => U): Unit = {
+ var these: LinearSeq[A] = coll
+ while (!these.isEmpty) {
+ f(these.head)
+ these = these.tail
+ }
+ }
+
+ override def forall(p: A => Boolean): Boolean = {
+ var these: LinearSeq[A] = coll
+ while (!these.isEmpty) {
+ if (!p(these.head)) return false
+ these = these.tail
+ }
+ true
+ }
+
+ override def exists(p: A => Boolean): Boolean = {
+ var these: LinearSeq[A] = coll
+ while (!these.isEmpty) {
+ if (p(these.head)) return true
+ these = these.tail
+ }
+ false
+ }
+
+ override def contains[A1 >: A](elem: A1): Boolean = {
+ var these: LinearSeq[A] = coll
+ while (!these.isEmpty) {
+ if (these.head == elem) return true
+ these = these.tail
+ }
+ false
+ }
+
+ override def find(p: A => Boolean): Option[A] = {
+ var these: LinearSeq[A] = coll
+ while (!these.isEmpty) {
+ if (p(these.head)) return Some(these.head)
+ these = these.tail
+ }
+ None
+ }
+
+ override def foldLeft[B](z: B)(op: (B, A) => B): B = {
+ var acc = z
+ var these: LinearSeq[A] = coll
+ while (!these.isEmpty) {
+ acc = op(acc, these.head)
+ these = these.tail
+ }
+ acc
+ }
+
+ override def sameElements[B >: A](that: IterableOnce[B]): Boolean = {
+ @tailrec def linearSeqEq(a: LinearSeq[B], b: LinearSeq[B]): Boolean =
+ (a eq b) || {
+ if (a.nonEmpty && b.nonEmpty && a.head == b.head) {
+ linearSeqEq(a.tail, b.tail)
+ }
+ else {
+ a.isEmpty && b.isEmpty
+ }
+ }
+
+ that match {
+ case that: LinearSeq[B] => linearSeqEq(coll, that)
+ case _ => super.sameElements(that)
+ }
+ }
+
+ override def segmentLength(p: A => Boolean, from: Int): Int = {
+ var i = 0
+ var seq = drop(from)
+ while (seq.nonEmpty && p(seq.head)) {
+ i += 1
+ seq = seq.tail
+ }
+ i
+ }
+
+ override def indexWhere(p: A => Boolean, from: Int): Int = {
+ var i = math.max(from, 0)
+ var these: LinearSeq[A] = this drop from
+ while (these.nonEmpty) {
+ if (p(these.head))
+ return i
+
+ i += 1
+ these = these.tail
+ }
+ -1
+ }
+
+ override def lastIndexWhere(p: A => Boolean, end: Int): Int = {
+ var i = 0
+ var these: LinearSeq[A] = coll
+ var last = -1
+ while (!these.isEmpty && i <= end) {
+ if (p(these.head)) last = i
+ these = these.tail
+ i += 1
+ }
+ last
+ }
+
+ override def findLast(p: A => Boolean): Option[A] = {
+ var these: LinearSeq[A] = coll
+ var found = false
+ var last: A = null.asInstanceOf[A] // don't use `Option`, to prevent excessive `Some` allocation
+ while (these.nonEmpty) {
+ val elem = these.head
+ if (p(elem)) {
+ found = true
+ last = elem
+ }
+ these = these.tail
+ }
+ if (found) Some(last) else None
+ }
+
+ override def tails: Iterator[C] = {
+ val end = Iterator.single(empty)
+ Iterator.iterate(coll)(_.tail).takeWhile(_.nonEmpty) ++ end
+ }
+}
+
+trait StrictOptimizedLinearSeqOps[+A, +CC[X] <: LinearSeq[X], +C <: LinearSeq[A] with StrictOptimizedLinearSeqOps[A, CC, C]] extends Any with LinearSeqOps[A, CC, C] with StrictOptimizedSeqOps[A, CC, C] {
+ // A more efficient iterator implementation than the default LinearSeqIterator
+ override def iterator: Iterator[A] = new AbstractIterator[A] {
+ private[this] var current = StrictOptimizedLinearSeqOps.this
+ def hasNext = !current.isEmpty
+ def next() = { val r = current.head; current = current.tail; r }
+ }
+
+ // Optimized version of `drop` that avoids copying
+ override def drop(n: Int): C = {
+ @tailrec def loop(n: Int, s: C): C =
+ if (n <= 0 || s.isEmpty) s
+ else loop(n - 1, s.tail)
+ loop(n, coll)
+ }
+
+ override def dropWhile(p: A => Boolean): C = {
+ @tailrec def loop(s: C): C =
+ if (s.nonEmpty && p(s.head)) loop(s.tail)
+ else s
+ loop(coll)
+ }
+}
+
+/** A specialized Iterator for LinearSeqs that is lazy enough for Stream and LazyList. This is accomplished by not
+ * evaluating the tail after returning the current head.
+ */
+private[collection] final class LinearSeqIterator[A](coll: LinearSeqOps[A, LinearSeq, LinearSeq[A]]) extends AbstractIterator[A] {
+ // A call-by-need cell
+ private[this] final class LazyCell(st: => LinearSeqOps[A, LinearSeq, LinearSeq[A]]) { lazy val v = st }
+
+ private[this] var these: LazyCell = {
+ // Reassign reference to avoid creating a private class field and holding a reference to the head.
+ // LazyCell would otherwise close over `coll`.
+ val initialHead = coll
+ new LazyCell(initialHead)
+ }
+
+ def hasNext: Boolean = these.v.nonEmpty
+
+ def next(): A =
+ if (isEmpty) Iterator.empty.next()
+ else {
+ val cur = these.v
+ val result = cur.head
+ these = new LazyCell(cur.tail)
+ result
+ }
+}
diff --git a/library/src/scala/collection/Map.scala b/library/src/scala/collection/Map.scala
new file mode 100644
index 000000000000..1b88058d3197
--- /dev/null
+++ b/library/src/scala/collection/Map.scala
@@ -0,0 +1,420 @@
+/*
+ * 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 collection
+
+import scala.annotation.nowarn
+import scala.collection.generic.DefaultSerializable
+import scala.collection.mutable.StringBuilder
+import scala.util.hashing.MurmurHash3
+
+/** Base Map type */
+trait Map[K, +V]
+ extends Iterable[(K, V)]
+ with MapOps[K, V, Map, Map[K, V]]
+ with MapFactoryDefaults[K, V, Map, Iterable]
+ with Equals {
+
+ def mapFactory: scala.collection.MapFactory[Map] = Map
+
+ def canEqual(that: Any): Boolean = true
+
+ /**
+ * Equality of maps is implemented using the lookup method [[get]]. This method returns `true` if
+ * - the argument `o` is a `Map`,
+ * - the two maps have the same [[size]], and
+ * - for every `(key, value)` pair in this map, `other.get(key) == Some(value)`.
+ *
+ * The implementation of `equals` checks the [[canEqual]] method, so subclasses of `Map` can narrow down the equality
+ * to specific map types. The `Map` implementations in the standard library can all be compared, their `canEqual`
+ * methods return `true`.
+ *
+ * Note: The `equals` method only respects the equality laws (symmetry, transitivity) if the two maps use the same
+ * key equivalence function in their lookup operation. For example, the key equivalence operation in a
+ * [[scala.collection.immutable.TreeMap]] is defined by its ordering. Comparing a `TreeMap` with a `HashMap` leads
+ * to unexpected results if `ordering.equiv(k1, k2)` (used for lookup in `TreeMap`) is different from `k1 == k2`
+ * (used for lookup in `HashMap`).
+ *
+ * {{{
+ * scala> import scala.collection.immutable._
+ * scala> val ord: Ordering[String] = _ compareToIgnoreCase _
+ *
+ * scala> TreeMap("A" -> 1)(ord) == HashMap("a" -> 1)
+ * val res0: Boolean = false
+ *
+ * scala> HashMap("a" -> 1) == TreeMap("A" -> 1)(ord)
+ * val res1: Boolean = true
+ * }}}
+ *
+ *
+ * @param o The map to which this map is compared
+ * @return `true` if the two maps are equal according to the description
+ */
+ override def equals(o: Any): Boolean =
+ (this eq o.asInstanceOf[AnyRef]) || (o match {
+ case map: Map[K @unchecked, _] if map.canEqual(this) =>
+ (this.size == map.size) && {
+ try this.forall(kv => map.getOrElse(kv._1, Map.DefaultSentinelFn()) == kv._2)
+ catch { case _: ClassCastException => false } // PR #9565 / scala/bug#12228
+ }
+ case _ =>
+ false
+ })
+
+ override def hashCode(): Int = MurmurHash3.mapHash(this)
+
+ // These two methods are not in MapOps so that MapView is not forced to implement them
+ @deprecated("Use - or removed on an immutable Map", "2.13.0")
+ def - (key: K): Map[K, V]
+ @deprecated("Use -- or removedAll on an immutable Map", "2.13.0")
+ def - (key1: K, key2: K, keys: K*): Map[K, V]
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix: String = "Map"
+
+ override def toString(): String = super[Iterable].toString() // Because `Function1` overrides `toString` too
+}
+
+/** Base Map implementation type
+ *
+ * @tparam K Type of keys
+ * @tparam V Type of values
+ * @tparam CC type constructor of the map (e.g. `HashMap`). Operations returning a collection
+ * with a different type of entries `(L, W)` (e.g. `map`) return a `CC[L, W]`.
+ * @tparam C type of the map (e.g. `HashMap[Int, String]`). Operations returning a collection
+ * with the same type of element (e.g. `drop`, `filter`) return a `C`.
+ * @define coll map
+ * @define Coll `Map`
+ */
+// Note: the upper bound constraint on CC is useful only to
+// erase CC to IterableOps instead of Object
+trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C]
+ extends IterableOps[(K, V), Iterable, C]
+ with PartialFunction[K, V] {
+
+ override def view: MapView[K, V] = new MapView.Id(this)
+
+ /** Returns a [[Stepper]] for the keys of this map. See method [[stepper]]. */
+ def keyStepper[S <: Stepper[_]](implicit shape: StepperShape[K, S]): S = {
+ import convert.impl._
+ val s = shape.shape match {
+ case StepperShape.IntShape => new IntIteratorStepper (keysIterator.asInstanceOf[Iterator[Int]])
+ case StepperShape.LongShape => new LongIteratorStepper (keysIterator.asInstanceOf[Iterator[Long]])
+ case StepperShape.DoubleShape => new DoubleIteratorStepper(keysIterator.asInstanceOf[Iterator[Double]])
+ case _ => shape.seqUnbox(new AnyIteratorStepper(keysIterator))
+ }
+ s.asInstanceOf[S]
+ }
+
+ /** Returns a [[Stepper]] for the values of this map. See method [[stepper]]. */
+ def valueStepper[S <: Stepper[_]](implicit shape: StepperShape[V, S]): S = {
+ import convert.impl._
+ val s = shape.shape match {
+ case StepperShape.IntShape => new IntIteratorStepper (valuesIterator.asInstanceOf[Iterator[Int]])
+ case StepperShape.LongShape => new LongIteratorStepper (valuesIterator.asInstanceOf[Iterator[Long]])
+ case StepperShape.DoubleShape => new DoubleIteratorStepper(valuesIterator.asInstanceOf[Iterator[Double]])
+ case _ => shape.seqUnbox(new AnyIteratorStepper(valuesIterator))
+ }
+ s.asInstanceOf[S]
+ }
+
+ /** Similar to `fromIterable`, but returns a Map collection type.
+ * Note that the return type is now `CC[K2, V2]`.
+ */
+ @`inline` protected final def mapFromIterable[K2, V2](it: Iterable[(K2, V2)]): CC[K2, V2] = mapFactory.from(it)
+
+ /** The companion object of this map, providing various factory methods.
+ *
+ * @note When implementing a custom collection type and refining `CC` to the new type, this
+ * method needs to be overridden to return a factory for the new type (the compiler will
+ * issue an error otherwise).
+ */
+ def mapFactory: MapFactory[CC]
+
+ /** Optionally returns the value associated with a key.
+ *
+ * @param key the key value
+ * @return an option value containing the value associated with `key` in this map,
+ * or `None` if none exists.
+ */
+ def get(key: K): Option[V]
+
+ /** Returns the value associated with a key, or a default value if the key is not contained in the map.
+ * @param key the key.
+ * @param default a computation that yields a default value in case no binding for `key` is
+ * found in the map.
+ * @tparam V1 the result type of the default computation.
+ * @return the value associated with `key` if it exists,
+ * otherwise the result of the `default` computation.
+ */
+ def getOrElse[V1 >: V](key: K, default: => V1): V1 = get(key) match {
+ case Some(v) => v
+ case None => default
+ }
+
+ /** Retrieves the value which is associated with the given key. This
+ * method invokes the `default` method of the map if there is no mapping
+ * from the given key to a value. Unless overridden, the `default` method throws a
+ * `NoSuchElementException`.
+ *
+ * @param key the key
+ * @return the value associated with the given key, or the result of the
+ * map's `default` method, if none exists.
+ */
+ @throws[NoSuchElementException]
+ def apply(key: K): V = get(key) match {
+ case None => default(key)
+ case Some(value) => value
+ }
+
+ override /*PartialFunction*/ def applyOrElse[K1 <: K, V1 >: V](x: K1, default: K1 => V1): V1 = getOrElse(x, default(x))
+
+ /** A set representing the keys contained by this map.
+ *
+ * For efficiency the resulting set may be a view (maintaining a reference to the map and reflecting modifications
+ * to the map), but it may also be a strict collection without reference to the map.
+ *
+ * - To ensure an independent strict collection, use `m.keysIterator.toSet`
+ * - To obtain a view on the keys, use `scala.collection.View.fromIteratorProvider(m.keysIterator)`
+ *
+ * @return a set representing the keys contained by this map
+ */
+ def keySet: Set[K] = new KeySet
+
+ /** The implementation class of the set returned by `keySet`.
+ */
+ protected class KeySet extends AbstractSet[K] with GenKeySet with DefaultSerializable {
+ def diff(that: Set[K]): Set[K] = fromSpecific(this.view.filterNot(that))
+ }
+
+ /** A generic trait that is reused by keyset implementations */
+ protected trait GenKeySet { this: Set[K] =>
+ def iterator: Iterator[K] = MapOps.this.keysIterator
+ def contains(key: K): Boolean = MapOps.this.contains(key)
+ override def size: Int = MapOps.this.size
+ override def knownSize: Int = MapOps.this.knownSize
+ override def isEmpty: Boolean = MapOps.this.isEmpty
+ }
+
+ /** An [[Iterable]] collection of the keys contained by this map.
+ *
+ * For efficiency the resulting collection may be a view (maintaining a reference to the map and reflecting
+ * modifications to the map), but it may also be a strict collection without reference to the map.
+ *
+ * - To ensure an independent strict collection, use `m.keysIterator.toSet`
+ * - To obtain a view on the keys, use `scala.collection.View.fromIteratorProvider(m.keysIterator)`
+ *
+ * @return an [[Iterable]] collection of the keys contained by this map
+ */
+ @deprecatedOverriding("This method should be an alias for keySet", since="2.13.13")
+ def keys: Iterable[K] = keySet
+
+ /** Collects all values of this map in an iterable collection.
+ *
+ * @return the values of this map as an iterable.
+ */
+ def values: Iterable[V] = new AbstractIterable[V] with DefaultSerializable {
+ override def knownSize: Int = MapOps.this.knownSize
+ override def iterator: Iterator[V] = valuesIterator
+ }
+
+ /** An [[Iterator]] of the keys contained by this map.
+ *
+ * @return an [[Iterator]] of the keys contained by this map
+ */
+ def keysIterator: Iterator[K] = new AbstractIterator[K] {
+ val iter = MapOps.this.iterator
+ def hasNext = iter.hasNext
+ def next() = iter.next()._1
+ }
+
+ /** Creates an iterator for all values in this map.
+ *
+ * @return an iterator over all values that are associated with some key in this map.
+ */
+ def valuesIterator: Iterator[V] = new AbstractIterator[V] {
+ val iter = MapOps.this.iterator
+ def hasNext = iter.hasNext
+ def next() = iter.next()._2
+ }
+
+ /** Apply `f` to each key/value pair for its side effects
+ * Note: [U] parameter needed to help scalac's type inference.
+ */
+ def foreachEntry[U](f: (K, V) => U): Unit = {
+ val it = iterator
+ while (it.hasNext) {
+ val next = it.next()
+ f(next._1, next._2)
+ }
+ }
+
+ /** Filters this map by retaining only keys satisfying a predicate.
+ * @param p the predicate used to test keys
+ * @return an immutable map consisting only of those key value pairs of this map where the key satisfies
+ * the predicate `p`. The resulting map wraps the original map without copying any elements.
+ */
+ @deprecated("Use .view.filterKeys(f). A future version will include a strict version of this method (for now, .view.filterKeys(p).toMap).", "2.13.0")
+ def filterKeys(p: K => Boolean): MapView[K, V] = new MapView.FilterKeys(this, p)
+
+ /** Transforms this map by applying a function to every retrieved value.
+ * @param f the function used to transform values of this map.
+ * @return a map view which maps every key of this map
+ * to `f(this(key))`. The resulting map wraps the original map without copying any elements.
+ */
+ @deprecated("Use .view.mapValues(f). A future version will include a strict version of this method (for now, .view.mapValues(f).toMap).", "2.13.0")
+ def mapValues[W](f: V => W): MapView[K, W] = new MapView.MapValues(this, f)
+
+ /** Defines the default value computation for the map,
+ * returned when a key is not found.
+ *
+ * The method implemented here throws an exception,
+ * but it may be overridden by subclasses.
+ *
+ * @param key the given key value for which a binding is missing.
+ * @throws NoSuchElementException if no default value is defined
+ */
+ @throws[NoSuchElementException]
+ def default(key: K): V =
+ throw new NoSuchElementException("key not found: " + key)
+
+ /** Tests whether this map contains a binding for a key.
+ *
+ * @param key the key
+ * @return `true` if there is a binding for `key` in this map, `false` otherwise.
+ */
+ def contains(key: K): Boolean = get(key).isDefined
+
+
+ /** Tests whether this map contains a binding for a key. This method,
+ * which implements an abstract method of trait `PartialFunction`,
+ * is equivalent to `contains`.
+ *
+ * @param key the key
+ * @return `true` if there is a binding for `key` in this map, `false` otherwise.
+ */
+ def isDefinedAt(key: K): Boolean = contains(key)
+
+ /** Builds a new map by applying a function to all elements of this $coll.
+ *
+ * @param f the function to apply to each element.
+ * @return a new $coll resulting from applying the given function
+ * `f` to each element of this $coll and collecting the results.
+ */
+ def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = mapFactory.from(new View.Map(this, f))
+
+ /** Builds a new collection by applying a partial function to all elements of this $coll
+ * on which the function is defined.
+ *
+ * @param pf the partial function which filters and maps the $coll.
+ * @tparam K2 the key type of the returned $coll.
+ * @tparam V2 the value type of the returned $coll.
+ * @return a new $coll resulting from applying the given partial function
+ * `pf` to each element on which it is defined and collecting the results.
+ * The order of the elements is preserved.
+ */
+ def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)]): CC[K2, V2] =
+ mapFactory.from(new View.Collect(this, pf))
+
+ /** Builds a new map by applying a function to all elements of this $coll
+ * and using the elements of the resulting collections.
+ *
+ * @param f the function to apply to each element.
+ * @return a new $coll resulting from applying the given collection-valued function
+ * `f` to each element of this $coll and concatenating the results.
+ */
+ def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] = mapFactory.from(new View.FlatMap(this, f))
+
+ /** Returns a new $coll containing the elements from the left hand operand followed by the elements from the
+ * right hand operand. The element type of the $coll is the most specific superclass encompassing
+ * the element types of the two operands.
+ *
+ * @param suffix the iterable to append.
+ * @return a new $coll which contains all elements
+ * of this $coll followed by all elements of `suffix`.
+ */
+ def concat[V2 >: V](suffix: collection.IterableOnce[(K, V2)]): CC[K, V2] = mapFactory.from(suffix match {
+ case it: Iterable[(K, V2)] => new View.Concat(this, it)
+ case _ => iterator.concat(suffix.iterator)
+ })
+
+ // Not final because subclasses refine the result type, e.g. in SortedMap, the result type is
+ // SortedMap's CC, while Map's CC is fixed to Map
+ /** Alias for `concat` */
+ /*@`inline` final*/ def ++ [V2 >: V](xs: collection.IterableOnce[(K, V2)]): CC[K, V2] = concat(xs)
+
+ override def addString(sb: StringBuilder, start: String, sep: String, end: String): sb.type =
+ iterator.map { case (k, v) => s"$k -> $v" }.addString(sb, start, sep, end)
+
+ @deprecated("Consider requiring an immutable Map or fall back to Map.concat.", "2.13.0")
+ def + [V1 >: V](kv: (K, V1)): CC[K, V1] =
+ mapFactory.from(new View.Appended(this, kv))
+
+ @deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
+ def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): CC[K, V1] =
+ mapFactory.from(new View.Concat(new View.Appended(new View.Appended(this, elem1), elem2), elems))
+
+ @deprecated("Consider requiring an immutable Map.", "2.13.0")
+ @`inline` def -- (keys: IterableOnce[K]): C = {
+ lazy val keysSet = keys.iterator.to(immutable.Set)
+ fromSpecific(this.view.filterKeys(k => !keysSet.contains(k)))
+ }
+
+ @deprecated("Use ++ instead of ++: for collections of type Iterable", "2.13.0")
+ def ++: [V1 >: V](that: IterableOnce[(K,V1)]): CC[K,V1] = {
+ val thatIterable: Iterable[(K, V1)] = that match {
+ case that: Iterable[(K, V1)] => that
+ case that => View.from(that)
+ }
+ mapFactory.from(new View.Concat(thatIterable, this))
+ }
+}
+
+object MapOps {
+ /** Specializes `WithFilter` for Map collection types by adding overloads to transformation
+ * operations that can return a Map.
+ *
+ * @define coll map collection
+ */
+ @SerialVersionUID(3L)
+ class WithFilter[K, +V, +IterableCC[_], +CC[_, _] <: IterableOps[_, AnyConstr, _]](
+ self: MapOps[K, V, CC, _] with IterableOps[(K, V), IterableCC, _],
+ p: ((K, V)) => Boolean
+ ) extends IterableOps.WithFilter[(K, V), IterableCC](self, p) with Serializable {
+
+ def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] =
+ self.mapFactory.from(new View.Map(filtered, f))
+
+ def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] =
+ self.mapFactory.from(new View.FlatMap(filtered, f))
+
+ override def withFilter(q: ((K, V)) => Boolean): WithFilter[K, V, IterableCC, CC] =
+ new WithFilter[K, V, IterableCC, CC](self, (kv: (K, V)) => p(kv) && q(kv))
+
+ }
+
+}
+
+/**
+ * $factoryInfo
+ * @define coll map
+ * @define Coll `Map`
+ */
+@SerialVersionUID(3L)
+object Map extends MapFactory.Delegate[Map](immutable.Map) {
+ private val DefaultSentinel: AnyRef = new AnyRef
+ private val DefaultSentinelFn: () => AnyRef = () => DefaultSentinel
+}
+
+/** Explicit instantiation of the `Map` trait to reduce class file size in subclasses. */
+abstract class AbstractMap[K, +V] extends AbstractIterable[(K, V)] with Map[K, V]
diff --git a/library/src/scala/collection/MapView.scala b/library/src/scala/collection/MapView.scala
new file mode 100644
index 000000000000..39742c434c41
--- /dev/null
+++ b/library/src/scala/collection/MapView.scala
@@ -0,0 +1,188 @@
+/*
+ * 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 scala.annotation.nowarn
+import scala.collection.MapView.SomeMapOps
+import scala.collection.mutable.Builder
+
+trait MapView[K, +V]
+ extends MapOps[K, V, ({ type l[X, Y] = View[(X, Y)] })#l, View[(K, V)]]
+ with View[(K, V)] {
+
+ override def view: MapView[K, V] = this
+
+ // Ideally this returns a `View`, but bincompat
+ /** Creates a view over all keys of this map.
+ *
+ * @return the keys of this map as a view.
+ */
+ @nowarn("msg=overriding method keys")
+ override def keys: Iterable[K] = new MapView.Keys(this)
+
+ // Ideally this returns a `View`, but bincompat
+ /** Creates a view over all values of this map.
+ *
+ * @return the values of this map as a view.
+ */
+ override def values: Iterable[V] = new MapView.Values(this)
+
+ /** Filters this map by retaining only keys satisfying a predicate.
+ * @param p the predicate used to test keys
+ * @return an immutable map consisting only of those key value pairs of this map where the key satisfies
+ * the predicate `p`. The resulting map wraps the original map without copying any elements.
+ */
+ override def filterKeys(p: K => Boolean): MapView[K, V] = new MapView.FilterKeys(this, p)
+
+ /** Transforms this map by applying a function to every retrieved value.
+ * @param f the function used to transform values of this map.
+ * @return a map view which maps every key of this map
+ * to `f(this(key))`. The resulting map wraps the original map without copying any elements.
+ */
+ override def mapValues[W](f: V => W): MapView[K, W] = new MapView.MapValues(this, f)
+
+ override def filter(pred: ((K, V)) => Boolean): MapView[K, V] = new MapView.Filter(this, isFlipped = false, pred)
+
+ override def filterNot(pred: ((K, V)) => Boolean): MapView[K, V] = new MapView.Filter(this, isFlipped = true, pred)
+
+ override def partition(p: ((K, V)) => Boolean): (MapView[K, V], MapView[K, V]) = (filter(p), filterNot(p))
+
+ override def tapEach[U](f: ((K, V)) => U): MapView[K, V] = new MapView.TapEach(this, f)
+
+ def mapFactory: MapViewFactory = MapView
+
+ override def empty: MapView[K, V] = mapFactory.empty
+
+ override def withFilter(p: ((K, V)) => Boolean): MapOps.WithFilter[K, V, View, ({ type l[X, Y] = View[(X, Y)] })#l] = new MapOps.WithFilter(this, p)
+
+ override def toString: String = super[View].toString
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix: String = "MapView"
+}
+
+object MapView extends MapViewFactory {
+
+ /** An `IterableOps` whose collection type and collection type constructor are unknown */
+ type SomeIterableConstr[X, Y] = IterableOps[_, AnyConstr, _]
+ /** A `MapOps` whose collection type and collection type constructor are (mostly) unknown */
+ type SomeMapOps[K, +V] = MapOps[K, V, SomeIterableConstr, _]
+
+ @SerialVersionUID(3L)
+ private val EmptyMapView: MapView[Any, Nothing] = new AbstractMapView[Any, Nothing] {
+ override def get(key: Any): Option[Nothing] = None
+ override def iterator: Iterator[Nothing] = Iterator.empty[Nothing]
+ override def knownSize: Int = 0
+ override def isEmpty: Boolean = true
+ override def filterKeys(p: Any => Boolean): MapView[Any, Nothing] = this
+ override def mapValues[W](f: Nothing => W): MapView[Any, Nothing] = this
+ override def filter(pred: ((Any, Nothing)) => Boolean): MapView[Any, Nothing] = this
+ override def filterNot(pred: ((Any, Nothing)) => Boolean): MapView[Any, Nothing] = this
+ override def partition(p: ((Any, Nothing)) => Boolean): (MapView[Any, Nothing], MapView[Any, Nothing]) = (this, this)
+ }
+
+ @SerialVersionUID(3L)
+ class Id[K, +V](underlying: SomeMapOps[K, V]) extends AbstractMapView[K, V] {
+ def get(key: K): Option[V] = underlying.get(key)
+ def iterator: Iterator[(K, V)] = underlying.iterator
+ override def knownSize: Int = underlying.knownSize
+ override def isEmpty: Boolean = underlying.isEmpty
+ }
+
+ // Ideally this is public, but bincompat
+ @SerialVersionUID(3L)
+ private class Keys[K](underlying: SomeMapOps[K, _]) extends AbstractView[K] {
+ def iterator: Iterator[K] = underlying.keysIterator
+ override def knownSize: Int = underlying.knownSize
+ override def isEmpty: Boolean = underlying.isEmpty
+ }
+
+ // Ideally this is public, but bincompat
+ @SerialVersionUID(3L)
+ private class Values[+V](underlying: SomeMapOps[_, V]) extends AbstractView[V] {
+ def iterator: Iterator[V] = underlying.valuesIterator
+ override def knownSize: Int = underlying.knownSize
+ override def isEmpty: Boolean = underlying.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ class MapValues[K, +V, +W](underlying: SomeMapOps[K, V], f: V => W) extends AbstractMapView[K, W] {
+ def iterator: Iterator[(K, W)] = underlying.iterator.map(kv => (kv._1, f(kv._2)))
+ def get(key: K): Option[W] = underlying.get(key).map(f)
+ override def knownSize: Int = underlying.knownSize
+ override def isEmpty: Boolean = underlying.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ class FilterKeys[K, +V](underlying: SomeMapOps[K, V], p: K => Boolean) extends AbstractMapView[K, V] {
+ def iterator: Iterator[(K, V)] = underlying.iterator.filter { case (k, _) => p(k) }
+ def get(key: K): Option[V] = if (p(key)) underlying.get(key) else None
+ override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = iterator.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ class Filter[K, +V](underlying: SomeMapOps[K, V], isFlipped: Boolean, p: ((K, V)) => Boolean) extends AbstractMapView[K, V] {
+ def iterator: Iterator[(K, V)] = underlying.iterator.filterImpl(p, isFlipped)
+ def get(key: K): Option[V] = underlying.get(key) match {
+ case s @ Some(v) if p((key, v)) != isFlipped => s
+ case _ => None
+ }
+ override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = iterator.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ class TapEach[K, +V, +U](underlying: SomeMapOps[K, V], f: ((K, V)) => U) extends AbstractMapView[K, V] {
+ override def get(key: K): Option[V] = {
+ underlying.get(key) match {
+ case s @ Some(v) =>
+ f((key, v))
+ s
+ case None => None
+ }
+ }
+ override def iterator: Iterator[(K, V)] = underlying.iterator.tapEach(f)
+ override def knownSize: Int = underlying.knownSize
+ override def isEmpty: Boolean = underlying.isEmpty
+ }
+
+ override def newBuilder[X, Y]: Builder[(X, Y), MapView[X, Y]] = mutable.HashMap.newBuilder[X, Y].mapResult(_.view)
+
+ override def empty[K, V]: MapView[K, V] = EmptyMapView.asInstanceOf[MapView[K, V]]
+
+ override def from[K, V](it: IterableOnce[(K, V)]): View[(K, V)] = View.from(it)
+
+ override def from[K, V](it: SomeMapOps[K, V]): MapView[K, V] = it match {
+ case mv: MapView[K, V] => mv
+ case other => new MapView.Id(other)
+ }
+
+ override def apply[K, V](elems: (K, V)*): MapView[K, V] = from(elems.toMap)
+}
+
+trait MapViewFactory extends collection.MapFactory[({ type l[X, Y] = View[(X, Y)]})#l] {
+
+ def newBuilder[X, Y]: Builder[(X, Y), MapView[X, Y]]
+
+ def empty[X, Y]: MapView[X, Y]
+
+ def from[K, V](it: SomeMapOps[K, V]): MapView[K, V]
+
+ override def apply[K, V](elems: (K, V)*): MapView[K, V] = from(elems.toMap)
+}
+
+/** Explicit instantiation of the `MapView` trait to reduce class file size in subclasses. */
+@SerialVersionUID(3L)
+abstract class AbstractMapView[K, +V] extends AbstractView[(K, V)] with MapView[K, V]
+
diff --git a/library/src/scala/collection/Searching.scala b/library/src/scala/collection/Searching.scala
new file mode 100644
index 000000000000..8b8132870287
--- /dev/null
+++ b/library/src/scala/collection/Searching.scala
@@ -0,0 +1,57 @@
+/*
+ * 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 scala.language.implicitConversions
+import scala.collection.generic.IsSeq
+
+object Searching {
+
+ /** The result of performing a search on a sorted sequence
+ *
+ * Example usage:
+ *
+ * {{{
+ * val list = List(1, 3, 4, 5) // list must be sorted before searching
+ * list.search(4) // Found(2)
+ * list.search(2) // InsertionPoint(1)
+ * }}}
+ *
+ * */
+ sealed abstract class SearchResult {
+ /** The index corresponding to the element searched for in the sequence, if it was found,
+ * or the index where the element would be inserted in the sequence, if it was not in the sequence */
+ def insertionPoint: Int
+ }
+
+ /** The result of performing a search on a sorted sequence, where the element was found.
+ *
+ * @param foundIndex the index corresponding to the element searched for in the sequence
+ */
+ case class Found(foundIndex: Int) extends SearchResult {
+ override def insertionPoint: Int = foundIndex
+ }
+
+ /** The result of performing a search on a sorted sequence, where the element was not found
+ *
+ * @param insertionPoint the index where the element would be inserted in the sequence
+ */
+ case class InsertionPoint(insertionPoint: Int) extends SearchResult
+
+ @deprecated("Search methods are defined directly on SeqOps and do not require scala.collection.Searching any more", "2.13.0")
+ class SearchImpl[Repr, A](private val coll: SeqOps[A, AnyConstr, _]) extends AnyVal
+
+ @deprecated("Search methods are defined directly on SeqOps and do not require scala.collection.Searching any more", "2.13.0")
+ implicit def search[Repr, A](coll: Repr)(implicit fr: IsSeq[Repr]): SearchImpl[Repr, fr.A] =
+ new SearchImpl(fr.conversion(coll))
+}
diff --git a/library/src/scala/collection/Seq.scala b/library/src/scala/collection/Seq.scala
new file mode 100644
index 000000000000..f9bb5c2cf483
--- /dev/null
+++ b/library/src/scala/collection/Seq.scala
@@ -0,0 +1,1190 @@
+/*
+ * 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 scala.collection.immutable.Range
+import scala.util.hashing.MurmurHash3
+import Searching.{Found, InsertionPoint, SearchResult}
+import scala.annotation.nowarn
+
+/** Base trait for sequence collections
+ *
+ * @tparam A the element type of the collection
+ */
+trait Seq[+A]
+ extends Iterable[A]
+ with PartialFunction[Int, A]
+ with SeqOps[A, Seq, Seq[A]]
+ with IterableFactoryDefaults[A, Seq]
+ with Equals {
+
+ override def iterableFactory: SeqFactory[Seq] = Seq
+
+ def canEqual(that: Any): Boolean = true
+
+ override def equals(o: Any): Boolean =
+ (this eq o.asInstanceOf[AnyRef]) || (o match {
+ case seq: Seq[A @unchecked] if seq.canEqual(this) => sameElements(seq)
+ case _ => false
+ })
+
+ override def hashCode(): Int = MurmurHash3.seqHash(this)
+
+ override def toString(): String = super[Iterable].toString()
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix: String = "Seq"
+}
+
+/**
+ * $factoryInfo
+ * @define coll sequence
+ * @define Coll `Seq`
+ */
+@SerialVersionUID(3L)
+object Seq extends SeqFactory.Delegate[Seq](immutable.Seq)
+
+/** Base trait for Seq operations
+ *
+ * @tparam A the element type of the collection
+ * @tparam CC type constructor of the collection (e.g. `List`, `Set`). Operations returning a collection
+ * with a different type of element `B` (e.g. `map`) return a `CC[B]`.
+ * @tparam C type of the collection (e.g. `List[Int]`, `String`, `BitSet`). Operations returning a collection
+ * with the same type of element (e.g. `drop`, `filter`) return a `C`.
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ *
+ * Note: may not terminate for infinite-sized collections.
+ *
+ * @define willNotTerminateInf
+ *
+ * Note: will not terminate for infinite-sized collections.
+ *
+ * @define coll sequence
+ * @define Coll `Seq`
+ */
+trait SeqOps[+A, +CC[_], +C] extends Any
+ with IterableOps[A, CC, C] { self =>
+
+ override def view: SeqView[A] = new SeqView.Id[A](this)
+
+ /** Gets the element at the specified index. This operation is provided for convenience in `Seq`. It should
+ * not be assumed to be efficient unless you have an `IndexedSeq`. */
+ @throws[IndexOutOfBoundsException]
+ def apply(i: Int): A
+
+ /** The length (number of elements) of the $coll. `size` is an alias for `length` in `Seq` collections. */
+ def length: Int
+
+ /** A copy of the $coll with an element prepended.
+ *
+ * Also, the original $coll is not modified, so you will want to capture the result.
+ *
+ * Example:
+ * {{{
+ * scala> val x = List(1)
+ * x: List[Int] = List(1)
+ *
+ * scala> val y = 2 +: x
+ * y: List[Int] = List(2, 1)
+ *
+ * scala> println(x)
+ * List(1)
+ * }}}
+ *
+ * @param elem the prepended element
+ * @tparam B the element type of the returned $coll.
+ *
+ * @return a new $coll consisting of `value` followed
+ * by all elements of this $coll.
+ */
+ def prepended[B >: A](elem: B): CC[B] = iterableFactory.from(new View.Prepended(elem, this))
+
+ /** Alias for `prepended`.
+ *
+ * Note that :-ending operators are right associative (see example).
+ * A mnemonic for `+:` vs. `:+` is: the COLon goes on the COLlection side.
+ */
+ @`inline` final def +: [B >: A](elem: B): CC[B] = prepended(elem)
+
+ /** A copy of this $coll with an element appended.
+ *
+ * $willNotTerminateInf
+ *
+ * Example:
+ * {{{
+ * scala> val a = List(1)
+ * a: List[Int] = List(1)
+ *
+ * scala> val b = a :+ 2
+ * b: List[Int] = List(1, 2)
+ *
+ * scala> println(a)
+ * List(1)
+ * }}}
+ *
+ * @param elem the appended element
+ * @tparam B the element type of the returned $coll.
+ * @return a new $coll consisting of
+ * all elements of this $coll followed by `value`.
+ */
+ def appended[B >: A](elem: B): CC[B] = iterableFactory.from(new View.Appended(this, elem))
+
+ /** Alias for `appended`.
+ *
+ * Note that :-ending operators are right associative (see example).
+ * A mnemonic for `+:` vs. `:+` is: the COLon goes on the COLlection side.
+ */
+ @`inline` final def :+ [B >: A](elem: B): CC[B] = appended(elem)
+
+ /** As with `:++`, returns a new collection containing the elements from the left operand followed by the
+ * elements from the right operand.
+ *
+ * It differs from `:++` in that the right operand determines the type of
+ * the resulting collection rather than the left one.
+ * Mnemonic: the COLon is on the side of the new COLlection type.
+ *
+ * @param prefix the iterable to prepend.
+ * @tparam B the element type of the returned collection.
+ * @return a new $coll which contains all elements of `prefix` followed
+ * by all the elements of this $coll.
+ */
+ def prependedAll[B >: A](prefix: IterableOnce[B]): CC[B] = iterableFactory.from(prefix match {
+ case prefix: Iterable[B] => new View.Concat(prefix, this)
+ case _ => prefix.iterator ++ iterator
+ })
+
+ /** Alias for `prependedAll`. */
+ @`inline` override final def ++: [B >: A](prefix: IterableOnce[B]): CC[B] = prependedAll(prefix)
+
+ /** Returns a new $coll containing the elements from the left hand operand followed by the elements from the
+ * right hand operand. The element type of the $coll is the most specific superclass encompassing
+ * the element types of the two operands.
+ *
+ * @param suffix the iterable to append.
+ * @tparam B the element type of the returned collection.
+ * @return a new collection of type `CC[B]` which contains all elements
+ * of this $coll followed by all elements of `suffix`.
+ */
+ def appendedAll[B >: A](suffix: IterableOnce[B]): CC[B] = super.concat(suffix)
+
+ /** Alias for `appendedAll`. */
+ @`inline` final def :++ [B >: A](suffix: IterableOnce[B]): CC[B] = appendedAll(suffix)
+
+ // Make `concat` an alias for `appendedAll` so that it benefits from performance
+ // overrides of this method
+ @`inline` final override def concat[B >: A](suffix: IterableOnce[B]): CC[B] = appendedAll(suffix)
+
+ /** Produces a new sequence which contains all elements of this $coll and also all elements of
+ * a given sequence. `xs union ys` is equivalent to `xs ++ ys`.
+ *
+ * @param that the sequence to add.
+ * @tparam B the element type of the returned $coll.
+ * @return a new collection which contains all elements of this $coll
+ * followed by all elements of `that`.
+ */
+ @deprecated("Use `concat` instead", "2.13.0")
+ @inline final def union[B >: A](that: Seq[B]): CC[B] = concat(that)
+
+ final override def size: Int = length
+
+ /** Selects all the elements of this $coll ignoring the duplicates.
+ *
+ * @return a new $coll consisting of all the elements of this $coll without duplicates.
+ */
+ def distinct: C = distinctBy(identity)
+
+ /** Selects all the elements of this $coll ignoring the duplicates as determined by `==` after applying
+ * the transforming function `f`.
+ *
+ * @param f The transforming function whose result is used to determine the uniqueness of each element
+ * @tparam B the type of the elements after being transformed by `f`
+ * @return a new $coll consisting of all the elements of this $coll without duplicates.
+ */
+ def distinctBy[B](f: A => B): C = fromSpecific(new View.DistinctBy(this, f))
+
+ /** Returns a new $coll with the elements of this $coll in reverse order.
+ *
+ * $willNotTerminateInf
+ * $willForceEvaluation
+ *
+ * @return a new $coll with all elements of this $coll in reverse order.
+ */
+ def reverse: C = fromSpecific(reversed)
+
+ /** An iterator yielding the elements of this $coll in reverse order.
+ *
+ * $willNotTerminateInf
+ *
+ * Note: `xs.reverseIterator` is the same as `xs.reverse.iterator` but might be more efficient.
+ *
+ * @return an iterator yielding the elements of this $coll in reverse order.
+ */
+ def reverseIterator: Iterator[A] = reversed.iterator
+
+ /** Tests whether this $coll contains the given sequence at a given index.
+ *
+ * '''Note''': If the both the receiver object `this` and the argument
+ * `that` are infinite sequences this method may not terminate.
+ *
+ * @param that the sequence to test
+ * @param offset the index where the sequence is searched.
+ * @return `true` if the sequence `that` is contained in this $coll at
+ * index `offset`, otherwise `false`.
+ */
+ def startsWith[B >: A](that: IterableOnce[B], offset: Int = 0): Boolean = {
+ val i = iterator drop offset
+ val j = that.iterator
+ while (j.hasNext && i.hasNext)
+ if (i.next() != j.next())
+ return false
+
+ !j.hasNext
+ }
+
+ /** Tests whether this $coll ends with the given sequence.
+ * $willNotTerminateInf
+ * @param that the sequence to test
+ * @return `true` if this $coll has `that` as a suffix, `false` otherwise.
+ */
+ def endsWith[B >: A](that: Iterable[B]): Boolean = {
+ if (that.isEmpty) true
+ else {
+ val i = iterator.drop(length - that.size)
+ val j = that.iterator
+ while (i.hasNext && j.hasNext)
+ if (i.next() != j.next())
+ return false
+
+ !j.hasNext
+ }
+ }
+
+ /** Tests whether this $coll contains given index.
+ *
+ * The implementations of methods `apply` and `isDefinedAt` turn a `Seq[A]` into
+ * a `PartialFunction[Int, A]`.
+ *
+ * @param idx the index to test
+ * @return `true` if this $coll contains an element at position `idx`, `false` otherwise.
+ */
+ def isDefinedAt(idx: Int): Boolean = idx >= 0 && lengthIs > idx
+
+ /** A copy of this $coll with an element value appended until a given target length is reached.
+ *
+ * @param len the target length
+ * @param elem the padding value
+ * @tparam B the element type of the returned $coll.
+ * @return a new $coll consisting of
+ * all elements of this $coll followed by the minimal number of occurrences of `elem` so
+ * that the resulting collection has a length of at least `len`.
+ */
+ def padTo[B >: A](len: Int, elem: B): CC[B] = iterableFactory.from(new View.PadTo(this, len, elem))
+
+ /** Computes the length of the longest segment that starts from the first element
+ * and whose elements all satisfy some predicate.
+ *
+ * $mayNotTerminateInf
+ *
+ * @param p the predicate used to test elements.
+ * @return the length of the longest segment of this $coll that starts from the first element
+ * such that every element of the segment satisfies the predicate `p`.
+ */
+ final def segmentLength(p: A => Boolean): Int = segmentLength(p, 0)
+
+ /** Computes the length of the longest segment that starts from some index
+ * and whose elements all satisfy some predicate.
+ *
+ * $mayNotTerminateInf
+ *
+ * @param p the predicate used to test elements.
+ * @param from the index where the search starts.
+ * @return the length of the longest segment of this $coll starting from index `from`
+ * such that every element of the segment satisfies the predicate `p`.
+ */
+ def segmentLength(p: A => Boolean, from: Int): Int = {
+ var i = 0
+ val it = iterator.drop(from)
+ while (it.hasNext && p(it.next()))
+ i += 1
+ i
+ }
+
+ /** Returns the length of the longest prefix whose elements all satisfy some predicate.
+ *
+ * $mayNotTerminateInf
+ *
+ * @param p the predicate used to test elements.
+ * @return the length of the longest prefix of this $coll
+ * such that every element of the segment satisfies the predicate `p`.
+ */
+ @deprecated("Use segmentLength instead of prefixLength", "2.13.0")
+ @`inline` final def prefixLength(p: A => Boolean): Int = segmentLength(p, 0)
+
+ /** Finds index of the first element satisfying some predicate after or at some start index.
+ *
+ * $mayNotTerminateInf
+ *
+ * @param p the predicate used to test elements.
+ * @param from the start index
+ * @return the index `>= from` of the first element of this $coll that satisfies the predicate `p`,
+ * or `-1`, if none exists.
+ */
+ def indexWhere(p: A => Boolean, from: Int): Int = iterator.indexWhere(p, from)
+
+ /** Finds index of the first element satisfying some predicate.
+ *
+ * $mayNotTerminateInf
+ *
+ * @param p the predicate used to test elements.
+ * @return the index `>= 0` of the first element of this $coll that satisfies the predicate `p`,
+ * or `-1`, if none exists.
+ */
+ @deprecatedOverriding("Override indexWhere(p, from) instead - indexWhere(p) calls indexWhere(p, 0)", "2.13.0")
+ def indexWhere(p: A => Boolean): Int = indexWhere(p, 0)
+
+ /** Finds index of first occurrence of some value in this $coll after or at some start index.
+ *
+ * @param elem the element value to search for.
+ * @tparam B the type of the element `elem`.
+ * @param from the start index
+ * @return the index `>= from` of the first element of this $coll that is equal (as determined by `==`)
+ * to `elem`, or `-1`, if none exists.
+ */
+ def indexOf[B >: A](elem: B, from: Int): Int = indexWhere(elem == _, from)
+
+ /** Finds index of first occurrence of some value in this $coll.
+ *
+ * @param elem the element value to search for.
+ * @tparam B the type of the element `elem`.
+ * @return the index `>= 0` of the first element of this $coll that is equal (as determined by `==`)
+ * to `elem`, or `-1`, if none exists.
+ */
+ @deprecatedOverriding("Override indexOf(elem, from) instead - indexOf(elem) calls indexOf(elem, 0)", "2.13.0")
+ def indexOf[B >: A](elem: B): Int = indexOf(elem, 0)
+
+ /** Finds index of last occurrence of some value in this $coll before or at a given end index.
+ *
+ * $willNotTerminateInf
+ *
+ * @param elem the element value to search for.
+ * @param end the end index.
+ * @tparam B the type of the element `elem`.
+ * @return the index `<= end` of the last element of this $coll that is equal (as determined by `==`)
+ * to `elem`, or `-1`, if none exists.
+ */
+ def lastIndexOf[B >: A](elem: B, end: Int = length - 1): Int = lastIndexWhere(elem == _, end)
+
+ /** Finds index of last element satisfying some predicate before or at given end index.
+ *
+ * $willNotTerminateInf
+ *
+ * @param p the predicate used to test elements.
+ * @return the index `<= end` of the last element of this $coll that satisfies the predicate `p`,
+ * or `-1`, if none exists.
+ */
+ def lastIndexWhere(p: A => Boolean, end: Int): Int = {
+ var i = length - 1
+ val it = reverseIterator
+ while (it.hasNext && { val elem = it.next(); (i > end || !p(elem)) }) i -= 1
+ i
+ }
+
+ /** Finds index of last element satisfying some predicate.
+ *
+ * $willNotTerminateInf
+ *
+ * @param p the predicate used to test elements.
+ * @return the index of the last element of this $coll that satisfies the predicate `p`,
+ * or `-1`, if none exists.
+ */
+ @deprecatedOverriding("Override lastIndexWhere(p, end) instead - lastIndexWhere(p) calls lastIndexWhere(p, Int.MaxValue)", "2.13.0")
+ def lastIndexWhere(p: A => Boolean): Int = lastIndexWhere(p, Int.MaxValue)
+
+ @inline private[this] def toGenericSeq: scala.collection.Seq[A] = this match {
+ case s: scala.collection.Seq[A] => s
+ case _ => toSeq
+ }
+
+ /** Finds first index after or at a start index where this $coll contains a given sequence as a slice.
+ * $mayNotTerminateInf
+ * @param that the sequence to test
+ * @param from the start index
+ * @return the first index `>= from` such that the elements of this $coll starting at this index
+ * match the elements of sequence `that`, or `-1` if no such subsequence exists.
+ */
+ // TODO Should be implemented in a way that preserves laziness
+ def indexOfSlice[B >: A](that: Seq[B], from: Int): Int =
+ if (that.isEmpty && from == 0) 0
+ else {
+ val l = knownSize
+ val tl = that.knownSize
+ if (l >= 0 && tl >= 0) {
+ val clippedFrom = math.max(0, from)
+ if (from > l) -1
+ else if (tl < 1) clippedFrom
+ else if (l < tl) -1
+ else SeqOps.kmpSearch(toGenericSeq, clippedFrom, l, that, 0, tl, forward = true)
+ }
+ else {
+ var i = from
+ var s: scala.collection.Seq[A] = toGenericSeq.drop(i)
+ while (!s.isEmpty) {
+ if (s startsWith that)
+ return i
+
+ i += 1
+ s = s.tail
+ }
+ -1
+ }
+ }
+
+ /** Finds first index where this $coll contains a given sequence as a slice.
+ * $mayNotTerminateInf
+ * @param that the sequence to test
+ * @return the first index `>= 0` such that the elements of this $coll starting at this index
+ * match the elements of sequence `that`, or `-1` if no such subsequence exists.
+ */
+ @deprecatedOverriding("Override indexOfSlice(that, from) instead - indexOfSlice(that) calls indexOfSlice(that, 0)", "2.13.0")
+ def indexOfSlice[B >: A](that: Seq[B]): Int = indexOfSlice(that, 0)
+
+ /** Finds last index before or at a given end index where this $coll contains a given sequence as a slice.
+ *
+ * $willNotTerminateInf
+ *
+ * @param that the sequence to test
+ * @param end the end index
+ * @return the last index `<= end` such that the elements of this $coll starting at this index
+ * match the elements of sequence `that`, or `-1` if no such subsequence exists.
+ */
+ def lastIndexOfSlice[B >: A](that: Seq[B], end: Int): Int = {
+ val l = length
+ val tl = that.length
+ val clippedL = math.min(l-tl, end)
+
+ if (end < 0) -1
+ else if (tl < 1) clippedL
+ else if (l < tl) -1
+ else SeqOps.kmpSearch(toGenericSeq, 0, clippedL+tl, that, 0, tl, forward = false)
+ }
+
+ /** Finds last index where this $coll contains a given sequence as a slice.
+ *
+ * $willNotTerminateInf
+ *
+ * @param that the sequence to test
+ * @return the last index such that the elements of this $coll starting at this index
+ * match the elements of sequence `that`, or `-1` if no such subsequence exists.
+ */
+ @deprecatedOverriding("Override lastIndexOfSlice(that, end) instead - lastIndexOfSlice(that) calls lastIndexOfSlice(that, Int.MaxValue)", "2.13.0")
+ def lastIndexOfSlice[B >: A](that: Seq[B]): Int = lastIndexOfSlice(that, Int.MaxValue)
+
+ /** Finds the last element of the $coll satisfying a predicate, if any.
+ *
+ * $willNotTerminateInf
+ *
+ * @param p the predicate used to test elements.
+ * @return an option value containing the last element in the $coll
+ * that satisfies `p`, or `None` if none exists.
+ */
+ def findLast(p: A => Boolean): Option[A] = {
+ val it = reverseIterator
+ while (it.hasNext) {
+ val elem = it.next()
+ if (p(elem)) return Some(elem)
+ }
+ None
+ }
+
+ /** Tests whether this $coll contains a given sequence as a slice.
+ * $mayNotTerminateInf
+ * @param that the sequence to test
+ * @return `true` if this $coll contains a slice with the same elements
+ * as `that`, otherwise `false`.
+ */
+ def containsSlice[B >: A](that: Seq[B]): Boolean = indexOfSlice(that) != -1
+
+ /** Tests whether this $coll contains a given value as an element.
+ * $mayNotTerminateInf
+ *
+ * @param elem the element to test.
+ * @return `true` if this $coll has an element that is equal (as
+ * determined by `==`) to `elem`, `false` otherwise.
+ */
+ def contains[A1 >: A](elem: A1): Boolean = exists (_ == elem)
+
+ @deprecated("Use .reverseIterator.map(f).to(...) instead of .reverseMap(f)", "2.13.0")
+ def reverseMap[B](f: A => B): CC[B] = iterableFactory.from(new View.Map(View.fromIteratorProvider(() => reverseIterator), f))
+
+ /** Iterates over distinct permutations of elements.
+ *
+ * $willForceEvaluation
+ *
+ * @return An Iterator which traverses the distinct permutations of this $coll.
+ * @example {{{
+ * Seq('a', 'b', 'b').permutations.foreach(println)
+ * // List(a, b, b)
+ * // List(b, a, b)
+ * // List(b, b, a)
+ * }}}
+ */
+ def permutations: Iterator[C] =
+ if (isEmpty) Iterator.single(coll)
+ else new PermutationsItr
+
+ /** Iterates over combinations of elements.
+ *
+ * A '''combination''' of length `n` is a sequence of `n` elements selected in order of their first index in this sequence.
+ *
+ * For example, `"xyx"` has two combinations of length 2. The `x` is selected first: `"xx"`, `"xy"`.
+ * The sequence `"yx"` is not returned as a combination because it is subsumed by `"xy"`.
+ *
+ * If there is more than one way to generate the same combination, only one will be returned.
+ *
+ * For example, the result `"xy"` arbitrarily selected one of the `x` elements.
+ *
+ * As a further illustration, `"xyxx"` has three different ways to generate `"xy"` because there are three elements `x`
+ * to choose from. Moreover, there are three unordered pairs `"xx"` but only one is returned.
+ *
+ * It is not specified which of these equal combinations is returned. It is an implementation detail
+ * that should not be relied on. For example, the combination `"xx"` does not necessarily contain
+ * the first `x` in this sequence. This behavior is observable if the elements compare equal
+ * but are not identical.
+ *
+ * As a consequence, `"xyx".combinations(3).next()` is `"xxy"`: the combination does not reflect the order
+ * of the original sequence, but the order in which elements were selected, by "first index";
+ * the order of each `x` element is also arbitrary.
+ *
+ * $willForceEvaluation
+ *
+ * @return An Iterator which traverses the n-element combinations of this $coll.
+ * @example {{{
+ * Seq('a', 'b', 'b', 'b', 'c').combinations(2).foreach(println)
+ * // List(a, b)
+ * // List(a, c)
+ * // List(b, b)
+ * // List(b, c)
+ * Seq('b', 'a', 'b').combinations(2).foreach(println)
+ * // List(b, b)
+ * // List(b, a)
+ * }}}
+ */
+ def combinations(n: Int): Iterator[C] =
+ if (n < 0 || n > size) Iterator.empty
+ else new CombinationsItr(n)
+
+ private class PermutationsItr extends AbstractIterator[C] {
+ private[this] val (elms, idxs) = init()
+ private[this] var _hasNext = true
+
+ def hasNext = _hasNext
+ @throws[NoSuchElementException]
+ def next(): C = {
+ if (!hasNext)
+ Iterator.empty.next()
+
+ val forcedElms = new mutable.ArrayBuffer[A](elms.size) ++= elms
+ val result = (newSpecificBuilder ++= forcedElms).result()
+ var i = idxs.length - 2
+ while(i >= 0 && idxs(i) >= idxs(i+1))
+ i -= 1
+
+ if (i < 0)
+ _hasNext = false
+ else {
+ var j = idxs.length - 1
+ while(idxs(j) <= idxs(i)) j -= 1
+ swap(i,j)
+
+ val len = (idxs.length - i) / 2
+ var k = 1
+ while (k <= len) {
+ swap(i+k, idxs.length - k)
+ k += 1
+ }
+ }
+ result
+ }
+ private def swap(i: Int, j: Int): Unit = {
+ val tmpI = idxs(i)
+ idxs(i) = idxs(j)
+ idxs(j) = tmpI
+ val tmpE = elms(i)
+ elms(i) = elms(j)
+ elms(j) = tmpE
+ }
+
+ private[this] def init() = {
+ val m = mutable.HashMap[A, Int]()
+ val (es, is) = (self.toGenericSeq map (e => (e, m.getOrElseUpdate(e, m.size))) sortBy (_._2)).unzip
+
+ (es.to(mutable.ArrayBuffer), is.toArray)
+ }
+ }
+
+ private class CombinationsItr(n: Int) extends AbstractIterator[C] {
+ // generating all nums such that:
+ // (1) nums(0) + .. + nums(length-1) = n
+ // (2) 0 <= nums(i) <= cnts(i), where 0 <= i <= cnts.length-1
+ private[this] val (elms, cnts, nums) = init()
+ private[this] val offs = cnts.scanLeft(0)(_ + _)
+ private[this] var _hasNext = true
+
+ def hasNext = _hasNext
+ def next(): C = {
+ if (!hasNext)
+ Iterator.empty.next()
+
+ /* Calculate this result. */
+ val buf = newSpecificBuilder
+ for(k <- 0 until nums.length; j <- 0 until nums(k))
+ buf += elms(offs(k)+j)
+ val res = buf.result()
+
+ /* Prepare for the next call to next. */
+ var idx = nums.length - 1
+ while (idx >= 0 && nums(idx) == cnts(idx))
+ idx -= 1
+
+ idx = nums.lastIndexWhere(_ > 0, idx - 1)
+
+ if (idx < 0)
+ _hasNext = false
+ else {
+ // OPT: hand rolled version of `sum = nums.view(idx + 1, nums.length).sum + 1`
+ var sum = 1
+ var i = idx + 1
+ while (i < nums.length) {
+ sum += nums(i)
+ i += 1
+ }
+ nums(idx) -= 1
+ for (k <- (idx+1) until nums.length) {
+ nums(k) = sum min cnts(k)
+ sum -= nums(k)
+ }
+ }
+
+ res
+ }
+
+ /** Rearrange seq to newSeq a0a0..a0a1..a1...ak..ak such that
+ * seq.count(_ == aj) == cnts(j)
+ *
+ * @return (newSeq,cnts,nums)
+ */
+ private def init(): (IndexedSeq[A], Array[Int], Array[Int]) = {
+ val m = mutable.HashMap[A, Int]()
+
+ // e => (e, weight(e))
+ val (es, is) = (self.toGenericSeq map (e => (e, m.getOrElseUpdate(e, m.size))) sortBy (_._2)).unzip
+ val cs = new Array[Int](m.size)
+ is foreach (i => cs(i) += 1)
+ val ns = new Array[Int](cs.length)
+
+ var r = n
+ 0 until ns.length foreach { k =>
+ ns(k) = r min cs(k)
+ r -= ns(k)
+ }
+ (es.to(IndexedSeq), cs, ns)
+ }
+ }
+
+ /** Sorts this $coll according to an Ordering.
+ *
+ * The sort is stable. That is, elements that are equal (as determined by
+ * `ord.compare`) appear in the same order in the sorted sequence as in the original.
+ *
+ * @see [[scala.math.Ordering]]
+ *
+ * $willForceEvaluation
+ *
+ * @param ord the ordering to be used to compare elements.
+ * @return a $coll consisting of the elements of this $coll
+ * sorted according to the ordering `ord`.
+ */
+ def sorted[B >: A](implicit ord: Ordering[B]): C = {
+ val len = this.length
+ val b = newSpecificBuilder
+ if (len == 1) b += head
+ else if (len > 1) {
+ b.sizeHint(len)
+ val arr = new Array[Any](len)
+ @annotation.unused val copied = copyToArray(arr)
+ //assert(copied == len)
+ java.util.Arrays.sort(arr.asInstanceOf[Array[AnyRef]], ord.asInstanceOf[Ordering[AnyRef]])
+ var i = 0
+ while (i < len) {
+ b += arr(i).asInstanceOf[A]
+ i += 1
+ }
+ }
+ b.result()
+ }
+
+ /** Sorts this $coll according to a comparison function.
+ * $willNotTerminateInf
+ * $willForceEvaluation
+ *
+ * The sort is stable. That is, elements that are equal
+ * (`lt` returns false for both directions of comparison)
+ * appear in the same order in the sorted sequence as in the original.
+ *
+ * @param lt a predicate that is true if
+ * its first argument strictly precedes its second argument in
+ * the desired ordering.
+ * @return a $coll consisting of the elements of this $coll
+ * sorted according to the comparison function `lt`.
+ * @example {{{
+ * List("Steve", "Bobby", "Tom", "John", "Bob").sortWith((x, y) => x.take(3).compareTo(y.take(3)) < 0) =
+ * List("Bobby", "Bob", "John", "Steve", "Tom")
+ * }}}
+ */
+ def sortWith(lt: (A, A) => Boolean): C = sorted(Ordering.fromLessThan(lt))
+
+ /** Sorts this $coll according to the Ordering which results from transforming
+ * an implicitly given Ordering with a transformation function.
+ * $willNotTerminateInf
+ * $willForceEvaluation
+ *
+ * The sort is stable. That is, elements that are equal (as determined by
+ * `ord.compare`) appear in the same order in the sorted sequence as in the original.
+ *
+ * @see [[scala.math.Ordering]]
+ * @param f the transformation function mapping elements
+ * to some other domain `B`.
+ * @param ord the ordering assumed on domain `B`.
+ * @tparam B the target type of the transformation `f`, and the type where
+ * the ordering `ord` is defined.
+ * @return a $coll consisting of the elements of this $coll
+ * sorted according to the ordering where `x < y` if
+ * `ord.lt(f(x), f(y))`.
+ *
+ * @example {{{
+ * val words = "The quick brown fox jumped over the lazy dog".split(' ')
+ * // this works because scala.Ordering will implicitly provide an Ordering[Tuple2[Int, Char]]
+ * words.sortBy(x => (x.length, x.head))
+ * res0: Array[String] = Array(The, dog, fox, the, lazy, over, brown, quick, jumped)
+ * }}}
+ */
+ def sortBy[B](f: A => B)(implicit ord: Ordering[B]): C = sorted(ord on f)
+
+ /** Produces the range of all indices of this sequence.
+ * $willForceEvaluation
+ *
+ * @return a `Range` value from `0` to one less than the length of this $coll.
+ */
+ def indices: Range = Range(0, length)
+
+ override final def sizeCompare(otherSize: Int): Int = lengthCompare(otherSize)
+
+ /** Compares the length of this $coll to a test value.
+ *
+ * @param len the test value that gets compared with the length.
+ * @return A value `x` where
+ * {{{
+ * x < 0 if this.length < len
+ * x == 0 if this.length == len
+ * x > 0 if this.length > len
+ * }}}
+ * The method as implemented here does not call `length` directly; its running time
+ * is `O(length min len)` instead of `O(length)`. The method should be overridden
+ * if computing `length` is cheap and `knownSize` returns `-1`.
+ *
+ * @see [[lengthIs]]
+ */
+ def lengthCompare(len: Int): Int = super.sizeCompare(len)
+
+ override final def sizeCompare(that: Iterable[_]): Int = lengthCompare(that)
+
+ /** Compares the length of this $coll to the size of another `Iterable`.
+ *
+ * @param that the `Iterable` whose size is compared with this $coll's length.
+ * @return A value `x` where
+ * {{{
+ * x < 0 if this.length < that.size
+ * x == 0 if this.length == that.size
+ * x > 0 if this.length > that.size
+ * }}}
+ * The method as implemented here does not call `length` or `size` directly; its running time
+ * is `O(this.length min that.size)` instead of `O(this.length + that.size)`.
+ * The method should be overridden if computing `size` is cheap and `knownSize` returns `-1`.
+ */
+ def lengthCompare(that: Iterable[_]): Int = super.sizeCompare(that)
+
+ /** Returns a value class containing operations for comparing the length of this $coll to a test value.
+ *
+ * These operations are implemented in terms of [[lengthCompare(Int) `lengthCompare(Int)`]], and
+ * allow the following more readable usages:
+ *
+ * {{{
+ * this.lengthIs < len // this.lengthCompare(len) < 0
+ * this.lengthIs <= len // this.lengthCompare(len) <= 0
+ * this.lengthIs == len // this.lengthCompare(len) == 0
+ * this.lengthIs != len // this.lengthCompare(len) != 0
+ * this.lengthIs >= len // this.lengthCompare(len) >= 0
+ * this.lengthIs > len // this.lengthCompare(len) > 0
+ * }}}
+ */
+ @inline final def lengthIs: IterableOps.SizeCompareOps = new IterableOps.SizeCompareOps(this)
+
+ override def isEmpty: Boolean = lengthCompare(0) == 0
+
+ /** Tests whether the elements of this collection are the same (and in the same order)
+ * as those of `that`.
+ */
+ def sameElements[B >: A](that: IterableOnce[B]): Boolean = {
+ val thisKnownSize = knownSize
+ val knownSizeDifference = thisKnownSize != -1 && {
+ val thatKnownSize = that.knownSize
+ thatKnownSize != -1 && thisKnownSize != thatKnownSize
+ }
+ !knownSizeDifference && iterator.sameElements(that)
+ }
+
+ /** Tests whether every element of this $coll relates to the
+ * corresponding element of another sequence by satisfying a test predicate.
+ *
+ * @param that the other sequence
+ * @param p the test predicate, which relates elements from both sequences
+ * @tparam B the type of the elements of `that`
+ * @return `true` if both sequences have the same length and
+ * `p(x, y)` is `true` for all corresponding elements `x` of this $coll
+ * and `y` of `that`, otherwise `false`.
+ */
+ def corresponds[B](that: Seq[B])(p: (A, B) => Boolean): Boolean = {
+ val i = iterator
+ val j = that.iterator
+ while (i.hasNext && j.hasNext)
+ if (!p(i.next(), j.next()))
+ return false
+ !i.hasNext && !j.hasNext
+ }
+
+ /** Computes the multiset difference between this $coll and another sequence.
+ *
+ * @param that the sequence of elements to remove
+ * @return a new $coll which contains all elements of this $coll
+ * except some of occurrences of elements that also appear in `that`.
+ * If an element value `x` appears
+ * ''n'' times in `that`, then the first ''n'' occurrences of `x` will not form
+ * part of the result, but any following occurrences will.
+ */
+ def diff[B >: A](that: Seq[B]): C = {
+ val occ = occCounts(that)
+ fromSpecific(iterator.filter { x =>
+ var include = false
+ occ.updateWith(x) {
+ case None => {
+ include = true
+ None
+ }
+ case Some(1) => None
+ case Some(n) => Some(n - 1)
+ }
+ include
+ })
+ }
+
+ /** Computes the multiset intersection between this $coll and another sequence.
+ *
+ * @param that the sequence of elements to intersect with.
+ * @return a new $coll which contains all elements of this $coll
+ * which also appear in `that`.
+ * If an element value `x` appears
+ * ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained
+ * in the result, but any following occurrences will be omitted.
+ */
+ def intersect[B >: A](that: Seq[B]): C = {
+ val occ = occCounts(that)
+ fromSpecific(iterator.filter { x =>
+ var include = true
+ occ.updateWith(x) {
+ case None => {
+ include = false
+ None
+ }
+ case Some(1) => None
+ case Some(n) => Some(n - 1)
+ }
+ include
+ })
+ }
+
+ /** Produces a new $coll where a slice of elements in this $coll is replaced by another sequence.
+ *
+ * Patching at negative indices is the same as patching starting at 0.
+ * Patching at indices at or larger than the length of the original $coll appends the patch to the end.
+ * If the `replaced` count would exceed the available elements, the difference in excess is ignored.
+ *
+ * @param from the index of the first replaced element
+ * @param other the replacement sequence
+ * @param replaced the number of elements to drop in the original $coll
+ * @tparam B the element type of the returned $coll.
+ * @return a new $coll consisting of all elements of this $coll
+ * except that `replaced` elements starting from `from` are replaced
+ * by all the elements of `other`.
+ */
+ def patch[B >: A](from: Int, other: IterableOnce[B], replaced: Int): CC[B] =
+ iterableFactory.from(new View.Patched(this, from, other, replaced))
+
+ /** A copy of this $coll with one single replaced element.
+ * @param index the position of the replacement
+ * @param elem the replacing element
+ * @tparam B the element type of the returned $coll.
+ * @return a new $coll which is a copy of this $coll with the element at position `index` replaced by `elem`.
+ * @throws IndexOutOfBoundsException if `index` does not satisfy `0 <= index < length`. In case of a
+ * lazy collection this exception may be thrown at a later time or not at
+ * all (if the end of the collection is never evaluated).
+ */
+ def updated[B >: A](index: Int, elem: B): CC[B] = {
+ if(index < 0) throw new IndexOutOfBoundsException(index.toString)
+ val k = knownSize
+ if(k >= 0 && index >= k) throw new IndexOutOfBoundsException(index.toString)
+ iterableFactory.from(new View.Updated(this, index, elem))
+ }
+
+ protected[collection] def occCounts[B](sq: Seq[B]): mutable.Map[B, Int] = {
+ val occ = new mutable.HashMap[B, Int]()
+ for (y <- sq) occ.updateWith(y) {
+ case None => Some(1)
+ case Some(n) => Some(n + 1)
+ }
+ occ
+ }
+
+ /** Searches this sorted sequence for a specific element. If the sequence is an
+ * `IndexedSeq`, a binary search is used. Otherwise, a linear search is used.
+ *
+ * The sequence should be sorted with the same `Ordering` before calling; otherwise,
+ * the results are undefined.
+ *
+ * @see [[scala.collection.IndexedSeq]]
+ * @see [[scala.math.Ordering]]
+ * @see [[scala.collection.SeqOps]], method `sorted`
+ *
+ * @param elem the element to find.
+ * @param ord the ordering to be used to compare elements.
+ *
+ * @return a `Found` value containing the index corresponding to the element in the
+ * sequence, or the `InsertionPoint` where the element would be inserted if
+ * the element is not in the sequence.
+ */
+ def search[B >: A](elem: B)(implicit ord: Ordering[B]): SearchResult =
+ linearSearch(view, elem, 0)(ord)
+
+ /** Searches within an interval in this sorted sequence for a specific element. If this
+ * sequence is an `IndexedSeq`, a binary search is used. Otherwise, a linear search
+ * is used.
+ *
+ * The sequence should be sorted with the same `Ordering` before calling; otherwise,
+ * the results are undefined.
+ *
+ * @see [[scala.collection.IndexedSeq]]
+ * @see [[scala.math.Ordering]]
+ * @see [[scala.collection.SeqOps]], method `sorted`
+ *
+ * @param elem the element to find.
+ * @param from the index where the search starts.
+ * @param to the index following where the search ends.
+ * @param ord the ordering to be used to compare elements.
+ *
+ * @return a `Found` value containing the index corresponding to the element in the
+ * sequence, or the `InsertionPoint` where the element would be inserted if
+ * the element is not in the sequence.
+ *
+ * @note if `to <= from`, the search space is empty, and an `InsertionPoint` at `from`
+ * is returned
+ */
+ def search[B >: A](elem: B, from: Int, to: Int) (implicit ord: Ordering[B]): SearchResult =
+ linearSearch(view.slice(from, to), elem, math.max(0, from))(ord)
+
+ private[this] def linearSearch[B >: A](c: View[A], elem: B, offset: Int)
+ (implicit ord: Ordering[B]): SearchResult = {
+ var idx = offset
+ val it = c.iterator
+ while (it.hasNext) {
+ val cur = it.next()
+ if (ord.equiv(elem, cur)) return Found(idx)
+ else if (ord.lt(elem, cur)) return InsertionPoint(idx)
+ idx += 1
+ }
+ InsertionPoint(idx)
+ }
+}
+
+object SeqOps {
+
+ // KMP search utilities
+
+ /** A KMP implementation, based on the undoubtedly reliable wikipedia entry.
+ * Note: I made this private to keep it from entering the API. That can be reviewed.
+ *
+ * @param S Sequence that may contain target
+ * @param m0 First index of S to consider
+ * @param m1 Last index of S to consider (exclusive)
+ * @param W Target sequence
+ * @param n0 First index of W to match
+ * @param n1 Last index of W to match (exclusive)
+ * @param forward Direction of search (from beginning==true, from end==false)
+ * @return Index of start of sequence if found, -1 if not (relative to beginning of S, not m0).
+ */
+ private def kmpSearch[B](S: scala.collection.Seq[B], m0: Int, m1: Int, W: scala.collection.Seq[B], n0: Int, n1: Int, forward: Boolean): Int = {
+ // Check for redundant case when target has single valid element
+ def clipR(x: Int, y: Int) = if (x < y) x else -1
+ def clipL(x: Int, y: Int) = if (x > y) x else -1
+
+ if (n1 == n0+1) {
+ if (forward)
+ clipR(S.indexOf(W(n0), m0), m1)
+ else
+ clipL(S.lastIndexOf(W(n0), m1-1), m0-1)
+ }
+
+ // Check for redundant case when both sequences are same size
+ else if (m1-m0 == n1-n0) {
+ // Accepting a little slowness for the uncommon case.
+ if (S.iterator.slice(m0, m1).sameElements(W.iterator.slice(n0, n1))) m0
+ else -1
+ }
+ // Now we know we actually need KMP search, so do it
+ else S match {
+ case xs: scala.collection.IndexedSeq[_] =>
+ // We can index into S directly; it should be adequately fast
+ val Wopt = kmpOptimizeWord(W, n0, n1, forward)
+ val T = kmpJumpTable(Wopt, n1-n0)
+ var i, m = 0
+ val zero = if (forward) m0 else m1-1
+ val delta = if (forward) 1 else -1
+ while (i+m < m1-m0) {
+ if (Wopt(i) == S(zero+delta*(i+m))) {
+ i += 1
+ if (i == n1-n0) return (if (forward) m+m0 else m1-m-i)
+ }
+ else {
+ val ti = T(i)
+ m += i - ti
+ if (i > 0) i = ti
+ }
+ }
+ -1
+ case _ =>
+ // We had better not index into S directly!
+ val iter = S.iterator.drop(m0)
+ val Wopt = kmpOptimizeWord(W, n0, n1, forward = true)
+ val T = kmpJumpTable(Wopt, n1-n0)
+ val cache = new Array[AnyRef](n1-n0) // Ring buffer--need a quick way to do a look-behind
+ var largest = 0
+ var i, m = 0
+ var answer = -1
+ while (m+m0+n1-n0 <= m1) {
+ while (i+m >= largest) {
+ cache(largest%(n1-n0)) = iter.next().asInstanceOf[AnyRef]
+ largest += 1
+ }
+ if (Wopt(i) == cache((i+m)%(n1-n0)).asInstanceOf[B]) {
+ i += 1
+ if (i == n1-n0) {
+ if (forward) return m+m0
+ else {
+ i -= 1
+ answer = m+m0
+ val ti = T(i)
+ m += i - ti
+ if (i > 0) i = ti
+ }
+ }
+ }
+ else {
+ val ti = T(i)
+ m += i - ti
+ if (i > 0) i = ti
+ }
+ }
+ answer
+ }
+ }
+
+ /** Make sure a target sequence has fast, correctly-ordered indexing for KMP.
+ *
+ * @param W The target sequence
+ * @param n0 The first element in the target sequence that we should use
+ * @param n1 The far end of the target sequence that we should use (exclusive)
+ * @return Target packed in an IndexedSeq (taken from iterator unless W already is an IndexedSeq)
+ */
+ private def kmpOptimizeWord[B](W: scala.collection.Seq[B], n0: Int, n1: Int, forward: Boolean): IndexedSeqView[B] = W match {
+ case iso: IndexedSeq[B] =>
+ // Already optimized for indexing--use original (or custom view of original)
+ if (forward && n0==0 && n1==W.length) iso.view
+ else if (forward) new AbstractIndexedSeqView[B] {
+ val length = n1 - n0
+ def apply(x: Int) = iso(n0 + x)
+ }
+ else new AbstractIndexedSeqView[B] {
+ def length = n1 - n0
+ def apply(x: Int) = iso(n1 - 1 - x)
+ }
+ case _ =>
+ // W is probably bad at indexing. Pack in array (in correct orientation)
+ // Would be marginally faster to special-case each direction
+ new AbstractIndexedSeqView[B] {
+ private[this] val Warr = new Array[AnyRef](n1-n0)
+ private[this] val delta = if (forward) 1 else -1
+ private[this] val done = if (forward) n1-n0 else -1
+ val wit = W.iterator.drop(n0)
+ var i = if (forward) 0 else (n1-n0-1)
+ while (i != done) {
+ Warr(i) = wit.next().asInstanceOf[AnyRef]
+ i += delta
+ }
+
+ val length = n1 - n0
+ def apply(x: Int) = Warr(x).asInstanceOf[B]
+ }
+ }
+
+ /** Make a jump table for KMP search.
+ *
+ * @param Wopt The target sequence
+ * @param wlen Just in case we're only IndexedSeq and not IndexedSeqOptimized
+ * @return KMP jump table for target sequence
+ */
+ private def kmpJumpTable[B](Wopt: IndexedSeqView[B], wlen: Int) = {
+ val arr = new Array[Int](wlen)
+ var pos = 2
+ var cnd = 0
+ arr(0) = -1
+ arr(1) = 0
+ while (pos < wlen) {
+ if (Wopt(pos-1) == Wopt(cnd)) {
+ arr(pos) = cnd + 1
+ pos += 1
+ cnd += 1
+ }
+ else if (cnd > 0) {
+ cnd = arr(cnd)
+ }
+ else {
+ arr(pos) = 0
+ pos += 1
+ }
+ }
+ arr
+ }
+}
+
+/** Explicit instantiation of the `Seq` trait to reduce class file size in subclasses. */
+abstract class AbstractSeq[+A] extends AbstractIterable[A] with Seq[A]
diff --git a/library/src/scala/collection/SeqMap.scala b/library/src/scala/collection/SeqMap.scala
new file mode 100644
index 000000000000..f2b65dfbfb6f
--- /dev/null
+++ b/library/src/scala/collection/SeqMap.scala
@@ -0,0 +1,40 @@
+/*
+ * 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 scala.annotation.nowarn
+
+/**
+ * A generic trait for ordered maps. Concrete classes have to provide
+ * functionality for the abstract methods in `SeqMap`.
+ *
+ * Note that when checking for equality [[SeqMap]] does not take into account
+ * ordering.
+ *
+ * @tparam K the type of the keys contained in this linked map.
+ * @tparam V the type of the values associated with the keys in this linked map.
+ * @define coll immutable seq map
+ * @define Coll `immutable.SeqMap`
+ */
+
+trait SeqMap[K, +V] extends Map[K, V]
+ with MapOps[K, V, SeqMap, SeqMap[K, V]]
+ with MapFactoryDefaults[K, V, SeqMap, Iterable] {
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix: String = "SeqMap"
+
+ override def mapFactory: MapFactory[SeqMap] = SeqMap
+}
+
+object SeqMap extends MapFactory.Delegate[immutable.SeqMap](immutable.SeqMap)
+
diff --git a/library/src/scala/collection/SeqView.scala b/library/src/scala/collection/SeqView.scala
new file mode 100644
index 000000000000..a45797892220
--- /dev/null
+++ b/library/src/scala/collection/SeqView.scala
@@ -0,0 +1,214 @@
+/*
+ * 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 collection
+
+import scala.annotation.nowarn
+import scala.collection.generic.CommonErrors
+
+
+trait SeqView[+A] extends SeqOps[A, View, View[A]] with View[A] {
+ override def view: SeqView[A] = this
+
+ override def map[B](f: A => B): SeqView[B] = new SeqView.Map(this, f)
+ override def appended[B >: A](elem: B): SeqView[B] = new SeqView.Appended(this, elem)
+ override def prepended[B >: A](elem: B): SeqView[B] = new SeqView.Prepended(elem, this)
+ override def reverse: SeqView[A] = new SeqView.Reverse(this)
+ override def take(n: Int): SeqView[A] = new SeqView.Take(this, n)
+ override def drop(n: Int): SeqView[A] = new SeqView.Drop(this, n)
+ override def takeRight(n: Int): SeqView[A] = new SeqView.TakeRight(this, n)
+ override def dropRight(n: Int): SeqView[A] = new SeqView.DropRight(this, n)
+ override def tapEach[U](f: A => U): SeqView[A] = new SeqView.Map(this, { (a: A) => f(a); a })
+
+ def concat[B >: A](suffix: SeqView.SomeSeqOps[B]): SeqView[B] = new SeqView.Concat(this, suffix)
+ def appendedAll[B >: A](suffix: SeqView.SomeSeqOps[B]): SeqView[B] = new SeqView.Concat(this, suffix)
+ def prependedAll[B >: A](prefix: SeqView.SomeSeqOps[B]): SeqView[B] = new SeqView.Concat(prefix, this)
+
+ override def sorted[B >: A](implicit ord: Ordering[B]): SeqView[A] = new SeqView.Sorted(this, ord)
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix: String = "SeqView"
+}
+
+object SeqView {
+
+ /** A `SeqOps` whose collection type and collection type constructor are unknown */
+ private type SomeSeqOps[+A] = SeqOps[A, AnyConstr, _]
+
+ /** A view that doesn’t apply any transformation to an underlying sequence */
+ @SerialVersionUID(3L)
+ class Id[+A](underlying: SomeSeqOps[A]) extends AbstractSeqView[A] {
+ def apply(idx: Int): A = underlying.apply(idx)
+ def length: Int = underlying.length
+ def iterator: Iterator[A] = underlying.iterator
+ override def knownSize: Int = underlying.knownSize
+ override def isEmpty: Boolean = underlying.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ class Map[+A, +B](underlying: SomeSeqOps[A], f: A => B) extends View.Map[A, B](underlying, f) with SeqView[B] {
+ def apply(idx: Int): B = f(underlying(idx))
+ def length: Int = underlying.length
+ }
+
+ @SerialVersionUID(3L)
+ class Appended[+A](underlying: SomeSeqOps[A], elem: A) extends View.Appended(underlying, elem) with SeqView[A] {
+ def apply(idx: Int): A = if (idx == underlying.length) elem else underlying(idx)
+ def length: Int = underlying.length + 1
+ }
+
+ @SerialVersionUID(3L)
+ class Prepended[+A](elem: A, underlying: SomeSeqOps[A]) extends View.Prepended(elem, underlying) with SeqView[A] {
+ def apply(idx: Int): A = if (idx == 0) elem else underlying(idx - 1)
+ def length: Int = underlying.length + 1
+ }
+
+ @SerialVersionUID(3L)
+ class Concat[A](prefix: SomeSeqOps[A], suffix: SomeSeqOps[A]) extends View.Concat[A](prefix, suffix) with SeqView[A] {
+ def apply(idx: Int): A = {
+ val l = prefix.length
+ if (idx < l) prefix(idx) else suffix(idx - l)
+ }
+ def length: Int = prefix.length + suffix.length
+ }
+
+ @SerialVersionUID(3L)
+ class Reverse[A](underlying: SomeSeqOps[A]) extends AbstractSeqView[A] {
+ def apply(i: Int) = underlying.apply(size - 1 - i)
+ def length = underlying.size
+ def iterator: Iterator[A] = underlying.reverseIterator
+ override def knownSize: Int = underlying.knownSize
+ override def isEmpty: Boolean = underlying.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ class Take[+A](underlying: SomeSeqOps[A], n: Int) extends View.Take(underlying, n) with SeqView[A] {
+ def apply(idx: Int): A = if (idx < n) {
+ underlying(idx)
+ } else {
+ throw (
+ if (underlying.knownSize >= 0) CommonErrors.indexOutOfBounds(index = idx, max = knownSize - 1)
+ else CommonErrors.indexOutOfBounds(index = idx)
+ )
+ }
+ def length: Int = underlying.length min normN
+ }
+
+ @SerialVersionUID(3L)
+ class TakeRight[+A](underlying: SomeSeqOps[A], n: Int) extends View.TakeRight(underlying, n) with SeqView[A] {
+ private[this] val delta = (underlying.size - (n max 0)) max 0
+ def length = underlying.size - delta
+ @throws[IndexOutOfBoundsException]
+ def apply(i: Int) = underlying.apply(i + delta)
+ }
+
+ @SerialVersionUID(3L)
+ class Drop[A](underlying: SomeSeqOps[A], n: Int) extends View.Drop[A](underlying, n) with SeqView[A] {
+ def length = (underlying.size - normN) max 0
+ @throws[IndexOutOfBoundsException]
+ def apply(i: Int) = underlying.apply(i + normN)
+ override def drop(n: Int): SeqView[A] = new Drop(underlying, this.n + n)
+ }
+
+ @SerialVersionUID(3L)
+ class DropRight[A](underlying: SomeSeqOps[A], n: Int) extends View.DropRight[A](underlying, n) with SeqView[A] {
+ private[this] val len = (underlying.size - (n max 0)) max 0
+ def length = len
+ @throws[IndexOutOfBoundsException]
+ def apply(i: Int) = underlying.apply(i)
+ }
+
+ @SerialVersionUID(3L)
+ class Sorted[A, B >: A] private (private[this] var underlying: SomeSeqOps[A],
+ private[this] val len: Int,
+ ord: Ordering[B])
+ extends SeqView[A] {
+ outer =>
+
+ // force evaluation immediately by calling `length` so infinite collections
+ // hang on `sorted`/`sortWith`/`sortBy` rather than on arbitrary method calls
+ def this(underlying: SomeSeqOps[A], ord: Ordering[B]) = this(underlying, underlying.length, ord)
+
+ @SerialVersionUID(3L)
+ private[this] class ReverseSorted extends SeqView[A] {
+ private[this] lazy val _reversed = new SeqView.Reverse(_sorted)
+
+ def apply(i: Int): A = _reversed.apply(i)
+ def length: Int = len
+ def iterator: Iterator[A] = Iterator.empty ++ _reversed.iterator // very lazy
+ override def knownSize: Int = len
+ override def isEmpty: Boolean = len == 0
+ override def to[C1](factory: Factory[A, C1]): C1 = _reversed.to(factory)
+ override def reverse: SeqView[A] = outer
+ override protected def reversed: Iterable[A] = outer
+
+ override def sorted[B1 >: A](implicit ord1: Ordering[B1]): SeqView[A] =
+ if (ord1 == Sorted.this.ord) outer
+ else if (ord1.isReverseOf(Sorted.this.ord)) this
+ else new Sorted(elems, len, ord1)
+ }
+
+ @volatile private[this] var evaluated = false
+
+ private[this] lazy val _sorted: Seq[A] = {
+ val res = {
+ val len = this.len
+ if (len == 0) Nil
+ else if (len == 1) List(underlying.head)
+ else {
+ val arr = new Array[Any](len) // Array[Any] =:= Array[AnyRef]
+ @annotation.unused val copied = underlying.copyToArray(arr)
+ //assert(copied == len)
+ java.util.Arrays.sort(arr.asInstanceOf[Array[AnyRef]], ord.asInstanceOf[Ordering[AnyRef]])
+ // casting the Array[AnyRef] to Array[A] and creating an ArraySeq from it
+ // is safe because:
+ // - the ArraySeq is immutable, and items that are not of type A
+ // cannot be added to it
+ // - we know it only contains items of type A (and if this collection
+ // contains items of another type, we'd get a CCE anyway)
+ // - the cast doesn't actually do anything in the runtime because the
+ // type of A is not known and Array[_] is Array[AnyRef]
+ immutable.ArraySeq.unsafeWrapArray(arr.asInstanceOf[Array[A]])
+ }
+ }
+ evaluated = true
+ underlying = null
+ res
+ }
+
+ private[this] def elems: SomeSeqOps[A] = {
+ val orig = underlying
+ if (evaluated) _sorted else orig
+ }
+
+ def apply(i: Int): A = _sorted.apply(i)
+ def length: Int = len
+ def iterator: Iterator[A] = Iterator.empty ++ _sorted.iterator // very lazy
+ override def knownSize: Int = len
+ override def isEmpty: Boolean = len == 0
+ override def to[C1](factory: Factory[A, C1]): C1 = _sorted.to(factory)
+ override def reverse: SeqView[A] = new ReverseSorted
+ // we know `_sorted` is either tiny or has efficient random access,
+ // so this is acceptable for `reversed`
+ override protected def reversed: Iterable[A] = new ReverseSorted
+
+ override def sorted[B1 >: A](implicit ord1: Ordering[B1]): SeqView[A] =
+ if (ord1 == this.ord) this
+ else if (ord1.isReverseOf(this.ord)) reverse
+ else new Sorted(elems, len, ord1)
+ }
+}
+
+/** Explicit instantiation of the `SeqView` trait to reduce class file size in subclasses. */
+@SerialVersionUID(3L)
+abstract class AbstractSeqView[+A] extends AbstractView[A] with SeqView[A]
diff --git a/library/src/scala/collection/Set.scala b/library/src/scala/collection/Set.scala
new file mode 100644
index 000000000000..f682e20861ab
--- /dev/null
+++ b/library/src/scala/collection/Set.scala
@@ -0,0 +1,269 @@
+/*
+ * 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 collection
+
+import scala.util.hashing.MurmurHash3
+import java.lang.String
+
+import scala.annotation.nowarn
+
+/** Base trait for set collections.
+ */
+trait Set[A]
+ extends Iterable[A]
+ with SetOps[A, Set, Set[A]]
+ with Equals
+ with IterableFactoryDefaults[A, Set] {
+
+ def canEqual(that: Any) = true
+
+ /**
+ * Equality of sets is implemented using the lookup method [[contains]]. This method returns `true` if
+ * - the argument `that` is a `Set`,
+ * - the two sets have the same [[size]], and
+ * - for every `element` this set, `other.contains(element) == true`.
+ *
+ * The implementation of `equals` checks the [[canEqual]] method, so subclasses of `Set` can narrow down the equality
+ * to specific set types. The `Set` implementations in the standard library can all be compared, their `canEqual`
+ * methods return `true`.
+ *
+ * Note: The `equals` method only respects the equality laws (symmetry, transitivity) if the two sets use the same
+ * element equivalence function in their lookup operation. For example, the element equivalence operation in a
+ * [[scala.collection.immutable.TreeSet]] is defined by its ordering. Comparing a `TreeSet` with a `HashSet` leads
+ * to unexpected results if `ordering.equiv(e1, e2)` (used for lookup in `TreeSet`) is different from `e1 == e2`
+ * (used for lookup in `HashSet`).
+ *
+ * {{{
+ * scala> import scala.collection.immutable._
+ * scala> val ord: Ordering[String] = _ compareToIgnoreCase _
+ *
+ * scala> TreeSet("A")(ord) == HashSet("a")
+ * val res0: Boolean = false
+ *
+ * scala> HashSet("a") == TreeSet("A")(ord)
+ * val res1: Boolean = true
+ * }}}
+ *
+ *
+ * @param that The set to which this set is compared
+ * @return `true` if the two sets are equal according to the description
+ */
+ override def equals(that: Any): Boolean =
+ (this eq that.asInstanceOf[AnyRef]) || (that match {
+ case set: Set[A @unchecked] if set.canEqual(this) =>
+ (this.size == set.size) && {
+ try this.subsetOf(set)
+ catch { case _: ClassCastException => false } // PR #9565 / scala/bug#12228
+ }
+ case _ =>
+ false
+ })
+
+ override def hashCode(): Int = MurmurHash3.setHash(this)
+
+ override def iterableFactory: IterableFactory[Set] = Set
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix: String = "Set"
+
+ override def toString(): String = super[Iterable].toString() // Because `Function1` overrides `toString` too
+}
+
+/** Base trait for set operations
+ *
+ * @define coll set
+ * @define Coll `Set`
+ */
+trait SetOps[A, +CC[_], +C <: SetOps[A, CC, C]]
+ extends IterableOps[A, CC, C]
+ with (A => Boolean) {
+
+ def contains(elem: A): Boolean
+
+ /** Tests if some element is contained in this set.
+ *
+ * This method is equivalent to `contains`. It allows sets to be interpreted as predicates.
+ * @param elem the element to test for membership.
+ * @return `true` if `elem` is contained in this set, `false` otherwise.
+ */
+ @`inline` final def apply(elem: A): Boolean = this.contains(elem)
+
+ /** Tests whether this set is a subset of another set.
+ *
+ * @param that the set to test.
+ * @return `true` if this set is a subset of `that`, i.e. if
+ * every element of this set is also an element of `that`.
+ */
+ def subsetOf(that: Set[A]): Boolean = this.forall(that)
+
+ /** An iterator over all subsets of this set of the given size.
+ * If the requested size is impossible, an empty iterator is returned.
+ *
+ * @param len the size of the subsets.
+ * @return the iterator.
+ */
+ def subsets(len: Int): Iterator[C] = {
+ if (len < 0 || len > size) Iterator.empty
+ else new SubsetsItr(this.to(IndexedSeq), len)
+ }
+
+ /** An iterator over all subsets of this set.
+ *
+ * @return the iterator.
+ */
+ def subsets(): Iterator[C] = new AbstractIterator[C] {
+ private[this] val elms = SetOps.this.to(IndexedSeq)
+ private[this] var len = 0
+ private[this] var itr: Iterator[C] = Iterator.empty
+
+ def hasNext = len <= elms.size || itr.hasNext
+ def next() = {
+ if (!itr.hasNext) {
+ if (len > elms.size) Iterator.empty.next()
+ else {
+ itr = new SubsetsItr(elms, len)
+ len += 1
+ }
+ }
+
+ itr.next()
+ }
+ }
+
+ /** An Iterator including all subsets containing exactly len elements.
+ * If the elements in 'This' type is ordered, then the subsets will also be in the same order.
+ * ListSet(1,2,3).subsets => {{1},{2},{3},{1,2},{1,3},{2,3},{1,2,3}}
+ *
+ * $willForceEvaluation
+ *
+ */
+ private class SubsetsItr(elms: IndexedSeq[A], len: Int) extends AbstractIterator[C] {
+ private[this] val idxs = Array.range(0, len+1)
+ private[this] var _hasNext = true
+ idxs(len) = elms.size
+
+ def hasNext = _hasNext
+ @throws[NoSuchElementException]
+ def next(): C = {
+ if (!hasNext) Iterator.empty.next()
+
+ val buf = newSpecificBuilder
+ idxs.slice(0, len) foreach (idx => buf += elms(idx))
+ val result = buf.result()
+
+ var i = len - 1
+ while (i >= 0 && idxs(i) == idxs(i+1)-1) i -= 1
+
+ if (i < 0) _hasNext = false
+ else {
+ idxs(i) += 1
+ for (j <- (i+1) until len)
+ idxs(j) = idxs(j-1) + 1
+ }
+
+ result
+ }
+ }
+
+ /** Computes the intersection between this set and another set.
+ *
+ * @param that the set to intersect with.
+ * @return a new set consisting of all elements that are both in this
+ * set and in the given set `that`.
+ */
+ def intersect(that: Set[A]): C = this.filter(that)
+
+ /** Alias for `intersect` */
+ @`inline` final def & (that: Set[A]): C = intersect(that)
+
+ /** Computes the difference of this set and another set.
+ *
+ * @param that the set of elements to exclude.
+ * @return a set containing those elements of this
+ * set that are not also contained in the given set `that`.
+ */
+ def diff(that: Set[A]): C
+
+ /** Alias for `diff` */
+ @`inline` final def &~ (that: Set[A]): C = this diff that
+
+ @deprecated("Consider requiring an immutable Set", "2.13.0")
+ def -- (that: IterableOnce[A]): C = {
+ val toRemove = that.iterator.to(immutable.Set)
+ fromSpecific(view.filterNot(toRemove))
+ }
+
+ @deprecated("Consider requiring an immutable Set or fall back to Set.diff", "2.13.0")
+ def - (elem: A): C = diff(Set(elem))
+
+ @deprecated("Use &- with an explicit collection argument instead of - with varargs", "2.13.0")
+ def - (elem1: A, elem2: A, elems: A*): C = diff(elems.toSet + elem1 + elem2)
+
+ /** Creates a new $coll by adding all elements contained in another collection to this $coll, omitting duplicates.
+ *
+ * This method takes a collection of elements and adds all elements, omitting duplicates, into $coll.
+ *
+ * Example:
+ * {{{
+ * scala> val a = Set(1, 2) concat Set(2, 3)
+ * a: scala.collection.immutable.Set[Int] = Set(1, 2, 3)
+ * }}}
+ *
+ * @param that the collection containing the elements to add.
+ * @return a new $coll with the given elements added, omitting duplicates.
+ */
+ def concat(that: collection.IterableOnce[A]): C = this match {
+ case optimizedSet @ (_ : scala.collection.immutable.Set.Set1[A] | _: scala.collection.immutable.Set.Set2[A] | _: scala.collection.immutable.Set.Set3[A] | _: scala.collection.immutable.Set.Set4[A]) =>
+ // StrictOptimizedSetOps optimization of concat (these Sets cannot extend StrictOptimizedSetOps because of binary-incompatible return type; cf. PR #10036)
+ var result = optimizedSet.asInstanceOf[scala.collection.immutable.SetOps[A, scala.collection.immutable.Set, scala.collection.immutable.Set[A]]]
+ val it = that.iterator
+ while (it.hasNext) result = result + it.next()
+ result.asInstanceOf[C]
+ case _ => fromSpecific(that match {
+ case that: collection.Iterable[A] => new View.Concat(this, that)
+ case _ => iterator.concat(that.iterator)
+ })
+ }
+
+ @deprecated("Consider requiring an immutable Set or fall back to Set.union", "2.13.0")
+ def + (elem: A): C = fromSpecific(new View.Appended(this, elem))
+
+ @deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
+ def + (elem1: A, elem2: A, elems: A*): C = fromSpecific(new View.Concat(new View.Appended(new View.Appended(this, elem1), elem2), elems))
+
+ /** Alias for `concat` */
+ @`inline` final def ++ (that: collection.IterableOnce[A]): C = concat(that)
+
+ /** Computes the union between of set and another set.
+ *
+ * @param that the set to form the union with.
+ * @return a new set consisting of all elements that are in this
+ * set or in the given set `that`.
+ */
+ @`inline` final def union(that: Set[A]): C = concat(that)
+
+ /** Alias for `union` */
+ @`inline` final def | (that: Set[A]): C = concat(that)
+}
+
+/**
+ * $factoryInfo
+ * @define coll set
+ * @define Coll `Set`
+ */
+@SerialVersionUID(3L)
+object Set extends IterableFactory.Delegate[Set](immutable.Set)
+
+/** Explicit instantiation of the `Set` trait to reduce class file size in subclasses. */
+abstract class AbstractSet[A] extends AbstractIterable[A] with Set[A]
diff --git a/library/src/scala/collection/SortedMap.scala b/library/src/scala/collection/SortedMap.scala
new file mode 100644
index 000000000000..d2ccb9e38aa9
--- /dev/null
+++ b/library/src/scala/collection/SortedMap.scala
@@ -0,0 +1,220 @@
+/*
+ * 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 collection
+
+import scala.annotation.{implicitNotFound, nowarn}
+
+/** A Map whose keys are sorted according to a [[scala.math.Ordering]]*/
+trait SortedMap[K, +V]
+ extends Map[K, V]
+ with SortedMapOps[K, V, SortedMap, SortedMap[K, V]]
+ with SortedMapFactoryDefaults[K, V, SortedMap, Iterable, Map]{
+
+ def unsorted: Map[K, V] = this
+
+ def sortedMapFactory: SortedMapFactory[SortedMap] = SortedMap
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix: String = "SortedMap"
+
+ override def equals(that: Any): Boolean = that match {
+ case _ if this eq that.asInstanceOf[AnyRef] => true
+ case sm: SortedMap[K @unchecked, _] if sm.ordering == this.ordering =>
+ (sm canEqual this) &&
+ (this.size == sm.size) && {
+ val i1 = this.iterator
+ val i2 = sm.iterator
+ var allEqual = true
+ while (allEqual && i1.hasNext) {
+ val kv1 = i1.next()
+ val kv2 = i2.next()
+ allEqual = ordering.equiv(kv1._1, kv2._1) && kv1._2 == kv2._2
+ }
+ allEqual
+ }
+ case _ => super.equals(that)
+ }
+}
+
+trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], +C <: SortedMapOps[K, V, CC, C]]
+ extends MapOps[K, V, Map, C]
+ with SortedOps[K, C] {
+
+ /** The companion object of this sorted map, providing various factory methods.
+ *
+ * @note When implementing a custom collection type and refining `CC` to the new type, this
+ * method needs to be overridden to return a factory for the new type (the compiler will
+ * issue an error otherwise).
+ */
+ def sortedMapFactory: SortedMapFactory[CC]
+
+ /** Similar to `mapFromIterable`, but returns a SortedMap collection type.
+ * Note that the return type is now `CC[K2, V2]`.
+ */
+ @`inline` protected final def sortedMapFromIterable[K2, V2](it: Iterable[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] = sortedMapFactory.from(it)
+
+ def unsorted: Map[K, V]
+
+ /**
+ * Creates an iterator over all the key/value pairs
+ * contained in this map having a key greater than or
+ * equal to `start` according to the ordering of
+ * this map. x.iteratorFrom(y) is equivalent
+ * to but often more efficient than x.from(y).iterator.
+ *
+ * @param start The lower bound (inclusive)
+ * on the keys to be returned
+ */
+ def iteratorFrom(start: K): Iterator[(K, V)]
+
+ /**
+ * Creates an iterator over all the keys(or elements) contained in this
+ * collection greater than or equal to `start`
+ * according to the ordering of this collection. x.keysIteratorFrom(y)
+ * is equivalent to but often more efficient than
+ * x.from(y).keysIterator.
+ *
+ * @param start The lower bound (inclusive)
+ * on the keys to be returned
+ */
+ def keysIteratorFrom(start: K): Iterator[K]
+
+ /**
+ * Creates an iterator over all the values contained in this
+ * map that are associated with a key greater than or equal to `start`
+ * according to the ordering of this map. x.valuesIteratorFrom(y) is
+ * equivalent to but often more efficient than
+ * x.from(y).valuesIterator.
+ *
+ * @param start The lower bound (inclusive)
+ * on the keys to be returned
+ */
+ def valuesIteratorFrom(start: K): Iterator[V] = iteratorFrom(start).map(_._2)
+
+ def firstKey: K = head._1
+ def lastKey: K = last._1
+
+ /** Find the element with smallest key larger than or equal to a given key.
+ * @param key The given key.
+ * @return `None` if there is no such node.
+ */
+ def minAfter(key: K): Option[(K, V)] = rangeFrom(key).headOption
+
+ /** Find the element with largest key less than a given key.
+ * @param key The given key.
+ * @return `None` if there is no such node.
+ */
+ def maxBefore(key: K): Option[(K, V)] = rangeUntil(key).lastOption
+
+ def rangeTo(to: K): C = {
+ val i = keySet.rangeFrom(to).iterator
+ if (i.isEmpty) return coll
+ val next = i.next()
+ if (ordering.compare(next, to) == 0)
+ if (i.isEmpty) coll
+ else rangeUntil(i.next())
+ else
+ rangeUntil(next)
+ }
+
+ override def keySet: SortedSet[K] = new KeySortedSet
+
+ /** The implementation class of the set returned by `keySet` */
+ protected class KeySortedSet extends SortedSet[K] with GenKeySet with GenKeySortedSet {
+ def diff(that: Set[K]): SortedSet[K] = fromSpecific(view.filterNot(that))
+ def rangeImpl(from: Option[K], until: Option[K]): SortedSet[K] = {
+ val map = SortedMapOps.this.rangeImpl(from, until)
+ new map.KeySortedSet
+ }
+ }
+
+ /** A generic trait that is reused by sorted keyset implementations */
+ protected trait GenKeySortedSet extends GenKeySet { this: SortedSet[K] =>
+ implicit def ordering: Ordering[K] = SortedMapOps.this.ordering
+ def iteratorFrom(start: K): Iterator[K] = SortedMapOps.this.keysIteratorFrom(start)
+ }
+
+ // And finally, we add new overloads taking an ordering
+ /** Builds a new sorted map by applying a function to all elements of this $coll.
+ *
+ * @param f the function to apply to each element.
+ * @return a new $coll resulting from applying the given function
+ * `f` to each element of this $coll and collecting the results.
+ */
+ def map[K2, V2](f: ((K, V)) => (K2, V2))(implicit @implicitNotFound(SortedMapOps.ordMsg) ordering: Ordering[K2]): CC[K2, V2] =
+ sortedMapFactory.from(new View.Map[(K, V), (K2, V2)](this, f))
+
+ /** Builds a new sorted map by applying a function to all elements of this $coll
+ * and using the elements of the resulting collections.
+ *
+ * @param f the function to apply to each element.
+ * @return a new $coll resulting from applying the given collection-valued function
+ * `f` to each element of this $coll and concatenating the results.
+ */
+ def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)])(implicit @implicitNotFound(SortedMapOps.ordMsg) ordering: Ordering[K2]): CC[K2, V2] =
+ sortedMapFactory.from(new View.FlatMap(this, f))
+
+ /** Builds a new sorted map by applying a partial function to all elements of this $coll
+ * on which the function is defined.
+ *
+ * @param pf the partial function which filters and maps the $coll.
+ * @return a new $coll resulting from applying the given partial function
+ * `pf` to each element on which it is defined and collecting the results.
+ * The order of the elements is preserved.
+ */
+ def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)])(implicit @implicitNotFound(SortedMapOps.ordMsg) ordering: Ordering[K2]): CC[K2, V2] =
+ sortedMapFactory.from(new View.Collect(this, pf))
+
+ override def concat[V2 >: V](suffix: IterableOnce[(K, V2)]): CC[K, V2] = sortedMapFactory.from(suffix match {
+ case it: Iterable[(K, V2)] => new View.Concat(this, it)
+ case _ => iterator.concat(suffix.iterator)
+ })(using ordering)
+
+ /** Alias for `concat` */
+ @`inline` override final def ++ [V2 >: V](xs: IterableOnce[(K, V2)]): CC[K, V2] = concat(xs)
+
+ @deprecated("Consider requiring an immutable Map or fall back to Map.concat", "2.13.0")
+ override def + [V1 >: V](kv: (K, V1)): CC[K, V1] = sortedMapFactory.from(new View.Appended(this, kv))(using ordering)
+
+ @deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
+ override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): CC[K, V1] = sortedMapFactory.from(new View.Concat(new View.Appended(new View.Appended(this, elem1), elem2), elems))(using ordering)
+}
+
+object SortedMapOps {
+ private[collection] final val ordMsg = "No implicit Ordering[${K2}] found to build a SortedMap[${K2}, ${V2}]. You may want to upcast to a Map[${K}, ${V}] first by calling `unsorted`."
+
+ /** Specializes `MapWithFilter` for sorted Map collections
+ *
+ * @define coll sorted map collection
+ */
+ class WithFilter[K, +V, +IterableCC[_], +MapCC[X, Y] <: Map[X, Y], +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _]](
+ self: SortedMapOps[K, V, CC, _] with MapOps[K, V, MapCC, _] with IterableOps[(K, V), IterableCC, _],
+ p: ((K, V)) => Boolean
+ ) extends MapOps.WithFilter[K, V, IterableCC, MapCC](self, p) {
+
+ def map[K2 : Ordering, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] =
+ self.sortedMapFactory.from(new View.Map(filtered, f))
+
+ def flatMap[K2 : Ordering, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] =
+ self.sortedMapFactory.from(new View.FlatMap(filtered, f))
+
+ override def withFilter(q: ((K, V)) => Boolean): WithFilter[K, V, IterableCC, MapCC, CC] =
+ new WithFilter[K, V, IterableCC, MapCC, CC](self, (kv: (K, V)) => p(kv) && q(kv))
+
+ }
+
+}
+
+@SerialVersionUID(3L)
+object SortedMap extends SortedMapFactory.Delegate[SortedMap](immutable.SortedMap)
diff --git a/library/src/scala/collection/SortedOps.scala b/library/src/scala/collection/SortedOps.scala
new file mode 100644
index 000000000000..bd034fbf14d6
--- /dev/null
+++ b/library/src/scala/collection/SortedOps.scala
@@ -0,0 +1,90 @@
+/*
+ * 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
+
+
+/** Base trait for sorted collections */
+trait SortedOps[A, +C] {
+
+ def ordering: Ordering[A]
+
+ /** Returns the first key of the collection. */
+ def firstKey: A
+
+ /** Returns the last key of the collection. */
+ def lastKey: A
+
+ /** Comparison function that orders keys. */
+ @deprecated("Use ordering.compare instead", "2.13.0")
+ @deprecatedOverriding("Use ordering.compare instead", "2.13.0")
+ @inline def compare(k0: A, k1: A): Int = ordering.compare(k0, k1)
+
+ /** Creates a ranged projection of this collection. Any mutations in the
+ * ranged projection will update this collection and vice versa.
+ *
+ * Note: keys are not guaranteed to be consistent between this collection
+ * and the projection. This is the case for buffers where indexing is
+ * relative to the projection.
+ *
+ * @param from The lower-bound (inclusive) of the ranged projection.
+ * `None` if there is no lower bound.
+ * @param until The upper-bound (exclusive) of the ranged projection.
+ * `None` if there is no upper bound.
+ */
+ def rangeImpl(from: Option[A], until: Option[A]): C
+
+ /** Creates a ranged projection of this collection with both a lower-bound
+ * and an upper-bound.
+ *
+ * @param from The lower-bound (inclusive) of the ranged projection.
+ * @param until The upper-bound (exclusive) of the ranged projection.
+ */
+ def range(from: A, until: A): C = rangeImpl(Some(from), Some(until))
+
+ /** Creates a ranged projection of this collection with no upper-bound.
+ *
+ * @param from The lower-bound (inclusive) of the ranged projection.
+ */
+ @deprecated("Use rangeFrom", "2.13.0")
+ final def from(from: A): C = rangeFrom(from)
+
+ /** Creates a ranged projection of this collection with no upper-bound.
+ *
+ * @param from The lower-bound (inclusive) of the ranged projection.
+ */
+ def rangeFrom(from: A): C = rangeImpl(Some(from), None)
+
+ /** Creates a ranged projection of this collection with no lower-bound.
+ *
+ * @param until The upper-bound (exclusive) of the ranged projection.
+ */
+ @deprecated("Use rangeUntil", "2.13.0")
+ final def until(until: A): C = rangeUntil(until)
+
+ /** Creates a ranged projection of this collection with no lower-bound.
+ *
+ * @param until The upper-bound (exclusive) of the ranged projection.
+ */
+ def rangeUntil(until: A): C = rangeImpl(None, Some(until))
+
+ /** Create a range projection of this collection with no lower-bound.
+ * @param to The upper-bound (inclusive) of the ranged projection.
+ */
+ @deprecated("Use rangeTo", "2.13.0")
+ final def to(to: A): C = rangeTo(to)
+
+ /** Create a range projection of this collection with no lower-bound.
+ * @param to The upper-bound (inclusive) of the ranged projection.
+ */
+ def rangeTo(to: A): C
+}
diff --git a/library/src/scala/collection/SortedSet.scala b/library/src/scala/collection/SortedSet.scala
new file mode 100644
index 000000000000..7c655aad128a
--- /dev/null
+++ b/library/src/scala/collection/SortedSet.scala
@@ -0,0 +1,189 @@
+/*
+ * 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 scala.annotation.{implicitNotFound, nowarn}
+import scala.annotation.unchecked.uncheckedVariance
+
+/** Base type of sorted sets */
+trait SortedSet[A] extends Set[A]
+ with SortedSetOps[A, SortedSet, SortedSet[A]]
+ with SortedSetFactoryDefaults[A, SortedSet, Set] {
+
+ def unsorted: Set[A] = this
+
+ def sortedIterableFactory: SortedIterableFactory[SortedSet] = SortedSet
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix: String = "SortedSet"
+
+ override def equals(that: Any): Boolean = that match {
+ case _ if this eq that.asInstanceOf[AnyRef] => true
+ case ss: SortedSet[A @unchecked] if ss.ordering == this.ordering =>
+ (ss canEqual this) &&
+ (this.size == ss.size) && {
+ val i1 = this.iterator
+ val i2 = ss.iterator
+ var allEqual = true
+ while (allEqual && i1.hasNext)
+ allEqual = ordering.equiv(i1.next(), i2.next())
+ allEqual
+ }
+ case _ =>
+ super.equals(that)
+ }
+
+}
+
+trait SortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]]
+ extends SetOps[A, Set, C]
+ with SortedOps[A, C] {
+
+ /** The companion object of this sorted set, providing various factory methods.
+ *
+ * @note When implementing a custom collection type and refining `CC` to the new type, this
+ * method needs to be overridden to return a factory for the new type (the compiler will
+ * issue an error otherwise).
+ */
+ def sortedIterableFactory: SortedIterableFactory[CC]
+
+ def unsorted: Set[A]
+
+ /**
+ * Creates an iterator that contains all values from this collection
+ * greater than or equal to `start` according to the ordering of
+ * this collection. x.iteratorFrom(y) is equivalent to but will usually
+ * be more efficient than x.from(y).iterator
+ *
+ * @param start The lower-bound (inclusive) of the iterator
+ */
+ def iteratorFrom(start: A): Iterator[A]
+
+ @deprecated("Use `iteratorFrom` instead.", "2.13.0")
+ @`inline` def keysIteratorFrom(start: A): Iterator[A] = iteratorFrom(start)
+
+ def firstKey: A = head
+ def lastKey: A = last
+
+ /** Find the smallest element larger than or equal to a given key.
+ * @param key The given key.
+ * @return `None` if there is no such node.
+ */
+ def minAfter(key: A): Option[A] = rangeFrom(key).headOption
+
+ /** Find the largest element less than a given key.
+ * @param key The given key.
+ * @return `None` if there is no such node.
+ */
+ def maxBefore(key: A): Option[A] = rangeUntil(key).lastOption
+
+ override def min[B >: A](implicit ord: Ordering[B]): A =
+ if (isEmpty) throw new UnsupportedOperationException("empty.min")
+ else if (ord == ordering) head
+ else if (ord isReverseOf ordering) last
+ else super.min[B] // need the type annotation for it to infer the correct implicit
+
+ override def max[B >: A](implicit ord: Ordering[B]): A =
+ if (isEmpty) throw new UnsupportedOperationException("empty.max")
+ else if (ord == ordering) last
+ else if (ord isReverseOf ordering) head
+ else super.max[B] // need the type annotation for it to infer the correct implicit
+
+ def rangeTo(to: A): C = {
+ val i = rangeFrom(to).iterator
+ if (i.isEmpty) return coll
+ val next = i.next()
+ if (ordering.compare(next, to) == 0)
+ if (i.isEmpty) coll
+ else rangeUntil(i.next())
+ else
+ rangeUntil(next)
+ }
+
+ /** Builds a new sorted collection by applying a function to all elements of this $coll.
+ *
+ * @param f the function to apply to each element.
+ * @tparam B the element type of the returned collection.
+ * @return a new $coll resulting from applying the given function
+ * `f` to each element of this $coll and collecting the results.
+ */
+ def map[B](f: A => B)(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] =
+ sortedIterableFactory.from(new View.Map(this, f))
+
+ /** Builds a new sorted collection by applying a function to all elements of this $coll
+ * and using the elements of the resulting collections.
+ *
+ * @param f the function to apply to each element.
+ * @tparam B the element type of the returned collection.
+ * @return a new $coll resulting from applying the given collection-valued function
+ * `f` to each element of this $coll and concatenating the results.
+ */
+ def flatMap[B](f: A => IterableOnce[B])(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] =
+ sortedIterableFactory.from(new View.FlatMap(this, f))
+
+ /** Returns a $coll formed from this $coll and another iterable collection
+ * by combining corresponding elements in pairs.
+ * If one of the two collections is longer than the other, its remaining elements are ignored.
+ *
+ * @param that The iterable providing the second half of each result pair
+ * @tparam B the type of the second half of the returned pairs
+ * @return a new $coll containing pairs consisting of corresponding elements of this $coll and `that`.
+ * The length of the returned collection is the minimum of the lengths of this $coll and `that`.
+ */
+ def zip[B](that: IterableOnce[B])(implicit @implicitNotFound(SortedSetOps.zipOrdMsg) ev: Ordering[(A @uncheckedVariance, B)]): CC[(A @uncheckedVariance, B)] = // sound bcs of VarianceNote
+ sortedIterableFactory.from(that match {
+ case that: Iterable[B] => new View.Zip(this, that)
+ case _ => iterator.zip(that)
+ })
+
+ /** Builds a new sorted collection by applying a partial function to all elements of this $coll
+ * on which the function is defined.
+ *
+ * @param pf the partial function which filters and maps the $coll.
+ * @tparam B the element type of the returned collection.
+ * @return a new $coll resulting from applying the given partial function
+ * `pf` to each element on which it is defined and collecting the results.
+ * The order of the elements is preserved.
+ */
+ def collect[B](pf: scala.PartialFunction[A, B])(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] =
+ sortedIterableFactory.from(new View.Collect(this, pf))
+}
+
+object SortedSetOps {
+ private[collection] final val ordMsg = "No implicit Ordering[${B}] found to build a SortedSet[${B}]. You may want to upcast to a Set[${A}] first by calling `unsorted`."
+ private[collection] final val zipOrdMsg = "No implicit Ordering[${B}] found to build a SortedSet[(${A}, ${B})]. You may want to upcast to a Set[${A}] first by calling `unsorted`."
+
+ /** Specialize `WithFilter` for sorted collections
+ *
+ * @define coll sorted collection
+ */
+ class WithFilter[+A, +IterableCC[_], +CC[X] <: SortedSet[X]](
+ self: SortedSetOps[A, CC, _] with IterableOps[A, IterableCC, _],
+ p: A => Boolean
+ ) extends IterableOps.WithFilter[A, IterableCC](self, p) {
+
+ def map[B : Ordering](f: A => B): CC[B] =
+ self.sortedIterableFactory.from(new View.Map(filtered, f))
+
+ def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] =
+ self.sortedIterableFactory.from(new View.FlatMap(filtered, f))
+
+ override def withFilter(q: A => Boolean): WithFilter[A, IterableCC, CC] =
+ new WithFilter[A, IterableCC, CC](self, (a: A) => p(a) && q(a))
+ }
+
+}
+
+@SerialVersionUID(3L)
+object SortedSet extends SortedIterableFactory.Delegate[SortedSet](immutable.SortedSet)
+
diff --git a/library/src/scala/collection/Stepper.scala b/library/src/scala/collection/Stepper.scala
new file mode 100644
index 000000000000..f1355e8182c3
--- /dev/null
+++ b/library/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())) }
+ }
+ }
+}
diff --git a/library/src/scala/collection/StepperShape.scala b/library/src/scala/collection/StepperShape.scala
new file mode 100644
index 000000000000..db8c00b47992
--- /dev/null
+++ b/library/src/scala/collection/StepperShape.scala
@@ -0,0 +1,114 @@
+/*
+ * 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.{lang => jl}
+
+import scala.collection.Stepper.EfficientSplit
+
+/** An implicit StepperShape instance is used in the [[IterableOnce.stepper]] to return a possibly
+ * specialized Stepper `S` according to the element type `T`.
+ */
+sealed trait StepperShape[-T, S <: Stepper[_]] {
+ /** Return the Int constant (as defined in the `StepperShape` companion object) for this `StepperShape`. */
+ def shape: StepperShape.Shape
+
+ /** Create an unboxing primitive sequential Stepper from a boxed `AnyStepper`.
+ * This is an identity operation for reference shapes. */
+ def seqUnbox(st: AnyStepper[T]): S
+
+ /** Create an unboxing primitive parallel (i.e. `with EfficientSplit`) Stepper from a boxed `AnyStepper`.
+ * This is an identity operation for reference shapes. */
+ def parUnbox(st: AnyStepper[T] with EfficientSplit): S with EfficientSplit
+}
+
+object StepperShape extends StepperShapeLowPriority1 {
+ class Shape private[StepperShape] (private val s: Int) extends AnyVal
+
+ // reference
+ val ReferenceShape = new Shape(0)
+
+ // primitive
+ val IntShape = new Shape(1)
+ val LongShape = new Shape(2)
+ val DoubleShape = new Shape(3)
+
+ // widening
+ val ByteShape = new Shape(4)
+ val ShortShape = new Shape(5)
+ val CharShape = new Shape(6)
+ val FloatShape = new Shape(7)
+
+ implicit val intStepperShape: StepperShape[Int, IntStepper] = new StepperShape[Int, IntStepper] {
+ def shape = IntShape
+ def seqUnbox(st: AnyStepper[Int]): IntStepper = new Stepper.UnboxingIntStepper(st)
+ def parUnbox(st: AnyStepper[Int] with EfficientSplit): IntStepper with EfficientSplit = new Stepper.UnboxingIntStepper(st) with EfficientSplit
+ }
+ implicit val jIntegerStepperShape: StepperShape[jl.Integer, IntStepper] = intStepperShape.asInstanceOf[StepperShape[jl.Integer, IntStepper]]
+
+ implicit val longStepperShape: StepperShape[Long, LongStepper] = new StepperShape[Long, LongStepper] {
+ def shape = LongShape
+ def seqUnbox(st: AnyStepper[Long]): LongStepper = new Stepper.UnboxingLongStepper(st)
+ def parUnbox(st: AnyStepper[Long] with EfficientSplit): LongStepper with EfficientSplit = new Stepper.UnboxingLongStepper(st) with EfficientSplit
+ }
+ implicit val jLongStepperShape: StepperShape[jl.Long, LongStepper] = longStepperShape.asInstanceOf[StepperShape[jl.Long, LongStepper]]
+
+ implicit val doubleStepperShape: StepperShape[Double, DoubleStepper] = new StepperShape[Double, DoubleStepper] {
+ def shape = DoubleShape
+ def seqUnbox(st: AnyStepper[Double]): DoubleStepper = new Stepper.UnboxingDoubleStepper(st)
+ def parUnbox(st: AnyStepper[Double] with EfficientSplit): DoubleStepper with EfficientSplit = new Stepper.UnboxingDoubleStepper(st) with EfficientSplit
+ }
+ implicit val jDoubleStepperShape: StepperShape[jl.Double, DoubleStepper] = doubleStepperShape.asInstanceOf[StepperShape[jl.Double, DoubleStepper]]
+
+ implicit val byteStepperShape: StepperShape[Byte, IntStepper] = new StepperShape[Byte, IntStepper] {
+ def shape = ByteShape
+ def seqUnbox(st: AnyStepper[Byte]): IntStepper = new Stepper.UnboxingByteStepper(st)
+ def parUnbox(st: AnyStepper[Byte] with EfficientSplit): IntStepper with EfficientSplit = new Stepper.UnboxingByteStepper(st) with EfficientSplit
+ }
+ implicit val jByteStepperShape: StepperShape[jl.Byte, IntStepper] = byteStepperShape.asInstanceOf[StepperShape[jl.Byte, IntStepper]]
+
+ implicit val shortStepperShape: StepperShape[Short, IntStepper] = new StepperShape[Short, IntStepper] {
+ def shape = ShortShape
+ def seqUnbox(st: AnyStepper[Short]): IntStepper = new Stepper.UnboxingShortStepper(st)
+ def parUnbox(st: AnyStepper[Short] with EfficientSplit): IntStepper with EfficientSplit = new Stepper.UnboxingShortStepper(st) with EfficientSplit
+ }
+ implicit val jShortStepperShape: StepperShape[jl.Short, IntStepper] = shortStepperShape.asInstanceOf[StepperShape[jl.Short, IntStepper]]
+
+ implicit val charStepperShape: StepperShape[Char, IntStepper] = new StepperShape[Char, IntStepper] {
+ def shape = CharShape
+ def seqUnbox(st: AnyStepper[Char]): IntStepper = new Stepper.UnboxingCharStepper(st)
+ def parUnbox(st: AnyStepper[Char] with EfficientSplit): IntStepper with EfficientSplit = new Stepper.UnboxingCharStepper(st) with EfficientSplit
+ }
+ implicit val jCharacterStepperShape: StepperShape[jl.Character, IntStepper] = charStepperShape.asInstanceOf[StepperShape[jl.Character, IntStepper]]
+
+ implicit val floatStepperShape: StepperShape[Float, DoubleStepper] = new StepperShape[Float, DoubleStepper] {
+ def shape = FloatShape
+ def seqUnbox(st: AnyStepper[Float]): DoubleStepper = new Stepper.UnboxingFloatStepper(st)
+ def parUnbox(st: AnyStepper[Float] with EfficientSplit): DoubleStepper with EfficientSplit = new Stepper.UnboxingFloatStepper(st) with EfficientSplit
+ }
+ implicit val jFloatStepperShape: StepperShape[jl.Float, DoubleStepper] = floatStepperShape.asInstanceOf[StepperShape[jl.Float, DoubleStepper]]
+}
+
+trait StepperShapeLowPriority1 extends StepperShapeLowPriority2 {
+ implicit def anyStepperShape[T]: StepperShape[T, AnyStepper[T]] = anyStepperShapePrototype.asInstanceOf[StepperShape[T, AnyStepper[T]]]
+}
+
+trait StepperShapeLowPriority2 {
+ implicit def baseStepperShape[T]: StepperShape[T, Stepper[T]] = anyStepperShapePrototype.asInstanceOf[StepperShape[T, Stepper[T]]]
+
+ protected val anyStepperShapePrototype: StepperShape[AnyRef, Stepper[AnyRef]] = new StepperShape[AnyRef, Stepper[AnyRef]] {
+ def shape = StepperShape.ReferenceShape
+ def seqUnbox(st: AnyStepper[AnyRef]): Stepper[AnyRef] = st
+ def parUnbox(st: AnyStepper[AnyRef] with EfficientSplit): Stepper[AnyRef] with EfficientSplit = st
+ }
+}
\ No newline at end of file
diff --git a/library/src/scala/collection/StrictOptimizedIterableOps.scala b/library/src/scala/collection/StrictOptimizedIterableOps.scala
new file mode 100644
index 000000000000..3260c1bc262e
--- /dev/null
+++ b/library/src/scala/collection/StrictOptimizedIterableOps.scala
@@ -0,0 +1,284 @@
+/*
+ * 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 collection
+
+import scala.annotation.nowarn
+import scala.annotation.unchecked.uncheckedVariance
+import scala.runtime.Statics
+
+/**
+ * Trait that overrides iterable operations to take advantage of strict builders.
+ *
+ * @tparam A Elements type
+ * @tparam CC Collection type constructor
+ * @tparam C Collection type
+ */
+trait StrictOptimizedIterableOps[+A, +CC[_], +C]
+ extends Any
+ with IterableOps[A, CC, C] {
+
+ // Optimized, push-based version of `partition`
+ override def partition(p: A => Boolean): (C, C) = {
+ val l, r = newSpecificBuilder
+ iterator.foreach(x => (if (p(x)) l else r) += x)
+ (l.result(), r.result())
+ }
+
+ override def span(p: A => Boolean): (C, C) = {
+ val first = newSpecificBuilder
+ val second = newSpecificBuilder
+ val it = iterator
+ var inFirst = true
+ while (it.hasNext && inFirst) {
+ val a = it.next()
+ if (p(a)) {
+ first += a
+ } else {
+ second += a
+ inFirst = false
+ }
+ }
+ while (it.hasNext) {
+ second += it.next()
+ }
+ (first.result(), second.result())
+ }
+
+ override def unzip[A1, A2](implicit asPair: A => (A1, A2)): (CC[A1], CC[A2]) = {
+ val first = iterableFactory.newBuilder[A1]
+ val second = iterableFactory.newBuilder[A2]
+ foreach { a =>
+ val pair = asPair(a)
+ first += pair._1
+ second += pair._2
+ }
+ (first.result(), second.result())
+ }
+
+ override def unzip3[A1, A2, A3](implicit asTriple: A => (A1, A2, A3)): (CC[A1], CC[A2], CC[A3]) = {
+ val b1 = iterableFactory.newBuilder[A1]
+ val b2 = iterableFactory.newBuilder[A2]
+ val b3 = iterableFactory.newBuilder[A3]
+
+ foreach { xyz =>
+ val triple = asTriple(xyz)
+ b1 += triple._1
+ b2 += triple._2
+ b3 += triple._3
+ }
+ (b1.result(), b2.result(), b3.result())
+ }
+
+ // The implementations of the following operations are not fundamentally different from
+ // the view-based implementations, but they turn out to be slightly faster because
+ // a couple of indirection levels are removed
+
+ override def map[B](f: A => B): CC[B] =
+ strictOptimizedMap(iterableFactory.newBuilder, f)
+
+ /**
+ * @param b Builder to use to build the resulting collection
+ * @param f Element transformation function
+ * @tparam B Type of elements of the resulting collection (e.g. `String`)
+ * @tparam C2 Type of the resulting collection (e.g. `List[String]`)
+ * @return The resulting collection
+ */
+ @inline protected[this] final def strictOptimizedMap[B, C2](b: mutable.Builder[B, C2], f: A => B): C2 = {
+ val it = iterator
+ while (it.hasNext) {
+ b += f(it.next())
+ }
+ b.result()
+ }
+
+ override def flatMap[B](f: A => IterableOnce[B]): CC[B] =
+ strictOptimizedFlatMap(iterableFactory.newBuilder, f)
+
+ /**
+ * @param b Builder to use to build the resulting collection
+ * @param f Element transformation function
+ * @tparam B Type of elements of the resulting collection (e.g. `String`)
+ * @tparam C2 Type of the resulting collection (e.g. `List[String]`)
+ * @return The resulting collection
+ */
+ @inline protected[this] final def strictOptimizedFlatMap[B, C2](b: mutable.Builder[B, C2], f: A => IterableOnce[B]): C2 = {
+ val it = iterator
+ while (it.hasNext) {
+ b ++= f(it.next())
+ }
+ b.result()
+ }
+
+ /**
+ * @param that Elements to concatenate to this collection
+ * @param b Builder to use to build the resulting collection
+ * @tparam B Type of elements of the resulting collections (e.g. `Int`)
+ * @tparam C2 Type of the resulting collection (e.g. `List[Int]`)
+ * @return The resulting collection
+ */
+ @inline protected[this] final def strictOptimizedConcat[B >: A, C2](that: IterableOnce[B], b: mutable.Builder[B, C2]): C2 = {
+ b ++= this
+ b ++= that
+ b.result()
+ }
+
+ override def collect[B](pf: PartialFunction[A, B]): CC[B] =
+ strictOptimizedCollect(iterableFactory.newBuilder, pf)
+
+ /**
+ * @param b Builder to use to build the resulting collection
+ * @param pf Element transformation partial function
+ * @tparam B Type of elements of the resulting collection (e.g. `String`)
+ * @tparam C2 Type of the resulting collection (e.g. `List[String]`)
+ * @return The resulting collection
+ */
+ @inline protected[this] final def strictOptimizedCollect[B, C2](b: mutable.Builder[B, C2], pf: PartialFunction[A, B]): C2 = {
+ val marker = Statics.pfMarker
+ val it = iterator
+ while (it.hasNext) {
+ val elem = it.next()
+ val v = pf.applyOrElse(elem, ((x: A) => marker).asInstanceOf[Function[A, B]])
+ if (marker ne v.asInstanceOf[AnyRef]) b += v
+ }
+ b.result()
+ }
+
+ override def flatten[B](implicit toIterableOnce: A => IterableOnce[B]): CC[B] =
+ strictOptimizedFlatten(iterableFactory.newBuilder)
+
+ /**
+ * @param b Builder to use to build the resulting collection
+ * @param toIterableOnce Evidence that `A` can be seen as an `IterableOnce[B]`
+ * @tparam B Type of elements of the resulting collection (e.g. `Int`)
+ * @tparam C2 Type of the resulting collection (e.g. `List[Int]`)
+ * @return The resulting collection
+ */
+ @inline protected[this] final def strictOptimizedFlatten[B, C2](b: mutable.Builder[B, C2])(implicit toIterableOnce: A => IterableOnce[B]): C2 = {
+ val it = iterator
+ while (it.hasNext) {
+ b ++= toIterableOnce(it.next())
+ }
+ b.result()
+ }
+
+ override def zip[B](that: IterableOnce[B]): CC[(A @uncheckedVariance, B)] =
+ strictOptimizedZip(that, iterableFactory.newBuilder[(A, B)])
+
+ /**
+ * @param that Collection to zip with this collection
+ * @param b Builder to use to build the resulting collection
+ * @tparam B Type of elements of the second collection (e.g. `String`)
+ * @tparam C2 Type of the resulting collection (e.g. `List[(Int, String)]`)
+ * @return The resulting collection
+ */
+ @inline protected[this] final def strictOptimizedZip[B, C2](that: IterableOnce[B], b: mutable.Builder[(A, B), C2]): C2 = {
+ val it1 = iterator
+ val it2 = that.iterator
+ while (it1.hasNext && it2.hasNext) {
+ b += ((it1.next(), it2.next()))
+ }
+ b.result()
+ }
+
+ override def zipWithIndex: CC[(A @uncheckedVariance, Int)] = {
+ val b = iterableFactory.newBuilder[(A, Int)]
+ var i = 0
+ val it = iterator
+ while (it.hasNext) {
+ b += ((it.next(), i))
+ i += 1
+ }
+ b.result()
+ }
+
+ override def scanLeft[B](z: B)(op: (B, A) => B): CC[B] = {
+ val b = iterableFactory.newBuilder[B]
+ b.sizeHint(this, delta = 0)
+ var acc = z
+ b += acc
+ val it = iterator
+ while (it.hasNext) {
+ acc = op(acc, it.next())
+ b += acc
+ }
+ b.result()
+ }
+
+ override def filter(pred: A => Boolean): C = filterImpl(pred, isFlipped = false)
+
+ override def filterNot(pred: A => Boolean): C = filterImpl(pred, isFlipped = true)
+
+ protected[collection] def filterImpl(pred: A => Boolean, isFlipped: Boolean): C = {
+ val b = newSpecificBuilder
+ val it = iterator
+ while (it.hasNext) {
+ val elem = it.next()
+ if (pred(elem) != isFlipped) {
+ b += elem
+ }
+ }
+ b.result()
+ }
+
+ // Optimized, push-based version of `partitionMap`
+ override def partitionMap[A1, A2](f: A => Either[A1, A2]): (CC[A1], CC[A2]) = {
+ val l = iterableFactory.newBuilder[A1]
+ val r = iterableFactory.newBuilder[A2]
+ foreach { x =>
+ f(x) match {
+ case Left(x1) => l += x1
+ case Right(x2) => r += x2
+ }
+ }
+ (l.result(), r.result())
+ }
+
+ // Optimization avoids creation of second collection
+ override def tapEach[U](f: A => U): C = {
+ foreach(f)
+ coll
+ }
+
+ /** A collection containing the last `n` elements of this collection.
+ * $willForceEvaluation
+ */
+ override def takeRight(n: Int): C = {
+ val b = newSpecificBuilder
+ b.sizeHintBounded(n, toIterable: @nowarn("cat=deprecation"))
+ val lead = iterator drop n
+ val it = iterator
+ while (lead.hasNext) {
+ lead.next()
+ it.next()
+ }
+ while (it.hasNext) b += it.next()
+ b.result()
+ }
+
+ /** The rest of the collection without its `n` last elements. For
+ * linear, immutable collections this should avoid making a copy.
+ * $willForceEvaluation
+ */
+ override def dropRight(n: Int): C = {
+ val b = newSpecificBuilder
+ if (n >= 0) b.sizeHint(this, delta = -n)
+ val lead = iterator drop n
+ val it = iterator
+ while (lead.hasNext) {
+ b += it.next()
+ lead.next()
+ }
+ b.result()
+ }
+}
diff --git a/library/src/scala/collection/StrictOptimizedMapOps.scala b/library/src/scala/collection/StrictOptimizedMapOps.scala
new file mode 100644
index 000000000000..a87ba3ee9e20
--- /dev/null
+++ b/library/src/scala/collection/StrictOptimizedMapOps.scala
@@ -0,0 +1,48 @@
+/*
+ * 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
+
+/**
+ * Trait that overrides map operations to take advantage of strict builders.
+ *
+ * @tparam K Type of keys
+ * @tparam V Type of values
+ * @tparam CC Collection type constructor
+ * @tparam C Collection type
+ */
+trait StrictOptimizedMapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C]
+ extends MapOps[K, V, CC, C]
+ with StrictOptimizedIterableOps[(K, V), Iterable, C] {
+
+ override def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] =
+ strictOptimizedMap(mapFactory.newBuilder, f)
+
+ override def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] =
+ strictOptimizedFlatMap(mapFactory.newBuilder, f)
+
+ override def concat[V2 >: V](suffix: IterableOnce[(K, V2)]): CC[K, V2] =
+ strictOptimizedConcat(suffix, mapFactory.newBuilder)
+
+ override def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)]): CC[K2, V2] =
+ strictOptimizedCollect(mapFactory.newBuilder, pf)
+
+ @deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
+ override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): CC[K, V1] = {
+ val b = mapFactory.newBuilder[K, V1]
+ b ++= this
+ b += elem1
+ b += elem2
+ if (elems.nonEmpty) b ++= elems
+ b.result()
+ }
+}
diff --git a/library/src/scala/collection/StrictOptimizedSeqOps.scala b/library/src/scala/collection/StrictOptimizedSeqOps.scala
new file mode 100644
index 000000000000..a131498d8b28
--- /dev/null
+++ b/library/src/scala/collection/StrictOptimizedSeqOps.scala
@@ -0,0 +1,108 @@
+/*
+ * 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
+
+/**
+ * Trait that overrides operations on sequences in order
+ * to take advantage of strict builders.
+ */
+trait StrictOptimizedSeqOps [+A, +CC[_], +C]
+ extends Any
+ with SeqOps[A, CC, C]
+ with StrictOptimizedIterableOps[A, CC, C] {
+
+ override def distinctBy[B](f: A => B): C = {
+ val builder = newSpecificBuilder
+ val seen = mutable.HashSet.empty[B]
+ val it = this.iterator
+ while (it.hasNext) {
+ val next = it.next()
+ if (seen.add(f(next))) builder += next
+ }
+ builder.result()
+ }
+
+ override def prepended[B >: A](elem: B): CC[B] = {
+ val b = iterableFactory.newBuilder[B]
+ b.sizeHint(this, delta = 1)
+ b += elem
+ b ++= this
+ b.result()
+ }
+
+ override def appended[B >: A](elem: B): CC[B] = {
+ val b = iterableFactory.newBuilder[B]
+ b.sizeHint(this, delta = 1)
+ b ++= this
+ b += elem
+ b.result()
+ }
+
+ override def appendedAll[B >: A](suffix: IterableOnce[B]): CC[B] =
+ strictOptimizedConcat(suffix, iterableFactory.newBuilder)
+
+ override def prependedAll[B >: A](prefix: IterableOnce[B]): CC[B] = {
+ val b = iterableFactory.newBuilder[B]
+ b ++= prefix
+ b ++= this
+ b.result()
+ }
+
+ override def padTo[B >: A](len: Int, elem: B): CC[B] = {
+ val b = iterableFactory.newBuilder[B]
+ val L = size
+ b.sizeHint(math.max(L, len))
+ var diff = len - L
+ b ++= this
+ while (diff > 0) {
+ b += elem
+ diff -= 1
+ }
+ b.result()
+ }
+
+ override def diff[B >: A](that: Seq[B]): C =
+ if (isEmpty || that.isEmpty) coll
+ else {
+ val occ = occCounts(that)
+ val b = newSpecificBuilder
+ for (x <- this) {
+ occ.updateWith(x) {
+ case None => {
+ b.addOne(x)
+ None
+ }
+ case Some(1) => None
+ case Some(n) => Some(n - 1)
+ }
+ }
+ b.result()
+ }
+
+ override def intersect[B >: A](that: Seq[B]): C =
+ if (isEmpty || that.isEmpty) empty
+ else {
+ val occ = occCounts(that)
+ val b = newSpecificBuilder
+ for (x <- this) {
+ occ.updateWith(x) {
+ case None => None
+ case Some(n) => {
+ b.addOne(x)
+ if (n == 1) None else Some(n - 1)
+ }
+ }
+ }
+ b.result()
+ }
+}
diff --git a/library/src/scala/collection/StrictOptimizedSetOps.scala b/library/src/scala/collection/StrictOptimizedSetOps.scala
new file mode 100644
index 000000000000..39e585324f45
--- /dev/null
+++ b/library/src/scala/collection/StrictOptimizedSetOps.scala
@@ -0,0 +1,29 @@
+/*
+ * 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
+
+/**
+ * Trait that overrides set operations to take advantage of strict builders.
+ *
+ * @tparam A Elements type
+ * @tparam CC Collection type constructor
+ * @tparam C Collection type
+ */
+trait StrictOptimizedSetOps[A, +CC[_], +C <: SetOps[A, CC, C]]
+ extends SetOps[A, CC, C]
+ with StrictOptimizedIterableOps[A, CC, C] {
+
+ override def concat(that: IterableOnce[A]): C =
+ strictOptimizedConcat(that, newSpecificBuilder)
+
+}
diff --git a/library/src/scala/collection/StrictOptimizedSortedMapOps.scala b/library/src/scala/collection/StrictOptimizedSortedMapOps.scala
new file mode 100644
index 000000000000..8317913c6d1b
--- /dev/null
+++ b/library/src/scala/collection/StrictOptimizedSortedMapOps.scala
@@ -0,0 +1,46 @@
+/*
+ * 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 scala.annotation.implicitNotFound
+
+/**
+ * Trait that overrides sorted map operations to take advantage of strict builders.
+ *
+ * @tparam K Type of keys
+ * @tparam V Type of values
+ * @tparam CC Collection type constructor
+ * @tparam C Collection type
+ */
+trait StrictOptimizedSortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], +C <: SortedMapOps[K, V, CC, C]]
+ extends SortedMapOps[K, V, CC, C]
+ with StrictOptimizedMapOps[K, V, Map, C] {
+
+ override def map[K2, V2](f: ((K, V)) => (K2, V2))(implicit @implicitNotFound(SortedMapOps.ordMsg) ordering: Ordering[K2]): CC[K2, V2] =
+ strictOptimizedMap(sortedMapFactory.newBuilder, f)
+
+ override def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)])(implicit @implicitNotFound(SortedMapOps.ordMsg) ordering: Ordering[K2]): CC[K2, V2] =
+ strictOptimizedFlatMap(sortedMapFactory.newBuilder, f)
+
+ override def concat[V2 >: V](xs: IterableOnce[(K, V2)]): CC[K, V2] =
+ strictOptimizedConcat(xs, sortedMapFactory.newBuilder(using ordering))
+
+ override def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)])(implicit @implicitNotFound(SortedMapOps.ordMsg) ordering: Ordering[K2]): CC[K2, V2] =
+ strictOptimizedCollect(sortedMapFactory.newBuilder, pf)
+
+ @deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
+ override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): CC[K, V1] = {
+ val m = ((this + elem1).asInstanceOf[Map[K, V]] + elem2).asInstanceOf[CC[K, V1]]
+ if(elems.isEmpty) m else m.concat(elems).asInstanceOf[CC[K, V1]]
+ }
+}
diff --git a/library/src/scala/collection/StrictOptimizedSortedSetOps.scala b/library/src/scala/collection/StrictOptimizedSortedSetOps.scala
new file mode 100644
index 000000000000..c01b0d8466f3
--- /dev/null
+++ b/library/src/scala/collection/StrictOptimizedSortedSetOps.scala
@@ -0,0 +1,42 @@
+/*
+ * 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 collection
+
+import scala.annotation.implicitNotFound
+import scala.annotation.unchecked.uncheckedVariance
+
+/**
+ * Trait that overrides sorted set operations to take advantage of strict builders.
+ *
+ * @tparam A Elements type
+ * @tparam CC Collection type constructor
+ * @tparam C Collection type
+ */
+trait StrictOptimizedSortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]]
+ extends SortedSetOps[A, CC, C]
+ with StrictOptimizedSetOps[A, Set, C] {
+
+ override def map[B](f: A => B)(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] =
+ strictOptimizedMap(sortedIterableFactory.newBuilder, f)
+
+ override def flatMap[B](f: A => IterableOnce[B])(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] =
+ strictOptimizedFlatMap(sortedIterableFactory.newBuilder, f)
+
+ override def zip[B](that: IterableOnce[B])(implicit @implicitNotFound(SortedSetOps.zipOrdMsg) ev: Ordering[(A @uncheckedVariance, B)]): CC[(A @uncheckedVariance, B)] =
+ strictOptimizedZip(that, sortedIterableFactory.newBuilder[(A, B)])
+
+ override def collect[B](pf: PartialFunction[A, B])(implicit @implicitNotFound(SortedSetOps.ordMsg) ev: Ordering[B]): CC[B] =
+ strictOptimizedCollect(sortedIterableFactory.newBuilder, pf)
+
+}
diff --git a/library/src/scala/collection/StringOps.scala b/library/src/scala/collection/StringOps.scala
new file mode 100644
index 000000000000..169a646d12fa
--- /dev/null
+++ b/library/src/scala/collection/StringOps.scala
@@ -0,0 +1,1653 @@
+/*
+ * 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 collection
+
+import java.lang.{StringBuilder => JStringBuilder}
+
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.convert.impl.{CharStringStepper, CodePointStringStepper}
+import scala.collection.immutable.{ArraySeq, WrappedString}
+import scala.collection.mutable.StringBuilder
+import scala.math.{ScalaNumber, max, min}
+import scala.reflect.ClassTag
+import scala.util.matching.Regex
+
+object StringOps {
+ // just statics for companion class.
+ private final val LF = 0x0A
+ private final val FF = 0x0C
+ private final val CR = 0x0D
+ private final val SU = 0x1A
+
+ private class StringIterator(private[this] val s: String) extends AbstractIterator[Char] {
+ private[this] var pos = 0
+ def hasNext: Boolean = pos < s.length
+ def next(): Char = {
+ if (pos >= s.length) Iterator.empty.next()
+ val r = s.charAt(pos)
+ pos += 1
+ r
+ }
+ }
+
+ private class ReverseIterator(private[this] val s: String) extends AbstractIterator[Char] {
+ private[this] var pos = s.length-1
+ def hasNext: Boolean = pos >= 0
+ def next(): Char = {
+ if (pos < 0) Iterator.empty.next()
+ val r = s.charAt(pos)
+ pos -= 1
+ r
+ }
+ }
+
+ private class GroupedIterator(s: String, groupSize: Int) extends AbstractIterator[String] {
+ private[this] var pos = 0
+ def hasNext: Boolean = pos < s.length
+ def next(): String = {
+ if(pos >= s.length) Iterator.empty.next()
+ val r = s.slice(pos, pos+groupSize)
+ pos += groupSize
+ r
+ }
+ }
+
+ /** A lazy filtered string. No filtering is applied until one of `foreach`, `map` or `flatMap` is called. */
+ class WithFilter(p: Char => Boolean, s: String) {
+
+ /** Apply `f` to each element for its side effects.
+ * Note: [U] parameter needed to help scalac's type inference.
+ */
+ def foreach[U](f: Char => U): Unit = {
+ val len = s.length
+ var i = 0
+ while(i < len) {
+ val x = s.charAt(i)
+ if(p(x)) f(x)
+ i += 1
+ }
+ }
+
+ /** Builds a new collection by applying a function to all chars of this filtered string.
+ *
+ * @param f the function to apply to each char.
+ * @return a new collection resulting from applying the given function
+ * `f` to each char of this string and collecting the results.
+ */
+ def map[B](f: Char => B): immutable.IndexedSeq[B] = {
+ val len = s.length
+ val b = immutable.IndexedSeq.newBuilder[B]
+ b.sizeHint(len)
+ var i = 0
+ while (i < len) {
+ val x = s.charAt(i)
+ if(p(x)) b.addOne(f(x))
+ i += 1
+ }
+ b.result()
+ }
+
+ /** Builds a new string by applying a function to all chars of this filtered string.
+ *
+ * @param f the function to apply to each char.
+ * @return a new string resulting from applying the given function
+ * `f` to each char of this string and collecting the results.
+ */
+ def map(f: Char => Char): String = {
+ val len = s.length
+ val sb = new JStringBuilder(len)
+ var i = 0
+ while (i < len) {
+ val x = s.charAt(i)
+ if(p(x)) sb.append(f(x))
+ i += 1
+ }
+ sb.toString
+ }
+
+ /** Builds a new collection by applying a function to all chars of this filtered string
+ * and using the elements of the resulting collections.
+ *
+ * @param f the function to apply to each char.
+ * @return a new collection resulting from applying the given collection-valued function
+ * `f` to each char of this string and concatenating the results.
+ */
+ def flatMap[B](f: Char => IterableOnce[B]): immutable.IndexedSeq[B] = {
+ val len = s.length
+ val b = immutable.IndexedSeq.newBuilder[B]
+ var i = 0
+ while (i < len) {
+ val x = s.charAt(i)
+ if(p(x)) b.addAll(f(x))
+ i += 1
+ }
+ b.result()
+ }
+
+ /** Builds a new string by applying a function to all chars of this filtered string
+ * and using the elements of the resulting Strings.
+ *
+ * @param f the function to apply to each char.
+ * @return a new string resulting from applying the given string-valued function
+ * `f` to each char of this string and concatenating the results.
+ */
+ def flatMap(f: Char => String): String = {
+ val len = s.length
+ val sb = new JStringBuilder
+ var i = 0
+ while (i < len) {
+ val x = s.charAt(i)
+ if(p(x)) sb.append(f(x))
+ i += 1
+ }
+ sb.toString
+ }
+
+ /** Creates a new non-strict filter which combines this filter with the given predicate. */
+ def withFilter(q: Char => Boolean): WithFilter = new WithFilter(a => p(a) && q(a), s)
+ }
+
+ /** Avoid an allocation in [[collect]]. */
+ private val fallback: Any => Any = _ => fallback
+}
+
+/** Provides extension methods for strings.
+ *
+ * Some of these methods treat strings as a plain collection of [[Char]]s
+ * without any regard for Unicode handling. Unless the user takes Unicode
+ * handling in to account or makes sure the strings don't require such handling,
+ * these methods may result in unpaired or invalidly paired surrogate code
+ * units.
+ *
+ * @define unicodeunaware This method treats a string as a plain sequence of
+ * Char code units and makes no attempt to keep
+ * surrogate pairs or codepoint sequences together.
+ * The user is responsible for making sure such cases
+ * are handled correctly. Failing to do so may result in
+ * an invalid Unicode string.
+ */
+final class StringOps(private val s: String) extends AnyVal {
+ import StringOps._
+
+ @`inline` def view: StringView = new StringView(s)
+
+ @`inline` def size: Int = s.length
+
+ @`inline` def knownSize: Int = s.length
+
+ /** Get the char at the specified index. */
+ @`inline` def apply(i: Int): Char = s.charAt(i)
+
+ def sizeCompare(otherSize: Int): Int = Integer.compare(s.length, otherSize)
+
+ def lengthCompare(len: Int): Int = Integer.compare(s.length, len)
+
+ def sizeIs: Int = s.length
+
+ def lengthIs: Int = s.length
+
+ /** Builds a new collection by applying a function to all chars of this string.
+ *
+ * @param f the function to apply to each char.
+ * @return a new collection resulting from applying the given function
+ * `f` to each char of this string and collecting the results.
+ */
+ def map[B](f: Char => B): immutable.IndexedSeq[B] = {
+ val len = s.length
+ val dst = new Array[AnyRef](len)
+ var i = 0
+ while (i < len) {
+ dst(i) = f(s charAt i).asInstanceOf[AnyRef]
+ i += 1
+ }
+ new ArraySeq.ofRef(dst).asInstanceOf[immutable.IndexedSeq[B]]
+ }
+
+ /** Builds a new string by applying a function to all chars of this string.
+ *
+ * @param f the function to apply to each char.
+ * @return a new string resulting from applying the given function
+ * `f` to each char of this string and collecting the results.
+ */
+ def map(f: Char => Char): String = {
+ val len = s.length
+ val dst = new Array[Char](len)
+ var i = 0
+ while (i < len) {
+ dst(i) = f(s charAt i)
+ i += 1
+ }
+ new String(dst)
+ }
+
+ /** Builds a new collection by applying a function to all chars of this string
+ * and using the elements of the resulting collections.
+ *
+ * @param f the function to apply to each char.
+ * @return a new collection resulting from applying the given collection-valued function
+ * `f` to each char of this string and concatenating the results.
+ */
+ def flatMap[B](f: Char => IterableOnce[B]): immutable.IndexedSeq[B] = {
+ val len = s.length
+ val b = immutable.IndexedSeq.newBuilder[B]
+ var i = 0
+ while (i < len) {
+ b.addAll(f(s.charAt(i)))
+ i += 1
+ }
+ b.result()
+ }
+
+ /** Builds a new string by applying a function to all chars of this string
+ * and using the elements of the resulting strings.
+ *
+ * @param f the function to apply to each char.
+ * @return a new string resulting from applying the given string-valued function
+ * `f` to each char of this string and concatenating the results.
+ */
+ def flatMap(f: Char => String): String = {
+ val len = s.length
+ val sb = new JStringBuilder
+ var i = 0
+ while (i < len) {
+ sb append f(s.charAt(i))
+ i += 1
+ }
+ sb.toString
+ }
+
+ /** Builds a new String by applying a partial function to all chars of this String
+ * on which the function is defined.
+ *
+ * @param pf the partial function which filters and maps the String.
+ * @return a new String resulting from applying the given partial function
+ * `pf` to each char on which it is defined and collecting the results.
+ */
+ def collect(pf: PartialFunction[Char, Char]): String = {
+ val fallback: Any => Any = StringOps.fallback
+ var i = 0
+ val b = new StringBuilder
+ while (i < s.length) {
+ val v = pf.applyOrElse(s.charAt(i), fallback)
+ if (v.asInstanceOf[AnyRef] ne fallback) b.addOne(v.asInstanceOf[Char])
+ i += 1
+ }
+ b.result()
+ }
+
+ /** Builds a new collection by applying a partial function to all chars of this String
+ * on which the function is defined.
+ *
+ * @param pf the partial function which filters and maps the String.
+ * @tparam B the element type of the returned collection.
+ * @return a new collection resulting from applying the given partial function
+ * `pf` to each char on which it is defined and collecting the results.
+ */
+ def collect[B](pf: PartialFunction[Char, B]): immutable.IndexedSeq[B] = {
+ val fallback: Any => Any = StringOps.fallback
+ var i = 0
+ val b = immutable.IndexedSeq.newBuilder[B]
+ while (i < s.length) {
+ val v = pf.applyOrElse(s.charAt(i), fallback)
+ if (v.asInstanceOf[AnyRef] ne fallback) b.addOne(v.asInstanceOf[B])
+ i += 1
+ }
+ b.result()
+ }
+
+ /** Returns a new collection containing the chars from this string followed by the elements from the
+ * right hand operand.
+ *
+ * @param suffix the collection to append.
+ * @return a new collection which contains all chars
+ * of this string followed by all elements of `suffix`.
+ */
+ def concat[B >: Char](suffix: IterableOnce[B]): immutable.IndexedSeq[B] = {
+ val b = immutable.IndexedSeq.newBuilder[B]
+ val k = suffix.knownSize
+ b.sizeHint(s.length + (if(k >= 0) k else 16))
+ b.addAll(new WrappedString(s))
+ b.addAll(suffix)
+ b.result()
+ }
+
+ /** Returns a new string containing the chars from this string followed by the chars from the
+ * right hand operand.
+ *
+ * @param suffix the collection to append.
+ * @return a new string which contains all chars
+ * of this string followed by all chars of `suffix`.
+ */
+ def concat(suffix: IterableOnce[Char]): String = {
+ val k = suffix.knownSize
+ val sb = new JStringBuilder(s.length + (if(k >= 0) k else 16))
+ sb.append(s)
+ for (ch <- suffix.iterator) sb.append(ch)
+ sb.toString
+ }
+
+ /** Returns a new string containing the chars from this string followed by the chars from the
+ * right hand operand.
+ *
+ * @param suffix the string to append.
+ * @return a new string which contains all chars
+ * of this string followed by all chars of `suffix`.
+ */
+ @`inline` def concat(suffix: String): String = s + suffix
+
+ /** Alias for `concat` */
+ @`inline` def ++[B >: Char](suffix: Iterable[B]): immutable.IndexedSeq[B] = concat(suffix)
+
+ /** Alias for `concat` */
+ @`inline` def ++(suffix: IterableOnce[Char]): String = concat(suffix)
+
+ /** Alias for `concat` */
+ def ++(xs: String): String = concat(xs)
+
+ /** Returns a collection with an element appended until a given target length is reached.
+ *
+ * @param len the target length
+ * @param elem the padding value
+ * @return a collection consisting of
+ * this string followed by the minimal number of occurrences of `elem` so
+ * that the resulting collection has a length of at least `len`.
+ */
+ def padTo[B >: Char](len: Int, elem: B): immutable.IndexedSeq[B] = {
+ val sLen = s.length
+ if (sLen >= len) new WrappedString(s) else {
+ val b = immutable.IndexedSeq.newBuilder[B]
+ b.sizeHint(len)
+ b.addAll(new WrappedString(s))
+ var i = sLen
+ while (i < len) {
+ b.addOne(elem)
+ i += 1
+ }
+ b.result()
+ }
+ }
+
+ /** Returns a string with a char appended until a given target length is reached.
+ *
+ * @param len the target length
+ * @param elem the padding value
+ * @return a string consisting of
+ * this string followed by the minimal number of occurrences of `elem` so
+ * that the resulting string has a length of at least `len`.
+ */
+ def padTo(len: Int, elem: Char): String = {
+ val sLen = s.length
+ if (sLen >= len) s else {
+ val sb = new JStringBuilder(len)
+ sb.append(s)
+ // With JDK 11, this can written as:
+ // sb.append(String.valueOf(elem).repeat(len - sLen))
+ var i = sLen
+ while (i < len) {
+ sb.append(elem)
+ i += 1
+ }
+ sb.toString
+ }
+ }
+
+ /** A copy of the string with an element prepended */
+ def prepended[B >: Char](elem: B): immutable.IndexedSeq[B] = {
+ val b = immutable.IndexedSeq.newBuilder[B]
+ b.sizeHint(s.length + 1)
+ b.addOne(elem)
+ b.addAll(new WrappedString(s))
+ b.result()
+ }
+
+ /** Alias for `prepended` */
+ @`inline` def +: [B >: Char] (elem: B): immutable.IndexedSeq[B] = prepended(elem)
+
+ /** A copy of the string with an char prepended */
+ def prepended(c: Char): String =
+ new JStringBuilder(s.length + 1).append(c).append(s).toString
+
+ /** Alias for `prepended` */
+ @`inline` def +: (c: Char): String = prepended(c)
+
+ /** A copy of the string with all elements from a collection prepended */
+ def prependedAll[B >: Char](prefix: IterableOnce[B]): immutable.IndexedSeq[B] = {
+ val b = immutable.IndexedSeq.newBuilder[B]
+ val k = prefix.knownSize
+ b.sizeHint(s.length + (if(k >= 0) k else 16))
+ b.addAll(prefix)
+ b.addAll(new WrappedString(s))
+ b.result()
+ }
+
+ /** Alias for `prependedAll` */
+ @`inline` def ++: [B >: Char] (prefix: IterableOnce[B]): immutable.IndexedSeq[B] = prependedAll(prefix)
+
+ /** A copy of the string with another string prepended */
+ def prependedAll(prefix: String): String = prefix + s
+
+ /** Alias for `prependedAll` */
+ @`inline` def ++: (prefix: String): String = prependedAll(prefix)
+
+ /** A copy of the string with an element appended */
+ def appended[B >: Char](elem: B): immutable.IndexedSeq[B] = {
+ val b = immutable.IndexedSeq.newBuilder[B]
+ b.sizeHint(s.length + 1)
+ b.addAll(new WrappedString(s))
+ b.addOne(elem)
+ b.result()
+ }
+
+ /** Alias for `appended` */
+ @`inline` def :+ [B >: Char](elem: B): immutable.IndexedSeq[B] = appended(elem)
+
+ /** A copy of the string with an element appended */
+ def appended(c: Char): String =
+ new JStringBuilder(s.length + 1).append(s).append(c).toString
+
+ /** Alias for `appended` */
+ @`inline` def :+ (c: Char): String = appended(c)
+
+ /** A copy of the string with all elements from a collection appended */
+ @`inline` def appendedAll[B >: Char](suffix: IterableOnce[B]): immutable.IndexedSeq[B] =
+ concat(suffix)
+
+ /** Alias for `appendedAll` */
+ @`inline` def :++ [B >: Char](suffix: IterableOnce[B]): immutable.IndexedSeq[B] =
+ concat(suffix)
+
+ /** A copy of the string with another string appended */
+ @`inline` def appendedAll(suffix: String): String = s + suffix
+
+ /** Alias for `appendedAll` */
+ @`inline` def :++ (suffix: String): String = s + suffix
+
+ /** Produces a new collection where a slice of characters in this string is replaced by another collection.
+ *
+ * Patching at negative indices is the same as patching starting at 0.
+ * Patching at indices at or larger than the length of the original string appends the patch to the end.
+ * If more values are replaced than actually exist, the excess is ignored.
+ *
+ * @param from the index of the first replaced char
+ * @param other the replacement collection
+ * @param replaced the number of chars to drop in the original string
+ * @return a new collection consisting of all chars of this string
+ * except that `replaced` chars starting from `from` are replaced
+ * by `other`.
+ */
+ def patch[B >: Char](from: Int, other: IterableOnce[B], replaced: Int): immutable.IndexedSeq[B] = {
+ val len = s.length
+ @`inline` def slc(off: Int, length: Int): WrappedString =
+ new WrappedString(s.substring(off, off+length))
+ val b = immutable.IndexedSeq.newBuilder[B]
+ val k = other.knownSize
+ if(k >= 0) b.sizeHint(len + k - replaced)
+ val chunk1 = if(from > 0) min(from, len) else 0
+ if(chunk1 > 0) b.addAll(slc(0, chunk1))
+ b ++= other
+ val remaining = len - chunk1 - replaced
+ if(remaining > 0) b.addAll(slc(len - remaining, remaining))
+ b.result()
+ }
+
+ /** Produces a new collection where a slice of characters in this string is replaced by another collection.
+ *
+ * Patching at negative indices is the same as patching starting at 0.
+ * Patching at indices at or larger than the length of the original string appends the patch to the end.
+ * If more values are replaced than actually exist, the excess is ignored.
+ *
+ * @param from the index of the first replaced char
+ * @param other the replacement string
+ * @param replaced the number of chars to drop in the original string
+ * @return a new string consisting of all chars of this string
+ * except that `replaced` chars starting from `from` are replaced
+ * by `other`.
+ * @note $unicodeunaware
+ */
+ def patch(from: Int, other: IterableOnce[Char], replaced: Int): String =
+ patch(from, other.iterator.mkString, replaced)
+
+ /** Produces a new string where a slice of characters in this string is replaced by another string.
+ *
+ * Patching at negative indices is the same as patching starting at 0.
+ * Patching at indices at or larger than the length of the original string appends the patch to the end.
+ * If more values are replaced than actually exist, the excess is ignored.
+ *
+ * @param from the index of the first replaced char
+ * @param other the replacement string
+ * @param replaced the number of chars to drop in the original string
+ * @return a new string consisting of all chars of this string
+ * except that `replaced` chars starting from `from` are replaced
+ * by `other`.
+ * @note $unicodeunaware
+ */
+ def patch(from: Int, other: String, replaced: Int): String = {
+ val len = s.length
+ val sb = new JStringBuilder(len + other.size - replaced)
+ val chunk1 = if(from > 0) min(from, len) else 0
+ if(chunk1 > 0) sb.append(s, 0, chunk1)
+ sb.append(other)
+ val remaining = len - chunk1 - replaced
+ if(remaining > 0) sb.append(s, len - remaining, len)
+ sb.toString
+ }
+
+ /** A copy of this string with one single replaced element.
+ * @param index the position of the replacement
+ * @param elem the replacing element
+ * @return a new string which is a copy of this string with the element at position `index` replaced by `elem`.
+ * @throws IndexOutOfBoundsException if `index` does not satisfy `0 <= index < length`.
+ * @note $unicodeunaware
+ */
+ def updated(index: Int, elem: Char): String = {
+ val sb = new JStringBuilder(s.length).append(s)
+ sb.setCharAt(index, elem)
+ sb.toString
+ }
+
+ /** Tests whether this string contains the given character.
+ *
+ * @param elem the character to test.
+ * @return `true` if this string has an element that is equal (as
+ * determined by `==`) to `elem`, `false` otherwise.
+ */
+ def contains(elem: Char): Boolean = s.indexOf(elem) >= 0
+
+ /** Displays all elements of this string in a string using start, end, and
+ * separator strings.
+ *
+ * @param start the starting string.
+ * @param sep the separator string.
+ * @param end the ending string.
+ * @return The resulting string
+ * begins with the string `start` and ends with the string
+ * `end`. Inside, the string chars of this string are separated by
+ * the string `sep`.
+ * @note $unicodeunaware
+ */
+ final def mkString(start: String, sep: String, end: String): String =
+ addString(new StringBuilder(), start, sep, end).toString
+
+ /** Displays all elements of this string in a string using a separator string.
+ *
+ * @param sep the separator string.
+ * @return In the resulting string
+ * the chars of this string are separated by the string `sep`.
+ * @note $unicodeunaware
+ */
+ @inline final def mkString(sep: String): String =
+ if (sep.isEmpty || s.length < 2) s
+ else mkString("", sep, "")
+
+ /** Returns this string */
+ @inline final def mkString: String = s
+
+ /** Appends this string to a string builder. */
+ @inline final def addString(b: StringBuilder): b.type = b.append(s)
+
+ /** Appends this string to a string builder using a separator string. */
+ @inline final def addString(b: StringBuilder, sep: String): b.type =
+ addString(b, "", sep, "")
+
+ /** Appends this string to a string builder using start, end and separator strings. */
+ final def addString(b: StringBuilder, start: String, sep: String, end: String): b.type = {
+ val jsb = b.underlying
+ if (start.length != 0) jsb.append(start)
+ val len = s.length
+ if (len != 0) {
+ if (sep.isEmpty) jsb.append(s)
+ else {
+ jsb.ensureCapacity(jsb.length + len + end.length + (len - 1) * sep.length)
+ jsb.append(s.charAt(0))
+ var i = 1
+ while (i < len) {
+ jsb.append(sep)
+ jsb.append(s.charAt(i))
+ i += 1
+ }
+ }
+ }
+ if (end.length != 0) jsb.append(end)
+ b
+ }
+
+ /** Selects an interval of elements. The returned string is made up
+ * of all elements `x` which satisfy the invariant:
+ * {{{
+ * from <= indexOf(x) < until
+ * }}}
+ *
+ * @param from the lowest index to include from this string.
+ * @param until the lowest index to EXCLUDE from this string.
+ * @return a string containing the elements greater than or equal to
+ * index `from` extending up to (but not including) index `until`
+ * of this string.
+ * @note $unicodeunaware
+ */
+ def slice(from: Int, until: Int): String = {
+ val start = from max 0
+ val end = until min s.length
+
+ if (start >= end) ""
+ else s.substring(start, end)
+ }
+
+ // Note: String.repeat is added in JDK 11.
+ /** Return the current string concatenated `n` times.
+ */
+ def *(n: Int): String = {
+ if (n <= 0) {
+ ""
+ } else {
+ val sb = new JStringBuilder(s.length * n)
+ var i = 0
+ while (i < n) {
+ sb.append(s)
+ i += 1
+ }
+ sb.toString
+ }
+ }
+
+ @`inline` private[this] def isLineBreak(c: Char) = c == CR || c == LF
+ @`inline` private[this] def isLineBreak2(c0: Char, c: Char) = c0 == CR && c == LF
+
+ /** Strip the trailing line separator from this string if there is one.
+ * The line separator is taken as `"\n"`, `"\r"`, or `"\r\n"`.
+ */
+ def stripLineEnd: String =
+ if (s.isEmpty) s
+ else {
+ var i = s.length - 1
+ val last = apply(i)
+ if (!isLineBreak(last)) s
+ else {
+ if (i > 0 && isLineBreak2(apply(i - 1), last)) i -= 1
+ s.substring(0, i)
+ }
+ }
+
+ /** Return an iterator of all lines embedded in this string,
+ * including trailing line separator characters.
+ *
+ * The empty string yields an empty iterator.
+ */
+ def linesWithSeparators: Iterator[String] = linesSeparated(stripped = false)
+
+ /** Lines in this string, where a line is terminated by
+ * `"\n"`, `"\r"`, `"\r\n"`, or the end of the string.
+ * A line may be empty. Line terminators are removed.
+ */
+ def linesIterator: Iterator[String] = linesSeparated(stripped = true)
+
+ // if `stripped`, exclude the line separators
+ private def linesSeparated(stripped: Boolean): Iterator[String] = new AbstractIterator[String] {
+ def hasNext: Boolean = !done
+ def next(): String = if (done) Iterator.empty.next() else advance()
+
+ private[this] val len = s.length
+ private[this] var index = 0
+ @`inline` private def done = index >= len
+ private def advance(): String = {
+ val start = index
+ while (!done && !isLineBreak(apply(index))) index += 1
+ var end = index
+ if (!done) {
+ val c = apply(index)
+ index += 1
+ if (!done && isLineBreak2(c, apply(index))) index += 1
+ if (!stripped) end = index
+ }
+ s.substring(start, end)
+ }
+ }
+
+ /** Return all lines in this string in an iterator, excluding trailing line
+ * end characters; i.e., apply `.stripLineEnd` to all lines
+ * returned by `linesWithSeparators`.
+ */
+ @deprecated("Use `linesIterator`, because JDK 11 adds a `lines` method on String", "2.13.0")
+ def lines: Iterator[String] = linesIterator
+
+ /** Returns this string with first character converted to upper case.
+ * If the first character of the string is capitalized, it is returned unchanged.
+ * This method does not convert characters outside the Basic Multilingual Plane (BMP).
+ */
+ def capitalize: String =
+ if (s == null || s.length == 0 || !s.charAt(0).isLower) s
+ else updated(0, s.charAt(0).toUpper)
+
+ /** Returns this string with the given `prefix` stripped. If this string does not
+ * start with `prefix`, it is returned unchanged.
+ */
+ def stripPrefix(prefix: String) =
+ if (s startsWith prefix) s.substring(prefix.length)
+ else s
+
+ /** Returns this string with the given `suffix` stripped. If this string does not
+ * end with `suffix`, it is returned unchanged.
+ */
+ def stripSuffix(suffix: String) =
+ if (s endsWith suffix) s.substring(0, s.length - suffix.length)
+ else s
+
+ /** Replace all literal occurrences of `literal` with the literal string `replacement`.
+ * This method is equivalent to [[java.lang.String#replace(CharSequence,CharSequence)]].
+ *
+ * @param literal the string which should be replaced everywhere it occurs
+ * @param replacement the replacement string
+ * @return the resulting string
+ */
+ @deprecated("Use `s.replace` as an exact replacement", "2.13.2")
+ def replaceAllLiterally(literal: String, replacement: String): String = s.replace(literal, replacement)
+
+ /** For every line in this string:
+ *
+ * Strip a leading prefix consisting of blanks or control characters
+ * followed by `marginChar` from the line.
+ */
+ def stripMargin(marginChar: Char): String = {
+ val sb = new JStringBuilder(s.length)
+ for (line <- linesWithSeparators) {
+ val len = line.length
+ var index = 0
+ while (index < len && line.charAt(index) <= ' ') index += 1
+ val stripped =
+ if (index < len && line.charAt(index) == marginChar) line.substring(index + 1)
+ else line
+ sb.append(stripped)
+ }
+ sb.toString
+ }
+
+ /** For every line in this string:
+ *
+ * Strip a leading prefix consisting of blanks or control characters
+ * followed by `|` from the line.
+ */
+ def stripMargin: String = stripMargin('|')
+
+ private[this] def escape(ch: Char): String = if (
+ (ch >= 'a') && (ch <= 'z') ||
+ (ch >= 'A') && (ch <= 'Z') ||
+ (ch >= '0' && ch <= '9')) ch.toString
+ else "\\" + ch
+
+ /** Split this string around the separator character
+ *
+ * If this string is the empty string, returns an array of strings
+ * that contains a single empty string.
+ *
+ * If this string is not the empty string, returns an array containing
+ * the substrings terminated by the start of the string, the end of the
+ * string or the separator character, excluding empty trailing substrings
+ *
+ * If the separator character is a surrogate character, only split on
+ * matching surrogate characters if they are not part of a surrogate pair
+ *
+ * The behaviour follows, and is implemented in terms of String.split(re: String)
+ *
+ *
+ * @example {{{
+ * "a.b".split('.') //returns Array("a", "b")
+ *
+ * //splitting the empty string always returns the array with a single
+ * //empty string
+ * "".split('.') //returns Array("")
+ *
+ * //only trailing empty substrings are removed
+ * "a.".split('.') //returns Array("a")
+ * ".a.".split('.') //returns Array("", "a")
+ * "..a..".split('.') //returns Array("", "", "a")
+ *
+ * //all parts are empty and trailing
+ * ".".split('.') //returns Array()
+ * "..".split('.') //returns Array()
+ *
+ * //surrogate pairs
+ * val high = 0xD852.toChar
+ * val low = 0xDF62.toChar
+ * val highstring = high.toString
+ * val lowstring = low.toString
+ *
+ * //well-formed surrogate pairs are not split
+ * val highlow = highstring + lowstring
+ * highlow.split(high) //returns Array(highlow)
+ *
+ * //bare surrogate characters are split
+ * val bare = "_" + highstring + "_"
+ * bare.split(high) //returns Array("_", "_")
+ *
+ * }}}
+ *
+ * @param separator the character used as a delimiter
+ */
+ def split(separator: Char): Array[String] = s.split(escape(separator))
+
+ @throws(classOf[java.util.regex.PatternSyntaxException])
+ def split(separators: Array[Char]): Array[String] = {
+ val re = separators.foldLeft("[")(_+escape(_)) + "]"
+ s.split(re)
+ }
+
+ /** You can follow a string with `.r`, turning it into a `Regex`. E.g.
+ *
+ * `"""A\w*""".r` is the regular expression for ASCII-only identifiers starting with `A`.
+ *
+ * `"""(?\d\d)-(?\d\d)-(?\d\d\d\d)""".r` matches dates
+ * and provides its subcomponents through groups named "month", "day" and
+ * "year".
+ */
+ def r: Regex = new Regex(s)
+
+ /** You can follow a string with `.r(g1, ... , gn)`, turning it into a `Regex`,
+ * with group names g1 through gn.
+ *
+ * `"""(\d\d)-(\d\d)-(\d\d\d\d)""".r("month", "day", "year")` matches dates
+ * and provides its subcomponents through groups named "month", "day" and
+ * "year".
+ *
+ * @param groupNames The names of the groups in the pattern, in the order they appear.
+ */
+ @deprecated("use inline group names like (?X) instead", "2.13.7")
+ def r(groupNames: String*): Regex = new Regex(s, groupNames: _*)
+
+ /**
+ * @throws java.lang.IllegalArgumentException If the string does not contain a parsable `Boolean`.
+ */
+ def toBoolean: Boolean = toBooleanImpl(s)
+
+ /**
+ * Try to parse as a `Boolean`
+ * @return `Some(true)` if the string is "true" case insensitive,
+ * `Some(false)` if the string is "false" case insensitive,
+ * and `None` if the string is anything else
+ * @throws java.lang.NullPointerException if the string is `null`
+ */
+ def toBooleanOption: Option[Boolean] = StringParsers.parseBool(s)
+
+ /**
+ * Parse as a `Byte` (string must contain only decimal digits and optional leading `-` or `+`).
+ * @throws java.lang.NumberFormatException If the string does not contain a parsable `Byte`.
+ */
+ def toByte: Byte = java.lang.Byte.parseByte(s)
+
+ /**
+ * Try to parse as a `Byte`
+ * @return `Some(value)` if the string contains a valid byte value, otherwise `None`
+ * @throws java.lang.NullPointerException if the string is `null`
+ */
+ def toByteOption: Option[Byte] = StringParsers.parseByte(s)
+
+ /**
+ * Parse as a `Short` (string must contain only decimal digits and optional leading `-` or `+`).
+ * @throws java.lang.NumberFormatException If the string does not contain a parsable `Short`.
+ */
+ def toShort: Short = java.lang.Short.parseShort(s)
+
+ /**
+ * Try to parse as a `Short`
+ * @return `Some(value)` if the string contains a valid short value, otherwise `None`
+ * @throws java.lang.NullPointerException if the string is `null`
+ */
+ def toShortOption: Option[Short] = StringParsers.parseShort(s)
+
+ /**
+ * Parse as an `Int` (string must contain only decimal digits and optional leading `-` or `+`).
+ * @throws java.lang.NumberFormatException If the string does not contain a parsable `Int`.
+ */
+ def toInt: Int = java.lang.Integer.parseInt(s)
+
+ /**
+ * Try to parse as an `Int`
+ * @return `Some(value)` if the string contains a valid Int value, otherwise `None`
+ * @throws java.lang.NullPointerException if the string is `null`
+ */
+ def toIntOption: Option[Int] = StringParsers.parseInt(s)
+
+ /**
+ * Parse as a `Long` (string must contain only decimal digits and optional leading `-` or `+`).
+ * @throws java.lang.NumberFormatException If the string does not contain a parsable `Long`.
+ */
+ def toLong: Long = java.lang.Long.parseLong(s)
+
+ /**
+ * Try to parse as a `Long`
+ * @return `Some(value)` if the string contains a valid long value, otherwise `None`
+ * @throws java.lang.NullPointerException if the string is `null`
+ */
+ def toLongOption: Option[Long] = StringParsers.parseLong(s)
+
+ /**
+ * Parse as a `Float` (surrounding whitespace is removed with a `trim`).
+ * @throws java.lang.NumberFormatException If the string does not contain a parsable `Float`.
+ * @throws java.lang.NullPointerException If the string is null.
+ */
+ def toFloat: Float = java.lang.Float.parseFloat(s)
+
+ /**
+ * Try to parse as a `Float`
+ * @return `Some(value)` if the string is a parsable `Float`, `None` otherwise
+ * @throws java.lang.NullPointerException If the string is null
+ */
+ def toFloatOption: Option[Float] = StringParsers.parseFloat(s)
+
+ /**
+ * Parse as a `Double` (surrounding whitespace is removed with a `trim`).
+ * @throws java.lang.NumberFormatException If the string does not contain a parsable `Double`.
+ * @throws java.lang.NullPointerException If the string is null.
+ */
+ def toDouble: Double = java.lang.Double.parseDouble(s)
+
+ /**
+ * Try to parse as a `Double`
+ * @return `Some(value)` if the string is a parsable `Double`, `None` otherwise
+ * @throws java.lang.NullPointerException If the string is null
+ */
+ def toDoubleOption: Option[Double] = StringParsers.parseDouble(s)
+
+ private[this] def toBooleanImpl(s: String): Boolean =
+ if (s == null) throw new IllegalArgumentException("For input string: \"null\"")
+ else if (s.equalsIgnoreCase("true")) true
+ else if (s.equalsIgnoreCase("false")) false
+ else throw new IllegalArgumentException("For input string: \""+s+"\"")
+
+ def toArray[B >: Char](implicit tag: ClassTag[B]): Array[B] =
+ if (tag == ClassTag.Char) s.toCharArray.asInstanceOf[Array[B]]
+ else new WrappedString(s).toArray[B]
+
+ private[this] def unwrapArg(arg: Any): AnyRef = arg match {
+ case x: ScalaNumber => x.underlying
+ case x => x.asInstanceOf[AnyRef]
+ }
+
+ /** Uses the underlying string as a pattern (in a fashion similar to
+ * printf in C), and uses the supplied arguments to fill in the
+ * holes.
+ *
+ * The interpretation of the formatting patterns is described in
+ * [[java.util.Formatter]], with the addition that
+ * classes deriving from `ScalaNumber` (such as [[scala.BigInt]] and
+ * [[scala.BigDecimal]]) are unwrapped to pass a type which `Formatter` understands.
+ *
+ * See [[scala.StringContext#f]] for a formatting interpolator that
+ * checks the format string at compilation.
+ *
+ * @param args the arguments used to instantiating the pattern.
+ * @throws java.util.IllegalFormatException if the format contains syntax or conversion errors
+ */
+ def format(args: Any*): String =
+ java.lang.String.format(s, args.map(unwrapArg): _*)
+
+ /** Like `format(args*)` but takes an initial `Locale` parameter
+ * which influences formatting as in `java.lang.String`'s format.
+ *
+ * The interpretation of the formatting patterns is described in
+ * [[java.util.Formatter]], with the addition that
+ * classes deriving from `ScalaNumber` (such as `scala.BigInt` and
+ * `scala.BigDecimal`) are unwrapped to pass a type which `Formatter`
+ * understands.
+ *
+ * @param l an instance of `java.util.Locale`
+ * @param args the arguments used to instantiating the pattern.
+ * @throws java.util.IllegalFormatException if the format contains syntax or conversion errors
+ */
+ def formatLocal(l: java.util.Locale, args: Any*): String =
+ java.lang.String.format(l, s, args.map(unwrapArg): _*)
+
+ def compare(that: String): Int = s.compareTo(that)
+
+ /** Returns true if `this` is less than `that` */
+ def < (that: String): Boolean = compare(that) < 0
+
+ /** Returns true if `this` is greater than `that`. */
+ def > (that: String): Boolean = compare(that) > 0
+
+ /** Returns true if `this` is less than or equal to `that`. */
+ def <= (that: String): Boolean = compare(that) <= 0
+
+ /** Returns true if `this` is greater than or equal to `that`. */
+ def >= (that: String): Boolean = compare(that) >= 0
+
+ /** Counts the number of chars in this string which satisfy a predicate */
+ def count(p: (Char) => Boolean): Int = {
+ var i, res = 0
+ val len = s.length
+ while(i < len) {
+ if(p(s.charAt(i))) res += 1
+ i += 1
+ }
+ res
+ }
+
+ /** Apply `f` to each element for its side effects.
+ * Note: [U] parameter needed to help scalac's type inference.
+ */
+ def foreach[U](f: Char => U): Unit = {
+ val len = s.length
+ var i = 0
+ while(i < len) {
+ f(s.charAt(i))
+ i += 1
+ }
+ }
+
+ /** Tests whether a predicate holds for all chars of this string.
+ *
+ * @param p the predicate used to test elements.
+ * @return `true` if this string is empty or the given predicate `p`
+ * holds for all chars of this string, otherwise `false`.
+ */
+ def forall(@deprecatedName("f", "2.13.3") p: Char => Boolean): Boolean = {
+ var i = 0
+ val len = s.length
+ while(i < len) {
+ if(!p(s.charAt(i))) return false
+ i += 1
+ }
+ true
+ }
+
+ /** Applies the given binary operator `op` to the given initial value `z` and all chars
+ * in this string, going left to right. Returns the initial value if this string is
+ * empty.
+ *
+ * If `x,,1,,`, `x,,2,,`, ..., `x,,n,,` are the chars in this string, 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 chars in this string,
+ * going left to right. Returns `z` if this string is empty.
+ */
+ def foldLeft[B](z: B)(op: (B, Char) => B): B = {
+ var v = z
+ var i = 0
+ val len = s.length
+ while(i < len) {
+ v = op(v, s.charAt(i))
+ i += 1
+ }
+ v
+ }
+
+ /** Applies the given binary operator `op` to all chars in this string and the given
+ * initial value `z`, going right to left. Returns the initial value if this string is
+ * empty.
+ *
+ * If `x,,1,,`, `x,,2,,`, ..., `x,,n,,` are the chars in this string, 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 chars in this string
+ * and `z`, going right to left. Returns `z` if this string
+ * is empty.
+ */
+ def foldRight[B](z: B)(op: (Char, B) => B): B = {
+ var v = z
+ var i = s.length - 1
+ while(i >= 0) {
+ v = op(s.charAt(i), v)
+ i -= 1
+ }
+ v
+ }
+
+ /** 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 `Char`.
+ * @param z An initial value.
+ * @param op A binary operator.
+ * @return The result of applying `op` to `z` and all chars in this string,
+ * going left to right. Returns `z` if this string is empty.
+ */
+ @`inline` def fold[A1 >: Char](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)
+
+ /** Selects the first char of this string.
+ * @return the first char of this string.
+ * @throws NoSuchElementException if the string is empty.
+ */
+ def head: Char = if(s.isEmpty) throw new NoSuchElementException("head of empty String") else s.charAt(0)
+
+ /** Optionally selects the first char.
+ * @return the first char of this string if it is nonempty,
+ * `None` if it is empty.
+ */
+ def headOption: Option[Char] =
+ if(s.isEmpty) None else Some(s.charAt(0))
+
+ /** Selects the last char of this string.
+ * @return the last char of this string.
+ * @throws NoSuchElementException if the string is empty.
+ */
+ def last: Char = if(s.isEmpty) throw new NoSuchElementException("last of empty String") else s.charAt(s.length-1)
+
+ /** Optionally selects the last char.
+ * @return the last char of this string if it is nonempty,
+ * `None` if it is empty.
+ */
+ def lastOption: Option[Char] =
+ if(s.isEmpty) None else Some(s.charAt(s.length-1))
+
+ /** Produces the range of all indices of this string.
+ *
+ * @return a `Range` value from `0` to one less than the length of this string.
+ */
+ def indices: Range = Range(0, s.length)
+
+ /** Iterator can be used only once */
+ def iterator: Iterator[Char] = new StringIterator(s)
+
+ /** Stepper can be used with Java 8 Streams. This method is equivalent to a call to
+ * [[charStepper]]. See also [[codePointStepper]].
+ */
+ @`inline` def stepper: IntStepper with EfficientSplit = charStepper
+
+ /** Steps over characters in this string. Values are packed in `Int` for efficiency
+ * and compatibility with Java 8 Streams which have an efficient specialization for `Int`.
+ */
+ @`inline` def charStepper: IntStepper with EfficientSplit = new CharStringStepper(s, 0, s.length)
+
+ /** Steps over code points in this string.
+ */
+ @`inline` def codePointStepper: IntStepper with EfficientSplit = new CodePointStringStepper(s, 0, s.length)
+
+ /** Tests whether the string is not empty. */
+ @`inline` def nonEmpty: Boolean = !s.isEmpty
+
+ /** Returns new sequence with elements in reversed order.
+ * @note $unicodeunaware
+ */
+ def reverse: String = new JStringBuilder(s).reverse().toString
+
+ /** An iterator yielding chars in reversed order.
+ *
+ * Note: `xs.reverseIterator` is the same as `xs.reverse.iterator` but implemented more efficiently.
+ *
+ * @return an iterator yielding the chars of this string in reversed order
+ */
+ def reverseIterator: Iterator[Char] = new ReverseIterator(s)
+
+ /** Creates a non-strict filter of this string.
+ *
+ * @note the difference between `c filter p` and `c withFilter p` is that
+ * the former creates a new string, whereas the latter only
+ * restricts the domain of subsequent `map`, `flatMap`, `foreach`,
+ * and `withFilter` operations.
+ *
+ * @param p the predicate used to test elements.
+ * @return an object of class `stringOps.WithFilter`, which supports
+ * `map`, `flatMap`, `foreach`, and `withFilter` operations.
+ * All these operations apply to those chars of this string
+ * which satisfy the predicate `p`.
+ */
+ def withFilter(p: Char => Boolean): StringOps.WithFilter = new StringOps.WithFilter(p, s)
+
+ /** The rest of the string without its first char.
+ * @throws UnsupportedOperationException if the string is empty.
+ * @note $unicodeunaware
+ */
+ def tail: String = if(s.isEmpty) throw new UnsupportedOperationException("tail of empty String") else slice(1, s.length)
+
+ /** The initial part of the string without its last char.
+ * @throws UnsupportedOperationException if the string is empty.
+ * @note $unicodeunaware
+ */
+ def init: String = if(s.isEmpty) throw new UnsupportedOperationException("init of empty String") else slice(0, s.length-1)
+
+ /** A string containing the first `n` chars of this string.
+ * @note $unicodeunaware
+ */
+ def take(n: Int): String = slice(0, min(n, s.length))
+
+ /** The rest of the string without its `n` first chars.
+ * @note $unicodeunaware
+ */
+ def drop(n: Int): String = slice(min(n, s.length), s.length)
+
+ /** A string containing the last `n` chars of this string.
+ * @note $unicodeunaware
+ */
+ def takeRight(n: Int): String = drop(s.length - max(n, 0))
+
+ /** The rest of the string without its `n` last chars.
+ * @note $unicodeunaware
+ */
+ def dropRight(n: Int): String = take(s.length - max(n, 0))
+
+ /** Iterates over the tails of this string. The first value will be this
+ * string and the final one will be an empty string, with the intervening
+ * values the results of successive applications of `tail`.
+ *
+ * @return an iterator over all the tails of this string
+ * @note $unicodeunaware
+ */
+ def tails: Iterator[String] = iterateUntilEmpty(_.tail)
+
+ /** Iterates over the inits of this string. The first value will be this
+ * string and the final one will be an empty string, with the intervening
+ * values the results of successive applications of `init`.
+ *
+ * @return an iterator over all the inits of this string
+ * @note $unicodeunaware
+ */
+ def inits: Iterator[String] = iterateUntilEmpty(_.init)
+
+ // A helper for tails and inits.
+ private[this] def iterateUntilEmpty(f: String => String): Iterator[String] =
+ Iterator.iterate(s)(f).takeWhile(x => !x.isEmpty) ++ Iterator.single("")
+
+ /** Selects all chars of this string which satisfy a predicate. */
+ def filter(pred: Char => Boolean): String = {
+ val len = s.length
+ val sb = new JStringBuilder(len)
+ var i = 0
+ while (i < len) {
+ val x = s.charAt(i)
+ if(pred(x)) sb.append(x)
+ i += 1
+ }
+ if(len == sb.length()) s else sb.toString
+ }
+
+ /** Selects all chars of this string which do not satisfy a predicate. */
+ @`inline` def filterNot(pred: Char => Boolean): String = filter(c => !pred(c))
+
+ /** Copy chars of this string to an array.
+ * Fills the given array `xs` starting at index 0.
+ * Copying will stop once either the entire string has been copied
+ * or the end of the array is reached
+ *
+ * @param xs the array to fill.
+ */
+ @`inline` def copyToArray(xs: Array[Char]): Int =
+ copyToArray(xs, 0, Int.MaxValue)
+
+ /** Copy chars of this string to an array.
+ * Fills the given array `xs` starting at index `start`.
+ * Copying will stop once either the entire string has been copied
+ * or the end of the array is reached
+ *
+ * @param xs the array to fill.
+ * @param start the starting index.
+ */
+ @`inline` def copyToArray(xs: Array[Char], start: Int): Int =
+ copyToArray(xs, start, Int.MaxValue)
+
+ /** Copy chars of this string to an array.
+ * Fills the given array `xs` starting at index `start` with at most `len` chars.
+ * Copying will stop once either the entire string has been copied,
+ * or the end of the array is reached or `len` chars have been copied.
+ *
+ * @param xs the array to fill.
+ * @param start the starting index.
+ * @param len the maximal number of elements to copy.
+ */
+ def copyToArray(xs: Array[Char], start: Int, len: Int): Int = {
+ val copied = IterableOnce.elemsToCopyToArray(s.length, xs.length, start, len)
+ if (copied > 0) {
+ s.getChars(0, copied, xs, start)
+ }
+ copied
+ }
+
+ /** Finds index of the first char satisfying some predicate after or at some start index.
+ *
+ * @param p the predicate used to test elements.
+ * @param from the start index
+ * @return the index `>= from` of the first element of this string that satisfies the predicate `p`,
+ * or `-1`, if none exists.
+ */
+ def indexWhere(p: Char => Boolean, from: Int = 0): Int = {
+ val len = s.length
+ var i = from
+ while(i < len) {
+ if(p(s.charAt(i))) return i
+ i += 1
+ }
+ -1
+ }
+
+ /** Finds index of the last char satisfying some predicate before or at some end index.
+ *
+ * @param p the predicate used to test elements.
+ * @param end the end index
+ * @return the index `<= end` of the last element of this string that satisfies the predicate `p`,
+ * or `-1`, if none exists.
+ */
+ def lastIndexWhere(p: Char => Boolean, end: Int = Int.MaxValue): Int = {
+ val len = s.length
+ var i = min(end, len-1)
+ while(i >= 0) {
+ if(p(s.charAt(i))) return i
+ i -= 1
+ }
+ -1
+ }
+
+ /** Tests whether a predicate holds for at least one char of this string. */
+ def exists(p: Char => Boolean): Boolean = indexWhere(p) != -1
+
+ /** Finds the first char of the string satisfying a predicate, if any.
+ *
+ * @param p the predicate used to test elements.
+ * @return an option value containing the first element in the string
+ * that satisfies `p`, or `None` if none exists.
+ */
+ def find(p: Char => Boolean): Option[Char] = indexWhere(p) match {
+ case -1 => None
+ case i => Some(s.charAt(i))
+ }
+
+ /** Drops longest prefix of chars that satisfy a predicate.
+ *
+ * @param p The predicate used to test elements.
+ * @return the longest suffix of this string whose first element
+ * does not satisfy the predicate `p`.
+ */
+ def dropWhile(p: Char => Boolean): String = indexWhere(c => !p(c)) match {
+ case -1 => ""
+ case i => s.substring(i)
+ }
+
+ /** Takes longest prefix of chars that satisfy a predicate. */
+ def takeWhile(p: Char => Boolean): String = indexWhere(c => !p(c)) match {
+ case -1 => s
+ case i => s.substring(0, i)
+ }
+
+ /** Splits this string into two at a given position.
+ * Note: `c splitAt n` is equivalent to `(c take n, c drop n)`.
+ *
+ * @param n the position at which to split.
+ * @return a pair of strings consisting of the first `n`
+ * chars of this string, and the other chars.
+ * @note $unicodeunaware
+ */
+ def splitAt(n: Int): (String, String) = (take(n), drop(n))
+
+ /** Splits this string into a prefix/suffix pair according to a predicate.
+ *
+ * Note: `c span p` is equivalent to (but more efficient than)
+ * `(c takeWhile p, c dropWhile p)`, provided the evaluation of the
+ * predicate `p` does not cause any side-effects.
+ *
+ * @param p the test predicate
+ * @return a pair consisting of the longest prefix of this string whose
+ * chars all satisfy `p`, and the rest of this string.
+ */
+ def span(p: Char => Boolean): (String, String) = indexWhere(c => !p(c)) match {
+ case -1 => (s, "")
+ case i => (s.substring(0, i), s.substring(i))
+ }
+
+ /** Partitions elements in fixed size strings.
+ * @see [[scala.collection.Iterator]], method `grouped`
+ *
+ * @param size the number of elements per group
+ * @return An iterator producing strings of size `size`, except the
+ * last will be less than size `size` if the elements don't divide evenly.
+ * @note $unicodeunaware
+ */
+ def grouped(size: Int): Iterator[String] = new StringOps.GroupedIterator(s, size)
+
+ /** A pair of, first, all chars that satisfy predicate `p` and, second, all chars that do not. */
+ def partition(p: Char => Boolean): (String, String) = {
+ val res1, res2 = new JStringBuilder
+ var i = 0
+ val len = s.length
+ while(i < len) {
+ val x = s.charAt(i)
+ (if(p(x)) res1 else res2).append(x)
+ i += 1
+ }
+ (res1.toString, res2.toString)
+ }
+
+ /** Applies a function `f` to each character of the string and returns a pair of strings: the first one
+ * made of those characters returned by `f` that were wrapped in [[scala.util.Left]], and the second
+ * one made of those wrapped in [[scala.util.Right]].
+ *
+ * Example:
+ * {{{
+ * val xs = "1one2two3three" partitionMap { c =>
+ * if (c > 'a') Left(c) else Right(c)
+ * }
+ * // xs == ("onetwothree", "123")
+ * }}}
+ *
+ * @param f the 'split function' mapping the elements of this string to an [[scala.util.Either]]
+ *
+ * @return a pair of strings: the first one made of those characters returned by `f` that were wrapped in [[scala.util.Left]],
+ * and the second one made of those wrapped in [[scala.util.Right]].
+ */
+ def partitionMap(f: Char => Either[Char,Char]): (String, String) = {
+ val res1, res2 = new JStringBuilder
+ var i = 0
+ val len = s.length
+ while(i < len) {
+ f(s.charAt(i)) match {
+ case Left(c) => res1.append(c)
+ case Right(c) => res2.append(c)
+ }
+ i += 1
+ }
+ (res1.toString, res2.toString)
+ }
+
+ /** Analogous to `zip` except that the elements in each collection are not consumed until a strict operation is
+ * invoked on the returned `LazyZip2` decorator.
+ *
+ * Calls to `lazyZip` can be chained to support higher arities (up to 4) without incurring the expense of
+ * constructing and deconstructing intermediary tuples.
+ *
+ * {{{
+ * val xs = List(1, 2, 3)
+ * val res = (xs lazyZip xs lazyZip xs lazyZip xs).map((a, b, c, d) => a + b + c + d)
+ * // res == List(4, 8, 12)
+ * }}}
+ *
+ * @param that the iterable providing the second element of each eventual pair
+ * @tparam B the type of the second element in each eventual pair
+ * @return a decorator `LazyZip2` that allows strict operations to be performed on the lazily evaluated pairs
+ * or chained calls to `lazyZip`. Implicit conversion to `Iterable[(A, B)]` is also supported.
+ */
+ def lazyZip[B](that: Iterable[B]): LazyZip2[Char, B, String] = new LazyZip2(s, new WrappedString(s), that)
+
+
+ /* ************************************************************************************************************
+ The remaining methods are provided for completeness but they delegate to WrappedString implementations which
+ may not provide the best possible performance. We need them in `StringOps` because their return type
+ mentions `C` (which is `String` in `StringOps` and `WrappedString` in `WrappedString`).
+ ************************************************************************************************************ */
+
+
+ /** Computes the multiset difference between this string and another sequence.
+ *
+ * @param that the sequence of chars to remove
+ * @return a new string which contains all chars of this string
+ * except some of occurrences of elements that also appear in `that`.
+ * If an element value `x` appears
+ * ''n'' times in `that`, then the first ''n'' occurrences of `x` will not form
+ * part of the result, but any following occurrences will.
+ * @note $unicodeunaware
+ */
+ def diff[B >: Char](that: Seq[B]): String = new WrappedString(s).diff(that).unwrap
+
+ /** Computes the multiset intersection between this string and another sequence.
+ *
+ * @param that the sequence of chars to intersect with.
+ * @return a new string which contains all chars of this string
+ * which also appear in `that`.
+ * If an element value `x` appears
+ * ''n'' times in `that`, then the first ''n'' occurrences of `x` will be retained
+ * in the result, but any following occurrences will be omitted.
+ * @note $unicodeunaware
+ */
+ def intersect[B >: Char](that: Seq[B]): String = new WrappedString(s).intersect(that).unwrap
+
+ /** Selects all distinct chars of this string ignoring the duplicates.
+ *
+ * @note $unicodeunaware
+ */
+ def distinct: String = new WrappedString(s).distinct.unwrap
+
+ /** Selects all distinct chars of this string ignoring the duplicates as determined by `==` after applying
+ * the transforming function `f`.
+ *
+ * @param f The transforming function whose result is used to determine the uniqueness of each element
+ * @tparam B the type of the elements after being transformed by `f`
+ * @return a new string consisting of all the chars of this string without duplicates.
+ * @note $unicodeunaware
+ */
+ def distinctBy[B](f: Char => B): String = new WrappedString(s).distinctBy(f).unwrap
+
+ /** Sorts the characters of this string according to an Ordering.
+ *
+ * The sort is stable. That is, elements that are equal (as determined by
+ * `ord.compare`) appear in the same order in the sorted sequence as in the original.
+ *
+ * @see [[scala.math.Ordering]]
+ *
+ * @param ord the ordering to be used to compare elements.
+ * @return a string consisting of the chars of this string
+ * sorted according to the ordering `ord`.
+ * @note $unicodeunaware
+ */
+ def sorted[B >: Char](implicit ord: Ordering[B]): String = new WrappedString(s).sorted(ord).unwrap
+
+ /** Sorts this string according to a comparison function.
+ *
+ * The sort is stable. That is, elements that are equal (as determined by
+ * `lt`) appear in the same order in the sorted sequence as in the original.
+ *
+ * @param lt the comparison function which tests whether
+ * its first argument precedes its second argument in
+ * the desired ordering.
+ * @return a string consisting of the elements of this string
+ * sorted according to the comparison function `lt`.
+ * @note $unicodeunaware
+ */
+ def sortWith(lt: (Char, Char) => Boolean): String = new WrappedString(s).sortWith(lt).unwrap
+
+ /** Sorts this string according to the Ordering which results from transforming
+ * an implicitly given Ordering with a transformation function.
+ *
+ * The sort is stable. That is, elements that are equal (as determined by
+ * `ord.compare`) appear in the same order in the sorted sequence as in the original.
+ *
+ * @see [[scala.math.Ordering]]
+ * @param f the transformation function mapping elements
+ * to some other domain `B`.
+ * @param ord the ordering assumed on domain `B`.
+ * @tparam B the target type of the transformation `f`, and the type where
+ * the ordering `ord` is defined.
+ * @return a string consisting of the chars of this string
+ * sorted according to the ordering where `x < y` if
+ * `ord.lt(f(x), f(y))`.
+ * @note $unicodeunaware
+ */
+ def sortBy[B](f: Char => B)(implicit ord: Ordering[B]): String = new WrappedString(s).sortBy(f)(ord).unwrap
+
+ /** Partitions this string into a map of strings according to some discriminator function.
+ *
+ * @param f the discriminator function.
+ * @tparam K the type of keys returned by the discriminator function.
+ * @return A map from keys to strings such that the following invariant holds:
+ * {{{
+ * (xs groupBy f)(k) = xs filter (x => f(x) == k)
+ * }}}
+ * That is, every key `k` is bound to a string of those elements `x`
+ * for which `f(x)` equals `k`.
+ * @note $unicodeunaware
+ */
+ def groupBy[K](f: Char => K): immutable.Map[K, String] = new WrappedString(s).groupBy(f).view.mapValues(_.unwrap).toMap
+
+ /** Groups chars in fixed size blocks by passing a "sliding window"
+ * over them (as opposed to partitioning them, as is done in grouped.)
+ * @see [[scala.collection.Iterator]], method `sliding`
+ *
+ * @param size the number of chars per group
+ * @param step the distance between the first chars of successive groups
+ * @return An iterator producing strings of size `size`, except the
+ * last element (which may be the only element) will be truncated
+ * if there are fewer than `size` chars remaining to be grouped.
+ * @note $unicodeunaware
+ */
+ def sliding(size: Int, step: Int = 1): Iterator[String] = new WrappedString(s).sliding(size, step).map(_.unwrap)
+
+ /** Iterates over combinations of elements.
+ *
+ * A '''combination''' of length `n` is a sequence of `n` elements selected in order of their first index in this sequence.
+ *
+ * For example, `"xyx"` has two combinations of length 2. The `x` is selected first: `"xx"`, `"xy"`.
+ * The sequence `"yx"` is not returned as a combination because it is subsumed by `"xy"`.
+ *
+ * If there is more than one way to generate the same combination, only one will be returned.
+ *
+ * For example, the result `"xy"` arbitrarily selected one of the `x` elements.
+ *
+ * As a further illustration, `"xyxx"` has three different ways to generate `"xy"` because there are three elements `x`
+ * to choose from. Moreover, there are three unordered pairs `"xx"` but only one is returned.
+ *
+ * It is not specified which of these equal combinations is returned. It is an implementation detail
+ * that should not be relied on. For example, the combination `"xx"` does not necessarily contain
+ * the first `x` in this sequence. This behavior is observable if the elements compare equal
+ * but are not identical.
+ *
+ * As a consequence, `"xyx".combinations(3).next()` is `"xxy"`: the combination does not reflect the order
+ * of the original sequence, but the order in which elements were selected, by "first index";
+ * the order of each `x` element is also arbitrary.
+ *
+ * @return An Iterator which traverses the n-element combinations of this string.
+ * @example {{{
+ * "abbbc".combinations(2).foreach(println)
+ * // ab
+ * // ac
+ * // bb
+ * // bc
+ * "bab".combinations(2).foreach(println)
+ * // bb
+ * // ba
+ * }}}
+ * @note $unicodeunaware
+ */
+ def combinations(n: Int): Iterator[String] = new WrappedString(s).combinations(n).map(_.unwrap)
+
+ /** Iterates over distinct permutations of elements.
+ *
+ * @return An Iterator which traverses the distinct permutations of this string.
+ * @example {{{
+ * "abb".permutations.foreach(println)
+ * // abb
+ * // bab
+ * // bba
+ * }}}
+ * @note $unicodeunaware
+ */
+ def permutations: Iterator[String] = new WrappedString(s).permutations.map(_.unwrap)
+}
+
+final case class StringView(s: String) extends AbstractIndexedSeqView[Char] {
+ def length = s.length
+ @throws[StringIndexOutOfBoundsException]
+ def apply(n: Int) = s.charAt(n)
+ override def toString: String = s"StringView($s)"
+}
diff --git a/library/src/scala/collection/StringParsers.scala b/library/src/scala/collection/StringParsers.scala
new file mode 100644
index 000000000000..36108dc539da
--- /dev/null
+++ b/library/src/scala/collection/StringParsers.scala
@@ -0,0 +1,321 @@
+/*
+ * 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 collection
+
+import scala.annotation.tailrec
+
+/** A module containing the implementations of parsers from strings to numeric types, and boolean
+ */
+private[scala] object StringParsers {
+
+ //compile-time constant helpers
+
+ //Int.MinValue == -2147483648
+ private final val intOverflowBoundary = -214748364
+ private final val intOverflowDigit = 9
+ //Long.MinValue == -9223372036854775808L
+ private final val longOverflowBoundary = -922337203685477580L
+ private final val longOverflowDigit = 9
+
+ private final val POS = true
+
+ @inline
+ private[this] final def decValue(ch: Char): Int = java.lang.Character.digit(ch, 10)
+
+ @inline
+ private[this] final def stepToOverflow(from: String, len: Int, agg: Int, isPositive: Boolean, min: Int): Option[Int] = {
+ @tailrec
+ def rec(i: Int, agg: Int): Option[Int] =
+ if (agg < min) None
+ else if (i == len) {
+ if (!isPositive) Some(agg)
+ else if (agg == min) None
+ else Some(-agg)
+ }
+ else {
+ val digit = decValue(from.charAt(i))
+ if (digit == -1) None
+ else rec(i + 1, agg * 10 - digit)
+ }
+ rec(1, agg)
+ }
+
+ @inline
+ private[this] final def isDigit(c: Char): Boolean = c >= '0' && c <= '9'
+
+ //bool
+ @inline
+ final def parseBool(from: String): Option[Boolean] =
+ if (from.equalsIgnoreCase("true")) Some(true)
+ else if (from.equalsIgnoreCase("false")) Some(false)
+ else None
+
+ //integral types
+ final def parseByte(from: String): Option[Byte] = {
+ val len = from.length()
+ //empty strings parse to None
+ if (len == 0) None
+ else {
+ val first = from.charAt(0)
+ val v = decValue(first)
+ if (len == 1) {
+ //"+" and "-" parse to None
+ if (v > -1) Some(v.toByte)
+ else None
+ }
+ else if (v > -1) stepToOverflow(from, len, -v, POS, Byte.MinValue).map(_.toByte)
+ else if (first == '+') stepToOverflow(from, len, 0, POS, Byte.MinValue).map(_.toByte)
+ else if (first == '-') stepToOverflow(from, len, 0, !POS, Byte.MinValue).map(_.toByte)
+ else None
+ }
+ }
+
+ final def parseShort(from: String): Option[Short] = {
+ val len = from.length()
+ //empty strings parse to None
+ if (len == 0) None
+ else {
+ val first = from.charAt(0)
+ val v = decValue(first)
+ if (len == 1) {
+ //"+" and "-" parse to None
+ if (v > -1) Some(v.toShort)
+ else None
+ }
+ else if (v > -1) stepToOverflow(from, len, -v, POS, Short.MinValue).map(_.toShort)
+ else if (first == '+') stepToOverflow(from, len, 0, POS, Short.MinValue).map(_.toShort)
+ else if (first == '-') stepToOverflow(from, len, 0, !POS, Short.MinValue).map(_.toShort)
+ else None
+ }
+ }
+
+ final def parseInt(from: String): Option[Int] = {
+ val len = from.length()
+
+ @tailrec
+ def step(i: Int, agg: Int, isPositive: Boolean): Option[Int] = {
+ if (i == len) {
+ if (!isPositive) Some(agg)
+ else if (agg == Int.MinValue) None
+ else Some(-agg)
+ }
+ else if (agg < intOverflowBoundary) None
+ else {
+ val digit = decValue(from.charAt(i))
+ if (digit == -1 || (agg == intOverflowBoundary && digit == intOverflowDigit)) None
+ else step(i + 1, (agg * 10) - digit, isPositive)
+ }
+ }
+ //empty strings parse to None
+ if (len == 0) None
+ else {
+ val first = from.charAt(0)
+ val v = decValue(first)
+ if (len == 1) {
+ //"+" and "-" parse to None
+ if (v > -1) Some(v)
+ else None
+ }
+ else if (v > -1) step(1, -v, POS)
+ else if (first == '+') step(1, 0, POS)
+ else if (first == '-') step(1, 0, !POS)
+ else None
+ }
+ }
+
+ final def parseLong(from: String): Option[Long] = {
+ //like parseInt, but Longer
+ val len = from.length()
+
+ @tailrec
+ def step(i: Int, agg: Long, isPositive: Boolean): Option[Long] = {
+ if (i == len) {
+ if (isPositive && agg == Long.MinValue) None
+ else if (isPositive) Some(-agg)
+ else Some(agg)
+ }
+ else if (agg < longOverflowBoundary) None
+ else {
+ val digit = decValue(from.charAt(i))
+ if (digit == -1 || (agg == longOverflowBoundary && digit == longOverflowDigit)) None
+ else step(i + 1, agg * 10 - digit, isPositive)
+ }
+ }
+ //empty strings parse to None
+ if (len == 0) None
+ else {
+ val first = from.charAt(0)
+ val v = decValue(first).toLong
+ if (len == 1) {
+ //"+" and "-" parse to None
+ if (v > -1) Some(v)
+ else None
+ }
+ else if (v > -1) step(1, -v, POS)
+ else if (first == '+') step(1, 0, POS)
+ else if (first == '-') step(1, 0, !POS)
+ else None
+ }
+ }
+
+ //floating point
+ final def checkFloatFormat(format: String): Boolean = {
+ //indices are tracked with a start index which points *at* the first index
+ //and an end index which points *after* the last index
+ //so that slice length === end - start
+ //thus start == end <=> empty slice
+ //and format.substring(start, end) is equivalent to the slice
+
+ //some utilities for working with index bounds into the original string
+ @inline
+ def forAllBetween(start: Int, end: Int, pred: Char => Boolean): Boolean = {
+ @tailrec
+ def rec(i: Int): Boolean = i >= end || pred(format.charAt(i)) && rec(i + 1)
+ rec(start)
+ }
+
+ //one after last index for the predicate to hold, or `from` if none hold
+ //may point after the end of the string
+ @inline
+ def skipIndexWhile(predicate: Char => Boolean, from: Int, until: Int): Int = {
+ @tailrec @inline
+ def rec(i: Int): Int = if ((i < until) && predicate(format.charAt(i))) rec(i + 1)
+ else i
+ rec(from)
+ }
+
+
+ def isHexFloatLiteral(startIndex: Int, endIndex: Int): Boolean = {
+ def isHexDigit(ch: Char) = ((ch >= '0' && ch <= '9') ||
+ (ch >= 'a' && ch <= 'f') ||
+ (ch >= 'A' && ch <= 'F'))
+
+ def prefixOK(startIndex: Int, endIndex: Int): Boolean = {
+ val len = endIndex - startIndex
+ (len > 0) && {
+ //the prefix part is
+ //hexDigits
+ //hexDigits.
+ //hexDigits.hexDigits
+ //.hexDigits
+ //but not .
+ if (format.charAt(startIndex) == '.') {
+ (len > 1) && forAllBetween(startIndex + 1, endIndex, isHexDigit)
+ } else {
+ val noLeading = skipIndexWhile(isHexDigit, startIndex, endIndex)
+ (noLeading >= endIndex) ||
+ ((format.charAt(noLeading) == '.') && forAllBetween(noLeading + 1, endIndex, isHexDigit))
+ }
+ }
+ }
+
+ def postfixOK(startIndex: Int, endIndex: Int): Boolean =
+ (startIndex < endIndex) && {
+ (forAllBetween(startIndex, endIndex, isDigit)) || {
+ val startchar = format.charAt(startIndex)
+ (startchar == '+' || startchar == '-') &&
+ (endIndex - startIndex > 1) &&
+ forAllBetween(startIndex + 1, endIndex, isDigit)
+ }
+ }
+ // prefix [pP] postfix
+ val pIndex = format.indexWhere(ch => ch == 'p' || ch == 'P', startIndex)
+ (pIndex <= endIndex) && prefixOK(startIndex, pIndex) && postfixOK(pIndex + 1, endIndex)
+ }
+
+ def isDecFloatLiteral(startIndex: Int, endIndex: Int): Boolean = {
+ //invariant: endIndex > startIndex
+
+ def isExp(c: Char): Boolean = c == 'e' || c == 'E'
+
+ def expOK(startIndex: Int, endIndex: Int): Boolean =
+ (startIndex < endIndex) && {
+ val startChar = format.charAt(startIndex)
+ if (startChar == '+' || startChar == '-')
+ (endIndex > (startIndex + 1)) &&
+ skipIndexWhile(isDigit, startIndex + 1, endIndex) == endIndex
+ else skipIndexWhile(isDigit, startIndex, endIndex) == endIndex
+ }
+
+ //significant can be one of
+ //* digits.digits
+ //* .digits
+ //* digits.
+ //but not just .
+ val startChar = format.charAt(startIndex)
+ if (startChar == '.') {
+ val noSignificant = skipIndexWhile(isDigit, startIndex + 1, endIndex)
+ // a digit is required followed by optional exp
+ (noSignificant > startIndex + 1) && (noSignificant >= endIndex ||
+ isExp(format.charAt(noSignificant)) && expOK(noSignificant + 1, endIndex)
+ )
+ }
+ else if (isDigit(startChar)) {
+ // one set of digits, then optionally a period, then optionally another set of digits, then optionally an exponent
+ val noInt = skipIndexWhile(isDigit, startIndex, endIndex)
+ // just the digits
+ (noInt == endIndex) || {
+ if (format.charAt(noInt) == '.') {
+ val noSignificant = skipIndexWhile(isDigit, noInt + 1, endIndex)
+ (noSignificant >= endIndex) || //no exponent
+ isExp(format.charAt(noSignificant)) && expOK(noSignificant + 1, endIndex)
+ } else
+ isExp(format.charAt(noInt)) && expOK(noInt + 1, endIndex)
+ }
+ }
+ else false
+ }
+
+ //count 0x00 to 0x20 as "whitespace", and nothing else
+ val unspacedStart = format.indexWhere(ch => ch.toInt > 0x20)
+ val unspacedEnd = format.lastIndexWhere(ch => ch.toInt > 0x20) + 1
+
+ if (unspacedStart == -1 || unspacedStart >= unspacedEnd || unspacedEnd <= 0) false
+ else {
+ //all formats can have a sign
+ val unsigned = {
+ val startchar = format.charAt(unspacedStart)
+ if (startchar == '-' || startchar == '+') unspacedStart + 1 else unspacedStart
+ }
+ if (unsigned >= unspacedEnd) false
+ //that's it for NaN and Infinity
+ else if (format.charAt(unsigned) == 'N') format.substring(unsigned, unspacedEnd) == "NaN"
+ else if (format.charAt(unsigned) == 'I') format.substring(unsigned, unspacedEnd) == "Infinity"
+ else {
+ //all other formats can have a format suffix
+ val desuffixed = {
+ val endchar = format.charAt(unspacedEnd - 1)
+ if (endchar == 'f' || endchar == 'F' || endchar == 'd' || endchar == 'D') unspacedEnd - 1
+ else unspacedEnd
+ }
+ val len = desuffixed - unsigned
+ if (len <= 0) false
+ else if (len >= 2 && (format.charAt(unsigned + 1) == 'x' || format.charAt(unsigned + 1) == 'X'))
+ format.charAt(unsigned) == '0' && isHexFloatLiteral(unsigned + 2, desuffixed)
+ else isDecFloatLiteral(unsigned, desuffixed)
+ }
+ }
+ }
+
+ @inline
+ def parseFloat(from: String): Option[Float] =
+ if (checkFloatFormat(from)) Some(java.lang.Float.parseFloat(from))
+ else None
+
+ @inline
+ def parseDouble(from: String): Option[Double] =
+ if (checkFloatFormat(from)) Some(java.lang.Double.parseDouble(from))
+ else None
+
+}
diff --git a/library/src/scala/collection/View.scala b/library/src/scala/collection/View.scala
new file mode 100644
index 000000000000..f304b8931f14
--- /dev/null
+++ b/library/src/scala/collection/View.scala
@@ -0,0 +1,535 @@
+/*
+ * 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 scala.annotation.{nowarn, tailrec}
+import scala.collection.mutable.{ArrayBuffer, Builder}
+import scala.collection.immutable.LazyList
+
+/** Views are collections whose transformation operations are non strict: the resulting elements
+ * are evaluated only when the view is effectively traversed (e.g. using `foreach` or `foldLeft`),
+ * or when the view is converted to a strict collection type (using the `to` operation).
+ * @define coll view
+ * @define Coll `View`
+ */
+trait View[+A] extends Iterable[A] with IterableOps[A, View, View[A]] with IterableFactoryDefaults[A, View] with Serializable {
+
+ override def view: View[A] = this
+
+ override def iterableFactory: IterableFactory[View] = View
+
+ override def empty: scala.collection.View[A] = iterableFactory.empty
+
+ override def toString: String = className + "()"
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix: String = "View"
+
+ @deprecated("Views no longer know about their underlying collection type; .force always returns an IndexedSeq", "2.13.0")
+ @`inline` def force: IndexedSeq[A] = toIndexedSeq
+}
+
+/** This object reifies operations on views as case classes
+ *
+ * @define Coll View
+ * @define coll view
+ */
+@SerialVersionUID(3L)
+object View extends IterableFactory[View] {
+
+ /**
+ * @return A `View[A]` whose underlying iterator is provided by the `it` parameter-less function.
+ *
+ * @param it Function creating the iterator to be used by the view. This function must always return
+ * a fresh `Iterator`, otherwise the resulting view will be effectively iterable only once.
+ *
+ * @tparam A View element type
+ */
+ def fromIteratorProvider[A](it: () => Iterator[A]): View[A] = new AbstractView[A] {
+ def iterator = it()
+ }
+
+ /**
+ * @return A view iterating over the given `Iterable`
+ *
+ * @param it The `IterableOnce` to view. A proper `Iterable` is used directly. If it is really only
+ * `IterableOnce` it gets memoized on the first traversal.
+ *
+ * @tparam E View element type
+ */
+ def from[E](it: IterableOnce[E]): View[E] = it match {
+ case it: View[E] => it
+ case it: Iterable[E] => View.fromIteratorProvider(() => it.iterator)
+ case _ => LazyList.from(it).view
+ }
+
+ def empty[A]: View[A] = Empty
+
+ def newBuilder[A]: Builder[A, View[A]] = ArrayBuffer.newBuilder[A].mapResult(from)
+
+ override def apply[A](xs: A*): View[A] = new Elems(xs: _*)
+
+ /** The empty view */
+ @SerialVersionUID(3L)
+ case object Empty extends AbstractView[Nothing] {
+ def iterator = Iterator.empty
+ override def knownSize = 0
+ override def isEmpty: Boolean = true
+ }
+
+ /** A view with exactly one element */
+ @SerialVersionUID(3L)
+ class Single[A](a: A) extends AbstractView[A] {
+ def iterator: Iterator[A] = Iterator.single(a)
+ override def knownSize: Int = 1
+ override def isEmpty: Boolean = false
+ }
+
+ /** A view with given elements */
+ @SerialVersionUID(3L)
+ class Elems[A](xs: A*) extends AbstractView[A] {
+ def iterator = xs.iterator
+ override def knownSize = xs.knownSize
+ override def isEmpty: Boolean = xs.isEmpty
+ }
+
+ /** A view containing the results of some element computation a number of times. */
+ @SerialVersionUID(3L)
+ class Fill[A](n: Int)(elem: => A) extends AbstractView[A] {
+ def iterator = Iterator.fill(n)(elem)
+ override def knownSize: Int = 0 max n
+ override def isEmpty: Boolean = n <= 0
+ }
+
+ /** A view containing values of a given function over a range of integer values starting from 0. */
+ @SerialVersionUID(3L)
+ class Tabulate[A](n: Int)(f: Int => A) extends AbstractView[A] {
+ def iterator: Iterator[A] = Iterator.tabulate(n)(f)
+ override def knownSize: Int = 0 max n
+ override def isEmpty: Boolean = n <= 0
+ }
+
+ /** A view containing repeated applications of a function to a start value */
+ @SerialVersionUID(3L)
+ class Iterate[A](start: A, len: Int)(f: A => A) extends AbstractView[A] {
+ def iterator: Iterator[A] = Iterator.iterate(start)(f).take(len)
+ override def knownSize: Int = 0 max len
+ override def isEmpty: Boolean = len <= 0
+ }
+
+ /** A view that uses a function `f` to produce elements of type `A` and update
+ * an internal state `S`.
+ */
+ @SerialVersionUID(3L)
+ class Unfold[A, S](initial: S)(f: S => Option[(A, S)]) extends AbstractView[A] {
+ def iterator: Iterator[A] = Iterator.unfold(initial)(f)
+ }
+
+ /** An `IterableOps` whose collection type and collection type constructor are unknown */
+ type SomeIterableOps[A] = IterableOps[A, AnyConstr, _]
+
+ /** A view that filters an underlying collection. */
+ @SerialVersionUID(3L)
+ class Filter[A](val underlying: SomeIterableOps[A], val p: A => Boolean, val isFlipped: Boolean) extends AbstractView[A] {
+ def iterator = underlying.iterator.filterImpl(p, isFlipped)
+ override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = iterator.isEmpty
+ }
+
+ object Filter {
+ def apply[A](underlying: Iterable[A], p: A => Boolean, isFlipped: Boolean): Filter[A] =
+ underlying match {
+ case filter: Filter[A] if filter.isFlipped == isFlipped => new Filter(filter.underlying, a => filter.p(a) && p(a), isFlipped)
+ case _ => new Filter(underlying, p, isFlipped)
+ }
+ }
+
+ /** A view that removes the duplicated elements as determined by the transformation function `f` */
+ @SerialVersionUID(3L)
+ class DistinctBy[A, B](underlying: SomeIterableOps[A], f: A => B) extends AbstractView[A] {
+ def iterator: Iterator[A] = underlying.iterator.distinctBy(f)
+ override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = underlying.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ class LeftPartitionMapped[A, A1, A2](underlying: SomeIterableOps[A], f: A => Either[A1, A2]) extends AbstractView[A1] {
+ def iterator: AbstractIterator[A1] = new AbstractIterator[A1] {
+ private[this] val self = underlying.iterator
+ private[this] var hd: A1 = _
+ private[this] var hdDefined: Boolean = false
+ def hasNext = hdDefined || {
+ @tailrec
+ def findNext(): Boolean =
+ if (self.hasNext) {
+ f(self.next()) match {
+ case Left(a1) => hd = a1; hdDefined = true; true
+ case Right(_) => findNext()
+ }
+ } else false
+ findNext()
+ }
+ def next() =
+ if (hasNext) {
+ hdDefined = false
+ hd
+ } else Iterator.empty.next()
+ }
+ }
+
+ @SerialVersionUID(3L)
+ class RightPartitionMapped[A, A1, A2](underlying: SomeIterableOps[A], f: A => Either[A1, A2]) extends AbstractView[A2] {
+ def iterator: AbstractIterator[A2] = new AbstractIterator[A2] {
+ private[this] val self = underlying.iterator
+ private[this] var hd: A2 = _
+ private[this] var hdDefined: Boolean = false
+ def hasNext = hdDefined || {
+ @tailrec
+ def findNext(): Boolean =
+ if (self.hasNext) {
+ f(self.next()) match {
+ case Left(_) => findNext()
+ case Right(a2) => hd = a2; hdDefined = true; true
+ }
+ } else false
+ findNext()
+ }
+ def next() =
+ if (hasNext) {
+ hdDefined = false
+ hd
+ } else Iterator.empty.next()
+ }
+ }
+
+ /** A view that drops leading elements of the underlying collection. */
+ @SerialVersionUID(3L)
+ class Drop[A](underlying: SomeIterableOps[A], n: Int) extends AbstractView[A] {
+ def iterator = underlying.iterator.drop(n)
+ protected val normN = n max 0
+ override def knownSize = {
+ val size = underlying.knownSize
+ if (size >= 0) (size - normN) max 0 else -1
+ }
+ override def isEmpty: Boolean = iterator.isEmpty
+ }
+
+ /** A view that drops trailing elements of the underlying collection. */
+ @SerialVersionUID(3L)
+ class DropRight[A](underlying: SomeIterableOps[A], n: Int) extends AbstractView[A] {
+ def iterator = dropRightIterator(underlying.iterator, n)
+ protected val normN = n max 0
+ override def knownSize = {
+ val size = underlying.knownSize
+ if (size >= 0) (size - normN) max 0 else -1
+ }
+ override def isEmpty: Boolean =
+ if(knownSize >= 0) knownSize == 0
+ else iterator.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ class DropWhile[A](underlying: SomeIterableOps[A], p: A => Boolean) extends AbstractView[A] {
+ def iterator = underlying.iterator.dropWhile(p)
+ override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = iterator.isEmpty
+ }
+
+ /** A view that takes leading elements of the underlying collection. */
+ @SerialVersionUID(3L)
+ class Take[+A](underlying: SomeIterableOps[A], n: Int) extends AbstractView[A] {
+ def iterator = underlying.iterator.take(n)
+ protected val normN = n max 0
+ override def knownSize = {
+ val size = underlying.knownSize
+ if (size >= 0) size min normN else -1
+ }
+ override def isEmpty: Boolean = iterator.isEmpty
+ }
+
+ /** A view that takes trailing elements of the underlying collection. */
+ @SerialVersionUID(3L)
+ class TakeRight[+A](underlying: SomeIterableOps[A], n: Int) extends AbstractView[A] {
+ def iterator = takeRightIterator(underlying.iterator, n)
+ protected val normN = n max 0
+ override def knownSize = {
+ val size = underlying.knownSize
+ if (size >= 0) size min normN else -1
+ }
+ override def isEmpty: Boolean =
+ if(knownSize >= 0) knownSize == 0
+ else iterator.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ class TakeWhile[A](underlying: SomeIterableOps[A], p: A => Boolean) extends AbstractView[A] {
+ def iterator: Iterator[A] = underlying.iterator.takeWhile(p)
+ override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = iterator.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ class ScanLeft[+A, +B](underlying: SomeIterableOps[A], z: B, op: (B, A) => B) extends AbstractView[B] {
+ def iterator: Iterator[B] = underlying.iterator.scanLeft(z)(op)
+ override def knownSize: Int = {
+ val size = underlying.knownSize
+ if (size >= 0) size + 1 else -1
+ }
+ override def isEmpty: Boolean = iterator.isEmpty
+ }
+
+ /** A view that maps elements of the underlying collection. */
+ @SerialVersionUID(3L)
+ class Map[+A, +B](underlying: SomeIterableOps[A], f: A => B) extends AbstractView[B] {
+ def iterator = underlying.iterator.map(f)
+ override def knownSize = underlying.knownSize
+ override def isEmpty: Boolean = underlying.isEmpty
+ }
+
+ /** A view that flatmaps elements of the underlying collection. */
+ @SerialVersionUID(3L)
+ class FlatMap[A, B](underlying: SomeIterableOps[A], f: A => IterableOnce[B]) extends AbstractView[B] {
+ def iterator = underlying.iterator.flatMap(f)
+ override def knownSize: Int = if (underlying.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = iterator.isEmpty
+ }
+
+ /** A view that collects elements of the underlying collection. */
+ @SerialVersionUID(3L)
+ class Collect[+A, B](underlying: SomeIterableOps[A], pf: PartialFunction[A, B]) extends AbstractView[B] {
+ def iterator = underlying.iterator.collect(pf)
+ }
+
+ /** A view that concatenates elements of the prefix collection or iterator with the elements
+ * of the suffix collection or iterator.
+ */
+ @SerialVersionUID(3L)
+ class Concat[A](prefix: SomeIterableOps[A], suffix: SomeIterableOps[A]) extends AbstractView[A] {
+ def iterator = prefix.iterator ++ suffix.iterator
+ override def knownSize = {
+ val prefixSize = prefix.knownSize
+ if (prefixSize >= 0) {
+ val suffixSize = suffix.knownSize
+ if (suffixSize >= 0) prefixSize + suffixSize
+ else -1
+ }
+ else -1
+ }
+ override def isEmpty: Boolean = prefix.isEmpty && suffix.isEmpty
+ }
+
+ /** A view that zips elements of the underlying collection with the elements
+ * of another collection.
+ */
+ @SerialVersionUID(3L)
+ class Zip[A, B](underlying: SomeIterableOps[A], other: Iterable[B]) extends AbstractView[(A, B)] {
+ def iterator = underlying.iterator.zip(other)
+ override def knownSize = {
+ val s1 = underlying.knownSize
+ if (s1 == 0) 0 else {
+ val s2 = other.knownSize
+ if (s2 == 0) 0 else s1 min s2
+ }
+ }
+ override def isEmpty: Boolean = underlying.isEmpty || other.isEmpty
+ }
+
+ /** A view that zips elements of the underlying collection with the elements
+ * of another collection. If one of the two collections is shorter than the other,
+ * placeholder elements are used to extend the shorter collection to the length of the longer.
+ */
+ @SerialVersionUID(3L)
+ class ZipAll[A, B](underlying: SomeIterableOps[A], other: Iterable[B], thisElem: A, thatElem: B) extends AbstractView[(A, B)] {
+ def iterator = underlying.iterator.zipAll(other, thisElem, thatElem)
+ override def knownSize = {
+ val s1 = underlying.knownSize
+ if(s1 == -1) -1 else {
+ val s2 = other.knownSize
+ if(s2 == -1) -1 else s1 max s2
+ }
+ }
+ override def isEmpty: Boolean = underlying.isEmpty && other.isEmpty
+ }
+
+ /** A view that appends an element to its elements */
+ @SerialVersionUID(3L)
+ class Appended[+A](underlying: SomeIterableOps[A], elem: A) extends AbstractView[A] {
+ def iterator: Iterator[A] = new Concat(underlying, new View.Single(elem)).iterator
+ override def knownSize: Int = {
+ val size = underlying.knownSize
+ if (size >= 0) size + 1 else -1
+ }
+ override def isEmpty: Boolean = false
+ }
+
+ /** A view that prepends an element to its elements */
+ @SerialVersionUID(3L)
+ class Prepended[+A](elem: A, underlying: SomeIterableOps[A]) extends AbstractView[A] {
+ def iterator: Iterator[A] = new Concat(new View.Single(elem), underlying).iterator
+ override def knownSize: Int = {
+ val size = underlying.knownSize
+ if (size >= 0) size + 1 else -1
+ }
+ override def isEmpty: Boolean = false
+ }
+
+ @SerialVersionUID(3L)
+ class Updated[A](underlying: SomeIterableOps[A], index: Int, elem: A) extends AbstractView[A] {
+ def iterator: Iterator[A] = new AbstractIterator[A] {
+ private[this] val it = underlying.iterator
+ private[this] var i = 0
+ def next(): A = {
+ val value = if (i == index) { it.next(); elem } else it.next()
+ i += 1
+ value
+ }
+ def hasNext: Boolean =
+ if(it.hasNext) true
+ else if(index >= i) throw new IndexOutOfBoundsException(index.toString)
+ else false
+ }
+ override def knownSize: Int = underlying.knownSize
+ override def isEmpty: Boolean = iterator.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ private[collection] class Patched[A](underlying: SomeIterableOps[A], from: Int, other: IterableOnce[A], replaced: Int) extends AbstractView[A] {
+ // we may be unable to traverse `other` more than once, so we need to cache it if that's the case
+ private val _other: Iterable[A] = other match {
+ case other: Iterable[A] => other
+ case other => LazyList.from(other)
+ }
+
+ def iterator: Iterator[A] = underlying.iterator.patch(from, _other.iterator, replaced)
+ override def knownSize: Int = if (underlying.knownSize == 0 && _other.knownSize == 0) 0 else super.knownSize
+ override def isEmpty: Boolean = if (knownSize == 0) true else iterator.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ class ZipWithIndex[A](underlying: SomeIterableOps[A]) extends AbstractView[(A, Int)] {
+ def iterator: Iterator[(A, Int)] = underlying.iterator.zipWithIndex
+ override def knownSize: Int = underlying.knownSize
+ override def isEmpty: Boolean = underlying.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ class PadTo[A](underlying: SomeIterableOps[A], len: Int, elem: A) extends AbstractView[A] {
+ def iterator: Iterator[A] = underlying.iterator.padTo(len, elem)
+
+ override def knownSize: Int = {
+ val size = underlying.knownSize
+ if (size >= 0) size max len else -1
+ }
+ override def isEmpty: Boolean = underlying.isEmpty && len <= 0
+ }
+
+ private[collection] def takeRightIterator[A](it: Iterator[A], n: Int): Iterator[A] = {
+ val k = it.knownSize
+ if(k == 0 || n <= 0) Iterator.empty
+ else if(n == Int.MaxValue) it
+ else if(k > 0) it.drop((k-n) max 0)
+ else new TakeRightIterator[A](it, n)
+ }
+
+ private final class TakeRightIterator[A](private[this] var underlying: Iterator[A], maxlen: Int) extends AbstractIterator[A] {
+ private[this] var len: Int = -1
+ private[this] var pos: Int = 0
+ private[this] var buf: ArrayBuffer[AnyRef] = _
+ def init(): Unit = if(buf eq null) {
+ buf = new ArrayBuffer[AnyRef](maxlen min 256)
+ len = 0
+ while(underlying.hasNext) {
+ val n = underlying.next().asInstanceOf[AnyRef]
+ if(pos >= buf.length) buf.addOne(n)
+ else buf(pos) = n
+ pos += 1
+ if(pos == maxlen) pos = 0
+ len += 1
+ }
+ underlying = null
+ if(len > maxlen) len = maxlen
+ pos = pos - len
+ if(pos < 0) pos += maxlen
+ }
+ override def knownSize = len
+ def hasNext: Boolean = {
+ init()
+ len > 0
+ }
+ def next(): A = {
+ init()
+ if(len == 0) Iterator.empty.next()
+ else {
+ val x = buf(pos).asInstanceOf[A]
+ pos += 1
+ if(pos == maxlen) pos = 0
+ len -= 1
+ x
+ }
+ }
+ override def drop(n: Int): Iterator[A] = {
+ init()
+ if (n > 0) {
+ len = (len - n) max 0
+ pos = (pos + n) % maxlen
+ }
+ this
+ }
+ }
+
+ private[collection] def dropRightIterator[A](it: Iterator[A], n: Int): Iterator[A] = {
+ if(n <= 0) it
+ else {
+ val k = it.knownSize
+ if(k >= 0) it.take(k - n)
+ else new DropRightIterator[A](it, n)
+ }
+ }
+
+ private final class DropRightIterator[A](private[this] var underlying: Iterator[A], maxlen: Int) extends AbstractIterator[A] {
+ private[this] var len: Int = -1 // known size or -1 if the end of `underlying` has not been seen yet
+ private[this] var pos: Int = 0
+ private[this] var buf: ArrayBuffer[AnyRef] = _
+ def init(): Unit = if(buf eq null) {
+ buf = new ArrayBuffer[AnyRef](maxlen min 256)
+ while(pos < maxlen && underlying.hasNext) {
+ buf.addOne(underlying.next().asInstanceOf[AnyRef])
+ pos += 1
+ }
+ if(!underlying.hasNext) len = 0
+ pos = 0
+ }
+ override def knownSize = len
+ def hasNext: Boolean = {
+ init()
+ len != 0
+ }
+ def next(): A = {
+ if(!hasNext) Iterator.empty.next()
+ else {
+ val x = buf(pos).asInstanceOf[A]
+ if(len == -1) {
+ buf(pos) = underlying.next().asInstanceOf[AnyRef]
+ if(!underlying.hasNext) len = 0
+ } else len -= 1
+ pos += 1
+ if(pos == maxlen) pos = 0
+ x
+ }
+ }
+ }
+}
+
+/** Explicit instantiation of the `View` trait to reduce class file size in subclasses. */
+@SerialVersionUID(3L)
+abstract class AbstractView[+A] extends scala.collection.AbstractIterable[A] with View[A]
diff --git a/library/src/scala/collection/WithFilter.scala b/library/src/scala/collection/WithFilter.scala
new file mode 100644
index 000000000000..7a68275336ff
--- /dev/null
+++ b/library/src/scala/collection/WithFilter.scala
@@ -0,0 +1,70 @@
+/*
+ * 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
+
+/** A template trait that contains just the `map`, `flatMap`, `foreach` and `withFilter` methods
+ * of trait `Iterable`.
+ *
+ * @tparam A Element type (e.g. `Int`)
+ * @tparam CC Collection type constructor (e.g. `List`)
+ *
+ * @define coll collection
+ */
+@SerialVersionUID(3L)
+abstract class WithFilter[+A, +CC[_]] extends Serializable {
+
+ /** Builds a new collection by applying a function to all elements of the
+ * `filtered` outer $coll.
+ *
+ * @param f the function to apply to each element.
+ * @tparam B the element type of the returned collection.
+ * @return a new $coll resulting from applying
+ * the given function `f` to each element of the filtered outer $coll
+ * and collecting the results.
+ */
+ def map[B](f: A => B): CC[B]
+
+ /** Builds a new collection by applying a function to all elements of the
+ * `filtered` outer $coll containing this `WithFilter` instance that satisfy
+ *
+ * @param f the function to apply to each element.
+ * @tparam B the element type of the returned collection.
+ * @return a new $coll resulting from applying
+ * the given collection-valued function `f` to each element
+ * of the filtered outer $coll and
+ * concatenating the results.
+ */
+ def flatMap[B](f: A => IterableOnce[B]): CC[B]
+
+ /** Applies a function `f` to all elements of the `filtered` outer $coll.
+ *
+ * @param f the function that is applied for its side-effect to every element.
+ * The result of function `f` is discarded.
+ *
+ * @tparam U the type parameter describing the result of function `f`.
+ * This result will always be ignored. Typically `U` is `Unit`,
+ * but this is not necessary.
+ */
+ def foreach[U](f: A => U): Unit
+
+ /** Further refines the filter for this `filtered` $coll.
+ *
+ * @param q the predicate used to test elements.
+ * @return an object of class `WithFilter`, which supports
+ * `map`, `flatMap`, `foreach`, and `withFilter` operations.
+ * All these operations apply to those elements of this $coll which
+ * also satisfy both `p` and `q` predicates.
+ */
+ def withFilter(q: A => Boolean): WithFilter[A, CC]
+
+}
diff --git a/library/src/scala/collection/concurrent/BasicNode.java b/library/src/scala/collection/concurrent/BasicNode.java
new file mode 100644
index 000000000000..b6a628d1295e
--- /dev/null
+++ b/library/src/scala/collection/concurrent/BasicNode.java
@@ -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.
+ */
+
+package scala.collection.concurrent;
+
+public abstract class BasicNode {
+
+ public abstract String string(int lev);
+
+}
diff --git a/library/src/scala/collection/concurrent/CNodeBase.java b/library/src/scala/collection/concurrent/CNodeBase.java
new file mode 100644
index 000000000000..4033c12af449
--- /dev/null
+++ b/library/src/scala/collection/concurrent/CNodeBase.java
@@ -0,0 +1,37 @@
+/*
+ * 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.concurrent;
+
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+
+abstract class CNodeBase extends MainNode {
+
+ @SuppressWarnings("unchecked")
+ public static final AtomicIntegerFieldUpdater> updater =
+ AtomicIntegerFieldUpdater.newUpdater((Class>) (Class>) CNodeBase.class, "csize");
+
+ public volatile int csize = -1;
+
+ public boolean CAS_SIZE(int oldval, int nval) {
+ return updater.compareAndSet(this, oldval, nval);
+ }
+
+ public void WRITE_SIZE(int nval) {
+ updater.set(this, nval);
+ }
+
+ public int READ_SIZE() {
+ return updater.get(this);
+ }
+
+}
diff --git a/library/src/scala/collection/concurrent/Gen.java b/library/src/scala/collection/concurrent/Gen.java
new file mode 100644
index 000000000000..548c1892321f
--- /dev/null
+++ b/library/src/scala/collection/concurrent/Gen.java
@@ -0,0 +1,15 @@
+/*
+ * 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.concurrent;
+
+final class Gen {}
diff --git a/library/src/scala/collection/concurrent/INodeBase.java b/library/src/scala/collection/concurrent/INodeBase.java
new file mode 100644
index 000000000000..b16265c68ea3
--- /dev/null
+++ b/library/src/scala/collection/concurrent/INodeBase.java
@@ -0,0 +1,39 @@
+/*
+ * 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.concurrent;
+
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+abstract class INodeBase extends BasicNode {
+
+ @SuppressWarnings("unchecked")
+ public static final AtomicReferenceFieldUpdater, MainNode, ?>> updater =
+ AtomicReferenceFieldUpdater.newUpdater((Class>) (Class>) INodeBase.class, (Class>) (Class>) MainNode.class, "mainnode");
+
+ static final Object RESTART = new Object();
+
+ static final Object NO_SUCH_ELEMENT_SENTINEL = new Object();
+
+ public volatile MainNode mainnode = null;
+
+ public final Gen gen;
+
+ public INodeBase(Gen generation) {
+ gen = generation;
+ }
+
+ public BasicNode prev() {
+ return null;
+ }
+
+}
diff --git a/library/src/scala/collection/concurrent/MainNode.java b/library/src/scala/collection/concurrent/MainNode.java
new file mode 100644
index 000000000000..1bfc11594ec9
--- /dev/null
+++ b/library/src/scala/collection/concurrent/MainNode.java
@@ -0,0 +1,46 @@
+/*
+ * 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.concurrent;
+
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+
+abstract class MainNode extends BasicNode {
+
+ @SuppressWarnings("unchecked")
+ public static final AtomicReferenceFieldUpdater, MainNode, ?>> updater =
+ AtomicReferenceFieldUpdater.newUpdater((Class>) (Class>) MainNode.class, (Class>) (Class>) MainNode.class, "prev");
+
+ public volatile MainNode prev = null;
+
+ public abstract int cachedSize(Object ct);
+
+ // standard contract
+ public abstract int knownSize();
+
+ public boolean CAS_PREV(MainNode oldval, MainNode nval) {
+ return updater.compareAndSet(this, oldval, nval);
+ }
+
+ public void WRITE_PREV(MainNode nval) {
+ updater.set(this, nval);
+ }
+
+ // do we need this? unclear in the javadocs...
+ // apparently not - volatile reads are supposed to be safe
+ // regardless of whether there are concurrent ARFU updates
+ @Deprecated @SuppressWarnings("unchecked")
+ public MainNode READ_PREV() {
+ return (MainNode) updater.get(this);
+ }
+
+}
diff --git a/library/src/scala/collection/concurrent/Map.scala b/library/src/scala/collection/concurrent/Map.scala
new file mode 100644
index 000000000000..291f85513b58
--- /dev/null
+++ b/library/src/scala/collection/concurrent/Map.scala
@@ -0,0 +1,190 @@
+/*
+ * 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 collection.concurrent
+
+import scala.annotation.tailrec
+
+/** A template trait for mutable maps that allow concurrent access.
+ *
+ * $concurrentmapinfo
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-mutable-collection-classes.html#concurrent_maps "Scala's Collection Library overview"]]
+ * section on `Concurrent Maps` for more information.
+ *
+ * @tparam K the key type of the map
+ * @tparam V the value type of the map
+ *
+ * @define Coll `concurrent.Map`
+ * @define coll concurrent map
+ * @define concurrentmapinfo
+ * This is a base trait for all Scala concurrent map implementations. It
+ * provides all of the methods a `Map` does, with the difference that all the
+ * changes are atomic. It also describes methods specific to concurrent maps.
+ *
+ * @define atomicop
+ * This is an atomic operation.
+ */
+trait Map[K, V] extends scala.collection.mutable.Map[K, V] {
+
+ /**
+ * Associates the given key with a given value, unless the key was already
+ * associated with some other value.
+ *
+ * $atomicop
+ *
+ * @param k key with which the specified value is to be associated with
+ * @param v value to be associated with the specified key
+ * @return `Some(oldvalue)` if there was a value `oldvalue` previously
+ * associated with the specified key, or `None` if there was no
+ * mapping for the specified key
+ */
+ def putIfAbsent(k: K, v: V): Option[V]
+
+ /**
+ * Removes the entry for the specified key if it's currently mapped to the
+ * specified value.
+ *
+ * $atomicop
+ *
+ * @param k key for which the entry should be removed
+ * @param v value expected to be associated with the specified key if
+ * the removal is to take place
+ * @return `true` if the removal took place, `false` otherwise
+ */
+ def remove(k: K, v: V): Boolean
+
+ /**
+ * Replaces the entry for the given key only if it was previously mapped to
+ * a given value.
+ *
+ * $atomicop
+ *
+ * @param k key for which the entry should be replaced
+ * @param oldvalue value expected to be associated with the specified key
+ * if replacing is to happen
+ * @param newvalue value to be associated with the specified key
+ * @return `true` if the entry was replaced, `false` otherwise
+ */
+ def replace(k: K, oldvalue: V, newvalue: V): Boolean
+
+ /**
+ * Replaces the entry for the given key only if it was previously mapped
+ * to some value.
+ *
+ * $atomicop
+ *
+ * @param k key for which the entry should be replaced
+ * @param v value to be associated with the specified key
+ * @return `Some(v)` if the given key was previously mapped to some value `v`, or `None` otherwise
+ */
+ def replace(k: K, v: V): Option[V]
+
+ override def getOrElseUpdate(key: K, @deprecatedName("op", since="2.13.13") defaultValue: => V): V = get(key) match {
+ case Some(v) => v
+ case None =>
+ val v = defaultValue
+ putIfAbsent(key, v) match {
+ case Some(ov) => ov
+ case None => v
+ }
+ }
+
+ /**
+ * Removes the entry for the specified key if it's currently mapped to the
+ * specified value. Comparison to the specified value is done using reference
+ * equality.
+ *
+ * Not all map implementations can support removal based on reference
+ * equality, and for those implementations, object equality is used instead.
+ *
+ * $atomicop
+ *
+ * @param k key for which the entry should be removed
+ * @param v value expected to be associated with the specified key if
+ * the removal is to take place
+ * @return `true` if the removal took place, `false` otherwise
+ */
+ // TODO: make part of the API in a future version
+ private[collection] def removeRefEq(k: K, v: V): Boolean = remove(k, v)
+
+ /**
+ * Replaces the entry for the given key only if it was previously mapped to
+ * a given value. Comparison to the specified value is done using reference
+ * equality.
+ *
+ * Not all map implementations can support replacement based on reference
+ * equality, and for those implementations, object equality is used instead.
+ *
+ * $atomicop
+ *
+ * @param k key for which the entry should be replaced
+ * @param oldValue value expected to be associated with the specified key
+ * if replacing is to happen
+ * @param newValue value to be associated with the specified key
+ * @return `true` if the entry was replaced, `false` otherwise
+ */
+ // TODO: make part of the API in a future version
+ private[collection] def replaceRefEq(k: K, oldValue: V, newValue: V): Boolean = replace(k, oldValue, newValue)
+
+ /**
+ * Update a mapping for the specified key and its current optionally mapped value
+ * (`Some` if there is current mapping, `None` if not).
+ *
+ * If the remapping function returns `Some(v)`, the mapping is updated with the new value `v`.
+ * If the remapping function returns `None`, the mapping is removed (or remains absent if initially absent).
+ * If the function itself throws an exception, the exception is rethrown, and the current mapping is left unchanged.
+ *
+ * If the map is updated by another concurrent access, the remapping function will be retried until successfully updated.
+ *
+ * @param key the key value
+ * @param remappingFunction a function that receives current optionally mapped value and return a new mapping
+ * @return the new value associated with the specified key
+ */
+ override def updateWith(key: K)(remappingFunction: Option[V] => Option[V]): Option[V] = updateWithAux(key)(remappingFunction)
+
+ @tailrec
+ private def updateWithAux(key: K)(remappingFunction: Option[V] => Option[V]): Option[V] = {
+ val previousValue = get(key)
+ val nextValue = remappingFunction(previousValue)
+ previousValue match {
+ case Some(prev) => nextValue match {
+ case Some(next) => if (replaceRefEq(key, prev, next)) return nextValue
+ case _ => if (removeRefEq(key, prev)) return None
+ }
+ case _ => nextValue match {
+ case Some(next) => if (putIfAbsent(key, next).isEmpty) return nextValue
+ case _ => return None
+ }
+ }
+ updateWithAux(key)(remappingFunction)
+ }
+
+ private[collection] def filterInPlaceImpl(p: (K, V) => Boolean): this.type = {
+ val it = iterator
+ while (it.hasNext) {
+ val (k, v) = it.next()
+ if (!p(k, v)) removeRefEq(k, v)
+ }
+ this
+ }
+
+ private[collection] def mapValuesInPlaceImpl(f: (K, V) => V): this.type = {
+ val it = iterator
+ while (it.hasNext) {
+ val (k, v) = it.next()
+ replaceRefEq(k, v, f(k, v))
+ }
+ this
+ }
+}
diff --git a/library/src/scala/collection/concurrent/TrieMap.scala b/library/src/scala/collection/concurrent/TrieMap.scala
new file mode 100644
index 000000000000..ddc5379f1f25
--- /dev/null
+++ b/library/src/scala/collection/concurrent/TrieMap.scala
@@ -0,0 +1,1200 @@
+/*
+ * 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 collection
+package concurrent
+
+import java.util.concurrent.atomic._
+import scala.{unchecked => uc}
+import scala.annotation.tailrec
+import scala.collection.concurrent.TrieMap.RemovalPolicy
+import scala.collection.generic.DefaultSerializable
+import scala.collection.immutable.{List, Nil}
+import scala.collection.mutable.GrowableBuilder
+import scala.util.Try
+import scala.util.hashing.Hashing
+
+private[collection] final class INode[K, V](bn: MainNode[K, V], g: Gen, equiv: Equiv[K]) extends INodeBase[K, V](g) {
+ import INodeBase._
+
+ WRITE(bn)
+
+ def this(g: Gen, equiv: Equiv[K]) = this(null, g, equiv)
+
+ def WRITE(nval: MainNode[K, V]) = INodeBase.updater.set(this, nval)
+
+ def CAS(old: MainNode[K, V], n: MainNode[K, V]) = INodeBase.updater.compareAndSet(this, old, n)
+
+ def gcasRead(ct: TrieMap[K, V]): MainNode[K, V] = GCAS_READ(ct)
+
+ def GCAS_READ(ct: TrieMap[K, V]): MainNode[K, V] = {
+ val m = /*READ*/mainnode
+ val prevval = /*READ*/m.prev
+ if (prevval eq null) m
+ else GCAS_Complete(m, ct)
+ }
+
+ @tailrec private def GCAS_Complete(m: MainNode[K, V], ct: TrieMap[K, V]): MainNode[K, V] = if (m eq null) null else {
+ // complete the GCAS
+ val prev = /*READ*/m.prev
+ val ctr = ct.readRoot(abort = true)
+
+ prev match {
+ case null =>
+ m
+ case fn: FailedNode[_, _] => // try to commit to previous value
+ if (CAS(m, fn.prev)) fn.prev
+ else GCAS_Complete(/*READ*/mainnode, ct)
+ case vn: MainNode[_, _] =>
+ // Assume that you've read the root from the generation G.
+ // Assume that the snapshot algorithm is correct.
+ // ==> you can only reach nodes in generations <= G.
+ // ==> `gen` is <= G.
+ // We know that `ctr.gen` is >= G.
+ // ==> if `ctr.gen` = `gen` then they are both equal to G.
+ // ==> otherwise, we know that either `ctr.gen` > G, `gen` < G,
+ // or both
+ if ((ctr.gen eq gen) && ct.nonReadOnly) {
+ // try to commit
+ if (m.CAS_PREV(prev, null)) m
+ else GCAS_Complete(m, ct)
+ } else {
+ // try to abort
+ m.CAS_PREV(prev, new FailedNode(prev))
+ GCAS_Complete(/*READ*/mainnode, ct)
+ }
+ }
+ }
+
+ def GCAS(old: MainNode[K, V], n: MainNode[K, V], ct: TrieMap[K, V]): Boolean = {
+ n.WRITE_PREV(old)
+ if (CAS(old, n)) {
+ GCAS_Complete(n, ct)
+ /*READ*/n.prev eq null
+ } else false
+ }
+
+ private def equal(k1: K, k2: K, ct: TrieMap[K, V]) = ct.equality.equiv(k1, k2)
+
+ private def inode(cn: MainNode[K, V]) = {
+ val nin = new INode[K, V](gen, equiv)
+ nin.WRITE(cn)
+ nin
+ }
+
+ def copyToGen(ngen: Gen, ct: TrieMap[K, V]) = {
+ val nin = new INode[K, V](ngen, equiv)
+ val main = GCAS_READ(ct)
+ nin.WRITE(main)
+ nin
+ }
+
+ /** Inserts a key value pair, overwriting the old pair if the keys match.
+ *
+ * @return true if successful, false otherwise
+ */
+ @tailrec def rec_insert(k: K, v: V, hc: Int, lev: Int, parent: INode[K, V], startgen: Gen, ct: TrieMap[K, V]): Boolean = {
+ val m = GCAS_READ(ct) // use -Yinline!
+
+ m match {
+ case cn: CNode[K, V] => // 1) a multiway node
+ val idx = (hc >>> lev) & 0x1f
+ val flag = 1 << idx
+ val bmp = cn.bitmap
+ val mask = flag - 1
+ val pos = Integer.bitCount(bmp & mask)
+ if ((bmp & flag) != 0) {
+ // 1a) insert below
+ cn.array(pos) match {
+ case in: INode[K, V] @uc =>
+ if (startgen eq in.gen) in.rec_insert(k, v, hc, lev + 5, this, startgen, ct)
+ else {
+ if (GCAS(cn, cn.renewed(startgen, ct), ct)) rec_insert(k, v, hc, lev, parent, startgen, ct)
+ else false
+ }
+ case sn: SNode[K, V] @uc =>
+ if (sn.hc == hc && equal(sn.k, k, ct)) GCAS(cn, cn.updatedAt(pos, new SNode(sn.k, v, hc), gen), ct)
+ else {
+ val rn = if (cn.gen eq gen) cn else cn.renewed(gen, ct)
+ val nn = rn.updatedAt(pos, inode(CNode.dual(sn, sn.hc, new SNode(k, v, hc), hc, lev + 5, gen, equiv)), gen)
+ GCAS(cn, nn, ct)
+ }
+ case basicNode => throw new MatchError(basicNode)
+ }
+ } else {
+ val rn = if (cn.gen eq gen) cn else cn.renewed(gen, ct)
+ val ncnode = rn.insertedAt(pos, flag, k, v, hc, gen)
+ GCAS(cn, ncnode, ct)
+ }
+ case tn: TNode[K, V] =>
+ clean(parent, ct, lev - 5)
+ false
+ case ln: LNode[K, V] => // 3) an l-node
+ val nn = ln.inserted(k, v)
+ GCAS(ln, nn, ct)
+ case mainNode => throw new MatchError(mainNode)
+ }
+ }
+
+
+
+ /** Inserts a new key value pair, given that a specific condition is met.
+ *
+ * @param cond KEY_PRESENT_OR_ABSENT - don't care if the key was there, insert or overwrite
+ * KEY_ABSENT - key wasn't there, insert only, do not overwrite
+ * KEY_PRESENT - key was there, overwrite only, do not insert
+ * other value `v` - only overwrite if the current value is this
+ * @param fullEquals whether to use reference or full equals when comparing `v` to the current value
+ * @param hc the hashcode of `k`
+ *
+ * @return null if unsuccessful, Option[V] otherwise (indicating previous value bound to the key)
+ */
+ @tailrec def rec_insertif(k: K, v: V, hc: Int, cond: AnyRef, fullEquals: Boolean, lev: Int, parent: INode[K, V], startgen: Gen, ct: TrieMap[K, V]): Option[V] = {
+ val m = GCAS_READ(ct) // use -Yinline!
+
+ m match {
+ case cn: CNode[K, V] => // 1) a multiway node
+ val idx = (hc >>> lev) & 0x1f
+ val flag = 1 << idx
+ val bmp = cn.bitmap
+ val mask = flag - 1
+ val pos = Integer.bitCount(bmp & mask)
+ if ((bmp & flag) != 0) {
+ // 1a) insert below
+ cn.array(pos) match {
+ case in: INode[K, V] @uc =>
+ if (startgen eq in.gen) in.rec_insertif(k, v, hc, cond, fullEquals, lev + 5, this, startgen, ct)
+ else {
+ if (GCAS(cn, cn.renewed(startgen, ct), ct)) rec_insertif(k, v, hc, cond, fullEquals, lev, parent, startgen, ct)
+ else null
+ }
+ case sn: SNode[K, V] @uc => cond match {
+ case INode.KEY_PRESENT_OR_ABSENT =>
+ if (sn.hc == hc && equal(sn.k, k, ct)) {
+ if (GCAS(cn, cn.updatedAt(pos, new SNode(sn.k, v, hc), gen), ct)) Some(sn.v) else null
+ } else {
+ val rn = if (cn.gen eq gen) cn else cn.renewed(gen, ct)
+ val nn = rn.updatedAt(pos, inode(CNode.dual(sn, sn.hc, new SNode(k, v, hc), hc, lev + 5, gen, equiv)), gen)
+ if (GCAS(cn, nn, ct)) None
+ else null
+ }
+ case INode.KEY_ABSENT =>
+ if (sn.hc == hc && equal(sn.k, k, ct)) Some(sn.v)
+ else {
+ val rn = if (cn.gen eq gen) cn else cn.renewed(gen, ct)
+ val nn = rn.updatedAt(pos, inode(CNode.dual(sn, sn.hc, new SNode(k, v, hc), hc, lev + 5, gen, equiv)), gen)
+ if (GCAS(cn, nn, ct)) None
+ else null
+ }
+ case INode.KEY_PRESENT =>
+ if (sn.hc == hc && equal(sn.k, k, ct)) {
+ if (GCAS(cn, cn.updatedAt(pos, new SNode(k, v, hc), gen), ct)) Some(sn.v) else null
+ } else None
+ case otherv =>
+ if (sn.hc == hc && equal(sn.k, k, ct) && (if (fullEquals) sn.v == otherv else sn.v.asInstanceOf[AnyRef] eq otherv)) {
+ if (GCAS(cn, cn.updatedAt(pos, new SNode(k, v, hc), gen), ct)) Some(sn.v) else null
+ } else None
+ }
+ case basicNode => throw new MatchError(basicNode)
+ }
+ } else cond match {
+ case INode.KEY_PRESENT_OR_ABSENT | INode.KEY_ABSENT =>
+ val rn = if (cn.gen eq gen) cn else cn.renewed(gen, ct)
+ val ncnode = rn.insertedAt(pos, flag, k, v, hc, gen)
+ if (GCAS(cn, ncnode, ct)) None else null
+ case INode.KEY_PRESENT => None
+ case otherv => None
+ }
+ case sn: TNode[K, V] =>
+ clean(parent, ct, lev - 5)
+ null
+ case ln: LNode[K, V] => // 3) an l-node
+ def insertln() = {
+ val nn = ln.inserted(k, v)
+ GCAS(ln, nn, ct)
+ }
+ cond match {
+ case INode.KEY_PRESENT_OR_ABSENT =>
+ val optv = ln.get(k)
+ if (insertln()) optv else null
+ case INode.KEY_ABSENT =>
+ ln.get(k) match {
+ case None => if (insertln()) None else null
+ case optv => optv
+ }
+ case INode.KEY_PRESENT =>
+ ln.get(k) match {
+ case Some(v0) => if (insertln()) Some(v0) else null
+ case None => None
+ }
+ case otherv =>
+ ln.get(k) match {
+ case Some(v0) if (if (fullEquals) v0 == otherv else v0.asInstanceOf[AnyRef] eq otherv) =>
+ if (insertln()) Some(otherv.asInstanceOf[V]) else null
+ case _ => None
+ }
+ }
+ case mainNode => throw new MatchError(mainNode)
+ }
+ }
+
+ /** Looks up the value associated with the key.
+ *
+ * @param hc the hashcode of `k`
+ *
+ * @return NO_SUCH_ELEMENT_SENTINEL if no value has been found, RESTART if the operation wasn't successful,
+ * or any other value otherwise
+ */
+ @tailrec def rec_lookup(k: K, hc: Int, lev: Int, parent: INode[K, V], startgen: Gen, ct: TrieMap[K, V]): AnyRef = {
+ val m = GCAS_READ(ct) // use -Yinline!
+
+ m match {
+ case cn: CNode[K, V] => // 1) a multinode
+ val idx = (hc >>> lev) & 0x1f
+ val flag = 1 << idx
+ val bmp = cn.bitmap
+ if ((bmp & flag) == 0) NO_SUCH_ELEMENT_SENTINEL // 1a) bitmap shows no binding
+ else { // 1b) bitmap contains a value - descend
+ val pos = if (bmp == 0xffffffff) idx else Integer.bitCount(bmp & (flag - 1))
+ val sub = cn.array(pos)
+ sub match {
+ case in: INode[K, V] @uc =>
+ if (ct.isReadOnly || (startgen eq in.gen)) in.rec_lookup(k, hc, lev + 5, this, startgen, ct)
+ else {
+ if (GCAS(cn, cn.renewed(startgen, ct), ct)) rec_lookup(k, hc, lev, parent, startgen, ct)
+ else RESTART
+ }
+ case sn: SNode[K, V] @uc => // 2) singleton node
+ if (sn.hc == hc && equal(sn.k, k, ct)) sn.v.asInstanceOf[AnyRef]
+ else NO_SUCH_ELEMENT_SENTINEL
+ case basicNode => throw new MatchError(basicNode)
+ }
+ }
+ case tn: TNode[_, _] => // 3) non-live node
+ def cleanReadOnly(tn: TNode[K, V]) = if (ct.nonReadOnly) {
+ clean(parent, ct, lev - 5)
+ RESTART
+ } else {
+ if (tn.hc == hc && tn.k == k) tn.v.asInstanceOf[AnyRef]
+ else NO_SUCH_ELEMENT_SENTINEL
+ }
+ cleanReadOnly(tn)
+ case ln: LNode[K, V] => // 5) an l-node
+ ln.get(k).asInstanceOf[Option[AnyRef]].getOrElse(NO_SUCH_ELEMENT_SENTINEL)
+ case mainNode => throw new MatchError(mainNode)
+ }
+ }
+
+ /** Removes the key associated with the given value.
+ *
+ * @param hc the hashcode of `k`
+ *
+ * @param removalPolicy policy deciding whether to remove `k` based on `v` and the
+ * current value associated with `k` (Always, FullEquals, or ReferenceEq)
+ *
+ * @return null if not successful, an Option[V] indicating the previous value otherwise
+ */
+ def rec_remove(
+ k: K,
+ v: V,
+ removalPolicy: Int,
+ hc: Int,
+ lev: Int,
+ parent: INode[K, V],
+ startgen: Gen,
+ ct: TrieMap[K, V]): Option[V] = {
+
+ GCAS_READ(ct) match {
+ case cn: CNode[K, V] =>
+ val idx = (hc >>> lev) & 0x1f
+ val bmp = cn.bitmap
+ val flag = 1 << idx
+ if ((bmp & flag) == 0) None
+ else {
+ val pos = Integer.bitCount(bmp & (flag - 1))
+ val sub = cn.array(pos)
+ val res = sub match {
+ case in: INode[K, V] @uc =>
+ if (startgen eq in.gen) in.rec_remove(k, v, removalPolicy, hc, lev + 5, this, startgen, ct)
+ else {
+ if (GCAS(cn, cn.renewed(startgen, ct), ct)) rec_remove(k, v, removalPolicy, hc, lev, parent, startgen, ct)
+ else null
+ }
+ case sn: SNode[K, V] @uc =>
+ if (sn.hc == hc && equal(sn.k, k, ct) && RemovalPolicy.shouldRemove(removalPolicy)(sn.v, v)) {
+ val ncn = cn.removedAt(pos, flag, gen).toContracted(lev)
+ if (GCAS(cn, ncn, ct)) Some(sn.v) else null
+ } else None
+ case basicNode => throw new MatchError(basicNode)
+ }
+
+ if (res == None || (res eq null)) res
+ else {
+ @tailrec def cleanParent(nonlive: AnyRef): Unit = {
+ val cn = parent.GCAS_READ(ct)
+ cn match {
+ case cn: CNode[K, V] =>
+ val idx = (hc >>> (lev - 5)) & 0x1f
+ val bmp = cn.bitmap
+ val flag = 1 << idx
+ if ((bmp & flag) == 0) {} // somebody already removed this i-node, we're done
+ else {
+ val pos = Integer.bitCount(bmp & (flag - 1))
+ val sub = cn.array(pos)
+ if (sub eq this) (nonlive: @uc) match {
+ case tn: TNode[K, V] @uc =>
+ val ncn = cn.updatedAt(pos, tn.copyUntombed, gen).toContracted(lev - 5)
+ if (!parent.GCAS(cn, ncn, ct))
+ if (ct.readRoot().gen == startgen) cleanParent(nonlive)
+ }
+ }
+ case _ => // parent is no longer a cnode, we're done
+ }
+ }
+
+ if (parent ne null) { // never tomb at root
+ val n = GCAS_READ(ct)
+ if (n.isInstanceOf[TNode[_, _]])
+ cleanParent(n)
+ }
+
+ res
+ }
+ }
+ case tn: TNode[K, V] =>
+ clean(parent, ct, lev - 5)
+ null
+ case ln: LNode[K, V] =>
+ if (removalPolicy == RemovalPolicy.Always) {
+ val optv = ln.get(k)
+ val nn = ln.removed(k, ct)
+ if (GCAS(ln, nn, ct)) optv else null
+ } else ln.get(k) match {
+ case optv @ Some(v0) if RemovalPolicy.shouldRemove(removalPolicy)(v, v0) =>
+ val nn = ln.removed(k, ct)
+ if (GCAS(ln, nn, ct)) optv else null
+ case _ => None
+ }
+ case mainNode => throw new MatchError(mainNode)
+ }
+ }
+
+ private def clean(nd: INode[K, V], ct: TrieMap[K, V], lev: Int): Unit = {
+ val m = nd.GCAS_READ(ct)
+ m match {
+ case cn: CNode[K, V] => nd.GCAS(cn, cn.toCompressed(ct, lev, gen), ct)
+ case _ =>
+ }
+ }
+
+ def isNullInode(ct: TrieMap[K, V]) = GCAS_READ(ct) eq null
+
+ def cachedSize(ct: TrieMap[K, V]): Int =
+ GCAS_READ(ct).cachedSize(ct)
+
+ def knownSize(ct: TrieMap[K, V]): Int =
+ GCAS_READ(ct).knownSize()
+
+ /* this is a quiescent method! */
+ def string(lev: Int) = "%sINode -> %s".format(" " * lev, mainnode match {
+ case null => ""
+ case tn: TNode[_, _] => "TNode(%s, %s, %d, !)".format(tn.k, tn.v, tn.hc)
+ case cn: CNode[_, _] => cn.string(lev)
+ case ln: LNode[_, _] => ln.string(lev)
+ case x => "".format(x)
+ })
+
+}
+
+
+private[concurrent] object INode {
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Arguments for `cond` argument in TrieMap#rec_insertif
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ final val KEY_PRESENT = new AnyRef
+ final val KEY_ABSENT = new AnyRef
+ final val KEY_PRESENT_OR_ABSENT = new AnyRef
+
+ def newRootNode[K, V](equiv: Equiv[K]) = {
+ val gen = new Gen
+ val cn = new CNode[K, V](0, new Array(0), gen)
+ new INode[K, V](cn, gen, equiv)
+ }
+}
+
+
+private[concurrent] final class FailedNode[K, V](p: MainNode[K, V]) extends MainNode[K, V] {
+ WRITE_PREV(p)
+
+ def string(lev: Int): Nothing = throw new UnsupportedOperationException
+
+ def cachedSize(ct: AnyRef): Int = throw new UnsupportedOperationException
+
+ def knownSize: Int = throw new UnsupportedOperationException
+
+ override def toString = "FailedNode(%s)".format(p)
+}
+
+
+private[concurrent] trait KVNode[K, V] {
+ def kvPair: (K, V)
+}
+
+
+private[collection] final class SNode[K, V](final val k: K, final val v: V, final val hc: Int)
+ extends BasicNode with KVNode[K, V] {
+ def copy = new SNode(k, v, hc)
+ def copyTombed = new TNode(k, v, hc)
+ def copyUntombed = new SNode(k, v, hc)
+ def kvPair = (k, v)
+ def string(lev: Int) = (" " * lev) + "SNode(%s, %s, %x)".format(k, v, hc)
+}
+
+// Tomb Node, used to ensure proper ordering during removals
+private[collection] final class TNode[K, V](final val k: K, final val v: V, final val hc: Int)
+ extends MainNode[K, V] with KVNode[K, V] {
+ def copy = new TNode(k, v, hc)
+ def copyTombed = new TNode(k, v, hc)
+ def copyUntombed = new SNode(k, v, hc)
+ def kvPair = (k, v)
+ def cachedSize(ct: AnyRef): Int = 1
+ def knownSize: Int = 1
+ def string(lev: Int) = (" " * lev) + "TNode(%s, %s, %x, !)".format(k, v, hc)
+}
+
+// List Node, leaf node that handles hash collisions
+private[collection] final class LNode[K, V](val entries: List[(K, V)], equiv: Equiv[K])
+ extends MainNode[K, V] {
+
+ def this(k: K, v: V, equiv: Equiv[K]) = this((k -> v) :: Nil, equiv)
+
+ def this(k1: K, v1: V, k2: K, v2: V, equiv: Equiv[K]) =
+ this(if (equiv.equiv(k1, k2)) (k2 -> v2) :: Nil else (k1 -> v1) :: (k2 -> v2) :: Nil, equiv)
+
+ def inserted(k: K, v: V) = {
+ var k0: K = k
+ @tailrec
+ def remove(elems: List[(K, V)], acc: List[(K, V)]): List[(K, V)] = {
+ if (elems.isEmpty) acc
+ else if (equiv.equiv(elems.head._1, k)) {
+ k0 = elems.head._1
+ acc ::: elems.tail
+ } else remove(elems.tail, elems.head :: acc)
+ }
+ val e = remove(entries, Nil)
+ new LNode((k0 -> v) :: e, equiv)
+ }
+
+ def removed(k: K, ct: TrieMap[K, V]): MainNode[K, V] = {
+ val updmap = entries.filterNot(entry => equiv.equiv(entry._1, k))
+ if (updmap.sizeIs > 1) new LNode(updmap, equiv)
+ else {
+ val (k, v) = updmap.iterator.next()
+ new TNode(k, v, ct.computeHash(k)) // create it tombed so that it gets compressed on subsequent accesses
+ }
+ }
+
+ def get(k: K): Option[V] = entries.find(entry => equiv.equiv(entry._1, k)).map(_._2)
+
+ def cachedSize(ct: AnyRef): Int = entries.size
+
+ def knownSize: Int = -1 // shouldn't ever be empty, and the size of a list is not known
+
+ def string(lev: Int) = (" " * lev) + "LNode(%s)".format(entries.mkString(", "))
+
+}
+
+// Ctrie Node, contains bitmap and array of references to branch nodes
+private[collection] final class CNode[K, V](val bitmap: Int, val array: Array[BasicNode], val gen: Gen) extends CNodeBase[K, V] {
+ // this should only be called from within read-only snapshots
+ def cachedSize(ct: AnyRef): Int = {
+ val currsz = READ_SIZE()
+ if (currsz != -1) currsz
+ else {
+ val sz = computeSize(ct.asInstanceOf[TrieMap[K, V]])
+ while (READ_SIZE() == -1) CAS_SIZE(-1, sz)
+ READ_SIZE()
+ }
+ }
+
+ def knownSize: Int = READ_SIZE() // this should only ever return -1 if unknown
+
+ // lends itself towards being parallelizable by choosing
+ // a random starting offset in the array
+ // => if there are concurrent size computations, they start
+ // at different positions, so they are more likely to
+ // to be independent
+ private def computeSize(ct: TrieMap[K, V]): Int = {
+ var i = 0
+ var sz = 0
+ val offset =
+ if (array.length > 0)
+ //util.Random.nextInt(array.length) /* <-- benchmarks show that this causes observable contention */
+ java.util.concurrent.ThreadLocalRandom.current.nextInt(0, array.length)
+ else 0
+ while (i < array.length) {
+ val pos = (i + offset) % array.length
+ array(pos) match {
+ case sn: SNode[_, _] => sz += 1
+ case in: INode[K, V] @uc => sz += in.cachedSize(ct)
+ case basicNode => throw new MatchError(basicNode)
+ }
+ i += 1
+ }
+ sz
+ }
+
+ def updatedAt(pos: Int, nn: BasicNode, gen: Gen) = {
+ val len = array.length
+ val narr = new Array[BasicNode](len)
+ Array.copy(array, 0, narr, 0, len)
+ narr(pos) = nn
+ new CNode[K, V](bitmap, narr, gen)
+ }
+
+ def removedAt(pos: Int, flag: Int, gen: Gen) = {
+ val arr = array
+ val len = arr.length
+ val narr = new Array[BasicNode](len - 1)
+ Array.copy(arr, 0, narr, 0, pos)
+ Array.copy(arr, pos + 1, narr, pos, len - pos - 1)
+ new CNode[K, V](bitmap ^ flag, narr, gen)
+ }
+
+ def insertedAt(pos: Int, flag: Int, k: K, v: V, hc: Int, gen: Gen) = {
+ val len = array.length
+ val bmp = bitmap
+ val narr = new Array[BasicNode](len + 1)
+ Array.copy(array, 0, narr, 0, pos)
+ narr(pos) = new SNode(k, v, hc)
+ Array.copy(array, pos, narr, pos + 1, len - pos)
+ new CNode[K, V](bmp | flag, narr, gen)
+ }
+
+ /** Returns a copy of this cnode such that all the i-nodes below it are copied
+ * to the specified generation `ngen`.
+ */
+ def renewed(ngen: Gen, ct: TrieMap[K, V]) = {
+ var i = 0
+ val arr = array
+ val len = arr.length
+ val narr = new Array[BasicNode](len)
+ while (i < len) {
+ arr(i) match {
+ case in: INode[K, V] @uc => narr(i) = in.copyToGen(ngen, ct)
+ case bn: BasicNode => narr(i) = bn
+ }
+ i += 1
+ }
+ new CNode[K, V](bitmap, narr, ngen)
+ }
+
+ private def resurrect(inode: INode[K, V], inodemain: AnyRef): BasicNode = inodemain match {
+ case tn: TNode[_, _] => tn.copyUntombed
+ case _ => inode
+ }
+
+ def toContracted(lev: Int): MainNode[K, V] = if (array.length == 1 && lev > 0) array(0) match {
+ case sn: SNode[K, V] @uc => sn.copyTombed
+ case _ => this
+ } else this
+
+ // - if the branching factor is 1 for this CNode, and the child
+ // is a tombed SNode, returns its tombed version
+ // - otherwise, if there is at least one non-null node below,
+ // returns the version of this node with at least some null-inodes
+ // removed (those existing when the op began)
+ // - if there are only null-i-nodes below, returns null
+ def toCompressed(ct: TrieMap[K, V], lev: Int, gen: Gen) = {
+ val bmp = bitmap
+ var i = 0
+ val arr = array
+ val tmparray = new Array[BasicNode](arr.length)
+ while (i < arr.length) { // construct new bitmap
+ val sub = arr(i)
+ sub match {
+ case in: INode[K, V] @uc =>
+ val inodemain = in.gcasRead(ct)
+ assert(inodemain ne null)
+ tmparray(i) = resurrect(in, inodemain)
+ case sn: SNode[K, V] @uc =>
+ tmparray(i) = sn
+ case basicNode => throw new MatchError(basicNode)
+ }
+ i += 1
+ }
+
+ new CNode[K, V](bmp, tmparray, gen).toContracted(lev)
+ }
+
+ def string(lev: Int): String = "CNode %x\n%s".format(bitmap, array.map(_.string(lev + 1)).mkString("\n"))
+
+ override def toString = {
+ def elems: Seq[String] = array.flatMap {
+ case sn: SNode[K, V] @uc => Iterable.single(sn.kvPair._2.toString)
+ case in: INode[K, V] @uc => Iterable.single(augmentString(in.toString).drop(14) + "(" + in.gen + ")")
+ case basicNode => throw new MatchError(basicNode)
+ }
+ f"CNode(sz: ${elems.size}%d; ${elems.sorted.mkString(", ")})"
+ }
+}
+
+private[concurrent] object CNode {
+
+ def dual[K, V](x: SNode[K, V], xhc: Int, y: SNode[K, V], yhc: Int, lev: Int, gen: Gen, equiv: Equiv[K]): MainNode[K, V] = if (lev < 35) {
+ val xidx = (xhc >>> lev) & 0x1f
+ val yidx = (yhc >>> lev) & 0x1f
+ val bmp = (1 << xidx) | (1 << yidx)
+ if (xidx == yidx) {
+ val subinode = new INode[K, V](gen, equiv)//(TrieMap.inodeupdater)
+ subinode.mainnode = dual(x, xhc, y, yhc, lev + 5, gen, equiv)
+ new CNode(bmp, Array(subinode), gen)
+ } else {
+ if (xidx < yidx) new CNode(bmp, Array(x, y), gen)
+ else new CNode(bmp, Array(y, x), gen)
+ }
+ } else {
+ new LNode(x.k, x.v, y.k, y.v, equiv)
+ }
+
+}
+
+
+private[concurrent] case class RDCSS_Descriptor[K, V](old: INode[K, V], expectedmain: MainNode[K, V], nv: INode[K, V]) {
+ @volatile var committed = false
+}
+
+
+/** A concurrent hash-trie or TrieMap is a concurrent thread-safe lock-free
+ * implementation of a hash array mapped trie. It is used to implement the
+ * concurrent map abstraction. It has particularly scalable concurrent insert
+ * and remove operations and is memory-efficient. It supports O(1), atomic,
+ * lock-free snapshots which are used to implement linearizable lock-free size,
+ * iterator and clear operations. The cost of evaluating the (lazy) snapshot is
+ * distributed across subsequent updates, thus making snapshot evaluation horizontally scalable.
+ *
+ * For details, see: [[http://lampwww.epfl.ch/~prokopec/ctries-snapshot.pdf]]
+ */
+@SerialVersionUID(-5212455458703321708L)
+final class TrieMap[K, V] private (r: AnyRef, rtupd: AtomicReferenceFieldUpdater[TrieMap[K, V], AnyRef], hashf: Hashing[K], ef: Equiv[K])
+ extends scala.collection.mutable.AbstractMap[K, V]
+ with scala.collection.concurrent.Map[K, V]
+ with scala.collection.mutable.MapOps[K, V, TrieMap, TrieMap[K, V]]
+ with scala.collection.MapFactoryDefaults[K, V, TrieMap, mutable.Iterable]
+ with DefaultSerializable {
+
+ private[this] var hashingobj = if (hashf.isInstanceOf[Hashing.Default[_]]) new TrieMap.MangledHashing[K] else hashf
+ private[this] var equalityobj = ef
+ @transient
+ private[this] var rootupdater = rtupd
+ def hashing = hashingobj
+ def equality = equalityobj
+ @volatile private var root = r
+
+ def this(hashf: Hashing[K], ef: Equiv[K]) = this(
+ INode.newRootNode(ef),
+ AtomicReferenceFieldUpdater.newUpdater(classOf[TrieMap[K, V]], classOf[AnyRef], "root"),
+ hashf,
+ ef
+ )
+
+ def this() = this(Hashing.default, Equiv.universal)
+
+ override def mapFactory: MapFactory[TrieMap] = TrieMap
+
+ /* internal methods */
+
+ private def writeObject(out: java.io.ObjectOutputStream): Unit = {
+ out.writeObject(hashingobj)
+ out.writeObject(equalityobj)
+
+ val it = iterator
+ while (it.hasNext) {
+ val (k, v) = it.next()
+ out.writeObject(k)
+ out.writeObject(v)
+ }
+ out.writeObject(TrieMapSerializationEnd)
+ }
+
+ private def readObject(in: java.io.ObjectInputStream): Unit = {
+ root = INode.newRootNode(equality)
+ rootupdater = AtomicReferenceFieldUpdater.newUpdater(classOf[TrieMap[K, V]], classOf[AnyRef], "root")
+
+ hashingobj = in.readObject().asInstanceOf[Hashing[K]]
+ equalityobj = in.readObject().asInstanceOf[Equiv[K]]
+
+ var obj: AnyRef = in.readObject()
+
+ while (obj != TrieMapSerializationEnd) {
+ obj = in.readObject()
+ if (obj != TrieMapSerializationEnd) {
+ val k = obj.asInstanceOf[K]
+ val v = in.readObject().asInstanceOf[V]
+ update(k, v)
+ }
+ }
+ }
+
+ private def CAS_ROOT(ov: AnyRef, nv: AnyRef) = rootupdater.compareAndSet(this, ov, nv)
+
+ private[collection] def readRoot(abort: Boolean = false): INode[K, V] = RDCSS_READ_ROOT(abort)
+
+ private[concurrent] def RDCSS_READ_ROOT(abort: Boolean = false): INode[K, V] = {
+ val r = /*READ*/root
+ r match {
+ case in: INode[K, V] @uc => in
+ case desc: RDCSS_Descriptor[K, V] @uc => RDCSS_Complete(abort)
+ case x => throw new MatchError(x)
+ }
+ }
+
+ @tailrec private def RDCSS_Complete(abort: Boolean): INode[K, V] = {
+ val v = /*READ*/root
+ v match {
+ case in: INode[K, V] @uc => in
+ case desc: RDCSS_Descriptor[K, V] @uc =>
+ val RDCSS_Descriptor(ov, exp, nv) = desc
+ if (abort) {
+ if (CAS_ROOT(desc, ov)) ov
+ else RDCSS_Complete(abort)
+ } else {
+ val oldmain = ov.gcasRead(this)
+ if (oldmain eq exp) {
+ if (CAS_ROOT(desc, nv)) {
+ desc.committed = true
+ nv
+ } else RDCSS_Complete(abort)
+ } else {
+ if (CAS_ROOT(desc, ov)) ov
+ else RDCSS_Complete(abort)
+ }
+ }
+ case x => throw new MatchError(x)
+ }
+ }
+
+ private def RDCSS_ROOT(ov: INode[K, V], expectedmain: MainNode[K, V], nv: INode[K, V]): Boolean = {
+ val desc = RDCSS_Descriptor(ov, expectedmain, nv)
+ if (CAS_ROOT(ov, desc)) {
+ RDCSS_Complete(abort = false)
+ /*READ*/desc.committed
+ } else false
+ }
+
+ @tailrec private def inserthc(k: K, hc: Int, v: V): Unit = {
+ val r = RDCSS_READ_ROOT()
+ if (!r.rec_insert(k, v, hc, 0, null, r.gen, this)) inserthc(k, hc, v)
+ }
+
+ @tailrec private def insertifhc(k: K, hc: Int, v: V, cond: AnyRef, fullEquals: Boolean): Option[V] = {
+ val r = RDCSS_READ_ROOT()
+
+ val ret = r.rec_insertif(k, v, hc, cond, fullEquals, 0, null, r.gen, this)
+ if (ret eq null) insertifhc(k, hc, v, cond, fullEquals)
+ else ret
+ }
+
+ /** Finds the value associated with this key
+ *
+ * @param k the key to look up
+ * @param hc the hashcode of `k`
+ *
+ * @return the value: V associated with `k`, if it exists. Otherwise, INodeBase.NO_SUCH_ELEMENT_SENTINEL
+ */
+ @tailrec private def lookuphc(k: K, hc: Int): AnyRef = {
+ val r = RDCSS_READ_ROOT()
+ val res = r.rec_lookup(k, hc, 0, null, r.gen, this)
+ if (res eq INodeBase.RESTART) lookuphc(k, hc)
+ else res
+ }
+
+ /** Removes a key-value pair from the map
+ *
+ * @param k the key to remove
+ * @param v the value compare with the value found associated with the key
+ * @param removalPolicy policy deciding whether to remove `k` based on `v` and the
+ * current value associated with `k` (Always, FullEquals, or ReferenceEq)
+ * @return an Option[V] indicating the previous value
+ */
+ @tailrec private def removehc(k: K, v: V, removalPolicy: Int, hc: Int): Option[V] = {
+ val r = RDCSS_READ_ROOT()
+ val res = r.rec_remove(k, v, removalPolicy, hc, 0, null, r.gen, this)
+ if (res ne null) res
+ else removehc(k, v, removalPolicy, hc)
+ }
+
+
+ def string = RDCSS_READ_ROOT().string(0)
+
+ /* public methods */
+
+ def isReadOnly = rootupdater eq null
+
+ def nonReadOnly = rootupdater ne null
+
+ /** Returns a snapshot of this TrieMap.
+ * This operation is lock-free and linearizable.
+ *
+ * The snapshot is lazily updated - the first time some branch
+ * in the snapshot or this TrieMap are accessed, they are rewritten.
+ * This means that the work of rebuilding both the snapshot and this
+ * TrieMap is distributed across all the threads doing updates or accesses
+ * subsequent to the snapshot creation.
+ */
+ @tailrec def snapshot(): TrieMap[K, V] = {
+ val r = RDCSS_READ_ROOT()
+ val expmain = r.gcasRead(this)
+ if (RDCSS_ROOT(r, expmain, r.copyToGen(new Gen, this))) new TrieMap(r.copyToGen(new Gen, this), rootupdater, hashing, equality)
+ else snapshot()
+ }
+
+ /** Returns a read-only snapshot of this TrieMap.
+ * This operation is lock-free and linearizable.
+ *
+ * The snapshot is lazily updated - the first time some branch
+ * of this TrieMap are accessed, it is rewritten. The work of creating
+ * the snapshot is thus distributed across subsequent updates
+ * and accesses on this TrieMap by all threads.
+ * Note that the snapshot itself is never rewritten unlike when calling
+ * the `snapshot` method, but the obtained snapshot cannot be modified.
+ *
+ * This method is used by other methods such as `size` and `iterator`.
+ */
+ @tailrec def readOnlySnapshot(): scala.collection.Map[K, V] = {
+ val r = RDCSS_READ_ROOT()
+ val expmain = r.gcasRead(this)
+ if (RDCSS_ROOT(r, expmain, r.copyToGen(new Gen, this))) new TrieMap(r, null, hashing, equality)
+ else readOnlySnapshot()
+ }
+
+ @tailrec override def clear(): Unit = {
+ val r = RDCSS_READ_ROOT()
+ if (!RDCSS_ROOT(r, r.gcasRead(this), INode.newRootNode[K, V](equality))) clear()
+ }
+
+ def computeHash(k: K) = hashingobj.hash(k)
+
+ @deprecated("Use getOrElse(k, null) instead.", "2.13.0")
+ def lookup(k: K): V = {
+ val hc = computeHash(k)
+ val lookupRes = lookuphc(k, hc)
+ val res = if (lookupRes == INodeBase.NO_SUCH_ELEMENT_SENTINEL) null else lookupRes
+ res.asInstanceOf[V]
+ }
+
+ override def apply(k: K): V = {
+ val hc = computeHash(k)
+ val res = lookuphc(k, hc)
+ if (res eq INodeBase.NO_SUCH_ELEMENT_SENTINEL) throw new NoSuchElementException
+ else res.asInstanceOf[V]
+ }
+
+ def get(k: K): Option[V] = {
+ val hc = computeHash(k)
+ val res = lookuphc(k, hc)
+ if (res eq INodeBase.NO_SUCH_ELEMENT_SENTINEL) None else Some(res).asInstanceOf[Option[V]]
+ }
+
+ override def put(key: K, value: V): Option[V] = {
+ val hc = computeHash(key)
+ insertifhc(key, hc, value, INode.KEY_PRESENT_OR_ABSENT, fullEquals = false /* unused */)
+ }
+
+ override def update(k: K, v: V): Unit = {
+ val hc = computeHash(k)
+ inserthc(k, hc, v)
+ }
+
+ def addOne(kv: (K, V)) = {
+ update(kv._1, kv._2)
+ this
+ }
+
+ override def remove(k: K): Option[V] = {
+ val hc = computeHash(k)
+ removehc(k = k, v = null.asInstanceOf[V], RemovalPolicy.Always, hc = hc)
+ }
+
+ def subtractOne(k: K) = {
+ remove(k)
+ this
+ }
+
+ def putIfAbsent(k: K, v: V): Option[V] = {
+ val hc = computeHash(k)
+ insertifhc(k, hc, v, INode.KEY_ABSENT, fullEquals = false /* unused */)
+ }
+
+ // TODO once computeIfAbsent is added to concurrent.Map,
+ // move the comment there and tweak the 'at most once' part
+ /** If the specified key is not already in the map, computes its value using
+ * the given thunk `defaultValue` and enters it into the map.
+ *
+ * If the specified mapping function throws an exception,
+ * that exception is rethrown.
+ *
+ * Note: This method will invoke `defaultValue` at most once.
+ * However, `defaultValue` may be invoked without the result being added to the map if
+ * a concurrent process is also trying to add a value corresponding to the
+ * same key `k`.
+ *
+ * @param k the key to modify
+ * @param defaultValue the expression that computes the value
+ * @return the newly added value
+ */
+ override def getOrElseUpdate(k: K, @deprecatedName("op", since="2.13.13") defaultValue: => V): V = {
+ val hc = computeHash(k)
+ lookuphc(k, hc) match {
+ case INodeBase.NO_SUCH_ELEMENT_SENTINEL =>
+ val v = defaultValue
+ insertifhc(k, hc, v, INode.KEY_ABSENT, fullEquals = false /* unused */) match {
+ case Some(oldValue) => oldValue
+ case None => v
+ }
+ case oldValue => oldValue.asInstanceOf[V]
+ }
+ }
+
+ def remove(k: K, v: V): Boolean = {
+ val hc = computeHash(k)
+ removehc(k, v, RemovalPolicy.FullEquals, hc).nonEmpty
+ }
+
+ override private[collection] def removeRefEq(k: K, v: V): Boolean = {
+ val hc = computeHash(k)
+ removehc(k, v, RemovalPolicy.ReferenceEq, hc).nonEmpty
+ }
+
+ def replace(k: K, oldvalue: V, newvalue: V): Boolean = {
+ val hc = computeHash(k)
+ insertifhc(k, hc, newvalue, oldvalue.asInstanceOf[AnyRef], fullEquals = true).nonEmpty
+ }
+
+ override private[collection] def replaceRefEq(k: K, oldValue: V, newValue: V): Boolean = {
+ val hc = computeHash(k)
+ insertifhc(k, hc, newValue, oldValue.asInstanceOf[AnyRef], fullEquals = false).nonEmpty
+ }
+
+ def replace(k: K, v: V): Option[V] = {
+ val hc = computeHash(k)
+ insertifhc(k, hc, v, INode.KEY_PRESENT, fullEquals = false /* unused */)
+ }
+
+ def iterator: Iterator[(K, V)] = {
+ if (nonReadOnly) readOnlySnapshot().iterator
+ else new TrieMapIterator(0, this)
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // scala/bug#10177 These methods need overrides as the inherited implementations
+ // call `.iterator` more than once, which doesn't guarantee a coherent
+ // view of the data if there is a concurrent writer
+ // Note that the we don't need overrides for keysIterator or valuesIterator
+ // TrieMapTest validates the behaviour.
+ override def values: Iterable[V] = {
+ if (nonReadOnly) readOnlySnapshot().values
+ else super.values
+ }
+ override def keySet: Set[K] = {
+ if (nonReadOnly) readOnlySnapshot().keySet
+ else super.keySet
+ }
+
+ override def view: MapView[K, V] = if (nonReadOnly) readOnlySnapshot().view else super.view
+
+ @deprecated("Use .view.filterKeys(f). A future version will include a strict version of this method (for now, .view.filterKeys(p).toMap).", "2.13.0")
+ override def filterKeys(p: K => Boolean): collection.MapView[K, V] = view.filterKeys(p)
+
+ @deprecated("Use .view.mapValues(f). A future version will include a strict version of this method (for now, .view.mapValues(f).toMap).", "2.13.0")
+ override def mapValues[W](f: V => W): collection.MapView[K, W] = view.mapValues(f)
+ // END extra overrides
+ ///////////////////////////////////////////////////////////////////
+
+ override def size: Int =
+ if (nonReadOnly) readOnlySnapshot().size
+ else RDCSS_READ_ROOT().cachedSize(this)
+ override def knownSize: Int =
+ if (nonReadOnly) -1
+ else RDCSS_READ_ROOT().knownSize(this)
+ override def isEmpty: Boolean =
+ (if (nonReadOnly) readOnlySnapshot() else this).sizeIs == 0 // sizeIs checks knownSize
+ override protected[this] def className = "TrieMap"
+
+ override def lastOption: Option[(K, V)] = if (isEmpty) None else Try(last).toOption
+}
+
+
+@SerialVersionUID(3L)
+object TrieMap extends MapFactory[TrieMap] {
+
+ def empty[K, V]: TrieMap[K, V] = new TrieMap[K, V]
+
+ def from[K, V](it: IterableOnce[(K, V)]): TrieMap[K, V] = new TrieMap[K, V]() ++= it
+
+ def newBuilder[K, V]: mutable.GrowableBuilder[(K, V), TrieMap[K, V]] = new GrowableBuilder(empty[K, V])
+
+ @transient
+ val inodeupdater: AtomicReferenceFieldUpdater[INodeBase[_, _], MainNode[_, _]] = AtomicReferenceFieldUpdater.newUpdater(classOf[INodeBase[_, _]], classOf[MainNode[_, _]], "mainnode")
+
+ class MangledHashing[K] extends Hashing[K] {
+ def hash(k: K): Int = scala.util.hashing.byteswap32(k.##)
+ }
+
+ private[concurrent] object RemovalPolicy {
+ final val Always = 0
+ final val FullEquals = 1
+ final val ReferenceEq = 2
+
+ def shouldRemove[V](removalPolicy: Int)(a: V, b: V): Boolean =
+ removalPolicy match {
+ case Always => true
+ case FullEquals => a == b
+ case ReferenceEq => a.asInstanceOf[AnyRef] eq b.asInstanceOf[AnyRef]
+ }
+ }
+}
+
+// non-final as an extension point for parallel collections
+private[collection] class TrieMapIterator[K, V](var level: Int, private var ct: TrieMap[K, V], mustInit: Boolean = true) extends AbstractIterator[(K, V)] {
+ private val stack = new Array[Array[BasicNode]](7)
+ private val stackpos = new Array[Int](7)
+ private var depth = -1
+ private var subiter: Iterator[(K, V)] = null
+ private var current: KVNode[K, V] = null
+
+ if (mustInit) initialize()
+
+ def hasNext = (current ne null) || (subiter ne null)
+
+ def next() = if (hasNext) {
+ var r: (K, V) = null
+ if (subiter ne null) {
+ r = subiter.next()
+ checkSubiter()
+ } else {
+ r = current.kvPair
+ advance()
+ }
+ r
+ } else Iterator.empty.next()
+
+ private def readin(in: INode[K, V]) = in.gcasRead(ct) match {
+ case cn: CNode[K, V] =>
+ depth += 1
+ stack(depth) = cn.array
+ stackpos(depth) = -1
+ advance()
+ case tn: TNode[K, V] =>
+ current = tn
+ case ln: LNode[K, V] =>
+ subiter = ln.entries.iterator
+ checkSubiter()
+ case null =>
+ current = null
+ case mainNode => throw new MatchError(mainNode)
+ }
+
+ private def checkSubiter() = if (!subiter.hasNext) {
+ subiter = null
+ advance()
+ }
+
+ private def initialize(): Unit = {
+ assert(ct.isReadOnly)
+
+ val r = ct.RDCSS_READ_ROOT()
+ readin(r)
+ }
+
+ @tailrec
+ final def advance(): Unit = if (depth >= 0) {
+ val npos = stackpos(depth) + 1
+ if (npos < stack(depth).length) {
+ stackpos(depth) = npos
+ stack(depth)(npos) match {
+ case sn: SNode[K, V] @uc => current = sn
+ case in: INode[K, V] @uc => readin(in)
+ case basicNode => throw new MatchError(basicNode)
+ }
+ } else {
+ depth -= 1
+ advance()
+ }
+ } else current = null
+
+ protected def newIterator(_lev: Int, _ct: TrieMap[K, V], _mustInit: Boolean): TrieMapIterator[K, V] = new TrieMapIterator[K, V](_lev, _ct, _mustInit)
+
+ protected def dupTo(it: TrieMapIterator[K, V]): Unit = {
+ it.level = this.level
+ it.ct = this.ct
+ it.depth = this.depth
+ it.current = this.current
+
+ // these need a deep copy
+ Array.copy(this.stack, 0, it.stack, 0, 7)
+ Array.copy(this.stackpos, 0, it.stackpos, 0, 7)
+
+ // this one needs to be evaluated
+ if (this.subiter == null) it.subiter = null
+ else {
+ val lst = this.subiter.to(immutable.List)
+ this.subiter = lst.iterator
+ it.subiter = lst.iterator
+ }
+ }
+
+ /** Returns a sequence of iterators over subsets of this iterator.
+ * It's used to ease the implementation of splitters for a parallel version of the TrieMap.
+ */
+ protected def subdivide(): Seq[Iterator[(K, V)]] = if (subiter ne null) {
+ // the case where an LNode is being iterated
+ val it = newIterator(level + 1, ct, _mustInit = false)
+ it.depth = -1
+ it.subiter = this.subiter
+ it.current = null
+ this.subiter = null
+ advance()
+ this.level += 1
+ Seq(it, this)
+ } else if (depth == -1) {
+ this.level += 1
+ Seq(this)
+ } else {
+ var d = 0
+ while (d <= depth) {
+ val rem = stack(d).length - 1 - stackpos(d)
+ if (rem > 0) {
+ val (arr1, arr2) = stack(d).drop(stackpos(d) + 1).splitAt(rem / 2)
+ stack(d) = arr1
+ stackpos(d) = -1
+ val it = newIterator(level + 1, ct, _mustInit = false)
+ it.stack(0) = arr2
+ it.stackpos(0) = -1
+ it.depth = 0
+ it.advance() // <-- fix it
+ this.level += 1
+ return Seq(this, it)
+ }
+ d += 1
+ }
+ this.level += 1
+ Seq(this)
+ }
+
+}
+
+/** Only used for ctrie serialization. */
+@SerialVersionUID(3L)
+private[concurrent] case object TrieMapSerializationEnd
diff --git a/library/src/scala/collection/convert/AsJavaConverters.scala b/library/src/scala/collection/convert/AsJavaConverters.scala
new file mode 100644
index 000000000000..2fc73da64fe7
--- /dev/null
+++ b/library/src/scala/collection/convert/AsJavaConverters.scala
@@ -0,0 +1,260 @@
+/*
+ * 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 collection
+package convert
+
+import java.util.{concurrent => juc}
+import java.{lang => jl, util => ju}
+
+import scala.{unchecked => uc}
+
+/** Defines converter methods from Scala to Java collections.
+ * These methods are available through the [[scala.jdk.javaapi.CollectionConverters]] object.
+ */
+trait AsJavaConverters {
+ import JavaCollectionWrappers._
+
+ /**
+ * Converts a Scala `Iterator` to a Java `Iterator`.
+ *
+ * The returned Java `Iterator` is backed by the provided Scala `Iterator` and any side-effects of
+ * using it via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Iterator` was previously obtained from an implicit or explicit call of
+ * `asScala` then the original Java `Iterator` will be returned.
+ *
+ * @param i The Scala `Iterator` to be converted.
+ * @return A Java `Iterator` view of the argument.
+ */
+ def asJava[A](i: Iterator[A]): ju.Iterator[A] = i match {
+ case null => null
+ case wrapper: JIteratorWrapper[A @uc] => wrapper.underlying
+ case _ => new IteratorWrapper(i)
+ }
+
+ /**
+ * Converts a Scala `Iterator` to a Java `Enumeration`.
+ *
+ * The returned Java `Enumeration` is backed by the provided Scala `Iterator` and any side-effects
+ * of using it via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Iterator` was previously obtained from an implicit or explicit call of
+ * `asScala` then the original Java `Enumeration` will be returned.
+ *
+ * @param i The Scala `Iterator` to be converted.
+ * @return A Java `Enumeration` view of the argument.
+ */
+ def asJavaEnumeration[A](i: Iterator[A]): ju.Enumeration[A] = i match {
+ case null => null
+ case wrapper: JEnumerationWrapper[A @uc] => wrapper.underlying
+ case _ => new IteratorWrapper(i)
+ }
+
+ /**
+ * Converts a Scala `Iterable` to a Java `Iterable`.
+ *
+ * The returned Java `Iterable` is backed by the provided Scala `Iterable` and any side-effects of
+ * using it via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Iterable` was previously obtained from an implicit or explicit call of
+ * `asScala` then the original Java `Iterable` will be returned.
+ *
+ * @param i The Scala `Iterable` to be converted.
+ * @return A Java `Iterable` view of the argument.
+ */
+ def asJava[A](i: Iterable[A]): jl.Iterable[A] = i match {
+ case null => null
+ case wrapper: JIterableWrapper[A @uc] => wrapper.underlying
+ case _ => new IterableWrapper(i)
+ }
+
+ /**
+ * Converts a Scala `Iterable` to an immutable Java `Collection`.
+ *
+ * If the Scala `Iterable` was previously obtained from an implicit or explicit call of
+ * `asScala` then the original Java `Collection` will be returned.
+ *
+ * @param i The Scala `Iterable` to be converted.
+ * @return A Java `Collection` view of the argument.
+ */
+ def asJavaCollection[A](i: Iterable[A]): ju.Collection[A] = i match {
+ case null => null
+ case wrapper: JCollectionWrapper[A @uc] => wrapper.underlying
+ case _ => new IterableWrapper(i)
+ }
+
+ /**
+ * Converts a Scala mutable `Buffer` to a Java List.
+ *
+ * The returned Java List is backed by the provided Scala `Buffer` and any side-effects of using
+ * it via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Buffer` was previously obtained from an implicit or explicit call of
+ * `asScala` then the original Java `List` will be returned.
+ *
+ * @param b The Scala `Buffer` to be converted.
+ * @return A Java `List` view of the argument.
+ */
+ def asJava[A](b: mutable.Buffer[A]): ju.List[A] = b match {
+ case null => null
+ case wrapper: JListWrapper[A @uc] => wrapper.underlying
+ case _ => new MutableBufferWrapper(b)
+ }
+
+ /**
+ * Converts a Scala mutable `Seq` to a Java `List`.
+ *
+ * The returned Java `List` is backed by the provided Scala `Seq` and any side-effects of using it
+ * via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Seq` was previously obtained from an implicit or explicit call of
+ * `asScala` then the original Java `List` will be returned.
+ *
+ * @param s The Scala `Seq` to be converted.
+ * @return A Java `List` view of the argument.
+ */
+ def asJava[A](s: mutable.Seq[A]): ju.List[A] = s match {
+ case null => null
+ case wrapper: JListWrapper[A @uc] => wrapper.underlying
+ case _ => new MutableSeqWrapper(s)
+ }
+
+ /**
+ * Converts a Scala `Seq` to a Java `List`.
+ *
+ * The returned Java `List` is backed by the provided Scala `Seq` and any side-effects of using it
+ * via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Seq` was previously obtained from an implicit or explicit call of
+ * `asScala` then the original Java `List` will be returned.
+ *
+ * @param s The Scala `Seq` to be converted.
+ * @return A Java `List` view of the argument.
+ */
+ def asJava[A](s: Seq[A]): ju.List[A] = s match {
+ case null => null
+ case wrapper: JListWrapper[A @uc] => wrapper.underlying
+ case _ => new SeqWrapper(s)
+ }
+
+ /**
+ * Converts a Scala mutable `Set` to a Java `Set`.
+ *
+ * The returned Java `Set` is backed by the provided Scala `Set` and any side-effects of using it
+ * via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Set` was previously obtained from an implicit or explicit call of
+ * `asScala` then the original Java `Set` will be returned.
+ *
+ * @param s The Scala mutable `Set` to be converted.
+ * @return A Java `Set` view of the argument.
+ */
+ def asJava[A](s: mutable.Set[A]): ju.Set[A] = s match {
+ case null => null
+ case wrapper: JSetWrapper[A @uc] => wrapper.underlying
+ case _ => new MutableSetWrapper(s)
+ }
+
+ /**
+ * Converts a Scala `Set` to a Java `Set`.
+ *
+ * The returned Java `Set` is backed by the provided Scala `Set` and any side-effects of using it
+ * via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Set` was previously obtained from an implicit or explicit call of
+ * `asScala` then the original Java `Set` will be returned.
+ *
+ * @param s The Scala `Set` to be converted.
+ * @return A Java `Set` view of the argument.
+ */
+ def asJava[A](s: Set[A]): ju.Set[A] = s match {
+ case null => null
+ case wrapper: JSetWrapper[A @uc] => wrapper.underlying
+ case _ => new SetWrapper(s)
+ }
+
+ /**
+ * Converts a Scala mutable `Map` to a Java `Map`.
+ *
+ * The returned Java `Map` is backed by the provided Scala `Map` and any side-effects of using it
+ * via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Map` was previously obtained from an implicit or explicit call of
+ * `asScala` then the original Java `Map` will be returned.
+ *
+ * @param m The Scala mutable `Map` to be converted.
+ * @return A Java `Map` view of the argument.
+ */
+ def asJava[K, V](m: mutable.Map[K, V]): ju.Map[K, V] = m match {
+ case null => null
+ case wrapper: JMapWrapper[K @uc, V @uc] => wrapper.underlying
+ case _ => new MutableMapWrapper(m)
+ }
+
+ /**
+ * Converts a Scala mutable `Map` to a Java `Dictionary`.
+ *
+ * The returned Java `Dictionary` is backed by the provided Scala `Dictionary` and any
+ * side-effects of using it via the Java interface will be visible via the Scala interface and
+ * vice versa.
+ *
+ * If the Scala `Map` was previously obtained from an implicit or explicit call of
+ * `asScala` then the original Java `Dictionary` will be returned.
+ *
+ * @param m The Scala `Map` to be converted.
+ * @return A Java `Dictionary` view of the argument.
+ */
+ def asJavaDictionary[K, V](m: mutable.Map[K, V]): ju.Dictionary[K, V] = m match {
+ case null => null
+ case wrapper: JDictionaryWrapper[K @uc, V @uc] => wrapper.underlying
+ case _ => new DictionaryWrapper(m)
+ }
+
+ /**
+ * Converts a Scala `Map` to a Java `Map`.
+ *
+ * The returned Java `Map` is backed by the provided Scala `Map` and any side-effects of using it
+ * via the Java interface will be visible via the Scala interface and vice versa.
+ *
+ * If the Scala `Map` was previously obtained from an implicit or explicit call of
+ * `asScala` then the original Java `Map` will be returned.
+ *
+ * @param m The Scala `Map` to be converted.
+ * @return A Java `Map` view of the argument.
+ */
+ def asJava[K, V](m: Map[K, V]): ju.Map[K, V] = m match {
+ case null => null
+ case wrapper: JMapWrapper[K @uc, V @uc] => wrapper.underlying
+ case _ => new MapWrapper(m)
+ }
+
+ /**
+ * Converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`.
+ *
+ * The returned Java `ConcurrentMap` is backed by the provided Scala `concurrent.Map` and any
+ * side-effects of using it via the Java interface will be visible via the Scala interface and
+ * vice versa.
+ *
+ * If the Scala `concurrent.Map` was previously obtained from an implicit or explicit call of
+ * `asScala` then the original Java `ConcurrentMap` will be returned.
+ *
+ * @param m The Scala `concurrent.Map` to be converted.
+ * @return A Java `ConcurrentMap` view of the argument.
+ */
+ def asJava[K, V](m: concurrent.Map[K, V]): juc.ConcurrentMap[K, V] = m match {
+ case null => null
+ case wrapper: JConcurrentMapWrapper[K @uc, V @uc] => wrapper.underlying
+ case _ => new ConcurrentMapWrapper(m)
+ }
+}
diff --git a/library/src/scala/collection/convert/AsJavaExtensions.scala b/library/src/scala/collection/convert/AsJavaExtensions.scala
new file mode 100644
index 000000000000..d356a419325d
--- /dev/null
+++ b/library/src/scala/collection/convert/AsJavaExtensions.scala
@@ -0,0 +1,108 @@
+/*
+ * 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 collection
+package convert
+
+import java.util.{concurrent => juc}
+import java.{lang => jl, util => ju}
+
+/** Defines `asJava` extension methods, available through [[scala.jdk.CollectionConverters]]. */
+trait AsJavaExtensions {
+ import scala.jdk.javaapi.{CollectionConverters => conv}
+
+ implicit class IteratorHasAsJava[A](i: Iterator[A]) {
+ /** Converts a Scala `Iterator` to a Java `Iterator`, see
+ * [[AsJavaConverters.asJava[A](i:Iterator[A])* `scala.jdk.javaapi.CollectionConverters.asJava`]].
+ */
+ def asJava: ju.Iterator[A] = conv.asJava(i)
+
+ /** Converts a Scala `Iterator` to a Java `Enumeration`, see
+ * [[AsJavaConverters.asJavaEnumeration `scala.jdk.javaapi.CollectionConverters.asJavaEnumeration`]].
+ */
+ def asJavaEnumeration: ju.Enumeration[A] = conv.asJavaEnumeration(i)
+ }
+
+ implicit class IterableHasAsJava[A](i: Iterable[A]) {
+ /** Converts a Scala `Iterable` to a Java `Iterable`, see
+ * [[AsJavaConverters.asJava[A](i:Iterable[A])* `scala.jdk.javaapi.CollectionConverters.asJava`]].
+ */
+ def asJava: jl.Iterable[A] = conv.asJava(i)
+
+ /** Converts a Scala `Iterator` to a Java `Collection`, see
+ * [[AsJavaConverters.asJavaCollection `scala.jdk.javaapi.CollectionConverters.asJavaCollection`]].
+ */
+ def asJavaCollection: ju.Collection[A] = conv.asJavaCollection(i)
+ }
+
+ implicit class BufferHasAsJava[A](b: mutable.Buffer[A]) {
+ /** Converts a Scala `Buffer` to a Java `List`, see
+ * [[AsJavaConverters.asJava[A](b:scala\.collection\.mutable\.Buffer[A])* `scala.jdk.javaapi.CollectionConverters.asJava`]].
+ */
+ def asJava: ju.List[A] = conv.asJava(b)
+ }
+
+ implicit class MutableSeqHasAsJava[A](s: mutable.Seq[A]) {
+ /** Converts a Scala `Seq` to a Java `List`, see
+ * [[AsJavaConverters.asJava[A](s:scala\.collection\.mutable\.Seq[A])* `scala.jdk.javaapi.CollectionConverters.asJava`]].
+ */
+ def asJava: ju.List[A] = conv.asJava(s)
+ }
+
+ implicit class SeqHasAsJava[A](s: Seq[A]) {
+ /** Converts a Scala `Seq` to a Java `List`, see
+ * [[AsJavaConverters.asJava[A](s:scala\.collection\.Seq[A])* `scala.jdk.javaapi.CollectionConverters.asJava`]].
+ */
+ def asJava: ju.List[A] = conv.asJava(s)
+ }
+
+ implicit class MutableSetHasAsJava[A](s: mutable.Set[A]) {
+ /** Converts a Scala `mutable.Set` to a Java `Set`, see
+ * [[AsJavaConverters.asJava[A](s:scala\.collection\.mutable\.Set[A])* `scala.jdk.javaapi.CollectionConverters.asJava`]].
+ */
+ def asJava: ju.Set[A] = conv.asJava(s)
+ }
+
+ implicit class SetHasAsJava[A](s: Set[A]) {
+ /** Converts a Scala `Set` to a Java `Set`, see
+ * [[AsJavaConverters.asJava[A](s:scala\.collection\.Set[A])* `scala.jdk.javaapi.CollectionConverters.asJava`]].
+ */
+ def asJava: ju.Set[A] = conv.asJava(s)
+ }
+
+ implicit class MutableMapHasAsJava[K, V](m: mutable.Map[K, V]) {
+ /** Converts a Scala `mutable.Map` to a Java `Map`, see
+ * [[AsJavaConverters.asJava[K,V](m:scala\.collection\.mutable\.Map[K,V])* `scala.jdk.javaapi.CollectionConverters.asJava`]].
+ */
+ def asJava: ju.Map[K, V] = conv.asJava(m)
+
+ /** Converts a Scala `mutable.Map` to a Java `Map`, see
+ * [[AsJavaConverters.asJavaDictionary `scala.jdk.javaapi.CollectionConverters.asJavaDictionary`]].
+ */
+ def asJavaDictionary: ju.Dictionary[K, V] = conv.asJavaDictionary(m)
+ }
+
+ implicit class MapHasAsJava[K, V](m: Map[K, V]) {
+ /** Converts a Scala `Map` to a Java `Map`, see
+ * [[AsJavaConverters.asJava[K,V](m:scala\.collection\.Map[K,V])* `scala.jdk.javaapi.CollectionConverters.asJava`]].
+ */
+ def asJava: ju.Map[K, V] = conv.asJava(m)
+ }
+
+ implicit class ConcurrentMapHasAsJava[K, V](m: concurrent.Map[K, V]) {
+ /** Converts a Scala `concurrent.Map` to a Java `ConcurrentMap`, see
+ * [[AsJavaConverters.asJava[K,V](m:scala\.collection\.concurrent\.Map[K,V])* `scala.jdk.javaapi.CollectionConverters.asJava`]].
+ */
+ def asJava: juc.ConcurrentMap[K, V] = conv.asJava(m)
+ }
+}
diff --git a/library/src/scala/collection/convert/AsScalaConverters.scala b/library/src/scala/collection/convert/AsScalaConverters.scala
new file mode 100644
index 000000000000..e1055c60b36e
--- /dev/null
+++ b/library/src/scala/collection/convert/AsScalaConverters.scala
@@ -0,0 +1,207 @@
+/*
+ * 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 collection
+package convert
+
+import java.util.{concurrent => juc}
+import java.{lang => jl, util => ju}
+
+import scala.{unchecked => uc}
+
+/** Defines converter methods from Java to Scala collections.
+ * These methods are available through the [[scala.jdk.javaapi.CollectionConverters]] object.
+ */
+trait AsScalaConverters {
+ import JavaCollectionWrappers._
+
+ /**
+ * Converts a Java `Iterator` to a Scala `Iterator`.
+ *
+ * The returned Scala `Iterator` is backed by the provided Java `Iterator` and any side-effects of
+ * using it via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `Iterator` was previously obtained from an implicit or explicit call of
+ * `asJava` then the original Scala `Iterator` will be returned.
+ *
+ * @param i The Java `Iterator` to be converted.
+ * @return A Scala `Iterator` view of the argument.
+ */
+ def asScala[A](i: ju.Iterator[A]): Iterator[A] = i match {
+ case null => null
+ case wrapper: IteratorWrapper[A @uc] => wrapper.underlying
+ case _ => new JIteratorWrapper(i)
+ }
+
+ /**
+ * Converts a Java `Enumeration` to a Scala `Iterator`.
+ *
+ * The returned Scala `Iterator` is backed by the provided Java `Enumeration` and any side-effects
+ * of using it via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `Enumeration` was previously obtained from an implicit or explicit call of
+ * `asJavaEnumeration` then the original Scala `Iterator` will be returned.
+ *
+ * @param e The Java `Enumeration` to be converted.
+ * @return A Scala `Iterator` view of the argument.
+ */
+ def asScala[A](e: ju.Enumeration[A]): Iterator[A] = e match {
+ case null => null
+ case wrapper: IteratorWrapper[A @uc] => wrapper.underlying
+ case _ => new JEnumerationWrapper(e)
+ }
+
+ /**
+ * Converts a Java `Iterable` to a Scala `Iterable`.
+ *
+ * The returned Scala `Iterable` is backed by the provided Java `Iterable` and any side-effects of
+ * using it via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `Iterable` was previously obtained from an implicit or explicit call of
+ * `asJava` then the original Scala `Iterable` will be returned.
+ *
+ * @param i The Java `Iterable` to be converted.
+ * @return A Scala `Iterable` view of the argument.
+ */
+ def asScala[A](i: jl.Iterable[A]): Iterable[A] = i match {
+ case null => null
+ case wrapper: IterableWrapper[A @uc] => wrapper.underlying
+ case _ => new JIterableWrapper(i)
+ }
+
+ /**
+ * Converts a Java `Collection` to a Scala `Iterable`.
+ *
+ * If the Java `Collection` was previously obtained from an implicit or explicit call of
+ * `asJavaCollection` then the original Scala `Iterable` will be returned.
+ *
+ * @param c The Java `Collection` to be converted.
+ * @return A Scala `Iterable` view of the argument.
+ */
+ def asScala[A](c: ju.Collection[A]): Iterable[A] = c match {
+ case null => null
+ case wrapper: IterableWrapper[A @uc] => wrapper.underlying
+ case _ => new JCollectionWrapper(c)
+ }
+
+ /**
+ * Converts a Java `List` to a Scala mutable `Buffer`.
+ *
+ * The returned Scala `Buffer` is backed by the provided Java `List` and any side-effects of using
+ * it via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `List` was previously obtained from an implicit or explicit call of
+ * `asJava` then the original Scala `Buffer` will be returned.
+ *
+ * @param l The Java `List` to be converted.
+ * @return A Scala mutable `Buffer` view of the argument.
+ */
+ def asScala[A](l: ju.List[A]): mutable.Buffer[A] = l match {
+ case null => null
+ case wrapper: MutableBufferWrapper[A @uc] => wrapper.underlying
+ case _ => new JListWrapper(l)
+ }
+
+ /**
+ * Converts a Java `Set` to a Scala mutable `Set`.
+ *
+ * The returned Scala `Set` is backed by the provided Java `Set` and any side-effects of using it
+ * via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `Set` was previously obtained from an implicit or explicit call of
+ * `asJava` then the original Scala `Set` will be returned.
+ *
+ * @param s The Java `Set` to be converted.
+ * @return A Scala mutable `Set` view of the argument.
+ */
+ def asScala[A](s: ju.Set[A]): mutable.Set[A] = s match {
+ case null => null
+ case wrapper: MutableSetWrapper[A @uc] => wrapper.underlying
+ case _ => new JSetWrapper(s)
+ }
+
+ /**
+ * Converts a Java `Map` to a Scala mutable `Map`.
+ *
+ * The returned Scala `Map` is backed by the provided Java `Map` and any side-effects of using it
+ * via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `Map` was previously obtained from an implicit or explicit call of
+ * `asJava` then the original Scala `Map` will be returned.
+ *
+ * If the wrapped map is synchronized (e.g. from `java.util.Collections.synchronizedMap`), it is
+ * your responsibility to wrap all non-atomic operations with `underlying.synchronized`.
+ * This includes `get`, as `java.util.Map`'s API does not allow for an atomic `get` when `null`
+ * values may be present.
+ *
+ * @param m The Java `Map` to be converted.
+ * @return A Scala mutable `Map` view of the argument.
+ */
+ def asScala[K, V](m: ju.Map[K, V]): mutable.Map[K, V] = m match {
+ case null => null
+ case wrapper: MutableMapWrapper[K @uc, V @uc] => wrapper.underlying
+ case _ => new JMapWrapper(m)
+ }
+
+ /**
+ * Converts a Java `ConcurrentMap` to a Scala mutable `ConcurrentMap`.
+ *
+ * The returned Scala `ConcurrentMap` is backed by the provided Java `ConcurrentMap` and any
+ * side-effects of using it via the Scala interface will be visible via the Java interface and
+ * vice versa.
+ *
+ * If the Java `ConcurrentMap` was previously obtained from an implicit or explicit call of
+ * `asJava` then the original Scala `ConcurrentMap` will be returned.
+ *
+ * @param m The Java `ConcurrentMap` to be converted.
+ * @return A Scala mutable `ConcurrentMap` view of the argument.
+ */
+ def asScala[K, V](m: juc.ConcurrentMap[K, V]): concurrent.Map[K, V] = m match {
+ case null => null
+ case wrapper: ConcurrentMapWrapper[K @uc, V @uc] => wrapper.underlyingConcurrentMap
+ case _ => new JConcurrentMapWrapper(m)
+ }
+
+ /**
+ * Converts a Java `Dictionary` to a Scala mutable `Map`.
+ *
+ * The returned Scala `Map` is backed by the provided Java `Dictionary` and any side-effects of
+ * using it via the Scala interface will be visible via the Java interface and vice versa.
+ *
+ * If the Java `Dictionary` was previously obtained from an implicit or explicit call of
+ * `asJavaDictionary` then the original Scala `Map` will be returned.
+ *
+ * @param d The Java `Dictionary` to be converted.
+ * @return A Scala mutable `Map` view of the argument.
+ */
+ def asScala[K, V](d: ju.Dictionary[K, V]): mutable.Map[K, V] = d match {
+ case null => null
+ case wrapper: DictionaryWrapper[K @uc, V @uc] => wrapper.underlying
+ case _ => new JDictionaryWrapper(d)
+ }
+
+ /**
+ * Converts a Java `Properties` to a Scala mutable `Map[String, String]`.
+ *
+ * The returned Scala `Map[String, String]` is backed by the provided Java `Properties` and any
+ * side-effects of using it via the Scala interface will be visible via the Java interface and
+ * vice versa.
+ *
+ * @param p The Java `Properties` to be converted.
+ * @return A Scala mutable `Map[String, String]` view of the argument.
+ */
+ def asScala(p: ju.Properties): mutable.Map[String, String] = p match {
+ case null => null
+ case _ => new JPropertiesWrapper(p)
+ }
+}
diff --git a/library/src/scala/collection/convert/AsScalaExtensions.scala b/library/src/scala/collection/convert/AsScalaExtensions.scala
new file mode 100644
index 000000000000..ef08f4505fe1
--- /dev/null
+++ b/library/src/scala/collection/convert/AsScalaExtensions.scala
@@ -0,0 +1,93 @@
+/*
+ * 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 collection
+package convert
+
+import java.util.{concurrent => juc}
+import java.{lang => jl, util => ju}
+
+/** Defines `asScala` extension methods, available through [[scala.jdk.CollectionConverters]]. */
+trait AsScalaExtensions {
+ import scala.jdk.javaapi.{CollectionConverters => conv}
+
+ implicit class IteratorHasAsScala[A](i: ju.Iterator[A]) {
+ /** Converts a Java `Iterator` to a Scala `Iterator`, see
+ * [[AsScalaConverters.asScala[A](i:java\.util\.Iterator[A])* `scala.jdk.javaapi.CollectionConverters.asScala`]].
+ */
+ def asScala: Iterator[A] = conv.asScala(i)
+ }
+
+ implicit class EnumerationHasAsScala[A](e: ju.Enumeration[A]) {
+ /** Converts a Java `Enumeration` to a Scala `Iterator`, see
+ * [[AsScalaConverters.asScala[A](e:java\.util\.Enumeration[A])* `scala.jdk.javaapi.CollectionConverters.asScala`]].
+ */
+ def asScala: Iterator[A] = conv.asScala(e)
+ }
+
+ implicit class IterableHasAsScala[A](i: jl.Iterable[A]) {
+ /** Converts a Java `Iterable` to a Scala `Iterable`, see
+ * [[AsScalaConverters.asScala[A](i:Iterable[A])* `scala.jdk.javaapi.CollectionConverters.asScala`]].
+ */
+ def asScala: Iterable[A] = conv.asScala(i)
+ }
+
+ implicit class CollectionHasAsScala[A](c: ju.Collection[A]) {
+ /** Converts a Java `Collection` to a Scala `Iterable`, see
+ * [[AsScalaConverters.asScala[A](c:java\.util\.Collection[A])* `scala.jdk.javaapi.CollectionConverters.asScala`]].
+ */
+ def asScala: Iterable[A] = conv.asScala(c)
+ }
+
+ implicit class ListHasAsScala[A](l: ju.List[A]) {
+ /** Converts a Java `List` to a Scala `Buffer`, see
+ * [[AsScalaConverters.asScala[A](l:java\.util\.List[A])* `scala.jdk.javaapi.CollectionConverters.asScala`]].
+ */
+ def asScala: mutable.Buffer[A] = conv.asScala(l)
+ }
+
+ implicit class SetHasAsScala[A](s: ju.Set[A]) {
+ /** Converts a Java `Set` to a Scala `Set`, see
+ * [[AsScalaConverters.asScala[A](s:java\.util\.Set[A])* `scala.jdk.javaapi.CollectionConverters.asScala`]].
+ */
+ def asScala: mutable.Set[A] = conv.asScala(s)
+ }
+
+ implicit class MapHasAsScala[K, V](m: ju.Map[K, V]) {
+ /** Converts a Java `Map` to a Scala `Map`, see
+ * [[AsScalaConverters.asScala[A,B](m:java\.util\.Map[A,B])* `scala.jdk.javaapi.CollectionConverters.asScala`]].
+ */
+ def asScala: mutable.Map[K, V] = conv.asScala(m)
+ }
+
+ implicit class ConcurrentMapHasAsScala[K, V](m: juc.ConcurrentMap[K, V]) {
+ /** Converts a Java `ConcurrentMap` to a Scala `concurrent.Map`, see
+ * [[AsScalaConverters.asScala[A,B](m:java\.util\.concurrent\.ConcurrentMap[A,B])* `scala.jdk.javaapi.CollectionConverters.asScala`]].
+ */
+ def asScala: concurrent.Map[K, V] = conv.asScala(m)
+ }
+
+ implicit class DictionaryHasAsScala[K, V](d: ju.Dictionary[K, V]) {
+ /** Converts a Java `Dictionary` to a Scala `Map`, see
+ * [[AsScalaConverters.asScala[A,B](d:java\.util\.Dictionary[A,B])* `scala.jdk.javaapi.CollectionConverters.asScala`]].
+ */
+ def asScala: mutable.Map[K, V] = conv.asScala(d)
+ }
+
+ implicit class PropertiesHasAsScala(i: ju.Properties) {
+ /** Converts a Java `Properties` to a Scala `Map`, see
+ * [[AsScalaConverters.asScala(p:java\.util\.Properties)* `scala.jdk.javaapi.CollectionConverters.asScala`]].
+ */
+ def asScala: mutable.Map[String, String] = conv.asScala(i)
+ }
+}
diff --git a/library/src/scala/collection/convert/ImplicitConversions.scala b/library/src/scala/collection/convert/ImplicitConversions.scala
new file mode 100644
index 000000000000..6492c60d6d9e
--- /dev/null
+++ b/library/src/scala/collection/convert/ImplicitConversions.scala
@@ -0,0 +1,181 @@
+/*
+ * 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 collection
+package convert
+
+import java.util.{concurrent => juc}
+import java.{lang => jl, util => ju}
+
+import scala.collection.JavaConverters._
+import scala.language.implicitConversions
+
+/** Defines implicit converter methods from Java to Scala collections. */
+@deprecated("Use `scala.jdk.CollectionConverters` instead", "2.13.0")
+trait ToScalaImplicits {
+ /** Implicitly converts a Java `Iterator` to a Scala `Iterator`.
+ * @see [[JavaConverters.asScalaIterator]]
+ */
+ implicit def `iterator asScala`[A](it: ju.Iterator[A]): Iterator[A] = asScalaIterator(it)
+
+ /** Implicitly converts a Java `Enumeration` to a Scala `Iterator`.
+ * @see [[JavaConverters.enumerationAsScalaIterator]]
+ */
+ implicit def `enumeration AsScalaIterator`[A](i: ju.Enumeration[A]): Iterator[A] = enumerationAsScalaIterator(i)
+
+ /** Implicitly converts a Java `Iterable` to a Scala `Iterable`.
+ * @see [[JavaConverters.iterableAsScalaIterable]]
+ */
+ implicit def `iterable AsScalaIterable`[A](i: jl.Iterable[A]): Iterable[A] = iterableAsScalaIterable(i)
+
+ /** Implicitly converts a Java `Collection` to an Scala `Iterable`.
+ * @see [[JavaConverters.collectionAsScalaIterable]]
+ */
+ implicit def `collection AsScalaIterable`[A](i: ju.Collection[A]): Iterable[A] = collectionAsScalaIterable(i)
+
+ /** Implicitly converts a Java `List` to a Scala mutable `Buffer`.
+ * @see [[JavaConverters.asScalaBuffer]]
+ */
+ implicit def `list asScalaBuffer`[A](l: ju.List[A]): mutable.Buffer[A] = asScalaBuffer(l)
+
+ /** Implicitly converts a Java `Set` to a Scala mutable `Set`.
+ * @see [[JavaConverters.asScalaSet]]
+ */
+ implicit def `set asScala`[A](s: ju.Set[A]): mutable.Set[A] = asScalaSet(s)
+
+ /** Implicitly converts a Java `Map` to a Scala mutable `Map`.
+ * @see [[JavaConverters.mapAsScalaMap]]
+ */
+ implicit def `map AsScala`[K, V](m: ju.Map[K, V]): mutable.Map[K, V] = mapAsScalaMap(m)
+
+ /** Implicitly converts a Java `ConcurrentMap` to a Scala mutable `ConcurrentMap`.
+ * @see [[JavaConverters.mapAsScalaConcurrentMap]]
+ */
+ implicit def `map AsScalaConcurrentMap`[K, V](m: juc.ConcurrentMap[K, V]): concurrent.Map[K, V] = mapAsScalaConcurrentMap(m)
+
+ /** Implicitly converts a Java `Dictionary` to a Scala mutable `Map`.
+ * @see [[JavaConverters.dictionaryAsScalaMap]]
+ */
+ implicit def `dictionary AsScalaMap`[K, V](p: ju.Dictionary[K, V]): mutable.Map[K, V] = dictionaryAsScalaMap(p)
+
+ /** Implicitly converts a Java `Properties` to a Scala `mutable Map[String, String]`.
+ * @see [[JavaConverters.propertiesAsScalaMap]]
+ */
+ implicit def `properties AsScalaMap`(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p)
+}
+
+/** Defines implicit conversions from Scala to Java collections. */
+@deprecated("Use `scala.jdk.CollectionConverters` instead", "2.13.0")
+trait ToJavaImplicits {
+ /** Implicitly converts a Scala `Iterator` to a Java `Iterator`.
+ * @see [[JavaConverters.asJavaIterator]]
+ */
+ implicit def `iterator asJava`[A](it: Iterator[A]): ju.Iterator[A] = asJavaIterator(it)
+
+ /** Implicitly converts a Scala `Iterator` to a Java `Enumeration`.
+ * @see [[JavaConverters.asJavaEnumeration]]
+ */
+ implicit def `enumeration asJava`[A](it: Iterator[A]): ju.Enumeration[A] = asJavaEnumeration(it)
+
+ /** Implicitly converts a Scala `Iterable` to a Java `Iterable`.
+ * @see [[JavaConverters.asJavaIterable]]
+ */
+ implicit def `iterable asJava`[A](i: Iterable[A]): jl.Iterable[A] = asJavaIterable(i)
+
+ /** Implicitly converts a Scala `Iterable` to an immutable Java `Collection`.
+ * @see [[JavaConverters.asJavaCollection]]
+ */
+ implicit def `collection asJava`[A](it: Iterable[A]): ju.Collection[A] = asJavaCollection(it)
+
+ /** Implicitly converts a Scala mutable `Buffer` to a Java `List`.
+ * @see [[JavaConverters.bufferAsJavaList]]
+ */
+ implicit def `buffer AsJavaList`[A](b: mutable.Buffer[A]): ju.List[A] = bufferAsJavaList(b)
+
+ /** Implicitly converts a Scala mutable `Seq` to a Java `List`.
+ * @see [[JavaConverters.mutableSeqAsJavaList]]
+ */
+ implicit def `mutableSeq AsJavaList`[A](seq: mutable.Seq[A]): ju.List[A] = mutableSeqAsJavaList(seq)
+
+ /** Implicitly converts a Scala `Seq` to a Java `List`.
+ * @see [[JavaConverters.seqAsJavaList]]
+ */
+ implicit def `seq AsJavaList`[A](seq: Seq[A]): ju.List[A] = seqAsJavaList(seq)
+
+ /** Implicitly converts a Scala mutable `Set` to a Java `Set`.
+ * @see [[JavaConverters.mutableSetAsJavaSet]]
+ */
+ implicit def `mutableSet AsJavaSet`[A](s: mutable.Set[A]): ju.Set[A] = mutableSetAsJavaSet(s)
+
+ /** Implicitly converts a Scala `Set` to a Java `Set`.
+ * @see [[JavaConverters.setAsJavaSet]]
+ */
+ implicit def `set AsJavaSet`[A](s: Set[A]): ju.Set[A] = setAsJavaSet(s)
+
+ /** Implicitly converts a Scala mutable `Map` to a Java `Map`.
+ * @see [[JavaConverters.mutableMapAsJavaMap]]
+ */
+ implicit def `mutableMap AsJavaMap`[K, V](m: mutable.Map[K, V]): ju.Map[K, V] = mutableMapAsJavaMap(m)
+
+ /** Implicitly converts a Scala mutable `Map` to a Java `Dictionary`.
+ * @see [[JavaConverters.asJavaDictionary]]
+ */
+ implicit def `dictionary asJava`[K, V](m: mutable.Map[K, V]): ju.Dictionary[K, V] = asJavaDictionary(m)
+
+ /** Implicitly converts a Scala `Map` to a Java `Map`.
+ * @see [[JavaConverters.mapAsJavaMap]]
+ */
+ implicit def `map AsJavaMap`[K, V](m: Map[K, V]): ju.Map[K, V] = mapAsJavaMap(m)
+
+ /** Implicitly converts a Scala mutable `concurrent.Map` to a Java `ConcurrentMap`.
+ * @see [[JavaConverters.mapAsJavaConcurrentMap]]
+ */
+ implicit def `map AsJavaConcurrentMap`[K, V](m: concurrent.Map[K, V]): juc.ConcurrentMap[K, V] = mapAsJavaConcurrentMap(m)
+}
+
+/**
+ * Convenience for miscellaneous implicit conversions from Scala to Java collections API.
+ *
+ * It is recommended to use explicit conversions provided by [[collection.JavaConverters]] instead.
+ * Implicit conversions may cause unexpected issues, see [[ImplicitConversions]].
+ */
+@deprecated("Use `scala.jdk.CollectionConverters` instead", "2.13.0")
+object ImplicitConversionsToJava extends ToJavaImplicits
+
+/**
+ * Convenience for miscellaneous implicit conversions from Java to Scala collections API.
+ *
+ * It is recommended to use explicit conversions provided by [[collection.JavaConverters]] instead.
+ * Implicit conversions may cause unexpected issues, see [[ImplicitConversions]].
+ */
+@deprecated("Use `scala.jdk.CollectionConverters` instead", "2.13.0")
+object ImplicitConversionsToScala extends ToScalaImplicits
+
+/**
+ * Convenience for miscellaneous implicit conversions between Java and Scala collections API.
+ *
+ * It is recommended to use explicit conversions provided by [[collection.JavaConverters]] instead.
+ * Implicit conversions may cause unexpected issues. Example:
+ *
+ * {{{
+ * import collection.convert.ImplicitConversions._
+ * case class StringBox(s: String)
+ * val m = Map(StringBox("one") -> "uno")
+ * m.get("one")
+ * }}}
+ *
+ * The above example returns `null` instead of producing a type error at compile-time. The map is
+ * implicitly converted to a `java.util.Map` which provides a method `get(x: AnyRef)`.
+ */
+@deprecated("Use `scala.jdk.CollectionConverters` instead", "2.13.0")
+object ImplicitConversions extends ToScalaImplicits with ToJavaImplicits
diff --git a/library/src/scala/collection/convert/JavaCollectionWrappers.scala b/library/src/scala/collection/convert/JavaCollectionWrappers.scala
new file mode 100644
index 000000000000..f79adff98e23
--- /dev/null
+++ b/library/src/scala/collection/convert/JavaCollectionWrappers.scala
@@ -0,0 +1,635 @@
+/*
+ * 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 collection
+package convert
+
+import java.util.{concurrent => juc}
+import java.util.{NavigableMap}
+import java.{lang => jl, util => ju}
+
+import scala.jdk.CollectionConverters._
+import scala.util.Try
+import scala.util.chaining._
+import scala.util.control.ControlThrowable
+
+/** Wrappers for exposing Scala collections as Java collections and vice-versa */
+@SerialVersionUID(3L)
+// not private[convert] because `WeakHashMap` uses JMapWrapper
+private[collection] object JavaCollectionWrappers extends Serializable {
+ @SerialVersionUID(3L)
+ class IteratorWrapper[A](val underlying: Iterator[A]) extends ju.Iterator[A] with ju.Enumeration[A] with Serializable {
+ def hasNext = underlying.hasNext
+ def next() = underlying.next()
+ def hasMoreElements = underlying.hasNext
+ def nextElement() = underlying.next()
+ override def remove(): Nothing = throw new UnsupportedOperationException
+ override def equals(other: Any): Boolean = other match {
+ case that: IteratorWrapper[_] => this.underlying == that.underlying
+ case _ => false
+ }
+ override def hashCode: Int = underlying.hashCode()
+ }
+
+ @SerialVersionUID(3L)
+ class JIteratorWrapper[A](val underlying: ju.Iterator[A]) extends AbstractIterator[A] with Serializable {
+ def hasNext = underlying.hasNext
+ def next() = underlying.next
+ override def equals(other: Any): Boolean = other match {
+ case that: JIteratorWrapper[_] => this.underlying == that.underlying
+ case _ => false
+ }
+ override def hashCode: Int = underlying.hashCode()
+ }
+
+ @SerialVersionUID(3L)
+ class JEnumerationWrapper[A](val underlying: ju.Enumeration[A]) extends AbstractIterator[A] with Serializable {
+ def hasNext = underlying.hasMoreElements
+ def next() = underlying.nextElement
+ override def equals(other: Any): Boolean = other match {
+ case that: JEnumerationWrapper[_] => this.underlying == that.underlying
+ case _ => false
+ }
+ override def hashCode: Int = underlying.hashCode()
+ }
+
+ trait IterableWrapperTrait[A] extends ju.AbstractCollection[A] {
+ val underlying: Iterable[A]
+ def size = underlying.size
+ override def iterator: IteratorWrapper[A] = new IteratorWrapper(underlying.iterator)
+ override def isEmpty = underlying.isEmpty
+ }
+
+ @SerialVersionUID(3L)
+ class IterableWrapper[A](val underlying: Iterable[A]) extends ju.AbstractCollection[A] with IterableWrapperTrait[A] with Serializable {
+ override def equals(other: Any): Boolean = other match {
+ case that: IterableWrapper[_] => this.underlying == that.underlying
+ case _ => false
+ }
+ override def hashCode: Int = underlying.hashCode()
+ }
+
+ @SerialVersionUID(3L)
+ class JIterableWrapper[A](val underlying: jl.Iterable[A])
+ extends AbstractIterable[A]
+ with StrictOptimizedIterableOps[A, Iterable, Iterable[A]]
+ with Serializable {
+ def iterator = underlying.iterator.asScala
+ override def iterableFactory: mutable.ArrayBuffer.type = mutable.ArrayBuffer
+ override def isEmpty: Boolean = !underlying.iterator().hasNext
+ override def equals(other: Any): Boolean = other match {
+ case that: JIterableWrapper[_] => this.underlying == that.underlying
+ case _ => false
+ }
+ override def hashCode: Int = underlying.hashCode()
+ }
+
+ @SerialVersionUID(3L)
+ class JCollectionWrapper[A](val underlying: ju.Collection[A])
+ extends AbstractIterable[A]
+ with StrictOptimizedIterableOps[A, Iterable, Iterable[A]]
+ with Serializable {
+ def iterator = underlying.iterator.asScala
+ override def size = underlying.size
+ override def knownSize: Int = if (underlying.isEmpty) 0 else super.knownSize
+ override def isEmpty = underlying.isEmpty
+ override def iterableFactory: mutable.ArrayBuffer.type = mutable.ArrayBuffer
+ override def equals(other: Any): Boolean = other match {
+ case that: JCollectionWrapper[_] => this.underlying == that.underlying
+ case _ => false
+ }
+ override def hashCode: Int = underlying.hashCode()
+ }
+
+ @SerialVersionUID(3L)
+ class SeqWrapper[A](val underlying: Seq[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] with Serializable {
+ def get(i: Int) = underlying(i)
+ }
+
+ @SerialVersionUID(3L)
+ class MutableSeqWrapper[A](val underlying: mutable.Seq[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] with Serializable {
+ def get(i: Int) = underlying(i)
+ override def set(i: Int, elem: A) = {
+ val p = underlying(i)
+ underlying(i) = elem
+ p
+ }
+ }
+
+ @SerialVersionUID(3L)
+ class MutableBufferWrapper[A](val underlying: mutable.Buffer[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] with Serializable {
+ def get(i: Int) = underlying(i)
+ override def set(i: Int, elem: A) = { val p = underlying(i); underlying(i) = elem; p }
+ override def add(elem: A) = { underlying += elem; true }
+ override def remove(i: Int) = underlying remove i
+ }
+
+ @SerialVersionUID(3L)
+ class JListWrapper[A](val underlying: ju.List[A])
+ extends mutable.AbstractBuffer[A]
+ with SeqOps[A, mutable.Buffer, mutable.Buffer[A]]
+ with StrictOptimizedSeqOps[A, mutable.Buffer, mutable.Buffer[A]]
+ with IterableFactoryDefaults[A, mutable.Buffer]
+ with Serializable {
+ def length = underlying.size
+ override def knownSize: Int = if (underlying.isEmpty) 0 else super.knownSize
+ override def isEmpty = underlying.isEmpty
+ override def iterator: Iterator[A] = underlying.iterator.asScala
+ def apply(i: Int) = underlying.get(i)
+ def update(i: Int, elem: A) = underlying.set(i, elem)
+ def prepend(elem: A) = { underlying.subList(0, 0) add elem; this }
+ def addOne(elem: A): this.type = { underlying add elem; this }
+ def insert(idx: Int,elem: A): Unit = underlying.subList(0, idx).add(elem)
+ def insertAll(i: Int, elems: IterableOnce[A]) = {
+ val ins = underlying.subList(0, i)
+ elems.iterator.foreach(ins.add(_))
+ }
+ def remove(i: Int) = underlying.remove(i)
+ def clear() = underlying.clear()
+ // Note: Clone cannot just call underlying.clone because in Java, only specific collections
+ // expose clone methods. Generically, they're protected.
+ override def clone(): JListWrapper[A] = new JListWrapper(new ju.ArrayList[A](underlying))
+ def patchInPlace(from: Int, patch: scala.collection.IterableOnce[A], replaced: Int): this.type = {
+ remove(from, replaced)
+ insertAll(from, patch)
+ this
+ }
+ def remove(from: Int, n: Int): Unit = underlying.subList(from, from+n).clear()
+ override def iterableFactory: mutable.ArrayBuffer.type = mutable.ArrayBuffer
+ override def subtractOne(elem: A): this.type = { underlying.remove(elem.asInstanceOf[AnyRef]); this }
+ }
+
+ @SerialVersionUID(3L)
+ class SetWrapper[A](underlying: Set[A]) extends ju.AbstractSet[A] with Serializable { self =>
+ // Note various overrides to avoid performance gotchas.
+ override def contains(o: Object): Boolean = {
+ try { underlying.contains(o.asInstanceOf[A]) }
+ catch { case cce: ClassCastException => false }
+ }
+ override def isEmpty = underlying.isEmpty
+ def size = underlying.size
+ def iterator: ju.Iterator[A] = new ju.Iterator[A] {
+ val ui = underlying.iterator
+ var prev: Option[A] = None
+ def hasNext = ui.hasNext
+ def next = { val e = ui.next(); prev = Some(e); e }
+ override def remove() = prev match {
+ case Some(e) =>
+ underlying match {
+ case ms: mutable.Set[a] =>
+ ms remove e
+ prev = None
+ case _ =>
+ throw new UnsupportedOperationException("remove")
+ }
+ case _ =>
+ throw new IllegalStateException("next must be called at least once before remove")
+ }
+ }
+ }
+
+ @SerialVersionUID(3L)
+ class MutableSetWrapper[A](val underlying: mutable.Set[A]) extends SetWrapper[A](underlying) with Serializable {
+ override def add(elem: A) = {
+ val sz = underlying.size
+ underlying += elem
+ sz < underlying.size
+ }
+ override def remove(elem: AnyRef) =
+ try underlying.remove(elem.asInstanceOf[A])
+ catch { case ex: ClassCastException => false }
+ override def clear() = underlying.clear()
+ }
+
+ @SerialVersionUID(3L)
+ class JSetWrapper[A](val underlying: ju.Set[A])
+ extends mutable.AbstractSet[A]
+ with mutable.SetOps[A, mutable.Set, mutable.Set[A]]
+ with StrictOptimizedSetOps[A, mutable.Set, mutable.Set[A]]
+ with Serializable {
+
+ override def size: Int = underlying.size
+ override def isEmpty: Boolean = underlying.isEmpty
+ override def knownSize: Int = if (underlying.isEmpty) 0 else super.knownSize
+ def iterator: Iterator[A] = underlying.iterator.asScala
+
+ def contains(elem: A): Boolean = underlying.contains(elem)
+
+ def addOne(elem: A): this.type = { underlying add elem; this }
+ def subtractOne(elem: A): this.type = { underlying remove elem; this }
+
+ override def remove(elem: A): Boolean = underlying remove elem
+
+ override def clear(): Unit = {
+ underlying.clear()
+ }
+
+ override def empty: mutable.Set[A] = new JSetWrapper(new ju.HashSet[A])
+
+ // Note: Clone cannot just call underlying.clone because in Java, only specific collections
+ // expose clone methods. Generically, they're protected.
+ override def clone(): mutable.Set[A] = new JSetWrapper[A](new ju.LinkedHashSet[A](underlying))
+
+ override def iterableFactory: IterableFactory[mutable.Set] = mutable.HashSet
+
+ override def filterInPlace(p: A => Boolean): this.type = {
+ if (underlying.size() > 0) underlying.removeIf(!p(_))
+ this
+ }
+ }
+
+ @SerialVersionUID(3L)
+ class MapWrapper[K, V](underlying: Map[K, V]) extends ju.AbstractMap[K, V] with Serializable { self =>
+ override def size = underlying.size
+
+ override def get(key: AnyRef): V = try {
+ underlying get key.asInstanceOf[K] match {
+ case None => null.asInstanceOf[V]
+ case Some(v) => v
+ }
+ } catch {
+ case ex: ClassCastException => null.asInstanceOf[V]
+ }
+
+ override def entrySet: ju.Set[ju.Map.Entry[K, V]] = new ju.AbstractSet[ju.Map.Entry[K, V]] {
+ def size = self.size
+
+ def iterator: ju.Iterator[ju.Map.Entry[K, V]] = new ju.Iterator[ju.Map.Entry[K, V]] {
+ val ui = underlying.iterator
+ var prev : Option[K] = None
+
+ def hasNext = ui.hasNext
+
+ def next(): ju.Map.Entry[K, V] = {
+ val (k, v) = ui.next()
+ prev = Some(k)
+ new ju.Map.Entry[K, V] {
+ def getKey = k
+ def getValue = v
+ def setValue(v1 : V) = self.put(k, v1)
+
+ // It's important that this implementation conform to the contract
+ // specified in the javadocs of java.util.Map.Entry.hashCode
+ //
+ // See https://github.com/scala/bug/issues/10663
+ override def hashCode = {
+ (if (k == null) 0 else k.hashCode()) ^
+ (if (v == null) 0 else v.hashCode())
+ }
+
+ override def equals(other: Any) = other match {
+ case e: ju.Map.Entry[_, _] => k == e.getKey && v == e.getValue
+ case _ => false
+ }
+ }
+ }
+
+ override def remove(): Unit = {
+ prev match {
+ case Some(k) =>
+ underlying match {
+ case mm: mutable.Map[a, _] =>
+ mm -= k
+ prev = None
+ case _ =>
+ throw new UnsupportedOperationException("remove")
+ }
+ case _ =>
+ throw new IllegalStateException("next must be called at least once before remove")
+ }
+ }
+ }
+ }
+
+ override def containsKey(key: AnyRef): Boolean = try {
+ // Note: Subclass of collection.Map with specific key type may redirect generic
+ // contains to specific contains, which will throw a ClassCastException if the
+ // wrong type is passed. This is why we need a type cast to A inside a try/catch.
+ underlying.contains(key.asInstanceOf[K])
+ } catch {
+ case ex: ClassCastException => false
+ }
+ }
+
+ @SerialVersionUID(3L)
+ class MutableMapWrapper[K, V](val underlying: mutable.Map[K, V]) extends MapWrapper[K, V](underlying) {
+ override def put(k: K, v: V) = underlying.put(k, v) match {
+ case Some(v1) => v1
+ case None => null.asInstanceOf[V]
+ }
+
+ override def remove(k: AnyRef): V = try {
+ underlying remove k.asInstanceOf[K] match {
+ case None => null.asInstanceOf[V]
+ case Some(v) => v
+ }
+ } catch {
+ case ex: ClassCastException => null.asInstanceOf[V]
+ }
+
+ override def clear() = underlying.clear()
+ }
+
+ @SerialVersionUID(3L)
+ abstract class AbstractJMapWrapper[K, V]
+ extends mutable.AbstractMap[K, V]
+ with JMapWrapperLike[K, V, mutable.Map, mutable.Map[K, V]] with Serializable
+
+ trait JMapWrapperLike[K, V, +CC[X, Y] <: mutable.MapOps[X, Y, CC, _], +C <: mutable.MapOps[K, V, CC, C]]
+ extends mutable.MapOps[K, V, CC, C]
+ with StrictOptimizedMapOps[K, V, CC, C]
+ with StrictOptimizedIterableOps[(K, V), mutable.Iterable, C] {
+
+ def underlying: ju.Map[K, V]
+
+ override def size = underlying.size
+
+ // support Some(null) if currently bound to null
+ def get(k: K) = {
+ val v = underlying.get(k)
+ if (v != null)
+ Some(v)
+ else if (underlying.containsKey(k))
+ Some(null.asInstanceOf[V])
+ else
+ None
+ }
+
+ override def getOrElseUpdate(key: K, op: => V): V =
+ underlying.computeIfAbsent(key, _ => op) match {
+ case null => update(key, null.asInstanceOf[V]); null.asInstanceOf[V]
+ case v => v
+ }
+
+ def addOne(kv: (K, V)): this.type = { underlying.put(kv._1, kv._2); this }
+ def subtractOne(key: K): this.type = { underlying remove key; this }
+
+ // support Some(null) if currently bound to null
+ override def put(k: K, v: V): Option[V] =
+ if (v == null) {
+ val present = underlying.containsKey(k)
+ val result = underlying.put(k, v)
+ if (present) Some(result) else None
+ } else {
+ var result: Option[V] = None
+ def recompute(k0: K, v0: V): V = v.tap(_ =>
+ if (v0 != null) result = Some(v0)
+ else if (underlying.containsKey(k0)) result = Some(null.asInstanceOf[V])
+ )
+ underlying.compute(k, recompute)
+ result
+ }
+
+ override def update(k: K, v: V): Unit = underlying.put(k, v)
+
+ override def updateWith(key: K)(remappingFunction: Option[V] => Option[V]): Option[V] = {
+ def remap(k: K, v: V): V =
+ remappingFunction(Option(v)) match {
+ case Some(null) => throw PutNull
+ case Some(x) => x
+ case None => null.asInstanceOf[V]
+ }
+ try Option(underlying.compute(key, remap))
+ catch {
+ case PutNull => update(key, null.asInstanceOf[V]); Some(null.asInstanceOf[V])
+ }
+ }
+
+ // support Some(null) if currently bound to null
+ override def remove(k: K): Option[V] = {
+ var result: Option[V] = None
+ def recompute(k0: K, v0: V): V = {
+ if (v0 != null) result = Some(v0)
+ else if (underlying.containsKey(k0)) result = Some(null.asInstanceOf[V])
+ null.asInstanceOf[V]
+ }
+ underlying.compute(k, recompute)
+ result
+ }
+
+ def iterator: Iterator[(K, V)] = new AbstractIterator[(K, V)] {
+ val ui = underlying.entrySet.iterator
+ def hasNext = ui.hasNext
+ def next() = { val e = ui.next(); (e.getKey, e.getValue) }
+ }
+
+ override def foreachEntry[U](f: (K, V) => U): Unit = {
+ val i = underlying.entrySet().iterator()
+ while (i.hasNext) {
+ val entry = i.next()
+ f(entry.getKey, entry.getValue)
+ }
+ }
+
+ override def clear() = underlying.clear()
+
+ }
+
+ /** Wraps a Java map as a Scala one. If the map is to support concurrent access,
+ * use [[JConcurrentMapWrapper]] instead. If the wrapped map is synchronized
+ * (e.g. from `java.util.Collections.synchronizedMap`), it is your responsibility
+ * to wrap all non-atomic operations with `underlying.synchronized`.
+ * This includes `get`, as `java.util.Map`'s API does not allow for an
+ * atomic `get` when `null` values may be present.
+ */
+ @SerialVersionUID(3L)
+ class JMapWrapper[K, V](val underlying : ju.Map[K, V])
+ extends AbstractJMapWrapper[K, V] with Serializable {
+
+ override def isEmpty: Boolean = underlying.isEmpty
+ override def knownSize: Int = if (underlying.isEmpty) 0 else super.knownSize
+ override def empty: JMapWrapper[K, V] = new JMapWrapper(new ju.HashMap[K, V])
+ }
+
+ @SerialVersionUID(3L)
+ class ConcurrentMapWrapper[K, V](underlying: concurrent.Map[K, V]) extends MutableMapWrapper[K, V](underlying) with juc.ConcurrentMap[K, V] {
+
+ def underlyingConcurrentMap: concurrent.Map[K, V] = underlying
+
+ override def putIfAbsent(k: K, v: V) = underlying.putIfAbsent(k, v).getOrElse(null.asInstanceOf[V])
+
+ override def remove(k: AnyRef, v: AnyRef) =
+ try underlying.remove(k.asInstanceOf[K], v.asInstanceOf[V])
+ catch { case ex: ClassCastException => false }
+
+ override def replace(k: K, v: V): V = underlying.replace(k, v).getOrElse(null.asInstanceOf[V])
+
+ override def replace(k: K, oldval: V, newval: V) = underlying.replace(k, oldval, newval)
+ }
+
+ /** Wraps a concurrent Java map as a Scala one. Single-element concurrent
+ * access is supported; multi-element operations such as maps and filters
+ * are not guaranteed to be atomic.
+ */
+ @SerialVersionUID(3L)
+ class JConcurrentMapWrapper[K, V](val underlying: juc.ConcurrentMap[K, V])
+ extends AbstractJMapWrapper[K, V]
+ with concurrent.Map[K, V] {
+
+ override def get(k: K) = Option(underlying get k)
+
+ override def getOrElseUpdate(key: K, op: => V): V =
+ underlying.computeIfAbsent(key, _ => op) match {
+ case null => super/*[concurrent.Map]*/.getOrElseUpdate(key, op)
+ case v => v
+ }
+
+ override def isEmpty: Boolean = underlying.isEmpty
+ override def knownSize: Int = if (underlying.isEmpty) 0 else super.knownSize
+ override def empty: JConcurrentMapWrapper[K, V] = new JConcurrentMapWrapper(new juc.ConcurrentHashMap[K, V])
+
+ def putIfAbsent(k: K, v: V): Option[V] = Option(underlying.putIfAbsent(k, v))
+
+ def remove(k: K, v: V): Boolean = underlying.remove(k, v)
+
+ def replace(k: K, v: V): Option[V] = Option(underlying.replace(k, v))
+
+ def replace(k: K, oldvalue: V, newvalue: V): Boolean = underlying.replace(k, oldvalue, newvalue)
+
+ override def lastOption: Option[(K, V)] =
+ underlying match {
+ case nav: NavigableMap[K @unchecked, V @unchecked] => Option(nav.lastEntry).map(e => (e.getKey, e.getValue))
+ case _ if isEmpty => None
+ case _ => Try(last).toOption
+ }
+
+ override def updateWith(key: K)(remappingFunction: Option[V] => Option[V]): Option[V] = {
+ def remap(k: K, v: V): V =
+ remappingFunction(Option(v)) match {
+ case Some(null) => throw PutNull // see scala/scala#10129
+ case Some(x) => x
+ case None => null.asInstanceOf[V]
+ }
+ try Option(underlying.compute(key, remap))
+ catch {
+ case PutNull => super/*[concurrent.Map]*/.updateWith(key)(remappingFunction)
+ }
+ }
+ }
+
+ @SerialVersionUID(3L)
+ class DictionaryWrapper[K, V](val underlying: mutable.Map[K, V]) extends ju.Dictionary[K, V] with Serializable {
+ def size: Int = underlying.size
+ def isEmpty: Boolean = underlying.isEmpty
+ def keys: ju.Enumeration[K] = underlying.keysIterator.asJavaEnumeration
+ def elements: ju.Enumeration[V] = underlying.valuesIterator.asJavaEnumeration
+ def get(key: AnyRef) = try {
+ underlying get key.asInstanceOf[K] match {
+ case None => null.asInstanceOf[V]
+ case Some(v) => v
+ }
+ } catch {
+ case ex: ClassCastException => null.asInstanceOf[V]
+ }
+ def put(key: K, value: V): V = underlying.put(key, value) match {
+ case Some(v) => v
+ case None => null.asInstanceOf[V]
+ }
+ override def remove(key: AnyRef) = try {
+ underlying remove key.asInstanceOf[K] match {
+ case None => null.asInstanceOf[V]
+ case Some(v) => v
+ }
+ } catch {
+ case ex: ClassCastException => null.asInstanceOf[V]
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case that: DictionaryWrapper[_, _] => this.underlying == that.underlying
+ case _ => false
+ }
+
+ override def hashCode: Int = underlying.hashCode()
+ }
+
+ @SerialVersionUID(3L)
+ class JDictionaryWrapper[K, V](val underlying: ju.Dictionary[K, V]) extends mutable.AbstractMap[K, V] with Serializable {
+ override def size: Int = underlying.size
+ override def isEmpty: Boolean = underlying.isEmpty
+ override def knownSize: Int = if (underlying.isEmpty) 0 else super.knownSize
+
+ def get(k: K) = Option(underlying get k)
+
+ def addOne(kv: (K, V)): this.type = { underlying.put(kv._1, kv._2); this }
+ def subtractOne(key: K): this.type = { underlying remove key; this }
+
+ override def put(k: K, v: V): Option[V] = Option(underlying.put(k, v))
+
+ override def update(k: K, v: V): Unit = { underlying.put(k, v) }
+
+ override def remove(k: K): Option[V] = Option(underlying remove k)
+ def iterator = underlying.keys.asScala map (k => (k, underlying get k))
+
+ override def clear() = iterator.foreach(entry => underlying.remove(entry._1))
+
+ override def mapFactory: mutable.HashMap.type = mutable.HashMap
+ }
+
+ @SerialVersionUID(3L)
+ class JPropertiesWrapper(underlying: ju.Properties)
+ extends mutable.AbstractMap[String, String]
+ with mutable.MapOps[String, String, mutable.Map, mutable.Map[String, String]]
+ with StrictOptimizedMapOps[String, String, mutable.Map, mutable.Map[String, String]]
+ with StrictOptimizedIterableOps[(String, String), mutable.Iterable, mutable.Map[String, String]]
+ with Serializable {
+
+ override def size = underlying.size
+ override def isEmpty: Boolean = underlying.isEmpty
+ override def knownSize: Int = size
+ def get(k: String) = {
+ val v = underlying get k
+ if (v != null) Some(v.asInstanceOf[String]) else None
+ }
+
+ def addOne(kv: (String, String)): this.type = { underlying.put(kv._1, kv._2); this }
+ def subtractOne(key: String): this.type = { underlying remove key; this }
+
+ override def put(k: String, v: String): Option[String] = {
+ val r = underlying.put(k, v)
+ if (r != null) Some(r.asInstanceOf[String]) else None
+ }
+
+ override def update(k: String, v: String): Unit = { underlying.put(k, v) }
+
+ override def remove(k: String): Option[String] = {
+ val r = underlying remove k
+ if (r != null) Some(r.asInstanceOf[String]) else None
+ }
+
+ def iterator: Iterator[(String, String)] = new AbstractIterator[(String, String)] {
+ val ui = underlying.entrySet.iterator
+ def hasNext = ui.hasNext
+ def next() = {
+ val e = ui.next()
+ (e.getKey.asInstanceOf[String], e.getValue.asInstanceOf[String])
+ }
+ }
+
+ override def clear() = underlying.clear()
+
+ override def empty: JPropertiesWrapper = new JPropertiesWrapper(new ju.Properties)
+
+ def getProperty(key: String) = underlying.getProperty(key)
+
+ def getProperty(key: String, defaultValue: String) =
+ underlying.getProperty(key, defaultValue)
+
+ def setProperty(key: String, value: String) =
+ underlying.setProperty(key, value)
+
+ override def mapFactory: mutable.HashMap.type = mutable.HashMap
+ }
+
+ /** Thrown when certain Map operations attempt to put a null value. */
+ private val PutNull = new ControlThrowable {}
+}
diff --git a/library/src/scala/collection/convert/StreamExtensions.scala b/library/src/scala/collection/convert/StreamExtensions.scala
new file mode 100644
index 000000000000..90b8bcb9031d
--- /dev/null
+++ b/library/src/scala/collection/convert/StreamExtensions.scala
@@ -0,0 +1,480 @@
+/*
+ * 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.convert
+
+import java.util.Spliterator
+import java.util.stream._
+import java.{lang => jl}
+
+import scala.annotation.implicitNotFound
+import scala.collection.Stepper.EfficientSplit
+import scala.collection._
+import scala.collection.convert.StreamExtensions.{AccumulatorFactoryInfo, StreamShape, StreamUnboxer}
+import scala.jdk.CollectionConverters._
+import scala.jdk._
+
+/** Defines extension methods to create Java Streams for Scala collections, available through
+ * [[scala.jdk.javaapi.StreamConverters]].
+ */
+trait StreamExtensions {
+ // collections
+
+ implicit class IterableHasSeqStream[A](cc: IterableOnce[A]) {
+ /** Create a sequential [[java.util.stream.Stream Java Stream]] for this collection. If the
+ * collection contains primitive values, a corresponding specialized Stream is returned (e.g.,
+ * [[java.util.stream.IntStream `IntStream`]]).
+ */
+ def asJavaSeqStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit s: StreamShape[A, S, St], st: StepperShape[A, St]): S =
+ s.fromStepper(cc.stepper, par = false)
+ }
+
+ // Not `CC[X] <: IterableOnce[X]`, but `C` with an extra constraint, to support non-parametric classes like IntAccumulator
+ implicit class IterableNonGenericHasParStream[A, C <: IterableOnce[_]](c: C)(implicit ev: C <:< IterableOnce[A]) {
+ private type IterableOnceWithEfficientStepper = IterableOnce[A] {
+ def stepper[S <: Stepper[_]](implicit shape : StepperShape[A, S]) : S with EfficientSplit
+ }
+
+ /** Create a parallel [[java.util.stream.Stream Java Stream]] for this collection. If the
+ * collection contains primitive values, a corresponding specialized Stream is returned (e.g.,
+ * [[java.util.stream.IntStream `IntStream`]]).
+ */
+ def asJavaParStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit
+ s: StreamShape[A, S, St],
+ st: StepperShape[A, St],
+ @implicitNotFound("`parStream` can only be called on collections where `stepper` returns a `Stepper with EfficientSplit`")
+ isEfficient: C <:< IterableOnceWithEfficientStepper): S =
+ s.fromStepper(ev(c).stepper, par = true)
+ }
+
+ // maps
+
+ implicit class MapHasSeqKeyValueStream[K, V, CC[X, Y] <: collection.MapOps[X, Y, collection.Map, _]](cc: CC[K, V]) {
+ /** Create a sequential [[java.util.stream.Stream Java Stream]] for the keys of this map. If
+ * the keys are primitive values, a corresponding specialized Stream is returned (e.g.,
+ * [[java.util.stream.IntStream `IntStream`]]).
+ */
+ def asJavaSeqKeyStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit s: StreamShape[K, S, St], st: StepperShape[K, St]): S =
+ s.fromStepper(cc.keyStepper, par = false)
+
+ /** Create a sequential [[java.util.stream.Stream Java Stream]] for the values of this map. If
+ * the values are primitives, a corresponding specialized Stream is returned (e.g.,
+ * [[java.util.stream.IntStream `IntStream`]]).
+ */
+ def asJavaSeqValueStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit s: StreamShape[V, S, St], st: StepperShape[V, St]): S =
+ s.fromStepper(cc.valueStepper, par = false)
+
+ // The asJavaSeqStream extension method for IterableOnce doesn't apply because its `CC` takes a single type parameter, whereas the one here takes two
+ /** Create a sequential [[java.util.stream.Stream Java Stream]] for the `(key, value)` pairs of
+ * this map.
+ */
+ def asJavaSeqStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit s: StreamShape[(K, V), S, St], st: StepperShape[(K, V), St]): S =
+ s.fromStepper(cc.stepper, par = false)
+ }
+
+
+ implicit class MapHasParKeyValueStream[K, V, CC[X, Y] <: collection.MapOps[X, Y, collection.Map, _]](cc: CC[K, V]) {
+ private type MapOpsWithEfficientKeyStepper = collection.MapOps[K, V, collection.Map, _] { def keyStepper[S <: Stepper[_]](implicit shape : StepperShape[K, S]) : S with EfficientSplit }
+ private type MapOpsWithEfficientValueStepper = collection.MapOps[K, V, collection.Map, _] { def valueStepper[S <: Stepper[_]](implicit shape : StepperShape[V, S]) : S with EfficientSplit }
+ private type MapOpsWithEfficientStepper = collection.MapOps[K, V, collection.Map, _] { def stepper[S <: Stepper[_]](implicit shape : StepperShape[(K, V), S]) : S with EfficientSplit }
+
+ /** Create a parallel [[java.util.stream.Stream Java Stream]] for the keys of this map. If
+ * the keys are primitive values, a corresponding specialized Stream is returned (e.g.,
+ * [[java.util.stream.IntStream `IntStream`]]).
+ */
+ def asJavaParKeyStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit
+ s: StreamShape[K, S, St],
+ st: StepperShape[K, St],
+ @implicitNotFound("parKeyStream can only be called on maps where `keyStepper` returns a `Stepper with EfficientSplit`")
+ isEfficient: CC[K, V] <:< MapOpsWithEfficientKeyStepper): S =
+ s.fromStepper(cc.keyStepper, par = true)
+
+ /** Create a parallel [[java.util.stream.Stream Java Stream]] for the values of this map. If
+ * the values are primitives, a corresponding specialized Stream is returned (e.g.,
+ * [[java.util.stream.IntStream `IntStream`]]).
+ */
+ def asJavaParValueStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit
+ s: StreamShape[V, S, St],
+ st: StepperShape[V, St],
+ @implicitNotFound("parValueStream can only be called on maps where `valueStepper` returns a `Stepper with EfficientSplit`")
+ isEfficient: CC[K, V] <:< MapOpsWithEfficientValueStepper): S =
+ s.fromStepper(cc.valueStepper, par = true)
+
+ // The asJavaParStream extension method for IterableOnce doesn't apply because its `CC` takes a single type parameter, whereas the one here takes two
+ /** Create a parallel [[java.util.stream.Stream Java Stream]] for the `(key, value)` pairs of
+ * this map.
+ */
+ def asJavaParStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit
+ s: StreamShape[(K, V), S, St],
+ st: StepperShape[(K, V), St],
+ @implicitNotFound("parStream can only be called on maps where `stepper` returns a `Stepper with EfficientSplit`")
+ isEfficient: CC[K, V] <:< MapOpsWithEfficientStepper): S =
+ s.fromStepper(cc.stepper, par = true)
+ }
+
+ // steppers
+
+ implicit class StepperHasSeqStream[A](stepper: Stepper[A]) {
+ /** Create a sequential [[java.util.stream.Stream Java Stream]] for this stepper. If the
+ * stepper yields primitive values, a corresponding specialized Stream is returned (e.g.,
+ * [[java.util.stream.IntStream `IntStream`]]).
+ */
+ def asJavaSeqStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit s: StreamShape[A, S, St], st: StepperShape[A, St]): S = {
+ val sStepper = stepper match {
+ case as: AnyStepper[A] => st.seqUnbox(as)
+ case _ => stepper.asInstanceOf[St]
+ }
+ s.fromStepper(sStepper, par = false)
+ }
+ }
+
+ implicit class StepperHasParStream[A](stepper: Stepper[A] with EfficientSplit) {
+ /** Create a parallel [[java.util.stream.Stream Java Stream]] for this stepper. If the
+ * stepper yields primitive values, a corresponding specialized Stream is returned (e.g.,
+ * [[java.util.stream.IntStream `IntStream`]]).
+ */
+ def asJavaParStream[S <: BaseStream[_, _], St <: Stepper[_]](implicit s: StreamShape[A, S, St], st: StepperShape[A, St]): S = {
+ val sStepper = stepper match {
+ case as: AnyStepper[A] with EfficientSplit => st.parUnbox(as)
+ case _ => stepper.asInstanceOf[St]
+ }
+ s.fromStepper(sStepper, par = true)
+ }
+ }
+
+ // arrays
+ // uses the JDK array spliterators (`DoubleArraySpliterator`). users can also call
+ // `array.stepper.seqStream`, which then uses the Scala steppers (`DoubleArrayStepper`). the
+ // steppers are also available on byte/short/char/float arrays (`WidenedByteArrayStepper`),
+ // JDK spliterators only for double/int/long/reference.
+
+ implicit class DoubleArrayHasSeqParStream(a: Array[Double]) {
+ /** Create a sequential [[java.util.stream.DoubleStream Java DoubleStream]] for this array. */
+ def asJavaSeqStream: DoubleStream = java.util.Arrays.stream(a)
+ /** Create a parallel [[java.util.stream.DoubleStream Java DoubleStream]] for this array. */
+ def asJavaParStream: DoubleStream = asJavaSeqStream.parallel
+ }
+
+ implicit class IntArrayHasSeqParStream(a: Array[Int]) {
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for this array. */
+ def asJavaSeqStream: IntStream = java.util.Arrays.stream(a)
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for this array. */
+ def asJavaParStream: IntStream = asJavaSeqStream.parallel
+ }
+
+ implicit class LongArrayHasSeqParStream(a: Array[Long]) {
+ /** Create a sequential [[java.util.stream.LongStream Java LongStream]] for this array. */
+ def asJavaSeqStream: LongStream = java.util.Arrays.stream(a)
+ /** Create a parallel [[java.util.stream.LongStream Java LongStream]] for this array. */
+ def asJavaParStream: LongStream = asJavaSeqStream.parallel
+ }
+
+ implicit class AnyArrayHasSeqParStream[A <: AnyRef](a: Array[A]) {
+ /** Create a sequential [[java.util.stream.Stream Java Stream]] for this array. */
+ def asJavaSeqStream: Stream[A] = java.util.Arrays.stream(a)
+ /** Create a parallel [[java.util.stream.Stream Java Stream]] for this array. */
+ def asJavaParStream: Stream[A] = asJavaSeqStream.parallel
+ }
+
+ implicit class ByteArrayHasSeqParStream(a: Array[Byte]) {
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for this array. */
+ def asJavaSeqStream: IntStream = a.stepper.asJavaSeqStream
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for this array. */
+ def asJavaParStream: IntStream = a.stepper.asJavaParStream
+ }
+
+ implicit class ShortArrayHasSeqParStream(a: Array[Short]) {
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for this array. */
+ def asJavaSeqStream: IntStream = a.stepper.asJavaSeqStream
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for this array. */
+ def asJavaParStream: IntStream = a.stepper.asJavaParStream
+ }
+
+ implicit class CharArrayHasSeqParStream(a: Array[Char]) {
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for this array. */
+ def asJavaSeqStream: IntStream = a.stepper.asJavaSeqStream
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for this array. */
+ def asJavaParStream: IntStream = a.stepper.asJavaParStream
+ }
+
+ implicit class FloatArrayHasSeqParStream(a: Array[Float]) {
+ /** Create a sequential [[java.util.stream.DoubleStream Java DoubleStream]] for this array. */
+ def asJavaSeqStream: DoubleStream = a.stepper.asJavaSeqStream
+ /** Create a parallel [[java.util.stream.DoubleStream Java DoubleStream]] for this array. */
+ def asJavaParStream: DoubleStream = a.stepper.asJavaParStream
+ }
+
+
+
+ // strings
+
+ implicit class StringHasSeqParStream(s: String) {
+ /**
+ * A sequential stream on the characters of a string, same as [[asJavaSeqCharStream]]. See also
+ * [[asJavaSeqCodePointStream]].
+ */
+ def asJavaSeqStream: IntStream = StreamSupport.intStream(s.stepper.spliterator, /* par = */ false)
+ /**
+ * A parallel stream on the characters of a string, same as [[asJavaParCharStream]]. See also
+ * [[asJavaParCodePointStream]].
+ */
+ def asJavaParStream: IntStream = StreamSupport.intStream(s.stepper.spliterator, /* par = */ true)
+
+ /** A sequential stream on the characters of a string. See also [[asJavaSeqCodePointStream]]. */
+ def asJavaSeqCharStream: IntStream = StreamSupport.intStream(s.charStepper.spliterator, /* par = */ false)
+ /** A parallel stream on the characters of a string. See also [[asJavaParCodePointStream]]. */
+ def asJavaParCharStream: IntStream = StreamSupport.intStream(s.charStepper.spliterator, /* par = */ true)
+
+ /** A sequential stream on the code points of a string. See also [[asJavaSeqCharStream]]. */
+ def asJavaSeqCodePointStream: IntStream = StreamSupport.intStream(s.codePointStepper.spliterator, /* par = */ false)
+ /** A parallel stream on the code points of a string. See also [[asJavaParCharStream]]. */
+ def asJavaParCodePointStream: IntStream = StreamSupport.intStream(s.codePointStepper.spliterator, /* par = */ true)
+ }
+
+ // toScala for streams
+
+ implicit class StreamHasToScala[A](stream: Stream[A]) {
+ /**
+ * Copy the elements of this stream into a Scala collection.
+ *
+ * Converting a parallel streams to an [[scala.jdk.Accumulator]] using `stream.toScala(Accumulator)`
+ * builds the result in parallel.
+ *
+ * A `toScala(Accumulator)` call automatically converts streams of boxed integers, longs or
+ * doubles are converted to the primitive accumulators ([[scala.jdk.IntAccumulator]], etc.).
+ *
+ * When converting a parallel stream to a different Scala collection, the stream is first
+ * converted into an [[scala.jdk.Accumulator]], which supports parallel building. The accumulator is
+ * then converted to the target collection. Note that the stream is processed eagerly while
+ * building the accumulator, even if the target collection is lazy.
+ *
+ * Sequential streams are directly converted to the target collection. If the target collection
+ * is lazy, the conversion is lazy as well.
+ */
+ def toScala[C1](factory: collection.Factory[A, C1])(implicit info: AccumulatorFactoryInfo[A, C1]): C1 = {
+
+ def anyAcc = stream.collect(AnyAccumulator.supplier[A], AnyAccumulator.adder[A], AnyAccumulator.merger[A])
+ if (info.companion == AnyAccumulator) anyAcc.asInstanceOf[C1]
+ else if (info.companion == IntAccumulator) stream.asInstanceOf[Stream[Int]].collect(IntAccumulator.supplier, IntAccumulator.boxedAdder, IntAccumulator.merger).asInstanceOf[C1]
+ else if (info.companion == LongAccumulator) stream.asInstanceOf[Stream[Long]].collect(LongAccumulator.supplier, LongAccumulator.boxedAdder, LongAccumulator.merger).asInstanceOf[C1]
+ else if (info.companion == DoubleAccumulator) stream.asInstanceOf[Stream[Double]].collect(DoubleAccumulator.supplier, DoubleAccumulator.boxedAdder, DoubleAccumulator.merger).asInstanceOf[C1]
+ else if (stream.isParallel) anyAcc.to(factory)
+ else factory.fromSpecific(stream.iterator.asScala)
+ }
+
+ /** Convert a generic Java Stream wrapping a primitive type to a corresponding primitive
+ * Stream.
+ */
+ def asJavaPrimitiveStream[S](implicit unboxer: StreamUnboxer[A, S]): S = unboxer(stream)
+ }
+
+ implicit class IntStreamHasToScala(stream: IntStream) {
+ /**
+ * Copy the elements of this stream into a Scala collection.
+ *
+ * Converting a parallel streams to an [[scala.jdk.Accumulator]] using `stream.toScala(Accumulator)`
+ * builds the result in parallel.
+ *
+ * A `toScala(Accumulator)` call automatically converts the `IntStream` to a primitive
+ * [[scala.jdk.IntAccumulator]].
+ *
+ * When converting a parallel stream to a different Scala collection, the stream is first
+ * converted into an [[scala.jdk.Accumulator]], which supports parallel building. The accumulator is
+ * then converted to the target collection. Note that the stream is processed eagerly while
+ * building the accumulator, even if the target collection is lazy.
+ *
+ * Sequential streams are directly converted to the target collection. If the target collection
+ * is lazy, the conversion is lazy as well.
+ */
+ def toScala[C1](factory: collection.Factory[Int, C1])(implicit info: AccumulatorFactoryInfo[Int, C1]): C1 = {
+ def intAcc = stream.collect(IntAccumulator.supplier, IntAccumulator.adder, IntAccumulator.merger)
+ if (info.companion == AnyAccumulator) stream.collect(AnyAccumulator.supplier[Int], AnyAccumulator.unboxedIntAdder, AnyAccumulator.merger[Int]).asInstanceOf[C1]
+ else if (info.companion == IntAccumulator) intAcc.asInstanceOf[C1]
+ else if (stream.isParallel) intAcc.to(factory)
+ else factory.fromSpecific(stream.iterator.asInstanceOf[java.util.Iterator[Int]].asScala)
+ }
+ }
+
+ implicit class LongStreamHasToScala(stream: LongStream) {
+ /**
+ * Copy the elements of this stream into a Scala collection.
+ *
+ * Converting a parallel streams to an [[scala.jdk.Accumulator]] using `stream.toScala(Accumulator)`
+ * builds the result in parallel.
+ *
+ * A `toScala(Accumulator)` call automatically converts the `LongStream` to a primitive
+ * [[scala.jdk.LongAccumulator]].
+ *
+ * When converting a parallel stream to a different Scala collection, the stream is first
+ * converted into an [[scala.jdk.Accumulator]], which supports parallel building. The accumulator is
+ * then converted to the target collection. Note that the stream is processed eagerly while
+ * building the accumulator, even if the target collection is lazy.
+ *
+ * Sequential streams are directly converted to the target collection. If the target collection
+ * is lazy, the conversion is lazy as well.
+ */
+ def toScala[C1](factory: collection.Factory[Long, C1])(implicit info: AccumulatorFactoryInfo[Long, C1]): C1 = {
+ def longAcc = stream.collect(LongAccumulator.supplier, LongAccumulator.adder, LongAccumulator.merger)
+ if (info.companion == AnyAccumulator) stream.collect(AnyAccumulator.supplier[Long], AnyAccumulator.unboxedLongAdder, AnyAccumulator.merger[Long]).asInstanceOf[C1]
+ else if (info.companion == LongAccumulator) longAcc.asInstanceOf[C1]
+ else if (stream.isParallel) longAcc.to(factory)
+ else factory.fromSpecific(stream.iterator.asInstanceOf[java.util.Iterator[Long]].asScala)
+ }
+ }
+
+ implicit class DoubleStreamHasToScala(stream: DoubleStream) {
+ /**
+ * Copy the elements of this stream into a Scala collection.
+ *
+ * Converting a parallel streams to an [[scala.jdk.Accumulator]] using `stream.toScala(Accumulator)`
+ * builds the result in parallel.
+ *
+ * A `toScala(Accumulator)` call automatically converts the `DoubleStream` to a primitive
+ * [[scala.jdk.DoubleAccumulator]].
+ *
+ * When converting a parallel stream to a different Scala collection, the stream is first
+ * converted into an [[scala.jdk.Accumulator]], which supports parallel building. The accumulator is
+ * then converted to the target collection. Note that the stream is processed eagerly while
+ * building the accumulator, even if the target collection is lazy.
+ *
+ * Sequential streams are directly converted to the target collection. If the target collection
+ * is lazy, the conversion is lazy as well.
+ */
+ def toScala[C1](factory: collection.Factory[Double, C1])(implicit info: AccumulatorFactoryInfo[Double, C1]): C1 = {
+ def doubleAcc = stream.collect(DoubleAccumulator.supplier, DoubleAccumulator.adder, DoubleAccumulator.merger)
+ if (info.companion == AnyAccumulator) stream.collect(AnyAccumulator.supplier[Double], AnyAccumulator.unboxedDoubleAdder, AnyAccumulator.merger[Double]).asInstanceOf[C1]
+ else if (info.companion == DoubleAccumulator) doubleAcc.asInstanceOf[C1]
+ else if (stream.isParallel) doubleAcc.to(factory)
+ else factory.fromSpecific(stream.iterator.asInstanceOf[java.util.Iterator[Double]].asScala)
+ }
+ }
+}
+
+object StreamExtensions {
+ /** An implicit StreamShape instance connects element types with the corresponding specialized
+ * Stream and Stepper types. This is used in `asJavaStream` extension methods to create
+ * generic or primitive streams according to the element type.
+ */
+ sealed trait StreamShape[T, S <: BaseStream[_, _], St <: Stepper[_]] {
+ final def fromStepper(st: St, par: Boolean): S = mkStream(st, par)
+ protected def mkStream(st: St, par: Boolean): S
+ }
+
+ object StreamShape extends StreamShapeLowPriority1 {
+ // primitive
+ implicit val intStreamShape : StreamShape[Int , IntStream , IntStepper] = mkIntStreamShape[Int]
+ implicit val longStreamShape : StreamShape[Long , LongStream , LongStepper] = mkLongStreamShape[Long]
+ implicit val doubleStreamShape: StreamShape[Double, DoubleStream, DoubleStepper] = mkDoubleStreamShape[Double]
+
+ // widening
+ implicit val byteStreamShape : StreamShape[Byte , IntStream , IntStepper] = mkIntStreamShape[Byte]
+ implicit val shortStreamShape: StreamShape[Short, IntStream , IntStepper] = mkIntStreamShape[Short]
+ implicit val charStreamShape : StreamShape[Char , IntStream , IntStepper] = mkIntStreamShape[Char]
+ implicit val floatStreamShape: StreamShape[Float, DoubleStream, DoubleStepper] = mkDoubleStreamShape[Float]
+
+ // boxed java primitives
+
+ implicit val jIntegerStreamShape : StreamShape[jl.Integer , IntStream , IntStepper ] = mkIntStreamShape[jl.Integer]
+ implicit val jLongStreamShape : StreamShape[jl.Long , LongStream , LongStepper ] = mkLongStreamShape[jl.Long]
+ implicit val jDoubleStreamShape : StreamShape[jl.Double , DoubleStream, DoubleStepper] = mkDoubleStreamShape[jl.Double]
+ implicit val jByteStreamShape : StreamShape[jl.Byte , IntStream , IntStepper ] = mkIntStreamShape[jl.Byte]
+ implicit val jShortStreamShape : StreamShape[jl.Short , IntStream , IntStepper ] = mkIntStreamShape[jl.Short]
+ implicit val jCharacterStreamShape : StreamShape[jl.Character, IntStream , IntStepper ] = mkIntStreamShape[jl.Character]
+ implicit val jFloatStreamShape : StreamShape[jl.Float , DoubleStream, DoubleStepper] = mkDoubleStreamShape[jl.Float]
+
+ private def mkIntStreamShape[T]: StreamShape[T, IntStream, IntStepper] = new StreamShape[T, IntStream, IntStepper] {
+ protected def mkStream(st: IntStepper, par: Boolean): IntStream = StreamSupport.intStream(st.spliterator, par)
+ }
+
+ private def mkLongStreamShape[T]: StreamShape[T, LongStream, LongStepper] = new StreamShape[T, LongStream, LongStepper] {
+ protected def mkStream(st: LongStepper, par: Boolean): LongStream = StreamSupport.longStream(st.spliterator, par)
+ }
+
+ private def mkDoubleStreamShape[T]: StreamShape[T, DoubleStream, DoubleStepper] = new StreamShape[T, DoubleStream, DoubleStepper] {
+ protected def mkStream(st: DoubleStepper, par: Boolean): DoubleStream = StreamSupport.doubleStream(st.spliterator, par)
+ }
+ }
+
+ trait StreamShapeLowPriority1 {
+ // reference
+ implicit def anyStreamShape[T]: StreamShape[T, Stream[T], Stepper[T]] = anyStreamShapePrototype.asInstanceOf[StreamShape[T, Stream[T], Stepper[T]]]
+
+ private[this] val anyStreamShapePrototype: StreamShape[AnyRef, Stream[AnyRef], Stepper[AnyRef]] = new StreamShape[AnyRef, Stream[AnyRef], Stepper[AnyRef]] {
+ def mkStream(s: Stepper[AnyRef], par: Boolean): Stream[AnyRef] = StreamSupport.stream(s.spliterator.asInstanceOf[Spliterator[AnyRef]], par)
+ }
+ }
+
+ /** Connects a stream element type `A` to the corresponding, potentially specialized, Stream type.
+ * Used in the `stream.asJavaPrimitiveStream` extension method.
+ */
+ sealed trait StreamUnboxer[A, S] {
+ def apply(s: Stream[A]): S
+ }
+ object StreamUnboxer {
+ implicit val intStreamUnboxer: StreamUnboxer[Int, IntStream] = new StreamUnboxer[Int, IntStream] {
+ def apply(s: Stream[Int]): IntStream = s.mapToInt(x => x)
+ }
+ implicit val javaIntegerStreamUnboxer: StreamUnboxer[jl.Integer, IntStream] = intStreamUnboxer.asInstanceOf[StreamUnboxer[jl.Integer, IntStream]]
+
+ implicit val longStreamUnboxer: StreamUnboxer[Long, LongStream] = new StreamUnboxer[Long, LongStream] {
+ def apply(s: Stream[Long]): LongStream = s.mapToLong(x => x)
+ }
+ implicit val javaLongStreamUnboxer: StreamUnboxer[jl.Long, LongStream] = longStreamUnboxer.asInstanceOf[StreamUnboxer[jl.Long, LongStream]]
+
+ implicit val doubleStreamUnboxer: StreamUnboxer[Double, DoubleStream] = new StreamUnboxer[Double, DoubleStream] {
+ def apply(s: Stream[Double]): DoubleStream = s.mapToDouble(x => x)
+ }
+ implicit val javaDoubleStreamUnboxer: StreamUnboxer[jl.Double, DoubleStream] = doubleStreamUnboxer.asInstanceOf[StreamUnboxer[jl.Double, DoubleStream]]
+ }
+
+
+
+ /** An implicit `AccumulatorFactoryInfo` connects primitive element types to the corresponding
+ * specialized [[scala.jdk.Accumulator]] factory. This is used in the `stream.toScala` extension methods
+ * to ensure collecting a primitive stream into a primitive accumulator does not box.
+ *
+ * When converting to a collection other than `Accumulator`, the generic
+ * `noAccumulatorFactoryInfo` is passed.
+ */
+ trait AccumulatorFactoryInfo[A, C] {
+ val companion: AnyRef
+ }
+ trait LowPriorityAccumulatorFactoryInfo {
+ implicit def noAccumulatorFactoryInfo[A, C]: AccumulatorFactoryInfo[A, C] = noAccumulatorFactoryInfoPrototype.asInstanceOf[AccumulatorFactoryInfo[A, C]]
+ private val noAccumulatorFactoryInfoPrototype: AccumulatorFactoryInfo[AnyRef, AnyRef] = new AccumulatorFactoryInfo[AnyRef, AnyRef] {
+ val companion: AnyRef = null
+ }
+ }
+ object AccumulatorFactoryInfo extends LowPriorityAccumulatorFactoryInfo {
+ implicit def anyAccumulatorFactoryInfo[A]: AccumulatorFactoryInfo[A, AnyAccumulator[A]] = anyAccumulatorFactoryInfoPrototype.asInstanceOf[AccumulatorFactoryInfo[A, AnyAccumulator[A]]]
+
+ private object anyAccumulatorFactoryInfoPrototype extends AccumulatorFactoryInfo[AnyRef, AnyAccumulator[AnyRef]] {
+ val companion: AnyRef = AnyAccumulator
+ }
+
+ implicit val intAccumulatorFactoryInfo: AccumulatorFactoryInfo[Int, IntAccumulator] = new AccumulatorFactoryInfo[Int, IntAccumulator] {
+ val companion: AnyRef = IntAccumulator
+ }
+
+ implicit val longAccumulatorFactoryInfo: AccumulatorFactoryInfo[Long, LongAccumulator] = new AccumulatorFactoryInfo[Long, LongAccumulator] {
+ val companion: AnyRef = LongAccumulator
+ }
+
+ implicit val doubleAccumulatorFactoryInfo: AccumulatorFactoryInfo[Double, DoubleAccumulator] = new AccumulatorFactoryInfo[Double, DoubleAccumulator] {
+ val companion: AnyRef = DoubleAccumulator
+ }
+
+ implicit val jIntegerAccumulatorFactoryInfo: AccumulatorFactoryInfo[jl.Integer, IntAccumulator] = intAccumulatorFactoryInfo.asInstanceOf[AccumulatorFactoryInfo[jl.Integer, IntAccumulator]]
+ implicit val jLongAccumulatorFactoryInfo: AccumulatorFactoryInfo[jl.Long, IntAccumulator] = longAccumulatorFactoryInfo.asInstanceOf[AccumulatorFactoryInfo[jl.Long, IntAccumulator]]
+ implicit val jDoubleAccumulatorFactoryInfo: AccumulatorFactoryInfo[jl.Double, IntAccumulator] = doubleAccumulatorFactoryInfo.asInstanceOf[AccumulatorFactoryInfo[jl.Double, IntAccumulator]]
+ }
+}
diff --git a/library/src/scala/collection/convert/impl/ArrayStepper.scala b/library/src/scala/collection/convert/impl/ArrayStepper.scala
new file mode 100644
index 000000000000..4e8408bca99a
--- /dev/null
+++ b/library/src/scala/collection/convert/impl/ArrayStepper.scala
@@ -0,0 +1,79 @@
+/*
+ * 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.convert
+package impl
+
+import scala.collection._
+
+private[collection] class ObjectArrayStepper[A <: Object](underlying: Array[A], _i0: Int, _iN: Int)
+ extends IndexedStepperBase[AnyStepper[A], ObjectArrayStepper[A]](_i0, _iN)
+ with AnyStepper[A] {
+ def nextStep(): A = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ protected def semiclone(half: Int): ObjectArrayStepper[A] = new ObjectArrayStepper[A](underlying, i0, half)
+}
+
+private[collection] class BoxedBooleanArrayStepper(underlying: Array[Boolean], _i0: Int, _iN: Int)
+ extends IndexedStepperBase[AnyStepper[Boolean], BoxedBooleanArrayStepper](_i0, _iN)
+ with AnyStepper[Boolean] {
+ def nextStep(): Boolean = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ protected def semiclone(half: Int): BoxedBooleanArrayStepper = new BoxedBooleanArrayStepper(underlying, i0, half)
+}
+
+private[collection] class WidenedByteArrayStepper(underlying: Array[Byte], _i0: Int, _iN: Int)
+ extends IndexedStepperBase[IntStepper, WidenedByteArrayStepper](_i0, _iN)
+ with IntStepper {
+ def nextStep(): Int = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ protected def semiclone(half: Int): WidenedByteArrayStepper = new WidenedByteArrayStepper(underlying, i0, half)
+}
+
+private[collection] class WidenedCharArrayStepper(underlying: Array[Char], _i0: Int, _iN: Int)
+ extends IndexedStepperBase[IntStepper, WidenedCharArrayStepper](_i0, _iN)
+ with IntStepper {
+ def nextStep(): Int = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ protected def semiclone(half: Int): WidenedCharArrayStepper = new WidenedCharArrayStepper(underlying, i0, half)
+}
+
+private[collection] class WidenedShortArrayStepper(underlying: Array[Short], _i0: Int, _iN: Int)
+ extends IndexedStepperBase[IntStepper, WidenedShortArrayStepper](_i0, _iN)
+ with IntStepper {
+ def nextStep(): Int = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ protected def semiclone(half: Int): WidenedShortArrayStepper = new WidenedShortArrayStepper(underlying, i0, half)
+}
+
+private[collection] class WidenedFloatArrayStepper(underlying: Array[Float], _i0: Int, _iN: Int)
+ extends IndexedStepperBase[DoubleStepper, WidenedFloatArrayStepper](_i0, _iN)
+ with DoubleStepper {
+ def nextStep(): Double = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ protected def semiclone(half: Int): WidenedFloatArrayStepper = new WidenedFloatArrayStepper(underlying, i0, half)
+}
+
+private[collection] class DoubleArrayStepper(underlying: Array[Double], _i0: Int, _iN: Int)
+ extends IndexedStepperBase[DoubleStepper, DoubleArrayStepper](_i0, _iN)
+ with DoubleStepper {
+ def nextStep(): Double = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ protected def semiclone(half: Int): DoubleArrayStepper = new DoubleArrayStepper(underlying, i0, half)
+}
+
+private[collection] class IntArrayStepper(underlying: Array[Int], _i0: Int, _iN: Int)
+ extends IndexedStepperBase[IntStepper, IntArrayStepper](_i0, _iN)
+ with IntStepper {
+ def nextStep(): Int = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ protected def semiclone(half: Int): IntArrayStepper = new IntArrayStepper(underlying, i0, half)
+}
+
+private[collection] class LongArrayStepper(underlying: Array[Long], _i0: Int, _iN: Int)
+ extends IndexedStepperBase[LongStepper, LongArrayStepper](_i0, _iN)
+ with LongStepper {
+ def nextStep(): Long = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ protected def semiclone(half: Int): LongArrayStepper = new LongArrayStepper(underlying, i0, half)
+}
diff --git a/library/src/scala/collection/convert/impl/BinaryTreeStepper.scala b/library/src/scala/collection/convert/impl/BinaryTreeStepper.scala
new file mode 100644
index 000000000000..d15977eced17
--- /dev/null
+++ b/library/src/scala/collection/convert/impl/BinaryTreeStepper.scala
@@ -0,0 +1,248 @@
+/*
+ * 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.convert
+package impl
+
+import java.util.Spliterator
+
+import annotation.tailrec
+import scala.collection.Stepper.EfficientSplit
+import scala.collection._
+
+
+private[collection] object BinaryTreeStepper {
+ val emptyStack = new Array[AnyRef](0)
+}
+
+
+/** A generic stepper that can traverse ordered binary trees.
+ * The tree is assumed to have all the stuff on the left first, then the root, then everything on the right.
+ *
+ * Splits occur at the root of whatever has not yet been traversed (the substepper steps up to but
+ * does not include the root).
+ *
+ * The stepper maintains an internal stack, not relying on the tree traversal to be reversible. Trees with
+ * nodes that maintain a parent pointer may be traversed slightly faster without a stack, but splitting is
+ * more awkward.
+ *
+ * Algorithmically, this class implements a simple state machine that unrolls the left-leaning links in
+ * a binary tree onto a stack. At all times, the machine should be in one of these states:
+ * 1. Empty: `myCurrent` is `null` and `index` is `-1`. `stack` should also be `Array.empty` then.
+ * 2. Ready: `myCurrent` is not `null` and contains the next `A` to be extracted
+ * 3. Pending: `myCurrent` is `null` and `stack(index)` contains the next node to visit
+ *
+ * Subclasses should allow this class to do all the work of maintaining state; `next` should simply
+ * reduce `maxLength` by one, and consume `myCurrent` and set it to `null` if `hasNext` is true.
+ */
+private[collection] abstract class BinaryTreeStepperBase[A, T >: Null <: AnyRef, Sub >: Null, Semi <: Sub with BinaryTreeStepperBase[A, T, _, _]](
+ protected var maxLength: Int, protected var myCurrent: T, protected var stack: Array[AnyRef], protected var index: Int,
+ protected val left: T => T, protected val right: T => T
+)
+extends EfficientSplit {
+ /** Unrolls a subtree onto the stack starting from a particular node, returning
+ * the last node found. This final node is _not_ placed on the stack, and
+ * may have things to its right.
+ */
+ @tailrec protected final def unroll(from: T): T = {
+ val l = left(from)
+ if (l eq null) from
+ else {
+ if (index+1 >= stack.length) stack = java.util.Arrays.copyOf(stack, 4 + stack.length*2)
+ index += 1
+ stack(index) = from
+ unroll(l)
+ }
+ }
+
+ /** Takes a subtree whose left side, if any, has already been visited, and unrolls
+ * the right side of the tree onto the stack, thereby detaching that node of
+ * the subtree from the stack entirely (so it is ready to use). It returns
+ * the node that is being detached. Note that the node must _not_ already be
+ * on the stack.
+ */
+ protected final def detach(node: T): node.type = {
+ val r = right(node)
+ if (r ne null) {
+ val last = unroll(r)
+ if (index+1 >= stack.length) stack = java.util.Arrays.copyOf(stack, 4 + stack.length*2)
+ index += 1
+ stack(index) = last
+ }
+ node
+ }
+
+ /** Given an empty state and the root of a new tree, initialize the tree properly
+ * to be in an (appropriate) ready state. Will do all sorts of wrong stuff if the
+ * tree is not already empty.
+ *
+ * Right now overwrites everything so could allow reuse, but isn't used for it.
+ */
+ private[impl] final def initialize(root: T, size: Int): Unit =
+ if (root eq null) {
+ maxLength = 0
+ myCurrent = null
+ stack = BinaryTreeStepper.emptyStack
+ index = -1
+ }
+ else {
+ maxLength = size
+ index = -1
+ myCurrent = detach(unroll(root))
+ }
+
+ protected def semiclone(maxL: Int, myC: T, stk: Array[AnyRef], ix: Int): Semi
+
+ def characteristics: Int = Spliterator.ORDERED
+
+ def estimateSize: Long = if (hasStep) maxLength else 0
+
+ def hasStep: Boolean = (myCurrent ne null) || (maxLength > 0 && {
+ if (index < 0) { maxLength = 0; stack = BinaryTreeStepper.emptyStack; false }
+ else {
+ val ans = stack(index).asInstanceOf[T]
+ index -= 1
+ myCurrent = detach(ans)
+ true
+ }
+ })
+
+ /** Splits the tree at the root by giving everything unrolled on the stack to a new stepper,
+ * detaching the root, and leaving the right-hand side of the root unrolled.
+ *
+ * If the tree is empty or only has one element left, it returns `null` instead of splitting.
+ */
+ def trySplit(): Sub =
+ if (!hasStep || index < 0) null
+ else {
+ val root = stack(0).asInstanceOf[T]
+ val leftStack =
+ if (index > 0) java.util.Arrays.copyOfRange(stack, 1, index+1)
+ else BinaryTreeStepper.emptyStack
+ val leftIndex = index - 1
+ val leftCurrent = myCurrent
+ var leftMax = maxLength
+ index = -1
+ detach(root)
+ myCurrent = root
+ leftMax -= 2+index
+ maxLength -= 2+leftIndex
+ semiclone(leftMax, leftCurrent, leftStack, leftIndex)
+ }
+}
+
+
+private[collection] final class AnyBinaryTreeStepper[A, T >: Null <: AnyRef](
+ _maxLength: Int, _myCurrent: T, _stack: Array[AnyRef], _index: Int, _left: T => T, _right: T => T, protected val extract: T => A
+)
+extends BinaryTreeStepperBase[A, T, AnyStepper[A], AnyBinaryTreeStepper[A, T]](_maxLength, _myCurrent, _stack, _index, _left, _right)
+with AnyStepper[A] {
+ def nextStep(): A =
+ if (hasStep) {
+ val ans = extract(myCurrent)
+ myCurrent = null
+ maxLength -= 1
+ ans
+ }
+ else Stepper.throwNSEE()
+
+ def semiclone(maxL: Int, myC: T, stk: Array[AnyRef], ix: Int): AnyBinaryTreeStepper[A, T] =
+ new AnyBinaryTreeStepper[A, T](maxL, myC, stk, ix, left, right, extract)
+}
+private[collection] object AnyBinaryTreeStepper {
+ def from[A, T >: Null <: AnyRef](maxLength: Int, root: T, left: T => T, right: T => T, extract: T => A): AnyBinaryTreeStepper[A, T] = {
+ val ans = new AnyBinaryTreeStepper(0, null, BinaryTreeStepper.emptyStack, -1, left, right, extract)
+ ans.initialize(root, maxLength)
+ ans
+ }
+}
+
+
+private[collection] final class DoubleBinaryTreeStepper[T >: Null <: AnyRef](
+ _maxLength: Int, _myCurrent: T, _stack: Array[AnyRef], _index: Int, _left: T => T, _right: T => T, protected val extract: T => Double
+)
+extends BinaryTreeStepperBase[Double, T, DoubleStepper, DoubleBinaryTreeStepper[T]](_maxLength, _myCurrent, _stack, _index, _left, _right)
+with DoubleStepper {
+ def nextStep(): Double =
+ if (hasStep) {
+ val ans = extract(myCurrent)
+ myCurrent = null
+ maxLength -= 1
+ ans
+ }
+ else Stepper.throwNSEE()
+
+ def semiclone(maxL: Int, myC: T, stk: Array[AnyRef], ix: Int): DoubleBinaryTreeStepper[T] =
+ new DoubleBinaryTreeStepper[T](maxL, myC, stk, ix, left, right, extract)
+}
+private [collection] object DoubleBinaryTreeStepper {
+ def from[T >: Null <: AnyRef](maxLength: Int, root: T, left: T => T, right: T => T, extract: T => Double): DoubleBinaryTreeStepper[T] = {
+ val ans = new DoubleBinaryTreeStepper(0, null, BinaryTreeStepper.emptyStack, -1, left, right, extract)
+ ans.initialize(root, maxLength)
+ ans
+ }
+}
+
+
+private[collection] final class IntBinaryTreeStepper[T >: Null <: AnyRef](
+ _maxLength: Int, _myCurrent: T, _stack: Array[AnyRef], _index: Int, _left: T => T, _right: T => T, protected val extract: T => Int
+)
+extends BinaryTreeStepperBase[Int, T, IntStepper, IntBinaryTreeStepper[T]](_maxLength, _myCurrent, _stack, _index, _left, _right)
+with IntStepper {
+ def nextStep(): Int =
+ if (hasStep) {
+ val ans = extract(myCurrent)
+ myCurrent = null
+ maxLength -= 1
+ ans
+ }
+ else Stepper.throwNSEE()
+
+ def semiclone(maxL: Int, myC: T, stk: Array[AnyRef], ix: Int): IntBinaryTreeStepper[T] =
+ new IntBinaryTreeStepper[T](maxL, myC, stk, ix, left, right, extract)
+}
+private [collection] object IntBinaryTreeStepper {
+ def from[T >: Null <: AnyRef](maxLength: Int, root: T, left: T => T, right: T => T, extract: T => Int): IntBinaryTreeStepper[T] = {
+ val ans = new IntBinaryTreeStepper(0, null, BinaryTreeStepper.emptyStack, -1, left, right, extract)
+ ans.initialize(root, maxLength)
+ ans
+ }
+}
+
+
+
+private[collection] final class LongBinaryTreeStepper[T >: Null <: AnyRef](
+ _maxLength: Int, _myCurrent: T, _stack: Array[AnyRef], _index: Int, _left: T => T, _right: T => T, protected val extract: T => Long
+)
+extends BinaryTreeStepperBase[Long, T, LongStepper, LongBinaryTreeStepper[T]](_maxLength, _myCurrent, _stack, _index, _left, _right)
+with LongStepper {
+ def nextStep(): Long =
+ if (hasStep) {
+ val ans = extract(myCurrent)
+ myCurrent = null
+ maxLength -= 1
+ ans
+ }
+ else Stepper.throwNSEE()
+
+ def semiclone(maxL: Int, myC: T, stk: Array[AnyRef], ix: Int): LongBinaryTreeStepper[T] =
+ new LongBinaryTreeStepper[T](maxL, myC, stk, ix, left, right, extract)
+}
+private [collection] object LongBinaryTreeStepper {
+ def from[T >: Null <: AnyRef](maxLength: Int, root: T, left: T => T, right: T => T, extract: T => Long): LongBinaryTreeStepper[T] = {
+ val ans = new LongBinaryTreeStepper(0, null, BinaryTreeStepper.emptyStack, -1, left, right, extract)
+ ans.initialize(root, maxLength)
+ ans
+ }
+}
+
+
diff --git a/library/src/scala/collection/convert/impl/BitSetStepper.scala b/library/src/scala/collection/convert/impl/BitSetStepper.scala
new file mode 100644
index 000000000000..905afaaf4a0d
--- /dev/null
+++ b/library/src/scala/collection/convert/impl/BitSetStepper.scala
@@ -0,0 +1,118 @@
+/*
+ * 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.convert
+package impl
+
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.{BitSetOps, IntStepper, Stepper}
+
+
+private[collection] final class BitSetStepper(
+ private var underlying: BitSetOps[_],
+ private var cache0: Long, private var cache1: Long,
+ _i0: Int, _iN: Int,
+ private var cacheIndex: Int
+)
+extends InOrderStepperBase[IntStepper, BitSetStepper](_i0, _iN)
+with IntStepper {
+ import BitSetOps.{WordLength, LogWL}
+
+ // When `found` is set, `i0` is an element that exists
+ protected var found: Boolean = false
+
+ @annotation.tailrec
+ protected def findNext(): Boolean =
+ if (i0 >= iN) false
+ else {
+ val ix = i0 >> LogWL
+ if (ix == cacheIndex || ix == cacheIndex+1) {
+ val i = scanLong(if (ix == cacheIndex) cache0 else cache1, i0 & (WordLength - 1))
+ if (i >= 0) {
+ i0 = (i0 & ~(WordLength - 1)) | i
+ found = (i0 < iN)
+ found
+ }
+ else {
+ i0 = (i0 & ~(WordLength - 1)) + WordLength
+ findNext()
+ }
+ }
+ else if (underlying eq null) {
+ i0 = iN
+ found = false
+ found
+ }
+ else {
+ cacheIndex = ix
+ cache0 = underlying.word(cacheIndex)
+ cache1 = if ((iN - 1) >> LogWL == ix) -1L else underlying.word(cacheIndex+1)
+ findNext()
+ }
+ }
+
+ def semiclone(half: Int): BitSetStepper =
+ if (underlying == null) {
+ val ans = new BitSetStepper(null, cache0, cache1, i0, half, cacheIndex)
+ ans.found = found
+ i0 = half
+ found = false
+ ans
+ }
+ else {
+ // Set up new stepper
+ val ixNewN = (half - 1) >> LogWL
+ val ans =
+ new BitSetStepper(if (ixNewN <= cacheIndex + 1) null else underlying, cache0, cache1, i0, half, cacheIndex)
+ if (found) ans.found = true
+
+ // Advance old stepper to breakpoint
+ val ixOld0 = half >> LogWL
+ if (ixOld0 > cacheIndex + 1) {
+ cache0 = underlying.word(ixOld0)
+ cache1 = if (((iN - 1) >> LogWL) == ixOld0) -1L else underlying.word(ixOld0+1)
+ cacheIndex = ixOld0
+ i0 = half
+ found = false
+ }
+
+ // Return new stepper
+ ans
+ }
+
+ @annotation.tailrec
+ private[this] def scanLong(bits: Long, from: Int): Int =
+ if (from >= WordLength) -1
+ else if ((bits & (1L << from)) != 0) from
+ else scanLong(bits, from + 1)
+
+ def nextStep(): Int =
+ if (found || findNext()) {
+ found = false
+ val ans = i0
+ i0 += 1
+ ans
+ }
+ else Stepper.throwNSEE()
+}
+
+private[collection] object BitSetStepper {
+ def from(bs: scala.collection.BitSetOps[_]): IntStepper with EfficientSplit =
+ new BitSetStepper(
+ if (bs.nwords <= 2) null else bs,
+ if (bs.nwords <= 0) -1L else bs.word(0),
+ if (bs.nwords <= 1) -1L else bs.word(1),
+ 0,
+ bs.nwords * BitSetOps.WordLength,
+ 0
+ )
+}
diff --git a/library/src/scala/collection/convert/impl/ChampStepper.scala b/library/src/scala/collection/convert/impl/ChampStepper.scala
new file mode 100644
index 000000000000..ddf7c34dc65a
--- /dev/null
+++ b/library/src/scala/collection/convert/impl/ChampStepper.scala
@@ -0,0 +1,245 @@
+/*
+ * 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.convert
+package impl
+
+import scala.collection.Stepper.EfficientSplit
+import scala.collection._
+import scala.collection.immutable.Node
+
+/** A stepper that is a slightly elaborated version of the ChampBaseIterator;
+ * the main difference is that it knows when it should stop instead of running
+ * to the end of all trees.
+ */
+private[collection] abstract class ChampStepperBase[
+ A, T <: Node[T], Sub >: Null, Semi <: Sub with ChampStepperBase[A, T, _, _]
+](protected var maxSize: Int)
+extends EfficientSplit {
+ import Node.MaxDepth
+
+ // Much of this code is identical to ChampBaseIterator. If you change that, look here too!
+
+ protected var currentValueCursor: Int = 0
+ protected var currentValueLength: Int = 0
+ protected var currentValueNode: T = _
+
+ private var currentStackLevel: Int = -1
+ private var nodeCursorsAndLengths: Array[Int] = _
+ private var nodes: Array[T] = _
+
+ private def initNodes(): Unit = {
+ if (nodeCursorsAndLengths eq null) {
+ nodeCursorsAndLengths = new Array[Int](MaxDepth * 2)
+ nodes = new Array[Node[T]](MaxDepth).asInstanceOf[Array[T]]
+ }
+ }
+ def initRoot(rootNode: T): Unit = {
+ if (rootNode.hasNodes) pushNode(rootNode)
+ if (rootNode.hasPayload) setupPayloadNode(rootNode)
+ }
+
+ private final def setupPayloadNode(node: T): Unit = {
+ currentValueNode = node
+ currentValueCursor = 0
+ currentValueLength = node.payloadArity
+ }
+
+ private final def pushNode(node: T): Unit = {
+ initNodes()
+ currentStackLevel = currentStackLevel + 1
+
+ val cursorIndex = currentStackLevel * 2
+ val lengthIndex = currentStackLevel * 2 + 1
+
+ nodes(currentStackLevel) = node
+ nodeCursorsAndLengths(cursorIndex) = 0
+ nodeCursorsAndLengths(lengthIndex) = node.nodeArity
+ }
+
+ private final def popNode(): Unit = {
+ currentStackLevel = currentStackLevel - 1
+ }
+
+ /**
+ * Searches for next node that contains payload values,
+ * and pushes encountered sub-nodes on a stack for depth-first traversal.
+ */
+ private final def searchNextValueNode(): Boolean = {
+ while (currentStackLevel >= 0) {
+ val cursorIndex = currentStackLevel * 2
+ val lengthIndex = currentStackLevel * 2 + 1
+
+ val nodeCursor = nodeCursorsAndLengths(cursorIndex)
+ val nodeLength = nodeCursorsAndLengths(lengthIndex)
+
+ if (nodeCursor < nodeLength) {
+ nodeCursorsAndLengths(cursorIndex) += 1
+
+ val nextNode = nodes(currentStackLevel).getNode(nodeCursor)
+
+ if (nextNode.hasNodes) { pushNode(nextNode) }
+ if (nextNode.hasPayload) { setupPayloadNode(nextNode) ; return true }
+ } else {
+ popNode()
+ }
+ }
+ false
+ }
+
+ def characteristics: Int = 0
+
+ def estimateSize: Long = if (hasStep) maxSize else 0L
+
+ def semiclone(): Semi
+
+ final def hasStep: Boolean = maxSize > 0 && {
+ val ans = (currentValueCursor < currentValueLength) || searchNextValueNode()
+ if (!ans) maxSize = 0
+ ans
+ }
+
+ final def trySplit(): Sub =
+ if (!hasStep) null
+ else {
+ var fork = 0
+ while (fork <= currentStackLevel && nodeCursorsAndLengths(2*fork) >= nodeCursorsAndLengths(2*fork + 1)) fork += 1
+ if (fork > currentStackLevel && currentValueCursor > currentValueLength -2) null
+ else {
+ val semi = semiclone()
+ semi.maxSize = maxSize
+ semi.currentValueCursor = currentValueCursor
+ semi.currentValueNode = currentValueNode
+ if (fork > currentStackLevel) {
+ // Just need to finish the current node
+ semi.currentStackLevel = -1
+ val i = (currentValueCursor + currentValueLength) >>> 1
+ semi.currentValueLength = i
+ currentValueCursor = i
+ }
+ else {
+ // Need (at least some of) the full stack, so make an identical copy
+ semi.nodeCursorsAndLengths = java.util.Arrays.copyOf(nodeCursorsAndLengths, nodeCursorsAndLengths.length)
+ semi.nodes = java.util.Arrays.copyOf(nodes.asInstanceOf[Array[Node[T]]], nodes.length).asInstanceOf[Array[T]]
+ semi.currentStackLevel = currentStackLevel
+ semi.currentValueLength = currentValueLength
+
+ // Split the top level of the stack where there's still something to split
+ // Could make this more efficient by duplicating code from searchNextValueNode
+ // instead of setting up for it to run normally. But splits tend to be rare,
+ // so it's not critically important.
+ //
+ // Note that this split can be kind of uneven; if we knew how many child nodes there
+ // were we could do better.
+ val i = (nodeCursorsAndLengths(2*fork) + nodeCursorsAndLengths(2*fork + 1)) >>> 1
+ semi.nodeCursorsAndLengths(2*fork + 1) = i
+ var j = currentStackLevel
+ while (j > fork) {
+ nodeCursorsAndLengths(2*j) = nodeCursorsAndLengths(2*j + 1)
+ j -= 1
+ }
+ nodeCursorsAndLengths(2*fork) = i
+ searchNextValueNode()
+ }
+ semi
+ }
+ }
+}
+
+
+private[collection] final class AnyChampStepper[A, T >: Null <: Node[T]](_maxSize: Int, protected val extract: (T, Int) => A)
+extends ChampStepperBase[A, T, AnyStepper[A], AnyChampStepper[A, T]](_maxSize)
+with AnyStepper[A] {
+ def nextStep(): A =
+ if (hasStep) {
+ val ans = extract(currentValueNode, currentValueCursor)
+ currentValueCursor += 1
+ maxSize -= 1
+ ans
+ }
+ else Stepper.throwNSEE()
+
+ def semiclone(): AnyChampStepper[A, T] = new AnyChampStepper[A, T](0, extract)
+}
+private[collection] object AnyChampStepper {
+ def from[A, T >: Null <: Node[T]](maxSize: Int, root: T, extract: (T, Int) => A): AnyChampStepper[A, T] = {
+ val ans = new AnyChampStepper[A, T](maxSize, extract)
+ ans.initRoot(root)
+ ans
+ }
+}
+
+private[collection] final class DoubleChampStepper[T >: Null <: Node[T]](_maxSize: Int, protected val extract: (T, Int) => Double)
+extends ChampStepperBase[Double, T, DoubleStepper, DoubleChampStepper[T]](_maxSize)
+with DoubleStepper {
+ def nextStep(): Double =
+ if (hasStep) {
+ val ans = extract(currentValueNode, currentValueCursor)
+ currentValueCursor += 1
+ maxSize -= 1
+ ans
+ }
+ else Stepper.throwNSEE()
+
+ def semiclone(): DoubleChampStepper[T] = new DoubleChampStepper[T](0, extract)
+}
+private[collection] object DoubleChampStepper {
+ def from[T >: Null <: Node[T]](maxSize: Int, root: T, extract: (T, Int) => Double): DoubleChampStepper[T] = {
+ val ans = new DoubleChampStepper[T](maxSize, extract)
+ ans.initRoot(root)
+ ans
+ }
+}
+
+private[collection] final class IntChampStepper[T >: Null <: Node[T]](_maxSize: Int, protected val extract: (T, Int) => Int)
+extends ChampStepperBase[Int, T, IntStepper, IntChampStepper[T]](_maxSize)
+with IntStepper {
+ def nextStep(): Int =
+ if (hasStep) {
+ val ans = extract(currentValueNode, currentValueCursor)
+ currentValueCursor += 1
+ maxSize -= 1
+ ans
+ }
+ else Stepper.throwNSEE()
+
+ def semiclone(): IntChampStepper[T] = new IntChampStepper[T](0, extract)
+}
+private[collection] object IntChampStepper {
+ def from[T >: Null <: Node[T]](maxSize: Int, root: T, extract: (T, Int) => Int): IntChampStepper[T] = {
+ val ans = new IntChampStepper[T](maxSize, extract)
+ ans.initRoot(root)
+ ans
+ }
+}
+
+private[collection] final class LongChampStepper[T >: Null <: Node[T]](_maxSize: Int, protected val extract: (T, Int) => Long)
+extends ChampStepperBase[Long, T, LongStepper, LongChampStepper[T]](_maxSize)
+with LongStepper {
+ def nextStep(): Long =
+ if (hasStep) {
+ val ans = extract(currentValueNode, currentValueCursor)
+ currentValueCursor += 1
+ maxSize -= 1
+ ans
+ }
+ else Stepper.throwNSEE()
+
+ def semiclone(): LongChampStepper[T] = new LongChampStepper[T](0, extract)
+}
+private[collection] object LongChampStepper {
+ def from[T >: Null <: Node[T]](maxSize: Int, root: T, extract: (T, Int) => Long): LongChampStepper[T] = {
+ val ans = new LongChampStepper[T](maxSize, extract)
+ ans.initRoot(root)
+ ans
+ }
+}
diff --git a/library/src/scala/collection/convert/impl/InOrderStepperBase.scala b/library/src/scala/collection/convert/impl/InOrderStepperBase.scala
new file mode 100644
index 000000000000..476b5c882177
--- /dev/null
+++ b/library/src/scala/collection/convert/impl/InOrderStepperBase.scala
@@ -0,0 +1,53 @@
+/*
+ * 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.convert
+package impl
+
+import java.util.Spliterator
+
+import scala.collection.Stepper.EfficientSplit
+
+/** Abstracts all the generic operations of stepping over a collection
+ * that has an indexable ordering but may have gaps.
+ *
+ * For collections that are guaranteed to not have gaps, use `IndexedStepperBase` instead.
+ */
+private[convert] abstract class InOrderStepperBase[Sub >: Null, Semi <: Sub](protected var i0: Int, protected var iN: Int)
+extends EfficientSplit {
+ /** Set `true` if the element at `i0` is known to be there. `false` if either not known or is a gap.
+ */
+ protected def found: Boolean
+
+ /** Advance `i0` over any gaps, updating internal state so `found` is correct at the new position.
+ * Returns the new value of `found`.
+ */
+ protected def findNext(): Boolean
+
+ protected def semiclone(half: Int): Semi
+
+ final def hasStep: Boolean = found || findNext()
+
+ def characteristics: Int = Spliterator.ORDERED
+
+ def estimateSize: Long = iN - i0
+
+ def trySplit(): Sub = {
+ if (iN-1 > i0) {
+ val half = (i0 + iN) >>> 1
+ val ans = semiclone(half)
+ i0 = half
+ ans
+ }
+ else null
+ }
+}
diff --git a/library/src/scala/collection/convert/impl/IndexedSeqStepper.scala b/library/src/scala/collection/convert/impl/IndexedSeqStepper.scala
new file mode 100644
index 000000000000..aa8fbe307278
--- /dev/null
+++ b/library/src/scala/collection/convert/impl/IndexedSeqStepper.scala
@@ -0,0 +1,44 @@
+/*
+ * 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.convert
+package impl
+
+import scala.collection._
+
+private[collection] class AnyIndexedSeqStepper[A](underlying: collection.IndexedSeqOps[A, AnyConstr, _], _i0: Int, _iN: Int)
+ extends IndexedStepperBase[AnyStepper[A], AnyIndexedSeqStepper[A]](_i0, _iN)
+ with AnyStepper[A] {
+ def nextStep(): A = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ protected def semiclone(half: Int): AnyIndexedSeqStepper[A] = new AnyIndexedSeqStepper[A](underlying, i0, half)
+}
+
+private[collection] class DoubleIndexedSeqStepper[CC <: collection.IndexedSeqOps[Double, AnyConstr, _]](underlying: CC, _i0: Int, _iN: Int)
+ extends IndexedStepperBase[DoubleStepper, DoubleIndexedSeqStepper[CC]](_i0, _iN)
+ with DoubleStepper {
+ def nextStep(): Double = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ protected def semiclone(half: Int): DoubleIndexedSeqStepper[CC] = new DoubleIndexedSeqStepper[CC](underlying, i0, half)
+}
+
+private[collection] class IntIndexedSeqStepper[CC <: collection.IndexedSeqOps[Int, AnyConstr, _]](underlying: CC, _i0: Int, _iN: Int)
+ extends IndexedStepperBase[IntStepper, IntIndexedSeqStepper[CC]](_i0, _iN)
+ with IntStepper {
+ def nextStep(): Int = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ protected def semiclone(half: Int): IntIndexedSeqStepper[CC] = new IntIndexedSeqStepper[CC](underlying, i0, half)
+}
+
+private[collection] class LongIndexedSeqStepper[CC <: collection.IndexedSeqOps[Long, AnyConstr, _]](underlying: CC, _i0: Int, _iN: Int)
+ extends IndexedStepperBase[LongStepper, LongIndexedSeqStepper[CC]](_i0, _iN)
+ with LongStepper {
+ def nextStep(): Long = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ protected def semiclone(half: Int): LongIndexedSeqStepper[CC] = new LongIndexedSeqStepper[CC](underlying, i0, half)
+}
diff --git a/library/src/scala/collection/convert/impl/IndexedStepperBase.scala b/library/src/scala/collection/convert/impl/IndexedStepperBase.scala
new file mode 100644
index 000000000000..d2094dd30da6
--- /dev/null
+++ b/library/src/scala/collection/convert/impl/IndexedStepperBase.scala
@@ -0,0 +1,40 @@
+/*
+ * 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.convert
+package impl
+
+import java.util.Spliterator
+
+import scala.collection.Stepper.EfficientSplit
+
+/** Abstracts all the generic operations of stepping over an indexable collection */
+private[convert] abstract class IndexedStepperBase[Sub >: Null, Semi <: Sub](protected var i0: Int, protected var iN: Int)
+ extends EfficientSplit {
+ protected def semiclone(half: Int): Semi
+
+ def hasStep: Boolean = i0 < iN
+
+ def characteristics: Int = Spliterator.ORDERED + Spliterator.SIZED + Spliterator.SUBSIZED
+
+ def estimateSize: Long = iN - i0
+
+ def trySplit(): Sub = {
+ if (iN-1 > i0) {
+ val half = (i0+iN) >>> 1
+ val ans = semiclone(half)
+ i0 = half
+ ans
+ }
+ else null
+ }
+}
diff --git a/library/src/scala/collection/convert/impl/IteratorStepper.scala b/library/src/scala/collection/convert/impl/IteratorStepper.scala
new file mode 100644
index 000000000000..8fac29cf96ae
--- /dev/null
+++ b/library/src/scala/collection/convert/impl/IteratorStepper.scala
@@ -0,0 +1,129 @@
+/*
+ * 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.convert
+package impl
+
+import java.util.Spliterator
+
+import scala.collection.{AnyStepper, DoubleStepper, IntStepper, LongStepper, Stepper}
+import scala.jdk.{AnyAccumulator, DoubleAccumulator, IntAccumulator, LongAccumulator}
+
+private[collection] class AnyIteratorStepper[A](_underlying: Iterator[A])
+ extends IteratorStepperBase[A, AnyStepper[A], AnyIteratorStepper[A]](_underlying)
+ with AnyStepper[A] {
+ protected def semiclone(): AnyIteratorStepper[A] = new AnyIteratorStepper(null)
+
+ def nextStep(): A = if (proxied ne null) proxied.nextStep() else underlying.next()
+
+ def trySplit(): AnyStepper[A] = if (proxied ne null) proxied.trySplit() else {
+ val acc = new AnyAccumulator[A]
+ var i = 0
+ val n = nextChunkSize & 0xFFFFFFFC
+ while (i < n && underlying.hasNext) { acc += underlying.next(); i += 1 }
+ if (i < n || !underlying.hasNext) {
+ proxied = acc.stepper
+ proxied.trySplit()
+ }
+ else {
+ val ans = semiclone()
+ ans.proxied = acc.stepper
+ nextChunkSize = if ((nextChunkSize&3) == 3) { if (n < 0x40000000) n*2 else n } else nextChunkSize + 1
+ ans
+ }
+ }
+}
+
+private[collection] class DoubleIteratorStepper(_underlying: Iterator[Double])
+ extends IteratorStepperBase[Double, DoubleStepper, DoubleIteratorStepper](_underlying)
+ with DoubleStepper {
+ protected def semiclone(): DoubleIteratorStepper = new DoubleIteratorStepper(null)
+
+ def nextStep(): Double = if (proxied ne null) proxied.nextStep() else underlying.next()
+
+ def trySplit(): DoubleStepper = if (proxied ne null) proxied.trySplit() else {
+ val acc = new DoubleAccumulator
+ var i = 0
+ val n = nextChunkSize & 0xFFFFFFFC
+ while (i < n && underlying.hasNext) { acc += underlying.next(); i += 1 }
+ if (i < n || !underlying.hasNext) {
+ proxied = acc.stepper
+ proxied.trySplit()
+ }
+ else {
+ val ans = semiclone()
+ ans.proxied = acc.stepper
+ nextChunkSize = if ((nextChunkSize&3) == 3) { if (n < 0x40000000) n*2 else n } else nextChunkSize + 1
+ ans
+ }
+ }
+}
+
+private[collection] class IntIteratorStepper(_underlying: Iterator[Int])
+ extends IteratorStepperBase[Int, IntStepper, IntIteratorStepper](_underlying)
+ with IntStepper {
+ protected def semiclone(): IntIteratorStepper = new IntIteratorStepper(null)
+
+ def nextStep(): Int = if (proxied ne null) proxied.nextStep() else underlying.next()
+
+ def trySplit(): IntStepper = if (proxied ne null) proxied.trySplit() else {
+ val acc = new IntAccumulator
+ var i = 0
+ val n = nextChunkSize & 0xFFFFFFFC
+ while (i < n && underlying.hasNext) { acc += underlying.next(); i += 1 }
+ if (i < n || !underlying.hasNext) {
+ proxied = acc.stepper
+ proxied.trySplit()
+ }
+ else {
+ val ans = semiclone()
+ ans.proxied = acc.stepper
+ nextChunkSize = if ((nextChunkSize&3) == 3) { if (n < 0x40000000) n*2 else n } else nextChunkSize + 1
+ ans
+ }
+ }
+}
+
+private[collection] class LongIteratorStepper(_underlying: Iterator[Long])
+ extends IteratorStepperBase[Long, LongStepper, LongIteratorStepper](_underlying)
+ with LongStepper {
+ protected def semiclone(): LongIteratorStepper = new LongIteratorStepper(null)
+
+ def nextStep(): Long = if (proxied ne null) proxied.nextStep() else underlying.next()
+
+ def trySplit(): LongStepper = if (proxied ne null) proxied.trySplit() else {
+ val acc = new LongAccumulator
+ var i = 0
+ val n = nextChunkSize & 0xFFFFFFFC
+ while (i < n && underlying.hasNext) { acc += underlying.next(); i += 1 }
+ if (i < n || !underlying.hasNext) {
+ proxied = acc.stepper
+ proxied.trySplit()
+ }
+ else {
+ val ans = semiclone()
+ ans.proxied = acc.stepper
+ nextChunkSize = if ((nextChunkSize&3) == 3) { if (n < 0x40000000) n*2 else n } else nextChunkSize + 1
+ ans
+ }
+ }
+}
+
+/** Common functionality for Steppers that step through an Iterator, caching the results as needed when a split is requested. */
+private[convert] abstract class IteratorStepperBase[A, SP >: Null <: Stepper[A], Semi <: SP](final protected val underlying: Iterator[A]) {
+ final protected var nextChunkSize = 16
+ final protected var proxied: SP = null
+ protected def semiclone(): Semi // Must initialize with null iterator!
+ def characteristics: Int = if (proxied ne null) Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED else Spliterator.ORDERED
+ def estimateSize: Long = if (proxied ne null) proxied.estimateSize else Long.MaxValue
+ def hasStep: Boolean = if (proxied ne null) proxied.hasStep else underlying.hasNext
+}
diff --git a/library/src/scala/collection/convert/impl/NumericRangeStepper.scala b/library/src/scala/collection/convert/impl/NumericRangeStepper.scala
new file mode 100644
index 000000000000..3a03f8fabf63
--- /dev/null
+++ b/library/src/scala/collection/convert/impl/NumericRangeStepper.scala
@@ -0,0 +1,38 @@
+/*
+ * 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.convert
+package impl
+
+import scala.collection.{AnyStepper, IntStepper, LongStepper, Stepper}
+import scala.collection.immutable.NumericRange
+
+private[collection] class AnyNumericRangeStepper[A](underlying: NumericRange[A], _i0: Int, _iN: Int)
+extends IndexedStepperBase[AnyStepper[A], AnyNumericRangeStepper[A]](_i0, _iN)
+with AnyStepper[A] {
+ def nextStep(): A = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ def semiclone(half: Int) = new AnyNumericRangeStepper[A](underlying, i0, half)
+}
+
+private[collection] class IntNumericRangeStepper(underlying: NumericRange[Int], _i0: Int, _iN: Int)
+extends IndexedStepperBase[IntStepper, IntNumericRangeStepper](_i0, _iN)
+with IntStepper {
+ def nextStep(): Int = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ def semiclone(half: Int) = new IntNumericRangeStepper(underlying, i0, half)
+}
+
+private[collection] class LongNumericRangeStepper(underlying: NumericRange[Long], _i0: Int, _iN: Int)
+extends IndexedStepperBase[LongStepper, LongNumericRangeStepper](_i0, _iN)
+with LongStepper {
+ def nextStep(): Long = if (hasStep) { val j = i0; i0 += 1; underlying(j) } else Stepper.throwNSEE()
+ def semiclone(half: Int) = new LongNumericRangeStepper(underlying, i0, half)
+}
diff --git a/library/src/scala/collection/convert/impl/RangeStepper.scala b/library/src/scala/collection/convert/impl/RangeStepper.scala
new file mode 100644
index 000000000000..46f803151704
--- /dev/null
+++ b/library/src/scala/collection/convert/impl/RangeStepper.scala
@@ -0,0 +1,40 @@
+/*
+ * 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.convert
+package impl
+
+import scala.collection.{IntStepper, Stepper}
+
+/** Implements Stepper on an integer Range. You don't actually need the Range to do this,
+ * so only the relevant parts are included. Because the arguments are protected, they are
+ * not error-checked; `Range` is required to provide valid arguments.
+ */
+private[collection] final class RangeStepper(protected var myNext: Int, myStep: Int, _i0: Int, _iN: Int)
+extends IndexedStepperBase[IntStepper, RangeStepper](_i0, _iN)
+with IntStepper {
+ def nextStep(): Int =
+ if (hasStep) {
+ val ans = myNext
+ myNext += myStep
+ i0 += 1
+ ans
+ }
+ else Stepper.throwNSEE()
+ protected def semiclone(half: Int): RangeStepper = new RangeStepper(myNext, myStep, i0, half)
+ override def trySplit(): IntStepper = {
+ val old_i0 = i0
+ val ans = super.trySplit()
+ myNext += (i0 - old_i0) * myStep
+ ans
+ }
+}
diff --git a/library/src/scala/collection/convert/impl/StringStepper.scala b/library/src/scala/collection/convert/impl/StringStepper.scala
new file mode 100644
index 000000000000..e8c4d7073c43
--- /dev/null
+++ b/library/src/scala/collection/convert/impl/StringStepper.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.collection.convert
+package impl
+
+import java.lang.Character.{charCount, isLowSurrogate}
+import java.util.Spliterator
+
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.{IntStepper, Stepper}
+
+/** Implements `Stepper` on a `String` where you step through chars packed into `Int`.
+ */
+private[collection] final class CharStringStepper(underlying: String, _i0: Int, _iN: Int)
+extends IndexedStepperBase[IntStepper, CharStringStepper](_i0, _iN)
+with IntStepper {
+ def nextStep(): Int =
+ if (hasStep) { val j = i0; i0 += 1; underlying.charAt(j) }
+ else Stepper.throwNSEE()
+
+ def semiclone(half: Int): CharStringStepper = new CharStringStepper(underlying, i0, half)
+}
+
+/** Implements `Stepper` on a `String` where you step through code points.
+ */
+private[collection] final class CodePointStringStepper(underlying: String, private var i0: Int, private var iN: Int)
+extends IntStepper with EfficientSplit {
+ def characteristics: Int = Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED
+ def estimateSize: Long = iN - i0
+ def hasStep: Boolean = i0 < iN
+ def nextStep(): Int = {
+ if (hasStep) {
+ val cp = underlying.codePointAt(i0)
+ i0 += charCount(cp)
+ cp
+ }
+ else Stepper.throwNSEE()
+ }
+ def trySplit(): CodePointStringStepper =
+ if (iN - 3 > i0) {
+ var half = (i0 + iN) >>> 1
+ if (isLowSurrogate(underlying.charAt(half))) half -= 1
+ val ans = new CodePointStringStepper(underlying, i0, half)
+ i0 = half
+ ans
+ }
+ else null
+}
diff --git a/library/src/scala/collection/convert/impl/TableStepper.scala b/library/src/scala/collection/convert/impl/TableStepper.scala
new file mode 100644
index 000000000000..2c144e4fae8f
--- /dev/null
+++ b/library/src/scala/collection/convert/impl/TableStepper.scala
@@ -0,0 +1,138 @@
+/*
+ * 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.convert
+package impl
+
+import scala.collection.Stepper.EfficientSplit
+import scala.collection._
+
+private[collection] abstract class TableStepperBase[A, I >: Null <: AnyRef, Sub >: Null, Semi <: Sub with TableStepperBase[A, I, _, _]](
+ protected var maxLength: Int, protected val table: Array[I], protected var i0: Int, protected val iN: Int
+)
+extends EfficientSplit {
+ // Always holds table(i0); if `null` it is time to switch to the next element
+ protected var myCurrent: I = if (i0 < iN) table(i0) else null
+
+ // Only call this when `myCurrent` is null (meaning we need to advance)
+ @annotation.tailrec
+ protected final def findNextCurrent(): Boolean =
+ if (i0 < iN) {
+ i0 += 1
+ if (i0 >= iN) false
+ else {
+ myCurrent = table(i0)
+ if (myCurrent eq null) findNextCurrent()
+ else true
+ }
+ }
+ else false
+
+ protected def semiclone(half: Int): Semi
+
+ def characteristics: Int = 0
+
+ def estimateSize: Long = if (!hasStep) { maxLength = 0; 0 } else maxLength
+
+ def hasStep: Boolean = (myCurrent ne null) || findNextCurrent()
+
+ def trySplit(): Sub = {
+ if (iN-1 > i0 && maxLength > 0) {
+ val half = (i0 + iN) >>> 1
+ val ans = semiclone(half)
+ ans.myCurrent = myCurrent
+ myCurrent = table(half)
+ var inLeft = if (ans.myCurrent ne null) 1 else 0
+ var inRight = if (myCurrent ne null) 1 else 0
+ if (iN - i0 < 32) {
+ var i = i0+1
+ while (i < half && (table(i) ne null)) { i += 1; inLeft += 1 }
+ i = half+1
+ while (i < iN && (table(i) ne null)) { i += 1; inRight += 1 }
+ }
+ maxLength -= inLeft
+ ans.maxLength -= inRight
+ i0 = half
+ ans
+ }
+ else null
+ }
+}
+
+
+private[collection] final class AnyTableStepper[A, I >: Null <: AnyRef](
+ _maxLength: Int, _table: Array[I], iterate: I => I, extract: I => A, _i0: Int, _iN: Int
+)
+extends TableStepperBase[A, I, AnyStepper[A], AnyTableStepper[A, I]](_maxLength, _table, _i0, _iN)
+with AnyStepper[A] {
+ def nextStep(): A =
+ if (hasStep) {
+ val ans = extract(myCurrent)
+ myCurrent = iterate(myCurrent)
+ ans
+ }
+ else Stepper.throwNSEE()
+
+ def semiclone(half: Int): AnyTableStepper[A, I] = new AnyTableStepper[A, I](maxLength, table, iterate, extract, i0, half)
+}
+
+
+private[collection] final class DoubleTableStepper[I >: Null <: AnyRef](
+ _maxLength: Int, _table: Array[I], iterate: I => I, extract: I => Double, _i0: Int, _iN: Int
+)
+extends TableStepperBase[Double, I, DoubleStepper, DoubleTableStepper[I]](_maxLength, _table, _i0, _iN)
+with DoubleStepper {
+ def nextStep(): Double =
+ if (hasStep) {
+ val ans = extract(myCurrent)
+ myCurrent = iterate(myCurrent)
+ ans
+ }
+ else Stepper.throwNSEE()
+
+ def semiclone(half: Int): DoubleTableStepper[I] = new DoubleTableStepper[I](maxLength, table, iterate, extract, i0, half)
+}
+
+
+private[collection] final class IntTableStepper[I >: Null <: AnyRef](
+ _maxLength: Int, _table: Array[I], iterate: I => I, extract: I => Int, _i0: Int, _iN: Int
+)
+extends TableStepperBase[Int, I, IntStepper, IntTableStepper[I]](_maxLength, _table, _i0, _iN)
+with IntStepper {
+ def nextStep(): Int =
+ if (hasStep) {
+ val ans = extract(myCurrent)
+ myCurrent = iterate(myCurrent)
+ ans
+ }
+ else Stepper.throwNSEE()
+
+ def semiclone(half: Int): IntTableStepper[I] = new IntTableStepper[I](maxLength, table, iterate, extract, i0, half)
+}
+
+
+private[collection] final class LongTableStepper[I >: Null <: AnyRef](
+ _maxLength: Int, _table: Array[I], iterate: I => I, extract: I => Long, _i0: Int, _iN: Int
+)
+extends TableStepperBase[Long, I, LongStepper, LongTableStepper[I]](_maxLength, _table, _i0, _iN)
+with LongStepper {
+ def nextStep(): Long =
+ if (hasStep) {
+ val ans = extract(myCurrent)
+ myCurrent = iterate(myCurrent)
+ ans
+ }
+ else Stepper.throwNSEE()
+
+ def semiclone(half: Int): LongTableStepper[I] = new LongTableStepper[I](maxLength, table, iterate, extract, i0, half)
+}
+
diff --git a/library/src/scala/collection/convert/impl/VectorStepper.scala b/library/src/scala/collection/convert/impl/VectorStepper.scala
new file mode 100644
index 000000000000..ca0d45330a70
--- /dev/null
+++ b/library/src/scala/collection/convert/impl/VectorStepper.scala
@@ -0,0 +1,131 @@
+/*
+ * 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.convert
+package impl
+
+import scala.collection._
+
+private[convert] abstract class VectorStepperBase[Sub >: Null, Semi <: Sub](
+ _i0: Int,
+ _iN: Int,
+ protected val displayN: Int,
+ protected val trunk: Array[AnyRef]
+)
+extends IndexedStepperBase[Sub, Semi](_i0, _iN) {
+ protected var index: Int = 32 // Force an advanceData on the first element
+ protected var leaves: Array[AnyRef] = null
+ protected var index1: Int = 32 // Force advanceData to defer to initTo on the first element
+ protected var twigs: Array[AnyRef] = null
+
+ protected final def advanceData(iX: Int): Unit = {
+ index1 += 1
+ if (index1 >= 32) initTo(iX)
+ else {
+ leaves = twigs(index1).asInstanceOf[Array[AnyRef]]
+ index = 0
+ }
+ }
+ protected final def initTo(iX: Int): Unit = displayN match {
+ case 0 =>
+ leaves = trunk
+ index = iX
+ case 1 =>
+ twigs = trunk
+ index1 = iX >>> 5
+ leaves = twigs(index1).asInstanceOf[Array[AnyRef]]
+ index = iX & 0x1F
+ case _ =>
+ var n = displayN
+ var dataN = trunk
+ while (n > 2) {
+ dataN = dataN((iX >> (5*n)) & 0x1F).asInstanceOf[Array[AnyRef]]
+ n -= 1
+ }
+ twigs = dataN((iX >>> 10) & 0x1F).asInstanceOf[Array[AnyRef]]
+ index1 = (iX >> 5) & 0x1F
+ leaves = twigs(index1).asInstanceOf[Array[AnyRef]]
+ index = iX & 0x1F
+ }
+}
+
+private[collection] class AnyVectorStepper[A](_i0: Int, _iN: Int, _displayN: Int, _trunk: Array[AnyRef])
+extends VectorStepperBase[AnyStepper[A], AnyVectorStepper[A]](_i0, _iN, _displayN, _trunk)
+with AnyStepper[A] {
+ def nextStep(): A = if (hasStep) {
+ index += 1
+ if (index >= 32) advanceData(i0)
+ i0 += 1
+ leaves(index).asInstanceOf[A]
+ } else Stepper.throwNSEE()
+ def semiclone(half: Int): AnyVectorStepper[A] = {
+ val ans = new AnyVectorStepper[A](i0, half, displayN, trunk)
+ index = 32
+ index1 = 32
+ i0 = half
+ ans
+ }
+}
+
+private[collection] class DoubleVectorStepper(_i0: Int, _iN: Int, _displayN: Int, _trunk: Array[AnyRef])
+extends VectorStepperBase[DoubleStepper, DoubleVectorStepper](_i0, _iN, _displayN, _trunk)
+with DoubleStepper {
+ def nextStep(): Double = if (hasStep) {
+ index += 1
+ if (index >= 32) advanceData(i0)
+ i0 += 1
+ leaves(index).asInstanceOf[Double]
+ } else Stepper.throwNSEE()
+ def semiclone(half: Int): DoubleVectorStepper = {
+ val ans = new DoubleVectorStepper(i0, half, displayN, trunk)
+ index = 32
+ index1 = 32
+ i0 = half
+ ans
+ }
+}
+
+private[collection] class IntVectorStepper(_i0: Int, _iN: Int, _displayN: Int, _trunk: Array[AnyRef])
+extends VectorStepperBase[IntStepper, IntVectorStepper](_i0, _iN, _displayN, _trunk)
+with IntStepper {
+ def nextStep(): Int = if (hasStep) {
+ index += 1
+ if (index >= 32) advanceData(i0)
+ i0 += 1
+ leaves(index).asInstanceOf[Int]
+ } else Stepper.throwNSEE()
+ def semiclone(half: Int): IntVectorStepper = {
+ val ans = new IntVectorStepper(i0, half, displayN, trunk)
+ index = 32
+ index1 = 32
+ i0 = half
+ ans
+ }
+}
+
+private[collection] class LongVectorStepper(_i0: Int, _iN: Int, _displayN: Int, _trunk: Array[AnyRef])
+extends VectorStepperBase[LongStepper, LongVectorStepper](_i0, _iN, _displayN, _trunk)
+with LongStepper {
+ def nextStep(): Long = if (hasStep) {
+ index += 1
+ if (index >= 32) advanceData(i0)
+ i0 += 1
+ leaves(index).asInstanceOf[Long]
+ } else Stepper.throwNSEE()
+ def semiclone(half: Int): LongVectorStepper = {
+ val ans = new LongVectorStepper(i0, half, displayN, trunk)
+ index = 32
+ index1 = 32
+ i0 = half
+ ans
+ }
+}
diff --git a/library/src/scala/collection/generic/BitOperations.scala b/library/src/scala/collection/generic/BitOperations.scala
new file mode 100644
index 000000000000..4464b4935d07
--- /dev/null
+++ b/library/src/scala/collection/generic/BitOperations.scala
@@ -0,0 +1,50 @@
+/*
+ * 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 generic
+
+
+/** Some bit operations.
+ *
+ * See [[https://www.drmaciver.com/2008/08/unsigned-comparison-in-javascala/]] for
+ * an explanation of unsignedCompare.
+ */
+private[collection] object BitOperations {
+ trait Int {
+ type Int = scala.Int
+ def zero(i: Int, mask: Int) = (i & mask) == 0
+ def mask(i: Int, mask: Int) = i & (complement(mask - 1) ^ mask)
+ def hasMatch(key: Int, prefix: Int, m: Int) = mask(key, m) == prefix
+ def unsignedCompare(i: Int, j: Int) = (i < j) ^ (i < 0) ^ (j < 0)
+ def shorter(m1: Int, m2: Int) = unsignedCompare(m2, m1)
+ def complement(i: Int) = (-1) ^ i
+ def bits(num: Int) = 31 to 0 by -1 map (i => (num >>> i & 1) != 0)
+ def bitString(num: Int, sep: String = "") = bits(num) map (b => if (b) "1" else "0") mkString sep
+ def highestOneBit(j: Int) = java.lang.Integer.highestOneBit(j)
+ }
+ object Int extends Int
+
+ trait Long {
+ type Long = scala.Long
+ def zero(i: Long, mask: Long) = (i & mask) == 0L
+ def mask(i: Long, mask: Long) = i & (complement(mask - 1) ^ mask)
+ def hasMatch(key: Long, prefix: Long, m: Long) = mask(key, m) == prefix
+ def unsignedCompare(i: Long, j: Long) = (i < j) ^ (i < 0L) ^ (j < 0L)
+ def shorter(m1: Long, m2: Long) = unsignedCompare(m2, m1)
+ def complement(i: Long) = (-1L) ^ i
+ def bits(num: Long) = 63L to 0L by -1L map (i => (num >>> i & 1L) != 0L)
+ def bitString(num: Long, sep: String = "") = bits(num) map (b => if (b) "1" else "0") mkString sep
+ def highestOneBit(j: Long) = java.lang.Long.highestOneBit(j)
+ }
+ object Long extends Long
+}
diff --git a/library/src/scala/collection/generic/CommonErrors.scala b/library/src/scala/collection/generic/CommonErrors.scala
new file mode 100644
index 000000000000..e9f863643d27
--- /dev/null
+++ b/library/src/scala/collection/generic/CommonErrors.scala
@@ -0,0 +1,29 @@
+/*
+ * 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 generic
+
+
+/** Some precomputed common errors to reduce the generated code size.
+ */
+private[collection] object CommonErrors {
+ /** IndexOutOfBounds exception with a known max index */
+ @noinline
+ def indexOutOfBounds(index: Int, max: Int): IndexOutOfBoundsException =
+ new IndexOutOfBoundsException(s"$index is out of bounds (min 0, max ${max})")
+
+ /** IndexOutOfBounds exception with an unknown max index. */
+ @noinline
+ def indexOutOfBounds(index: Int): IndexOutOfBoundsException =
+ new IndexOutOfBoundsException(s"$index is out of bounds (min 0, max unknown)")
+}
diff --git a/library/src/scala/collection/generic/DefaultSerializationProxy.scala b/library/src/scala/collection/generic/DefaultSerializationProxy.scala
new file mode 100644
index 000000000000..2e584eaa427d
--- /dev/null
+++ b/library/src/scala/collection/generic/DefaultSerializationProxy.scala
@@ -0,0 +1,87 @@
+/*
+ * 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.generic
+
+import java.io.{ObjectInputStream, ObjectOutputStream}
+
+import scala.collection.{Factory, Iterable}
+import scala.collection.mutable.Builder
+
+/** The default serialization proxy for collection implementations.
+ *
+ * This class is `final` and requires an extra `Factory` object rather than leaving the details of creating a `Builder`
+ * to an abstract method that could be implemented by a subclass. This is necessary because the factory is needed
+ * for deserializing this class's private state, which happens before any subclass fields would be deserialized. Any
+ * additional state required to create the proper `Builder` needs to be captured by the `factory`.
+ */
+@SerialVersionUID(3L)
+final class DefaultSerializationProxy[A](factory: Factory[A, Any], @transient private[this] val coll: Iterable[A]) extends Serializable {
+
+ @transient protected var builder: Builder[A, Any] = _
+
+ private[this] def writeObject(out: ObjectOutputStream): Unit = {
+ out.defaultWriteObject()
+ val k = coll.knownSize
+ out.writeInt(k)
+ var count = 0
+ coll.foreach { x =>
+ out.writeObject(x)
+ count += 1
+ }
+ if(k >= 0) {
+ if(count != k) throw new IllegalStateException(s"Illegal size $count of collection, expected $k")
+ } else out.writeObject(SerializeEnd)
+ }
+
+ private[this] def readObject(in: ObjectInputStream): Unit = {
+ in.defaultReadObject()
+ builder = factory.newBuilder
+ val k = in.readInt()
+ if(k >= 0) {
+ builder.sizeHint(k)
+ var count = 0
+ while(count < k) {
+ builder += in.readObject().asInstanceOf[A]
+ count += 1
+ }
+ } else {
+ while (true) in.readObject match {
+ case SerializeEnd => return
+ case a => builder += a.asInstanceOf[A]
+ }
+ }
+ }
+
+ protected[this] def readResolve(): Any = builder.result()
+}
+
+@SerialVersionUID(3L)
+private[collection] case object SerializeEnd
+
+/** Mix-in trait to enable DefaultSerializationProxy for the standard collection types. Depending on the type
+ * it is mixed into, it will dynamically choose `iterableFactory`, `mapFactory`, `sortedIterableFactory` or
+ * `sortedMapFactory` for deserialization into the respective `CC` type. Override `writeReplace` or implement
+ * it directly without using this trait if you need a non-standard factory or if you want to use a different
+ * serialization scheme.
+ */
+trait DefaultSerializable extends Serializable { this: scala.collection.Iterable[_] =>
+ protected[this] def writeReplace(): AnyRef = {
+ val f: Factory[Any, Any] = this match {
+ case it: scala.collection.SortedMap[_, _] => it.sortedMapFactory.sortedMapFactory[Any, Any](using it.ordering.asInstanceOf[Ordering[Any]]).asInstanceOf[Factory[Any, Any]]
+ case it: scala.collection.Map[_, _] => it.mapFactory.mapFactory[Any, Any].asInstanceOf[Factory[Any, Any]]
+ case it: scala.collection.SortedSet[_] => it.sortedIterableFactory.evidenceIterableFactory[Any](using it.ordering.asInstanceOf[Ordering[Any]])
+ case it => it.iterableFactory.iterableFactory
+ }
+ new DefaultSerializationProxy(f, this)
+ }
+}
diff --git a/library/src/scala/collection/generic/IsIterable.scala b/library/src/scala/collection/generic/IsIterable.scala
new file mode 100644
index 000000000000..2260f0f2aacb
--- /dev/null
+++ b/library/src/scala/collection/generic/IsIterable.scala
@@ -0,0 +1,164 @@
+/*
+ * 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 generic
+
+/** A trait which can be used to avoid code duplication when defining extension
+ * methods that should be applicable both to existing Scala collections (i.e.,
+ * types extending `Iterable`) as well as other (potentially user-defined)
+ * types that could be converted to a Scala collection type. This trait
+ * makes it possible to treat Scala collections and types that can be implicitly
+ * converted to a collection type uniformly. For example, one can provide
+ * extension methods that work both on collection types and on `String`s (`String`s
+ * do not extend `Iterable`, but can be converted to `Iterable`)
+ *
+ * `IsIterable` provides three members:
+ *
+ * 1. type member `A`, which represents the element type of the target `Iterable[A]`
+ * 1. type member `C`, which represents the type returned by transformation operations that preserve the collection’s elements type
+ * 1. method `apply`, which provides a way to convert between the type we wish to add extension methods to, `Repr`, and `IterableOps[A, Iterable, C]`.
+ *
+ * ===Usage===
+ *
+ * One must provide `IsIterable` as an implicit parameter type of an implicit
+ * conversion. Its usage is shown below. Our objective in the following example
+ * is to provide a generic extension method `mapReduce` to any type that extends
+ * or can be converted to `Iterable`. In our example, this includes
+ * `String`.
+ *
+ * {{{
+ * import scala.collection.{Iterable, IterableOps}
+ * import scala.collection.generic.IsIterable
+ *
+ * class ExtensionMethods[Repr, I <: IsIterable[Repr]](coll: Repr, it: I) {
+ * def mapReduce[B](mapper: it.A => B)(reducer: (B, B) => B): B = {
+ * val iter = it(coll).iterator
+ * var res = mapper(iter.next())
+ * while (iter.hasNext)
+ * res = reducer(res, mapper(iter.next()))
+ * res
+ * }
+ * }
+ *
+ * implicit def withExtensions[Repr](coll: Repr)(implicit it: IsIterable[Repr]): ExtensionMethods[Repr, it.type] =
+ * new ExtensionMethods(coll, it)
+ *
+ * // See it in action!
+ * List(1, 2, 3).mapReduce(_ * 2)(_ + _) // res0: Int = 12
+ * "Yeah, well, you know, that's just, like, your opinion, man.".mapReduce(x => 1)(_ + _) // res1: Int = 59
+ *}}}
+ *
+ * Here, we begin by creating a class `ExtensionMethods` which contains our
+ * `mapReduce` extension method.
+ *
+ * Note that `ExtensionMethods` takes a constructor argument `coll` of type `Repr`, where
+ * `Repr` represents (typically) the collection type, and an argument `it` of a subtype of `IsIterable[Repr]`.
+ * The body of the method starts by converting the `coll` argument to an `IterableOps` in order to
+ * call the `iterator` method on it.
+ * The remaining of the implementation is straightforward.
+ *
+ * The `withExtensions` implicit conversion makes the `mapReduce` operation available
+ * on any type `Repr` for which it exists an implicit `IsIterable[Repr]` instance.
+ * Note how we keep track of the precise type of the implicit `it` argument by using the
+ * `it.type` singleton type, rather than the wider `IsIterable[Repr]` type. We do that
+ * so that the information carried by the type members `A` and `C` of the `it` argument
+ * is not lost.
+ *
+ * When the `mapReduce` method is called on some type of which it is not
+ * a member, implicit search is triggered. Because implicit conversion
+ * `withExtensions` is generic, it will be applied as long as an implicit
+ * value of type `IsIterable[Repr]` can be found. Given that the
+ * `IsIterable` companion object contains implicit members that return values of type
+ * `IsIterable`, this requirement is typically satisfied, and the chain
+ * of interactions described in the previous paragraph is set into action.
+ * (See the `IsIterable` companion object, which contains a precise
+ * specification of the available implicits.)
+ *
+ * ''Note'': Currently, it's not possible to combine the implicit conversion and
+ * the class with the extension methods into an implicit class due to
+ * limitations of type inference.
+ *
+ * ===Implementing `IsIterable` for New Types===
+ *
+ * One must simply provide an implicit value of type `IsIterable`
+ * specific to the new type, or an implicit conversion which returns an
+ * instance of `IsIterable` specific to the new type.
+ *
+ * Below is an example of an implementation of the `IsIterable` trait
+ * where the `Repr` type is `Range`.
+ *
+ *{{{
+ * implicit val rangeRepr: IsIterable[Range] { type A = Int; type C = IndexedSeq[Int] } =
+ * new IsIterable[Range] {
+ * type A = Int
+ * type C = IndexedSeq[Int]
+ * def apply(coll: Range): IterableOps[Int, IndexedSeq, IndexedSeq[Int]] = coll
+ * }
+ *}}}
+ *
+ * (Note that in practice the `IsIterable[Range]` instance is already provided by
+ * the standard library, and it is defined as an `IsSeq[Range]` instance)
+ */
+trait IsIterable[Repr] extends IsIterableOnce[Repr] {
+
+ /** The type returned by transformation operations that preserve the same elements
+ * type (e.g. `filter`, `take`).
+ *
+ * In practice, this type is often `Repr` itself, excepted in the case
+ * of `SeqView[A]` (and other `View[A]` subclasses), where it is “only” `View[A]`.
+ */
+ type C
+
+ @deprecated("'conversion' is now a method named 'apply'", "2.13.0")
+ override val conversion: Repr => IterableOps[A, Iterable, C] = apply(_)
+
+ /** A conversion from the type `Repr` to `IterableOps[A, Iterable, C]` */
+ def apply(coll: Repr): IterableOps[A, Iterable, C]
+
+}
+
+object IsIterable extends IsIterableLowPriority {
+
+ // Straightforward case: IterableOps subclasses
+ implicit def iterableOpsIsIterable[A0, CC0[X] <: IterableOps[X, Iterable, CC0[X]]]: IsIterable[CC0[A0]] { type A = A0; type C = CC0[A0] } =
+ new IsIterable[CC0[A0]] {
+ type A = A0
+ type C = CC0[A0]
+ def apply(coll: CC0[A]): IterableOps[A, Iterable, C] = coll
+ }
+
+ // The `BitSet` type can not be unified with the `CC0` parameter of
+ // the above definition because it does not take a type parameter.
+ // Hence the need for a separate case:
+ implicit def bitSetOpsIsIterable[C0 <: BitSet with BitSetOps[C0]]: IsIterable[C0] { type A = Int; type C = C0 } =
+ new IsIterable[C0] {
+ type A = Int
+ type C = C0
+ def apply(coll: C0): IterableOps[Int, Iterable, C0] = coll
+ }
+
+}
+
+trait IsIterableLowPriority {
+
+ // Makes `IsSeq` instances visible in `IsIterable` companion
+ implicit def isSeqLikeIsIterable[Repr](implicit
+ isSeqLike: IsSeq[Repr]
+ ): IsIterable[Repr] { type A = isSeqLike.A; type C = isSeqLike.C } = isSeqLike
+
+ // Makes `IsMap` instances visible in `IsIterable` companion
+ implicit def isMapLikeIsIterable[Repr](implicit
+ isMapLike: IsMap[Repr]
+ ): IsIterable[Repr] { type A = isMapLike.A; type C = isMapLike.C } = isMapLike
+
+}
diff --git a/library/src/scala/collection/generic/IsIterableOnce.scala b/library/src/scala/collection/generic/IsIterableOnce.scala
new file mode 100644
index 000000000000..82f0ec8b7332
--- /dev/null
+++ b/library/src/scala/collection/generic/IsIterableOnce.scala
@@ -0,0 +1,71 @@
+/*
+ * 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 collection
+package generic
+
+/** Type class witnessing that a collection representation type `Repr` has
+ * elements of type `A` and has a conversion to `IterableOnce[A]`.
+ *
+ * This type enables simple enrichment of `IterableOnce`s with extension
+ * methods which can make full use of the mechanics of the Scala collections
+ * framework in their implementation.
+ *
+ * Example usage,
+ * {{{
+ * class FilterMapImpl[Repr, I <: IsIterableOnce[Repr]](coll: Repr, it: I) {
+ * final def filterMap[B, That](f: it.A => Option[B])(implicit bf: BuildFrom[Repr, B, That]): That = {
+ * val b = bf.newBuilder(coll)
+ * for(e <- it(coll).iterator) f(e) foreach (b +=)
+ * b.result()
+ * }
+ * }
+ * implicit def filterMap[Repr](coll: Repr)(implicit it: IsIterableOnce[Repr]): FilterMapImpl[Repr, it.type] =
+ * new FilterMapImpl(coll, it)
+ *
+ * List(1, 2, 3, 4, 5) filterMap (i => if(i % 2 == 0) Some(i) else None)
+ * // == List(2, 4)
+ * }}}
+ */
+trait IsIterableOnce[Repr] {
+
+ /** The type of elements we can traverse over (e.g. `Int`). */
+ type A
+
+ @deprecated("'conversion' is now a method named 'apply'", "2.13.0")
+ val conversion: Repr => IterableOnce[A] = apply(_)
+
+ /** A conversion from the representation type `Repr` to a `IterableOnce[A]`. */
+ def apply(coll: Repr): IterableOnce[A]
+
+}
+
+object IsIterableOnce extends IsIterableOnceLowPriority {
+
+ // Straightforward case: IterableOnce subclasses
+ implicit def iterableOnceIsIterableOnce[CC0[A] <: IterableOnce[A], A0]: IsIterableOnce[CC0[A0]] { type A = A0 } =
+ new IsIterableOnce[CC0[A0]] {
+ type A = A0
+ def apply(coll: CC0[A0]): IterableOnce[A0] = coll
+ }
+
+}
+
+trait IsIterableOnceLowPriority {
+
+ // Makes `IsIterable` instance visible in `IsIterableOnce` companion
+ implicit def isIterableLikeIsIterableOnce[Repr](implicit
+ isIterableLike: IsIterable[Repr]
+ ): IsIterableOnce[Repr] { type A = isIterableLike.A } = isIterableLike
+
+}
diff --git a/library/src/scala/collection/generic/IsMap.scala b/library/src/scala/collection/generic/IsMap.scala
new file mode 100644
index 000000000000..6178b2f2b7ca
--- /dev/null
+++ b/library/src/scala/collection/generic/IsMap.scala
@@ -0,0 +1,115 @@
+/*
+ * 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 generic
+
+import IsMap.Tupled
+import scala.collection.immutable.{IntMap, LongMap}
+
+/**
+ * Type class witnessing that a collection type `Repr`
+ * has keys of type `K`, values of type `V` and has a conversion to
+ * `MapOps[K, V, Iterable, C]`, for some types `K`, `V` and `C`.
+ *
+ * This type enables simple enrichment of `Map`s with extension methods.
+ *
+ * @see [[scala.collection.generic.IsIterable]]
+ * @tparam Repr Collection type (e.g. `Map[Int, String]`)
+ */
+trait IsMap[Repr] extends IsIterable[Repr] {
+
+ /** The type of keys */
+ type K
+
+ /** The type of values */
+ type V
+
+ type A = (K, V)
+
+ /** A conversion from the type `Repr` to `MapOps[K, V, Iterable, C]`
+ *
+ * @note The third type parameter of the returned `MapOps` value is
+ * still `Iterable` (and not `Map`) because `MapView[K, V]` only
+ * extends `MapOps[K, V, View, View[A]]`.
+ */
+ override def apply(c: Repr): MapOps[K, V, Tupled[Iterable]#Ap, C]
+
+}
+
+object IsMap {
+
+ /** Convenient type level function that takes a unary type constructor `F[_]`
+ * and returns a binary type constructor that tuples its parameters and passes
+ * them to `F`.
+ *
+ * `Tupled[F]#Ap` is equivalent to `({ type Ap[X, +Y] = F[(X, Y)] })#Ap`.
+ */
+ type Tupled[F[+_]] = { type Ap[X, Y] = F[(X, Y)] }
+
+ // Map collections
+ implicit def mapOpsIsMap[CC0[X, Y] <: MapOps[X, Y, Tupled[Iterable]#Ap, CC0[X, Y]], K0, V0]: IsMap[CC0[K0, V0]] { type K = K0; type V = V0; type C = CC0[K, V] } =
+ new IsMap[CC0[K0, V0]] {
+ type K = K0
+ type V = V0
+ type C = CC0[K0, V0]
+ def apply(c: CC0[K0, V0]): MapOps[K0, V0, Tupled[Iterable]#Ap, C] = c
+ }
+
+ // MapView
+ implicit def mapViewIsMap[CC0[X, Y] <: MapView[X, Y], K0, V0]: IsMap[CC0[K0, V0]] { type K = K0; type V = V0; type C = View[(K0, V0)] } =
+ new IsMap[CC0[K0, V0]] {
+ type K = K0
+ type V = V0
+ type C = View[(K, V)]
+ def apply(c: CC0[K0, V0]): MapOps[K0, V0, Tupled[Iterable]#Ap, View[(K0, V0)]] = c
+ }
+
+ // AnyRefMap has stricter bounds than the ones used by the mapOpsIsMap definition
+ @deprecated("AnyRefMap is deprecated", "2.13.16")
+ implicit def anyRefMapIsMap[K0 <: AnyRef, V0]: IsMap[mutable.AnyRefMap[K0, V0]] { type K = K0; type V = V0; type C = mutable.AnyRefMap[K0, V0] } =
+ new IsMap[mutable.AnyRefMap[K0, V0]] {
+ type K = K0
+ type V = V0
+ type C = mutable.AnyRefMap[K0, V0]
+ def apply(c: mutable.AnyRefMap[K0, V0]): MapOps[K0, V0, Tupled[Iterable]#Ap, mutable.AnyRefMap[K0, V0]] = c
+ }
+
+ // IntMap takes one type parameter only whereas mapOpsIsMap uses a parameter CC0 with two type parameters
+ implicit def intMapIsMap[V0]: IsMap[IntMap[V0]] { type K = Int; type V = V0; type C = IntMap[V0] } =
+ new IsMap[IntMap[V0]] {
+ type K = Int
+ type V = V0
+ type C = IntMap[V0]
+ def apply(c: IntMap[V0]): MapOps[Int, V0, Tupled[Iterable]#Ap, IntMap[V0]] = c
+ }
+
+ // LongMap is in a similar situation as IntMap
+ implicit def longMapIsMap[V0]: IsMap[LongMap[V0]] { type K = Long; type V = V0; type C = LongMap[V0] } =
+ new IsMap[LongMap[V0]] {
+ type K = Long
+ type V = V0
+ type C = LongMap[V0]
+ def apply(c: LongMap[V0]): MapOps[Long, V0, Tupled[Iterable]#Ap, LongMap[V0]] = c
+ }
+
+ // mutable.LongMap is in a similar situation as LongMap and IntMap
+ implicit def mutableLongMapIsMap[V0]: IsMap[mutable.LongMap[V0]] { type K = Long; type V = V0; type C = mutable.LongMap[V0] } =
+ new IsMap[mutable.LongMap[V0]] {
+ type K = Long
+ type V = V0
+ type C = mutable.LongMap[V0]
+ def apply(c: mutable.LongMap[V0]): MapOps[Long, V0, Tupled[Iterable]#Ap, mutable.LongMap[V0]] = c
+ }
+
+
+}
diff --git a/library/src/scala/collection/generic/IsSeq.scala b/library/src/scala/collection/generic/IsSeq.scala
new file mode 100644
index 000000000000..73d0cc9762d6
--- /dev/null
+++ b/library/src/scala/collection/generic/IsSeq.scala
@@ -0,0 +1,114 @@
+/*
+ * 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 generic
+
+import scala.reflect.ClassTag
+
+/** Type class witnessing that a collection representation type `Repr` has
+ * elements of type `A` and has a conversion to `SeqOps[A, Iterable, C]`, for
+ * some types `A` and `C`.
+ *
+ * This type enables simple enrichment of `Seq`s with extension methods which
+ * can make full use of the mechanics of the Scala collections framework in
+ * their implementation.
+ *
+ * @see [[scala.collection.generic.IsIterable]]
+ */
+trait IsSeq[Repr] extends IsIterable[Repr] {
+
+ @deprecated("'conversion' is now a method named 'apply'", "2.13.0")
+ override val conversion: Repr => SeqOps[A, Iterable, C] = apply(_)
+
+ /** A conversion from the type `Repr` to `SeqOps[A, Iterable, C]`
+ *
+ * @note The second type parameter of the returned `SeqOps` value is
+ * still `Iterable` (and not `Seq`) because `SeqView[A]` only
+ * extends `SeqOps[A, View, View[A]]`.
+ */
+ def apply(coll: Repr): SeqOps[A, Iterable, C]
+}
+
+object IsSeq {
+
+ private val seqOpsIsSeqVal: IsSeq[Seq[Any]] =
+ new IsSeq[Seq[Any]] {
+ type A = Any
+ type C = Any
+ def apply(coll: Seq[Any]): SeqOps[Any, Iterable, Any] = coll
+ }
+
+ implicit def seqOpsIsSeq[CC0[X] <: SeqOps[X, Iterable, CC0[X]], A0]: IsSeq[CC0[A0]] { type A = A0; type C = CC0[A0] } =
+ seqOpsIsSeqVal.asInstanceOf[IsSeq[CC0[A0]] { type A = A0; type C = CC0[A0] }]
+
+ implicit def seqViewIsSeq[CC0[X] <: SeqView[X], A0]: IsSeq[CC0[A0]] { type A = A0; type C = View[A0] } =
+ new IsSeq[CC0[A0]] {
+ type A = A0
+ type C = View[A]
+ def apply(coll: CC0[A0]): SeqOps[A0, View, View[A0]] = coll
+ }
+
+ implicit val stringIsSeq: IsSeq[String] { type A = Char; type C = String } =
+ new IsSeq[String] {
+ type A = Char
+ type C = String
+ def apply(s: String): SeqOps[Char, immutable.IndexedSeq, String] =
+ new SeqOps[Char, immutable.ArraySeq, String] {
+ def length: Int = s.length
+ def apply(i: Int): Char = s.charAt(i)
+ def toIterable: Iterable[Char] = new immutable.WrappedString(s)
+ protected[this] def coll: String = s
+ protected[this] def fromSpecific(coll: IterableOnce[Char]): String = coll.iterator.mkString
+ def iterableFactory: IterableFactory[immutable.ArraySeq] = immutable.ArraySeq.untagged
+ override def empty: String = ""
+ protected[this] def newSpecificBuilder: mutable.Builder[Char, String] = new StringBuilder
+ def iterator: Iterator[Char] = s.iterator
+ }
+ }
+
+ implicit val stringViewIsSeq: IsSeq[StringView] { type A = Char; type C = View[Char] } =
+ new IsSeq[StringView] {
+ type A = Char
+ type C = View[Char]
+ def apply(coll: StringView): SeqOps[Char, View, View[Char]] = coll
+ }
+
+ implicit def arrayIsSeq[A0 : ClassTag]: IsSeq[Array[A0]] { type A = A0; type C = Array[A0] } =
+ new IsSeq[Array[A0]] {
+ type A = A0
+ type C = Array[A0]
+ def apply(a: Array[A0]): SeqOps[A0, Seq, Array[A0]] =
+ new SeqOps[A, mutable.ArraySeq, Array[A]] {
+ def apply(i: Int): A = a(i)
+ def length: Int = a.length
+ def toIterable: Iterable[A] = mutable.ArraySeq.make(a)
+ protected def coll: Array[A] = a
+ protected def fromSpecific(coll: IterableOnce[A]): Array[A] = Array.from(coll)
+ def iterableFactory: IterableFactory[mutable.ArraySeq] = mutable.ArraySeq.untagged
+ override def empty: Array[A] = Array.empty[A]
+ protected def newSpecificBuilder: mutable.Builder[A, Array[A]] = Array.newBuilder
+ def iterator: Iterator[A] = a.iterator
+ }
+ }
+
+ // `Range` can not be unified with the `CC0` parameter of the
+ // `seqOpsIsSeq` definition because it does not take a type parameter.
+ // Hence the need for a separate case:
+ implicit def rangeIsSeq[C0 <: Range]: IsSeq[C0] { type A = Int; type C = immutable.IndexedSeq[Int] } =
+ new IsSeq[C0] {
+ type A = Int
+ type C = immutable.IndexedSeq[Int]
+ def apply(coll: C0): SeqOps[Int, Seq, immutable.IndexedSeq[Int]] = coll
+ }
+
+}
diff --git a/library/src/scala/collection/generic/Subtractable.scala b/library/src/scala/collection/generic/Subtractable.scala
new file mode 100644
index 000000000000..f8af03581aad
--- /dev/null
+++ b/library/src/scala/collection/generic/Subtractable.scala
@@ -0,0 +1,62 @@
+/*
+ * 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 collection
+package generic
+
+/** This trait represents collection-like objects that can be reduced
+ * using a '+' operator. It defines variants of `-` and `--`
+ * as convenience methods in terms of single-element removal `-`.
+ *
+ * @tparam A the type of the elements of the $coll.
+ * @tparam Repr the type of the $coll itself
+ * @define coll collection
+ * @define Coll Subtractable
+ */
+@deprecated("Subtractable is deprecated. This is now implemented as part of SetOps, MapOps, etc.", "2.13.0")
+trait Subtractable[A, +Repr <: Subtractable[A, Repr]] { self =>
+
+ /** The representation object of type `Repr` which contains the collection's elements
+ */
+ protected def repr: Repr
+
+ /** Creates a new $coll from this $coll with an element removed.
+ * @param elem the element to remove
+ * @return a new collection that contains all elements of the current $coll
+ * except one less occurrence of `elem`.
+ */
+ def -(elem: A): Repr
+
+ /** Creates a new $coll from this $coll with some elements removed.
+ *
+ * This method takes two or more elements to be removed. Another overloaded
+ * variant of this method handles the case where a single element is
+ * removed.
+ * @param elem1 the first element to remove.
+ * @param elem2 the second element to remove.
+ * @param elems the remaining elements to remove.
+ * @return a new $coll that contains all elements of the current $coll
+ * except one less occurrence of each of the given elements.
+ */
+ def -(elem1: A, elem2: A, elems: A*): Repr =
+ this - elem1 - elem2 -- elems
+
+ /** Creates a new $coll from this $coll by removing all elements of another
+ * collection.
+ *
+ * @param xs the collection containing the removed elements.
+ * @return a new $coll that contains all elements of the current $coll
+ * except one less occurrence of each of the elements of `elems`.
+ */
+ def --(xs: IterableOnce[A]): Repr = (repr /: xs.iterator) (_ - _)
+}
diff --git a/library/src/scala/collection/generic/package.scala b/library/src/scala/collection/generic/package.scala
new file mode 100644
index 000000000000..5aaf90547384
--- /dev/null
+++ b/library/src/scala/collection/generic/package.scala
@@ -0,0 +1,34 @@
+/*
+ * 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 object generic {
+ @deprecated("Clearable was moved from collection.generic to collection.mutable", "2.13.0")
+ type Clearable = scala.collection.mutable.Clearable
+
+ @deprecated("Use scala.collection.BuildFrom instead", "2.13.0")
+ type CanBuildFrom[-From, -A, +C] = scala.collection.BuildFrom[From, A, C]
+
+ @deprecated("Growable was moved from collection.generic to collection.mutable", "2.13.0")
+ type Growable[-A] = scala.collection.mutable.Growable[A]
+
+ @deprecated("Shrinkable was moved from collection.generic to collection.mutable", "2.13.0")
+ type Shrinkable[-A] = scala.collection.mutable.Shrinkable[A]
+
+ @deprecated("Use IsIterable instead", "2.13.0")
+ type IsTraversableLike[Repr] = IsIterable[Repr]
+
+ @deprecated("Use IsIterableOnce instead", "2.13.0")
+ type IsTraversableOnce[Repr] = IsIterableOnce[Repr]
+}
diff --git a/library/src/scala/collection/immutable/ArraySeq.scala b/library/src/scala/collection/immutable/ArraySeq.scala
new file mode 100644
index 000000000000..eafe9baa719f
--- /dev/null
+++ b/library/src/scala/collection/immutable/ArraySeq.scala
@@ -0,0 +1,694 @@
+/*
+ * 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.util.Arrays
+
+import scala.annotation.unchecked.uncheckedVariance
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.mutable.{ArrayBuffer, ArrayBuilder, Builder, ArraySeq => MutableArraySeq}
+import scala.collection.convert.impl._
+import scala.reflect.ClassTag
+import scala.runtime.ScalaRunTime
+import scala.util.Sorting
+import scala.util.hashing.MurmurHash3
+
+/**
+ * An immutable array.
+ *
+ * Supports efficient indexed access and has a small memory footprint.
+ *
+ * @define coll immutable array
+ * @define Coll `ArraySeq`
+ */
+sealed abstract class ArraySeq[+A]
+ extends AbstractSeq[A]
+ with IndexedSeq[A]
+ with IndexedSeqOps[A, ArraySeq, ArraySeq[A]]
+ with StrictOptimizedSeqOps[A, ArraySeq, ArraySeq[A]]
+ with EvidenceIterableFactoryDefaults[A, ArraySeq, ClassTag]
+ with Serializable {
+
+ /** The tag of the element type. This does not have to be equal to the element type of this ArraySeq. A primitive
+ * ArraySeq can be backed by an array of boxed values and a reference ArraySeq can be backed by an array of a supertype
+ * or subtype of the element type. */
+ protected def elemTag: ClassTag[_]
+
+ override def iterableFactory: SeqFactory[ArraySeq] = ArraySeq.untagged
+
+ /** The wrapped mutable `Array` that backs this `ArraySeq`. Any changes to this array will break
+ * the expected immutability. Its element type does not have to be equal to the element type of this ArraySeq.
+ * A primitive ArraySeq can be backed by an array of boxed values and a reference ArraySeq can be backed by an
+ * array of a supertype or subtype of the element type. */
+ def unsafeArray: Array[_]
+
+ protected def evidenceIterableFactory: ArraySeq.type = ArraySeq
+ protected def iterableEvidence: ClassTag[A @uncheckedVariance] = elemTag.asInstanceOf[ClassTag[A]]
+
+ def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit
+
+ @throws[ArrayIndexOutOfBoundsException]
+ def apply(i: Int): A
+
+ override def updated[B >: A](index: Int, elem: B): ArraySeq[B] = {
+ val dest = new Array[Any](length)
+ Array.copy(unsafeArray, 0, dest, 0, length)
+ dest(index) = elem
+ ArraySeq.unsafeWrapArray(dest).asInstanceOf[ArraySeq[B]]
+ }
+
+ override def map[B](f: A => B): ArraySeq[B] = {
+ val a = new Array[Any](size)
+ var i = 0
+ while (i < a.length){
+ a(i) = f(apply(i))
+ i += 1
+ }
+ ArraySeq.unsafeWrapArray(a).asInstanceOf[ArraySeq[B]]
+ }
+
+ override def prepended[B >: A](elem: B): ArraySeq[B] =
+ ArraySeq.unsafeWrapArray(unsafeArray.prepended[Any](elem)).asInstanceOf[ArraySeq[B]]
+
+ override def appended[B >: A](elem: B): ArraySeq[B] =
+ ArraySeq.unsafeWrapArray(unsafeArray.appended[Any](elem)).asInstanceOf[ArraySeq[B]]
+
+ /** Fast concatenation of two [[ArraySeq]]s.
+ *
+ * @return null if optimisation not possible.
+ */
+ private def appendedAllArraySeq[B >: A](that: ArraySeq[B]): ArraySeq[B] = {
+ // Optimise concatenation of two ArraySeqs
+ // For ArraySeqs with sizes of [100, 1000, 10000] this is [3.5, 4.1, 5.2]x as fast
+ if (isEmpty)
+ that
+ else if (that.isEmpty)
+ this
+ else {
+ val thisIsObj = this.unsafeArray.isInstanceOf[Array[AnyRef]]
+ val thatIsObj = that.unsafeArray.isInstanceOf[Array[AnyRef]]
+ val mismatch = thisIsObj != thatIsObj
+ if (mismatch)
+ // Combining primatives and objects: abort
+ null
+ else if (thisIsObj) {
+ // A and B are objects
+ val ax = this.unsafeArray.asInstanceOf[Array[A]]
+ val ay = that.unsafeArray.asInstanceOf[Array[B]]
+ val len = ax.length + ay.length
+ val a = new Array[AnyRef](len)
+ System.arraycopy(ax, 0, a, 0, ax.length)
+ System.arraycopy(ay, 0, a, ax.length, ay.length)
+ ArraySeq.unsafeWrapArray(a).asInstanceOf[ArraySeq[B]]
+ } else {
+ // A is a primative and B = A. Use this instance's protected ClassTag.
+ val ax = this.unsafeArray.asInstanceOf[Array[A]]
+ val ay = that.unsafeArray.asInstanceOf[Array[A]]
+ val len = ax.length + ay.length
+ val a = iterableEvidence.newArray(len)
+ System.arraycopy(ax, 0, a, 0, ax.length)
+ System.arraycopy(ay, 0, a, ax.length, ay.length)
+ ArraySeq.unsafeWrapArray(a).asInstanceOf[ArraySeq[B]]
+ }
+ }
+ }
+
+ override def appendedAll[B >: A](suffix: collection.IterableOnce[B]): ArraySeq[B] = {
+ def genericResult = {
+ val k = suffix.knownSize
+ if (k == 0) this
+ else {
+ val b = ArrayBuilder.make[Any]
+ if(k >= 0) b.sizeHint(k + unsafeArray.length)
+ b.addAll(unsafeArray)
+ b.addAll(suffix)
+ ArraySeq.unsafeWrapArray(b.result()).asInstanceOf[ArraySeq[B]]
+ }
+ }
+
+ suffix match {
+ case that: ArraySeq[_] =>
+ val result = appendedAllArraySeq(that.asInstanceOf[ArraySeq[B]])
+ if (result == null) genericResult
+ else result
+ case _ =>
+ genericResult
+ }
+ }
+
+ override def prependedAll[B >: A](prefix: collection.IterableOnce[B]): ArraySeq[B] = {
+ def genericResult = {
+ val k = prefix.knownSize
+ if (k == 0) this
+ else {
+ val b = ArrayBuilder.make[Any]
+ if(k >= 0) b.sizeHint(k + unsafeArray.length)
+ b.addAll(prefix)
+ if(k < 0) b.sizeHint(b.length + unsafeArray.length)
+ b.addAll(unsafeArray)
+ ArraySeq.unsafeWrapArray(b.result()).asInstanceOf[ArraySeq[B]]
+ }
+ }
+
+ prefix match {
+ case that: ArraySeq[_] =>
+ val result = that.asInstanceOf[ArraySeq[B]].appendedAllArraySeq(this)
+ if (result == null) genericResult
+ else result
+ case _ =>
+ genericResult
+ }
+ }
+
+ override def zip[B](that: collection.IterableOnce[B]): ArraySeq[(A, B)] =
+ that match {
+ case bs: ArraySeq[B] =>
+ ArraySeq.tabulate(length min bs.length) { i =>
+ (apply(i), bs(i))
+ }
+ case _ =>
+ strictOptimizedZip[B, ArraySeq[(A, B)]](that, iterableFactory.newBuilder)
+ }
+
+ override def take(n: Int): ArraySeq[A] =
+ if (unsafeArray.length <= n)
+ this
+ else
+ ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).take(n)).asInstanceOf[ArraySeq[A]]
+
+ override def takeRight(n: Int): ArraySeq[A] =
+ if (unsafeArray.length <= n)
+ this
+ else
+ ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).takeRight(n)).asInstanceOf[ArraySeq[A]]
+
+ override def drop(n: Int): ArraySeq[A] =
+ if (n <= 0)
+ this
+ else
+ ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).drop(n)).asInstanceOf[ArraySeq[A]]
+
+ override def dropRight(n: Int): ArraySeq[A] =
+ if (n <= 0)
+ this
+ else
+ ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).dropRight(n)).asInstanceOf[ArraySeq[A]]
+
+ override def slice(from: Int, until: Int): ArraySeq[A] =
+ if (from <= 0 && unsafeArray.length <= until)
+ this
+ else
+ ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).slice(from, until)).asInstanceOf[ArraySeq[A]]
+
+ override def foldLeft[B](z: B)(f: (B, A) => B): B = {
+ // For ArraySeqs with sizes of [100, 1000, 10000] this is [1.3, 1.8, 1.8]x as fast
+ // as the same while-loop over this instead of unsafeArray.
+ val array = unsafeArray
+ var b = z
+ var i = 0
+ while (i < array.length) {
+ val a = array(i).asInstanceOf[A]
+ b = f(b, a)
+ i += 1
+ }
+ b
+ }
+
+ override def foldRight[B](z: B)(f: (A, B) => B): B = {
+ // For ArraySeqs with sizes of [100, 1000, 10000] this is [1.6, 1.8, 2.7]x as fast
+ // as the same while-loop over this instead of unsafeArray.
+ val array = unsafeArray
+ var b = z
+ var i = array.length
+ while (i > 0) {
+ i -= 1
+ val a = array(i).asInstanceOf[A]
+ b = f(a, b)
+ }
+ b
+ }
+
+ override def tail: ArraySeq[A] = ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).tail).asInstanceOf[ArraySeq[A]]
+
+ override def reverse: ArraySeq[A] = ArraySeq.unsafeWrapArray(new ArrayOps(unsafeArray).reverse).asInstanceOf[ArraySeq[A]]
+
+ override protected[this] def className = "ArraySeq"
+
+ override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = {
+ val copied = IterableOnce.elemsToCopyToArray(length, xs.length, start, len)
+ if(copied > 0) {
+ Array.copy(unsafeArray, 0, xs, start, copied)
+ }
+ copied
+ }
+
+ override protected final def applyPreferredMaxLength: Int = Int.MaxValue
+
+ override def sorted[B >: A](implicit ord: Ordering[B]): ArraySeq[A] =
+ if(unsafeArray.length <= 1) this
+ else {
+ val a = Array.copyAs[AnyRef](unsafeArray, length)(ClassTag.AnyRef)
+ Arrays.sort(a, ord.asInstanceOf[Ordering[AnyRef]])
+ new ArraySeq.ofRef[AnyRef](a).asInstanceOf[ArraySeq[A]]
+ }
+}
+
+/**
+ * $factoryInfo
+ * @define coll immutable array
+ * @define Coll `ArraySeq`
+ */
+@SerialVersionUID(3L)
+object ArraySeq extends StrictOptimizedClassTagSeqFactory[ArraySeq] { self =>
+ val untagged: SeqFactory[ArraySeq] = new ClassTagSeqFactory.AnySeqDelegate(self)
+
+ private[this] lazy val emptyImpl = new ArraySeq.ofRef[Nothing](new Array[Nothing](0))
+
+ def empty[A : ClassTag]: ArraySeq[A] = emptyImpl
+
+ def from[A](it: scala.collection.IterableOnce[A])(implicit tag: ClassTag[A]): ArraySeq[A] = it match {
+ case as: ArraySeq[A] => as
+ case _ => unsafeWrapArray(Array.from[A](it))
+ }
+
+ def newBuilder[A : ClassTag]: Builder[A, ArraySeq[A]] =
+ ArrayBuffer.newBuilder[A].mapResult(b => unsafeWrapArray[A](b.toArray))
+
+ override def fill[A : ClassTag](n: Int)(elem: => A): ArraySeq[A] = tabulate(n)(_ => elem)
+
+ override def tabulate[A : ClassTag](n: Int)(f: Int => A): ArraySeq[A] = {
+ val elements = Array.ofDim[A](scala.math.max(n, 0))
+ var i = 0
+ while (i < n) {
+ ScalaRunTime.array_update(elements, i, f(i))
+ i = i + 1
+ }
+ ArraySeq.unsafeWrapArray(elements)
+ }
+
+ /**
+ * Wrap an existing `Array` into an `ArraySeq` of the proper primitive specialization type
+ * without copying. Any changes to wrapped array will break the expected immutability.
+ *
+ * Note that an array containing boxed primitives can be wrapped in an `ArraySeq` without
+ * copying. For example, `val a: Array[Any] = Array(1)` is an array of `Object` at runtime,
+ * containing `Integer`s. An `ArraySeq[Int]` can be obtained with a cast:
+ * `ArraySeq.unsafeWrapArray(a).asInstanceOf[ArraySeq[Int]]`. The values are still
+ * boxed, the resulting instance is an [[ArraySeq.ofRef]]. Writing
+ * `ArraySeq.unsafeWrapArray(a.asInstanceOf[Array[Int]])` does not work, it throws a
+ * `ClassCastException` at runtime.
+ */
+ def unsafeWrapArray[T](x: Array[T]): ArraySeq[T] = ((x: @unchecked) match {
+ case null => null
+ case x: Array[AnyRef] => new ofRef[AnyRef](x)
+ case x: Array[Int] => new ofInt(x)
+ case x: Array[Double] => new ofDouble(x)
+ case x: Array[Long] => new ofLong(x)
+ case x: Array[Float] => new ofFloat(x)
+ case x: Array[Char] => new ofChar(x)
+ case x: Array[Byte] => new ofByte(x)
+ case x: Array[Short] => new ofShort(x)
+ case x: Array[Boolean] => new ofBoolean(x)
+ case x: Array[Unit] => new ofUnit(x)
+ }).asInstanceOf[ArraySeq[T]]
+
+ @SerialVersionUID(3L)
+ final class ofRef[T <: AnyRef](val unsafeArray: Array[T]) extends ArraySeq[T] {
+ def elemTag: ClassTag[T] = ClassTag[T](unsafeArray.getClass.getComponentType)
+ def length: Int = unsafeArray.length
+ @throws[ArrayIndexOutOfBoundsException]
+ def apply(i: Int): T = unsafeArray(i)
+ override def hashCode = MurmurHash3.arraySeqHash(unsafeArray)
+ override def equals(that: Any): Boolean = that match {
+ case that: ofRef[_] =>
+ Array.equals(
+ this.unsafeArray.asInstanceOf[Array[AnyRef]],
+ that.unsafeArray.asInstanceOf[Array[AnyRef]])
+ case _ => super.equals(that)
+ }
+ override def sorted[B >: T](implicit ord: Ordering[B]): ArraySeq.ofRef[T] = {
+ if(unsafeArray.length <= 1) this
+ else {
+ val a = unsafeArray.clone()
+ Arrays.sort(a, ord.asInstanceOf[Ordering[T]])
+ new ArraySeq.ofRef(a)
+ }
+ }
+ override def iterator: Iterator[T] = new ArrayOps.ArrayIterator[T](unsafeArray)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[T, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ new ObjectArrayStepper(unsafeArray, 0, unsafeArray.length)
+ else shape.parUnbox(new ObjectArrayStepper(unsafeArray, 0, unsafeArray.length).asInstanceOf[AnyStepper[T] with EfficientSplit])
+ ).asInstanceOf[S with EfficientSplit]
+ }
+
+ @SerialVersionUID(3L)
+ final class ofByte(val unsafeArray: Array[Byte]) extends ArraySeq[Byte] {
+ // Type erases to `ManifestFactory.ByteManifest`, but can't annotate that because it's not accessible
+ protected def elemTag: ClassTag.Byte.type = ClassTag.Byte
+ def length: Int = unsafeArray.length
+ @throws[ArrayIndexOutOfBoundsException]
+ def apply(i: Int): Byte = unsafeArray(i)
+ override def hashCode = MurmurHash3.arraySeqHash(unsafeArray)
+ override def equals(that: Any) = that match {
+ case that: ofByte => Arrays.equals(unsafeArray, that.unsafeArray)
+ case _ => super.equals(that)
+ }
+ override def sorted[B >: Byte](implicit ord: Ordering[B]): ArraySeq[Byte] =
+ if(length <= 1) this
+ else if(ord eq Ordering.Byte) {
+ val a = unsafeArray.clone()
+ Arrays.sort(a)
+ new ArraySeq.ofByte(a)
+ } else super.sorted[B]
+ override def iterator: Iterator[Byte] = new ArrayOps.ArrayIterator[Byte](unsafeArray)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Byte, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParIntStepper(new WidenedByteArrayStepper(unsafeArray, 0, unsafeArray.length))
+ else new WidenedByteArrayStepper(unsafeArray, 0, unsafeArray.length)
+ ).asInstanceOf[S with EfficientSplit]
+ override def updated[B >: Byte](index: Int, elem: B): ArraySeq[B] =
+ elem match {
+ case b: Byte => new ArraySeq.ofByte(unsafeArray.updated(index, b))
+ case _ => super.updated(index, elem)
+ }
+ override def appended[B >: Byte](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Byte => new ArraySeq.ofByte(unsafeArray.appended(b))
+ case _ => super.appended(elem)
+ }
+ override def prepended[B >: Byte](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Byte => new ArraySeq.ofByte(unsafeArray.prepended(b))
+ case _ => super.prepended(elem)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ final class ofShort(val unsafeArray: Array[Short]) extends ArraySeq[Short] {
+ // Type erases to `ManifestFactory.ShortManifest`, but can't annotate that because it's not accessible
+ protected def elemTag: ClassTag.Short.type = ClassTag.Short
+ def length: Int = unsafeArray.length
+ @throws[ArrayIndexOutOfBoundsException]
+ def apply(i: Int): Short = unsafeArray(i)
+ override def hashCode = MurmurHash3.arraySeqHash(unsafeArray)
+ override def equals(that: Any) = that match {
+ case that: ofShort => Arrays.equals(unsafeArray, that.unsafeArray)
+ case _ => super.equals(that)
+ }
+ override def sorted[B >: Short](implicit ord: Ordering[B]): ArraySeq[Short] =
+ if(length <= 1) this
+ else if(ord eq Ordering.Short) {
+ val a = unsafeArray.clone()
+ Arrays.sort(a)
+ new ArraySeq.ofShort(a)
+ } else super.sorted[B]
+ override def iterator: Iterator[Short] = new ArrayOps.ArrayIterator[Short](unsafeArray)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Short, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParIntStepper(new WidenedShortArrayStepper(unsafeArray, 0, unsafeArray.length))
+ else new WidenedShortArrayStepper(unsafeArray, 0, unsafeArray.length)
+ ).asInstanceOf[S with EfficientSplit]
+ override def updated[B >: Short](index: Int, elem: B): ArraySeq[B] =
+ elem match {
+ case b: Short => new ArraySeq.ofShort(unsafeArray.updated(index, b))
+ case _ => super.updated(index, elem)
+ }
+ override def appended[B >: Short](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Short => new ArraySeq.ofShort(unsafeArray.appended(b))
+ case _ => super.appended(elem)
+ }
+ override def prepended[B >: Short](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Short => new ArraySeq.ofShort(unsafeArray.prepended(b))
+ case _ => super.prepended(elem)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ final class ofChar(val unsafeArray: Array[Char]) extends ArraySeq[Char] {
+ // Type erases to `ManifestFactory.CharManifest`, but can't annotate that because it's not accessible
+ protected def elemTag: ClassTag.Char.type = ClassTag.Char
+ def length: Int = unsafeArray.length
+ @throws[ArrayIndexOutOfBoundsException]
+ def apply(i: Int): Char = unsafeArray(i)
+ override def hashCode = MurmurHash3.arraySeqHash(unsafeArray)
+ override def equals(that: Any) = that match {
+ case that: ofChar => Arrays.equals(unsafeArray, that.unsafeArray)
+ case _ => super.equals(that)
+ }
+ override def sorted[B >: Char](implicit ord: Ordering[B]): ArraySeq[Char] =
+ if(length <= 1) this
+ else if(ord eq Ordering.Char) {
+ val a = unsafeArray.clone()
+ Arrays.sort(a)
+ new ArraySeq.ofChar(a)
+ } else super.sorted[B]
+ override def iterator: Iterator[Char] = new ArrayOps.ArrayIterator[Char](unsafeArray)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Char, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParIntStepper(new WidenedCharArrayStepper(unsafeArray, 0, unsafeArray.length))
+ else new WidenedCharArrayStepper(unsafeArray, 0, unsafeArray.length)
+ ).asInstanceOf[S with EfficientSplit]
+ override def updated[B >: Char](index: Int, elem: B): ArraySeq[B] =
+ elem match {
+ case b: Char => new ArraySeq.ofChar(unsafeArray.updated(index, b))
+ case _ => super.updated(index, elem)
+ }
+ override def appended[B >: Char](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Char => new ArraySeq.ofChar(unsafeArray.appended(b))
+ case _ => super.appended(elem)
+ }
+ override def prepended[B >: Char](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Char => new ArraySeq.ofChar(unsafeArray.prepended(b))
+ case _ => super.prepended(elem)
+ }
+
+ override def addString(sb: StringBuilder, start: String, sep: String, end: String): sb.type =
+ (new MutableArraySeq.ofChar(unsafeArray)).addString(sb, start, sep, end)
+ }
+
+ @SerialVersionUID(3L)
+ final class ofInt(val unsafeArray: Array[Int]) extends ArraySeq[Int] {
+ // Type erases to `ManifestFactory.IntManifest`, but can't annotate that because it's not accessible
+ protected def elemTag: ClassTag.Int.type = ClassTag.Int
+ def length: Int = unsafeArray.length
+ @throws[ArrayIndexOutOfBoundsException]
+ def apply(i: Int): Int = unsafeArray(i)
+ override def hashCode = MurmurHash3.arraySeqHash(unsafeArray)
+ override def equals(that: Any) = that match {
+ case that: ofInt => Arrays.equals(unsafeArray, that.unsafeArray)
+ case _ => super.equals(that)
+ }
+ override def sorted[B >: Int](implicit ord: Ordering[B]): ArraySeq[Int] =
+ if(length <= 1) this
+ else if(ord eq Ordering.Int) {
+ val a = unsafeArray.clone()
+ Arrays.sort(a)
+ new ArraySeq.ofInt(a)
+ } else super.sorted[B]
+ override def iterator: Iterator[Int] = new ArrayOps.ArrayIterator[Int](unsafeArray)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Int, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParIntStepper(new IntArrayStepper(unsafeArray, 0, unsafeArray.length))
+ else new IntArrayStepper(unsafeArray, 0, unsafeArray.length)
+ ).asInstanceOf[S with EfficientSplit]
+ override def updated[B >: Int](index: Int, elem: B): ArraySeq[B] =
+ elem match {
+ case b: Int => new ArraySeq.ofInt(unsafeArray.updated(index, b))
+ case _ => super.updated(index, elem)
+ }
+ override def appended[B >: Int](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Int => new ArraySeq.ofInt(unsafeArray.appended(b))
+ case _ => super.appended(elem)
+ }
+ override def prepended[B >: Int](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Int => new ArraySeq.ofInt(unsafeArray.prepended(b))
+ case _ => super.prepended(elem)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ final class ofLong(val unsafeArray: Array[Long]) extends ArraySeq[Long] {
+ // Type erases to `ManifestFactory.LongManifest`, but can't annotate that because it's not accessible
+ protected def elemTag: ClassTag.Long.type = ClassTag.Long
+ def length: Int = unsafeArray.length
+ @throws[ArrayIndexOutOfBoundsException]
+ def apply(i: Int): Long = unsafeArray(i)
+ override def hashCode = MurmurHash3.arraySeqHash(unsafeArray)
+ override def equals(that: Any) = that match {
+ case that: ofLong => Arrays.equals(unsafeArray, that.unsafeArray)
+ case _ => super.equals(that)
+ }
+ override def sorted[B >: Long](implicit ord: Ordering[B]): ArraySeq[Long] =
+ if(length <= 1) this
+ else if(ord eq Ordering.Long) {
+ val a = unsafeArray.clone()
+ Arrays.sort(a)
+ new ArraySeq.ofLong(a)
+ } else super.sorted[B]
+ override def iterator: Iterator[Long] = new ArrayOps.ArrayIterator[Long](unsafeArray)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Long, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParLongStepper(new LongArrayStepper(unsafeArray, 0, unsafeArray.length))
+ else new LongArrayStepper(unsafeArray, 0, unsafeArray.length)
+ ).asInstanceOf[S with EfficientSplit]
+ override def updated[B >: Long](index: Int, elem: B): ArraySeq[B] =
+ elem match {
+ case b: Long => new ArraySeq.ofLong(unsafeArray.updated(index, b))
+ case _ => super.updated(index, elem)
+ }
+ override def appended[B >: Long](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Long => new ArraySeq.ofLong(unsafeArray.appended(b))
+ case _ => super.appended(elem)
+ }
+ override def prepended[B >: Long](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Long => new ArraySeq.ofLong(unsafeArray.prepended(b))
+ case _ => super.prepended(elem)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ final class ofFloat(val unsafeArray: Array[Float]) extends ArraySeq[Float] {
+ // Type erases to `ManifestFactory.FloatManifest`, but can't annotate that because it's not accessible
+ protected def elemTag: ClassTag.Float.type = ClassTag.Float
+ def length: Int = unsafeArray.length
+ @throws[ArrayIndexOutOfBoundsException]
+ def apply(i: Int): Float = unsafeArray(i)
+ override def hashCode = MurmurHash3.arraySeqHash(unsafeArray)
+ override def equals(that: Any) = that match {
+ case that: ofFloat => Arrays.equals(unsafeArray, that.unsafeArray)
+ case _ => super.equals(that)
+ }
+ override def iterator: Iterator[Float] = new ArrayOps.ArrayIterator[Float](unsafeArray)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Float, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParDoubleStepper(new WidenedFloatArrayStepper(unsafeArray, 0, unsafeArray.length))
+ else new WidenedFloatArrayStepper(unsafeArray, 0, unsafeArray.length)
+ ).asInstanceOf[S with EfficientSplit]
+ override def updated[B >: Float](index: Int, elem: B): ArraySeq[B] =
+ elem match {
+ case b: Float => new ArraySeq.ofFloat(unsafeArray.updated(index, b))
+ case _ => super.updated(index, elem)
+ }
+ override def appended[B >: Float](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Float => new ArraySeq.ofFloat(unsafeArray.appended(b))
+ case _ => super.appended(elem)
+ }
+ override def prepended[B >: Float](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Float => new ArraySeq.ofFloat(unsafeArray.prepended(b))
+ case _ => super.prepended(elem)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ final class ofDouble(val unsafeArray: Array[Double]) extends ArraySeq[Double] {
+ // Type erases to `ManifestFactory.DoubleManifest`, but can't annotate that because it's not accessible
+ protected def elemTag: ClassTag.Double.type = ClassTag.Double
+ def length: Int = unsafeArray.length
+ @throws[ArrayIndexOutOfBoundsException]
+ def apply(i: Int): Double = unsafeArray(i)
+ override def hashCode = MurmurHash3.arraySeqHash(unsafeArray)
+ override def equals(that: Any) = that match {
+ case that: ofDouble => Arrays.equals(unsafeArray, that.unsafeArray)
+ case _ => super.equals(that)
+ }
+ override def iterator: Iterator[Double] = new ArrayOps.ArrayIterator[Double](unsafeArray)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Double, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParDoubleStepper(new DoubleArrayStepper(unsafeArray, 0, unsafeArray.length))
+ else new DoubleArrayStepper(unsafeArray, 0, unsafeArray.length)
+ ).asInstanceOf[S with EfficientSplit]
+ override def updated[B >: Double](index: Int, elem: B): ArraySeq[B] =
+ elem match {
+ case b: Double => new ArraySeq.ofDouble(unsafeArray.updated(index, b))
+ case _ => super.updated(index, elem)
+ }
+ override def appended[B >: Double](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Double => new ArraySeq.ofDouble(unsafeArray.appended(b))
+ case _ => super.appended(elem)
+ }
+ override def prepended[B >: Double](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Double => new ArraySeq.ofDouble(unsafeArray.prepended(b))
+ case _ => super.prepended(elem)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ final class ofBoolean(val unsafeArray: Array[Boolean]) extends ArraySeq[Boolean] {
+ // Type erases to `ManifestFactory.BooleanManifest`, but can't annotate that because it's not accessible
+ protected def elemTag: ClassTag.Boolean.type = ClassTag.Boolean
+ def length: Int = unsafeArray.length
+ @throws[ArrayIndexOutOfBoundsException]
+ def apply(i: Int): Boolean = unsafeArray(i)
+ override def hashCode = MurmurHash3.arraySeqHash(unsafeArray)
+ override def equals(that: Any) = that match {
+ case that: ofBoolean => Arrays.equals(unsafeArray, that.unsafeArray)
+ case _ => super.equals(that)
+ }
+ override def sorted[B >: Boolean](implicit ord: Ordering[B]): ArraySeq[Boolean] =
+ if(length <= 1) this
+ else if(ord eq Ordering.Boolean) {
+ val a = unsafeArray.clone()
+ Sorting.stableSort(a)
+ new ArraySeq.ofBoolean(a)
+ } else super.sorted[B]
+ override def iterator: Iterator[Boolean] = new ArrayOps.ArrayIterator[Boolean](unsafeArray)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Boolean, S]): S with EfficientSplit =
+ new BoxedBooleanArrayStepper(unsafeArray, 0, unsafeArray.length).asInstanceOf[S with EfficientSplit]
+ override def updated[B >: Boolean](index: Int, elem: B): ArraySeq[B] =
+ elem match {
+ case b: Boolean => new ArraySeq.ofBoolean(unsafeArray.updated(index, b))
+ case _ => super.updated(index, elem)
+ }
+ override def appended[B >: Boolean](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Boolean => new ArraySeq.ofBoolean(unsafeArray.appended(b))
+ case _ => super.appended(elem)
+ }
+ override def prepended[B >: Boolean](elem: B): ArraySeq[B] =
+ elem match {
+ case b: Boolean => new ArraySeq.ofBoolean(unsafeArray.prepended(b))
+ case _ => super.prepended(elem)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ final class ofUnit(val unsafeArray: Array[Unit]) extends ArraySeq[Unit] {
+ // Type erases to `ManifestFactory.UnitManifest`, but can't annotate that because it's not accessible
+ protected def elemTag: ClassTag.Unit.type = ClassTag.Unit
+ def length: Int = unsafeArray.length
+ @throws[ArrayIndexOutOfBoundsException]
+ def apply(i: Int): Unit = unsafeArray(i)
+ override def hashCode = MurmurHash3.arraySeqHash(unsafeArray)
+ override def equals(that: Any) = that match {
+ case that: ofUnit => unsafeArray.length == that.unsafeArray.length
+ case _ => super.equals(that)
+ }
+ override def iterator: Iterator[Unit] = new ArrayOps.ArrayIterator[Unit](unsafeArray)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Unit, S]): S with EfficientSplit =
+ new ObjectArrayStepper[AnyRef](unsafeArray.asInstanceOf[Array[AnyRef]], 0, unsafeArray.length).asInstanceOf[S with EfficientSplit]
+ }
+}
diff --git a/library/src/scala/collection/immutable/BitSet.scala b/library/src/scala/collection/immutable/BitSet.scala
new file mode 100644
index 000000000000..a9b5837ff566
--- /dev/null
+++ b/library/src/scala/collection/immutable/BitSet.scala
@@ -0,0 +1,375 @@
+/*
+ * 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 collection
+package immutable
+
+import BitSetOps.{LogWL, updateArray}
+import mutable.Builder
+import scala.annotation.{implicitNotFound, nowarn}
+
+/** A class for immutable bitsets.
+ * $bitsetinfo
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-immutable-collection-classes.html#immutable-bitsets "Scala's Collection Library overview"]]
+ * section on `Immutable BitSets` for more information.
+ *
+ * @define Coll `immutable.BitSet`
+ * @define coll immutable bitset
+ */
+sealed abstract class BitSet
+ extends AbstractSet[Int]
+ with SortedSet[Int]
+ with SortedSetOps[Int, SortedSet, BitSet]
+ with StrictOptimizedSortedSetOps[Int, SortedSet, BitSet]
+ with collection.BitSet
+ with collection.BitSetOps[BitSet]
+ with Serializable {
+
+ override def unsorted: Set[Int] = this
+
+ override protected def fromSpecific(coll: IterableOnce[Int]): BitSet = bitSetFactory.fromSpecific(coll)
+ override protected def newSpecificBuilder: Builder[Int, BitSet] = bitSetFactory.newBuilder
+ override def empty: BitSet = bitSetFactory.empty
+
+ def bitSetFactory: BitSet.type = BitSet
+
+ protected[collection] def fromBitMaskNoCopy(elems: Array[Long]): BitSet = BitSet.fromBitMaskNoCopy(elems)
+
+ def incl(elem: Int): BitSet = {
+ require(elem >= 0, "bitset element must be >= 0")
+ if (contains(elem)) this
+ else {
+ val idx = elem >> LogWL
+ updateWord(idx, word(idx) | (1L << elem))
+ }
+ }
+
+ def excl(elem: Int): BitSet = {
+ require(elem >= 0, "bitset element must be >= 0")
+ if (contains(elem)) {
+ val idx = elem >> LogWL
+ updateWord(idx, word(idx) & ~(1L << elem))
+ } else this
+ }
+
+ /** Update word at index `idx`; enlarge set if `idx` outside range of set.
+ */
+ protected def updateWord(idx: Int, w: Long): BitSet
+
+ override def map(f: Int => Int): BitSet = strictOptimizedMap(newSpecificBuilder, f)
+ override def map[B](f: Int => B)(implicit @implicitNotFound(collection.BitSet.ordMsg) ev: Ordering[B]): SortedSet[B] =
+ super[StrictOptimizedSortedSetOps].map(f)
+
+ override def flatMap(f: Int => IterableOnce[Int]): BitSet = strictOptimizedFlatMap(newSpecificBuilder, f)
+ override def flatMap[B](f: Int => IterableOnce[B])(implicit @implicitNotFound(collection.BitSet.ordMsg) ev: Ordering[B]): SortedSet[B] =
+ super[StrictOptimizedSortedSetOps].flatMap(f)
+
+ override def collect(pf: PartialFunction[Int, Int]): BitSet = strictOptimizedCollect(newSpecificBuilder, pf)
+ override def collect[B](pf: scala.PartialFunction[Int, B])(implicit @implicitNotFound(collection.BitSet.ordMsg) ev: Ordering[B]): SortedSet[B] =
+ super[StrictOptimizedSortedSetOps].collect(pf)
+
+ // necessary for disambiguation
+ override def zip[B](that: scala.IterableOnce[B])(implicit @implicitNotFound(collection.BitSet.zipOrdMsg) ev: Ordering[(Int, B)]): SortedSet[(Int, B)] =
+ super.zip(that)
+
+ protected[this] def writeReplace(): AnyRef = new BitSet.SerializationProxy(this)
+}
+
+/**
+ * $factoryInfo
+ * @define Coll `immutable.BitSet`
+ * @define coll immutable bitset
+ */
+@nowarn("cat=deprecation&msg=Implementation classes of BitSet should not be accessed directly")
+@SerialVersionUID(3L)
+object BitSet extends SpecificIterableFactory[Int, BitSet] {
+
+ def fromSpecific(it: scala.collection.IterableOnce[Int]): BitSet =
+ it match {
+ case bs: BitSet => bs
+ case _ => (newBuilder ++= it).result()
+ }
+
+ final val empty: BitSet = new BitSet1(0L)
+
+ def newBuilder: Builder[Int, BitSet] =
+ mutable.BitSet.newBuilder.mapResult(bs => fromBitMaskNoCopy(bs.elems))
+
+ private def createSmall(a: Long, b: Long): BitSet = if (b == 0L) new BitSet1(a) else new BitSet2(a, b)
+
+ /** A bitset containing all the bits in an array */
+ def fromBitMask(elems: Array[Long]): BitSet = {
+ val len = elems.length
+ if (len == 0) empty
+ else if (len == 1) new BitSet1(elems(0))
+ else if (len == 2) createSmall(elems(0), elems(1))
+ else {
+ val a = java.util.Arrays.copyOf(elems, len)
+ new BitSetN(a)
+ }
+ }
+
+ /** A bitset containing all the bits in an array, wrapping the existing
+ * array without copying.
+ */
+ def fromBitMaskNoCopy(elems: Array[Long]): BitSet = {
+ val len = elems.length
+ if (len == 0) empty
+ else if (len == 1) new BitSet1(elems(0))
+ else if (len == 2) createSmall(elems(0), elems(1))
+ else new BitSetN(elems)
+ }
+
+ @deprecated("Implementation classes of BitSet should not be accessed directly", "2.13.0")
+ class BitSet1(val elems: Long) extends BitSet {
+ protected[collection] def nwords = 1
+ protected[collection] def word(idx: Int) = if (idx == 0) elems else 0L
+ protected[collection] def updateWord(idx: Int, w: Long): BitSet =
+ if (idx == 0) new BitSet1(w)
+ else if (idx == 1) createSmall(elems, w)
+ else this.fromBitMaskNoCopy(updateArray(Array(elems), idx, w))
+
+
+ override def diff(other: collection.Set[Int]): BitSet = other match {
+ case bs: collection.BitSet => bs.nwords match {
+ case 0 => this
+ case _ =>
+ val newElems = elems & ~bs.word(0)
+ if (newElems == 0L) this.empty else new BitSet1(newElems)
+ }
+ case _ => super.diff(other)
+ }
+
+ override def filterImpl(pred: Int => Boolean, isFlipped: Boolean): BitSet = {
+ val _elems = BitSetOps.computeWordForFilter(pred, isFlipped, elems, 0)
+ if (_elems == 0L) this.empty else new BitSet1(_elems)
+ }
+ }
+
+ @deprecated("Implementation classes of BitSet should not be accessed directly", "2.13.0")
+ class BitSet2(val elems0: Long, val elems1: Long) extends BitSet {
+ protected[collection] def nwords = 2
+ protected[collection] def word(idx: Int) = if (idx == 0) elems0 else if (idx == 1) elems1 else 0L
+ protected[collection] def updateWord(idx: Int, w: Long): BitSet =
+ if (idx == 0) new BitSet2(w, elems1)
+ else if (idx == 1) createSmall(elems0, w)
+ else this.fromBitMaskNoCopy(updateArray(Array(elems0, elems1), idx, w))
+
+
+ override def diff(other: collection.Set[Int]): BitSet = other match {
+ case bs: collection.BitSet => bs.nwords match {
+ case 0 => this
+ case 1 =>
+ new BitSet2(elems0 & ~bs.word(0), elems1)
+ case _ =>
+ val _elems0 = elems0 & ~bs.word(0)
+ val _elems1 = elems1 & ~bs.word(1)
+
+ if (_elems1 == 0L) {
+ if (_elems0 == 0L) {
+ this.empty
+ } else {
+ new BitSet1(_elems0)
+ }
+ } else {
+ new BitSet2(_elems0, _elems1)
+ }
+ }
+ case _ => super.diff(other)
+ }
+
+ override def filterImpl(pred: Int => Boolean, isFlipped: Boolean): BitSet = {
+ val _elems0 = BitSetOps.computeWordForFilter(pred, isFlipped, elems0, 0)
+ val _elems1 = BitSetOps.computeWordForFilter(pred, isFlipped, elems1, 1)
+
+ if (_elems1 == 0L) {
+ if (_elems0 == 0L) {
+ this.empty
+ }
+ else new BitSet1(_elems0)
+ }
+ else new BitSet2(_elems0, _elems1)
+ }
+ }
+
+ @deprecated("Implementation classes of BitSet should not be accessed directly", "2.13.0")
+ class BitSetN(val elems: Array[Long]) extends BitSet {
+ protected[collection] def nwords = elems.length
+
+ protected[collection] def word(idx: Int) = if (idx < nwords) elems(idx) else 0L
+
+ protected[collection] def updateWord(idx: Int, w: Long): BitSet = this.fromBitMaskNoCopy(updateArray(elems, idx, w))
+
+ override def diff(that: collection.Set[Int]): BitSet = that match {
+ case bs: collection.BitSet =>
+ /*
+ * Algorithm:
+ *
+ * We iterate, word-by-word, backwards from the shortest of the two bitsets (this, or bs) i.e. the one with
+ * the fewer words. Two extra concerns for optimization are described below.
+ *
+ * Array Shrinking:
+ * If `this` is not longer than `bs`, then since we must iterate through the full array of words,
+ * we can track the new highest index word which is non-zero, at little additional cost. At the end, the new
+ * Array[Long] allocated for the returned BitSet will only be of size `maxNonZeroIndex + 1`
+ *
+ * Tracking Changes:
+ * If the two sets are disjoint, then we can return `this`. Therefor, until at least one change is detected,
+ * we check each word for if it has changed from its corresponding word in `this`. Once a single change is
+ * detected, we stop checking because the cost of the new Array must be paid anyways.
+ */
+
+ val bsnwords = bs.nwords
+ val thisnwords = nwords
+ if (bsnwords >= thisnwords) {
+ // here, we may have opportunity to shrink the size of the array
+ // so, track the highest index which is non-zero. That ( + 1 ) will be our new array length
+ var i = thisnwords - 1
+ var currentWord = 0L
+ // if there are never any changes, we can return `this` at the end
+ var anyChanges = false
+ while (i >= 0 && currentWord == 0L) {
+ val oldWord = word(i)
+ currentWord = oldWord & ~bs.word(i)
+ anyChanges ||= currentWord != oldWord
+ i -= 1
+ }
+ i match {
+ case -1 =>
+ if (anyChanges) {
+ if (currentWord == 0) {
+ this.empty
+ } else {
+ new BitSet1(currentWord)
+ }
+ } else {
+ this
+ }
+ case 0 =>
+ val oldFirstWord = word(0)
+ val firstWord = oldFirstWord & ~bs.word(0)
+ anyChanges ||= firstWord != oldFirstWord
+ if (anyChanges) {
+ new BitSet2(firstWord, currentWord)
+ } else {
+ this
+ }
+ case _ =>
+ val minimumNonZeroIndex: Int = i + 1
+ while (!anyChanges && i >= 0) {
+ val oldWord = word(i)
+ currentWord = oldWord & ~bs.word(i)
+ anyChanges ||= currentWord != oldWord
+ i -= 1
+ }
+ if (anyChanges) {
+ val newArray = elems.take(minimumNonZeroIndex + 1)
+ newArray(i + 1) = currentWord
+ while (i >= 0) {
+ newArray(i) = word(i) & ~bs.word(i)
+ i -= 1
+ }
+ new BitSetN(newArray)
+ } else {
+ this
+ }
+ }
+ } else {
+ var i = bsnwords - 1
+ var anyChanges = false
+ var currentWord = 0L
+ while (i >= 0 && !anyChanges) {
+ val oldWord = word(i)
+ currentWord = oldWord & ~bs.word(i)
+ anyChanges ||= currentWord != oldWord
+ i -= 1
+ }
+ if (anyChanges) {
+ val newElems = elems.clone()
+ newElems(i + 1) = currentWord
+ while (i >= 0) {
+ newElems(i) = word(i) & ~bs.word(i)
+ i -= 1
+ }
+ this.fromBitMaskNoCopy(newElems)
+ } else {
+ this
+ }
+ }
+ case _ => super.diff(that)
+ }
+
+
+ override def filterImpl(pred: Int => Boolean, isFlipped: Boolean): BitSet = {
+ // here, we may have opportunity to shrink the size of the array
+ // so, track the highest index which is non-zero. That ( + 1 ) will be our new array length
+ var i = nwords - 1
+ var currentWord = 0L
+ // if there are never any changes, we can return `this` at the end
+ var anyChanges = false
+ while (i >= 0 && currentWord == 0L) {
+ val oldWord = word(i)
+ currentWord = BitSetOps.computeWordForFilter(pred, isFlipped, oldWord, i)
+ anyChanges ||= currentWord != oldWord
+ i -= 1
+ }
+ i match {
+ case -1 =>
+ if (anyChanges) {
+ if (currentWord == 0) {
+ this.empty
+ } else {
+ new BitSet1(currentWord)
+ }
+ } else {
+ this
+ }
+ case 0 =>
+ val oldFirstWord = word(0)
+ val firstWord = BitSetOps.computeWordForFilter(pred, isFlipped, oldFirstWord, 0)
+ anyChanges ||= firstWord != oldFirstWord
+ if (anyChanges) {
+ new BitSet2(firstWord, currentWord)
+ } else {
+ this
+ }
+ case _ =>
+ val minimumNonZeroIndex: Int = i + 1
+ while (!anyChanges && i >= 0) {
+ val oldWord = word(i)
+ currentWord = BitSetOps.computeWordForFilter(pred, isFlipped, oldWord, i)
+ anyChanges ||= currentWord != oldWord
+ i -= 1
+ }
+ if (anyChanges) {
+ val newArray = elems.take(minimumNonZeroIndex + 1)
+ newArray(i + 1) = currentWord
+ while (i >= 0) {
+ newArray(i) = BitSetOps.computeWordForFilter(pred, isFlipped, word(i), i)
+ i -= 1
+ }
+ new BitSetN(newArray)
+ } else {
+ this
+ }
+ }
+ }
+
+ override def toBitMask: Array[Long] = elems.clone()
+ }
+
+ @SerialVersionUID(3L)
+ private final class SerializationProxy(coll: BitSet) extends scala.collection.BitSet.SerializationProxy(coll) {
+ protected[this] def readResolve(): Any = BitSet.fromBitMaskNoCopy(elems)
+ }
+}
diff --git a/library/src/scala/collection/immutable/ChampCommon.scala b/library/src/scala/collection/immutable/ChampCommon.scala
new file mode 100644
index 000000000000..7b3e3949a126
--- /dev/null
+++ b/library/src/scala/collection/immutable/ChampCommon.scala
@@ -0,0 +1,252 @@
+/*
+ * 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.immutable
+
+import scala.collection.AbstractIterator
+import java.lang.Integer.bitCount
+import java.lang.Math.ceil
+import java.lang.System.arraycopy
+
+private[collection] object Node {
+ final val HashCodeLength = 32
+
+ final val BitPartitionSize = 5
+
+ final val BitPartitionMask = (1 << BitPartitionSize) - 1
+
+ final val MaxDepth = ceil(HashCodeLength.toDouble / BitPartitionSize).toInt
+
+ final val BranchingFactor = 1 << BitPartitionSize
+
+ final def maskFrom(hash: Int, shift: Int): Int = (hash >>> shift) & BitPartitionMask
+
+ final def bitposFrom(mask: Int): Int = 1 << mask
+
+ final def indexFrom(bitmap: Int, bitpos: Int): Int = bitCount(bitmap & (bitpos - 1))
+
+ final def indexFrom(bitmap: Int, mask: Int, bitpos: Int): Int = if (bitmap == -1) mask else indexFrom(bitmap, bitpos)
+
+}
+
+private[collection] abstract class Node[T <: Node[T]] {
+
+ def hasNodes: Boolean
+
+ def nodeArity: Int
+
+ def getNode(index: Int): T
+
+ def hasPayload: Boolean
+
+ def payloadArity: Int
+
+ def getPayload(index: Int): Any
+
+ def getHash(index: Int): Int
+
+ def cachedJavaKeySetHashCode: Int
+
+ private final def arrayIndexOutOfBounds(as: Array[_], ix:Int): ArrayIndexOutOfBoundsException =
+ new ArrayIndexOutOfBoundsException(s"$ix is out of bounds (min 0, max ${as.length-1}")
+
+ protected final def removeElement(as: Array[Int], ix: Int): Array[Int] = {
+ if (ix < 0) throw arrayIndexOutOfBounds(as, ix)
+ if (ix > as.length - 1) throw arrayIndexOutOfBounds(as, ix)
+ val result = new Array[Int](as.length - 1)
+ arraycopy(as, 0, result, 0, ix)
+ arraycopy(as, ix + 1, result, ix, as.length - ix - 1)
+ result
+ }
+
+ protected final def removeAnyElement(as: Array[Any], ix: Int): Array[Any] = {
+ if (ix < 0) throw arrayIndexOutOfBounds(as, ix)
+ if (ix > as.length - 1) throw arrayIndexOutOfBounds(as, ix)
+ val result = new Array[Any](as.length - 1)
+ arraycopy(as, 0, result, 0, ix)
+ arraycopy(as, ix + 1, result, ix, as.length - ix - 1)
+ result
+ }
+
+ protected final def insertElement(as: Array[Int], ix: Int, elem: Int): Array[Int] = {
+ if (ix < 0) throw arrayIndexOutOfBounds(as, ix)
+ if (ix > as.length) throw arrayIndexOutOfBounds(as, ix)
+ val result = new Array[Int](as.length + 1)
+ arraycopy(as, 0, result, 0, ix)
+ result(ix) = elem
+ arraycopy(as, ix, result, ix + 1, as.length - ix)
+ result
+ }
+ protected final def insertAnyElement(as: Array[Any], ix: Int, elem: Int): Array[Any] = {
+ if (ix < 0) throw arrayIndexOutOfBounds(as, ix)
+ if (ix > as.length) throw arrayIndexOutOfBounds(as, ix)
+ val result = new Array[Any](as.length + 1)
+ arraycopy(as, 0, result, 0, ix)
+ result(ix) = elem
+ arraycopy(as, ix, result, ix + 1, as.length - ix)
+ result
+ }
+}
+
+/**
+ * Base class for fixed-stack iterators that traverse a hash-trie. The iterator performs a
+ * depth-first pre-order traversal, which yields first all payload elements of the current
+ * node before traversing sub-nodes (left to right).
+ *
+ * @tparam T the trie node type we are iterating over
+ */
+private[immutable] abstract class ChampBaseIterator[A, T <: Node[T]] extends AbstractIterator[A] {
+
+ import Node.MaxDepth
+
+ // Note--this code is duplicated to a large extent both in
+ // ChampBaseReverseIterator and in convert.impl.ChampStepperBase.
+ // If you change this code, check those also in case they also
+ // need to be modified.
+
+ protected var currentValueCursor: Int = 0
+ protected var currentValueLength: Int = 0
+ protected var currentValueNode: T = _
+
+ private[this] var currentStackLevel: Int = -1
+ private[this] var nodeCursorsAndLengths: Array[Int] = _
+ private[this] var nodes: Array[T] = _
+ private def initNodes(): Unit = {
+ if (nodeCursorsAndLengths eq null) {
+ nodeCursorsAndLengths = new Array[Int](MaxDepth * 2)
+ nodes = new Array[Node[T]](MaxDepth).asInstanceOf[Array[T]]
+ }
+ }
+
+ def this(rootNode: T) = {
+ this()
+ if (rootNode.hasNodes) pushNode(rootNode)
+ if (rootNode.hasPayload) setupPayloadNode(rootNode)
+ }
+
+ private final def setupPayloadNode(node: T): Unit = {
+ currentValueNode = node
+ currentValueCursor = 0
+ currentValueLength = node.payloadArity
+ }
+
+ private final def pushNode(node: T): Unit = {
+ initNodes()
+ currentStackLevel = currentStackLevel + 1
+
+ val cursorIndex = currentStackLevel * 2
+ val lengthIndex = currentStackLevel * 2 + 1
+
+ nodes(currentStackLevel) = node
+ nodeCursorsAndLengths(cursorIndex) = 0
+ nodeCursorsAndLengths(lengthIndex) = node.nodeArity
+ }
+
+ private final def popNode(): Unit = {
+ currentStackLevel = currentStackLevel - 1
+ }
+
+ /**
+ * Searches for next node that contains payload values,
+ * and pushes encountered sub-nodes on a stack for depth-first traversal.
+ */
+ private final def searchNextValueNode(): Boolean = {
+ while (currentStackLevel >= 0) {
+ val cursorIndex = currentStackLevel * 2
+ val lengthIndex = currentStackLevel * 2 + 1
+
+ val nodeCursor = nodeCursorsAndLengths(cursorIndex)
+ val nodeLength = nodeCursorsAndLengths(lengthIndex)
+
+ if (nodeCursor < nodeLength) {
+ nodeCursorsAndLengths(cursorIndex) += 1
+
+ val nextNode = nodes(currentStackLevel).getNode(nodeCursor)
+
+ if (nextNode.hasNodes) { pushNode(nextNode) }
+ if (nextNode.hasPayload) { setupPayloadNode(nextNode) ; return true }
+ } else {
+ popNode()
+ }
+ }
+
+ return false
+ }
+
+ final def hasNext = (currentValueCursor < currentValueLength) || searchNextValueNode()
+
+}
+
+/**
+ * Base class for fixed-stack iterators that traverse a hash-trie in reverse order. The base
+ * iterator performs a depth-first post-order traversal, traversing sub-nodes (right to left).
+ *
+ * @tparam T the trie node type we are iterating over
+ */
+private[immutable] abstract class ChampBaseReverseIterator[A, T <: Node[T]] extends AbstractIterator[A] {
+
+ import Node.MaxDepth
+
+ protected var currentValueCursor: Int = -1
+ protected var currentValueNode: T = _
+
+ private[this] var currentStackLevel: Int = -1
+ private[this] val nodeIndex: Array[Int] = new Array[Int](MaxDepth + 1)
+ private[this] val nodeStack: Array[T] = new Array[Node[T]](MaxDepth + 1).asInstanceOf[Array[T]]
+
+ def this(rootNode: T) = {
+ this()
+ pushNode(rootNode)
+ searchNextValueNode()
+ }
+
+ private final def setupPayloadNode(node: T): Unit = {
+ currentValueNode = node
+ currentValueCursor = node.payloadArity - 1
+ }
+
+ private final def pushNode(node: T): Unit = {
+ currentStackLevel = currentStackLevel + 1
+
+ nodeStack(currentStackLevel) = node
+ nodeIndex(currentStackLevel) = node.nodeArity - 1
+ }
+
+ private final def popNode(): Unit = {
+ currentStackLevel = currentStackLevel - 1
+ }
+
+ /**
+ * Searches for rightmost node that contains payload values,
+ * and pushes encountered sub-nodes on a stack for depth-first traversal.
+ */
+ private final def searchNextValueNode(): Boolean = {
+ while (currentStackLevel >= 0) {
+ val nodeCursor = nodeIndex(currentStackLevel) ; nodeIndex(currentStackLevel) = nodeCursor - 1
+
+ if (nodeCursor >= 0) {
+ val nextNode = nodeStack(currentStackLevel).getNode(nodeCursor)
+ pushNode(nextNode)
+ } else {
+ val currNode = nodeStack(currentStackLevel)
+ popNode()
+
+ if (currNode.hasPayload) { setupPayloadNode(currNode) ; return true }
+ }
+ }
+
+ return false
+ }
+
+ final def hasNext = (currentValueCursor >= 0) || searchNextValueNode()
+
+}
diff --git a/library/src/scala/collection/immutable/HashMap.scala b/library/src/scala/collection/immutable/HashMap.scala
new file mode 100644
index 000000000000..e9257f1948fc
--- /dev/null
+++ b/library/src/scala/collection/immutable/HashMap.scala
@@ -0,0 +1,2422 @@
+/*
+ * 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 collection.immutable
+
+import java.lang.Integer.bitCount
+import java.lang.System.arraycopy
+
+import scala.annotation.unchecked.{uncheckedVariance => uV}
+import scala.collection.Hashing.improve
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.generic.DefaultSerializable
+import scala.collection.mutable, mutable.ReusableBuilder
+import scala.collection.{Iterator, MapFactory, MapFactoryDefaults, Stepper, StepperShape, mutable}
+import scala.runtime.AbstractFunction2
+import scala.runtime.Statics.releaseFence
+import scala.util.hashing.MurmurHash3
+
+/** This class implements immutable maps using a Compressed Hash-Array Mapped Prefix-tree.
+ * See paper https://michael.steindorfer.name/publications/oopsla15.pdf for more details.
+ *
+ * @tparam K the type of the keys contained in this hash set.
+ * @tparam V the type of the values associated with the keys in this hash map.
+ *
+ * @define Coll `immutable.HashMap`
+ * @define coll immutable champ hash map
+ */
+
+final class HashMap[K, +V] private[immutable] (private[immutable] val rootNode: BitmapIndexedMapNode[K, V])
+ extends AbstractMap[K, V]
+ with StrictOptimizedMapOps[K, V, HashMap, HashMap[K, V]]
+ with MapFactoryDefaults[K, V, HashMap, Iterable]
+ with DefaultSerializable {
+
+ def this() = this(MapNode.empty)
+
+ // This release fence is present because rootNode may have previously been mutated during construction.
+ releaseFence()
+
+ override def mapFactory: MapFactory[HashMap] = HashMap
+
+ override def knownSize: Int = rootNode.size
+
+ override def size: Int = rootNode.size
+
+ override def isEmpty: Boolean = rootNode.size == 0
+
+ override def keySet: Set[K] = if (size == 0) Set.empty else new HashKeySet
+
+ private[immutable] final class HashKeySet extends ImmutableKeySet {
+
+ private[this] def newKeySetOrThis(newHashMap: HashMap[K, _]): Set[K] =
+ if (newHashMap eq HashMap.this) this else newHashMap.keySet
+ private[this] def newKeySetOrThis(newRootNode: BitmapIndexedMapNode[K, _]): Set[K] =
+ if (newRootNode eq rootNode) this else new HashMap(newRootNode).keySet
+
+ override def incl(elem: K): Set[K] = {
+ val originalHash = elem.##
+ val improvedHash = improve(originalHash)
+ val newNode = rootNode.updated(elem, null.asInstanceOf[V], originalHash, improvedHash, 0, replaceValue = false)
+ newKeySetOrThis(newNode)
+ }
+ override def excl(elem: K): Set[K] = newKeySetOrThis(HashMap.this - elem)
+ override def filter(pred: K => Boolean): Set[K] = newKeySetOrThis(HashMap.this.filter(kv => pred(kv._1)))
+ override def filterNot(pred: K => Boolean): Set[K] = newKeySetOrThis(HashMap.this.filterNot(kv => pred(kv._1)))
+ }
+
+ def iterator: Iterator[(K, V)] = {
+ if (isEmpty) Iterator.empty
+ else new MapKeyValueTupleIterator[K, V](rootNode)
+ }
+
+ override def keysIterator: Iterator[K] = {
+ if (isEmpty) Iterator.empty
+ else new MapKeyIterator[K, V](rootNode)
+ }
+ override def valuesIterator: Iterator[V] = {
+ if (isEmpty) Iterator.empty
+ else new MapValueIterator[K, V](rootNode)
+ }
+
+ protected[immutable] def reverseIterator: Iterator[(K, V)] = {
+ if (isEmpty) Iterator.empty
+ else new MapKeyValueTupleReverseIterator[K, V](rootNode)
+ }
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[(K, V), S]): S with EfficientSplit =
+ shape.
+ parUnbox(collection.convert.impl.AnyChampStepper.from[(K, V), MapNode[K, V]](size, rootNode, (node, i) => node.getPayload(i)))
+
+ override def keyStepper[S <: Stepper[_]](implicit shape: StepperShape[K, S]): S with EfficientSplit = {
+ import collection.convert.impl._
+ val s = shape.shape match {
+ case StepperShape.IntShape => IntChampStepper.from[ MapNode[K, V]](size, rootNode, (node, i) => node.getKey(i).asInstanceOf[Int])
+ case StepperShape.LongShape => LongChampStepper.from[ MapNode[K, V]](size, rootNode, (node, i) => node.getKey(i).asInstanceOf[Long])
+ case StepperShape.DoubleShape => DoubleChampStepper.from[MapNode[K, V]](size, rootNode, (node, i) => node.getKey(i).asInstanceOf[Double])
+ case _ => shape.parUnbox(AnyChampStepper.from[K, MapNode[K, V]](size, rootNode, (node, i) => node.getKey(i)))
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ override def valueStepper[S <: Stepper[_]](implicit shape: StepperShape[V, S]): S with EfficientSplit = {
+ import collection.convert.impl._
+ val s = shape.shape match {
+ case StepperShape.IntShape => IntChampStepper.from[ MapNode[K, V]](size, rootNode, (node, i) => node.getValue(i).asInstanceOf[Int])
+ case StepperShape.LongShape => LongChampStepper.from[ MapNode[K, V]](size, rootNode, (node, i) => node.getValue(i).asInstanceOf[Long])
+ case StepperShape.DoubleShape => DoubleChampStepper.from[MapNode[K, V]](size, rootNode, (node, i) => node.getValue(i).asInstanceOf[Double])
+ case _ => shape.parUnbox(AnyChampStepper.from[V, MapNode[K, V]](size, rootNode, (node, i) => node.getValue(i)))
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ override final def contains(key: K): Boolean = {
+ val keyUnimprovedHash = key.##
+ val keyHash = improve(keyUnimprovedHash)
+ rootNode.containsKey(key, keyUnimprovedHash, keyHash, 0)
+ }
+
+ override def apply(key: K): V = {
+ val keyUnimprovedHash = key.##
+ val keyHash = improve(keyUnimprovedHash)
+ rootNode.apply(key, keyUnimprovedHash, keyHash, 0)
+ }
+
+ def get(key: K): Option[V] = {
+ val keyUnimprovedHash = key.##
+ val keyHash = improve(keyUnimprovedHash)
+ rootNode.get(key, keyUnimprovedHash, keyHash, 0)
+ }
+
+ override def getOrElse[V1 >: V](key: K, default: => V1): V1 = {
+ val keyUnimprovedHash = key.##
+ val keyHash = improve(keyUnimprovedHash)
+ rootNode.getOrElse(key, keyUnimprovedHash, keyHash, 0, default)
+ }
+
+ @inline private[this] def newHashMapOrThis[V1 >: V](newRootNode: BitmapIndexedMapNode[K, V1]): HashMap[K, V1] =
+ if (newRootNode eq rootNode) this else new HashMap(newRootNode)
+
+ def updated[V1 >: V](key: K, value: V1): HashMap[K, V1] = {
+ val keyUnimprovedHash = key.##
+ newHashMapOrThis(rootNode.updated(key, value, keyUnimprovedHash, improve(keyUnimprovedHash), 0, replaceValue = true))
+ }
+
+ // preemptively overridden in anticipation of performance optimizations
+ override def updatedWith[V1 >: V](key: K)(remappingFunction: Option[V] => Option[V1]): HashMap[K, V1] =
+ super.updatedWith[V1](key)(remappingFunction)
+
+ def removed(key: K): HashMap[K, V] = {
+ val keyUnimprovedHash = key.##
+ newHashMapOrThis(rootNode.removed(key, keyUnimprovedHash, improve(keyUnimprovedHash), 0))
+ }
+
+ override def concat[V1 >: V](that: scala.IterableOnce[(K, V1)]): HashMap[K, V1] = that match {
+ case hm: HashMap[K, V1] =>
+ if (isEmpty) hm
+ else {
+ val newNode = rootNode.concat(hm.rootNode, 0)
+ if (newNode eq hm.rootNode) hm
+ else newHashMapOrThis(newNode)
+ }
+ case hm: mutable.HashMap[K @unchecked, V @unchecked] =>
+ val iter = hm.nodeIterator
+ var current = rootNode
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = hm.unimproveHash(next.hash)
+ val improved = improve(originalHash)
+ current = current.updated(next.key, next.value, originalHash, improved, 0, replaceValue = true)
+
+ if (current ne rootNode) {
+ var shallowlyMutableNodeMap = Node.bitposFrom(Node.maskFrom(improved, 0))
+
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = hm.unimproveHash(next.hash)
+ shallowlyMutableNodeMap = current.updateWithShallowMutations(next.key, next.value, originalHash, improve(originalHash), 0, shallowlyMutableNodeMap)
+ }
+ return new HashMap(current)
+ }
+ }
+ this
+ case lhm: mutable.LinkedHashMap[K @unchecked, V @unchecked] =>
+ val iter = lhm.entryIterator
+ var current = rootNode
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = lhm.unimproveHash(next.hash)
+ val improved = improve(originalHash)
+ current = current.updated(next.key, next.value, originalHash, improved, 0, replaceValue = true)
+
+ if (current ne rootNode) {
+ var shallowlyMutableNodeMap = Node.bitposFrom(Node.maskFrom(improved, 0))
+
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = lhm.unimproveHash(next.hash)
+ shallowlyMutableNodeMap = current.updateWithShallowMutations(next.key, next.value, originalHash, improve(originalHash), 0, shallowlyMutableNodeMap)
+ }
+ return new HashMap(current)
+ }
+ }
+ this
+ case _ =>
+ class accum extends AbstractFunction2[K, V1, Unit] with Function1[(K, V1), Unit] {
+ var changed = false
+ var shallowlyMutableNodeMap: Int = 0
+ var current: BitmapIndexedMapNode[K, V1] = rootNode
+ def apply(kv: (K, V1)) = apply(kv._1, kv._2)
+ def apply(key: K, value: V1): Unit = {
+ val originalHash = key.##
+ val improved = improve(originalHash)
+ if (!changed) {
+ current = current.updated(key, value, originalHash, improved, 0, replaceValue = true)
+ if (current ne rootNode) {
+ // Note: We could have started with shallowlyMutableNodeMap = 0, however this way, in the case that
+ // the first changed key ended up in a subnode beneath root, we mark that root right away as being
+ // shallowly mutable.
+ //
+ // since key->value has just been inserted, and certainly caused a new root node to be created, we can say with
+ // certainty that it either caused a new subnode to be created underneath `current`, in which case we should
+ // carry on mutating that subnode, or it ended up as a child data pair of the root, in which case, no harm is
+ // done by including its bit position in the shallowlyMutableNodeMap anyways.
+ changed = true
+ shallowlyMutableNodeMap = Node.bitposFrom(Node.maskFrom(improved, 0))
+ }
+ } else {
+ shallowlyMutableNodeMap = current.updateWithShallowMutations(key, value, originalHash, improved, 0, shallowlyMutableNodeMap)
+ }
+ }
+ }
+ that match {
+ case thatMap: Map[K, V1] =>
+ if (thatMap.isEmpty) this
+ else {
+ val accum = new accum
+ thatMap.foreachEntry(accum)
+ newHashMapOrThis(accum.current)
+ }
+ case _ =>
+ val it = that.iterator
+ if (it.isEmpty) this
+ else {
+ val accum = new accum
+ it.foreach(accum)
+ newHashMapOrThis(accum.current)
+ }
+ }
+ }
+
+ override def tail: HashMap[K, V] = this - head._1
+
+ override def init: HashMap[K, V] = this - last._1
+
+ override def head: (K, V) = iterator.next()
+
+ override def last: (K, V) = reverseIterator.next()
+
+ override def foreach[U](f: ((K, V)) => U): Unit = rootNode.foreach(f)
+
+ override def foreachEntry[U](f: (K, V) => U): Unit = rootNode.foreachEntry(f)
+
+ /** Applies a function to each key, value, and **original** hash value in this Map */
+ @inline private[collection] def foreachWithHash(f: (K, V, Int) => Unit): Unit = rootNode.foreachWithHash(f)
+
+ override def equals(that: Any): Boolean =
+ that match {
+ case map: HashMap[_, _] => (this eq map) || (this.rootNode == map.rootNode)
+ case _ => super.equals(that)
+ }
+
+ override def hashCode(): Int = {
+ if (isEmpty) MurmurHash3.emptyMapHash
+ else {
+ // Optimized to avoid recomputation of key hashcodes as these are cached in the nodes and can be assumed to be
+ // immutable.
+ val hashIterator = new MapKeyValueTupleHashIterator(rootNode)
+ val hash = MurmurHash3.unorderedHash(hashIterator, MurmurHash3.mapSeed)
+ // assert(hash == super.hashCode())
+ hash
+ }
+ }
+
+ override protected[this] def className = "HashMap"
+
+ /** Merges this HashMap with an other HashMap by combining all key-value pairs of both maps, and delegating to a merge
+ * function to resolve any key collisions between the two HashMaps.
+ *
+ * @example {{{
+ * val left = HashMap(1 -> 1, 2 -> 1)
+ * val right = HashMap(2 -> 2, 3 -> 2)
+ *
+ * val merged = left.merged(right){ case ((k0, v0), (k1, v1)) => (k0 + k1) -> (v0 + v1) }
+ * // HashMap(1 -> 1, 3 -> 2, 4 -> 3)
+ *
+ * }}}
+ *
+ * @param that the HashMap to merge this HashMap with
+ * @param mergef the merge function which resolves collisions between the two HashMaps. If `mergef` is null, then
+ * keys from `this` will overwrite keys from `that`, making the behaviour equivalent to
+ * `that.concat(this)`
+ *
+ * @note In cases where `mergef` returns keys which themselves collide with other keys returned by `merge`, or
+ * found in `this` or `that`, it is not defined which value will be chosen. For example:
+ *
+ * Colliding multiple results of merging:
+ * {{{
+ * // key `3` collides between a result of merging keys `1` and `2`
+ * val left = HashMap(1 -> 1, 2 -> 2)
+ * val right = HashMap(1 -> 1, 2 -> 2)
+ *
+ * val merged = left.merged(right){ case (_, (_, v1)) => 3 -> v1 }
+ * // HashMap(3 -> 2) is returned, but it could also have returned HashMap(3 -> 1)
+ * }}}
+ * Colliding results of merging with other keys:
+ * {{{
+ * // key `2` collides between a result of merging `1`, and existing key `2`
+ * val left = HashMap(1 -> 1, 2 -> 1)
+ * val right = HashMap(1 -> 2)
+ *
+ * val merged = left.merged(right)((_,_) => 2 -> 3)
+ * // HashMap(2 -> 1) is returned, but it could also have returned HashMap(2 -> 3)
+ * }}}
+ *
+ */
+ def merged[V1 >: V](that: HashMap[K, V1])(mergef: ((K, V), (K, V1)) => (K, V1)): HashMap[K, V1] =
+ if (mergef == null) {
+ that ++ this
+ } else {
+ if (isEmpty) that
+ else if (that.isEmpty) this
+ else if (size == 1) {
+ val payload@(k, v) = rootNode.getPayload(0)
+ val originalHash = rootNode.getHash(0)
+ val improved = improve(originalHash)
+
+ if (that.rootNode.containsKey(k, originalHash, improved, 0)) {
+ val thatPayload = that.rootNode.getTuple(k, originalHash, improved, 0)
+ val (mergedK, mergedV) = mergef(payload, thatPayload)
+ val mergedOriginalHash = mergedK.##
+ val mergedImprovedHash = improve(mergedOriginalHash)
+ new HashMap(that.rootNode.removed(thatPayload._1, originalHash, improved, 0).updated(mergedK, mergedV, mergedOriginalHash, mergedImprovedHash, 0, replaceValue = true))
+ } else {
+ new HashMap(that.rootNode.updated(k, v, originalHash, improved, 0, replaceValue = true))
+ }
+ } else if (that.size == 0) {
+ val thatPayload@(k, v) = rootNode.getPayload(0)
+ val thatOriginalHash = rootNode.getHash(0)
+ val thatImproved = improve(thatOriginalHash)
+
+ if (rootNode.containsKey(k, thatOriginalHash, thatImproved, 0)) {
+ val payload = rootNode.getTuple(k, thatOriginalHash, thatImproved, 0)
+ val (mergedK, mergedV) = mergef(payload, thatPayload)
+ val mergedOriginalHash = mergedK.##
+ val mergedImprovedHash = improve(mergedOriginalHash)
+ new HashMap(rootNode.updated(mergedK, mergedV, mergedOriginalHash, mergedImprovedHash, 0, replaceValue = true))
+ } else {
+ new HashMap(rootNode.updated(k, v, thatOriginalHash, thatImproved, 0, replaceValue = true))
+ }
+ } else {
+ val builder = new HashMapBuilder[K, V1]
+ rootNode.mergeInto(that.rootNode, builder, 0)(mergef)
+ builder.result()
+ }
+ }
+
+ override def transform[W](f: (K, V) => W): HashMap[K, W] =
+ newHashMapOrThis(rootNode.transform[Any](f)).asInstanceOf[HashMap[K, W]]
+
+ override protected[collection] def filterImpl(pred: ((K, V)) => Boolean, isFlipped: Boolean): HashMap[K, V] = {
+ val newRootNode = rootNode.filterImpl(pred, isFlipped)
+ if (newRootNode eq rootNode) this
+ else if (newRootNode.size == 0) HashMap.empty
+ else new HashMap(newRootNode)
+ }
+
+ override def removedAll(keys: IterableOnce[K]): HashMap[K, V] = {
+ if (isEmpty) {
+ this
+ } else {
+ keys match {
+ case hashSet: HashSet[K] =>
+ if (hashSet.isEmpty) {
+ this
+ } else {
+ // TODO: Remove all keys from the hashSet in a sub-linear fashion by only visiting the nodes in the tree
+ // This can be a direct port of the implementation of `SetNode[A]#diff(SetNode[A])`
+ val newRootNode = new MapNodeRemoveAllSetNodeIterator(hashSet.rootNode).removeAll(rootNode)
+ if (newRootNode eq rootNode) this
+ else if (newRootNode.size <= 0) HashMap.empty
+ else new HashMap(newRootNode)
+ }
+ case hashSet: collection.mutable.HashSet[K] =>
+ if (hashSet.isEmpty) {
+ this
+ } else {
+ val iter = hashSet.nodeIterator
+ var curr = rootNode
+
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = hashSet.unimproveHash(next.hash)
+ val improved = improve(originalHash)
+ curr = curr.removed(next.key, originalHash, improved, 0)
+ if (curr.size == 0) {
+ return HashMap.empty
+ }
+ }
+ newHashMapOrThis(curr)
+ }
+ case lhashSet: collection.mutable.LinkedHashSet[K] =>
+ if (lhashSet.isEmpty) {
+ this
+ } else {
+ val iter = lhashSet.entryIterator
+ var curr = rootNode
+
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = lhashSet.unimproveHash(next.hash)
+ val improved = improve(originalHash)
+ curr = curr.removed(next.key, originalHash, improved, 0)
+ if (curr.size == 0) {
+ return HashMap.empty
+ }
+ }
+ newHashMapOrThis(curr)
+ }
+ case _ =>
+ val iter = keys.iterator
+ var curr = rootNode
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = next.##
+ val improved = improve(originalHash)
+ curr = curr.removed(next, originalHash, improved, 0)
+ if (curr.size == 0) {
+ return HashMap.empty
+ }
+ }
+ newHashMapOrThis(curr)
+ }
+ }
+ }
+
+ override def partition(p: ((K, V)) => Boolean): (HashMap[K, V], HashMap[K, V]) = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ //
+ // In particular, `partition` could be optimized to traverse the trie node-by-node, splitting each node into two,
+ // based on the result of applying `p` to its elements and subnodes.
+ super.partition(p)
+ }
+
+ override def take(n: Int): HashMap[K, V] = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ //
+ // In particular, `take` could be optimized to construct a new trie structure by visiting each node, and including
+ // those nodes in the resulting trie, until `n` total elements have been included.
+ super.take(n)
+ }
+
+ override def takeRight(n: Int): HashMap[K, V] = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ //
+ // In particular, `take` could be optimized to construct a new trie structure by visiting each node in reverse, and
+ // and including those nodes in the resulting trie, until `n` total elements have been included.
+ super.takeRight(n)
+ }
+
+ override def takeWhile(p: ((K, V)) => Boolean): HashMap[K, V] = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ //
+ // In particular, `takeWhile` could be optimized to construct a new trie structure by visiting each node, and
+ // including those nodes in the resulting trie, until `p` returns `false`
+ super.takeWhile(p)
+ }
+
+ override def dropWhile(p: ((K, V)) => Boolean): HashMap[K, V] = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ //
+ // In particular, `dropWhile` could be optimized to construct a new trie structure by visiting each node, and
+ // dropping those nodes in the resulting trie, until `p` returns `true`
+ super.dropWhile(p)
+ }
+
+ override def dropRight(n: Int): HashMap[K, V] = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ //
+ // In particular, `dropRight` could be optimized to construct a new trie structure by visiting each node, in reverse
+ // order, and dropping all nodes until `n` elements have been dropped
+ super.dropRight(n)
+ }
+
+ override def drop(n: Int): HashMap[K, V] = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ //
+ // In particular, `dropRight` could be optimized to construct a new trie structure by visiting each node, and
+ // dropping all nodes until `n` elements have been dropped
+ super.drop(n)
+ }
+
+ override def span(p: ((K, V)) => Boolean): (HashMap[K, V], HashMap[K, V]) = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ //
+ // In particular, `scan` could be optimized to construct a new trie structure by visiting each node, and
+ // keeping each node and element until `p` returns false, then including the remaining nodes in the second result.
+ // This would avoid having to rebuild most of the trie, and would eliminate the need to perform hashing and equality
+ // checks.
+ super.span(p)
+ }
+
+}
+
+private[immutable] object MapNode {
+
+ private final val EmptyMapNode = new BitmapIndexedMapNode(0, 0, Array.empty, Array.empty, 0, 0)
+
+ def empty[K, V]: BitmapIndexedMapNode[K, V] = EmptyMapNode.asInstanceOf[BitmapIndexedMapNode[K, V]]
+
+ final val TupleLength = 2
+
+}
+
+
+private[immutable] sealed abstract class MapNode[K, +V] extends Node[MapNode[K, V @uV]] {
+ def apply(key: K, originalHash: Int, hash: Int, shift: Int): V
+
+ def get(key: K, originalHash: Int, hash: Int, shift: Int): Option[V]
+
+ def getOrElse[V1 >: V](key: K, originalHash: Int, hash: Int, shift: Int, f: => V1): V1
+
+ def containsKey(key: K, originalHash: Int, hash: Int, shift: Int): Boolean
+
+ /** Returns a MapNode with the passed key-value assignment added
+ *
+ * @param key the key to add to the MapNode
+ * @param value the value to associate with `key`
+ * @param originalHash the original hash of `key`
+ * @param hash the improved hash of `key`
+ * @param shift the shift of the node (distanceFromRoot * BitPartitionSize)
+ * @param replaceValue if true, then the value currently associated to `key` will be replaced with the passed value
+ * argument.
+ * if false, then the key will be inserted if not already present, however if the key is present
+ * then the passed value will not replace the current value. That is, if `false`, then this
+ * method has `update if not exists` semantics.
+ */
+ def updated[V1 >: V](key: K, value: V1, originalHash: Int, hash: Int, shift: Int, replaceValue: Boolean): MapNode[K, V1]
+
+ def removed[V1 >: V](key: K, originalHash: Int, hash: Int, shift: Int): MapNode[K, V1]
+
+ def hasNodes: Boolean
+
+ def nodeArity: Int
+
+ def getNode(index: Int): MapNode[K, V]
+
+ def hasPayload: Boolean
+
+ def payloadArity: Int
+
+ def getKey(index: Int): K
+
+ def getValue(index: Int): V
+
+ def getPayload(index: Int): (K, V)
+
+ def size: Int
+
+ def foreach[U](f: ((K, V)) => U): Unit
+
+ def foreachEntry[U](f: (K, V) => U): Unit
+
+ def foreachWithHash(f: (K, V, Int) => Unit): Unit
+
+ def transform[W](f: (K, V) => W): MapNode[K, W]
+
+ def copy(): MapNode[K, V]
+
+ def concat[V1 >: V](that: MapNode[K, V1], shift: Int): MapNode[K, V1]
+
+ def filterImpl(pred: ((K, V)) => Boolean, isFlipped: Boolean): MapNode[K, V]
+
+ /** Merges this node with that node, adding each resulting tuple to `builder`
+ *
+ * `this` should be a node from `left` hashmap in `left.merged(right)(mergef)`
+ *
+ * @param that node from the "right" HashMap. Must also be at the same "path" or "position" within the right tree,
+ * as `this` is, within the left tree
+ */
+ def mergeInto[V1 >: V](that: MapNode[K, V1], builder: HashMapBuilder[K, V1], shift: Int)(mergef: ((K, V), (K, V1)) => (K, V1)): Unit
+
+ /** Returns the exact (equal by reference) key, and value, associated to a given key.
+ * If the key is not bound to a value, then an exception is thrown
+ */
+ def getTuple(key: K, originalHash: Int, hash: Int, shift: Int): (K, V)
+
+ /** Adds all key-value pairs to a builder */
+ def buildTo[V1 >: V](builder: HashMapBuilder[K, V1]): Unit
+}
+
+private final class BitmapIndexedMapNode[K, +V](
+ var dataMap: Int,
+ var nodeMap: Int,
+ var content: Array[Any],
+ var originalHashes: Array[Int],
+ var size: Int,
+ var cachedJavaKeySetHashCode: Int) extends MapNode[K, V] {
+
+ releaseFence()
+
+ import MapNode._
+ import Node._
+
+ /*
+ assert(checkInvariantContentIsWellTyped())
+ assert(checkInvariantSubNodesAreCompacted())
+
+ private final def checkInvariantSubNodesAreCompacted(): Boolean =
+ new MapKeyValueTupleIterator[K, V](this).size - payloadArity >= 2 * nodeArity
+
+ private final def checkInvariantContentIsWellTyped(): Boolean = {
+ val predicate1 = TupleLength * payloadArity + nodeArity == content.length
+
+ val predicate2 = Range(0, TupleLength * payloadArity)
+ .forall(i => content(i).isInstanceOf[MapNode[_, _]] == false)
+
+ val predicate3 = Range(TupleLength * payloadArity, content.length)
+ .forall(i => content(i).isInstanceOf[MapNode[_, _]] == true)
+
+ predicate1 && predicate2 && predicate3
+ }
+ */
+
+ def getKey(index: Int): K = content(TupleLength * index).asInstanceOf[K]
+ def getValue(index: Int): V = content(TupleLength * index + 1).asInstanceOf[V]
+
+ def getPayload(index: Int) = Tuple2(
+ content(TupleLength * index).asInstanceOf[K],
+ content(TupleLength * index + 1).asInstanceOf[V])
+
+ override def getHash(index: Int): Int = originalHashes(index)
+
+ def getNode(index: Int): MapNode[K, V] =
+ content(content.length - 1 - index).asInstanceOf[MapNode[K, V]]
+
+ def apply(key: K, originalHash: Int, keyHash: Int, shift: Int): V = {
+ val mask = maskFrom(keyHash, shift)
+ val bitpos = bitposFrom(mask)
+
+ if ((dataMap & bitpos) != 0) {
+ val index = indexFrom(dataMap, mask, bitpos)
+ if (key == getKey(index)) getValue(index) else throw new NoSuchElementException(s"key not found: $key")
+ } else if ((nodeMap & bitpos) != 0) {
+ getNode(indexFrom(nodeMap, mask, bitpos)).apply(key, originalHash, keyHash, shift + BitPartitionSize)
+ } else {
+ throw new NoSuchElementException(s"key not found: $key")
+ }
+ }
+
+ def get(key: K, originalHash: Int, keyHash: Int, shift: Int): Option[V] = {
+ val mask = maskFrom(keyHash, shift)
+ val bitpos = bitposFrom(mask)
+
+ if ((dataMap & bitpos) != 0) {
+ val index = indexFrom(dataMap, mask, bitpos)
+ val key0 = this.getKey(index)
+ if (key == key0) Some(this.getValue(index)) else None
+ } else if ((nodeMap & bitpos) != 0) {
+ val index = indexFrom(nodeMap, mask, bitpos)
+ this.getNode(index).get(key, originalHash, keyHash, shift + BitPartitionSize)
+ } else {
+ None
+ }
+ }
+
+ override def getTuple(key: K, originalHash: Int, hash: Int, shift: Int): (K, V) = {
+ val mask = maskFrom(hash, shift)
+ val bitpos = bitposFrom(mask)
+
+ if ((dataMap & bitpos) != 0) {
+ val index = indexFrom(dataMap, mask, bitpos)
+ val payload = getPayload(index)
+ if (key == payload._1) payload else Iterator.empty.next()
+ } else if ((nodeMap & bitpos) != 0) {
+ val index = indexFrom(nodeMap, mask, bitpos)
+ getNode(index).getTuple(key, originalHash, hash, shift + BitPartitionSize)
+ } else {
+ Iterator.empty.next()
+ }
+ }
+
+ def getOrElse[V1 >: V](key: K, originalHash: Int, keyHash: Int, shift: Int, f: => V1): V1 = {
+ val mask = maskFrom(keyHash, shift)
+ val bitpos = bitposFrom(mask)
+
+ if ((dataMap & bitpos) != 0) {
+ val index = indexFrom(dataMap, mask, bitpos)
+ val key0 = this.getKey(index)
+ if (key == key0) getValue(index) else f
+ } else if ((nodeMap & bitpos) != 0) {
+ val index = indexFrom(nodeMap, mask, bitpos)
+ this.getNode(index).getOrElse(key, originalHash, keyHash, shift + BitPartitionSize, f)
+ } else {
+ f
+ }
+ }
+
+ override def containsKey(key: K, originalHash: Int, keyHash: Int, shift: Int): Boolean = {
+ val mask = maskFrom(keyHash, shift)
+ val bitpos = bitposFrom(mask)
+
+ if ((dataMap & bitpos) != 0) {
+ val index = indexFrom(dataMap, mask, bitpos)
+ // assert(hashes(index) == computeHash(this.getKey(index)), (hashes.toSeq, content.toSeq, index, key, keyHash, shift))
+ (originalHashes(index) == originalHash) && key == getKey(index)
+ } else if ((nodeMap & bitpos) != 0) {
+ getNode(indexFrom(nodeMap, mask, bitpos)).containsKey(key, originalHash, keyHash, shift + BitPartitionSize)
+ } else {
+ false
+ }
+ }
+
+
+ def updated[V1 >: V](key: K, value: V1, originalHash: Int, keyHash: Int, shift: Int, replaceValue: Boolean): BitmapIndexedMapNode[K, V1] = {
+ val mask = maskFrom(keyHash, shift)
+ val bitpos = bitposFrom(mask)
+
+ if ((dataMap & bitpos) != 0) {
+ val index = indexFrom(dataMap, mask, bitpos)
+ val key0 = getKey(index)
+ val key0UnimprovedHash = getHash(index)
+ if (key0UnimprovedHash == originalHash && key0 == key) {
+ if (replaceValue) {
+ val value0 = this.getValue(index)
+ if ((key0.asInstanceOf[AnyRef] eq key.asInstanceOf[AnyRef]) && (value0.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef]))
+ this
+ else copyAndSetValue(bitpos, key, value)
+ } else this
+ } else {
+ val value0 = this.getValue(index)
+ val key0Hash = improve(key0UnimprovedHash)
+ val subNodeNew = mergeTwoKeyValPairs(key0, value0, key0UnimprovedHash, key0Hash, key, value, originalHash, keyHash, shift + BitPartitionSize)
+
+ copyAndMigrateFromInlineToNode(bitpos, key0Hash, subNodeNew)
+ }
+ } else if ((nodeMap & bitpos) != 0) {
+ val index = indexFrom(nodeMap, mask, bitpos)
+ val subNode = this.getNode(index)
+ val subNodeNew = subNode.updated(key, value, originalHash, keyHash, shift + BitPartitionSize, replaceValue)
+
+ if (subNodeNew eq subNode) this else copyAndSetNode(bitpos, subNode, subNodeNew)
+ } else copyAndInsertValue(bitpos, key, originalHash, keyHash, value)
+ }
+
+ /** A variant of `updated` which performs shallow mutations on the root (`this`), and if possible, on immediately
+ * descendant child nodes (only one level beneath `this`)
+ *
+ * The caller should pass a bitmap of child nodes of this node, which this method may mutate.
+ * If this method may mutate a child node, then if the updated key-value belongs in that child node, it will
+ * be shallowly mutated (its children will not be mutated).
+ *
+ * If instead this method may not mutate the child node in which the to-be-updated key-value pair belongs, then
+ * that child will be updated immutably, but the result will be mutably re-inserted as a child of this node.
+ *
+ * @param key the key to update
+ * @param value the value to set `key` to
+ * @param originalHash key.##
+ * @param keyHash the improved hash
+ * @param shallowlyMutableNodeMap bitmap of child nodes of this node, which can be shallowly mutated
+ * during the call to this method
+ *
+ * @return Int which is the bitwise OR of shallowlyMutableNodeMap and any freshly created nodes, which will be
+ * available for mutations in subsequent calls.
+ */
+ def updateWithShallowMutations[V1 >: V](key: K, value: V1, originalHash: Int, keyHash: Int, shift: Int, shallowlyMutableNodeMap: Int): Int = {
+ val mask = maskFrom(keyHash, shift)
+ val bitpos = bitposFrom(mask)
+
+ if ((dataMap & bitpos) != 0) {
+ val index = indexFrom(dataMap, mask, bitpos)
+ val key0 = getKey(index)
+ val key0UnimprovedHash = getHash(index)
+ if (key0UnimprovedHash == originalHash && key0 == key) {
+ val value0 = this.getValue(index)
+ if (!((key0.asInstanceOf[AnyRef] eq key.asInstanceOf[AnyRef]) && (value0.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef]))) {
+ val dataIx = dataIndex(bitpos)
+ val idx = TupleLength * dataIx
+ content(idx + 1) = value
+ }
+ shallowlyMutableNodeMap
+ } else {
+ val value0 = this.getValue(index)
+ val key0Hash = improve(key0UnimprovedHash)
+
+ val subNodeNew = mergeTwoKeyValPairs(key0, value0, key0UnimprovedHash, key0Hash, key, value, originalHash, keyHash, shift + BitPartitionSize)
+ migrateFromInlineToNodeInPlace(bitpos, key0Hash, subNodeNew)
+ shallowlyMutableNodeMap | bitpos
+ }
+ } else if ((nodeMap & bitpos) != 0) {
+ val index = indexFrom(nodeMap, mask, bitpos)
+ val subNode = this.getNode(index)
+ val subNodeSize = subNode.size
+ val subNodeHashCode = subNode.cachedJavaKeySetHashCode
+
+ var returnMutableNodeMap = shallowlyMutableNodeMap
+
+ val subNodeNew: MapNode[K, V1] = subNode match {
+ case subNodeBm: BitmapIndexedMapNode[K, V] if (bitpos & shallowlyMutableNodeMap) != 0 =>
+ subNodeBm.updateWithShallowMutations(key, value, originalHash, keyHash, shift + BitPartitionSize, 0)
+ subNodeBm
+ case _ =>
+ val result = subNode.updated(key, value, originalHash, keyHash, shift + BitPartitionSize, replaceValue = true)
+ if (result ne subNode) {
+ returnMutableNodeMap |= bitpos
+ }
+ result
+ }
+
+ this.content(this.content.length - 1 - this.nodeIndex(bitpos)) = subNodeNew
+ this.size = this.size - subNodeSize + subNodeNew.size
+ this.cachedJavaKeySetHashCode = this.cachedJavaKeySetHashCode - subNodeHashCode + subNodeNew.cachedJavaKeySetHashCode
+ returnMutableNodeMap
+ } else {
+ val dataIx = dataIndex(bitpos)
+ val idx = TupleLength * dataIx
+
+ val src = this.content
+ val dst = new Array[Any](src.length + TupleLength)
+
+ // copy 'src' and insert 2 element(s) at position 'idx'
+ arraycopy(src, 0, dst, 0, idx)
+ dst(idx) = key
+ dst(idx + 1) = value
+ arraycopy(src, idx, dst, idx + TupleLength, src.length - idx)
+
+ this.dataMap |= bitpos
+ this.content = dst
+ this.originalHashes = insertElement(originalHashes, dataIx, originalHash)
+ this.size += 1
+ this.cachedJavaKeySetHashCode += keyHash
+ shallowlyMutableNodeMap
+ }
+ }
+
+ def removed[V1 >: V](key: K, originalHash: Int, keyHash: Int, shift: Int): BitmapIndexedMapNode[K, V1] = {
+ val mask = maskFrom(keyHash, shift)
+ val bitpos = bitposFrom(mask)
+
+ if ((dataMap & bitpos) != 0) {
+ val index = indexFrom(dataMap, mask, bitpos)
+ val key0 = this.getKey(index)
+
+ if (key0 == key) {
+ if (this.payloadArity == 2 && this.nodeArity == 0) {
+ /*
+ * Create new node with remaining pair. The new node will a) either become the new root
+ * returned, or b) unwrapped and inlined during returning.
+ */
+ val newDataMap = if (shift == 0) (dataMap ^ bitpos) else bitposFrom(maskFrom(keyHash, 0))
+ if (index == 0)
+ new BitmapIndexedMapNode[K, V1](newDataMap, 0, Array(getKey(1), getValue(1)), Array(originalHashes(1)), 1, improve(getHash(1)))
+ else
+ new BitmapIndexedMapNode[K, V1](newDataMap, 0, Array(getKey(0), getValue(0)), Array(originalHashes(0)), 1, improve(getHash(0)))
+ } else copyAndRemoveValue(bitpos, keyHash)
+ } else this
+ } else if ((nodeMap & bitpos) != 0) {
+ val index = indexFrom(nodeMap, mask, bitpos)
+ val subNode = this.getNode(index)
+
+ val subNodeNew = subNode.removed(key, originalHash, keyHash, shift + BitPartitionSize)
+ // assert(subNodeNew.size != 0, "Sub-node must have at least one element.")
+
+ if (subNodeNew eq subNode) return this
+
+ // cache just in case subNodeNew is a hashCollision node, in which in which case a little arithmetic is avoided
+ // in Vector#length
+ val subNodeNewSize = subNodeNew.size
+
+ if (subNodeNewSize == 1) {
+ if (this.size == subNode.size) {
+ // subNode is the only child (no other data or node children of `this` exist)
+ // escalate (singleton or empty) result
+ subNodeNew.asInstanceOf[BitmapIndexedMapNode[K, V]]
+ } else {
+ // inline value (move to front)
+ copyAndMigrateFromNodeToInline(bitpos, subNode, subNodeNew)
+ }
+ } else if (subNodeNewSize > 1) {
+ // modify current node (set replacement node)
+ copyAndSetNode(bitpos, subNode, subNodeNew)
+ } else this
+ } else this
+ }
+
+ def mergeTwoKeyValPairs[V1 >: V](key0: K, value0: V1, originalHash0: Int, keyHash0: Int, key1: K, value1: V1, originalHash1: Int, keyHash1: Int, shift: Int): MapNode[K, V1] = {
+ // assert(key0 != key1)
+
+ if (shift >= HashCodeLength) {
+ new HashCollisionMapNode[K, V1](originalHash0, keyHash0, Vector((key0, value0), (key1, value1)))
+ } else {
+ val mask0 = maskFrom(keyHash0, shift)
+ val mask1 = maskFrom(keyHash1, shift)
+ val newCachedHash = keyHash0 + keyHash1
+
+ if (mask0 != mask1) {
+ // unique prefixes, payload fits on same level
+ val dataMap = bitposFrom(mask0) | bitposFrom(mask1)
+
+ if (mask0 < mask1) {
+ new BitmapIndexedMapNode[K, V1](dataMap, 0, Array(key0, value0, key1, value1), Array(originalHash0, originalHash1), 2, newCachedHash)
+ } else {
+ new BitmapIndexedMapNode[K, V1](dataMap, 0, Array(key1, value1, key0, value0), Array(originalHash1, originalHash0), 2, newCachedHash)
+ }
+ } else {
+ // identical prefixes, payload must be disambiguated deeper in the trie
+ val nodeMap = bitposFrom(mask0)
+ val node = mergeTwoKeyValPairs(key0, value0, originalHash0, keyHash0, key1, value1, originalHash1, keyHash1, shift + BitPartitionSize)
+ new BitmapIndexedMapNode[K, V1](0, nodeMap, Array(node), Array.emptyIntArray, node.size, node.cachedJavaKeySetHashCode)
+ }
+ }
+ }
+
+ def hasNodes: Boolean = nodeMap != 0
+
+ def nodeArity: Int = bitCount(nodeMap)
+
+ def hasPayload: Boolean = dataMap != 0
+
+ def payloadArity: Int = bitCount(dataMap)
+
+ def dataIndex(bitpos: Int) = bitCount(dataMap & (bitpos - 1))
+
+ def nodeIndex(bitpos: Int) = bitCount(nodeMap & (bitpos - 1))
+
+ def copyAndSetValue[V1 >: V](bitpos: Int, newKey: K, newValue: V1): BitmapIndexedMapNode[K, V1] = {
+ val dataIx = dataIndex(bitpos)
+ val idx = TupleLength * dataIx
+
+ val src = this.content
+ val dst = new Array[Any](src.length)
+
+ // copy 'src' and set 1 element(s) at position 'idx'
+ arraycopy(src, 0, dst, 0, src.length)
+ //dst(idx) = newKey
+ dst(idx + 1) = newValue
+ new BitmapIndexedMapNode[K, V1](dataMap, nodeMap, dst, originalHashes, size, cachedJavaKeySetHashCode)
+ }
+
+ def copyAndSetNode[V1 >: V](bitpos: Int, oldNode: MapNode[K, V1], newNode: MapNode[K, V1]): BitmapIndexedMapNode[K, V1] = {
+ val idx = this.content.length - 1 - this.nodeIndex(bitpos)
+
+ val src = this.content
+ val dst = new Array[Any](src.length)
+
+ // copy 'src' and set 1 element(s) at position 'idx'
+ arraycopy(src, 0, dst, 0, src.length)
+ dst(idx) = newNode
+ new BitmapIndexedMapNode[K, V1](
+ dataMap,
+ nodeMap,
+ dst,
+ originalHashes,
+ size - oldNode.size + newNode.size,
+ cachedJavaKeySetHashCode - oldNode.cachedJavaKeySetHashCode + newNode.cachedJavaKeySetHashCode
+ )
+ }
+
+ def copyAndInsertValue[V1 >: V](bitpos: Int, key: K, originalHash: Int, keyHash: Int, value: V1): BitmapIndexedMapNode[K, V1] = {
+ val dataIx = dataIndex(bitpos)
+ val idx = TupleLength * dataIx
+
+ val src = this.content
+ val dst = new Array[Any](src.length + TupleLength)
+
+ // copy 'src' and insert 2 element(s) at position 'idx'
+ arraycopy(src, 0, dst, 0, idx)
+ dst(idx) = key
+ dst(idx + 1) = value
+ arraycopy(src, idx, dst, idx + TupleLength, src.length - idx)
+
+ val dstHashes = insertElement(originalHashes, dataIx, originalHash)
+
+ new BitmapIndexedMapNode[K, V1](dataMap | bitpos, nodeMap, dst, dstHashes, size + 1, cachedJavaKeySetHashCode + keyHash)
+ }
+
+ def copyAndRemoveValue(bitpos: Int, keyHash: Int): BitmapIndexedMapNode[K, V] = {
+ val dataIx = dataIndex(bitpos)
+ val idx = TupleLength * dataIx
+
+ val src = this.content
+ val dst = new Array[Any](src.length - TupleLength)
+
+ // copy 'src' and remove 2 element(s) at position 'idx'
+ arraycopy(src, 0, dst, 0, idx)
+ arraycopy(src, idx + TupleLength, dst, idx, src.length - idx - TupleLength)
+
+ val dstHashes = removeElement(originalHashes, dataIx)
+
+ new BitmapIndexedMapNode[K, V](dataMap ^ bitpos, nodeMap, dst, dstHashes, size - 1, cachedJavaKeySetHashCode - keyHash)
+ }
+
+ /** Variant of `copyAndMigrateFromInlineToNode` which mutates `this` rather than returning a new node.
+ *
+ * @param bitpos the bit position of the data to migrate to node
+ * @param keyHash the improved hash of the key currently at `bitpos`
+ * @param node the node to place at `bitpos` beneath `this`
+ */
+ def migrateFromInlineToNodeInPlace[V1 >: V](bitpos: Int, keyHash: Int, node: MapNode[K, V1]): this.type = {
+ val dataIx = dataIndex(bitpos)
+ val idxOld = TupleLength * dataIx
+ val idxNew = this.content.length - TupleLength - nodeIndex(bitpos)
+
+ val src = this.content
+ val dst = new Array[Any](src.length - TupleLength + 1)
+
+ // copy 'src' and remove 2 element(s) at position 'idxOld' and
+ // insert 1 element(s) at position 'idxNew'
+ // assert(idxOld <= idxNew)
+ arraycopy(src, 0, dst, 0, idxOld)
+ arraycopy(src, idxOld + TupleLength, dst, idxOld, idxNew - idxOld)
+ dst(idxNew) = node
+ arraycopy(src, idxNew + TupleLength, dst, idxNew + 1, src.length - idxNew - TupleLength)
+
+ val dstHashes = removeElement(originalHashes, dataIx)
+
+ this.dataMap = dataMap ^ bitpos
+ this.nodeMap = nodeMap | bitpos
+ this.content = dst
+ this.originalHashes = dstHashes
+ this.size = size - 1 + node.size
+ this.cachedJavaKeySetHashCode = cachedJavaKeySetHashCode - keyHash + node.cachedJavaKeySetHashCode
+ this
+ }
+
+ def copyAndMigrateFromInlineToNode[V1 >: V](bitpos: Int, keyHash: Int, node: MapNode[K, V1]): BitmapIndexedMapNode[K, V1] = {
+ val dataIx = dataIndex(bitpos)
+ val idxOld = TupleLength * dataIx
+ val idxNew = this.content.length - TupleLength - nodeIndex(bitpos)
+
+ val src = this.content
+ val dst = new Array[Any](src.length - TupleLength + 1)
+
+ // copy 'src' and remove 2 element(s) at position 'idxOld' and
+ // insert 1 element(s) at position 'idxNew'
+ // assert(idxOld <= idxNew)
+ arraycopy(src, 0, dst, 0, idxOld)
+ arraycopy(src, idxOld + TupleLength, dst, idxOld, idxNew - idxOld)
+ dst(idxNew) = node
+ arraycopy(src, idxNew + TupleLength, dst, idxNew + 1, src.length - idxNew - TupleLength)
+
+ val dstHashes = removeElement(originalHashes, dataIx)
+
+ new BitmapIndexedMapNode[K, V1](
+ dataMap = dataMap ^ bitpos,
+ nodeMap = nodeMap | bitpos,
+ content = dst,
+ originalHashes = dstHashes,
+ size = size - 1 + node.size,
+ cachedJavaKeySetHashCode = cachedJavaKeySetHashCode - keyHash + node.cachedJavaKeySetHashCode
+ )
+ }
+
+ def copyAndMigrateFromNodeToInline[V1 >: V](bitpos: Int, oldNode: MapNode[K, V1], node: MapNode[K, V1]): BitmapIndexedMapNode[K, V1] = {
+ val idxOld = this.content.length - 1 - nodeIndex(bitpos)
+ val dataIxNew = dataIndex(bitpos)
+ val idxNew = TupleLength * dataIxNew
+
+ val key = node.getKey(0)
+ val value = node.getValue(0)
+ val src = this.content
+ val dst = new Array[Any](src.length - 1 + TupleLength)
+
+ // copy 'src' and remove 1 element(s) at position 'idxOld' and
+ // insert 2 element(s) at position 'idxNew'
+ // assert(idxOld >= idxNew)
+ arraycopy(src, 0, dst, 0, idxNew)
+ dst(idxNew) = key
+ dst(idxNew + 1) = value
+ arraycopy(src, idxNew, dst, idxNew + TupleLength, idxOld - idxNew)
+ arraycopy(src, idxOld + 1, dst, idxOld + TupleLength, src.length - idxOld - 1)
+ val hash = node.getHash(0)
+ val dstHashes = insertElement(originalHashes, dataIxNew, hash)
+ new BitmapIndexedMapNode[K, V1](
+ dataMap = dataMap | bitpos,
+ nodeMap = nodeMap ^ bitpos,
+ content = dst,
+ originalHashes = dstHashes,
+ size = size - oldNode.size + 1,
+ cachedJavaKeySetHashCode = cachedJavaKeySetHashCode - oldNode.cachedJavaKeySetHashCode + node.cachedJavaKeySetHashCode
+ )
+ }
+
+ override def foreach[U](f: ((K, V)) => U): Unit = {
+ val iN = payloadArity // arity doesn't change during this operation
+ var i = 0
+ while (i < iN) {
+ f(getPayload(i))
+ i += 1
+ }
+
+ val jN = nodeArity // arity doesn't change during this operation
+ var j = 0
+ while (j < jN) {
+ getNode(j).foreach(f)
+ j += 1
+ }
+ }
+
+ override def foreachEntry[U](f: (K, V) => U): Unit = {
+ val iN = payloadArity // arity doesn't change during this operation
+ var i = 0
+ while (i < iN) {
+ f(getKey(i), getValue(i))
+ i += 1
+ }
+
+ val jN = nodeArity // arity doesn't change during this operation
+ var j = 0
+ while (j < jN) {
+ getNode(j).foreachEntry(f)
+ j += 1
+ }
+ }
+
+ override def foreachWithHash(f: (K, V, Int) => Unit): Unit = {
+ var i = 0
+ val iN = payloadArity // arity doesn't change during this operation
+ while (i < iN) {
+ f(getKey(i), getValue(i), getHash(i))
+ i += 1
+ }
+
+ val jN = nodeArity // arity doesn't change during this operation
+ var j = 0
+ while (j < jN) {
+ getNode(j).foreachWithHash(f)
+ j += 1
+ }
+ }
+ override def buildTo[V1 >: V](builder: HashMapBuilder[K, V1]): Unit = {
+ var i = 0
+ val iN = payloadArity
+ val jN = nodeArity
+ while (i < iN) {
+ builder.addOne(getKey(i), getValue(i), getHash(i))
+ i += 1
+ }
+
+ var j = 0
+ while (j < jN) {
+ getNode(j).buildTo(builder)
+ j += 1
+ }
+ }
+
+ override def transform[W](f: (K, V) => W): BitmapIndexedMapNode[K, W] = {
+ var newContent: Array[Any] = null
+ val iN = payloadArity // arity doesn't change during this operation
+ val jN = nodeArity // arity doesn't change during this operation
+ val newContentLength = content.length
+ var i = 0
+ while (i < iN) {
+ val key = getKey(i)
+ val value = getValue(i)
+ val newValue = f(key, value)
+ if (newContent eq null) {
+ if (newValue.asInstanceOf[AnyRef] ne value.asInstanceOf[AnyRef]) {
+ newContent = content.clone()
+ newContent(TupleLength * i + 1) = newValue
+ }
+ } else {
+ newContent(TupleLength * i + 1) = newValue
+ }
+ i += 1
+ }
+
+ var j = 0
+ while (j < jN) {
+ val node = getNode(j)
+ val newNode = node.transform(f)
+ if (newContent eq null) {
+ if (newNode ne node) {
+ newContent = content.clone()
+ newContent(newContentLength - j - 1) = newNode
+ }
+ } else
+ newContent(newContentLength - j - 1) = newNode
+ j += 1
+ }
+ if (newContent eq null) this.asInstanceOf[BitmapIndexedMapNode[K, W]]
+ else new BitmapIndexedMapNode[K, W](dataMap, nodeMap, newContent, originalHashes, size, cachedJavaKeySetHashCode)
+ }
+
+ override def mergeInto[V1 >: V](that: MapNode[K, V1], builder: HashMapBuilder[K, V1], shift: Int)(mergef: ((K, V), (K, V1)) => (K, V1)): Unit = that match {
+ case bm: BitmapIndexedMapNode[K, V] @unchecked =>
+ if (size == 0) {
+ that.buildTo(builder)
+ return
+ } else if (bm.size == 0) {
+ buildTo(builder)
+ return
+ }
+
+ val allMap = dataMap | bm.dataMap | nodeMap | bm.nodeMap
+
+ val minIndex: Int = Integer.numberOfTrailingZeros(allMap)
+ val maxIndex: Int = Node.BranchingFactor - Integer.numberOfLeadingZeros(allMap)
+
+ {
+ var index = minIndex
+ var leftIdx = 0
+ var rightIdx = 0
+
+ while (index < maxIndex) {
+ val bitpos = bitposFrom(index)
+
+ if ((bitpos & dataMap) != 0) {
+ val leftKey = getKey(leftIdx)
+ val leftValue = getValue(leftIdx)
+ val leftOriginalHash = getHash(leftIdx)
+ if ((bitpos & bm.dataMap) != 0) {
+ // left data and right data
+ val rightKey = bm.getKey(rightIdx)
+ val rightValue = bm.getValue(rightIdx)
+ val rightOriginalHash = bm.getHash(rightIdx)
+ if (leftOriginalHash == rightOriginalHash && leftKey == rightKey) {
+ builder.addOne(mergef((leftKey, leftValue), (rightKey, rightValue)))
+ } else {
+ builder.addOne(leftKey, leftValue, leftOriginalHash)
+ builder.addOne(rightKey, rightValue, rightOriginalHash)
+ }
+ rightIdx += 1
+ } else if ((bitpos & bm.nodeMap) != 0) {
+ // left data and right node
+ val subNode = bm.getNode(bm.nodeIndex(bitpos))
+ val leftImprovedHash = improve(leftOriginalHash)
+ val removed = subNode.removed(leftKey, leftOriginalHash, leftImprovedHash, shift + BitPartitionSize)
+ if (removed eq subNode) {
+ // no overlap in leftData and rightNode, just build both children to builder
+ subNode.buildTo(builder)
+ builder.addOne(leftKey, leftValue, leftOriginalHash, leftImprovedHash)
+ } else {
+ // there is collision, so special treatment for that key
+ removed.buildTo(builder)
+ builder.addOne(mergef((leftKey, leftValue), subNode.getTuple(leftKey, leftOriginalHash, leftImprovedHash, shift + BitPartitionSize)))
+ }
+ } else {
+ // left data and nothing on right
+ builder.addOne(leftKey, leftValue, leftOriginalHash)
+ }
+ leftIdx += 1
+ } else if ((bitpos & nodeMap) != 0) {
+ if ((bitpos & bm.dataMap) != 0) {
+ // left node and right data
+ val rightKey = bm.getKey(rightIdx)
+ val rightValue = bm.getValue(rightIdx)
+ val rightOriginalHash = bm.getHash(rightIdx)
+ val rightImprovedHash = improve(rightOriginalHash)
+
+ val subNode = getNode(nodeIndex(bitpos))
+ val removed = subNode.removed(rightKey, rightOriginalHash, rightImprovedHash, shift + BitPartitionSize)
+ if (removed eq subNode) {
+ // no overlap in leftNode and rightData, just build both children to builder
+ subNode.buildTo(builder)
+ builder.addOne(rightKey, rightValue, rightOriginalHash, rightImprovedHash)
+ } else {
+ // there is collision, so special treatment for that key
+ removed.buildTo(builder)
+ builder.addOne(mergef(subNode.getTuple(rightKey, rightOriginalHash, rightImprovedHash, shift + BitPartitionSize), (rightKey, rightValue)))
+ }
+ rightIdx += 1
+
+ } else if ((bitpos & bm.nodeMap) != 0) {
+ // left node and right node
+ getNode(nodeIndex(bitpos)).mergeInto(bm.getNode(bm.nodeIndex(bitpos)), builder, shift + BitPartitionSize)(mergef)
+ } else {
+ // left node and nothing on right
+ getNode(nodeIndex(bitpos)).buildTo(builder)
+ }
+ } else if ((bitpos & bm.dataMap) != 0) {
+ // nothing on left, right data
+ val dataIndex = bm.dataIndex(bitpos)
+ builder.addOne(bm.getKey(dataIndex),bm.getValue(dataIndex), bm.getHash(dataIndex))
+ rightIdx += 1
+
+ } else if ((bitpos & bm.nodeMap) != 0) {
+ // nothing on left, right node
+ bm.getNode(bm.nodeIndex(bitpos)).buildTo(builder)
+ }
+
+ index += 1
+ }
+ }
+ case _: HashCollisionMapNode[_, _] =>
+ throw new RuntimeException("Cannot merge BitmapIndexedMapNode with HashCollisionMapNode")
+ }
+
+ override def equals(that: Any): Boolean =
+ that match {
+ case node: BitmapIndexedMapNode[_, _] =>
+ (this eq node) ||
+ (this.cachedJavaKeySetHashCode == node.cachedJavaKeySetHashCode) &&
+ (this.nodeMap == node.nodeMap) &&
+ (this.dataMap == node.dataMap) &&
+ (this.size == node.size) &&
+ java.util.Arrays.equals(this.originalHashes, node.originalHashes) &&
+ deepContentEquality(this.content, node.content, content.length)
+ case _ => false
+ }
+
+ @inline private def deepContentEquality(a1: Array[Any], a2: Array[Any], length: Int): Boolean = {
+ if (a1 eq a2)
+ true
+ else {
+ var isEqual = true
+ var i = 0
+
+ while (isEqual && i < length) {
+ isEqual = a1(i) == a2(i)
+ i += 1
+ }
+
+ isEqual
+ }
+ }
+
+ override def hashCode(): Int =
+ throw new UnsupportedOperationException("Trie nodes do not support hashing.")
+
+ override def concat[V1 >: V](that: MapNode[K, V1], shift: Int): BitmapIndexedMapNode[K, V1] = that match {
+ case bm: BitmapIndexedMapNode[K, V] @unchecked =>
+ if (size == 0) return bm
+ else if (bm.size == 0 || (bm eq this)) return this
+ else if (bm.size == 1) {
+ val originalHash = bm.getHash(0)
+ return this.updated(bm.getKey(0), bm.getValue(0), originalHash, improve(originalHash), shift, replaceValue = true)
+ }
+ // if we go through the merge and the result does not differ from `bm`, we can just return `bm`, to improve sharing
+ // So, `anyChangesMadeSoFar` will be set to `true` as soon as we encounter a difference between the
+ // currently-being-computed result, and `bm`
+ var anyChangesMadeSoFar = false
+
+ val allMap = dataMap | bm.dataMap | nodeMap | bm.nodeMap
+
+ // minimumIndex is inclusive -- it is the first index for which there is data or nodes
+ val minimumBitPos: Int = Node.bitposFrom(Integer.numberOfTrailingZeros(allMap))
+ // maximumIndex is inclusive -- it is the last index for which there is data or nodes
+ // it could not be exclusive, because then upper bound in worst case (Node.BranchingFactor) would be out-of-bound
+ // of int bitposition representation
+ val maximumBitPos: Int = Node.bitposFrom(Node.BranchingFactor - Integer.numberOfLeadingZeros(allMap) - 1)
+
+ var leftNodeRightNode = 0
+ var leftDataRightNode = 0
+ var leftNodeRightData = 0
+ var leftDataOnly = 0
+ var rightDataOnly = 0
+ var leftNodeOnly = 0
+ var rightNodeOnly = 0
+ var leftDataRightDataMigrateToNode = 0
+ var leftDataRightDataRightOverwrites = 0
+
+ var dataToNodeMigrationTargets = 0
+
+ {
+ var bitpos = minimumBitPos
+ var leftIdx = 0
+ var rightIdx = 0
+ var finished = false
+
+ while (!finished) {
+
+ if ((bitpos & dataMap) != 0) {
+ if ((bitpos & bm.dataMap) != 0) {
+ val leftOriginalHash = getHash(leftIdx)
+ if (leftOriginalHash == bm.getHash(rightIdx) && getKey(leftIdx) == bm.getKey(rightIdx)) {
+ leftDataRightDataRightOverwrites |= bitpos
+ } else {
+ leftDataRightDataMigrateToNode |= bitpos
+ dataToNodeMigrationTargets |= Node.bitposFrom(Node.maskFrom(improve(leftOriginalHash), shift))
+ }
+ rightIdx += 1
+ } else if ((bitpos & bm.nodeMap) != 0) {
+ leftDataRightNode |= bitpos
+ } else {
+ leftDataOnly |= bitpos
+ }
+ leftIdx += 1
+ } else if ((bitpos & nodeMap) != 0) {
+ if ((bitpos & bm.dataMap) != 0) {
+ leftNodeRightData |= bitpos
+ rightIdx += 1
+ } else if ((bitpos & bm.nodeMap) != 0) {
+ leftNodeRightNode |= bitpos
+ } else {
+ leftNodeOnly |= bitpos
+ }
+ } else if ((bitpos & bm.dataMap) != 0) {
+ rightDataOnly |= bitpos
+ rightIdx += 1
+ } else if ((bitpos & bm.nodeMap) != 0) {
+ rightNodeOnly |= bitpos
+ }
+
+ if (bitpos == maximumBitPos) {
+ finished = true
+ } else {
+ bitpos = bitpos << 1
+ }
+ }
+ }
+
+
+ val newDataMap = leftDataOnly | rightDataOnly | leftDataRightDataRightOverwrites
+
+ val newNodeMap =
+ leftNodeRightNode |
+ leftDataRightNode |
+ leftNodeRightData |
+ leftNodeOnly |
+ rightNodeOnly |
+ dataToNodeMigrationTargets
+
+
+ if ((newDataMap == (rightDataOnly | leftDataRightDataRightOverwrites)) && (newNodeMap == rightNodeOnly)) {
+ // nothing from `this` will make it into the result -- return early
+ return bm
+ }
+
+ val newDataSize = bitCount(newDataMap)
+ val newContentSize = (MapNode.TupleLength * newDataSize) + bitCount(newNodeMap)
+
+ val newContent = new Array[Any](newContentSize)
+ val newOriginalHashes = new Array[Int](newDataSize)
+ var newSize = 0
+ var newCachedHashCode = 0
+
+ {
+ var leftDataIdx = 0
+ var rightDataIdx = 0
+ var leftNodeIdx = 0
+ var rightNodeIdx = 0
+
+ val nextShift = shift + Node.BitPartitionSize
+
+ var compressedDataIdx = 0
+ var compressedNodeIdx = 0
+
+ var bitpos = minimumBitPos
+ var finished = false
+
+ while (!finished) {
+
+ if ((bitpos & leftNodeRightNode) != 0) {
+ val rightNode = bm.getNode(rightNodeIdx)
+ val newNode = getNode(leftNodeIdx).concat(rightNode, nextShift)
+ if (rightNode ne newNode) {
+ anyChangesMadeSoFar = true
+ }
+ newContent(newContentSize - compressedNodeIdx - 1) = newNode
+ compressedNodeIdx += 1
+ rightNodeIdx += 1
+ leftNodeIdx += 1
+ newSize += newNode.size
+ newCachedHashCode += newNode.cachedJavaKeySetHashCode
+
+ } else if ((bitpos & leftDataRightNode) != 0) {
+ val newNode = {
+ val n = bm.getNode(rightNodeIdx)
+ val leftKey = getKey(leftDataIdx)
+ val leftValue = getValue(leftDataIdx)
+ val leftOriginalHash = getHash(leftDataIdx)
+ val leftImproved = improve(leftOriginalHash)
+
+ val updated = n.updated(leftKey, leftValue, leftOriginalHash, leftImproved, nextShift, replaceValue = false)
+
+ if (updated ne n) {
+ anyChangesMadeSoFar = true
+ }
+
+ updated
+ }
+
+ newContent(newContentSize - compressedNodeIdx - 1) = newNode
+ compressedNodeIdx += 1
+ rightNodeIdx += 1
+ leftDataIdx += 1
+ newSize += newNode.size
+ newCachedHashCode += newNode.cachedJavaKeySetHashCode
+ }
+ else if ((bitpos & leftNodeRightData) != 0) {
+ anyChangesMadeSoFar = true
+ val newNode = {
+ val rightOriginalHash = bm.getHash(rightDataIdx)
+ getNode(leftNodeIdx).updated(
+ key = bm.getKey(rightDataIdx),
+ value = bm.getValue(rightDataIdx),
+ originalHash = bm.getHash(rightDataIdx),
+ hash = improve(rightOriginalHash),
+ shift = nextShift,
+ replaceValue = true
+ )
+ }
+
+ newContent(newContentSize - compressedNodeIdx - 1) = newNode
+ compressedNodeIdx += 1
+ leftNodeIdx += 1
+ rightDataIdx += 1
+ newSize += newNode.size
+ newCachedHashCode += newNode.cachedJavaKeySetHashCode
+
+ } else if ((bitpos & leftDataOnly) != 0) {
+ anyChangesMadeSoFar = true
+ val originalHash = originalHashes(leftDataIdx)
+ newContent(MapNode.TupleLength * compressedDataIdx) = getKey(leftDataIdx).asInstanceOf[AnyRef]
+ newContent(MapNode.TupleLength * compressedDataIdx + 1) = getValue(leftDataIdx).asInstanceOf[AnyRef]
+ newOriginalHashes(compressedDataIdx) = originalHash
+
+ compressedDataIdx += 1
+ leftDataIdx += 1
+ newSize += 1
+ newCachedHashCode += improve(originalHash)
+ } else if ((bitpos & rightDataOnly) != 0) {
+ val originalHash = bm.originalHashes(rightDataIdx)
+ newContent(MapNode.TupleLength * compressedDataIdx) = bm.getKey(rightDataIdx).asInstanceOf[AnyRef]
+ newContent(MapNode.TupleLength * compressedDataIdx + 1) = bm.getValue(rightDataIdx).asInstanceOf[AnyRef]
+ newOriginalHashes(compressedDataIdx) = originalHash
+
+ compressedDataIdx += 1
+ rightDataIdx += 1
+ newSize += 1
+ newCachedHashCode += improve(originalHash)
+ } else if ((bitpos & leftNodeOnly) != 0) {
+ anyChangesMadeSoFar = true
+ val newNode = getNode(leftNodeIdx)
+ newContent(newContentSize - compressedNodeIdx - 1) = newNode
+ compressedNodeIdx += 1
+ leftNodeIdx += 1
+ newSize += newNode.size
+ newCachedHashCode += newNode.cachedJavaKeySetHashCode
+ } else if ((bitpos & rightNodeOnly) != 0) {
+ val newNode = bm.getNode(rightNodeIdx)
+ newContent(newContentSize - compressedNodeIdx - 1) = newNode
+ compressedNodeIdx += 1
+ rightNodeIdx += 1
+ newSize += newNode.size
+ newCachedHashCode += newNode.cachedJavaKeySetHashCode
+ } else if ((bitpos & leftDataRightDataMigrateToNode) != 0) {
+ anyChangesMadeSoFar = true
+ val newNode = {
+ val leftOriginalHash = getHash(leftDataIdx)
+ val rightOriginalHash = bm.getHash(rightDataIdx)
+
+ bm.mergeTwoKeyValPairs(
+ getKey(leftDataIdx), getValue(leftDataIdx), leftOriginalHash, improve(leftOriginalHash),
+ bm.getKey(rightDataIdx), bm.getValue(rightDataIdx), rightOriginalHash, improve(rightOriginalHash),
+ nextShift
+ )
+ }
+
+ newContent(newContentSize - compressedNodeIdx - 1) = newNode
+ compressedNodeIdx += 1
+ leftDataIdx += 1
+ rightDataIdx += 1
+ newSize += newNode.size
+ newCachedHashCode += newNode.cachedJavaKeySetHashCode
+ } else if ((bitpos & leftDataRightDataRightOverwrites) != 0) {
+ val originalHash = bm.originalHashes(rightDataIdx)
+ newContent(MapNode.TupleLength * compressedDataIdx) = bm.getKey(rightDataIdx).asInstanceOf[AnyRef]
+ newContent(MapNode.TupleLength * compressedDataIdx + 1) = bm.getValue(rightDataIdx).asInstanceOf[AnyRef]
+ newOriginalHashes(compressedDataIdx) = originalHash
+
+ compressedDataIdx += 1
+ rightDataIdx += 1
+ newSize += 1
+ newCachedHashCode += improve(originalHash)
+ leftDataIdx += 1
+ }
+
+ if (bitpos == maximumBitPos) {
+ finished = true
+ } else {
+ bitpos = bitpos << 1
+ }
+ }
+ }
+
+ if (anyChangesMadeSoFar)
+ new BitmapIndexedMapNode(
+ dataMap = newDataMap,
+ nodeMap = newNodeMap,
+ content = newContent,
+ originalHashes = newOriginalHashes,
+ size = newSize,
+ cachedJavaKeySetHashCode = newCachedHashCode
+ )
+ else bm
+
+ case _ =>
+ // should never happen -- hash collisions are never at the same level as bitmapIndexedMapNodes
+ throw new UnsupportedOperationException("Cannot concatenate a HashCollisionMapNode with a BitmapIndexedMapNode")
+ }
+
+ override def copy(): BitmapIndexedMapNode[K, V] = {
+ val contentClone = content.clone()
+ val contentLength = contentClone.length
+ var i = bitCount(dataMap) * TupleLength
+ while (i < contentLength) {
+ contentClone(i) = contentClone(i).asInstanceOf[MapNode[K, V]].copy()
+ i += 1
+ }
+ new BitmapIndexedMapNode[K, V](dataMap, nodeMap, contentClone, originalHashes.clone(), size, cachedJavaKeySetHashCode)
+ }
+
+ override def filterImpl(pred: ((K, V)) => Boolean, flipped: Boolean): BitmapIndexedMapNode[K, V] = {
+ if (size == 0) this
+ else if (size == 1) {
+ if (pred(getPayload(0)) != flipped) this else MapNode.empty
+ } else if (nodeMap == 0) {
+ // Performance optimization for nodes of depth 1:
+ //
+ // this node has no "node" children, all children are inlined data elems, therefor logic is significantly simpler
+ // approach:
+ // * traverse the content array, accumulating in `newDataMap: Int` any bit positions of keys which pass the filter
+ // * (bitCount(newDataMap) * TupleLength) tells us the new content array and originalHashes array size, so now perform allocations
+ // * traverse the content array once more, placing each passing element (according to `newDatamap`) in the new content and originalHashes arrays
+ //
+ // note:
+ // * this optimization significantly improves performance of not only small trees, but also larger trees, since
+ // even non-root nodes are affected by this improvement, and large trees will consist of many nodes as
+ // descendants
+ //
+ val minimumIndex: Int = Integer.numberOfTrailingZeros(dataMap)
+ val maximumIndex: Int = Node.BranchingFactor - Integer.numberOfLeadingZeros(dataMap)
+
+ var newDataMap = 0
+ var newCachedHashCode = 0
+ var dataIndex = 0
+
+ var i = minimumIndex
+
+ while(i < maximumIndex) {
+ val bitpos = bitposFrom(i)
+
+ if ((bitpos & dataMap) != 0) {
+ val payload = getPayload(dataIndex)
+ val passed = pred(payload) != flipped
+
+ if (passed) {
+ newDataMap |= bitpos
+ newCachedHashCode += improve(getHash(dataIndex))
+ }
+
+ dataIndex += 1
+ }
+
+ i += 1
+ }
+
+ if (newDataMap == 0) {
+ MapNode.empty
+ } else if (newDataMap == dataMap) {
+ this
+ } else {
+ val newSize = Integer.bitCount(newDataMap)
+ val newContent = new Array[Any](newSize * TupleLength)
+ val newOriginalHashCodes = new Array[Int](newSize)
+ val newMaximumIndex: Int = Node.BranchingFactor - Integer.numberOfLeadingZeros(newDataMap)
+
+ var j = Integer.numberOfTrailingZeros(newDataMap)
+
+ var newDataIndex = 0
+
+
+ while (j < newMaximumIndex) {
+ val bitpos = bitposFrom(j)
+ if ((bitpos & newDataMap) != 0) {
+ val oldIndex = indexFrom(dataMap, bitpos)
+ newContent(newDataIndex * TupleLength) = content(oldIndex * TupleLength)
+ newContent(newDataIndex * TupleLength + 1) = content(oldIndex * TupleLength + 1)
+ newOriginalHashCodes(newDataIndex) = originalHashes(oldIndex)
+ newDataIndex += 1
+ }
+ j += 1
+ }
+
+ new BitmapIndexedMapNode(newDataMap, 0, newContent, newOriginalHashCodes, newSize, newCachedHashCode)
+ }
+
+
+ } else {
+ val allMap = dataMap | nodeMap
+ val minimumIndex: Int = Integer.numberOfTrailingZeros(allMap)
+ val maximumIndex: Int = Node.BranchingFactor - Integer.numberOfLeadingZeros(allMap)
+
+ var oldDataPassThrough = 0
+
+ // bitmap of nodes which, when filtered, returned a single-element node. These must be migrated to data
+ var nodeMigrateToDataTargetMap = 0
+ // the queue of single-element, post-filter nodes
+ var nodesToMigrateToData: mutable.Queue[MapNode[K, V]] = null
+
+ // bitmap of all nodes which, when filtered, returned themselves. They are passed forward to the returned node
+ var nodesToPassThroughMap = 0
+
+ // bitmap of any nodes which, after being filtered, returned a node that is not empty, but also not `eq` itself
+ // These are stored for later inclusion into the final `content` array
+ // not named `newNodesMap` (plural) to avoid confusion with `newNodeMap` (singular)
+ var mapOfNewNodes = 0
+ // each bit in `mapOfNewNodes` corresponds to one element in this queue
+ var newNodes: mutable.Queue[MapNode[K, V]] = null
+
+ var newDataMap = 0
+ var newNodeMap = 0
+ var newSize = 0
+ var newCachedHashCode = 0
+
+ var dataIndex = 0
+ var nodeIndex = 0
+
+ var i = minimumIndex
+ while (i < maximumIndex) {
+ val bitpos = bitposFrom(i)
+
+ if ((bitpos & dataMap) != 0) {
+ val payload = getPayload(dataIndex)
+ val passed = pred(payload) != flipped
+
+ if (passed) {
+ newDataMap |= bitpos
+ oldDataPassThrough |= bitpos
+ newSize += 1
+ newCachedHashCode += improve(getHash(dataIndex))
+ }
+
+ dataIndex += 1
+ } else if ((bitpos & nodeMap) != 0) {
+ val oldSubNode = getNode(nodeIndex)
+ val newSubNode = oldSubNode.filterImpl(pred, flipped)
+
+ newSize += newSubNode.size
+ newCachedHashCode += newSubNode.cachedJavaKeySetHashCode
+
+ // if (newSubNode.size == 0) do nothing (drop it)
+ if (newSubNode.size > 1) {
+ newNodeMap |= bitpos
+ if (oldSubNode eq newSubNode) {
+ nodesToPassThroughMap |= bitpos
+ } else {
+ mapOfNewNodes |= bitpos
+ if (newNodes eq null) {
+ newNodes = mutable.Queue.empty
+ }
+ newNodes += newSubNode
+ }
+ } else if (newSubNode.size == 1) {
+ newDataMap |= bitpos
+ nodeMigrateToDataTargetMap |= bitpos
+ if (nodesToMigrateToData eq null) {
+ nodesToMigrateToData = mutable.Queue()
+ }
+ nodesToMigrateToData += newSubNode
+ }
+
+ nodeIndex += 1
+ }
+
+ i += 1
+ }
+
+ if (newSize == 0) {
+ MapNode.empty
+ } else if (newSize == size) {
+ this
+ } else {
+ val newDataSize = bitCount(newDataMap)
+ val newContentSize = (MapNode.TupleLength * newDataSize) + bitCount(newNodeMap)
+ val newContent = new Array[Any](newContentSize)
+ val newOriginalHashes = new Array[Int](newDataSize)
+
+ val newAllMap = newDataMap | newNodeMap
+ val maxIndex = Node.BranchingFactor - Integer.numberOfLeadingZeros(newAllMap)
+
+ // note: We MUST start from the minimum index in the old (`this`) node, otherwise `old{Node,Data}Index` will
+ // not be incremented properly. Otherwise we could have started at Integer.numberOfTrailingZeroes(newAllMap)
+ var i = minimumIndex
+
+ var oldDataIndex = 0
+ var oldNodeIndex = 0
+
+ var newDataIndex = 0
+ var newNodeIndex = 0
+
+ while (i < maxIndex) {
+ val bitpos = bitposFrom(i)
+
+ if ((bitpos & oldDataPassThrough) != 0) {
+ newContent(newDataIndex * TupleLength) = getKey(oldDataIndex)
+ newContent(newDataIndex * TupleLength + 1) = getValue(oldDataIndex)
+ newOriginalHashes(newDataIndex) = getHash(oldDataIndex)
+ newDataIndex += 1
+ oldDataIndex += 1
+ } else if ((bitpos & nodesToPassThroughMap) != 0) {
+ newContent(newContentSize - newNodeIndex - 1) = getNode(oldNodeIndex)
+ newNodeIndex += 1
+ oldNodeIndex += 1
+ } else if ((bitpos & nodeMigrateToDataTargetMap) != 0) {
+ // we need not check for null here. If nodeMigrateToDataTargetMap != 0, then nodesMigrateToData must not be null
+ val node = nodesToMigrateToData.dequeue()
+ newContent(TupleLength * newDataIndex) = node.getKey(0)
+ newContent(TupleLength * newDataIndex + 1) = node.getValue(0)
+ newOriginalHashes(newDataIndex) = node.getHash(0)
+ newDataIndex += 1
+ oldNodeIndex += 1
+ } else if ((bitpos & mapOfNewNodes) != 0) {
+ newContent(newContentSize - newNodeIndex - 1) = newNodes.dequeue()
+ newNodeIndex += 1
+ oldNodeIndex += 1
+ } else if ((bitpos & dataMap) != 0) {
+ oldDataIndex += 1
+ } else if ((bitpos & nodeMap) != 0) {
+ oldNodeIndex += 1
+ }
+
+ i += 1
+ }
+
+ new BitmapIndexedMapNode[K, V](newDataMap, newNodeMap, newContent, newOriginalHashes, newSize, newCachedHashCode)
+ }
+ }
+ }
+}
+
+private final class HashCollisionMapNode[K, +V ](
+ val originalHash: Int,
+ val hash: Int,
+ var content: Vector[(K, V @uV)]
+ ) extends MapNode[K, V] {
+
+ import Node._
+
+ require(content.length >= 2)
+
+ releaseFence()
+
+ private[immutable] def indexOf(key: Any): Int = {
+ val iter = content.iterator
+ var i = 0
+ while (iter.hasNext) {
+ if (iter.next()._1 == key) return i
+ i += 1
+ }
+ -1
+ }
+
+ def size: Int = content.length
+
+ def apply(key: K, originalHash: Int, hash: Int, shift: Int): V = get(key, originalHash, hash, shift).getOrElse(Iterator.empty.next())
+
+ def get(key: K, originalHash: Int, hash: Int, shift: Int): Option[V] =
+ if (this.hash == hash) {
+ val index = indexOf(key)
+ if (index >= 0) Some(content(index)._2) else None
+ } else None
+
+ override def getTuple(key: K, originalHash: Int, hash: Int, shift: Int): (K, V) = {
+ val index = indexOf(key)
+ if (index >= 0) content(index) else Iterator.empty.next()
+ }
+
+ def getOrElse[V1 >: V](key: K, originalHash: Int, hash: Int, shift: Int, f: => V1): V1 = {
+ if (this.hash == hash) {
+ indexOf(key) match {
+ case -1 => f
+ case other => content(other)._2
+ }
+ } else f
+ }
+
+ override def containsKey(key: K, originalHash: Int, hash: Int, shift: Int): Boolean =
+ this.hash == hash && indexOf(key) >= 0
+
+ def contains[V1 >: V](key: K, value: V1, hash: Int, shift: Int): Boolean =
+ this.hash == hash && {
+ val index = indexOf(key)
+ index >= 0 && (content(index)._2.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef])
+ }
+
+ def updated[V1 >: V](key: K, value: V1, originalHash: Int, hash: Int, shift: Int, replaceValue: Boolean): MapNode[K, V1] = {
+ val index = indexOf(key)
+ if (index >= 0) {
+ if (replaceValue) {
+ if (content(index)._2.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef]) {
+ this
+ } else {
+ new HashCollisionMapNode[K, V1](originalHash, hash, content.updated[(K, V1)](index, (key, value)))
+ }
+ } else {
+ this
+ }
+ } else {
+ new HashCollisionMapNode[K, V1](originalHash, hash, content.appended[(K, V1)]((key, value)))
+ }
+ }
+
+ def removed[V1 >: V](key: K, originalHash: Int, hash: Int, shift: Int): MapNode[K, V1] = {
+ if (!this.containsKey(key, originalHash, hash, shift)) {
+ this
+ } else {
+ val updatedContent = content.filterNot(keyValuePair => keyValuePair._1 == key)
+ // assert(updatedContent.size == content.size - 1)
+
+ updatedContent.size match {
+ case 1 =>
+ val (k, v) = updatedContent(0)
+ new BitmapIndexedMapNode[K, V1](bitposFrom(maskFrom(hash, 0)), 0, Array(k, v), Array(originalHash), 1, hash)
+ case _ => new HashCollisionMapNode[K, V1](originalHash, hash, updatedContent)
+ }
+ }
+ }
+
+ def hasNodes: Boolean = false
+
+ def nodeArity: Int = 0
+
+ def getNode(index: Int): MapNode[K, V] =
+ throw new IndexOutOfBoundsException("No sub-nodes present in hash-collision leaf node.")
+
+ def hasPayload: Boolean = true
+
+ def payloadArity: Int = content.length
+
+ def getKey(index: Int): K = getPayload(index)._1
+ def getValue(index: Int): V = getPayload(index)._2
+
+ def getPayload(index: Int): (K, V) = content(index)
+
+ override def getHash(index: Int): Int = originalHash
+
+ def foreach[U](f: ((K, V)) => U): Unit = content.foreach(f)
+
+ def foreachEntry[U](f: (K, V) => U): Unit = content.foreach { case (k, v) => f(k, v)}
+
+ override def foreachWithHash(f: (K, V, Int) => Unit): Unit = {
+ val iter = content.iterator
+ while (iter.hasNext) {
+ val next = iter.next()
+ f(next._1, next._2, originalHash)
+ }
+ }
+
+ override def transform[W](f: (K, V) => W): HashCollisionMapNode[K, W] = {
+ val newContent = Vector.newBuilder[(K, W)]
+ val contentIter = content.iterator
+ // true if any values have been transformed to a different value via `f`
+ var anyChanges = false
+ while(contentIter.hasNext) {
+ val (k, v) = contentIter.next()
+ val newValue = f(k, v)
+ newContent.addOne((k, newValue))
+ anyChanges ||= (v.asInstanceOf[AnyRef] ne newValue.asInstanceOf[AnyRef])
+ }
+ if (anyChanges) new HashCollisionMapNode(originalHash, hash, newContent.result())
+ else this.asInstanceOf[HashCollisionMapNode[K, W]]
+ }
+
+ override def equals(that: Any): Boolean =
+ that match {
+ case node: HashCollisionMapNode[_, _] =>
+ (this eq node) ||
+ (this.hash == node.hash) &&
+ (this.content.length == node.content.length) && {
+ val iter = content.iterator
+ while (iter.hasNext) {
+ val (key, value) = iter.next()
+ val index = node.indexOf(key)
+ if (index < 0 || value != node.content(index)._2) {
+ return false
+ }
+ }
+ true
+ }
+ case _ => false
+ }
+
+ override def concat[V1 >: V](that: MapNode[K, V1], shift: Int): HashCollisionMapNode[K, V1] = that match {
+ case hc: HashCollisionMapNode[K, V1] =>
+ if (hc eq this) {
+ this
+ } else {
+ var newContent: VectorBuilder[(K, V1)] = null
+ val iter = content.iterator
+ while (iter.hasNext) {
+ val nextPayload = iter.next()
+ if (hc.indexOf(nextPayload._1) < 0) {
+ if (newContent eq null) {
+ newContent = new VectorBuilder[(K, V1)]()
+ newContent.addAll(hc.content)
+ }
+ newContent.addOne(nextPayload)
+ }
+ }
+ if (newContent eq null) hc else new HashCollisionMapNode(originalHash, hash, newContent.result())
+ }
+ case _: BitmapIndexedMapNode[K, V1] =>
+ // should never happen -- hash collisions are never at the same level as bitmapIndexedMapNodes
+ throw new UnsupportedOperationException("Cannot concatenate a HashCollisionMapNode with a BitmapIndexedMapNode")
+ }
+
+
+ override def mergeInto[V1 >: V](that: MapNode[K, V1], builder: HashMapBuilder[K, V1], shift: Int)(mergef: ((K, V), (K, V1)) => (K, V1)): Unit = that match {
+ case hc: HashCollisionMapNode[K, V1] =>
+ val iter = content.iterator
+ val rightArray = hc.content.toArray[AnyRef] // really Array[(K, V1)]
+
+ def rightIndexOf(key: K): Int = {
+ var i = 0
+ while (i < rightArray.length) {
+ val elem = rightArray(i)
+ if ((elem ne null) && (elem.asInstanceOf[(K, V1)])._1 == key) return i
+ i += 1
+ }
+ -1
+ }
+
+ while (iter.hasNext) {
+ val nextPayload = iter.next()
+ val index = rightIndexOf(nextPayload._1)
+
+ if (index == -1) {
+ builder.addOne(nextPayload)
+ } else {
+ val rightPayload = rightArray(index).asInstanceOf[(K, V1)]
+ rightArray(index) = null
+
+ builder.addOne(mergef(nextPayload, rightPayload))
+ }
+ }
+
+ var i = 0
+ while (i < rightArray.length) {
+ val elem = rightArray(i)
+ if (elem ne null) builder.addOne(elem.asInstanceOf[(K, V1)])
+ i += 1
+ }
+ case _: BitmapIndexedMapNode[K, V1] =>
+ throw new RuntimeException("Cannot merge HashCollisionMapNode with BitmapIndexedMapNode")
+
+ }
+
+ override def buildTo[V1 >: V](builder: HashMapBuilder[K, V1]): Unit = {
+ val iter = content.iterator
+ while (iter.hasNext) {
+ val (k, v) = iter.next()
+ builder.addOne(k, v, originalHash, hash)
+ }
+ }
+
+ override def filterImpl(pred: ((K, V)) => Boolean, flipped: Boolean): MapNode[K, V] = {
+ val newContent = content.filterImpl(pred, flipped)
+ val newContentLength = newContent.length
+ if (newContentLength == 0) {
+ MapNode.empty
+ } else if (newContentLength == 1) {
+ val (k, v) = newContent.head
+ new BitmapIndexedMapNode[K, V](bitposFrom(maskFrom(hash, 0)), 0, Array(k, v), Array(originalHash), 1, hash)
+ } else if (newContentLength == content.length) this
+ else new HashCollisionMapNode(originalHash, hash, newContent)
+ }
+
+ override def copy(): HashCollisionMapNode[K, V] = new HashCollisionMapNode[K, V](originalHash, hash, content)
+
+ override def hashCode(): Int =
+ throw new UnsupportedOperationException("Trie nodes do not support hashing.")
+
+ override def cachedJavaKeySetHashCode: Int = size * hash
+
+}
+
+private final class MapKeyIterator[K, V](rootNode: MapNode[K, V])
+ extends ChampBaseIterator[K, MapNode[K, V]](rootNode) {
+
+ def next() = {
+ if (!hasNext) Iterator.empty.next()
+
+ val key = currentValueNode.getKey(currentValueCursor)
+ currentValueCursor += 1
+
+ key
+ }
+
+}
+
+private final class MapValueIterator[K, V](rootNode: MapNode[K, V])
+ extends ChampBaseIterator[V, MapNode[K, V]](rootNode) {
+
+ def next() = {
+ if (!hasNext) Iterator.empty.next()
+
+ val value = currentValueNode.getValue(currentValueCursor)
+ currentValueCursor += 1
+
+ value
+ }
+}
+
+private final class MapKeyValueTupleIterator[K, V](rootNode: MapNode[K, V])
+ extends ChampBaseIterator[(K, V), MapNode[K, V]](rootNode) {
+
+ def next() = {
+ if (!hasNext) Iterator.empty.next()
+
+ val payload = currentValueNode.getPayload(currentValueCursor)
+ currentValueCursor += 1
+
+ payload
+ }
+
+}
+
+private final class MapKeyValueTupleReverseIterator[K, V](rootNode: MapNode[K, V])
+ extends ChampBaseReverseIterator[(K, V), MapNode[K, V]](rootNode) {
+
+ def next() = {
+ if (!hasNext) Iterator.empty.next()
+
+ val payload = currentValueNode.getPayload(currentValueCursor)
+ currentValueCursor -= 1
+
+ payload
+ }
+}
+
+private final class MapKeyValueTupleHashIterator[K, V](rootNode: MapNode[K, V])
+ extends ChampBaseReverseIterator[Any, MapNode[K, V]](rootNode) {
+ private[this] var hash = 0
+ private[this] var value: V = _
+ override def hashCode(): Int = MurmurHash3.tuple2Hash(hash, value.##, MurmurHash3.productSeed)
+ def next(): MapKeyValueTupleHashIterator[K, V] = {
+ if (!hasNext) Iterator.empty.next()
+
+ hash = currentValueNode.getHash(currentValueCursor)
+ value = currentValueNode.getValue(currentValueCursor)
+ currentValueCursor -= 1
+ this
+ }
+}
+
+/** Used in HashMap[K, V]#removeAll(HashSet[K]) */
+private final class MapNodeRemoveAllSetNodeIterator[K](rootSetNode: SetNode[K]) extends ChampBaseIterator[K, SetNode[K]](rootSetNode) {
+ /** Returns the result of immutably removing all keys in `rootSetNode` from `rootMapNode` */
+ def removeAll[V](rootMapNode: BitmapIndexedMapNode[K, V]): BitmapIndexedMapNode[K, V] = {
+ var curr = rootMapNode
+ while (curr.size > 0 && hasNext) {
+ val originalHash = currentValueNode.getHash(currentValueCursor)
+ curr = curr.removed(
+ key = currentValueNode.getPayload(currentValueCursor),
+ keyHash = improve(originalHash),
+ originalHash = originalHash,
+ shift = 0
+ )
+ currentValueCursor += 1
+ }
+ curr
+ }
+
+ override def next(): K = Iterator.empty.next()
+}
+
+/**
+ * $factoryInfo
+ *
+ * @define Coll `immutable.HashMap`
+ * @define coll immutable champ hash map
+ */
+@SerialVersionUID(3L)
+object HashMap extends MapFactory[HashMap] {
+
+ @transient
+ private final val EmptyMap = new HashMap(MapNode.empty)
+
+ def empty[K, V]: HashMap[K, V] =
+ EmptyMap.asInstanceOf[HashMap[K, V]]
+
+ def from[K, V](source: collection.IterableOnce[(K, V)]): HashMap[K, V] =
+ source match {
+ case hs: HashMap[K, V] => hs
+ case _ => (newBuilder[K, V] ++= source).result()
+ }
+
+ /** Create a new Builder which can be reused after calling `result()` without an
+ * intermediate call to `clear()` in order to build multiple related results.
+ */
+ def newBuilder[K, V]: ReusableBuilder[(K, V), HashMap[K, V]] = new HashMapBuilder[K, V]
+}
+
+
+/** A Builder for a HashMap.
+ * $multipleResults
+ */
+private[immutable] final class HashMapBuilder[K, V] extends ReusableBuilder[(K, V), HashMap[K, V]] {
+ import MapNode._
+ import Node._
+
+ private def newEmptyRootNode = new BitmapIndexedMapNode[K, V](0, 0, Array.emptyObjectArray.asInstanceOf[Array[Any]], Array.emptyIntArray, 0, 0)
+
+ /** The last given out HashMap as a return value of `result()`, if any, otherwise null.
+ * Indicates that on next add, the elements should be copied to an identical structure, before continuing
+ * mutations. */
+ private var aliased: HashMap[K, V] = _
+
+ private def isAliased: Boolean = aliased != null
+
+ /** The root node of the partially built hashmap. */
+ private var rootNode: BitmapIndexedMapNode[K, V] = newEmptyRootNode
+
+ private[immutable] def getOrElse[V0 >: V](key: K, value: V0): V0 =
+ if (rootNode.size == 0) value
+ else {
+ val originalHash = key.##
+ rootNode.getOrElse(key, originalHash, improve(originalHash), 0, value)
+ }
+
+ /** Inserts element `elem` into array `as` at index `ix`, shifting right the trailing elems */
+ private[this] def insertElement(as: Array[Int], ix: Int, elem: Int): Array[Int] = {
+ if (ix < 0) throw new ArrayIndexOutOfBoundsException
+ if (ix > as.length) throw new ArrayIndexOutOfBoundsException
+ val result = new Array[Int](as.length + 1)
+ arraycopy(as, 0, result, 0, ix)
+ result(ix) = elem
+ arraycopy(as, ix, result, ix + 1, as.length - ix)
+ result
+ }
+
+ /** Inserts key-value into the bitmapIndexMapNode. Requires that this is a new key-value pair */
+ private[this] def insertValue[V1 >: V](bm: BitmapIndexedMapNode[K, V],bitpos: Int, key: K, originalHash: Int, keyHash: Int, value: V1): Unit = {
+ val dataIx = bm.dataIndex(bitpos)
+ val idx = TupleLength * dataIx
+
+ val src = bm.content
+ val dst = new Array[Any](src.length + TupleLength)
+
+ // copy 'src' and insert 2 element(s) at position 'idx'
+ arraycopy(src, 0, dst, 0, idx)
+ dst(idx) = key
+ dst(idx + 1) = value
+ arraycopy(src, idx, dst, idx + TupleLength, src.length - idx)
+
+ val dstHashes = insertElement(bm.originalHashes, dataIx, originalHash)
+
+ bm.dataMap |= bitpos
+ bm.content = dst
+ bm.originalHashes = dstHashes
+ bm.size += 1
+ bm.cachedJavaKeySetHashCode += keyHash
+ }
+
+ /** Upserts a key/value pair into mapNode, mutably */
+ private[immutable] def update(mapNode: MapNode[K, V], key: K, value: V, originalHash: Int, keyHash: Int, shift: Int): Unit = {
+ mapNode match {
+ case bm: BitmapIndexedMapNode[K, V] =>
+ val mask = maskFrom(keyHash, shift)
+ val bitpos = bitposFrom(mask)
+ if ((bm.dataMap & bitpos) != 0) {
+ val index = indexFrom(bm.dataMap, mask, bitpos)
+ val key0 = bm.getKey(index)
+ val key0UnimprovedHash = bm.getHash(index)
+
+ if (key0UnimprovedHash == originalHash && key0 == key) {
+ bm.content(TupleLength * index + 1) = value
+ } else {
+ val value0 = bm.getValue(index)
+ val key0Hash = improve(key0UnimprovedHash)
+
+ val subNodeNew: MapNode[K, V] =
+ bm.mergeTwoKeyValPairs(key0, value0, key0UnimprovedHash, key0Hash, key, value, originalHash, keyHash, shift + BitPartitionSize)
+
+ bm.migrateFromInlineToNodeInPlace(bitpos, key0Hash, subNodeNew)
+ }
+
+ } else if ((bm.nodeMap & bitpos) != 0) {
+ val index = indexFrom(bm.nodeMap, mask, bitpos)
+ val subNode = bm.getNode(index)
+ val beforeSize = subNode.size
+ val beforeHash = subNode.cachedJavaKeySetHashCode
+ update(subNode, key, value, originalHash, keyHash, shift + BitPartitionSize)
+ bm.size += subNode.size - beforeSize
+ bm.cachedJavaKeySetHashCode += subNode.cachedJavaKeySetHashCode - beforeHash
+ } else {
+ insertValue(bm, bitpos, key, originalHash, keyHash, value)
+ }
+ case hc: HashCollisionMapNode[K, V] =>
+ val index = hc.indexOf(key)
+ if (index < 0) {
+ hc.content = hc.content.appended((key, value))
+ } else {
+ hc.content = hc.content.updated(index, (key, value))
+ }
+ }
+ }
+
+ /** If currently referencing aliased structure, copy elements to new mutable structure */
+ private[this] def ensureUnaliased() = {
+ if (isAliased) copyElems()
+ aliased = null
+ }
+
+ /** Copy elements to new mutable structure */
+ private[this] def copyElems(): Unit = {
+ rootNode = rootNode.copy()
+ }
+
+ override def result(): HashMap[K, V] =
+ if (rootNode.size == 0) {
+ HashMap.empty
+ } else if (aliased != null) {
+ aliased
+ } else {
+ aliased = new HashMap(rootNode)
+ releaseFence()
+ aliased
+ }
+
+ override def addOne(elem: (K, V)): this.type = {
+ ensureUnaliased()
+ val h = elem._1.##
+ val im = improve(h)
+ update(rootNode, elem._1, elem._2, h, im, 0)
+ this
+ }
+
+ def addOne(key: K, value: V): this.type = {
+ ensureUnaliased()
+ val originalHash = key.##
+ update(rootNode, key, value, originalHash, improve(originalHash), 0)
+ this
+ }
+ def addOne(key: K, value: V, originalHash: Int): this.type = {
+ ensureUnaliased()
+ update(rootNode, key, value, originalHash, improve(originalHash), 0)
+ this
+ }
+ def addOne(key: K, value: V, originalHash: Int, hash: Int): this.type = {
+ ensureUnaliased()
+ update(rootNode, key, value, originalHash, hash, 0)
+ this
+ }
+
+ override def addAll(xs: IterableOnce[(K, V)]): this.type = {
+ ensureUnaliased()
+ xs match {
+ case hm: HashMap[K, V] =>
+ new ChampBaseIterator[(K, V), MapNode[K, V]](hm.rootNode) {
+ while(hasNext) {
+ val originalHash = currentValueNode.getHash(currentValueCursor)
+ update(
+ mapNode = rootNode,
+ key = currentValueNode.getKey(currentValueCursor),
+ value = currentValueNode.getValue(currentValueCursor),
+ originalHash = originalHash,
+ keyHash = improve(originalHash),
+ shift = 0
+ )
+ currentValueCursor += 1
+ }
+
+ override def next() = Iterator.empty.next()
+ }
+ case hm: collection.mutable.HashMap[K, V] =>
+ val iter = hm.nodeIterator
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = hm.unimproveHash(next.hash)
+ val hash = improve(originalHash)
+ update(rootNode, next.key, next.value, originalHash, hash, 0)
+ }
+ case lhm: collection.mutable.LinkedHashMap[K, V] =>
+ val iter = lhm.entryIterator
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = lhm.unimproveHash(next.hash)
+ val hash = improve(originalHash)
+ update(rootNode, next.key, next.value, originalHash, hash, 0)
+ }
+ case thatMap: Map[K, V] =>
+ thatMap.foreachEntry((key, value) => addOne(key, value))
+ case other =>
+ val it = other.iterator
+ while(it.hasNext) addOne(it.next())
+ }
+
+ this
+ }
+
+ override def clear(): Unit = {
+ aliased = null
+ if (rootNode.size > 0) {
+ rootNode = newEmptyRootNode
+ }
+ }
+
+ private[collection] def size: Int = rootNode.size
+
+ override def knownSize: Int = rootNode.size
+}
diff --git a/library/src/scala/collection/immutable/HashSet.scala b/library/src/scala/collection/immutable/HashSet.scala
new file mode 100644
index 000000000000..3c72236a5395
--- /dev/null
+++ b/library/src/scala/collection/immutable/HashSet.scala
@@ -0,0 +1,2116 @@
+/*
+ * 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 collection
+package immutable
+
+import java.lang.Integer.{bitCount, numberOfTrailingZeros}
+import java.lang.System.arraycopy
+
+import scala.collection.Hashing.improve
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.generic.DefaultSerializable
+import scala.collection.mutable.ReusableBuilder
+import scala.runtime.Statics.releaseFence
+import scala.util.hashing.MurmurHash3
+
+/** This class implements immutable sets using a Compressed Hash-Array Mapped Prefix-tree.
+ * See paper https://michael.steindorfer.name/publications/oopsla15.pdf for more details.
+ *
+ * @tparam A the type of the elements contained in this hash set.
+ * @define Coll `immutable.HashSet`
+ * @define coll immutable champ hash set
+ */
+final class HashSet[A] private[immutable](private[immutable] val rootNode: BitmapIndexedSetNode[A])
+ extends AbstractSet[A]
+ with StrictOptimizedSetOps[A, HashSet, HashSet[A]]
+ with IterableFactoryDefaults[A, HashSet]
+ with DefaultSerializable {
+
+ def this() = this(SetNode.empty)
+
+ // This release fence is present because rootNode may have previously been mutated during construction.
+ releaseFence()
+
+ private[this] def newHashSetOrThis(newRootNode: BitmapIndexedSetNode[A]): HashSet[A] =
+ if (rootNode eq newRootNode) this else new HashSet(newRootNode)
+
+ override def iterableFactory: IterableFactory[HashSet] = HashSet
+
+ override def knownSize: Int = rootNode.size
+
+ override def size: Int = rootNode.size
+
+ override def isEmpty: Boolean = rootNode.size == 0
+
+ def iterator: Iterator[A] = {
+ if (isEmpty) Iterator.empty
+ else new SetIterator[A](rootNode)
+ }
+
+ protected[immutable] def reverseIterator: Iterator[A] = new SetReverseIterator[A](rootNode)
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit = {
+ import convert.impl._
+ val s = shape.shape match {
+ case StepperShape.IntShape => IntChampStepper.from[ SetNode[A]](size, rootNode, (node, i) => node.getPayload(i).asInstanceOf[Int])
+ case StepperShape.LongShape => LongChampStepper.from[ SetNode[A]](size, rootNode, (node, i) => node.getPayload(i).asInstanceOf[Long])
+ case StepperShape.DoubleShape => DoubleChampStepper.from[SetNode[A]](size, rootNode, (node, i) => node.getPayload(i).asInstanceOf[Double])
+ case _ => shape.parUnbox(AnyChampStepper.from[A, SetNode[A]](size, rootNode, (node, i) => node.getPayload(i)))
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ def contains(element: A): Boolean = {
+ val elementUnimprovedHash = element.##
+ val elementHash = improve(elementUnimprovedHash)
+ rootNode.contains(element, elementUnimprovedHash, elementHash, 0)
+ }
+
+ def incl(element: A): HashSet[A] = {
+ val elementUnimprovedHash = element.##
+ val elementHash = improve(elementUnimprovedHash)
+ val newRootNode = rootNode.updated(element, elementUnimprovedHash, elementHash, 0)
+ newHashSetOrThis(newRootNode)
+ }
+
+ def excl(element: A): HashSet[A] = {
+ val elementUnimprovedHash = element.##
+ val elementHash = improve(elementUnimprovedHash)
+ val newRootNode = rootNode.removed(element, elementUnimprovedHash, elementHash, 0)
+ newHashSetOrThis(newRootNode)
+ }
+
+ override def concat(that: IterableOnce[A]): HashSet[A] =
+ that match {
+ case hs: HashSet[A] =>
+ if (isEmpty) hs
+ else {
+ val newNode = rootNode.concat(hs.rootNode, 0)
+ if (newNode eq hs.rootNode) hs
+ else newHashSetOrThis(newNode)
+ }
+ case hs: collection.mutable.HashSet[A] =>
+ val iter = hs.nodeIterator
+ var current = rootNode
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = hs.unimproveHash(next.hash)
+ val improved = improve(originalHash)
+ current = current.updated(next.key, originalHash, improved, 0)
+
+ if (current ne rootNode) {
+ var shallowlyMutableNodeMap = Node.bitposFrom(Node.maskFrom(improved, 0))
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = hs.unimproveHash(next.hash)
+ val improved = improve(originalHash)
+ shallowlyMutableNodeMap = current.updateWithShallowMutations(next.key, originalHash, improved, 0, shallowlyMutableNodeMap)
+ }
+ return new HashSet(current)
+ }
+ }
+ this
+ case lhs: collection.mutable.LinkedHashSet[A] =>
+ val iter = lhs.entryIterator
+ var current = rootNode
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = lhs.unimproveHash(next.hash)
+ val improved = improve(originalHash)
+ current = current.updated(next.key, originalHash, improved, 0)
+
+ if (current ne rootNode) {
+ var shallowlyMutableNodeMap = Node.bitposFrom(Node.maskFrom(improved, 0))
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = lhs.unimproveHash(next.hash)
+ val improved = improve(originalHash)
+ shallowlyMutableNodeMap = current.updateWithShallowMutations(next.key, originalHash, improved, 0, shallowlyMutableNodeMap)
+ }
+ return new HashSet(current)
+ }
+ }
+ this
+ case _ =>
+ val iter = that.iterator
+ var current = rootNode
+ while (iter.hasNext) {
+ val element = iter.next()
+ val originalHash = element.##
+ val improved = improve(originalHash)
+ current = current.updated(element, originalHash, improved, 0)
+
+ if (current ne rootNode) {
+ // Note: We could have started with shallowlyMutableNodeMap = 0, however this way, in the case that
+ // the first changed key ended up in a subnode beneath root, we mark that root right away as being
+ // shallowly mutable.
+ //
+ // since `element` has just been inserted, and certainly caused a new root node to be created, we can say with
+ // certainty that it either caused a new subnode to be created underneath `current`, in which case we should
+ // carry on mutating that subnode, or it ended up as a child data pair of the root, in which case, no harm is
+ // done by including its bit position in the shallowlyMutableNodeMap anyways.
+ var shallowlyMutableNodeMap = Node.bitposFrom(Node.maskFrom(improved, 0))
+ while (iter.hasNext) {
+ val element = iter.next()
+ val originalHash = element.##
+ val improved = improve(originalHash)
+ shallowlyMutableNodeMap = current.updateWithShallowMutations(element, originalHash, improved, 0, shallowlyMutableNodeMap)
+ }
+ return new HashSet(current)
+ }
+ }
+ this
+ }
+
+ override def tail: HashSet[A] = this - head
+
+ override def init: HashSet[A] = this - last
+
+ override def head: A = iterator.next()
+
+ override def last: A = reverseIterator.next()
+
+ override def foreach[U](f: A => U): Unit = rootNode.foreach(f)
+
+ /** Applies a function f to each element, and its corresponding **original** hash, in this Set */
+ @`inline` private[collection] def foreachWithHash(f: (A, Int) => Unit): Unit = rootNode.foreachWithHash(f)
+
+ /** Applies a function f to each element, and its corresponding **original** hash, in this Set
+ * Stops iterating the first time that f returns `false`.*/
+ @`inline` private[collection] def foreachWithHashWhile(f: (A, Int) => Boolean): Unit = rootNode.foreachWithHashWhile(f)
+
+ // For binary compatibility, the method used to have this signature by mistake.
+ // protected is public in bytecode.
+ protected def subsetOf(that: Set[A]): Boolean = subsetOf(that: collection.Set[A])
+
+ override def subsetOf(that: collection.Set[A]): Boolean = isEmpty || !that.isEmpty && (that match {
+ case set: HashSet[A] => rootNode.subsetOf(set.rootNode, 0)
+ case _ => super.subsetOf(that)
+ })
+
+ override def equals(that: Any): Boolean =
+ that match {
+ case set: HashSet[_] => (this eq set) || (this.rootNode == set.rootNode)
+ case _ => super.equals(that)
+ }
+
+ override protected[this] def className = "HashSet"
+
+ override def hashCode(): Int = {
+ val it = new SetHashIterator(rootNode)
+ val hash = MurmurHash3.unorderedHash(it, MurmurHash3.setSeed)
+ //assert(hash == super.hashCode())
+ hash
+ }
+
+ override def diff(that: collection.Set[A]): HashSet[A] = {
+ if (isEmpty) {
+ this
+ } else {
+ that match {
+ case hashSet: HashSet[A] =>
+ if (hashSet.isEmpty) this else {
+ val newRootNode = rootNode.diff(hashSet.rootNode, 0)
+ if (newRootNode.size == 0) HashSet.empty else newHashSetOrThis(rootNode.diff(hashSet.rootNode, 0))
+ }
+ case hashSet: collection.mutable.HashSet[A] =>
+ val iter = hashSet.nodeIterator
+ var curr = rootNode
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = hashSet.unimproveHash(next.hash)
+ val improved = improve(originalHash)
+ curr = curr.removed(next.key, originalHash, improved, 0)
+ if (curr ne rootNode) {
+ if (curr.size == 0) {
+ return HashSet.empty
+ }
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = hashSet.unimproveHash(next.hash)
+ val improved = improve(originalHash)
+
+ curr.removeWithShallowMutations(next.key, originalHash, improved)
+
+ if (curr.size == 0) {
+ return HashSet.empty
+ }
+ }
+ return new HashSet(curr)
+ }
+ }
+ this
+
+ case other =>
+ val thatKnownSize = other.knownSize
+
+ if (thatKnownSize == 0) {
+ this
+ } else if (thatKnownSize <= size) {
+ /* this branch intentionally includes the case of thatKnownSize == -1. We know that HashSets are quite fast at look-up, so
+ we're likely to be the faster of the two at that. */
+ removedAllWithShallowMutations(other)
+ } else {
+ // TODO: Develop more sophisticated heuristic for which branch to take
+ filterNot(other.contains)
+ }
+ }
+
+ }
+ }
+
+ /** Immutably removes all elements of `that` from this HashSet
+ *
+ * Mutation is used internally, but only on root SetNodes which this method itself creates.
+ *
+ * That is, this method is safe to call on published sets because it does not mutate `this`
+ */
+ private[this] def removedAllWithShallowMutations(that: IterableOnce[A]): HashSet[A] = {
+ val iter = that.iterator
+ var curr = rootNode
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = next.##
+ val improved = improve(originalHash)
+ curr = curr.removed(next, originalHash, improved, 0)
+ if (curr ne rootNode) {
+ if (curr.size == 0) {
+ return HashSet.empty
+ }
+ while (iter.hasNext) {
+ val next = iter.next()
+ val originalHash = next.##
+ val improved = improve(originalHash)
+
+ curr.removeWithShallowMutations(next, originalHash, improved)
+
+ if (curr.size == 0) {
+ return HashSet.empty
+ }
+ }
+ return new HashSet(curr)
+ }
+ }
+ this
+ }
+
+ override def removedAll(that: IterableOnce[A]): HashSet[A] = that match {
+ case set: scala.collection.Set[A] => diff(set)
+ case range: Range if range.length > size =>
+ filter {
+ case i: Int => !range.contains(i)
+ case _ => true
+ }
+
+ case _ =>
+ removedAllWithShallowMutations(that)
+ }
+
+ override def partition(p: A => Boolean): (HashSet[A], HashSet[A]) = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ super.partition(p)
+ }
+
+ override def span(p: A => Boolean): (HashSet[A], HashSet[A]) = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ super.span(p)
+ }
+
+ override protected[collection] def filterImpl(pred: A => Boolean, isFlipped: Boolean): HashSet[A] = {
+ val newRootNode = rootNode.filterImpl(pred, isFlipped)
+ if (newRootNode eq rootNode) this
+ else if (newRootNode.size == 0) HashSet.empty
+ else new HashSet(newRootNode)
+ }
+
+ override def intersect(that: collection.Set[A]): HashSet[A] = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ super.intersect(that)
+ }
+
+ override def take(n: Int): HashSet[A] = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ super.take(n)
+ }
+
+ override def takeRight(n: Int): HashSet[A] = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ super.takeRight(n)
+ }
+
+ override def takeWhile(p: A => Boolean): HashSet[A] = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ super.takeWhile(p)
+ }
+
+ override def drop(n: Int): HashSet[A] = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ super.drop(n)
+ }
+
+ override def dropRight(n: Int): HashSet[A] = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ super.dropRight(n)
+ }
+
+ override def dropWhile(p: A => Boolean): HashSet[A] = {
+ // This method has been preemptively overridden in order to ensure that an optimizing implementation may be included
+ // in a minor release without breaking binary compatibility.
+ super.dropWhile(p)
+ }
+}
+
+private[immutable] object SetNode {
+
+ private final val EmptySetNode = new BitmapIndexedSetNode(0, 0, Array.empty, Array.empty, 0, 0)
+
+ def empty[A]: BitmapIndexedSetNode[A] = EmptySetNode.asInstanceOf[BitmapIndexedSetNode[A]]
+
+ final val TupleLength = 1
+
+}
+
+private[immutable] sealed abstract class SetNode[A] extends Node[SetNode[A]] {
+
+ def contains(element: A, originalHash: Int, hash: Int, shift: Int): Boolean
+
+ def updated(element: A, originalHash: Int, hash: Int, shift: Int): SetNode[A]
+
+ def removed(element: A, originalHash: Int, hash: Int, shift: Int): SetNode[A]
+
+ def hasNodes: Boolean
+
+ def nodeArity: Int
+
+ def getNode(index: Int): SetNode[A]
+
+ def hasPayload: Boolean
+
+ def payloadArity: Int
+
+ def getPayload(index: Int): A
+
+ def size: Int
+
+ def foreach[U](f: A => U): Unit
+
+ def subsetOf(that: SetNode[A], shift: Int): Boolean
+
+ def copy(): SetNode[A]
+
+ def filterImpl(pred: A => Boolean, flipped: Boolean): SetNode[A]
+
+ def diff(that: SetNode[A], shift: Int): SetNode[A]
+
+ def concat(that: SetNode[A], shift: Int): SetNode[A]
+
+ def foreachWithHash(f: (A, Int) => Unit): Unit
+
+ def foreachWithHashWhile(f: (A, Int) => Boolean): Boolean
+}
+
+private final class BitmapIndexedSetNode[A](
+ var dataMap: Int,
+ var nodeMap: Int,
+ var content: Array[Any],
+ var originalHashes: Array[Int],
+ var size: Int,
+ var cachedJavaKeySetHashCode: Int) extends SetNode[A] {
+
+ import Node._
+ import SetNode._
+
+ /*
+ assert(checkInvariantContentIsWellTyped())
+ assert(checkInvariantSubNodesAreCompacted())
+
+ private final def checkInvariantSubNodesAreCompacted(): Boolean =
+ new SetIterator[A](this).size - payloadArity >= 2 * nodeArity
+
+ private final def checkInvariantContentIsWellTyped(): Boolean = {
+ val predicate1 = TupleLength * payloadArity + nodeArity == content.length
+
+ val predicate2 = Range(0, TupleLength * payloadArity)
+ .forall(i => content(i).isInstanceOf[SetNode[_]] == false)
+
+ val predicate3 = Range(TupleLength * payloadArity, content.length)
+ .forall(i => content(i).isInstanceOf[SetNode[_]] == true)
+
+ predicate1 && predicate2 && predicate3
+ }
+ */
+
+ def getPayload(index: Int): A = content(index).asInstanceOf[A]
+
+ override def getHash(index: Int): Int = originalHashes(index)
+
+ def getNode(index: Int): SetNode[A] = content(content.length - 1 - index).asInstanceOf[SetNode[A]]
+
+ def contains(element: A, originalHash: Int, elementHash: Int, shift: Int): Boolean = {
+ val mask = maskFrom(elementHash, shift)
+ val bitpos = bitposFrom(mask)
+
+ if ((dataMap & bitpos) != 0) {
+ val index = indexFrom(dataMap, mask, bitpos)
+ return originalHashes(index) == originalHash && element == this.getPayload(index)
+ }
+
+ if ((nodeMap & bitpos) != 0) {
+ val index = indexFrom(nodeMap, mask, bitpos)
+ return this.getNode(index).contains(element, originalHash, elementHash, shift + BitPartitionSize)
+ }
+
+ false
+ }
+
+ def updated(element: A, originalHash: Int, elementHash: Int, shift: Int): BitmapIndexedSetNode[A] = {
+ val mask = maskFrom(elementHash, shift)
+ val bitpos = bitposFrom(mask)
+
+ if ((dataMap & bitpos) != 0) {
+ val index = indexFrom(dataMap, mask, bitpos)
+ val element0 = this.getPayload(index)
+
+ if (element0.asInstanceOf[AnyRef] eq element.asInstanceOf[AnyRef]) {
+ return this
+ } else {
+ val element0UnimprovedHash = getHash(index)
+ val element0Hash = improve(element0UnimprovedHash)
+ if (originalHash == element0UnimprovedHash && element0 == element) {
+ return this
+ } else {
+ val subNodeNew = mergeTwoKeyValPairs(element0, element0UnimprovedHash, element0Hash, element, originalHash, elementHash, shift + BitPartitionSize)
+ return copyAndMigrateFromInlineToNode(bitpos, element0Hash, subNodeNew)
+ }
+ }
+ }
+ if ((nodeMap & bitpos) != 0) {
+ val index = indexFrom(nodeMap, mask, bitpos)
+ val subNode = this.getNode(index)
+
+ val subNodeNew = subNode.updated(element, originalHash, elementHash, shift + BitPartitionSize)
+ if (subNode eq subNodeNew) {
+ return this
+ } else {
+ return copyAndSetNode(bitpos, subNode, subNodeNew)
+ }
+ }
+
+ copyAndInsertValue(bitpos, element, originalHash, elementHash)
+ }
+ /** A variant of `updated` which performs shallow mutations on the root (`this`), and if possible, on immediately
+ * descendant child nodes (only one level beneath `this`)
+ *
+ * The caller should pass a bitmap of child nodes of this node, which this method may mutate.
+ * If this method may mutate a child node, then if the updated value is located in that child node, it will
+ * be shallowly mutated (its children will not be mutated).
+ *
+ * If instead this method may not mutate the child node in which the to-be-updated value is located, then
+ * that child will be updated immutably, but the result will be mutably re-inserted as a child of this node.
+ *
+ * @param key the key to update
+ * @param originalHash key.##
+ * @param keyHash the improved hash
+ * @param shallowlyMutableNodeMap bitmap of child nodes of this node, which can be shallowly mutated
+ * during the call to this method
+ *
+ * @return Int which is the bitwise OR of shallowlyMutableNodeMap and any freshly created nodes, which will be
+ * available for mutations in subsequent calls.
+ */
+ def updateWithShallowMutations(element: A, originalHash: Int, elementHash: Int, shift: Int, shallowlyMutableNodeMap: Int): Int = {
+ val mask = maskFrom(elementHash, shift)
+ val bitpos = bitposFrom(mask)
+
+ if ((dataMap & bitpos) != 0) {
+ val index = indexFrom(dataMap, mask, bitpos)
+ val element0 = getPayload(index)
+ val element0UnimprovedHash = getHash(index)
+ if (element0UnimprovedHash == originalHash && element0 == element) {
+ shallowlyMutableNodeMap
+ } else {
+ val element0Hash = improve(element0UnimprovedHash)
+ val subNodeNew = mergeTwoKeyValPairs(element0, element0UnimprovedHash, element0Hash, element, originalHash, elementHash, shift + BitPartitionSize)
+ migrateFromInlineToNodeInPlace(bitpos, element0Hash, subNodeNew)
+ shallowlyMutableNodeMap | bitpos
+ }
+ } else if ((nodeMap & bitpos) != 0) {
+ val index = indexFrom(nodeMap, mask, bitpos)
+ val subNode = this.getNode(index)
+ val subNodeSize = subNode.size
+ val subNodeCachedJavaKeySetHashCode = subNode.cachedJavaKeySetHashCode
+
+ var returnNodeMap = shallowlyMutableNodeMap
+
+ val subNodeNew: SetNode[A] = subNode match {
+ case subNodeBm: BitmapIndexedSetNode[A] if (bitpos & shallowlyMutableNodeMap) != 0 =>
+ subNodeBm.updateWithShallowMutations(element, originalHash, elementHash, shift + BitPartitionSize, 0)
+ subNodeBm
+ case _ =>
+ val subNodeNew = subNode.updated(element, originalHash, elementHash, shift + BitPartitionSize)
+ if (subNodeNew ne subNode) {
+ returnNodeMap |= bitpos
+ }
+ subNodeNew
+ }
+
+ this.content(this.content.length - 1 - this.nodeIndex(bitpos)) = subNodeNew
+ this.size = this.size - subNodeSize + subNodeNew.size
+ this.cachedJavaKeySetHashCode = this.cachedJavaKeySetHashCode - subNodeCachedJavaKeySetHashCode + subNodeNew.cachedJavaKeySetHashCode
+ returnNodeMap
+ } else {
+ val dataIx = dataIndex(bitpos)
+ val idx = dataIx
+
+ val src = this.content
+ val dst = new Array[Any](src.length + TupleLength)
+
+ // copy 'src' and insert 2 element(s) at position 'idx'
+ arraycopy(src, 0, dst, 0, idx)
+ dst(idx) = element
+ arraycopy(src, idx, dst, idx + TupleLength, src.length - idx)
+
+ val dstHashes = insertElement(originalHashes, dataIx, originalHash)
+
+ this.dataMap |= bitpos
+ this.content = dst
+ this.originalHashes = dstHashes
+ this.size += 1
+ this.cachedJavaKeySetHashCode += elementHash
+ shallowlyMutableNodeMap
+ }
+ }
+
+
+ def removed(element: A, originalHash: Int, elementHash: Int, shift: Int): BitmapIndexedSetNode[A] = {
+ val mask = maskFrom(elementHash, shift)
+ val bitpos = bitposFrom(mask)
+
+ if ((dataMap & bitpos) != 0) {
+ val index = indexFrom(dataMap, mask, bitpos)
+ val element0 = this.getPayload(index)
+
+ if (element0 == element) {
+ if (this.payloadArity == 2 && this.nodeArity == 0) {
+ // Create new node with remaining pair. The new node will a) either become the new root
+ // returned, or b) unwrapped and inlined during returning.
+ val newDataMap = if (shift == 0) (dataMap ^ bitpos) else bitposFrom(maskFrom(elementHash, 0))
+ if (index == 0) new BitmapIndexedSetNode[A](newDataMap, 0, Array(getPayload(1)), Array(originalHashes(1)), size - 1, improve(originalHashes(1)))
+ else new BitmapIndexedSetNode[A](newDataMap, 0, Array(getPayload(0)), Array(originalHashes(0)), size - 1, improve(originalHashes(0)))
+ }
+ else copyAndRemoveValue(bitpos, elementHash)
+ }
+ else this
+ }
+ else if ((nodeMap & bitpos) != 0) {
+ val index = indexFrom(nodeMap, mask, bitpos)
+ val subNode = this.getNode(index)
+ val subNodeNew = subNode.removed(element, originalHash, elementHash, shift + BitPartitionSize)
+
+ if (subNodeNew eq subNode) this
+ // if subNodeNew is a hashCollision node, size has cost in Vector#length
+ else subNodeNew.size match {
+ case 1 =>
+ // subNode is the only child (no other data or node children of `this` exist)
+ // escalate (singleton or empty) result
+ if (this.size == subNode.size) subNodeNew.asInstanceOf[BitmapIndexedSetNode[A]]
+ // inline value (move to front)
+ else copyAndMigrateFromNodeToInline(bitpos, elementHash, subNode, subNodeNew)
+ case subNodeNewSize if subNodeNewSize > 1 =>
+ // modify current node (set replacement node)
+ copyAndSetNode(bitpos, subNode, subNodeNew)
+ case _ => this
+ }
+ }
+ else this
+ }
+ /** Variant of `removed` which will perform mutation on only the top-level node (`this`), rather than return a new
+ * node
+ *
+ * Should only be called on root nodes, because shift is assumed to be 0
+ *
+ * @param element the element to remove
+ * @param originalHash the original hash of `element`
+ * @param elementHash the improved hash of `element`
+ */
+ def removeWithShallowMutations(element: A, originalHash: Int, elementHash: Int): this.type = {
+ val mask = maskFrom(elementHash, 0)
+ val bitpos = bitposFrom(mask)
+
+ if ((dataMap & bitpos) != 0) {
+ val index = indexFrom(dataMap, mask, bitpos)
+ val element0 = this.getPayload(index)
+
+ if (element0 == element) {
+ if (this.payloadArity == 2 && this.nodeArity == 0) {
+ val newDataMap = dataMap ^ bitpos
+ if (index == 0) {
+ val newContent = Array[Any](getPayload(1))
+ val newOriginalHashes = Array(originalHashes(1))
+ val newCachedJavaKeySetHashCode = improve(getHash(1))
+ this.content = newContent
+ this.originalHashes = newOriginalHashes
+ this.cachedJavaKeySetHashCode = newCachedJavaKeySetHashCode
+ } else {
+ val newContent = Array[Any](getPayload(0))
+ val newOriginalHashes = Array(originalHashes(0))
+ val newCachedJavaKeySetHashCode = improve(getHash(0))
+ this.content = newContent
+ this.originalHashes = newOriginalHashes
+ this.cachedJavaKeySetHashCode = newCachedJavaKeySetHashCode
+ }
+ this.dataMap = newDataMap
+ this.nodeMap = 0
+ this.size = 1
+ this
+ }
+ else {
+ val dataIx = dataIndex(bitpos)
+ val idx = TupleLength * dataIx
+
+ val src = this.content
+ val dst = new Array[Any](src.length - TupleLength)
+
+ arraycopy(src, 0, dst, 0, idx)
+ arraycopy(src, idx + TupleLength, dst, idx, src.length - idx - TupleLength)
+
+ val dstHashes = removeElement(originalHashes, dataIx)
+
+ this.dataMap = this.dataMap ^ bitpos
+ this.content = dst
+ this.originalHashes = dstHashes
+ this.size -= 1
+ this.cachedJavaKeySetHashCode -= elementHash
+ this
+ }
+ } else this
+ } else if ((nodeMap & bitpos) != 0) {
+ val index = indexFrom(nodeMap, mask, bitpos)
+ val subNode = this.getNode(index)
+
+ val subNodeNew = subNode.removed(element, originalHash, elementHash, BitPartitionSize).asInstanceOf[BitmapIndexedSetNode[A]]
+
+ if (subNodeNew eq subNode) return this
+
+ if (subNodeNew.size == 1) {
+ if (this.payloadArity == 0 && this.nodeArity == 1) {
+ this.dataMap = subNodeNew.dataMap
+ this.nodeMap = subNodeNew.nodeMap
+ this.content = subNodeNew.content
+ this.originalHashes = subNodeNew.originalHashes
+ this.size = subNodeNew.size
+ this.cachedJavaKeySetHashCode = subNodeNew.cachedJavaKeySetHashCode
+ this
+ } else {
+ migrateFromNodeToInlineInPlace(bitpos, originalHash, elementHash, subNode, subNodeNew)
+ this
+ }
+ } else {
+ // size must be > 1
+ this.content(this.content.length - 1 - this.nodeIndex(bitpos)) = subNodeNew
+ this.size -= 1
+ this.cachedJavaKeySetHashCode = this.cachedJavaKeySetHashCode - subNode.cachedJavaKeySetHashCode + subNodeNew.cachedJavaKeySetHashCode
+ this
+ }
+ } else this
+ }
+
+ def mergeTwoKeyValPairs(key0: A, originalKeyHash0: Int, keyHash0: Int, key1: A, originalKeyHash1: Int, keyHash1: Int, shift: Int): SetNode[A] = {
+ // assert(key0 != key1)
+
+ if (shift >= HashCodeLength) {
+ new HashCollisionSetNode[A](originalKeyHash0, keyHash0, Vector(key0, key1))
+ } else {
+ val mask0 = maskFrom(keyHash0, shift)
+ val mask1 = maskFrom(keyHash1, shift)
+
+ if (mask0 != mask1) {
+ // unique prefixes, payload fits on same level
+ val dataMap = bitposFrom(mask0) | bitposFrom(mask1)
+ val newCachedHashCode = keyHash0 + keyHash1
+
+ if (mask0 < mask1) {
+ new BitmapIndexedSetNode[A](dataMap, 0, Array(key0, key1), Array(originalKeyHash0, originalKeyHash1), 2, newCachedHashCode)
+ } else {
+ new BitmapIndexedSetNode[A](dataMap, 0, Array(key1, key0), Array(originalKeyHash1, originalKeyHash0), 2, newCachedHashCode)
+ }
+ } else {
+ // identical prefixes, payload must be disambiguated deeper in the trie
+ val nodeMap = bitposFrom(mask0)
+ val node = mergeTwoKeyValPairs(key0, originalKeyHash0, keyHash0, key1, originalKeyHash1, keyHash1, shift + BitPartitionSize)
+
+ new BitmapIndexedSetNode[A](0, nodeMap, Array(node), Array.emptyIntArray, node.size, node.cachedJavaKeySetHashCode)
+ }
+ }
+ }
+
+ def hasPayload: Boolean = dataMap != 0
+
+ def payloadArity: Int = bitCount(dataMap)
+
+ def hasNodes: Boolean = nodeMap != 0
+
+ def nodeArity: Int = bitCount(nodeMap)
+
+ def dataIndex(bitpos: Int) = bitCount(dataMap & (bitpos - 1))
+
+ def nodeIndex(bitpos: Int) = bitCount(nodeMap & (bitpos - 1))
+
+ def copyAndSetNode(bitpos: Int, oldNode: SetNode[A], newNode: SetNode[A]) = {
+ val idx = this.content.length - 1 - this.nodeIndex(bitpos)
+
+ val src = this.content
+ val dst = new Array[Any](src.length)
+
+ // copy 'src' and set 1 element(s) at position 'idx'
+ arraycopy(src, 0, dst, 0, src.length)
+ dst(idx) = newNode
+ new BitmapIndexedSetNode[A](
+ dataMap = dataMap,
+ nodeMap = nodeMap,
+ content = dst,
+ originalHashes = originalHashes,
+ size = size - oldNode.size + newNode.size,
+ cachedJavaKeySetHashCode = cachedJavaKeySetHashCode - oldNode.cachedJavaKeySetHashCode + newNode.cachedJavaKeySetHashCode
+ )
+ }
+
+ def copyAndInsertValue(bitpos: Int, key: A, originalHash: Int, elementHash: Int) = {
+ val dataIx = dataIndex(bitpos)
+ val idx = TupleLength * dataIx
+
+ val src = this.content
+ val dst = new Array[Any](src.length + 1)
+
+ // copy 'src' and insert 1 element(s) at position 'idx'
+ arraycopy(src, 0, dst, 0, idx)
+ dst(idx) = key
+ arraycopy(src, idx, dst, idx + 1, src.length - idx)
+ val dstHashes = insertElement(originalHashes, dataIx, originalHash)
+
+ new BitmapIndexedSetNode[A](dataMap | bitpos, nodeMap, dst, dstHashes, size + 1, cachedJavaKeySetHashCode + elementHash)
+ }
+
+ def copyAndSetValue(bitpos: Int, key: A, originalHash: Int, elementHash: Int) = {
+ val dataIx = dataIndex(bitpos)
+ val idx = TupleLength * dataIx
+
+ val src = this.content
+ val dst = new Array[Any](src.length)
+
+ // copy 'src' and set 1 element(s) at position 'idx'
+ arraycopy(src, 0, dst, 0, src.length)
+ dst(idx) = key
+
+ new BitmapIndexedSetNode[A](dataMap | bitpos, nodeMap, dst, originalHashes, size, cachedJavaKeySetHashCode)
+ }
+
+ def copyAndRemoveValue(bitpos: Int, elementHash: Int) = {
+ val dataIx = dataIndex(bitpos)
+ val idx = TupleLength * dataIx
+
+ val src = this.content
+ val dst = new Array[Any](src.length - 1)
+
+ // copy 'src' and remove 1 element(s) at position 'idx'
+ arraycopy(src, 0, dst, 0, idx)
+ arraycopy(src, idx + 1, dst, idx, src.length - idx - 1)
+ val dstHashes = removeElement(originalHashes, dataIx)
+ new BitmapIndexedSetNode[A](dataMap ^ bitpos, nodeMap, dst, dstHashes, size - 1, cachedJavaKeySetHashCode - elementHash)
+ }
+
+ def copyAndMigrateFromInlineToNode(bitpos: Int, elementHash: Int, node: SetNode[A]) = {
+ val dataIx = dataIndex(bitpos)
+ val idxOld = TupleLength * dataIx
+ val idxNew = this.content.length - TupleLength - nodeIndex(bitpos)
+
+ val src = this.content
+ val dst = new Array[Any](src.length - 1 + 1)
+
+ // copy 'src' and remove 1 element(s) at position 'idxOld' and
+ // insert 1 element(s) at position 'idxNew'
+ // assert(idxOld <= idxNew)
+ arraycopy(src, 0, dst, 0, idxOld)
+ arraycopy(src, idxOld + 1, dst, idxOld, idxNew - idxOld)
+ dst(idxNew) = node
+ arraycopy(src, idxNew + 1, dst, idxNew + 1, src.length - idxNew - 1)
+ val dstHashes = removeElement(originalHashes, dataIx)
+ new BitmapIndexedSetNode[A](
+ dataMap = dataMap ^ bitpos,
+ nodeMap = nodeMap | bitpos,
+ content = dst, originalHashes = dstHashes,
+ size = size - 1 + node.size,
+ cachedJavaKeySetHashCode = cachedJavaKeySetHashCode - elementHash + node.cachedJavaKeySetHashCode
+ )
+ }
+ /** Variant of `copyAndMigrateFromInlineToNode` which mutates `this` rather than returning a new node.
+ *
+ * Note: This method will mutate `this`, and will mutate `this.content`
+ *
+ * Mutation of `this.content` will occur as an optimization not possible in maps. Since TupleLength == 1 for sets,
+ * content array size does not change during inline <-> node migrations. Therefor, since we are updating in-place,
+ * we reuse this.content by shifting data/nodes around, rather than allocating a new array.
+ *
+ * @param bitpos the bit position of the data to migrate to node
+ * @param keyHash the improved hash of the element currently at `bitpos`
+ * @param node the node to place at `bitpos`
+ */
+ def migrateFromInlineToNodeInPlace(bitpos: Int, keyHash: Int, node: SetNode[A]): this.type = {
+ val dataIx = dataIndex(bitpos)
+ val idxOld = TupleLength * dataIx
+ val idxNew = this.content.length - TupleLength - nodeIndex(bitpos)
+
+ arraycopy(content, idxOld + TupleLength, content, idxOld, idxNew - idxOld)
+ content(idxNew) = node
+
+ this.dataMap = this.dataMap ^ bitpos
+ this.nodeMap = this.nodeMap | bitpos
+ this.originalHashes = removeElement(originalHashes, dataIx)
+ this.size = this.size - 1 + node.size
+ this.cachedJavaKeySetHashCode = this.cachedJavaKeySetHashCode - keyHash + node.cachedJavaKeySetHashCode
+ this
+ }
+
+ def copyAndMigrateFromNodeToInline(bitpos: Int, elementHash: Int, oldNode: SetNode[A], node: SetNode[A]) = {
+ val idxOld = this.content.length - 1 - nodeIndex(bitpos)
+ val dataIxNew = dataIndex(bitpos)
+ val idxNew = TupleLength * dataIxNew
+
+ val src = this.content
+ val dst = new Array[Any](src.length - 1 + 1)
+
+ // copy 'src' and remove 1 element(s) at position 'idxOld' and
+ // insert 1 element(s) at position 'idxNew'
+ // assert(idxOld >= idxNew)
+ arraycopy(src, 0, dst, 0, idxNew)
+ dst(idxNew) = node.getPayload(0)
+ arraycopy(src, idxNew, dst, idxNew + 1, idxOld - idxNew)
+ arraycopy(src, idxOld + 1, dst, idxOld + 1, src.length - idxOld - 1)
+ val hash = node.getHash(0)
+ val dstHashes = insertElement(originalHashes, dataIxNew, hash)
+ new BitmapIndexedSetNode[A](
+ dataMap = dataMap | bitpos,
+ nodeMap = nodeMap ^ bitpos,
+ content = dst,
+ originalHashes = dstHashes,
+ size = size - oldNode.size + 1,
+ cachedJavaKeySetHashCode = cachedJavaKeySetHashCode - oldNode.cachedJavaKeySetHashCode + node.cachedJavaKeySetHashCode
+ )
+ }
+
+ /** Variant of `copyAndMigrateFromNodeToInline` which mutates `this` rather than returning a new node.
+ *
+ * Note: This method will mutate `this`, and will mutate `this.content`
+ *
+ * Mutation of `this.content` will occur as an optimization not possible in maps. Since TupleLength == 1 for sets,
+ * content array size does not change during inline <-> node migrations. Therefor, since we are updating in-place,
+ * we reuse this.content by shifting data/nodes around, rather than allocating a new array.
+ *
+ * @param bitpos the bit position of the node to migrate inline
+ * @param oldNode the node currently stored at position `bitpos`
+ * @param node the node containing the single element to migrate inline
+ */
+ def migrateFromNodeToInlineInPlace(bitpos: Int, originalHash: Int, elementHash: Int, oldNode: SetNode[A], node: SetNode[A]): Unit = {
+ val idxOld = this.content.length - 1 - nodeIndex(bitpos)
+ val dataIxNew = dataIndex(bitpos)
+ val element = node.getPayload(0)
+ arraycopy(content, dataIxNew, content, dataIxNew + 1, idxOld - dataIxNew)
+ content(dataIxNew) = element
+ val hash = node.getHash(0)
+ val dstHashes = insertElement(originalHashes, dataIxNew, hash)
+
+ this.dataMap = this.dataMap | bitpos
+ this.nodeMap = this.nodeMap ^ bitpos
+ this.originalHashes = dstHashes
+ this.size = this.size - oldNode.size + 1
+ this.cachedJavaKeySetHashCode = this.cachedJavaKeySetHashCode - oldNode.cachedJavaKeySetHashCode + node.cachedJavaKeySetHashCode
+ }
+
+ def foreach[U](f: A => U): Unit = {
+ val thisPayloadArity = payloadArity
+ var i = 0
+ while (i < thisPayloadArity) {
+ f(getPayload(i))
+ i += 1
+ }
+
+ val thisNodeArity = nodeArity
+ var j = 0
+ while (j < thisNodeArity) {
+ getNode(j).foreach(f)
+ j += 1
+ }
+ }
+
+ def subsetOf(that: SetNode[A], shift: Int): Boolean = if (this eq that) true else that match {
+ case _: HashCollisionSetNode[A] => false
+ case node: BitmapIndexedSetNode[A] =>
+ val thisBitmap = this.dataMap | this.nodeMap
+ val nodeBitmap = node.dataMap | node.nodeMap
+
+ if ((thisBitmap | nodeBitmap) != nodeBitmap)
+ return false
+
+ var bitmap = thisBitmap & nodeBitmap
+ var bitsToSkip = numberOfTrailingZeros(bitmap)
+
+ var isValidSubset = true
+ while (isValidSubset && bitsToSkip < HashCodeLength) {
+ val bitpos = bitposFrom(bitsToSkip)
+
+ isValidSubset =
+ if ((this.dataMap & bitpos) != 0) {
+ if ((node.dataMap & bitpos) != 0) {
+ // Data x Data
+ val payload0 = this.getPayload(indexFrom(this.dataMap, bitpos))
+ val payload1 = node.getPayload(indexFrom(node.dataMap, bitpos))
+ payload0 == payload1
+ } else {
+ // Data x Node
+ val thisDataIndex = indexFrom(this.dataMap, bitpos)
+ val payload = this.getPayload(thisDataIndex)
+ val subNode = that.getNode(indexFrom(node.nodeMap, bitpos))
+ val elementUnimprovedHash = getHash(thisDataIndex)
+ val elementHash = improve(elementUnimprovedHash)
+ subNode.contains(payload, elementUnimprovedHash, elementHash, shift + BitPartitionSize)
+ }
+ } else ((node.dataMap & bitpos) == 0) && {
+ // Node x Node
+ val subNode0 = this.getNode(indexFrom(this.nodeMap, bitpos))
+ val subNode1 = node.getNode(indexFrom(node.nodeMap, bitpos))
+ subNode0.subsetOf(subNode1, shift + BitPartitionSize)
+ }
+
+ val newBitmap = bitmap ^ bitpos
+ bitmap = newBitmap
+ bitsToSkip = numberOfTrailingZeros(newBitmap)
+ }
+ isValidSubset
+ }
+
+ override def filterImpl(pred: A => Boolean, flipped: Boolean): BitmapIndexedSetNode[A] = {
+ if (size == 0) this
+ else if (size == 1) {
+ if (pred(getPayload(0)) != flipped) this else SetNode.empty
+ } else if (nodeMap == 0) {
+ // Performance optimization for nodes of depth 1:
+ //
+ // this node has no "node" children, all children are inlined data elems, therefor logic is significantly simpler
+ // approach:
+ // * traverse the content array, accumulating in `newDataMap: Int` any bit positions of keys which pass the filter
+ // * (bitCount(newDataMap) * TupleLength) tells us the new content array and originalHashes array size, so now perform allocations
+ // * traverse the content array once more, placing each passing element (according to `newDatamap`) in the new content and originalHashes arrays
+ //
+ // note:
+ // * this optimization significantly improves performance of not only small trees, but also larger trees, since
+ // even non-root nodes are affected by this improvement, and large trees will consist of many nodes as
+ // descendants
+ //
+ val minimumIndex: Int = Integer.numberOfTrailingZeros(dataMap)
+ val maximumIndex: Int = Node.BranchingFactor - Integer.numberOfLeadingZeros(dataMap)
+
+ var newDataMap = 0
+ var newCachedHashCode = 0
+ var dataIndex = 0
+
+ var i = minimumIndex
+
+ while(i < maximumIndex) {
+ val bitpos = bitposFrom(i)
+
+ if ((bitpos & dataMap) != 0) {
+ val payload = getPayload(dataIndex)
+ val passed = pred(payload) != flipped
+
+ if (passed) {
+ newDataMap |= bitpos
+ newCachedHashCode += improve(getHash(dataIndex))
+ }
+
+ dataIndex += 1
+ }
+
+ i += 1
+ }
+
+ if (newDataMap == 0) {
+ SetNode.empty
+ } else if (newDataMap == dataMap) {
+ this
+ } else {
+ val newSize = Integer.bitCount(newDataMap)
+ val newContent = new Array[Any](newSize)
+ val newOriginalHashCodes = new Array[Int](newSize)
+ val newMaximumIndex: Int = Node.BranchingFactor - Integer.numberOfLeadingZeros(newDataMap)
+
+ var j = Integer.numberOfTrailingZeros(newDataMap)
+
+ var newDataIndex = 0
+
+ while (j < newMaximumIndex) {
+ val bitpos = bitposFrom(j)
+ if ((bitpos & newDataMap) != 0) {
+ val oldIndex = indexFrom(dataMap, bitpos)
+ newContent(newDataIndex) = content(oldIndex)
+ newOriginalHashCodes(newDataIndex) = originalHashes(oldIndex)
+ newDataIndex += 1
+ }
+ j += 1
+ }
+
+ new BitmapIndexedSetNode(newDataMap, 0, newContent, newOriginalHashCodes, newSize, newCachedHashCode)
+ }
+ } else {
+ val allMap = dataMap | nodeMap
+ val minimumIndex: Int = Integer.numberOfTrailingZeros(allMap)
+ val maximumIndex: Int = Node.BranchingFactor - Integer.numberOfLeadingZeros(allMap)
+
+ var oldDataPassThrough = 0
+
+ // bitmap of nodes which, when filtered, returned a single-element node. These must be migrated to data
+ var nodeMigrateToDataTargetMap = 0
+
+ // TODO: When filtering results in a single-elem node, simply `(A, originalHash, improvedHash)` could be returned,
+ // rather than a singleton node (to avoid pointlessly allocating arrays, nodes, which would just be inlined in
+ // the parent anyways). This would probably involve changing the return type of filterImpl to `AnyRef` which may
+ // return at runtime a SetNode[A], or a tuple of (A, Int, Int)
+
+ // the queue of single-element, post-filter nodes
+ var nodesToMigrateToData: mutable.Queue[SetNode[A]] = null
+
+ // bitmap of all nodes which, when filtered, returned themselves. They are passed forward to the returned node
+ var nodesToPassThroughMap = 0
+
+ // bitmap of any nodes which, after being filtered, returned a node that is not empty, but also not `eq` itself
+ // These are stored for later inclusion into the final `content` array
+ // not named `newNodesMap` (plural) to avoid confusion with `newNodeMap` (singular)
+ var mapOfNewNodes = 0
+ // each bit in `mapOfNewNodes` corresponds to one element in this queue
+ var newNodes: mutable.Queue[SetNode[A]] = null
+
+ var newDataMap = 0
+ var newNodeMap = 0
+ var newSize = 0
+ var newCachedHashCode = 0
+
+ var dataIndex = 0
+ var nodeIndex = 0
+
+ var i = minimumIndex
+ while (i < maximumIndex) {
+ val bitpos = bitposFrom(i)
+
+ if ((bitpos & dataMap) != 0) {
+ val payload = getPayload(dataIndex)
+ val passed = pred(payload) != flipped
+
+ if (passed) {
+ newDataMap |= bitpos
+ oldDataPassThrough |= bitpos
+ newSize += 1
+ newCachedHashCode += improve(getHash(dataIndex))
+ }
+
+ dataIndex += 1
+ } else if ((bitpos & nodeMap) != 0) {
+ val oldSubNode = getNode(nodeIndex)
+ val newSubNode = oldSubNode.filterImpl(pred, flipped)
+
+ newSize += newSubNode.size
+ newCachedHashCode += newSubNode.cachedJavaKeySetHashCode
+
+ // if (newSubNode.size == 0) do nothing (drop it)
+ if (newSubNode.size > 1) {
+ newNodeMap |= bitpos
+ if (oldSubNode eq newSubNode) {
+ nodesToPassThroughMap |= bitpos
+ } else {
+ mapOfNewNodes |= bitpos
+ if (newNodes eq null) {
+ newNodes = mutable.Queue.empty
+ }
+ newNodes += newSubNode
+ }
+ } else if (newSubNode.size == 1) {
+ newDataMap |= bitpos
+ nodeMigrateToDataTargetMap |= bitpos
+ if (nodesToMigrateToData eq null) {
+ nodesToMigrateToData = mutable.Queue.empty
+ }
+ nodesToMigrateToData += newSubNode
+ }
+
+ nodeIndex += 1
+ }
+
+ i += 1
+ }
+
+ this.newNodeFrom(
+ newSize = newSize,
+ newDataMap = newDataMap,
+ newNodeMap = newNodeMap,
+ minimumIndex = minimumIndex,
+ oldDataPassThrough = oldDataPassThrough,
+ nodesToPassThroughMap = nodesToPassThroughMap,
+ nodeMigrateToDataTargetMap = nodeMigrateToDataTargetMap,
+ nodesToMigrateToData = nodesToMigrateToData,
+ mapOfNewNodes = mapOfNewNodes,
+ newNodes = newNodes,
+ newCachedHashCode = newCachedHashCode
+ )
+ }
+ }
+
+ override def diff(that: SetNode[A], shift: Int): BitmapIndexedSetNode[A] = that match {
+ case bm: BitmapIndexedSetNode[A] =>
+ if (size == 0) this
+ else if (size == 1) {
+ val h = getHash(0)
+ if (that.contains(getPayload(0), h, improve(h), shift)) SetNode.empty else this
+ } else {
+ val allMap = dataMap | nodeMap
+ val minimumIndex: Int = Integer.numberOfTrailingZeros(allMap)
+ val maximumIndex: Int = Node.BranchingFactor - Integer.numberOfLeadingZeros(allMap)
+
+ var oldDataPassThrough = 0
+
+ // bitmap of nodes which, when filtered, returned a single-element node. These must be migrated to data
+ var nodeMigrateToDataTargetMap = 0
+ // the queue of single-element, post-filter nodes
+ var nodesToMigrateToData: mutable.Queue[SetNode[A]] = null
+
+ // bitmap of all nodes which, when filtered, returned themselves. They are passed forward to the returned node
+ var nodesToPassThroughMap = 0
+
+ // bitmap of any nodes which, after being filtered, returned a node that is not empty, but also not `eq` itself
+ // These are stored for later inclusion into the final `content` array
+ // not named `newNodesMap` (plural) to avoid confusion with `newNodeMap` (singular)
+ var mapOfNewNodes = 0
+ // each bit in `mapOfNewNodes` corresponds to one element in this queue
+ var newNodes: mutable.Queue[SetNode[A]] = null
+
+ var newDataMap = 0
+ var newNodeMap = 0
+ var newSize = 0
+ var newCachedHashCode = 0
+
+ var dataIndex = 0
+ var nodeIndex = 0
+
+ var i = minimumIndex
+ while (i < maximumIndex) {
+ val bitpos = bitposFrom(i)
+
+ if ((bitpos & dataMap) != 0) {
+ val payload = getPayload(dataIndex)
+ val originalHash = getHash(dataIndex)
+ val hash = improve(originalHash)
+
+ if (!bm.contains(payload, originalHash, hash, shift)) {
+ newDataMap |= bitpos
+ oldDataPassThrough |= bitpos
+ newSize += 1
+ newCachedHashCode += hash
+ }
+
+ dataIndex += 1
+ } else if ((bitpos & nodeMap) != 0) {
+ val oldSubNode = getNode(nodeIndex)
+
+ val newSubNode: SetNode[A] =
+ if ((bitpos & bm.dataMap) != 0) {
+ val thatDataIndex = indexFrom(bm.dataMap, bitpos)
+ val thatPayload = bm.getPayload(thatDataIndex)
+ val thatOriginalHash = bm.getHash(thatDataIndex)
+ val thatHash = improve(thatOriginalHash)
+ oldSubNode.removed(thatPayload, thatOriginalHash, thatHash, shift + BitPartitionSize)
+ } else if ((bitpos & bm.nodeMap) != 0) {
+ oldSubNode.diff(bm.getNode(indexFrom(bm.nodeMap, bitpos)), shift + BitPartitionSize)
+ } else {
+ oldSubNode
+ }
+
+ newSize += newSubNode.size
+ newCachedHashCode += newSubNode.cachedJavaKeySetHashCode
+
+ // if (newSubNode.size == 0) do nothing (drop it)
+ if (newSubNode.size > 1) {
+ newNodeMap |= bitpos
+ if (oldSubNode eq newSubNode) {
+ nodesToPassThroughMap |= bitpos
+ } else {
+ mapOfNewNodes |= bitpos
+ if (newNodes eq null) {
+ newNodes = mutable.Queue.empty
+ }
+ newNodes += newSubNode
+ }
+ } else if (newSubNode.size == 1) {
+ newDataMap |= bitpos
+ nodeMigrateToDataTargetMap |= bitpos
+ if (nodesToMigrateToData eq null) {
+ nodesToMigrateToData = mutable.Queue.empty
+ }
+ nodesToMigrateToData += newSubNode
+ }
+
+ nodeIndex += 1
+ }
+
+ i += 1
+ }
+ this.newNodeFrom(
+ newSize = newSize,
+ newDataMap = newDataMap,
+ newNodeMap = newNodeMap,
+ minimumIndex = minimumIndex,
+ oldDataPassThrough = oldDataPassThrough,
+ nodesToPassThroughMap = nodesToPassThroughMap,
+ nodeMigrateToDataTargetMap = nodeMigrateToDataTargetMap,
+ nodesToMigrateToData = nodesToMigrateToData,
+ mapOfNewNodes = mapOfNewNodes,
+ newNodes = newNodes,
+ newCachedHashCode = newCachedHashCode
+ )
+ }
+ case _: HashCollisionSetNode[A] =>
+ // this branch should never happen, because HashCollisionSetNodes and BitMapIndexedSetNodes do not occur at the
+ // same depth
+ throw new RuntimeException("BitmapIndexedSetNode diff HashCollisionSetNode")
+ }
+
+ /** Utility method only for use in `diff` and `filterImpl`
+ *
+ * @param newSize the size of the new SetNode
+ * @param newDataMap the dataMap of the new SetNode
+ * @param newNodeMap the nodeMap of the new SetNode
+ * @param minimumIndex the minimum index (in range of [0, 31]) for which there are sub-nodes or data beneath the new
+ * SetNode
+ * @param oldDataPassThrough bitmap representing all the data that are just passed from `this` to the new
+ * SetNode
+ * @param nodesToPassThroughMap bitmap representing all nodes that are just passed from `this` to the new SetNode
+ * @param nodeMigrateToDataTargetMap bitmap representing all positions which will now be data in the new SetNode,
+ * but which were nodes in `this`
+ * @param nodesToMigrateToData a queue (in order of child position) of single-element nodes, which will be migrated
+ * to data, in positions in the `nodeMigrateToDataTargetMap`
+ * @param mapOfNewNodes bitmap of positions of new nodes to include in the new SetNode
+ * @param newNodes queue in order of child position, of all new nodes to include in the new SetNode
+ * @param newCachedHashCode the cached java keyset hashcode of the new SetNode
+ */
+ private[this] def newNodeFrom(
+ newSize: Int,
+ newDataMap: Int,
+ newNodeMap: Int,
+ minimumIndex: Int,
+ oldDataPassThrough: Int,
+ nodesToPassThroughMap: Int,
+ nodeMigrateToDataTargetMap: Int,
+ nodesToMigrateToData: mutable.Queue[SetNode[A]],
+ mapOfNewNodes: Int,
+ newNodes: mutable.Queue[SetNode[A]],
+ newCachedHashCode: Int): BitmapIndexedSetNode[A] = {
+ if (newSize == 0) {
+ SetNode.empty
+ } else if (newSize == size) {
+ this
+ } else {
+ val newDataSize = bitCount(newDataMap)
+ val newContentSize = newDataSize + bitCount(newNodeMap)
+ val newContent = new Array[Any](newContentSize)
+ val newOriginalHashes = new Array[Int](newDataSize)
+
+ val newAllMap = newDataMap | newNodeMap
+ val maxIndex = Node.BranchingFactor - Integer.numberOfLeadingZeros(newAllMap)
+
+ // note: We MUST start from the minimum index in the old (`this`) node, otherwise `old{Node,Data}Index` will
+ // not be incremented properly. Otherwise we could have started at Integer.numberOfTrailingZeroes(newAllMap)
+ var i = minimumIndex
+
+ var oldDataIndex = 0
+ var oldNodeIndex = 0
+
+ var newDataIndex = 0
+ var newNodeIndex = 0
+
+ while (i < maxIndex) {
+ val bitpos = bitposFrom(i)
+
+ if ((bitpos & oldDataPassThrough) != 0) {
+ newContent(newDataIndex) = getPayload(oldDataIndex)
+ newOriginalHashes(newDataIndex) = getHash(oldDataIndex)
+ newDataIndex += 1
+ oldDataIndex += 1
+ } else if ((bitpos & nodesToPassThroughMap) != 0) {
+ newContent(newContentSize - newNodeIndex - 1) = getNode(oldNodeIndex)
+ newNodeIndex += 1
+ oldNodeIndex += 1
+ } else if ((bitpos & nodeMigrateToDataTargetMap) != 0) {
+ // we need not check for null here. If nodeMigrateToDataTargetMap != 0, then nodesMigrateToData must not be null
+ val node = nodesToMigrateToData.dequeue()
+ newContent(newDataIndex) = node.getPayload(0)
+ newOriginalHashes(newDataIndex) = node.getHash(0)
+ newDataIndex += 1
+ oldNodeIndex += 1
+ } else if ((bitpos & mapOfNewNodes) != 0) {
+ // we need not check for null here. If mapOfNewNodes != 0, then newNodes must not be null
+ newContent(newContentSize - newNodeIndex - 1) = newNodes.dequeue()
+ newNodeIndex += 1
+ oldNodeIndex += 1
+ } else if ((bitpos & dataMap) != 0) {
+ oldDataIndex += 1
+ } else if ((bitpos & nodeMap) != 0) {
+ oldNodeIndex += 1
+ }
+
+ i += 1
+ }
+
+ new BitmapIndexedSetNode[A](newDataMap, newNodeMap, newContent, newOriginalHashes, newSize, newCachedHashCode)
+ }
+ }
+
+
+ override def equals(that: Any): Boolean =
+ that match {
+ case node: BitmapIndexedSetNode[_] =>
+ (this eq node) ||
+ (this.cachedJavaKeySetHashCode == node.cachedJavaKeySetHashCode) &&
+ (this.nodeMap == node.nodeMap) &&
+ (this.dataMap == node.dataMap) &&
+ (this.size == node.size) &&
+ java.util.Arrays.equals(this.originalHashes, node.originalHashes) &&
+ deepContentEquality(this.content, node.content, content.length)
+ case _ => false
+ }
+
+ @`inline` private def deepContentEquality(a1: Array[Any], a2: Array[Any], length: Int): Boolean = {
+ if (a1 eq a2)
+ true
+ else {
+ var isEqual = true
+ var i = 0
+
+ while (isEqual && i < length) {
+ isEqual = a1(i) == a2(i)
+ i += 1
+ }
+
+ isEqual
+ }
+ }
+
+ override def hashCode(): Int =
+ throw new UnsupportedOperationException("Trie nodes do not support hashing.")
+
+ override def toString: String = f"BitmapIndexedSetNode(size=$size, dataMap=$dataMap%x, nodeMap=$nodeMap%x)" // content=${scala.runtime.ScalaRunTime.stringOf(content)}
+
+ override def copy(): BitmapIndexedSetNode[A] = {
+ val contentClone = content.clone()
+ val contentLength = contentClone.length
+ var i = bitCount(dataMap)
+ while (i < contentLength) {
+ contentClone(i) = contentClone(i).asInstanceOf[SetNode[A]].copy()
+ i += 1
+ }
+ new BitmapIndexedSetNode[A](dataMap, nodeMap, contentClone, originalHashes.clone(), size, cachedJavaKeySetHashCode)
+ }
+
+ override def concat(that: SetNode[A], shift: Int): BitmapIndexedSetNode[A] = that match {
+ case bm: BitmapIndexedSetNode[A] =>
+ if (size == 0) return bm
+ else if (bm.size == 0 || (bm eq this)) return this
+ else if (bm.size == 1) {
+ val originalHash = bm.getHash(0)
+ return this.updated(bm.getPayload(0), originalHash, improve(originalHash), shift)
+ }
+
+ // if we go through the merge and the result does not differ from `this`, we can just return `this`, to improve sharing
+ // So, `anyChangesMadeSoFar` will be set to `true` as soon as we encounter a difference between the
+ // currently-being-computed result, and `this`
+ var anyChangesMadeSoFar = false
+
+ // bitmap containing `1` in any position that has any descendant in either left or right, either data or node
+ val allMap = dataMap | bm.dataMap | nodeMap | bm.nodeMap
+
+ // minimumIndex is inclusive -- it is the first index for which there is data or nodes
+ val minimumBitPos: Int = Node.bitposFrom(Integer.numberOfTrailingZeros(allMap))
+ // maximumIndex is inclusive -- it is the last index for which there is data or nodes
+ // it could not be exclusive, because then upper bound in worst case (Node.BranchingFactor) would be out-of-bound
+ // of int bitposition representation
+ val maximumBitPos: Int = Node.bitposFrom(Node.BranchingFactor - Integer.numberOfLeadingZeros(allMap) - 1)
+
+ var leftNodeRightNode = 0
+ var leftDataRightNode = 0
+ var leftNodeRightData = 0
+ var leftDataOnly = 0
+ var rightDataOnly = 0
+ var leftNodeOnly = 0
+ var rightNodeOnly = 0
+ var leftDataRightDataMigrateToNode = 0
+ var leftDataRightDataLeftOverwrites = 0
+
+ var dataToNodeMigrationTargets = 0
+
+ {
+ var bitpos = minimumBitPos
+ var leftIdx = 0
+ var rightIdx = 0
+ var finished = false
+
+ while (!finished) {
+
+ if ((bitpos & dataMap) != 0) {
+ if ((bitpos & bm.dataMap) != 0) {
+ if (getHash(leftIdx) == bm.getHash(rightIdx) && getPayload(leftIdx) == bm.getPayload(rightIdx)) {
+ leftDataRightDataLeftOverwrites |= bitpos
+ } else {
+ leftDataRightDataMigrateToNode |= bitpos
+ dataToNodeMigrationTargets |= Node.bitposFrom(Node.maskFrom(improve(getHash(leftIdx)), shift))
+ }
+ rightIdx += 1
+ } else if ((bitpos & bm.nodeMap) != 0) {
+ leftDataRightNode |= bitpos
+ } else {
+ leftDataOnly |= bitpos
+ }
+ leftIdx += 1
+ } else if ((bitpos & nodeMap) != 0) {
+ if ((bitpos & bm.dataMap) != 0) {
+ leftNodeRightData |= bitpos
+ rightIdx += 1
+ } else if ((bitpos & bm.nodeMap) != 0) {
+ leftNodeRightNode |= bitpos
+ } else {
+ leftNodeOnly |= bitpos
+ }
+ } else if ((bitpos & bm.dataMap) != 0) {
+ rightDataOnly |= bitpos
+ rightIdx += 1
+ } else if ((bitpos & bm.nodeMap) != 0) {
+ rightNodeOnly |= bitpos
+ }
+
+ if (bitpos == maximumBitPos) {
+ finished = true
+ } else {
+ bitpos = bitpos << 1
+ }
+ }
+ }
+
+
+ val newDataMap = leftDataOnly | rightDataOnly | leftDataRightDataLeftOverwrites
+
+ val newNodeMap =
+ leftNodeRightNode |
+ leftDataRightNode |
+ leftNodeRightData |
+ leftNodeOnly |
+ rightNodeOnly |
+ dataToNodeMigrationTargets
+
+
+ if ((newDataMap == (leftDataOnly | leftDataRightDataLeftOverwrites)) && (newNodeMap == leftNodeOnly)) {
+ // nothing from `bm` will make it into the result -- return early
+ return this
+ }
+
+ val newDataSize = bitCount(newDataMap)
+ val newContentSize = newDataSize + bitCount(newNodeMap)
+
+ val newContent = new Array[Any](newContentSize)
+ val newOriginalHashes = new Array[Int](newDataSize)
+ var newSize = 0
+ var newCachedHashCode = 0
+
+ {
+ var leftDataIdx = 0
+ var rightDataIdx = 0
+ var leftNodeIdx = 0
+ var rightNodeIdx = 0
+
+ val nextShift = shift + Node.BitPartitionSize
+
+ var compressedDataIdx = 0
+ var compressedNodeIdx = 0
+
+ var bitpos = minimumBitPos
+ var finished = false
+
+ while (!finished) {
+
+ if ((bitpos & leftNodeRightNode) != 0) {
+ val leftNode = getNode(leftNodeIdx)
+ val newNode = leftNode.concat(bm.getNode(rightNodeIdx), nextShift)
+ if (leftNode ne newNode) {
+ anyChangesMadeSoFar = true
+ }
+ newContent(newContentSize - compressedNodeIdx - 1) = newNode
+ compressedNodeIdx += 1
+ rightNodeIdx += 1
+ leftNodeIdx += 1
+ newSize += newNode.size
+ newCachedHashCode += newNode.cachedJavaKeySetHashCode
+
+ } else if ((bitpos & leftDataRightNode) != 0) {
+ anyChangesMadeSoFar = true
+ val newNode = {
+ val n = bm.getNode(rightNodeIdx)
+ val leftPayload = getPayload(leftDataIdx)
+ val leftOriginalHash = getHash(leftDataIdx)
+ val leftImproved = improve(leftOriginalHash)
+ n.updated(leftPayload, leftOriginalHash, leftImproved, nextShift)
+ }
+
+ newContent(newContentSize - compressedNodeIdx - 1) = newNode
+ compressedNodeIdx += 1
+ rightNodeIdx += 1
+ leftDataIdx += 1
+ newSize += newNode.size
+ newCachedHashCode += newNode.cachedJavaKeySetHashCode
+ }
+ else if ((bitpos & leftNodeRightData) != 0) {
+ val newNode = {
+ val rightOriginalHash = bm.getHash(rightDataIdx)
+ val leftNode = getNode(leftNodeIdx)
+ val updated = leftNode.updated(
+ element = bm.getPayload(rightDataIdx),
+ originalHash = bm.getHash(rightDataIdx),
+ hash = improve(rightOriginalHash),
+ shift = nextShift
+ )
+ if (updated ne leftNode) {
+ anyChangesMadeSoFar = true
+ }
+ updated
+ }
+
+ newContent(newContentSize - compressedNodeIdx - 1) = newNode
+ compressedNodeIdx += 1
+ leftNodeIdx += 1
+ rightDataIdx += 1
+ newSize += newNode.size
+ newCachedHashCode += newNode.cachedJavaKeySetHashCode
+
+ } else if ((bitpos & leftDataOnly) != 0) {
+ val originalHash = originalHashes(leftDataIdx)
+ newContent(compressedDataIdx) = getPayload(leftDataIdx).asInstanceOf[AnyRef]
+ newOriginalHashes(compressedDataIdx) = originalHash
+
+ compressedDataIdx += 1
+ leftDataIdx += 1
+ newSize += 1
+ newCachedHashCode += improve(originalHash)
+ } else if ((bitpos & rightDataOnly) != 0) {
+ anyChangesMadeSoFar = true
+ val originalHash = bm.originalHashes(rightDataIdx)
+ newContent(compressedDataIdx) = bm.getPayload(rightDataIdx).asInstanceOf[AnyRef]
+ newOriginalHashes(compressedDataIdx) = originalHash
+
+ compressedDataIdx += 1
+ rightDataIdx += 1
+ newSize += 1
+ newCachedHashCode += improve(originalHash)
+ } else if ((bitpos & leftNodeOnly) != 0) {
+ val newNode = getNode(leftNodeIdx)
+ newContent(newContentSize - compressedNodeIdx - 1) = newNode
+ compressedNodeIdx += 1
+ leftNodeIdx += 1
+ newSize += newNode.size
+ newCachedHashCode += newNode.cachedJavaKeySetHashCode
+ } else if ((bitpos & rightNodeOnly) != 0) {
+ anyChangesMadeSoFar = true
+ val newNode = bm.getNode(rightNodeIdx)
+ newContent(newContentSize - compressedNodeIdx - 1) = newNode
+ compressedNodeIdx += 1
+ rightNodeIdx += 1
+ newSize += newNode.size
+ newCachedHashCode += newNode.cachedJavaKeySetHashCode
+ } else if ((bitpos & leftDataRightDataMigrateToNode) != 0) {
+ anyChangesMadeSoFar = true
+ val newNode = {
+ val leftOriginalHash = getHash(leftDataIdx)
+ val rightOriginalHash = bm.getHash(rightDataIdx)
+
+ bm.mergeTwoKeyValPairs(
+ getPayload(leftDataIdx), leftOriginalHash, improve(leftOriginalHash),
+ bm.getPayload(rightDataIdx), rightOriginalHash, improve(rightOriginalHash),
+ nextShift
+ )
+ }
+
+ newContent(newContentSize - compressedNodeIdx - 1) = newNode
+ compressedNodeIdx += 1
+ leftDataIdx += 1
+ rightDataIdx += 1
+ newSize += newNode.size
+ newCachedHashCode += newNode.cachedJavaKeySetHashCode
+ } else if ((bitpos & leftDataRightDataLeftOverwrites) != 0) {
+ val originalHash = bm.originalHashes(rightDataIdx)
+ newContent(compressedDataIdx) = bm.getPayload(rightDataIdx).asInstanceOf[AnyRef]
+ newOriginalHashes(compressedDataIdx) = originalHash
+
+ compressedDataIdx += 1
+ rightDataIdx += 1
+ newSize += 1
+ newCachedHashCode += improve(originalHash)
+ leftDataIdx += 1
+ }
+
+ if (bitpos == maximumBitPos) {
+ finished = true
+ } else {
+ bitpos = bitpos << 1
+ }
+ }
+ }
+
+ if (anyChangesMadeSoFar)
+ new BitmapIndexedSetNode(
+ dataMap = newDataMap,
+ nodeMap = newNodeMap,
+ content = newContent,
+ originalHashes = newOriginalHashes,
+ size = newSize,
+ cachedJavaKeySetHashCode = newCachedHashCode
+ )
+ else this
+
+ case _ =>
+ // should never happen -- hash collisions are never at the same level as bitmapIndexedSetNodes
+ throw new UnsupportedOperationException("Cannot concatenate a HashCollisionSetNode with a BitmapIndexedSetNode")
+ }
+
+ override def foreachWithHash(f: (A, Int) => Unit): Unit = {
+ val iN = payloadArity // arity doesn't change during this operation
+ var i = 0
+ while (i < iN) {
+ f(getPayload(i), getHash(i))
+ i += 1
+ }
+
+ val jN = nodeArity // arity doesn't change during this operation
+ var j = 0
+ while (j < jN) {
+ getNode(j).foreachWithHash(f)
+ j += 1
+ }
+ }
+
+ override def foreachWithHashWhile(f: (A, Int) => Boolean): Boolean = {
+ val thisPayloadArity = payloadArity
+ var pass = true
+ var i = 0
+ while (i < thisPayloadArity && pass) {
+ pass &&= f(getPayload(i), getHash(i))
+ i += 1
+ }
+
+ val thisNodeArity = nodeArity
+ var j = 0
+ while (j < thisNodeArity && pass) {
+ pass &&= getNode(j).foreachWithHashWhile(f)
+ j += 1
+ }
+ pass
+ }
+}
+
+private final class HashCollisionSetNode[A](val originalHash: Int, val hash: Int, var content: Vector[A]) extends SetNode[A] {
+
+ import Node._
+
+ require(content.length >= 2)
+
+ def contains(element: A, originalHash: Int, hash: Int, shift: Int): Boolean =
+ this.hash == hash && content.contains(element)
+
+ def updated(element: A, originalHash: Int, hash: Int, shift: Int): SetNode[A] =
+ if (this.contains(element, originalHash, hash, shift)) {
+ this
+ } else {
+ new HashCollisionSetNode[A](originalHash, hash, content.appended(element))
+ }
+
+ /**
+ * Remove an element from the hash collision node.
+ *
+ * When after deletion only one element remains, we return a bit-mapped indexed node with a
+ * singleton element and a hash-prefix for trie level 0. This node will be then a) either become
+ * the new root, or b) unwrapped and inlined deeper in the trie.
+ */
+ def removed(element: A, originalHash: Int, hash: Int, shift: Int): SetNode[A] =
+ if (!this.contains(element, originalHash, hash, shift)) {
+ this
+ } else {
+ val updatedContent = content.filterNot(element0 => element0 == element)
+ // assert(updatedContent.size == content.size - 1)
+
+ updatedContent.size match {
+ case 1 => new BitmapIndexedSetNode[A](bitposFrom(maskFrom(hash, 0)), 0, Array(updatedContent(0)), Array(originalHash), 1, hash)
+ case _ => new HashCollisionSetNode[A](originalHash, hash, updatedContent)
+ }
+ }
+
+ def hasNodes: Boolean = false
+
+ def nodeArity: Int = 0
+
+ def getNode(index: Int): SetNode[A] =
+ throw new IndexOutOfBoundsException("No sub-nodes present in hash-collision leaf node.")
+
+ def hasPayload: Boolean = true
+
+ def payloadArity: Int = content.length
+
+ def getPayload(index: Int): A = content(index)
+
+ override def getHash(index: Int): Int = originalHash
+
+ def size: Int = content.length
+
+ def foreach[U](f: A => U): Unit = {
+ val iter = content.iterator
+ while (iter.hasNext) {
+ f(iter.next())
+ }
+ }
+
+
+ override def cachedJavaKeySetHashCode: Int = size * hash
+
+ def subsetOf(that: SetNode[A], shift: Int): Boolean = if (this eq that) true else that match {
+ case node: HashCollisionSetNode[A] =>
+ this.payloadArity <= node.payloadArity && this.content.forall(node.content.contains)
+ case _ =>
+ false
+ }
+
+ override def filterImpl(pred: A => Boolean, flipped: Boolean): SetNode[A] = {
+ val newContent = content.filterImpl(pred, flipped)
+ val newContentLength = newContent.length
+ if (newContentLength == 0) {
+ SetNode.empty
+ } else if (newContentLength == 1) {
+ new BitmapIndexedSetNode[A](bitposFrom(maskFrom(hash, 0)), 0, Array(newContent.head), Array(originalHash), 1, hash)
+ } else if (newContent.length == content.length) this
+ else new HashCollisionSetNode(originalHash, hash, newContent)
+ }
+
+ override def diff(that: SetNode[A], shift: Int): SetNode[A] =
+ filterImpl(that.contains(_, originalHash, hash, shift), flipped = true)
+
+ override def equals(that: Any): Boolean =
+ that match {
+ case node: HashCollisionSetNode[_] =>
+ (this eq node) ||
+ (this.hash == node.hash) &&
+ (this.content.size == node.content.size) &&
+ this.content.forall(node.content.contains)
+ case _ => false
+ }
+
+ override def hashCode(): Int =
+ throw new UnsupportedOperationException("Trie nodes do not support hashing.")
+
+ override def copy(): HashCollisionSetNode[A] = new HashCollisionSetNode[A](originalHash, hash, content)
+
+ override def concat(that: SetNode[A], shift: Int): SetNode[A] = that match {
+ case hc: HashCollisionSetNode[A] =>
+ if (hc eq this) {
+ this
+ } else {
+ var newContent: VectorBuilder[A] = null
+ val iter = hc.content.iterator
+ while (iter.hasNext) {
+ val nextPayload = iter.next()
+ if (!content.contains(nextPayload)) {
+ if (newContent eq null) {
+ newContent = new VectorBuilder()
+ newContent.addAll(this.content)
+ }
+ newContent.addOne(nextPayload)
+ }
+ }
+ if (newContent eq null) this else new HashCollisionSetNode(originalHash, hash, newContent.result())
+ }
+ case _: BitmapIndexedSetNode[A] =>
+ // should never happen -- hash collisions are never at the same level as bitmapIndexedSetNodes
+ throw new UnsupportedOperationException("Cannot concatenate a HashCollisionSetNode with a BitmapIndexedSetNode")
+ }
+
+ override def foreachWithHash(f: (A, Int) => Unit): Unit = {
+ val iter = content.iterator
+ while (iter.hasNext) {
+ val next = iter.next()
+ f(next.asInstanceOf[A], originalHash)
+ }
+ }
+
+ override def foreachWithHashWhile(f: (A, Int) => Boolean): Boolean = {
+ var stillGoing = true
+ val iter = content.iterator
+ while (iter.hasNext && stillGoing) {
+ val next = iter.next()
+ stillGoing &&= f(next.asInstanceOf[A], originalHash)
+ }
+ stillGoing
+ }
+}
+
+private final class SetIterator[A](rootNode: SetNode[A])
+ extends ChampBaseIterator[A, SetNode[A]](rootNode) {
+
+ def next() = {
+ if (!hasNext) Iterator.empty.next()
+
+ val payload = currentValueNode.getPayload(currentValueCursor)
+ currentValueCursor += 1
+
+ payload
+ }
+
+}
+
+private final class SetReverseIterator[A](rootNode: SetNode[A])
+ extends ChampBaseReverseIterator[A, SetNode[A]](rootNode) {
+
+ def next(): A = {
+ if (!hasNext) Iterator.empty.next()
+
+ val payload = currentValueNode.getPayload(currentValueCursor)
+ currentValueCursor -= 1
+
+ payload
+ }
+
+}
+
+private final class SetHashIterator[A](rootNode: SetNode[A])
+ extends ChampBaseIterator[AnyRef, SetNode[A]](rootNode) {
+ private[this] var hash = 0
+ override def hashCode(): Int = hash
+
+ def next(): AnyRef = {
+ if (!hasNext) Iterator.empty.next()
+
+ hash = currentValueNode.getHash(currentValueCursor)
+ currentValueCursor += 1
+ this
+ }
+
+}
+
+
+/**
+ * $factoryInfo
+ *
+ * @define Coll `immutable.HashSet`
+ * @define coll immutable champ hash set
+ */
+@SerialVersionUID(3L)
+object HashSet extends IterableFactory[HashSet] {
+
+ @transient
+ private final val EmptySet = new HashSet(SetNode.empty)
+
+ def empty[A]: HashSet[A] =
+ EmptySet.asInstanceOf[HashSet[A]]
+
+ def from[A](source: collection.IterableOnce[A]): HashSet[A] =
+ source match {
+ case hs: HashSet[A] => hs
+ case _ if source.knownSize == 0 => empty[A]
+ case _ => (newBuilder[A] ++= source).result()
+ }
+
+ /** Create a new Builder which can be reused after calling `result()` without an
+ * intermediate call to `clear()` in order to build multiple related results.
+ */
+ def newBuilder[A]: ReusableBuilder[A, HashSet[A]] = new HashSetBuilder
+}
+
+/** Builder for HashSet.
+ * $multipleResults
+ */
+private[collection] final class HashSetBuilder[A] extends ReusableBuilder[A, HashSet[A]] {
+ import Node._
+ import SetNode._
+
+ private def newEmptyRootNode = new BitmapIndexedSetNode[A](0, 0, Array.emptyObjectArray.asInstanceOf[Array[Any]], Array.emptyIntArray, 0, 0)
+
+ /** The last given out HashSet as a return value of `result()`, if any, otherwise null.
+ * Indicates that on next add, the elements should be copied to an identical structure, before continuing
+ * mutations. */
+ private var aliased: HashSet[A] = _
+
+ private def isAliased: Boolean = aliased != null
+
+ /** The root node of the partially built hashmap. */
+ private var rootNode: BitmapIndexedSetNode[A] = newEmptyRootNode
+
+ /** Inserts element `elem` into array `as` at index `ix`, shifting right the trailing elems */
+ private def insertElement(as: Array[Int], ix: Int, elem: Int): Array[Int] = {
+ if (ix < 0) throw new ArrayIndexOutOfBoundsException
+ if (ix > as.length) throw new ArrayIndexOutOfBoundsException
+ val result = new Array[Int](as.length + 1)
+ arraycopy(as, 0, result, 0, ix)
+ result(ix) = elem
+ arraycopy(as, ix, result, ix + 1, as.length - ix)
+ result
+ }
+
+ /** Inserts key-value into the bitmapIndexMapNode. Requires that this is a new key-value pair */
+ private def insertValue[A1 >: A](bm: BitmapIndexedSetNode[A], bitpos: Int, key: A, originalHash: Int, keyHash: Int): Unit = {
+ val dataIx = bm.dataIndex(bitpos)
+ val idx = TupleLength * dataIx
+
+ val src = bm.content
+ val dst = new Array[Any](src.length + TupleLength)
+
+ // copy 'src' and insert 2 element(s) at position 'idx'
+ arraycopy(src, 0, dst, 0, idx)
+ dst(idx) = key
+ arraycopy(src, idx, dst, idx + TupleLength, src.length - idx)
+
+ val dstHashes = insertElement(bm.originalHashes, dataIx, originalHash)
+
+ bm.dataMap = bm.dataMap | bitpos
+ bm.content = dst
+ bm.originalHashes = dstHashes
+ bm.size += 1
+ bm.cachedJavaKeySetHashCode += keyHash
+ }
+
+ /** Mutates `bm` to replace inline data at bit position `bitpos` with updated key/value */
+ private def setValue[A1 >: A](bm: BitmapIndexedSetNode[A], bitpos: Int, elem: A): Unit = {
+ val dataIx = bm.dataIndex(bitpos)
+ val idx = TupleLength * dataIx
+ bm.content(idx) = elem
+ }
+
+ def update(setNode: SetNode[A], element: A, originalHash: Int, elementHash: Int, shift: Int): Unit =
+ setNode match {
+ case bm: BitmapIndexedSetNode[A] =>
+ val mask = maskFrom(elementHash, shift)
+ val bitpos = bitposFrom(mask)
+
+ if ((bm.dataMap & bitpos) != 0) {
+ val index = indexFrom(bm.dataMap, mask, bitpos)
+ val element0 = bm.getPayload(index)
+ val element0UnimprovedHash = bm.getHash(index)
+
+ if (element0UnimprovedHash == originalHash && element0 == element) {
+ setValue(bm, bitpos, element0)
+ } else {
+ val element0Hash = improve(element0UnimprovedHash)
+ val subNodeNew = bm.mergeTwoKeyValPairs(element0, element0UnimprovedHash, element0Hash, element, originalHash, elementHash, shift + BitPartitionSize)
+ bm.migrateFromInlineToNodeInPlace(bitpos, element0Hash, subNodeNew)
+ }
+ } else if ((bm.nodeMap & bitpos) != 0) {
+ val index = indexFrom(bm.nodeMap, mask, bitpos)
+ val subNode = bm.getNode(index)
+ val beforeSize = subNode.size
+ val beforeHashCode = subNode.cachedJavaKeySetHashCode
+ update(subNode, element, originalHash, elementHash, shift + BitPartitionSize)
+ bm.size += subNode.size - beforeSize
+ bm.cachedJavaKeySetHashCode += subNode.cachedJavaKeySetHashCode - beforeHashCode
+ } else {
+ insertValue(bm, bitpos, element, originalHash, elementHash)
+ }
+ case hc: HashCollisionSetNode[A] =>
+ val index = hc.content.indexOf(element)
+ if (index < 0) {
+ hc.content = hc.content.appended(element)
+ } else {
+ hc.content = hc.content.updated(index, element)
+ }
+ }
+
+ /** If currently referencing aliased structure, copy elements to new mutable structure */
+ private def ensureUnaliased():Unit = {
+ if (isAliased) copyElems()
+ aliased = null
+ }
+
+ /** Copy elements to new mutable structure */
+ private def copyElems(): Unit = {
+ rootNode = rootNode.copy()
+ }
+
+ override def result(): HashSet[A] =
+ if (rootNode.size == 0) {
+ HashSet.empty
+ } else if (aliased != null) {
+ aliased
+ } else {
+ aliased = new HashSet(rootNode)
+ releaseFence()
+ aliased
+ }
+
+ override def addOne(elem: A): this.type = {
+ ensureUnaliased()
+ val h = elem.##
+ val im = improve(h)
+ update(rootNode, elem, originalHash = h, elementHash = im, shift = 0)
+ this
+ }
+
+ override def addAll(xs: IterableOnce[A]) = {
+ ensureUnaliased()
+ xs match {
+ case hm: HashSet[A] =>
+ new ChampBaseIterator[A, SetNode[A]](hm.rootNode) {
+ while(hasNext) {
+ val originalHash = currentValueNode.getHash(currentValueCursor)
+ update(
+ setNode = rootNode,
+ element = currentValueNode.getPayload(currentValueCursor),
+ originalHash = originalHash,
+ elementHash = improve(originalHash),
+ shift = 0
+ )
+ currentValueCursor += 1
+ }
+ override def next() = Iterator.empty.next()
+ }
+ case other =>
+ val it = other.iterator
+ while(it.hasNext) addOne(it.next())
+ }
+
+ this
+ }
+
+ override def clear(): Unit = {
+ aliased = null
+ if (rootNode.size > 0) {
+ // if rootNode is empty, we will not have given it away anyways, we instead give out the reused Set.empty
+ rootNode = newEmptyRootNode
+ }
+ }
+
+ private[collection] def size: Int = rootNode.size
+
+ override def knownSize: Int = rootNode.size
+}
diff --git a/library/src/scala/collection/immutable/IntMap.scala b/library/src/scala/collection/immutable/IntMap.scala
new file mode 100644
index 000000000000..1aa1a6108d0c
--- /dev/null
+++ b/library/src/scala/collection/immutable/IntMap.scala
@@ -0,0 +1,502 @@
+/*
+ * 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 scala.collection.generic.{BitOperations, DefaultSerializationProxy}
+import scala.collection.mutable.{Builder, ImmutableBuilder}
+import scala.annotation.tailrec
+import scala.annotation.unchecked.uncheckedVariance
+import scala.language.implicitConversions
+
+/** Utility class for integer maps.
+ */
+private[immutable] object IntMapUtils extends BitOperations.Int {
+ def branchMask(i: Int, j: Int) = highestOneBit(i ^ j)
+
+ def join[T](p1: Int, t1: IntMap[T], p2: Int, t2: IntMap[T]): IntMap[T] = {
+ val m = branchMask(p1, p2)
+ val p = mask(p1, m)
+ if (zero(p1, m)) IntMap.Bin(p, m, t1, t2)
+ else IntMap.Bin(p, m, t2, t1)
+ }
+
+ def bin[T](prefix: Int, mask: Int, left: IntMap[T], right: IntMap[T]): IntMap[T] = (left, right) match {
+ case (left, IntMap.Nil) => left
+ case (IntMap.Nil, right) => right
+ case (left, right) => IntMap.Bin(prefix, mask, left, right)
+ }
+}
+
+import IntMapUtils.{Int => _, _}
+
+/** A companion object for integer maps.
+ *
+ * @define Coll `IntMap`
+ */
+object IntMap {
+ def empty[T] : IntMap[T] = IntMap.Nil
+
+ def singleton[T](key: Int, value: T): IntMap[T] = IntMap.Tip(key, value)
+
+ def apply[T](elems: (Int, T)*): IntMap[T] =
+ elems.foldLeft(empty[T])((x, y) => x.updated(y._1, y._2))
+
+ def from[V](coll: IterableOnce[(Int, V)]): IntMap[V] =
+ newBuilder[V].addAll(coll).result()
+
+ private[immutable] case object Nil extends IntMap[Nothing] {
+ // Important! Without this equals method in place, an infinite
+ // loop from Map.equals => size => pattern-match-on-Nil => equals
+ // develops. Case objects and custom equality don't mix without
+ // careful handling.
+ override def equals(that : Any) = that match {
+ case _: this.type => true
+ case _: IntMap[_] => false // The only empty IntMaps are eq Nil
+ case _ => super.equals(that)
+ }
+ }
+
+ private[immutable] case class Tip[+T](key: Int, value: T) extends IntMap[T]{
+ def withValue[S](s: S) =
+ if (s.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef]) this.asInstanceOf[IntMap.Tip[S]]
+ else IntMap.Tip(key, s)
+ }
+
+ private[immutable] case class Bin[+T](prefix: Int, mask: Int, left: IntMap[T], right: IntMap[T]) extends IntMap[T] {
+ def bin[S](left: IntMap[S], right: IntMap[S]): IntMap[S] = {
+ if ((this.left eq left) && (this.right eq right)) this.asInstanceOf[IntMap.Bin[S]]
+ else IntMap.Bin[S](prefix, mask, left, right)
+ }
+ }
+
+ def newBuilder[V]: Builder[(Int, V), IntMap[V]] =
+ new ImmutableBuilder[(Int, V), IntMap[V]](empty) {
+ def addOne(elem: (Int, V)): this.type = { elems = elems + elem; this }
+ }
+
+ implicit def toFactory[V](dummy: IntMap.type): Factory[(Int, V), IntMap[V]] = ToFactory.asInstanceOf[Factory[(Int, V), IntMap[V]]]
+
+ @SerialVersionUID(3L)
+ private[this] object ToFactory extends Factory[(Int, AnyRef), IntMap[AnyRef]] with Serializable {
+ def fromSpecific(it: IterableOnce[(Int, AnyRef)]): IntMap[AnyRef] = IntMap.from[AnyRef](it)
+ def newBuilder: Builder[(Int, AnyRef), IntMap[AnyRef]] = IntMap.newBuilder[AnyRef]
+ }
+
+ implicit def toBuildFrom[V](factory: IntMap.type): BuildFrom[Any, (Int, V), IntMap[V]] = ToBuildFrom.asInstanceOf[BuildFrom[Any, (Int, V), IntMap[V]]]
+ private[this] object ToBuildFrom extends BuildFrom[Any, (Int, AnyRef), IntMap[AnyRef]] {
+ def fromSpecific(from: Any)(it: IterableOnce[(Int, AnyRef)]) = IntMap.from(it)
+ def newBuilder(from: Any) = IntMap.newBuilder[AnyRef]
+ }
+
+ implicit def iterableFactory[V]: Factory[(Int, V), IntMap[V]] = toFactory(this)
+ implicit def buildFromIntMap[V]: BuildFrom[IntMap[_], (Int, V), IntMap[V]] = toBuildFrom(this)
+}
+
+// Iterator over a non-empty IntMap.
+private[immutable] abstract class IntMapIterator[V, T](it: IntMap[V]) extends AbstractIterator[T] {
+
+ // Basically this uses a simple stack to emulate conversion over the tree. However
+ // because we know that Ints are at least 32 bits we can have at most 32 IntMap.Bins and
+ // one IntMap.Tip sitting on the tree at any point. Therefore we know the maximum stack
+ // depth is 33 and
+ var index = 0
+ var buffer = new Array[AnyRef](33)
+
+ def pop = {
+ index -= 1
+ buffer(index).asInstanceOf[IntMap[V]]
+ }
+
+ def push(x: IntMap[V]): Unit = {
+ buffer(index) = x.asInstanceOf[AnyRef]
+ index += 1
+ }
+ push(it)
+
+ /**
+ * What value do we assign to a tip?
+ */
+ def valueOf(tip: IntMap.Tip[V]): T
+
+ def hasNext = index != 0
+ @tailrec
+ final def next(): T =
+ pop match {
+ case IntMap.Bin(_,_, t@IntMap.Tip(_, _), right) => {
+ push(right)
+ valueOf(t)
+ }
+ case IntMap.Bin(_, _, left, right) => {
+ push(right)
+ push(left)
+ next()
+ }
+ case t@IntMap.Tip(_, _) => valueOf(t)
+ // This should never happen. We don't allow IntMap.Nil in subtrees of the IntMap
+ // and don't return an IntMapIterator for IntMap.Nil.
+ case IntMap.Nil => throw new IllegalStateException("Empty maps not allowed as subtrees")
+ }
+}
+
+private[immutable] class IntMapEntryIterator[V](it: IntMap[V]) extends IntMapIterator[V, (Int, V)](it) {
+ def valueOf(tip: IntMap.Tip[V]) = (tip.key, tip.value)
+}
+
+private[immutable] class IntMapValueIterator[V](it: IntMap[V]) extends IntMapIterator[V, V](it) {
+ def valueOf(tip: IntMap.Tip[V]) = tip.value
+}
+
+private[immutable] class IntMapKeyIterator[V](it: IntMap[V]) extends IntMapIterator[V, Int](it) {
+ def valueOf(tip: IntMap.Tip[V]) = tip.key
+}
+
+import IntMap._
+
+/** Specialised immutable map structure for integer keys, based on
+ * [[https://ittc.ku.edu/~andygill/papers/IntMap98.pdf Fast Mergeable Integer Maps]]
+ * by Okasaki and Gill. Essentially a trie based on binary digits of the integers.
+ *
+ * '''Note:''' This class is as of 2.8 largely superseded by HashMap.
+ *
+ * @tparam T type of the values associated with integer keys.
+ *
+ * @define Coll `immutable.IntMap`
+ * @define coll immutable integer map
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+sealed abstract class IntMap[+T] extends AbstractMap[Int, T]
+ with StrictOptimizedMapOps[Int, T, Map, IntMap[T]]
+ with Serializable {
+
+ override protected def fromSpecific(coll: scala.collection.IterableOnce[(Int, T) @uncheckedVariance]): IntMap[T] =
+ intMapFrom[T](coll)
+ protected def intMapFrom[V2](coll: scala.collection.IterableOnce[(Int, V2)]): IntMap[V2] = {
+ val b = IntMap.newBuilder[V2]
+ b.sizeHint(coll)
+ b.addAll(coll)
+ b.result()
+ }
+ override protected def newSpecificBuilder: Builder[(Int, T), IntMap[T]] @uncheckedVariance =
+ new ImmutableBuilder[(Int, T), IntMap[T]](empty) {
+ def addOne(elem: (Int, T)): this.type = { elems = elems + elem; this }
+ }
+
+ override def empty: IntMap[T] = IntMap.Nil
+
+ override def toList = {
+ val buffer = new scala.collection.mutable.ListBuffer[(Int, T)]
+ foreach(buffer += _)
+ buffer.toList
+ }
+
+ /**
+ * Iterator over key, value pairs of the map in unsigned order of the keys.
+ *
+ * @return an iterator over pairs of integer keys and corresponding values.
+ */
+ def iterator: Iterator[(Int, T)] = this match {
+ case IntMap.Nil => Iterator.empty
+ case _ => new IntMapEntryIterator(this)
+ }
+
+ /**
+ * Loops over the key, value pairs of the map in unsigned order of the keys.
+ */
+ override final def foreach[U](f: ((Int, T)) => U): Unit = this match {
+ case IntMap.Bin(_, _, left, right) => { left.foreach(f); right.foreach(f) }
+ case IntMap.Tip(key, value) => f((key, value))
+ case IntMap.Nil =>
+ }
+
+ override def foreachEntry[U](f: (Int, T) => U): Unit = this match {
+ case IntMap.Bin(_, _, left, right) => { left.foreachEntry(f); right.foreachEntry(f) }
+ case IntMap.Tip(key, value) => f(key, value)
+ case IntMap.Nil =>
+ }
+
+ override def keysIterator: Iterator[Int] = this match {
+ case IntMap.Nil => Iterator.empty
+ case _ => new IntMapKeyIterator(this)
+ }
+
+ /**
+ * Loop over the keys of the map. The same as `keys.foreach(f)`, but may
+ * be more efficient.
+ *
+ * @param f The loop body
+ */
+ final def foreachKey[U](f: Int => U): Unit = this match {
+ case IntMap.Bin(_, _, left, right) => { left.foreachKey(f); right.foreachKey(f) }
+ case IntMap.Tip(key, _) => f(key)
+ case IntMap.Nil =>
+ }
+
+ override def valuesIterator: Iterator[T] = this match {
+ case IntMap.Nil => Iterator.empty
+ case _ => new IntMapValueIterator(this)
+ }
+
+ /**
+ * Loop over the values of the map. The same as `values.foreach(f)`, but may
+ * be more efficient.
+ *
+ * @param f The loop body
+ */
+ final def foreachValue[U](f: T => U): Unit = this match {
+ case IntMap.Bin(_, _, left, right) => { left.foreachValue(f); right.foreachValue(f) }
+ case IntMap.Tip(_, value) => f(value)
+ case IntMap.Nil =>
+ }
+
+ override protected[this] def className = "IntMap"
+
+ override def isEmpty = this eq IntMap.Nil
+ override def knownSize: Int = if (isEmpty) 0 else super.knownSize
+ override def filter(f: ((Int, T)) => Boolean): IntMap[T] = this match {
+ case IntMap.Bin(prefix, mask, left, right) => {
+ val (newleft, newright) = (left.filter(f), right.filter(f))
+ if ((left eq newleft) && (right eq newright)) this
+ else bin(prefix, mask, newleft, newright)
+ }
+ case IntMap.Tip(key, value) =>
+ if (f((key, value))) this
+ else IntMap.Nil
+ case IntMap.Nil => IntMap.Nil
+ }
+
+ override def transform[S](f: (Int, T) => S): IntMap[S] = this match {
+ case b@IntMap.Bin(prefix, mask, left, right) => b.bin(left.transform(f), right.transform(f))
+ case t@IntMap.Tip(key, value) => t.withValue(f(key, value))
+ case IntMap.Nil => IntMap.Nil
+ }
+
+ final override def size: Int = this match {
+ case IntMap.Nil => 0
+ case IntMap.Tip(_, _) => 1
+ case IntMap.Bin(_, _, left, right) => left.size + right.size
+ }
+
+ @tailrec
+ final def get(key: Int): Option[T] = this match {
+ case IntMap.Bin(prefix, mask, left, right) => if (zero(key, mask)) left.get(key) else right.get(key)
+ case IntMap.Tip(key2, value) => if (key == key2) Some(value) else None
+ case IntMap.Nil => None
+ }
+
+ @tailrec
+ final override def getOrElse[S >: T](key: Int, default: => S): S = this match {
+ case IntMap.Nil => default
+ case IntMap.Tip(key2, value) => if (key == key2) value else default
+ case IntMap.Bin(prefix, mask, left, right) =>
+ if (zero(key, mask)) left.getOrElse(key, default) else right.getOrElse(key, default)
+ }
+
+ @tailrec
+ final override def apply(key: Int): T = this match {
+ case IntMap.Bin(prefix, mask, left, right) => if (zero(key, mask)) left(key) else right(key)
+ case IntMap.Tip(key2, value) => if (key == key2) value else throw new IllegalArgumentException("Key not found")
+ case IntMap.Nil => throw new IllegalArgumentException("key not found")
+ }
+
+ override def + [S >: T] (kv: (Int, S)): IntMap[S] = updated(kv._1, kv._2)
+
+ override def updated[S >: T](key: Int, value: S): IntMap[S] = this match {
+ case IntMap.Bin(prefix, mask, left, right) =>
+ if (!hasMatch(key, prefix, mask)) join(key, IntMap.Tip(key, value), prefix, this)
+ else if (zero(key, mask)) IntMap.Bin(prefix, mask, left.updated(key, value), right)
+ else IntMap.Bin(prefix, mask, left, right.updated(key, value))
+ case IntMap.Tip(key2, value2) =>
+ if (key == key2) IntMap.Tip(key, value)
+ else join(key, IntMap.Tip(key, value), key2, this)
+ case IntMap.Nil => IntMap.Tip(key, value)
+ }
+
+ def map[V2](f: ((Int, T)) => (Int, V2)): IntMap[V2] = intMapFrom(new View.Map(this, f))
+
+ def flatMap[V2](f: ((Int, T)) => IterableOnce[(Int, V2)]): IntMap[V2] = intMapFrom(new View.FlatMap(this, f))
+
+ override def concat[V1 >: T](that: collection.IterableOnce[(Int, V1)]): IntMap[V1] =
+ super.concat(that).asInstanceOf[IntMap[V1]] // Already has correct type but not declared as such
+
+ override def ++ [V1 >: T](that: collection.IterableOnce[(Int, V1)]): IntMap[V1] = concat(that)
+
+ def collect[V2](pf: PartialFunction[(Int, T), (Int, V2)]): IntMap[V2] =
+ strictOptimizedCollect(IntMap.newBuilder[V2], pf)
+
+ /**
+ * Updates the map, using the provided function to resolve conflicts if the key is already present.
+ *
+ * Equivalent to:
+ * {{{
+ * this.get(key) match {
+ * case None => this.update(key, value)
+ * case Some(oldvalue) => this.update(key, f(oldvalue, value)
+ * }
+ * }}}
+ *
+ * @tparam S The supertype of values in this `LongMap`.
+ * @param key The key to update
+ * @param value The value to use if there is no conflict
+ * @param f The function used to resolve conflicts.
+ * @return The updated map.
+ */
+ def updateWith[S >: T](key: Int, value: S, f: (T, S) => S): IntMap[S] = this match {
+ case IntMap.Bin(prefix, mask, left, right) =>
+ if (!hasMatch(key, prefix, mask)) join(key, IntMap.Tip(key, value), prefix, this)
+ else if (zero(key, mask)) IntMap.Bin(prefix, mask, left.updateWith(key, value, f), right)
+ else IntMap.Bin(prefix, mask, left, right.updateWith(key, value, f))
+ case IntMap.Tip(key2, value2) =>
+ if (key == key2) IntMap.Tip(key, f(value2, value))
+ else join(key, IntMap.Tip(key, value), key2, this)
+ case IntMap.Nil => IntMap.Tip(key, value)
+ }
+
+ def removed (key: Int): IntMap[T] = this match {
+ case IntMap.Bin(prefix, mask, left, right) =>
+ if (!hasMatch(key, prefix, mask)) this
+ else if (zero(key, mask)) bin(prefix, mask, left - key, right)
+ else bin(prefix, mask, left, right - key)
+ case IntMap.Tip(key2, _) =>
+ if (key == key2) IntMap.Nil
+ else this
+ case IntMap.Nil => IntMap.Nil
+ }
+
+ /**
+ * A combined transform and filter function. Returns an `IntMap` such that
+ * for each `(key, value)` mapping in this map, if `f(key, value) == None`
+ * the map contains no mapping for key, and if `f(key, value)`.
+ *
+ * @tparam S The type of the values in the resulting `LongMap`.
+ * @param f The transforming function.
+ * @return The modified map.
+ */
+ def modifyOrRemove[S](f: (Int, T) => Option[S]): IntMap[S] = this match {
+ case IntMap.Bin(prefix, mask, left, right) =>
+ val newleft = left.modifyOrRemove(f)
+ val newright = right.modifyOrRemove(f)
+ if ((left eq newleft) && (right eq newright)) this.asInstanceOf[IntMap[S]]
+ else bin(prefix, mask, newleft, newright)
+ case IntMap.Tip(key, value) => f(key, value) match {
+ case None =>
+ IntMap.Nil
+ case Some(value2) =>
+ //hack to preserve sharing
+ if (value.asInstanceOf[AnyRef] eq value2.asInstanceOf[AnyRef]) this.asInstanceOf[IntMap[S]]
+ else IntMap.Tip(key, value2)
+ }
+ case IntMap.Nil =>
+ IntMap.Nil
+ }
+
+ /**
+ * Forms a union map with that map, using the combining function to resolve conflicts.
+ *
+ * @tparam S The type of values in `that`, a supertype of values in `this`.
+ * @param that The map to form a union with.
+ * @param f The function used to resolve conflicts between two mappings.
+ * @return Union of `this` and `that`, with identical key conflicts resolved using the function `f`.
+ */
+ def unionWith[S >: T](that: IntMap[S], f: (Int, S, S) => S): IntMap[S] = (this, that) match{
+ case (IntMap.Bin(p1, m1, l1, r1), that@(IntMap.Bin(p2, m2, l2, r2))) =>
+ if (shorter(m1, m2)) {
+ if (!hasMatch(p2, p1, m1)) join(p1, this, p2, that)
+ else if (zero(p2, m1)) IntMap.Bin(p1, m1, l1.unionWith(that, f), r1)
+ else IntMap.Bin(p1, m1, l1, r1.unionWith(that, f))
+ } else if (shorter(m2, m1)){
+ if (!hasMatch(p1, p2, m2)) join(p1, this, p2, that)
+ else if (zero(p1, m2)) IntMap.Bin(p2, m2, this.unionWith(l2, f), r2)
+ else IntMap.Bin(p2, m2, l2, this.unionWith(r2, f))
+ }
+ else {
+ if (p1 == p2) IntMap.Bin(p1, m1, l1.unionWith(l2,f), r1.unionWith(r2, f))
+ else join(p1, this, p2, that)
+ }
+ case (IntMap.Tip(key, value), x) => x.updateWith[S](key, value, (x, y) => f(key, y, x))
+ case (x, IntMap.Tip(key, value)) => x.updateWith[S](key, value, (x, y) => f(key, x, y))
+ case (IntMap.Nil, x) => x
+ case (x, IntMap.Nil) => x
+ }
+
+ /**
+ * Forms the intersection of these two maps with a combining function. The
+ * resulting map is a map that has only keys present in both maps and has
+ * values produced from the original mappings by combining them with `f`.
+ *
+ * @tparam S The type of values in `that`.
+ * @tparam R The type of values in the resulting `LongMap`.
+ * @param that The map to intersect with.
+ * @param f The combining function.
+ * @return Intersection of `this` and `that`, with values for identical keys produced by function `f`.
+ */
+ def intersectionWith[S, R](that: IntMap[S], f: (Int, T, S) => R): IntMap[R] = (this, that) match {
+ case (IntMap.Bin(p1, m1, l1, r1), that@IntMap.Bin(p2, m2, l2, r2)) =>
+ if (shorter(m1, m2)) {
+ if (!hasMatch(p2, p1, m1)) IntMap.Nil
+ else if (zero(p2, m1)) l1.intersectionWith(that, f)
+ else r1.intersectionWith(that, f)
+ } else if (m1 == m2) bin(p1, m1, l1.intersectionWith(l2, f), r1.intersectionWith(r2, f))
+ else {
+ if (!hasMatch(p1, p2, m2)) IntMap.Nil
+ else if (zero(p1, m2)) this.intersectionWith(l2, f)
+ else this.intersectionWith(r2, f)
+ }
+ case (IntMap.Tip(key, value), that) => that.get(key) match {
+ case None => IntMap.Nil
+ case Some(value2) => IntMap.Tip(key, f(key, value, value2))
+ }
+ case (_, IntMap.Tip(key, value)) => this.get(key) match {
+ case None => IntMap.Nil
+ case Some(value2) => IntMap.Tip(key, f(key, value2, value))
+ }
+ case (_, _) => IntMap.Nil
+ }
+
+ /**
+ * Left biased intersection. Returns the map that has all the same mappings
+ * as this but only for keys which are present in the other map.
+ *
+ * @tparam R The type of values in `that`.
+ * @param that The map to intersect with.
+ * @return A map with all the keys both in `this` and `that`, mapped to corresponding values from `this`.
+ */
+ def intersection[R](that: IntMap[R]): IntMap[T] =
+ this.intersectionWith(that, (key: Int, value: T, value2: R) => value)
+
+ def ++[S >: T](that: IntMap[S]) =
+ this.unionWith[S](that, (key, x, y) => y)
+
+ /**
+ * The entry with the lowest key value considered in unsigned order.
+ */
+ @tailrec
+ final def firstKey: Int = this match {
+ case Bin(_, _, l, r) => l.firstKey
+ case Tip(k, v) => k
+ case IntMap.Nil => throw new IllegalStateException("Empty set")
+ }
+
+ /**
+ * The entry with the highest key value considered in unsigned order.
+ */
+ @tailrec
+ final def lastKey: Int = this match {
+ case Bin(_, _, l, r) => r.lastKey
+ case Tip(k, v) => k
+ case IntMap.Nil => throw new IllegalStateException("Empty set")
+ }
+
+ protected[this] def writeReplace(): AnyRef = new DefaultSerializationProxy(IntMap.toFactory[T](IntMap), this)
+}
diff --git a/library/src/scala/collection/immutable/Iterable.scala b/library/src/scala/collection/immutable/Iterable.scala
new file mode 100644
index 000000000000..a38c60ed8cc2
--- /dev/null
+++ b/library/src/scala/collection/immutable/Iterable.scala
@@ -0,0 +1,37 @@
+/*
+ * 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.immutable
+
+import scala.collection.{IterableFactory, IterableFactoryDefaults}
+
+/** A trait for collections that are guaranteed immutable.
+ *
+ * @tparam A the element type of the collection
+ *
+ * @define coll immutable collection
+ * @define Coll `immutable.Iterable`
+ */
+trait Iterable[+A] extends collection.Iterable[A]
+ with collection.IterableOps[A, Iterable, Iterable[A]]
+ with IterableFactoryDefaults[A, Iterable] {
+
+ override def iterableFactory: IterableFactory[Iterable] = Iterable
+}
+
+@SerialVersionUID(3L)
+object Iterable extends IterableFactory.Delegate[Iterable](List) {
+ override def from[E](it: IterableOnce[E]): Iterable[E] = it match {
+ case iterable: Iterable[E] => iterable
+ case _ => super.from(it)
+ }
+}
diff --git a/library/src/scala/collection/immutable/LazyList.scala b/library/src/scala/collection/immutable/LazyList.scala
new file mode 100644
index 000000000000..54591032e2af
--- /dev/null
+++ b/library/src/scala/collection/immutable/LazyList.scala
@@ -0,0 +1,1405 @@
+/*
+ * 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 collection
+package immutable
+
+import java.io.{ObjectInputStream, ObjectOutputStream}
+import java.lang.{StringBuilder => JStringBuilder}
+
+import scala.annotation.tailrec
+import scala.collection.generic.SerializeEnd
+import scala.collection.mutable.{Builder, ReusableBuilder, StringBuilder}
+import scala.language.implicitConversions
+import scala.runtime.Statics
+
+/** This class implements an immutable linked list. We call it "lazy"
+ * because it computes its elements only when they are needed.
+ *
+ * Elements are memoized; that is, the value of each element is computed at most once.
+ *
+ * Elements are computed in-order and are never skipped. In other words,
+ * accessing the tail causes the head to be computed first.
+ *
+ * How lazy is a `LazyList`? When you have a value of type `LazyList`, you
+ * don't know yet whether the list is empty or not. If you learn that it is non-empty,
+ * then you also know that the head has been computed. But the tail is itself
+ * a `LazyList`, whose emptiness-or-not might remain undetermined.
+ *
+ * A `LazyList` may be infinite. For example, `LazyList.from(0)` contains
+ * all of the natural numbers 0, 1, 2, and so on. For infinite sequences,
+ * some methods (such as `count`, `sum`, `max` or `min`) will not terminate.
+ *
+ * Here is an example:
+ *
+ * {{{
+ * import scala.math.BigInt
+ * object Main extends App {
+ * val fibs: LazyList[BigInt] =
+ * BigInt(0) #:: BigInt(1) #:: fibs.zip(fibs.tail).map{ n => n._1 + n._2 }
+ * fibs.take(5).foreach(println)
+ * }
+ *
+ * // prints
+ * //
+ * // 0
+ * // 1
+ * // 1
+ * // 2
+ * // 3
+ * }}}
+ *
+ * To illustrate, let's add some output to the definition `fibs`, so we
+ * see what's going on.
+ *
+ * {{{
+ * import scala.math.BigInt
+ * object Main extends App {
+ * val fibs: LazyList[BigInt] =
+ * BigInt(0) #:: BigInt(1) #::
+ * fibs.zip(fibs.tail).map{ n =>
+ * println(s"Adding \${n._1} and \${n._2}")
+ * n._1 + n._2
+ * }
+ * fibs.take(5).foreach(println)
+ * fibs.take(6).foreach(println)
+ * }
+ *
+ * // prints
+ * //
+ * // 0
+ * // 1
+ * // Adding 0 and 1
+ * // 1
+ * // Adding 1 and 1
+ * // 2
+ * // Adding 1 and 2
+ * // 3
+ *
+ * // And then prints
+ * //
+ * // 0
+ * // 1
+ * // 1
+ * // 2
+ * // 3
+ * // Adding 2 and 3
+ * // 5
+ * }}}
+ *
+ * Note that the definition of `fibs` uses `val` not `def`. The memoization of the
+ * `LazyList` requires us to have somewhere to store the information and a `val`
+ * allows us to do that.
+ *
+ * Further remarks about the semantics of `LazyList`:
+ *
+ * - Though the `LazyList` changes as it is accessed, this does not
+ * contradict its immutability. Once the values are memoized they do
+ * not change. Values that have yet to be memoized still "exist", they
+ * simply haven't been computed yet.
+ *
+ * - One must be cautious of memoization; it can eat up memory if you're not
+ * careful. That's because memoization of the `LazyList` creates a structure much like
+ * [[scala.collection.immutable.List]]. As long as something is holding on to
+ * the head, the head holds on to the tail, and so on recursively.
+ * If, on the other hand, there is nothing holding on to the head (e.g. if we used
+ * `def` to define the `LazyList`) then once it is no longer being used directly,
+ * it disappears.
+ *
+ * - Note that some operations, including [[drop]], [[dropWhile]],
+ * [[flatMap]] or [[collect]] may process a large number of intermediate
+ * elements before returning.
+ *
+ * Here's another example. Let's start with the natural numbers and iterate
+ * over them.
+ *
+ * {{{
+ * // We'll start with a silly iteration
+ * def loop(s: String, i: Int, iter: Iterator[Int]): Unit = {
+ * // Stop after 200,000
+ * if (i < 200001) {
+ * if (i % 50000 == 0) println(s + i)
+ * loop(s, iter.next(), iter)
+ * }
+ * }
+ *
+ * // Our first LazyList definition will be a val definition
+ * val lazylist1: LazyList[Int] = {
+ * def loop(v: Int): LazyList[Int] = v #:: loop(v + 1)
+ * loop(0)
+ * }
+ *
+ * // Because lazylist1 is a val, everything that the iterator produces is held
+ * // by virtue of the fact that the head of the LazyList is held in lazylist1
+ * val it1 = lazylist1.iterator
+ * loop("Iterator1: ", it1.next(), it1)
+ *
+ * // We can redefine this LazyList such that all we have is the Iterator left
+ * // and allow the LazyList to be garbage collected as required. Using a def
+ * // to provide the LazyList ensures that no val is holding onto the head as
+ * // is the case with lazylist1
+ * def lazylist2: LazyList[Int] = {
+ * def loop(v: Int): LazyList[Int] = v #:: loop(v + 1)
+ * loop(0)
+ * }
+ * val it2 = lazylist2.iterator
+ * loop("Iterator2: ", it2.next(), it2)
+ *
+ * // And, of course, we don't actually need a LazyList at all for such a simple
+ * // problem. There's no reason to use a LazyList if you don't actually need
+ * // one.
+ * val it3 = new Iterator[Int] {
+ * var i = -1
+ * def hasNext = true
+ * def next(): Int = { i += 1; i }
+ * }
+ * loop("Iterator3: ", it3.next(), it3)
+ * }}}
+ *
+ * In the `fibs` example earlier, the fact that `tail` works at all is of interest.
+ * `fibs` has an initial `(0, 1, LazyList(...))`, so `tail` is deterministic.
+ * If we defined `fibs` such that only `0` were concretely known, then the act
+ * of determining `tail` would require the evaluation of `tail`, so the
+ * computation would be unable to progress, as in this code:
+ * {{{
+ * // The first time we try to access the tail we're going to need more
+ * // information which will require us to recurse, which will require us to
+ * // recurse, which...
+ * lazy val sov: LazyList[Vector[Int]] = Vector(0) #:: sov.zip(sov.tail).map { n => n._1 ++ n._2 }
+ * }}}
+ *
+ * The definition of `fibs` above creates a larger number of objects than
+ * necessary depending on how you might want to implement it. The following
+ * implementation provides a more "cost effective" implementation due to the
+ * fact that it has a more direct route to the numbers themselves:
+ *
+ * {{{
+ * lazy val fib: LazyList[Int] = {
+ * def loop(h: Int, n: Int): LazyList[Int] = h #:: loop(n, h + n)
+ * loop(1, 1)
+ * }
+ * }}}
+ *
+ * The head, the tail and whether the list is empty or not can be initially unknown.
+ * Once any of those are evaluated, they are all known, though if the tail is
+ * built with `#::` or `#:::`, it's content still isn't evaluated. Instead, evaluating
+ * the tails content is deferred until the tails empty status, head or tail is
+ * evaluated.
+ *
+ * Delaying the evaluation of whether a LazyList is empty or not until it's needed
+ * allows LazyList to not eagerly evaluate any elements on a call to `filter`.
+ *
+ * Only when it's further evaluated (which may be never!) any of the elements gets
+ * forced.
+ *
+ * for example:
+ *
+ * {{{
+ * def tailWithSideEffect: LazyList[Nothing] = {
+ * println("getting empty LazyList")
+ * LazyList.empty
+ * }
+ *
+ * val emptyTail = tailWithSideEffect // prints "getting empty LazyList"
+ *
+ * val suspended = 1 #:: tailWithSideEffect // doesn't print anything
+ * val tail = suspended.tail // although the tail is evaluated, *still* nothing is yet printed
+ * val filtered = tail.filter(_ => false) // still nothing is printed
+ * filtered.isEmpty // prints "getting empty LazyList"
+ * }}}
+ *
+ * ----
+ *
+ * You may sometimes encounter an exception like the following:
+ *
+ * {{{
+ * java.lang.RuntimeException: "LazyList evaluation depends on its own result (self-reference); see docs for more info
+ * }}}
+ *
+ * This exception occurs when a `LazyList` is attempting to derive its next element
+ * from itself, and is attempting to read the element currently being evaluated. A
+ * trivial example of such might be
+ *
+ * {{{
+ * lazy val a: LazyList[Int] = 1 #:: 2 #:: a.filter(_ > 2)
+ * }}}
+ *
+ * When attempting to evaluate the third element of `a`, it will skip the first two
+ * elements and read the third, but that element is already being evaluated. This is
+ * often caused by a subtle logic error; in this case, using `>=` in the `filter`
+ * would fix the error.
+ *
+ * @tparam A the type of the elements contained in this lazy list.
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-immutable-collection-classes.html#lazylists "Scala's Collection Library overview"]]
+ * section on `LazyLists` for more information.
+ * @define Coll `LazyList`
+ * @define coll lazy list
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define appendStackSafety Note: Repeated chaining of calls to append methods (`appended`,
+ * `appendedAll`, `lazyAppendedAll`) without forcing any of the
+ * intermediate resulting lazy lists may overflow the stack when
+ * the final result is forced.
+ * @define preservesLaziness This method preserves laziness; elements are only evaluated
+ * individually as needed.
+ * @define initiallyLazy This method does not evaluate anything until an operation is performed
+ * on the result (e.g. calling `head` or `tail`, or checking if it is empty).
+ * @define evaluatesAllElements This method evaluates all elements of the collection.
+ */
+@SerialVersionUID(3L)
+final class LazyList[+A] private(private[this] var lazyState: () => LazyList.State[A])
+ extends AbstractSeq[A]
+ with LinearSeq[A]
+ with LinearSeqOps[A, LazyList, LazyList[A]]
+ with IterableFactoryDefaults[A, LazyList]
+ with Serializable {
+ import LazyList._
+
+ @volatile private[this] var stateEvaluated: Boolean = false
+ @inline private def stateDefined: Boolean = stateEvaluated
+ private[this] var midEvaluation = false
+
+ private lazy val state: State[A] = {
+ // if it's already mid-evaluation, we're stuck in an infinite
+ // self-referential loop (also it's empty)
+ if (midEvaluation) {
+ throw new RuntimeException(
+ "LazyList evaluation depends on its own result (self-reference); see docs for more info"
+ )
+ }
+ midEvaluation = true
+ val res = try lazyState() finally midEvaluation = false
+ // if we set it to `true` before evaluating, we may infinite loop
+ // if something expects `state` to already be evaluated
+ stateEvaluated = true
+ lazyState = null // allow GC
+ res
+ }
+
+ override def iterableFactory: SeqFactory[LazyList] = LazyList
+
+ override def isEmpty: Boolean = state eq State.Empty
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def knownSize: Int = if (knownIsEmpty) 0 else -1
+
+ override def head: A = state.head
+
+ override def tail: LazyList[A] = state.tail
+
+ @inline private[this] def knownIsEmpty: Boolean = stateEvaluated && (isEmpty: @inline)
+ @inline private def knownNonEmpty: Boolean = stateEvaluated && !(isEmpty: @inline)
+
+ /** Evaluates all undefined elements of the lazy list.
+ *
+ * This method detects cycles in lazy lists, and terminates after all
+ * elements of the cycle are evaluated. For example:
+ *
+ * {{{
+ * val ring: LazyList[Int] = 1 #:: 2 #:: 3 #:: ring
+ * ring.force
+ * ring.toString
+ *
+ * // prints
+ * //
+ * // LazyList(1, 2, 3, ...)
+ * }}}
+ *
+ * This method will *not* terminate for non-cyclic infinite-sized collections.
+ *
+ * @return this
+ */
+ def force: this.type = {
+ // Use standard 2x 1x iterator trick for cycle detection ("those" is slow one)
+ var these, those: LazyList[A] = this
+ if (!these.isEmpty) {
+ these = these.tail
+ }
+ while (those ne these) {
+ if (these.isEmpty) return this
+ these = these.tail
+ if (these.isEmpty) return this
+ these = these.tail
+ if (these eq those) return this
+ those = those.tail
+ }
+ this
+ }
+
+ /** @inheritdoc
+ *
+ * The iterator returned by this method preserves laziness; elements are
+ * only evaluated individually as needed.
+ */
+ override def iterator: Iterator[A] =
+ if (knownIsEmpty) Iterator.empty
+ else new LazyIterator(this)
+
+ /** Apply the given function `f` to each element of this linear sequence
+ * (while respecting the order of the elements).
+ *
+ * @param f The treatment to apply to each element.
+ * @note Overridden here as final to trigger tail-call optimization, which
+ * replaces 'this' with 'tail' at each iteration. This is absolutely
+ * necessary for allowing the GC to collect the underlying LazyList as elements
+ * are consumed.
+ * @note This function will force the realization of the entire LazyList
+ * unless the `f` throws an exception.
+ */
+ @tailrec
+ override def foreach[U](f: A => U): Unit = {
+ if (!isEmpty) {
+ f(head)
+ tail.foreach(f)
+ }
+ }
+
+ /** LazyList specialization of foldLeft which allows GC to collect along the
+ * way.
+ *
+ * @tparam B The type of value being accumulated.
+ * @param z The initial value seeded into the function `op`.
+ * @param op The operation to perform on successive elements of the `LazyList`.
+ * @return The accumulated value from successive applications of `op`.
+ */
+ @tailrec
+ override def foldLeft[B](z: B)(op: (B, A) => B): B =
+ if (isEmpty) z
+ else tail.foldLeft(op(z, head))(op)
+
+ // State.Empty doesn't use the SerializationProxy
+ protected[this] def writeReplace(): AnyRef =
+ if (knownNonEmpty) new LazyList.SerializationProxy[A](this) else this
+
+ override protected[this] def className = "LazyList"
+
+ /** The lazy list resulting from the concatenation of this lazy list with the argument lazy list.
+ *
+ * $preservesLaziness
+ *
+ * $appendStackSafety
+ *
+ * @param suffix The collection that gets appended to this lazy list
+ * @return The lazy list containing elements of this lazy list and the iterable object.
+ */
+ def lazyAppendedAll[B >: A](suffix: => collection.IterableOnce[B]): LazyList[B] =
+ newLL {
+ if (isEmpty) suffix match {
+ case lazyList: LazyList[B] => lazyList.state // don't recompute the LazyList
+ case coll if coll.knownSize == 0 => State.Empty
+ case coll => stateFromIterator(coll.iterator)
+ }
+ else sCons(head, tail lazyAppendedAll suffix)
+ }
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ *
+ * $appendStackSafety
+ */
+ override def appendedAll[B >: A](suffix: IterableOnce[B]): LazyList[B] =
+ if (knownIsEmpty) LazyList.from(suffix)
+ else lazyAppendedAll(suffix)
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ *
+ * $appendStackSafety
+ */
+ override def appended[B >: A](elem: B): LazyList[B] =
+ if (knownIsEmpty) newLL(sCons(elem, LazyList.empty))
+ else lazyAppendedAll(Iterator.single(elem))
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def scanLeft[B](z: B)(op: (B, A) => B): LazyList[B] =
+ if (knownIsEmpty) newLL(sCons(z, LazyList.empty))
+ else newLL(scanLeftState(z)(op))
+
+ private def scanLeftState[B](z: B)(op: (B, A) => B): State[B] =
+ sCons(
+ z,
+ newLL {
+ if (isEmpty) State.Empty
+ else tail.scanLeftState(op(z, head))(op)
+ }
+ )
+
+ /** LazyList specialization of reduceLeft which allows GC to collect
+ * along the way.
+ *
+ * @tparam B The type of value being accumulated.
+ * @param f The operation to perform on successive elements of the `LazyList`.
+ * @return The accumulated value from successive applications of `f`.
+ */
+ override def reduceLeft[B >: A](f: (B, A) => B): B = {
+ if (this.isEmpty) throw new UnsupportedOperationException("empty.reduceLeft")
+ else {
+ var reducedRes: B = this.head
+ var left: LazyList[A] = this.tail
+ while (!left.isEmpty) {
+ reducedRes = f(reducedRes, left.head)
+ left = left.tail
+ }
+ reducedRes
+ }
+ }
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def partition(p: A => Boolean): (LazyList[A], LazyList[A]) = (filter(p), filterNot(p))
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def partitionMap[A1, A2](f: A => Either[A1, A2]): (LazyList[A1], LazyList[A2]) = {
+ val (left, right) = map(f).partition(_.isLeft)
+ (left.map(_.asInstanceOf[Left[A1, _]].value), right.map(_.asInstanceOf[Right[_, A2]].value))
+ }
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def filter(pred: A => Boolean): LazyList[A] =
+ if (knownIsEmpty) LazyList.empty
+ else LazyList.filterImpl(this, pred, isFlipped = false)
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def filterNot(pred: A => Boolean): LazyList[A] =
+ if (knownIsEmpty) LazyList.empty
+ else LazyList.filterImpl(this, pred, isFlipped = true)
+
+ /** A `collection.WithFilter` which allows GC of the head of lazy list during processing.
+ *
+ * This method is not particularly useful for a lazy list, as [[filter]] already preserves
+ * laziness.
+ *
+ * The `collection.WithFilter` returned by this method preserves laziness; elements are
+ * only evaluated individually as needed.
+ */
+ override def withFilter(p: A => Boolean): collection.WithFilter[A, LazyList] =
+ new LazyList.WithFilter(coll, p)
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def prepended[B >: A](elem: B): LazyList[B] = newLL(sCons(elem, this))
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def prependedAll[B >: A](prefix: collection.IterableOnce[B]): LazyList[B] =
+ if (knownIsEmpty) LazyList.from(prefix)
+ else if (prefix.knownSize == 0) this
+ else newLL(stateFromIteratorConcatSuffix(prefix.iterator)(state))
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def map[B](f: A => B): LazyList[B] =
+ if (knownIsEmpty) LazyList.empty
+ else (mapImpl(f): @inline)
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def tapEach[U](f: A => U): LazyList[A] = map { a => f(a); a }
+
+ private def mapImpl[B](f: A => B): LazyList[B] =
+ newLL {
+ if (isEmpty) State.Empty
+ else sCons(f(head), tail.mapImpl(f))
+ }
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def collect[B](pf: PartialFunction[A, B]): LazyList[B] =
+ if (knownIsEmpty) LazyList.empty
+ else LazyList.collectImpl(this, pf)
+
+ /** @inheritdoc
+ *
+ * This method does not evaluate any elements further than
+ * the first element for which the partial function is defined.
+ */
+ @tailrec
+ override def collectFirst[B](pf: PartialFunction[A, B]): Option[B] =
+ if (isEmpty) None
+ else {
+ val res = pf.applyOrElse(head, LazyList.anyToMarker.asInstanceOf[A => B])
+ if (res.asInstanceOf[AnyRef] eq Statics.pfMarker) tail.collectFirst(pf)
+ else Some(res)
+ }
+
+ /** @inheritdoc
+ *
+ * This method does not evaluate any elements further than
+ * the first element matching the predicate.
+ */
+ @tailrec
+ override def find(p: A => Boolean): Option[A] =
+ if (isEmpty) None
+ else {
+ val elem = head
+ if (p(elem)) Some(elem)
+ else tail.find(p)
+ }
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ // optimisations are not for speed, but for functionality
+ // see tickets #153, #498, #2147, and corresponding tests in run/ (as well as run/stream_flatmap_odds.scala)
+ override def flatMap[B](f: A => IterableOnce[B]): LazyList[B] =
+ if (knownIsEmpty) LazyList.empty
+ else LazyList.flatMapImpl(this, f)
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def flatten[B](implicit asIterable: A => IterableOnce[B]): LazyList[B] = flatMap(asIterable)
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def zip[B](that: collection.IterableOnce[B]): LazyList[(A, B)] =
+ if (this.knownIsEmpty || that.knownSize == 0) LazyList.empty
+ else newLL(zipState(that.iterator))
+
+ private def zipState[B](it: Iterator[B]): State[(A, B)] =
+ if (this.isEmpty || !it.hasNext) State.Empty
+ else sCons((head, it.next()), newLL { tail zipState it })
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def zipWithIndex: LazyList[(A, Int)] = this zip LazyList.from(0)
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def zipAll[A1 >: A, B](that: collection.Iterable[B], thisElem: A1, thatElem: B): LazyList[(A1, B)] = {
+ if (this.knownIsEmpty) {
+ if (that.knownSize == 0) LazyList.empty
+ else LazyList.continually(thisElem) zip that
+ } else {
+ if (that.knownSize == 0) zip(LazyList.continually(thatElem))
+ else newLL(zipAllState(that.iterator, thisElem, thatElem))
+ }
+ }
+
+ private def zipAllState[A1 >: A, B](it: Iterator[B], thisElem: A1, thatElem: B): State[(A1, B)] = {
+ if (it.hasNext) {
+ if (this.isEmpty) sCons((thisElem, it.next()), newLL { LazyList.continually(thisElem) zipState it })
+ else sCons((this.head, it.next()), newLL { this.tail.zipAllState(it, thisElem, thatElem) })
+ } else {
+ if (this.isEmpty) State.Empty
+ else sCons((this.head, thatElem), this.tail zip LazyList.continually(thatElem))
+ }
+ }
+
+ /** @inheritdoc
+ *
+ * This method is not particularly useful for a lazy list, as [[zip]] already preserves
+ * laziness.
+ *
+ * The `collection.LazyZip2` returned by this method preserves laziness; elements are
+ * only evaluated individually as needed.
+ */
+ // just in case it can be meaningfully overridden at some point
+ override def lazyZip[B](that: collection.Iterable[B]): LazyZip2[A, B, LazyList.this.type] =
+ super.lazyZip(that)
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def unzip[A1, A2](implicit asPair: A => (A1, A2)): (LazyList[A1], LazyList[A2]) =
+ (map(asPair(_)._1), map(asPair(_)._2))
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def unzip3[A1, A2, A3](implicit asTriple: A => (A1, A2, A3)): (LazyList[A1], LazyList[A2], LazyList[A3]) =
+ (map(asTriple(_)._1), map(asTriple(_)._2), map(asTriple(_)._3))
+
+ /** @inheritdoc
+ *
+ * $initiallyLazy
+ * Additionally, it preserves laziness for all except the first `n` elements.
+ */
+ override def drop(n: Int): LazyList[A] =
+ if (n <= 0) this
+ else if (knownIsEmpty) LazyList.empty
+ else LazyList.dropImpl(this, n)
+
+ /** @inheritdoc
+ *
+ * $initiallyLazy
+ * Additionally, it preserves laziness for all elements after the predicate returns `false`.
+ */
+ override def dropWhile(p: A => Boolean): LazyList[A] =
+ if (knownIsEmpty) LazyList.empty
+ else LazyList.dropWhileImpl(this, p)
+
+ /** @inheritdoc
+ *
+ * $initiallyLazy
+ */
+ override def dropRight(n: Int): LazyList[A] = {
+ if (n <= 0) this
+ else if (knownIsEmpty) LazyList.empty
+ else newLL {
+ var scout = this
+ var remaining = n
+ // advance scout n elements ahead (or until empty)
+ while (remaining > 0 && !scout.isEmpty) {
+ remaining -= 1
+ scout = scout.tail
+ }
+ dropRightState(scout)
+ }
+ }
+
+ private def dropRightState(scout: LazyList[_]): State[A] =
+ if (scout.isEmpty) State.Empty
+ else sCons(head, newLL(tail.dropRightState(scout.tail)))
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def take(n: Int): LazyList[A] =
+ if (knownIsEmpty) LazyList.empty
+ else (takeImpl(n): @inline)
+
+ private def takeImpl(n: Int): LazyList[A] = {
+ if (n <= 0) LazyList.empty
+ else newLL {
+ if (isEmpty) State.Empty
+ else sCons(head, tail.takeImpl(n - 1))
+ }
+ }
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def takeWhile(p: A => Boolean): LazyList[A] =
+ if (knownIsEmpty) LazyList.empty
+ else (takeWhileImpl(p): @inline)
+
+ private def takeWhileImpl(p: A => Boolean): LazyList[A] =
+ newLL {
+ if (isEmpty || !p(head)) State.Empty
+ else sCons(head, tail.takeWhileImpl(p))
+ }
+
+ /** @inheritdoc
+ *
+ * $initiallyLazy
+ */
+ override def takeRight(n: Int): LazyList[A] =
+ if (n <= 0 || knownIsEmpty) LazyList.empty
+ else LazyList.takeRightImpl(this, n)
+
+ /** @inheritdoc
+ *
+ * $initiallyLazy
+ * Additionally, it preserves laziness for all but the first `from` elements.
+ */
+ override def slice(from: Int, until: Int): LazyList[A] = take(until).drop(from)
+
+ /** @inheritdoc
+ *
+ * $evaluatesAllElements
+ */
+ override def reverse: LazyList[A] = reverseOnto(LazyList.empty)
+
+ // need contravariant type B to make the compiler happy - still returns LazyList[A]
+ @tailrec
+ private def reverseOnto[B >: A](tl: LazyList[B]): LazyList[B] =
+ if (isEmpty) tl
+ else tail.reverseOnto(newLL(sCons(head, tl)))
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def diff[B >: A](that: collection.Seq[B]): LazyList[A] =
+ if (knownIsEmpty) LazyList.empty
+ else super.diff(that)
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def intersect[B >: A](that: collection.Seq[B]): LazyList[A] =
+ if (knownIsEmpty) LazyList.empty
+ else super.intersect(that)
+
+ @tailrec
+ private def lengthGt(len: Int): Boolean =
+ if (len < 0) true
+ else if (isEmpty) false
+ else tail.lengthGt(len - 1)
+
+ /** @inheritdoc
+ *
+ * The iterator returned by this method mostly preserves laziness;
+ * a single element ahead of the iterator is evaluated.
+ */
+ override def grouped(size: Int): Iterator[LazyList[A]] = {
+ require(size > 0, "size must be positive, but was " + size)
+ slidingImpl(size = size, step = size)
+ }
+
+ /** @inheritdoc
+ *
+ * The iterator returned by this method mostly preserves laziness;
+ * `size - step max 1` elements ahead of the iterator are evaluated.
+ */
+ override def sliding(size: Int, step: Int): Iterator[LazyList[A]] = {
+ require(size > 0 && step > 0, s"size=$size and step=$step, but both must be positive")
+ slidingImpl(size = size, step = step)
+ }
+
+ @inline private def slidingImpl(size: Int, step: Int): Iterator[LazyList[A]] =
+ if (knownIsEmpty) Iterator.empty
+ else new SlidingIterator[A](this, size = size, step = step)
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def padTo[B >: A](len: Int, elem: B): LazyList[B] = {
+ if (len <= 0) this
+ else newLL {
+ if (isEmpty) LazyList.fill(len)(elem).state
+ else sCons(head, tail.padTo(len - 1, elem))
+ }
+ }
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def patch[B >: A](from: Int, other: IterableOnce[B], replaced: Int): LazyList[B] =
+ if (knownIsEmpty) LazyList from other
+ else patchImpl(from, other, replaced)
+
+ private def patchImpl[B >: A](from: Int, other: IterableOnce[B], replaced: Int): LazyList[B] =
+ newLL {
+ if (from <= 0) stateFromIteratorConcatSuffix(other.iterator)(LazyList.dropImpl(this, replaced).state)
+ else if (isEmpty) stateFromIterator(other.iterator)
+ else sCons(head, tail.patchImpl(from - 1, other, replaced))
+ }
+
+ /** @inheritdoc
+ *
+ * $evaluatesAllElements
+ */
+ // overridden just in case a lazy implementation is developed at some point
+ override def transpose[B](implicit asIterable: A => collection.Iterable[B]): LazyList[LazyList[B]] = super.transpose
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ override def updated[B >: A](index: Int, elem: B): LazyList[B] =
+ if (index < 0) throw new IndexOutOfBoundsException(s"$index")
+ else updatedImpl(index, elem, index)
+
+ private def updatedImpl[B >: A](index: Int, elem: B, startIndex: Int): LazyList[B] = {
+ newLL {
+ if (index <= 0) sCons(elem, tail)
+ else if (tail.isEmpty) throw new IndexOutOfBoundsException(startIndex.toString)
+ else sCons(head, tail.updatedImpl(index - 1, elem, startIndex))
+ }
+ }
+
+ /** Appends all elements of this $coll to a string builder using start, end, and separator strings.
+ * The written text begins with the string `start` and ends with the string `end`.
+ * Inside, the string representations (w.r.t. the method `toString`)
+ * of all elements of this $coll are separated by the string `sep`.
+ *
+ * An undefined state is represented with `"<not computed>"` and cycles are represented with `"<cycle>"`.
+ *
+ * $evaluatesAllElements
+ *
+ * @param sb the string builder to which elements are appended.
+ * @param start the starting string.
+ * @param sep the separator string.
+ * @param end the ending string.
+ * @return the string builder `b` to which elements were appended.
+ */
+ override def addString(sb: StringBuilder, start: String, sep: String, end: String): sb.type = {
+ force
+ addStringNoForce(sb.underlying, start, sep, end)
+ sb
+ }
+
+ private[this] def addStringNoForce(b: JStringBuilder, start: String, sep: String, end: String): b.type = {
+ b.append(start)
+ if (!stateDefined) b.append("")
+ else if (!isEmpty) {
+ b.append(head)
+ var cursor = this
+ @inline def appendCursorElement(): Unit = b.append(sep).append(cursor.head)
+ var scout = tail
+ @inline def scoutNonEmpty: Boolean = scout.stateDefined && !scout.isEmpty
+ if ((cursor ne scout) && (!scout.stateDefined || (cursor.state ne scout.state))) {
+ cursor = scout
+ if (scoutNonEmpty) {
+ scout = scout.tail
+ // Use 2x 1x iterator trick for cycle detection; slow iterator can add strings
+ while ((cursor ne scout) && scoutNonEmpty && (cursor.state ne scout.state)) {
+ appendCursorElement()
+ cursor = cursor.tail
+ scout = scout.tail
+ if (scoutNonEmpty) scout = scout.tail
+ }
+ }
+ }
+ if (!scoutNonEmpty) { // Not a cycle, scout hit an end
+ while (cursor ne scout) {
+ appendCursorElement()
+ cursor = cursor.tail
+ }
+ // if cursor (eq scout) has state defined, it is empty; else unknown state
+ if (!cursor.stateDefined) b.append(sep).append("")
+ } else {
+ @inline def same(a: LazyList[A], b: LazyList[A]): Boolean = (a eq b) || (a.state eq b.state)
+ // Cycle.
+ // If we have a prefix of length P followed by a cycle of length C,
+ // the scout will be at position (P%C) in the cycle when the cursor
+ // enters it at P. They'll then collide when the scout advances another
+ // C - (P%C) ahead of the cursor.
+ // If we run the scout P farther, then it will be at the start of
+ // the cycle: (C - (P%C) + (P%C)) == C == 0. So if another runner
+ // starts at the beginning of the prefix, they'll collide exactly at
+ // the start of the loop.
+ var runner = this
+ var k = 0
+ while (!same(runner, scout)) {
+ runner = runner.tail
+ scout = scout.tail
+ k += 1
+ }
+ // Now runner and scout are at the beginning of the cycle. Advance
+ // cursor, adding to string, until it hits; then we'll have covered
+ // everything once. If cursor is already at beginning, we'd better
+ // advance one first unless runner didn't go anywhere (in which case
+ // we've already looped once).
+ if (same(cursor, scout) && (k > 0)) {
+ appendCursorElement()
+ cursor = cursor.tail
+ }
+ while (!same(cursor, scout)) {
+ appendCursorElement()
+ cursor = cursor.tail
+ }
+ b.append(sep).append("")
+ }
+ }
+ b.append(end)
+ b
+ }
+
+ /** $preservesLaziness
+ *
+ * @return a string representation of this collection. An undefined state is
+ * represented with `"<not computed>"` and cycles are represented with `"<cycle>"`
+ *
+ * Examples:
+ *
+ * - `"LazyList(4, <not computed>)"`, a non-empty lazy list ;
+ * - `"LazyList(1, 2, 3, <not computed>)"`, a lazy list with at least three elements ;
+ * - `"LazyList(1, 2, 3, <cycle>)"`, an infinite lazy list that contains
+ * a cycle at the fourth element.
+ */
+ override def toString(): String = addStringNoForce(new JStringBuilder(className), "(", ", ", ")").toString
+
+ /** @inheritdoc
+ *
+ * $preservesLaziness
+ */
+ @deprecated("Check .knownSize instead of .hasDefiniteSize for more actionable information (see scaladoc for details)", "2.13.0")
+ override def hasDefiniteSize: Boolean = {
+ if (!stateDefined) false
+ else if (isEmpty) true
+ else {
+ // Two-iterator trick (2x & 1x speed) for cycle detection.
+ var those = this
+ var these = tail
+ while (those ne these) {
+ if (!these.stateDefined) return false
+ else if (these.isEmpty) return true
+ these = these.tail
+ if (!these.stateDefined) return false
+ else if (these.isEmpty) return true
+ these = these.tail
+ if (those eq these) return false
+ those = those.tail
+ }
+ false // Cycle detected
+ }
+ }
+}
+
+/**
+ * $factoryInfo
+ * @define coll lazy list
+ * @define Coll `LazyList`
+ */
+@SerialVersionUID(3L)
+object LazyList extends SeqFactory[LazyList] {
+ // Eagerly evaluate cached empty instance
+ private[this] val _empty = newLL(State.Empty).force
+
+ private sealed trait State[+A] extends Serializable {
+ def head: A
+ def tail: LazyList[A]
+ }
+
+ private object State {
+ @SerialVersionUID(3L)
+ object Empty extends State[Nothing] {
+ def head: Nothing = throw new NoSuchElementException("head of empty lazy list")
+ def tail: LazyList[Nothing] = throw new UnsupportedOperationException("tail of empty lazy list")
+ }
+
+ @SerialVersionUID(3L)
+ final class Cons[A](val head: A, val tail: LazyList[A]) extends State[A]
+ }
+
+ /** Creates a new LazyList. */
+ @inline private def newLL[A](state: => State[A]): LazyList[A] = new LazyList[A](() => state)
+
+ /** Creates a new State.Cons. */
+ @inline private def sCons[A](hd: A, tl: LazyList[A]): State[A] = new State.Cons[A](hd, tl)
+
+ private val anyToMarker: Any => Any = _ => Statics.pfMarker
+
+ /* All of the following `Impl` methods are carefully written so as not to
+ * leak the beginning of the `LazyList`. They copy the initial `LazyList` (`ll`) into
+ * `var rest`, which gets closed over as a `scala.runtime.ObjectRef`, thus not permanently
+ * leaking the head of the `LazyList`. Additionally, the methods are written so that, should
+ * an exception be thrown by the evaluation of the `LazyList` or any supplied function, they
+ * can continue their execution where they left off.
+ */
+
+ private def filterImpl[A](ll: LazyList[A], p: A => Boolean, isFlipped: Boolean): LazyList[A] = {
+ // DO NOT REFERENCE `ll` ANYWHERE ELSE, OR IT WILL LEAK THE HEAD
+ var restRef = ll // val restRef = new ObjectRef(ll)
+ newLL {
+ var elem: A = null.asInstanceOf[A]
+ var found = false
+ var rest = restRef // var rest = restRef.elem
+ while (!found && !rest.isEmpty) {
+ elem = rest.head
+ found = p(elem) != isFlipped
+ rest = rest.tail
+ restRef = rest // restRef.elem = rest
+ }
+ if (found) sCons(elem, filterImpl(rest, p, isFlipped)) else State.Empty
+ }
+ }
+
+ private def collectImpl[A, B](ll: LazyList[A], pf: PartialFunction[A, B]): LazyList[B] = {
+ // DO NOT REFERENCE `ll` ANYWHERE ELSE, OR IT WILL LEAK THE HEAD
+ var restRef = ll // val restRef = new ObjectRef(ll)
+ newLL {
+ val marker = Statics.pfMarker
+ val toMarker = anyToMarker.asInstanceOf[A => B] // safe because Function1 is erased
+
+ var res: B = marker.asInstanceOf[B] // safe because B is unbounded
+ var rest = restRef // var rest = restRef.elem
+ while((res.asInstanceOf[AnyRef] eq marker) && !rest.isEmpty) {
+ res = pf.applyOrElse(rest.head, toMarker)
+ rest = rest.tail
+ restRef = rest // restRef.elem = rest
+ }
+ if (res.asInstanceOf[AnyRef] eq marker) State.Empty
+ else sCons(res, collectImpl(rest, pf))
+ }
+ }
+
+ private def flatMapImpl[A, B](ll: LazyList[A], f: A => IterableOnce[B]): LazyList[B] = {
+ // DO NOT REFERENCE `ll` ANYWHERE ELSE, OR IT WILL LEAK THE HEAD
+ var restRef = ll // val restRef = new ObjectRef(ll)
+ newLL {
+ var it: Iterator[B] = null
+ var itHasNext = false
+ var rest = restRef // var rest = restRef.elem
+ while (!itHasNext && !rest.isEmpty) {
+ it = f(rest.head).iterator
+ itHasNext = it.hasNext
+ if (!itHasNext) { // wait to advance `rest` because `it.next()` can throw
+ rest = rest.tail
+ restRef = rest // restRef.elem = rest
+ }
+ }
+ if (itHasNext) {
+ val head = it.next()
+ rest = rest.tail
+ restRef = rest // restRef.elem = rest
+ sCons(head, newLL(stateFromIteratorConcatSuffix(it)(flatMapImpl(rest, f).state)))
+ } else State.Empty
+ }
+ }
+
+ private def dropImpl[A](ll: LazyList[A], n: Int): LazyList[A] = {
+ // DO NOT REFERENCE `ll` ANYWHERE ELSE, OR IT WILL LEAK THE HEAD
+ var restRef = ll // val restRef = new ObjectRef(ll)
+ var iRef = n // val iRef = new IntRef(n)
+ newLL {
+ var rest = restRef // var rest = restRef.elem
+ var i = iRef // var i = iRef.elem
+ while (i > 0 && !rest.isEmpty) {
+ rest = rest.tail
+ restRef = rest // restRef.elem = rest
+ i -= 1
+ iRef = i // iRef.elem = i
+ }
+ rest.state
+ }
+ }
+
+ private def dropWhileImpl[A](ll: LazyList[A], p: A => Boolean): LazyList[A] = {
+ // DO NOT REFERENCE `ll` ANYWHERE ELSE, OR IT WILL LEAK THE HEAD
+ var restRef = ll // val restRef = new ObjectRef(ll)
+ newLL {
+ var rest = restRef // var rest = restRef.elem
+ while (!rest.isEmpty && p(rest.head)) {
+ rest = rest.tail
+ restRef = rest // restRef.elem = rest
+ }
+ rest.state
+ }
+ }
+
+ private def takeRightImpl[A](ll: LazyList[A], n: Int): LazyList[A] = {
+ // DO NOT REFERENCE `ll` ANYWHERE ELSE, OR IT WILL LEAK THE HEAD
+ var restRef = ll // val restRef = new ObjectRef(ll)
+ var scoutRef = ll // val scoutRef = new ObjectRef(ll)
+ var remainingRef = n // val remainingRef = new IntRef(n)
+ newLL {
+ var scout = scoutRef // var scout = scoutRef.elem
+ var remaining = remainingRef // var remaining = remainingRef.elem
+ // advance `scout` `n` elements ahead (or until empty)
+ while (remaining > 0 && !scout.isEmpty) {
+ scout = scout.tail
+ scoutRef = scout // scoutRef.elem = scout
+ remaining -= 1
+ remainingRef = remaining // remainingRef.elem = remaining
+ }
+ var rest = restRef // var rest = restRef.elem
+ // advance `rest` and `scout` in tandem until `scout` reaches the end
+ while(!scout.isEmpty) {
+ scout = scout.tail
+ scoutRef = scout // scoutRef.elem = scout
+ rest = rest.tail // can't throw an exception as `scout` has already evaluated its tail
+ restRef = rest // restRef.elem = rest
+ }
+ // `rest` is the last `n` elements (or all of them)
+ rest.state
+ }
+ }
+
+ /** An alternative way of building and matching lazy lists using LazyList.cons(hd, tl).
+ */
+ object cons {
+ /** A lazy list consisting of a given first element and remaining elements
+ * @param hd The first element of the result lazy list
+ * @param tl The remaining elements of the result lazy list
+ */
+ def apply[A](hd: => A, tl: => LazyList[A]): LazyList[A] = newLL(sCons(hd, newLL(tl.state)))
+
+ /** Maps a lazy list to its head and tail */
+ def unapply[A](xs: LazyList[A]): Option[(A, LazyList[A])] = #::.unapply(xs)
+ }
+
+ implicit def toDeferrer[A](l: => LazyList[A]): Deferrer[A] = new Deferrer[A](() => l)
+
+ final class Deferrer[A] private[LazyList] (private val l: () => LazyList[A]) extends AnyVal {
+ /** Construct a LazyList consisting of a given first element followed by elements
+ * from another LazyList.
+ */
+ def #:: [B >: A](elem: => B): LazyList[B] = newLL(sCons(elem, newLL(l().state)))
+ /** Construct a LazyList consisting of the concatenation of the given LazyList and
+ * another LazyList.
+ */
+ def #:::[B >: A](prefix: LazyList[B]): LazyList[B] = prefix lazyAppendedAll l()
+ }
+
+ object #:: {
+ def unapply[A](s: LazyList[A]): Option[(A, LazyList[A])] =
+ if (!s.isEmpty) Some((s.head, s.tail)) else None
+ }
+
+ def from[A](coll: collection.IterableOnce[A]): LazyList[A] = coll match {
+ case lazyList: LazyList[A] => lazyList
+ case _ if coll.knownSize == 0 => empty[A]
+ case _ => newLL(stateFromIterator(coll.iterator))
+ }
+
+ def empty[A]: LazyList[A] = _empty
+
+ /** Creates a State from an Iterator, with another State appended after the Iterator
+ * is empty.
+ */
+ private def stateFromIteratorConcatSuffix[A](it: Iterator[A])(suffix: => State[A]): State[A] =
+ if (it.hasNext) sCons(it.next(), newLL(stateFromIteratorConcatSuffix(it)(suffix)))
+ else suffix
+
+ /** Creates a State from an IterableOnce. */
+ private def stateFromIterator[A](it: Iterator[A]): State[A] =
+ if (it.hasNext) sCons(it.next(), newLL(stateFromIterator(it)))
+ else State.Empty
+
+ override def concat[A](xss: collection.Iterable[A]*): LazyList[A] =
+ if (xss.knownSize == 0) empty
+ else newLL(concatIterator(xss.iterator))
+
+ private def concatIterator[A](it: Iterator[collection.Iterable[A]]): State[A] =
+ if (!it.hasNext) State.Empty
+ else stateFromIteratorConcatSuffix(it.next().iterator)(concatIterator(it))
+
+ /** An infinite LazyList that repeatedly applies a given function to a start value.
+ *
+ * @param start the start value of the LazyList
+ * @param f the function that's repeatedly applied
+ * @return the LazyList returning the infinite sequence of values `start, f(start), f(f(start)), ...`
+ */
+ def iterate[A](start: => A)(f: A => A): LazyList[A] =
+ newLL {
+ val head = start
+ sCons(head, iterate(f(head))(f))
+ }
+
+ /**
+ * Create an infinite LazyList starting at `start` and incrementing by
+ * step `step`.
+ *
+ * @param start the start value of the LazyList
+ * @param step the increment value of the LazyList
+ * @return the LazyList starting at value `start`.
+ */
+ def from(start: Int, step: Int): LazyList[Int] =
+ newLL(sCons(start, from(start + step, step)))
+
+ /**
+ * Create an infinite LazyList starting at `start` and incrementing by `1`.
+ *
+ * @param start the start value of the LazyList
+ * @return the LazyList starting at value `start`.
+ */
+ def from(start: Int): LazyList[Int] = from(start, 1)
+
+ /**
+ * Create an infinite LazyList containing the given element expression (which
+ * is computed for each occurrence).
+ *
+ * @param elem the element composing the resulting LazyList
+ * @return the LazyList containing an infinite number of elem
+ */
+ def continually[A](elem: => A): LazyList[A] = newLL(sCons(elem, continually(elem)))
+
+ override def fill[A](n: Int)(elem: => A): LazyList[A] =
+ if (n > 0) newLL(sCons(elem, fill(n - 1)(elem))) else empty
+
+ override def tabulate[A](n: Int)(f: Int => A): LazyList[A] = {
+ def at(index: Int): LazyList[A] =
+ if (index < n) newLL(sCons(f(index), at(index + 1))) else empty
+
+ at(0)
+ }
+
+ // significantly simpler than the iterator returned by Iterator.unfold
+ override def unfold[A, S](init: S)(f: S => Option[(A, S)]): LazyList[A] =
+ newLL {
+ f(init) match {
+ case Some((elem, state)) => sCons(elem, unfold(state)(f))
+ case None => State.Empty
+ }
+ }
+
+ /** The builder returned by this method only evaluates elements
+ * of collections added to it as needed.
+ *
+ * @tparam A the type of the ${coll}’s elements
+ * @return A builder for $Coll objects.
+ */
+ def newBuilder[A]: Builder[A, LazyList[A]] = new LazyBuilder[A]
+
+ private class LazyIterator[+A](private[this] var lazyList: LazyList[A]) extends AbstractIterator[A] {
+ override def hasNext: Boolean = !lazyList.isEmpty
+
+ override def next(): A =
+ if (lazyList.isEmpty) Iterator.empty.next()
+ else {
+ val res = lazyList.head
+ lazyList = lazyList.tail
+ res
+ }
+ }
+
+ private class SlidingIterator[A](private[this] var lazyList: LazyList[A], size: Int, step: Int)
+ extends AbstractIterator[LazyList[A]] {
+ private val minLen = size - step max 0
+ private var first = true
+
+ def hasNext: Boolean =
+ if (first) !lazyList.isEmpty
+ else lazyList.lengthGt(minLen)
+
+ def next(): LazyList[A] = {
+ if (!hasNext) Iterator.empty.next()
+ else {
+ first = false
+ val list = lazyList
+ lazyList = list.drop(step)
+ list.take(size)
+ }
+ }
+ }
+
+ private final class WithFilter[A] private[LazyList](lazyList: LazyList[A], p: A => Boolean)
+ extends collection.WithFilter[A, LazyList] {
+ private[this] val filtered = lazyList.filter(p)
+ def map[B](f: A => B): LazyList[B] = filtered.map(f)
+ def flatMap[B](f: A => IterableOnce[B]): LazyList[B] = filtered.flatMap(f)
+ def foreach[U](f: A => U): Unit = filtered.foreach(f)
+ def withFilter(q: A => Boolean): collection.WithFilter[A, LazyList] = new WithFilter(filtered, q)
+ }
+
+ private final class LazyBuilder[A] extends ReusableBuilder[A, LazyList[A]] {
+ import LazyBuilder._
+
+ private[this] var next: DeferredState[A] = _
+ private[this] var list: LazyList[A] = _
+
+ clear()
+
+ override def clear(): Unit = {
+ val deferred = new DeferredState[A]
+ list = newLL(deferred.eval())
+ next = deferred
+ }
+
+ override def result(): LazyList[A] = {
+ next init State.Empty
+ list
+ }
+
+ override def addOne(elem: A): this.type = {
+ val deferred = new DeferredState[A]
+ next init sCons(elem, newLL(deferred.eval()))
+ next = deferred
+ this
+ }
+
+ // lazy implementation which doesn't evaluate the collection being added
+ override def addAll(xs: IterableOnce[A]): this.type = {
+ if (xs.knownSize != 0) {
+ val deferred = new DeferredState[A]
+ next init stateFromIteratorConcatSuffix(xs.iterator)(deferred.eval())
+ next = deferred
+ }
+ this
+ }
+ }
+
+ private object LazyBuilder {
+ final class DeferredState[A] {
+ private[this] var _state: () => State[A] = _
+
+ def eval(): State[A] = {
+ val state = _state
+ if (state == null) throw new IllegalStateException("uninitialized")
+ state()
+ }
+
+ // racy
+ def init(state: => State[A]): Unit = {
+ if (_state != null) throw new IllegalStateException("already initialized")
+ _state = () => state
+ }
+ }
+ }
+
+ /** This serialization proxy is used for LazyLists which start with a sequence of evaluated cons cells.
+ * The forced sequence is serialized in a compact, sequential format, followed by the unevaluated tail, which uses
+ * standard Java serialization to store the complete structure of unevaluated thunks. This allows the serialization
+ * of long evaluated lazy lists without exhausting the stack through recursive serialization of cons cells.
+ */
+ @SerialVersionUID(3L)
+ final class SerializationProxy[A](@transient protected var coll: LazyList[A]) extends Serializable {
+
+ private[this] def writeObject(out: ObjectOutputStream): Unit = {
+ out.defaultWriteObject()
+ var these = coll
+ while (these.knownNonEmpty) {
+ out.writeObject(these.head)
+ these = these.tail
+ }
+ out.writeObject(SerializeEnd)
+ out.writeObject(these)
+ }
+
+ private[this] def readObject(in: ObjectInputStream): Unit = {
+ in.defaultReadObject()
+ val init = new mutable.ListBuffer[A]
+ var initRead = false
+ while (!initRead) in.readObject match {
+ case SerializeEnd => initRead = true
+ case a => init += a.asInstanceOf[A]
+ }
+ val tail = in.readObject().asInstanceOf[LazyList[A]]
+ // scala/scala#10118: caution that no code path can evaluate `tail.state`
+ // before the resulting LazyList is returned
+ val it = init.toList.iterator
+ coll = newLL(stateFromIteratorConcatSuffix(it)(tail.state))
+ }
+
+ private[this] def readResolve(): Any = coll
+ }
+}
diff --git a/library/src/scala/collection/immutable/List.scala b/library/src/scala/collection/immutable/List.scala
new file mode 100644
index 000000000000..66cb8a487cde
--- /dev/null
+++ b/library/src/scala/collection/immutable/List.scala
@@ -0,0 +1,693 @@
+/*
+ * 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 collection
+package immutable
+
+import scala.annotation.unchecked.uncheckedVariance
+import scala.annotation.tailrec
+import mutable.{Builder, ListBuffer}
+import scala.collection.generic.{CommonErrors, DefaultSerializable}
+import scala.runtime.Statics.releaseFence
+
+/** A class for immutable linked lists representing ordered collections
+ * of elements of type `A`.
+ *
+ * This class comes with two implementing case classes `scala.Nil`
+ * and `scala.::` that implement the abstract members `isEmpty`,
+ * `head` and `tail`.
+ *
+ * This class is optimal for last-in-first-out (LIFO), stack-like access patterns. If you need another access
+ * pattern, for example, random access or FIFO, consider using a collection more suited to this than `List`.
+ *
+ * ==Performance==
+ * '''Time:''' `List` has `O(1)` prepend and head/tail access. Most other operations are `O(n)` on the number of elements in the list.
+ * This includes the index-based lookup of elements, `length`, `append` and `reverse`.
+ *
+ * '''Space:''' `List` implements '''structural sharing''' of the tail list. This means that many operations are either
+ * zero- or constant-memory cost.
+ * {{{
+ * val mainList = List(3, 2, 1)
+ * val with4 = 4 :: mainList // re-uses mainList, costs one :: instance
+ * val with42 = 42 :: mainList // also re-uses mainList, cost one :: instance
+ * val shorter = mainList.tail // costs nothing as it uses the same 2::1::Nil instances as mainList
+ * }}}
+ *
+ * @example {{{
+ * // Make a list via the companion object factory
+ * val days = List("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
+ *
+ * // Make a list element-by-element
+ * val when = "AM" :: "PM" :: Nil
+ *
+ * // Pattern match
+ * days match {
+ * case firstDay :: otherDays =>
+ * println("The first day of the week is: " + firstDay)
+ * case Nil =>
+ * println("There don't seem to be any week days.")
+ * }
+ * }}}
+ *
+ * @note The functional list is characterized by persistence and structural sharing, thus offering considerable
+ * performance and space consumption benefits in some scenarios if used correctly.
+ * However, note that objects having multiple references into the same functional list (that is,
+ * objects that rely on structural sharing), will be serialized and deserialized with multiple lists, one for
+ * each reference to it. I.e. structural sharing is lost after serialization/deserialization.
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-immutable-collection-classes.html#lists "Scala's Collection Library overview"]]
+ * section on `Lists` for more information.
+ *
+ * @define coll list
+ * @define Coll `List`
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+@SerialVersionUID(3L)
+sealed abstract class List[+A]
+ extends AbstractSeq[A]
+ with LinearSeq[A]
+ with LinearSeqOps[A, List, List[A]]
+ with StrictOptimizedLinearSeqOps[A, List, List[A]]
+ with StrictOptimizedSeqOps[A, List, List[A]]
+ with IterableFactoryDefaults[A, List]
+ with DefaultSerializable {
+
+ override def iterableFactory: SeqFactory[List] = List
+
+ /** Adds an element at the beginning of this list.
+ * @param elem the element to prepend.
+ * @return a list which contains `x` as first element and
+ * which continues with this list.
+ * Example:
+ * {{{1 :: List(2, 3) = List(2, 3).::(1) = List(1, 2, 3)}}}
+ */
+ def :: [B >: A](elem: B): List[B] = new ::(elem, this)
+
+ /** Adds the elements of a given list in front of this list.
+ *
+ * Example:
+ * {{{List(1, 2) ::: List(3, 4) = List(3, 4).:::(List(1, 2)) = List(1, 2, 3, 4)}}}
+ *
+ * @param prefix The list elements to prepend.
+ * @return a list resulting from the concatenation of the given
+ * list `prefix` and this list.
+ */
+ def ::: [B >: A](prefix: List[B]): List[B] =
+ if (isEmpty) prefix
+ else if (prefix.isEmpty) this
+ else {
+ val result = new ::[B](prefix.head, this)
+ var curr = result
+ var that = prefix.tail
+ while (!that.isEmpty) {
+ val temp = new ::[B](that.head, this)
+ curr.next = temp
+ curr = temp
+ that = that.tail
+ }
+ releaseFence()
+ result
+ }
+
+ /** Adds the elements of a given list in reverse order in front of this list.
+ * `xs reverse_::: ys` is equivalent to
+ * `xs.reverse ::: ys` but is more efficient.
+ *
+ * @param prefix the prefix to reverse and then prepend
+ * @return the concatenation of the reversed prefix and the current list.
+ */
+ def reverse_:::[B >: A](prefix: List[B]): List[B] = {
+ var these: List[B] = this
+ var pres = prefix
+ while (!pres.isEmpty) {
+ these = pres.head :: these
+ pres = pres.tail
+ }
+ these
+ }
+
+ override final def isEmpty: Boolean = this eq Nil
+
+ override def prepended[B >: A](elem: B): List[B] = elem :: this
+
+ override def prependedAll[B >: A](prefix: collection.IterableOnce[B]): List[B] = prefix match {
+ case xs: List[B] => xs ::: this
+ case _ if prefix.knownSize == 0 => this
+ case b: ListBuffer[B] if this.isEmpty => b.toList
+ case _ =>
+ val iter = prefix.iterator
+ if (iter.hasNext) {
+ val result = new ::[B](iter.next(), this)
+ var curr = result
+ while (iter.hasNext) {
+ val temp = new ::[B](iter.next(), this)
+ curr.next = temp
+ curr = temp
+ }
+ releaseFence()
+ result
+ } else {
+ this
+ }
+ }
+
+ // When calling appendAll with another list `suffix`, avoid copying `suffix`
+ override def appendedAll[B >: A](suffix: collection.IterableOnce[B]): List[B] = suffix match {
+ case xs: List[B] => this ::: xs
+ case _ => super.appendedAll(suffix)
+ }
+
+ override def take(n: Int): List[A] = if (isEmpty || n <= 0) Nil else {
+ val h = new ::(head, Nil)
+ var t = h
+ var rest = tail
+ var i = 1
+ while ({if (rest.isEmpty) return this; i < n}) {
+ i += 1
+ val nx = new ::(rest.head, Nil)
+ t.next = nx
+ t = nx
+ rest = rest.tail
+ }
+ releaseFence()
+ h
+ }
+
+ /** @inheritdoc
+ *
+ * @example {{{
+ * // Given a list
+ * val letters = List('a','b','c','d','e')
+ *
+ * // `slice` returns all elements beginning at index `from` and afterwards,
+ * // up until index `until` (excluding index `until`.)
+ * letters.slice(1,3) // Returns List('b','c')
+ * }}}
+ */
+ override def slice(from: Int, until: Int): List[A] = {
+ val lo = scala.math.max(from, 0)
+ if (until <= lo || isEmpty) Nil
+ else this drop lo take (until - lo)
+ }
+
+ override def takeRight(n: Int): List[A] = {
+ @tailrec
+ def loop(lead: List[A], lag: List[A]): List[A] = lead match {
+ case Nil => lag
+ case _ :: tail => loop(tail, lag.tail)
+ }
+ loop(drop(n), this)
+ }
+
+ // dropRight is inherited from LinearSeq
+
+ override def splitAt(n: Int): (List[A], List[A]) = {
+ val b = new ListBuffer[A]
+ var i = 0
+ var these = this
+ while (!these.isEmpty && i < n) {
+ i += 1
+ b += these.head
+ these = these.tail
+ }
+ (b.toList, these)
+ }
+
+ override def updated[B >: A](index: Int, elem: B): List[B] = {
+ var i = 0
+ var current = this
+ val prefix = ListBuffer.empty[B]
+ while (i < index && current.nonEmpty) {
+ i += 1
+ prefix += current.head
+ current = current.tail
+ }
+ if (i == index && current.nonEmpty) {
+ prefix.prependToList(elem :: current.tail)
+ } else {
+ throw CommonErrors.indexOutOfBounds(index = index, max = length - 1)
+ }
+ }
+
+ final override def map[B](f: A => B): List[B] = {
+ if (this eq Nil) Nil else {
+ val h = new ::[B](f(head), Nil)
+ var t: ::[B] = h
+ var rest = tail
+ while (rest ne Nil) {
+ val nx = new ::(f(rest.head), Nil)
+ t.next = nx
+ t = nx
+ rest = rest.tail
+ }
+ releaseFence()
+ h
+ }
+ }
+
+ final override def collect[B](pf: PartialFunction[A, B]): List[B] = {
+ if (this eq Nil) Nil else {
+ var rest = this
+ var h: ::[B] = null
+ var x: Any = null
+ // Special case for first element
+ while (h eq null) {
+ x = pf.applyOrElse(rest.head, List.partialNotApplied)
+ if (x.asInstanceOf[AnyRef] ne List.partialNotApplied) h = new ::(x.asInstanceOf[B], Nil)
+ rest = rest.tail
+ if (rest eq Nil) return if (h eq null) Nil else h
+ }
+ var t = h
+ // Remaining elements
+ while (rest ne Nil) {
+ x = pf.applyOrElse(rest.head, List.partialNotApplied)
+ if (x.asInstanceOf[AnyRef] ne List.partialNotApplied) {
+ val nx = new ::(x.asInstanceOf[B], Nil)
+ t.next = nx
+ t = nx
+ }
+ rest = rest.tail
+ }
+ releaseFence()
+ h
+ }
+ }
+
+ final override def flatMap[B](f: A => IterableOnce[B]): List[B] = {
+ var rest = this
+ var h: ::[B] = null
+ var t: ::[B] = null
+ while (rest ne Nil) {
+ val it = f(rest.head).iterator
+ while (it.hasNext) {
+ val nx = new ::(it.next(), Nil)
+ if (t eq null) {
+ h = nx
+ } else {
+ t.next = nx
+ }
+ t = nx
+ }
+ rest = rest.tail
+ }
+ if (h eq null) Nil else {releaseFence(); h}
+ }
+
+ @inline final override def takeWhile(p: A => Boolean): List[A] = {
+ val b = new ListBuffer[A]
+ var these = this
+ while (!these.isEmpty && p(these.head)) {
+ b += these.head
+ these = these.tail
+ }
+ b.toList
+ }
+
+ @inline final override def span(p: A => Boolean): (List[A], List[A]) = {
+ val b = new ListBuffer[A]
+ var these = this
+ while (!these.isEmpty && p(these.head)) {
+ b += these.head
+ these = these.tail
+ }
+ (b.toList, these)
+ }
+
+ // Overridden with an implementation identical to the inherited one (at this time)
+ // solely so it can be finalized and thus inlinable.
+ @inline final override def foreach[U](f: A => U): Unit = {
+ var these = this
+ while (!these.isEmpty) {
+ f(these.head)
+ these = these.tail
+ }
+ }
+
+ final override def reverse: List[A] = {
+ var result: List[A] = Nil
+ var these = this
+ while (!these.isEmpty) {
+ result = these.head :: result
+ these = these.tail
+ }
+ result
+ }
+
+ final override def foldRight[B](z: B)(op: (A, B) => B): B = {
+ var acc = z
+ var these: List[A] = reverse
+ while (!these.isEmpty) {
+ acc = op(these.head, acc)
+ these = these.tail
+ }
+ acc
+ }
+
+ // Copy/Paste overrides to avoid interface calls inside loops.
+
+ override final def length: Int = {
+ var these = this
+ var len = 0
+ while (!these.isEmpty) {
+ len += 1
+ these = these.tail
+ }
+ len
+ }
+
+ override final def lengthCompare(len: Int): Int = {
+ @tailrec def loop(i: Int, xs: List[A]): Int = {
+ if (i == len)
+ if (xs.isEmpty) 0 else 1
+ else if (xs.isEmpty)
+ -1
+ else
+ loop(i + 1, xs.tail)
+ }
+ if (len < 0) 1
+ else loop(0, coll)
+ }
+
+ override final def forall(p: A => Boolean): Boolean = {
+ var these: List[A] = this
+ while (!these.isEmpty) {
+ if (!p(these.head)) return false
+ these = these.tail
+ }
+ true
+ }
+
+ override final def exists(p: A => Boolean): Boolean = {
+ var these: List[A] = this
+ while (!these.isEmpty) {
+ if (p(these.head)) return true
+ these = these.tail
+ }
+ false
+ }
+
+ override final def contains[A1 >: A](elem: A1): Boolean = {
+ var these: List[A] = this
+ while (!these.isEmpty) {
+ if (these.head == elem) return true
+ these = these.tail
+ }
+ false
+ }
+
+ override final def find(p: A => Boolean): Option[A] = {
+ var these: List[A] = this
+ while (!these.isEmpty) {
+ if (p(these.head)) return Some(these.head)
+ these = these.tail
+ }
+ None
+ }
+
+ override def last: A = {
+ if (isEmpty) throw new NoSuchElementException("List.last")
+ else {
+ var these = this
+ var scout = tail
+ while (!scout.isEmpty) {
+ these = scout
+ scout = scout.tail
+ }
+ these.head
+ }
+ }
+
+ override def corresponds[B](that: collection.Seq[B])(p: (A, B) => Boolean): Boolean = that match {
+ case that: LinearSeq[B] =>
+ var i = this
+ var j = that
+ while (!(i.isEmpty || j.isEmpty)) {
+ if (!p(i.head, j.head))
+ return false
+ i = i.tail
+ j = j.tail
+ }
+ i.isEmpty && j.isEmpty
+ case _ =>
+ super.corresponds(that)(p)
+ }
+
+ override protected[this] def className = "List"
+
+ /** Builds a new list by applying a function to all elements of this list.
+ * Like `xs map f`, but returns `xs` unchanged if function
+ * `f` maps all elements to themselves (as determined by `eq`).
+ *
+ * @param f the function to apply to each element.
+ * @tparam B the element type of the returned collection.
+ * @return a list resulting from applying the given function
+ * `f` to each element of this list and collecting the results.
+ */
+ @`inline` final def mapConserve[B >: A <: AnyRef](f: A => B): List[B] = {
+ // Note to developers: there exists a duplication between this function and `reflect.internal.util.Collections#map2Conserve`.
+ // If any successful optimization attempts or other changes are made, please rehash them there too.
+ @tailrec
+ def loop(mappedHead: List[B], mappedLast: ::[B], unchanged: List[A], pending: List[A]): List[B] = {
+ if (pending.isEmpty) {
+ if (mappedHead eq null) unchanged
+ else {
+ mappedLast.next = (unchanged: List[B])
+ mappedHead
+ }
+ }
+ else {
+ val head0 = pending.head
+ val head1 = f(head0)
+
+ if (head1 eq head0.asInstanceOf[AnyRef])
+ loop(mappedHead, mappedLast, unchanged, pending.tail)
+ else {
+ var xc = unchanged
+ var mappedHead1: List[B] = mappedHead
+ var mappedLast1: ::[B] = mappedLast
+ while (xc ne pending) {
+ val next = new ::[B](xc.head, Nil)
+ if (mappedHead1 eq null) mappedHead1 = next
+ if (mappedLast1 ne null) mappedLast1.next = next
+ mappedLast1 = next
+ xc = xc.tail
+ }
+ val next = new ::(head1, Nil)
+ if (mappedHead1 eq null) mappedHead1 = next
+ if (mappedLast1 ne null) mappedLast1.next = next
+ mappedLast1 = next
+ val tail0 = pending.tail
+ loop(mappedHead1, mappedLast1, tail0, tail0)
+
+ }
+ }
+ }
+ val result = loop(null, null, this, this)
+ releaseFence()
+ result
+ }
+
+ override def filter(p: A => Boolean): List[A] = filterCommon(p, isFlipped = false)
+
+ override def filterNot(p: A => Boolean): List[A] = filterCommon(p, isFlipped = true)
+
+ private[this] def filterCommon(p: A => Boolean, isFlipped: Boolean): List[A] = {
+
+ // everything seen so far so far is not included
+ @tailrec def noneIn(l: List[A]): List[A] = {
+ if (l.isEmpty)
+ Nil
+ else {
+ val h = l.head
+ val t = l.tail
+ if (p(h) != isFlipped)
+ allIn(l, t)
+ else
+ noneIn(t)
+ }
+ }
+
+ // everything from 'start' is included, if everything from this point is in we can return the origin
+ // start otherwise if we discover an element that is out we must create a new partial list.
+ @tailrec def allIn(start: List[A], remaining: List[A]): List[A] = {
+ if (remaining.isEmpty)
+ start
+ else {
+ val x = remaining.head
+ if (p(x) != isFlipped)
+ allIn(start, remaining.tail)
+ else
+ partialFill(start, remaining)
+ }
+ }
+
+ // we have seen elements that should be included then one that should be excluded, start building
+ def partialFill(origStart: List[A], firstMiss: List[A]): List[A] = {
+ val newHead = new ::(origStart.head, Nil)
+ var toProcess = origStart.tail
+ var currentLast = newHead
+
+ // we know that all elements are :: until at least firstMiss.tail
+ while (!(toProcess eq firstMiss)) {
+ val newElem = new ::(toProcess.head, Nil)
+ currentLast.next = newElem
+ currentLast = newElem
+ toProcess = toProcess.tail
+ }
+
+ // at this point newHead points to a list which is a duplicate of all the 'in' elements up to the first miss.
+ // currentLast is the last element in that list.
+
+ // now we are going to try and share as much of the tail as we can, only moving elements across when we have to.
+ var next = firstMiss.tail
+ var nextToCopy = next // the next element we would need to copy to our list if we cant share.
+ while (!next.isEmpty) {
+ // generally recommended is next.isNonEmpty but this incurs an extra method call.
+ val head: A = next.head
+ if (p(head) != isFlipped) {
+ next = next.tail
+ } else {
+ // its not a match - do we have outstanding elements?
+ while (!(nextToCopy eq next)) {
+ val newElem = new ::(nextToCopy.head, Nil)
+ currentLast.next = newElem
+ currentLast = newElem
+ nextToCopy = nextToCopy.tail
+ }
+ nextToCopy = next.tail
+ next = next.tail
+ }
+ }
+
+ // we have remaining elements - they are unchanged attach them to the end
+ if (!nextToCopy.isEmpty)
+ currentLast.next = nextToCopy
+
+ newHead
+ }
+
+ val result = noneIn(this)
+ releaseFence()
+ result
+ }
+
+ override def partition(p: A => Boolean): (List[A], List[A]) = {
+ if (isEmpty) List.TupleOfNil
+ else super.partition(p) match {
+ case (Nil, xs) => (Nil, this)
+ case (xs, Nil) => (this, Nil)
+ case pair => pair
+ }
+ }
+
+ final override def toList: List[A] = this
+
+ // Override for performance
+ override def equals(o: scala.Any): Boolean = {
+ @tailrec def listEq(a: List[_], b: List[_]): Boolean =
+ (a eq b) || {
+ val aEmpty = a.isEmpty
+ val bEmpty = b.isEmpty
+ if (!(aEmpty || bEmpty) && a.head == b.head) {
+ listEq(a.tail, b.tail)
+ }
+ else {
+ aEmpty && bEmpty
+ }
+ }
+
+ o match {
+ case that: List[_] => listEq(this, that)
+ case _ => super.equals(o)
+ }
+ }
+
+ // TODO: uncomment once bincompat allows (reference: scala/scala#9365)
+ /*
+ // Override for performance: traverse only as much as needed
+ // and share tail when nothing needs to be filtered out anymore
+ override def diff[B >: A](that: collection.Seq[B]): AnyRef = {
+ if (that.isEmpty || this.isEmpty) this
+ else if (tail.isEmpty) if (that.contains(head)) Nil else this
+ else {
+ val occ = occCounts(that)
+ val b = new ListBuffer[A]()
+ @tailrec
+ def rec(remainder: List[A]): List[A] = {
+ if(occ.isEmpty) b.prependToList(remainder)
+ else remainder match {
+ case Nil => b.result()
+ case head :: next => {
+ occ.updateWith(head){
+ case None => {
+ b.append(head)
+ None
+ }
+ case Some(1) => None
+ case Some(n) => Some(n - 1)
+ }
+ rec(next)
+ }
+ }
+ }
+ rec(this)
+ }
+ }
+ */
+
+}
+
+// Internal code that mutates `next` _must_ call `Statics.releaseFence()` if either immediately, or
+// before a newly-allocated, thread-local :: instance is aliased (e.g. in ListBuffer.toList)
+final case class :: [+A](override val head: A, private[scala] var next: List[A @uncheckedVariance]) // sound because `next` is used only locally
+ extends List[A] {
+ releaseFence()
+ override def headOption: Some[A] = Some(head)
+ override def tail: List[A] = next
+}
+
+case object Nil extends List[Nothing] {
+ override def head: Nothing = throw new NoSuchElementException("head of empty list")
+ override def headOption: None.type = None
+ override def tail: Nothing = throw new UnsupportedOperationException("tail of empty list")
+ override def last: Nothing = throw new NoSuchElementException("last of empty list")
+ override def init: Nothing = throw new UnsupportedOperationException("init of empty list")
+ override def knownSize: Int = 0
+ override def iterator: Iterator[Nothing] = Iterator.empty
+ override def unzip[A1, A2](implicit asPair: Nothing => (A1, A2)): (List[A1], List[A2]) = EmptyUnzip
+
+ @transient
+ private[this] val EmptyUnzip = (Nil, Nil)
+}
+
+/**
+ * $factoryInfo
+ * @define coll list
+ * @define Coll `List`
+ */
+@SerialVersionUID(3L)
+object List extends StrictOptimizedSeqFactory[List] {
+ private val TupleOfNil = (Nil, Nil)
+
+ def from[B](coll: collection.IterableOnce[B]): List[B] = Nil.prependedAll(coll)
+
+ def newBuilder[A]: Builder[A, List[A]] = new ListBuffer()
+
+ def empty[A]: List[A] = Nil
+
+ @transient
+ private[collection] val partialNotApplied = new Function1[Any, Any] { def apply(x: Any): Any = this }
+}
diff --git a/library/src/scala/collection/immutable/ListMap.scala b/library/src/scala/collection/immutable/ListMap.scala
new file mode 100644
index 000000000000..74d1697cac7f
--- /dev/null
+++ b/library/src/scala/collection/immutable/ListMap.scala
@@ -0,0 +1,372 @@
+/*
+ * 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 collection
+package immutable
+
+import scala.annotation.{nowarn, tailrec}
+import scala.collection.mutable.ReusableBuilder
+import scala.collection.generic.DefaultSerializable
+import scala.runtime.Statics.releaseFence
+import scala.util.hashing.MurmurHash3
+
+/**
+ * This class implements immutable maps using a list-based data structure. List map iterators and
+ * traversal methods visit key-value pairs in the order they were first inserted.
+ *
+ * Entries are stored internally in reversed insertion order, which means the newest key is at the
+ * head of the list. As such, methods such as `head` and `tail` are O(n), while `last` and `init`
+ * are O(1). Other operations, such as inserting or removing entries, are also O(n), which makes
+ * this collection suitable only for a small number of elements.
+ *
+ * Instances of `ListMap` represent empty maps; they can be either created by calling the
+ * constructor directly, or by applying the function `ListMap.empty`.
+ *
+ * @tparam K the type of the keys contained in this list map
+ * @tparam V the type of the values associated with the keys
+ *
+ * @define Coll ListMap
+ * @define coll list map
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+sealed class ListMap[K, +V]
+ extends AbstractMap[K, V]
+ with SeqMap[K, V]
+ with StrictOptimizedMapOps[K, V, ListMap, ListMap[K, V]]
+ with MapFactoryDefaults[K, V, ListMap, Iterable]
+ with DefaultSerializable {
+
+ override def mapFactory: MapFactory[ListMap] = ListMap
+
+ override def size: Int = 0
+
+ override def isEmpty: Boolean = true
+
+ override def knownSize: Int = 0
+ def get(key: K): Option[V] = None
+
+ def updated[V1 >: V](key: K, value: V1): ListMap[K, V1] = new ListMap.Node[K, V1](key, value, this)
+
+ def removed(key: K): ListMap[K, V] = this
+
+ def iterator: Iterator[(K, V)] = {
+ var curr: ListMap[K, V] = this
+ var res: List[(K, V)] = Nil
+ while (curr.nonEmpty) {
+ res = (curr.key, curr.value) :: res
+ curr = curr.next
+ }
+ res.iterator
+ }
+
+ @nowarn("msg=overriding method keys")
+ override def keys: Iterable[K] = {
+ var curr: ListMap[K, V] = this
+ var res: List[K] = Nil
+ while (curr.nonEmpty) {
+ res = curr.key :: res
+ curr = curr.next
+ }
+ res
+ }
+
+ override def hashCode(): Int = {
+ if (isEmpty) MurmurHash3.emptyMapHash
+ else {
+ // Can't efficiently override foreachEntry directly in ListMap because it would need to preserve iteration
+ // order be reversing the list first. But mapHash is symmetric so the reversed order is fine here.
+ val _reversed = new immutable.AbstractMap[K, V] {
+ override def isEmpty: Boolean = ListMap.this.isEmpty
+ override def removed(key: K): Map[K, V] = ListMap.this.removed(key)
+ override def updated[V1 >: V](key: K, value: V1): Map[K, V1] = ListMap.this.updated(key, value)
+ override def get(key: K): Option[V] = ListMap.this.get(key)
+ override def iterator: Iterator[(K, V)] = ListMap.this.iterator
+ override def foreachEntry[U](f: (K, V) => U): Unit = {
+ var curr: ListMap[K, V] = ListMap.this
+ while (curr.nonEmpty) {
+ f(curr.key, curr.value)
+ curr = curr.next
+ }
+ }
+ }
+ MurmurHash3.mapHash(_reversed)
+ }
+ }
+
+ private[immutable] def key: K = throw new NoSuchElementException("key of empty map")
+ private[immutable] def value: V = throw new NoSuchElementException("value of empty map")
+ private[immutable] def next: ListMap[K, V] = throw new NoSuchElementException("next of empty map")
+
+ override def foldRight[Z](z: Z)(op: ((K, V), Z) => Z): Z = ListMap.foldRightInternal(this, z, op)
+ override protected[this] def className = "ListMap"
+
+}
+
+/**
+ * $factoryInfo
+ *
+ * Note that each element insertion takes O(n) time, which means that creating a list map with
+ * n elements will take O(n^2^) time. This makes the builder suitable only for a small number of
+ * elements.
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-immutable-collection-classes.html#list-maps "Scala's Collection Library overview"]]
+ * section on `List Maps` for more information.
+ * @define Coll ListMap
+ * @define coll list map
+ */
+@SerialVersionUID(3L)
+object ListMap extends MapFactory[ListMap] {
+ /**
+ * Represents an entry in the `ListMap`.
+ */
+ private[immutable] final class Node[K, V](
+ override private[immutable] val key: K,
+ private[immutable] var _value: V,
+ private[immutable] var _init: ListMap[K, V]
+ ) extends ListMap[K, V] {
+ releaseFence()
+
+ override private[immutable] def value: V = _value
+
+ override def size: Int = sizeInternal(this, 0)
+
+ @tailrec private[this] def sizeInternal(cur: ListMap[K, V], acc: Int): Int =
+ if (cur.isEmpty) acc
+ else sizeInternal(cur.next, acc + 1)
+
+ override def isEmpty: Boolean = false
+
+ override def knownSize: Int = -1
+
+ @throws[NoSuchElementException]
+ override def apply(k: K): V = applyInternal(this, k)
+
+ @tailrec private[this] def applyInternal(cur: ListMap[K, V], k: K): V =
+ if (cur.isEmpty) throw new NoSuchElementException("key not found: " + k)
+ else if (k == cur.key) cur.value
+ else applyInternal(cur.next, k)
+
+ override def get(k: K): Option[V] = getInternal(this, k)
+
+ @tailrec private[this] def getInternal(cur: ListMap[K, V], k: K): Option[V] =
+ if (cur.isEmpty) None
+ else if (k == cur.key) Some(cur.value)
+ else getInternal(cur.next, k)
+
+ override def contains(k: K): Boolean = containsInternal(this, k)
+
+ @tailrec private[this] def containsInternal(cur: ListMap[K, V], k: K): Boolean =
+ if (cur.isEmpty) false
+ else if (k == cur.key) true
+ else containsInternal(cur.next, k)
+
+ override def updated[V1 >: V](k: K, v: V1): ListMap[K, V1] = {
+
+ var index = -1 // the index (in reverse) where the key to update exists, if it is found
+ var found = false // true if the key is found int he map
+ var isDifferent = false // true if the key was found and the values are different
+
+ {
+ var curr: ListMap[K, V] = this
+
+ while (curr.nonEmpty && !found) {
+ if (k == curr.key) {
+ found = true
+ isDifferent = v.asInstanceOf[AnyRef] ne curr.value.asInstanceOf[AnyRef]
+ }
+ index += 1
+ curr = curr.init
+ }
+ }
+
+ if (found) {
+ if (isDifferent) {
+ var newHead: ListMap.Node[K, V1] = null
+ var prev: ListMap.Node[K, V1] = null
+ var curr: ListMap[K, V1] = this
+ var i = 0
+ while (i < index) {
+ val temp = new ListMap.Node(curr.key, curr.value, null)
+ if (prev ne null) {
+ prev._init = temp
+ }
+ prev = temp
+ curr = curr.init
+ if (newHead eq null) {
+ newHead = prev
+ }
+ i += 1
+ }
+ val newNode = new ListMap.Node(curr.key, v, curr.init)
+ if (prev ne null) {
+ prev._init = newNode
+ }
+ releaseFence()
+ if (newHead eq null) newNode else newHead
+ } else {
+ this
+ }
+ } else {
+ new ListMap.Node(k, v, this)
+ }
+ }
+
+ @tailrec private[this] def removeInternal(k: K, cur: ListMap[K, V], acc: List[ListMap[K, V]]): ListMap[K, V] =
+ if (cur.isEmpty) acc.last
+ else if (k == cur.key) acc.foldLeft(cur.next) { (t, h) => new Node(h.key, h.value, t) }
+ else removeInternal(k, cur.next, cur :: acc)
+
+ override def removed(k: K): ListMap[K, V] = removeInternal(k, this, Nil)
+
+ override private[immutable] def next: ListMap[K, V] = _init
+
+ override def last: (K, V) = (key, value)
+ override def init: ListMap[K, V] = next
+
+ }
+
+ def empty[K, V]: ListMap[K, V] = EmptyListMap.asInstanceOf[ListMap[K, V]]
+
+ private object EmptyListMap extends ListMap[Any, Nothing]
+
+ def from[K, V](it: collection.IterableOnce[(K, V)]): ListMap[K, V] =
+ it match {
+ case lm: ListMap[K, V] => lm
+ case lhm: collection.mutable.LinkedHashMap[K, V] =>
+ // by directly iterating through LinkedHashMap entries, we save creating intermediate tuples for each
+ // key-value pair
+ var current: ListMap[K, V] = empty[K, V]
+ var firstEntry = lhm._firstEntry
+ while (firstEntry ne null) {
+ current = new Node(firstEntry.key, firstEntry.value, current)
+ firstEntry = firstEntry.later
+ }
+ current
+ case _: collection.Map[K, V] | _: collection.MapView[K, V] =>
+ // when creating from a map, we need not handle duplicate keys, so we can just append each key-value to the end
+ var current: ListMap[K, V] = empty[K, V]
+ val iter = it.iterator
+ while (iter.hasNext) {
+ val (k, v) = iter.next()
+ current = new Node(k, v, current)
+ }
+ current
+
+ case _ => (newBuilder[K, V] ++= it).result()
+ }
+
+ /** Returns a new ListMap builder
+ *
+ * The implementation safely handles additions after `result()` without calling `clear()`
+ *
+ * @tparam K the map key type
+ * @tparam V the map value type
+ */
+ def newBuilder[K, V]: ReusableBuilder[(K, V), ListMap[K, V]] = new ListMapBuilder[K, V]
+
+ @tailrec private def foldRightInternal[K, V, Z](map: ListMap[K, V], prevValue: Z, op: ((K, V), Z) => Z): Z = {
+ if (map.isEmpty) prevValue
+ else foldRightInternal(map.init, op(map.last, prevValue), op)
+ }
+}
+
+/** Builder for ListMap.
+ * $multipleResults
+ */
+private[immutable] final class ListMapBuilder[K, V] extends mutable.ReusableBuilder[(K, V), ListMap[K, V]] {
+ private[this] var isAliased: Boolean = false
+ private[this] var underlying: ListMap[K, V] = ListMap.empty
+
+ override def clear(): Unit = {
+ underlying = ListMap.empty
+ isAliased = false
+ }
+
+ override def result(): ListMap[K, V] = {
+ isAliased = true
+ releaseFence()
+ underlying
+ }
+
+ override def addOne(elem: (K, V)): this.type = addOne(elem._1, elem._2)
+
+ @tailrec
+ private[this] def insertValueAtKeyReturnFound(m: ListMap[K, V], key: K, value: V): Boolean = m match {
+ case n: ListMap.Node[K, V] =>
+ if (n.key == key) {
+ n._value = value
+ true
+ } else {
+ insertValueAtKeyReturnFound(n.init, key, value)
+ }
+ case _ => false
+ }
+
+ def addOne(key: K, value: V): this.type = {
+ if (isAliased) {
+ underlying = underlying.updated(key, value)
+ } else {
+ if (!insertValueAtKeyReturnFound(underlying, key, value)) {
+ underlying = new ListMap.Node(key, value, underlying)
+ }
+ }
+ this
+ }
+ override def addAll(xs: IterableOnce[(K, V)]): this.type = {
+ if (isAliased) {
+ super.addAll(xs)
+ } else if (underlying.nonEmpty) {
+ xs match {
+ case m: collection.Map[K, V] =>
+ // if it is a map, then its keys will not collide with themselves.
+ // therefor we only need to check the already-existing elements for collisions.
+ // No need to check the entire list
+
+ val iter = m.iterator
+ var newUnderlying = underlying
+ while (iter.hasNext) {
+ val next = iter.next()
+ if (!insertValueAtKeyReturnFound(underlying, next._1, next._2)) {
+ newUnderlying = new ListMap.Node[K, V](next._1, next._2, newUnderlying)
+ }
+ }
+ underlying = newUnderlying
+ this
+
+ case _ =>
+ super.addAll(xs)
+ }
+ } else xs match {
+ case lhm: collection.mutable.LinkedHashMap[K, V] =>
+ // special-casing LinkedHashMap avoids creating of Iterator and tuples for each key-value
+ var firstEntry = lhm._firstEntry
+ while (firstEntry ne null) {
+ underlying = new ListMap.Node(firstEntry.key, firstEntry.value, underlying)
+ firstEntry = firstEntry.later
+ }
+ this
+
+ case _: collection.Map[K, V] | _: collection.MapView[K, V] =>
+ val iter = xs.iterator
+ while (iter.hasNext) {
+ val (k, v) = iter.next()
+ underlying = new ListMap.Node(k, v, underlying)
+ }
+
+ this
+ case _ =>
+ super.addAll(xs)
+ }
+ }
+}
diff --git a/library/src/scala/collection/immutable/ListSet.scala b/library/src/scala/collection/immutable/ListSet.scala
new file mode 100644
index 000000000000..2e2758cb2747
--- /dev/null
+++ b/library/src/scala/collection/immutable/ListSet.scala
@@ -0,0 +1,138 @@
+/*
+ * 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 collection
+package immutable
+
+import mutable.{Builder, ImmutableBuilder}
+import scala.annotation.tailrec
+import scala.collection.generic.DefaultSerializable
+
+/**
+ * This class implements immutable sets using a list-based data structure. List set iterators and
+ * traversal methods visit elements in the order they were first inserted.
+ *
+ * Elements are stored internally in reversed insertion order, which means the newest element is at
+ * the head of the list. As such, methods such as `head` and `tail` are O(n), while `last` and
+ * `init` are O(1). Other operations, such as inserting or removing entries, are also O(n), which
+ * makes this collection suitable only for a small number of elements.
+ *
+ * Instances of `ListSet` represent empty sets; they can be either created by calling the
+ * constructor directly, or by applying the function `ListSet.empty`.
+ *
+ * @tparam A the type of the elements contained in this list set
+ *
+ * @define Coll ListSet
+ * @define coll list set
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+sealed class ListSet[A]
+ extends AbstractSet[A]
+ with StrictOptimizedSetOps[A, ListSet, ListSet[A]]
+ with IterableFactoryDefaults[A, ListSet]
+ with DefaultSerializable {
+
+ override protected[this] def className: String = "ListSet"
+
+ override def size: Int = 0
+ override def knownSize: Int = 0
+ override def isEmpty: Boolean = true
+
+ def contains(elem: A): Boolean = false
+
+ def incl(elem: A): ListSet[A] = new Node(elem)
+ def excl(elem: A): ListSet[A] = this
+
+ def iterator: scala.collection.Iterator[A] = {
+ var curr: ListSet[A] = this
+ var res: List[A] = Nil
+ while (!curr.isEmpty) {
+ res = curr.elem :: res
+ curr = curr.next
+ }
+ res.iterator
+ }
+
+ protected def elem: A = throw new NoSuchElementException("elem of empty set")
+ protected def next: ListSet[A] = throw new NoSuchElementException("next of empty set")
+
+ override def iterableFactory: IterableFactory[ListSet] = ListSet
+
+ /**
+ * Represents an entry in the `ListSet`.
+ */
+ protected class Node(override protected val elem: A) extends ListSet[A] {
+
+ override def size = sizeInternal(this, 0)
+ override def knownSize: Int = -1
+ @tailrec private[this] def sizeInternal(n: ListSet[A], acc: Int): Int =
+ if (n.isEmpty) acc
+ else sizeInternal(n.next, acc + 1)
+
+ override def isEmpty: Boolean = false
+
+ override def contains(e: A): Boolean = containsInternal(this, e)
+
+ @tailrec private[this] def containsInternal(n: ListSet[A], e: A): Boolean =
+ !n.isEmpty && (n.elem == e || containsInternal(n.next, e))
+
+ override def incl(e: A): ListSet[A] = if (contains(e)) this else new Node(e)
+
+ override def excl(e: A): ListSet[A] = removeInternal(e, this, Nil)
+
+ @tailrec private[this] def removeInternal(k: A, cur: ListSet[A], acc: List[ListSet[A]]): ListSet[A] =
+ if (cur.isEmpty) acc.last
+ else if (k == cur.elem) acc.foldLeft(cur.next)((t, h) => new t.Node(h.elem))
+ else removeInternal(k, cur.next, cur :: acc)
+
+ override protected def next: ListSet[A] = ListSet.this
+
+ override def last: A = elem
+
+ override def init: ListSet[A] = next
+ }
+}
+
+/**
+ * $factoryInfo
+ *
+ * Note that each element insertion takes O(n) time, which means that creating a list set with
+ * n elements will take O(n^2^) time. This makes the builder suitable only for a small number of
+ * elements.
+ *
+ * @define Coll ListSet
+ * @define coll list set
+ */
+@SerialVersionUID(3L)
+object ListSet extends IterableFactory[ListSet] {
+
+ def from[E](it: scala.collection.IterableOnce[E]): ListSet[E] =
+ it match {
+ case ls: ListSet[E] => ls
+ case _ if it.knownSize == 0 => empty[E]
+ case _ => (newBuilder[E] ++= it).result()
+ }
+
+ private object EmptyListSet extends ListSet[Any] {
+ override def knownSize: Int = 0
+ }
+ private[collection] def emptyInstance: ListSet[Any] = EmptyListSet
+
+ def empty[A]: ListSet[A] = EmptyListSet.asInstanceOf[ListSet[A]]
+
+ def newBuilder[A]: Builder[A, ListSet[A]] =
+ new ImmutableBuilder[A, ListSet[A]](empty) {
+ def addOne(elem: A): this.type = { elems = elems + elem; this }
+ }
+}
diff --git a/library/src/scala/collection/immutable/LongMap.scala b/library/src/scala/collection/immutable/LongMap.scala
new file mode 100644
index 000000000000..8ff968f58305
--- /dev/null
+++ b/library/src/scala/collection/immutable/LongMap.scala
@@ -0,0 +1,490 @@
+/*
+ * 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.IllegalStateException
+
+import scala.collection.generic.{BitOperations, DefaultSerializationProxy}
+import scala.collection.mutable.{Builder, ImmutableBuilder, ListBuffer}
+import scala.annotation.tailrec
+import scala.annotation.unchecked.uncheckedVariance
+import scala.language.implicitConversions
+
+/** Utility class for long maps.
+ */
+private[immutable] object LongMapUtils extends BitOperations.Long {
+ def branchMask(i: Long, j: Long) = highestOneBit(i ^ j)
+
+ def join[T](p1: Long, t1: LongMap[T], p2: Long, t2: LongMap[T]): LongMap[T] = {
+ val m = branchMask(p1, p2)
+ val p = mask(p1, m)
+ if (zero(p1, m)) LongMap.Bin(p, m, t1, t2)
+ else LongMap.Bin(p, m, t2, t1)
+ }
+
+ def bin[T](prefix: Long, mask: Long, left: LongMap[T], right: LongMap[T]): LongMap[T] = (left, right) match {
+ case (left, LongMap.Nil) => left
+ case (LongMap.Nil, right) => right
+ case (left, right) => LongMap.Bin(prefix, mask, left, right)
+ }
+}
+
+import LongMapUtils.{Long => _, _}
+
+/** A companion object for long maps.
+ *
+ * @define Coll `LongMap`
+ */
+object LongMap {
+ def empty[T]: LongMap[T] = LongMap.Nil
+ def singleton[T](key: Long, value: T): LongMap[T] = LongMap.Tip(key, value)
+ def apply[T](elems: (Long, T)*): LongMap[T] =
+ elems.foldLeft(empty[T])((x, y) => x.updated(y._1, y._2))
+
+ def from[V](coll: IterableOnce[(Long, V)]): LongMap[V] =
+ newBuilder[V].addAll(coll).result()
+
+ def newBuilder[V]: Builder[(Long, V), LongMap[V]] =
+ new ImmutableBuilder[(Long, V), LongMap[V]](empty) {
+ def addOne(elem: (Long, V)): this.type = { elems = elems + elem; this }
+ }
+
+ private[immutable] case object Nil extends LongMap[Nothing] {
+ // Important, don't remove this! See IntMap for explanation.
+ override def equals(that : Any) = that match {
+ case _: this.type => true
+ case _: LongMap[_] => false // The only empty LongMaps are eq Nil
+ case _ => super.equals(that)
+ }
+ }
+
+ private[immutable] case class Tip[+T](key: Long, value: T) extends LongMap[T] {
+ def withValue[S](s: S) =
+ if (s.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef]) this.asInstanceOf[LongMap.Tip[S]]
+ else LongMap.Tip(key, s)
+ }
+
+ private[immutable] case class Bin[+T](prefix: Long, mask: Long, left: LongMap[T], right: LongMap[T]) extends LongMap[T] {
+ def bin[S](left: LongMap[S], right: LongMap[S]): LongMap[S] = {
+ if ((this.left eq left) && (this.right eq right)) this.asInstanceOf[LongMap.Bin[S]]
+ else LongMap.Bin[S](prefix, mask, left, right)
+ }
+ }
+
+ implicit def toFactory[V](dummy: LongMap.type): Factory[(Long, V), LongMap[V]] = ToFactory.asInstanceOf[Factory[(Long, V), LongMap[V]]]
+
+ @SerialVersionUID(3L)
+ private[this] object ToFactory extends Factory[(Long, AnyRef), LongMap[AnyRef]] with Serializable {
+ def fromSpecific(it: IterableOnce[(Long, AnyRef)]): LongMap[AnyRef] = LongMap.from[AnyRef](it)
+ def newBuilder: Builder[(Long, AnyRef), LongMap[AnyRef]] = LongMap.newBuilder[AnyRef]
+ }
+
+ implicit def toBuildFrom[V](factory: LongMap.type): BuildFrom[Any, (Long, V), LongMap[V]] = ToBuildFrom.asInstanceOf[BuildFrom[Any, (Long, V), LongMap[V]]]
+ private[this] object ToBuildFrom extends BuildFrom[Any, (Long, AnyRef), LongMap[AnyRef]] {
+ def fromSpecific(from: Any)(it: IterableOnce[(Long, AnyRef)]) = LongMap.from(it)
+ def newBuilder(from: Any) = LongMap.newBuilder[AnyRef]
+ }
+
+ implicit def iterableFactory[V]: Factory[(Long, V), LongMap[V]] = toFactory(this)
+ implicit def buildFromLongMap[V]: BuildFrom[LongMap[_], (Long, V), LongMap[V]] = toBuildFrom(this)
+}
+
+// Iterator over a non-empty LongMap.
+private[immutable] abstract class LongMapIterator[V, T](it: LongMap[V]) extends AbstractIterator[T] {
+
+ // Basically this uses a simple stack to emulate conversion over the tree. However
+ // because we know that Longs are only 64 bits we can have at most 64 LongMap.Bins and
+ // one LongMap.Tip sitting on the tree at any point. Therefore we know the maximum stack
+ // depth is 65
+ var index = 0
+ var buffer = new Array[AnyRef](65)
+
+ def pop() = {
+ index -= 1
+ buffer(index).asInstanceOf[LongMap[V]]
+ }
+
+ def push(x: LongMap[V]): Unit = {
+ buffer(index) = x.asInstanceOf[AnyRef]
+ index += 1
+ }
+ push(it)
+
+ /**
+ * What value do we assign to a tip?
+ */
+ def valueOf(tip: LongMap.Tip[V]): T
+
+ def hasNext = index != 0
+ @tailrec
+ final def next(): T =
+ pop() match {
+ case LongMap.Bin(_,_, t@LongMap.Tip(_, _), right) => {
+ push(right)
+ valueOf(t)
+ }
+ case LongMap.Bin(_, _, left, right) => {
+ push(right)
+ push(left)
+ next()
+ }
+ case t@LongMap.Tip(_, _) => valueOf(t)
+ // This should never happen. We don't allow LongMap.Nil in subtrees of the LongMap
+ // and don't return an LongMapIterator for LongMap.Nil.
+ case LongMap.Nil => throw new IllegalStateException("Empty maps not allowed as subtrees")
+ }
+}
+
+private[immutable] class LongMapEntryIterator[V](it: LongMap[V]) extends LongMapIterator[V, (Long, V)](it){
+ def valueOf(tip: LongMap.Tip[V]) = (tip.key, tip.value)
+}
+
+private[immutable] class LongMapValueIterator[V](it: LongMap[V]) extends LongMapIterator[V, V](it){
+ def valueOf(tip: LongMap.Tip[V]) = tip.value
+}
+
+private[immutable] class LongMapKeyIterator[V](it: LongMap[V]) extends LongMapIterator[V, Long](it){
+ def valueOf(tip: LongMap.Tip[V]) = tip.key
+}
+
+/**
+ * Specialised immutable map structure for long keys, based on
+ * [[https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.37.5452 Fast Mergeable Long Maps]]
+ * by Okasaki and Gill. Essentially a trie based on binary digits of the integers.
+ *
+ * Note: This class is as of 2.8 largely superseded by HashMap.
+ *
+ * @tparam T type of the values associated with the long keys.
+ *
+ * @define Coll `immutable.LongMap`
+ * @define coll immutable long integer map
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+sealed abstract class LongMap[+T] extends AbstractMap[Long, T]
+ with StrictOptimizedMapOps[Long, T, Map, LongMap[T]]
+ with Serializable {
+
+ override protected def fromSpecific(coll: scala.collection.IterableOnce[(Long, T)] @uncheckedVariance): LongMap[T] = {
+ //TODO should this be the default implementation of this method in StrictOptimizedIterableOps?
+ val b = newSpecificBuilder
+ b.sizeHint(coll)
+ b.addAll(coll)
+ b.result()
+ }
+ override protected def newSpecificBuilder: Builder[(Long, T), LongMap[T]] @uncheckedVariance =
+ new ImmutableBuilder[(Long, T), LongMap[T]](empty) {
+ def addOne(elem: (Long, T)): this.type = { elems = elems + elem; this }
+ }
+
+ override def empty: LongMap[T] = LongMap.Nil
+
+ override def toList = {
+ val buffer = new ListBuffer[(Long, T)]
+ foreach(buffer += _)
+ buffer.toList
+ }
+
+ /**
+ * Iterator over key, value pairs of the map in unsigned order of the keys.
+ *
+ * @return an iterator over pairs of long keys and corresponding values.
+ */
+ def iterator: Iterator[(Long, T)] = this match {
+ case LongMap.Nil => Iterator.empty
+ case _ => new LongMapEntryIterator(this)
+ }
+
+ /**
+ * Loops over the key, value pairs of the map in unsigned order of the keys.
+ */
+ override final def foreach[U](f: ((Long, T)) => U): Unit = this match {
+ case LongMap.Bin(_, _, left, right) => { left.foreach(f); right.foreach(f) }
+ case LongMap.Tip(key, value) => f((key, value))
+ case LongMap.Nil =>
+ }
+
+ override final def foreachEntry[U](f: (Long, T) => U): Unit = this match {
+ case LongMap.Bin(_, _, left, right) => { left.foreachEntry(f); right.foreachEntry(f) }
+ case LongMap.Tip(key, value) => f(key, value)
+ case LongMap.Nil =>
+ }
+
+ override def keysIterator: Iterator[Long] = this match {
+ case LongMap.Nil => Iterator.empty
+ case _ => new LongMapKeyIterator(this)
+ }
+
+ /**
+ * Loop over the keys of the map. The same as keys.foreach(f), but may
+ * be more efficient.
+ *
+ * @param f The loop body
+ */
+ final def foreachKey[U](f: Long => U): Unit = this match {
+ case LongMap.Bin(_, _, left, right) => { left.foreachKey(f); right.foreachKey(f) }
+ case LongMap.Tip(key, _) => f(key)
+ case LongMap.Nil =>
+ }
+
+ override def valuesIterator: Iterator[T] = this match {
+ case LongMap.Nil => Iterator.empty
+ case _ => new LongMapValueIterator(this)
+ }
+
+ /**
+ * Loop over the values of the map. The same as values.foreach(f), but may
+ * be more efficient.
+ *
+ * @param f The loop body
+ */
+ final def foreachValue[U](f: T => U): Unit = this match {
+ case LongMap.Bin(_, _, left, right) => { left.foreachValue(f); right.foreachValue(f) }
+ case LongMap.Tip(_, value) => f(value)
+ case LongMap.Nil =>
+ }
+
+ override protected[this] def className = "LongMap"
+
+ override def isEmpty = this eq LongMap.Nil
+ override def knownSize: Int = if (isEmpty) 0 else super.knownSize
+ override def filter(f: ((Long, T)) => Boolean): LongMap[T] = this match {
+ case LongMap.Bin(prefix, mask, left, right) => {
+ val (newleft, newright) = (left.filter(f), right.filter(f))
+ if ((left eq newleft) && (right eq newright)) this
+ else bin(prefix, mask, newleft, newright)
+ }
+ case LongMap.Tip(key, value) =>
+ if (f((key, value))) this
+ else LongMap.Nil
+ case LongMap.Nil => LongMap.Nil
+ }
+
+ override def transform[S](f: (Long, T) => S): LongMap[S] = this match {
+ case b@LongMap.Bin(prefix, mask, left, right) => b.bin(left.transform(f), right.transform(f))
+ case t@LongMap.Tip(key, value) => t.withValue(f(key, value))
+ case LongMap.Nil => LongMap.Nil
+ }
+
+ final override def size: Int = this match {
+ case LongMap.Nil => 0
+ case LongMap.Tip(_, _) => 1
+ case LongMap.Bin(_, _, left, right) => left.size + right.size
+ }
+
+ @tailrec
+ final def get(key: Long): Option[T] = this match {
+ case LongMap.Bin(prefix, mask, left, right) => if (zero(key, mask)) left.get(key) else right.get(key)
+ case LongMap.Tip(key2, value) => if (key == key2) Some(value) else None
+ case LongMap.Nil => None
+ }
+
+ @tailrec
+ final override def getOrElse[S >: T](key: Long, default: => S): S = this match {
+ case LongMap.Nil => default
+ case LongMap.Tip(key2, value) => if (key == key2) value else default
+ case LongMap.Bin(prefix, mask, left, right) =>
+ if (zero(key, mask)) left.getOrElse(key, default) else right.getOrElse(key, default)
+ }
+
+ @tailrec
+ final override def apply(key: Long): T = this match {
+ case LongMap.Bin(prefix, mask, left, right) => if (zero(key, mask)) left(key) else right(key)
+ case LongMap.Tip(key2, value) => if (key == key2) value else throw new IllegalArgumentException("Key not found")
+ case LongMap.Nil => throw new IllegalArgumentException("key not found")
+ }
+
+ override def + [S >: T] (kv: (Long, S)): LongMap[S] = updated(kv._1, kv._2)
+
+ override def updated[S >: T](key: Long, value: S): LongMap[S] = this match {
+ case LongMap.Bin(prefix, mask, left, right) =>
+ if (!hasMatch(key, prefix, mask)) join(key, LongMap.Tip(key, value), prefix, this)
+ else if (zero(key, mask)) LongMap.Bin(prefix, mask, left.updated(key, value), right)
+ else LongMap.Bin(prefix, mask, left, right.updated(key, value))
+ case LongMap.Tip(key2, value2) =>
+ if (key == key2) LongMap.Tip(key, value)
+ else join(key, LongMap.Tip(key, value), key2, this)
+ case LongMap.Nil => LongMap.Tip(key, value)
+ }
+
+ /**
+ * Updates the map, using the provided function to resolve conflicts if the key is already present.
+ *
+ * Equivalent to
+ * {{{
+ * this.get(key) match {
+ * case None => this.update(key, value)
+ * case Some(oldvalue) => this.update(key, f(oldvalue, value)
+ * }
+ * }}}
+ *
+ * @tparam S The supertype of values in this `LongMap`.
+ * @param key The key to update.
+ * @param value The value to use if there is no conflict.
+ * @param f The function used to resolve conflicts.
+ * @return The updated map.
+ */
+ def updateWith[S >: T](key: Long, value: S, f: (T, S) => S): LongMap[S] = this match {
+ case LongMap.Bin(prefix, mask, left, right) =>
+ if (!hasMatch(key, prefix, mask)) join(key, LongMap.Tip(key, value), prefix, this)
+ else if (zero(key, mask)) LongMap.Bin(prefix, mask, left.updateWith(key, value, f), right)
+ else LongMap.Bin(prefix, mask, left, right.updateWith(key, value, f))
+ case LongMap.Tip(key2, value2) =>
+ if (key == key2) LongMap.Tip(key, f(value2, value))
+ else join(key, LongMap.Tip(key, value), key2, this)
+ case LongMap.Nil => LongMap.Tip(key, value)
+ }
+
+ def removed(key: Long): LongMap[T] = this match {
+ case LongMap.Bin(prefix, mask, left, right) =>
+ if (!hasMatch(key, prefix, mask)) this
+ else if (zero(key, mask)) bin(prefix, mask, left - key, right)
+ else bin(prefix, mask, left, right - key)
+ case LongMap.Tip(key2, _) =>
+ if (key == key2) LongMap.Nil
+ else this
+ case LongMap.Nil => LongMap.Nil
+ }
+
+ /**
+ * A combined transform and filter function. Returns an `LongMap` such that
+ * for each `(key, value)` mapping in this map, if `f(key, value) == None`
+ * the map contains no mapping for key, and if `f(key, value)`.
+ *
+ * @tparam S The type of the values in the resulting `LongMap`.
+ * @param f The transforming function.
+ * @return The modified map.
+ */
+ def modifyOrRemove[S](f: (Long, T) => Option[S]): LongMap[S] = this match {
+ case LongMap.Bin(prefix, mask, left, right) => {
+ val newleft = left.modifyOrRemove(f)
+ val newright = right.modifyOrRemove(f)
+ if ((left eq newleft) && (right eq newright)) this.asInstanceOf[LongMap[S]]
+ else bin(prefix, mask, newleft, newright)
+ }
+ case LongMap.Tip(key, value) => f(key, value) match {
+ case None => LongMap.Nil
+ case Some(value2) =>
+ //hack to preserve sharing
+ if (value.asInstanceOf[AnyRef] eq value2.asInstanceOf[AnyRef]) this.asInstanceOf[LongMap[S]]
+ else LongMap.Tip(key, value2)
+ }
+ case LongMap.Nil => LongMap.Nil
+ }
+
+ /**
+ * Forms a union map with that map, using the combining function to resolve conflicts.
+ *
+ * @tparam S The type of values in `that`, a supertype of values in `this`.
+ * @param that The map to form a union with.
+ * @param f The function used to resolve conflicts between two mappings.
+ * @return Union of `this` and `that`, with identical key conflicts resolved using the function `f`.
+ */
+ def unionWith[S >: T](that: LongMap[S], f: (Long, S, S) => S): LongMap[S] = (this, that) match{
+ case (LongMap.Bin(p1, m1, l1, r1), that@(LongMap.Bin(p2, m2, l2, r2))) =>
+ if (shorter(m1, m2)) {
+ if (!hasMatch(p2, p1, m1)) join(p1, this, p2, that)
+ else if (zero(p2, m1)) LongMap.Bin(p1, m1, l1.unionWith(that, f), r1)
+ else LongMap.Bin(p1, m1, l1, r1.unionWith(that, f))
+ } else if (shorter(m2, m1)){
+ if (!hasMatch(p1, p2, m2)) join(p1, this, p2, that)
+ else if (zero(p1, m2)) LongMap.Bin(p2, m2, this.unionWith(l2, f), r2)
+ else LongMap.Bin(p2, m2, l2, this.unionWith(r2, f))
+ }
+ else {
+ if (p1 == p2) LongMap.Bin(p1, m1, l1.unionWith(l2,f), r1.unionWith(r2, f))
+ else join(p1, this, p2, that)
+ }
+ case (LongMap.Tip(key, value), x) => x.updateWith(key, value, (x, y) => f(key, y, x))
+ case (x, LongMap.Tip(key, value)) => x.updateWith[S](key, value, (x, y) => f(key, x, y))
+ case (LongMap.Nil, x) => x
+ case (x, LongMap.Nil) => x
+ }
+
+ /**
+ * Forms the intersection of these two maps with a combining function. The
+ * resulting map is a map that has only keys present in both maps and has
+ * values produced from the original mappings by combining them with `f`.
+ *
+ * @tparam S The type of values in `that`.
+ * @tparam R The type of values in the resulting `LongMap`.
+ * @param that The map to intersect with.
+ * @param f The combining function.
+ * @return Intersection of `this` and `that`, with values for identical keys produced by function `f`.
+ */
+ def intersectionWith[S, R](that: LongMap[S], f: (Long, T, S) => R): LongMap[R] = (this, that) match {
+ case (LongMap.Bin(p1, m1, l1, r1), that@LongMap.Bin(p2, m2, l2, r2)) =>
+ if (shorter(m1, m2)) {
+ if (!hasMatch(p2, p1, m1)) LongMap.Nil
+ else if (zero(p2, m1)) l1.intersectionWith(that, f)
+ else r1.intersectionWith(that, f)
+ } else if (m1 == m2) bin(p1, m1, l1.intersectionWith(l2, f), r1.intersectionWith(r2, f))
+ else {
+ if (!hasMatch(p1, p2, m2)) LongMap.Nil
+ else if (zero(p1, m2)) this.intersectionWith(l2, f)
+ else this.intersectionWith(r2, f)
+ }
+ case (LongMap.Tip(key, value), that) => that.get(key) match {
+ case None => LongMap.Nil
+ case Some(value2) => LongMap.Tip(key, f(key, value, value2))
+ }
+ case (_, LongMap.Tip(key, value)) => this.get(key) match {
+ case None => LongMap.Nil
+ case Some(value2) => LongMap.Tip(key, f(key, value2, value))
+ }
+ case (_, _) => LongMap.Nil
+ }
+
+ /**
+ * Left biased intersection. Returns the map that has all the same mappings as this but only for keys
+ * which are present in the other map.
+ *
+ * @tparam R The type of values in `that`.
+ * @param that The map to intersect with.
+ * @return A map with all the keys both in `this` and `that`, mapped to corresponding values from `this`.
+ */
+ def intersection[R](that: LongMap[R]): LongMap[T] =
+ this.intersectionWith(that, (key: Long, value: T, value2: R) => value)
+
+ def ++[S >: T](that: LongMap[S]) =
+ this.unionWith[S](that, (key, x, y) => y)
+
+ @tailrec
+ final def firstKey: Long = this match {
+ case LongMap.Bin(_, _, l, r) => l.firstKey
+ case LongMap.Tip(k, v) => k
+ case LongMap.Nil => throw new IllegalStateException("Empty set")
+ }
+
+ @tailrec
+ final def lastKey: Long = this match {
+ case LongMap.Bin(_, _, l, r) => r.lastKey
+ case LongMap.Tip(k , v) => k
+ case LongMap.Nil => throw new IllegalStateException("Empty set")
+ }
+
+ def map[V2](f: ((Long, T)) => (Long, V2)): LongMap[V2] = LongMap.from(new View.Map(coll, f))
+
+ def flatMap[V2](f: ((Long, T)) => IterableOnce[(Long, V2)]): LongMap[V2] = LongMap.from(new View.FlatMap(coll, f))
+
+ override def concat[V1 >: T](that: scala.collection.IterableOnce[(Long, V1)]): LongMap[V1] =
+ super.concat(that).asInstanceOf[LongMap[V1]] // Already has correct type but not declared as such
+
+ override def ++ [V1 >: T](that: scala.collection.IterableOnce[(Long, V1)]): LongMap[V1] = concat(that)
+
+ def collect[V2](pf: PartialFunction[(Long, T), (Long, V2)]): LongMap[V2] =
+ strictOptimizedCollect(LongMap.newBuilder[V2], pf)
+
+ protected[this] def writeReplace(): AnyRef = new DefaultSerializationProxy(LongMap.toFactory[T](LongMap), this)
+}
diff --git a/library/src/scala/collection/immutable/Map.scala b/library/src/scala/collection/immutable/Map.scala
new file mode 100644
index 000000000000..8f372312512e
--- /dev/null
+++ b/library/src/scala/collection/immutable/Map.scala
@@ -0,0 +1,712 @@
+/*
+ * 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 collection
+package immutable
+
+import scala.annotation.unchecked.uncheckedVariance
+import scala.collection.generic.DefaultSerializable
+import scala.collection.immutable.Map.Map4
+import scala.collection.mutable.{Builder, ReusableBuilder}
+import SeqMap.{SeqMap1, SeqMap2, SeqMap3, SeqMap4}
+
+/** Base type of immutable Maps */
+trait Map[K, +V]
+ extends Iterable[(K, V)]
+ with collection.Map[K, V]
+ with MapOps[K, V, Map, Map[K, V]]
+ with MapFactoryDefaults[K, V, Map, Iterable] {
+
+ override def mapFactory: scala.collection.MapFactory[Map] = Map
+
+ override final def toMap[K2, V2](implicit ev: (K, V) <:< (K2, V2)): Map[K2, V2] = Map.from(this.asInstanceOf[Map[K2, V2]])
+
+ /** The same map with a given default function.
+ * Note: The default is only used for `apply`. Other methods like `get`, `contains`, `iterator`, `keys`, etc.
+ * are not affected by `withDefault`.
+ *
+ * Invoking transformer methods (e.g. `map`) will not preserve the default value.
+ *
+ * @param d the function mapping keys to values, used for non-present keys
+ * @return a wrapper of the map with a default value
+ */
+ def withDefault[V1 >: V](d: K => V1): Map[K, V1] = new Map.WithDefault[K, V1](this, d)
+
+ /** The same map with a given default value.
+ * Note: The default is only used for `apply`. Other methods like `get`, `contains`, `iterator`, `keys`, etc.
+ * are not affected by `withDefaultValue`.
+ *
+ * Invoking transformer methods (e.g. `map`) will not preserve the default value.
+ *
+ * @param d default value used for non-present keys
+ * @return a wrapper of the map with a default value
+ */
+ def withDefaultValue[V1 >: V](d: V1): Map[K, V1] = new Map.WithDefault[K, V1](this, _ => d)
+}
+
+/** Base trait of immutable Maps implementations
+ *
+ * @define coll immutable map
+ * @define Coll `immutable.Map`
+ */
+trait MapOps[K, +V, +CC[X, +Y] <: MapOps[X, Y, CC, _], +C <: MapOps[K, V, CC, C]]
+ extends IterableOps[(K, V), Iterable, C]
+ with collection.MapOps[K, V, CC, C] {
+
+ protected def coll: C with CC[K, V]
+
+ /** Removes a key from this map, returning a new map.
+ *
+ * @param key the key to be removed
+ * @return a new map without a binding for ''key''
+ */
+ def removed(key: K): C
+
+ /** Alias for `removed` */
+ @`inline` final def - (key: K): C = removed(key)
+
+ @deprecated("Use -- with an explicit collection", "2.13.0")
+ def - (key1: K, key2: K, keys: K*): C = removed(key1).removed(key2).removedAll(keys)
+
+ /** Creates a new $coll from this $coll by removing all elements of another
+ * collection.
+ *
+ * $willForceEvaluation
+ *
+ * @param keys the collection containing the removed elements.
+ * @return a new $coll that contains all elements of the current $coll
+ * except one less occurrence of each of the elements of `elems`.
+ */
+ def removedAll(keys: IterableOnce[K]): C = keys.iterator.foldLeft[C](coll)(_ - _)
+
+ /** Alias for `removedAll` */
+ @`inline` final override def -- (keys: IterableOnce[K]): C = removedAll(keys)
+
+ /** Creates a new map obtained by updating this map with a given key/value pair.
+ * @param key the key
+ * @param value the value
+ * @tparam V1 the type of the added value
+ * @return A new map with the new key/value mapping added to this map.
+ */
+ def updated[V1 >: V](key: K, value: V1): CC[K, V1]
+
+ /**
+ * Update a mapping for the specified key and its current optionally mapped value
+ * (`Some` if there is current mapping, `None` if not).
+ *
+ * If the remapping function returns `Some(v)`, the mapping is updated with the new value `v`.
+ * If the remapping function returns `None`, the mapping is removed (or remains absent if initially absent).
+ * If the function itself throws an exception, the exception is rethrown, and the current mapping is left unchanged.
+ *
+ * @param key the key value
+ * @param remappingFunction a function that receives current optionally mapped value and return a new mapping
+ * @return A new map with the updated mapping with the key
+ */
+ def updatedWith[V1 >: V](key: K)(remappingFunction: Option[V] => Option[V1]): CC[K,V1] = {
+ val previousValue = this.get(key)
+ remappingFunction(previousValue) match {
+ case None => previousValue.fold(coll)(_ => this.removed(key).coll)
+ case Some(nextValue) =>
+ if (previousValue.exists(_.asInstanceOf[AnyRef] eq nextValue.asInstanceOf[AnyRef])) coll
+ else coll.updated(key, nextValue)
+ }
+ }
+
+ /**
+ * Alias for `updated`
+ *
+ * @param kv the key/value pair.
+ * @tparam V1 the type of the value in the key/value pair.
+ * @return A new map with the new binding added to this map.
+ */
+ override def + [V1 >: V](kv: (K, V1)): CC[K, V1] = updated(kv._1, kv._2)
+
+ /** This function transforms all the values of mappings contained
+ * in this map with function `f`.
+ *
+ * @param f A function over keys and values
+ * @return the updated map
+ */
+ def transform[W](f: (K, V) => W): CC[K, W] = map { case (k, v) => (k, f(k, v)) }
+
+ override def keySet: Set[K] = new ImmutableKeySet
+
+ /** The implementation class of the set returned by `keySet` */
+ protected[immutable] class ImmutableKeySet extends AbstractSet[K] with GenKeySet with DefaultSerializable {
+ def incl(elem: K): Set[K] = if (this(elem)) this else empty ++ this + elem
+ def excl(elem: K): Set[K] = if (this(elem)) empty ++ this - elem else this
+ }
+
+}
+
+trait StrictOptimizedMapOps[K, +V, +CC[X, +Y] <: MapOps[X, Y, CC, _], +C <: MapOps[K, V, CC, C]]
+ extends MapOps[K, V, CC, C]
+ with collection.StrictOptimizedMapOps[K, V, CC, C]
+ with StrictOptimizedIterableOps[(K, V), Iterable, C] {
+
+ override def concat [V1 >: V](that: collection.IterableOnce[(K, V1)]): CC[K, V1] = {
+ var result: CC[K, V1] = coll
+ val it = that.iterator
+ while (it.hasNext) result = result + it.next()
+ result
+ }
+}
+
+
+/**
+ * $factoryInfo
+ * @define coll immutable map
+ * @define Coll `immutable.Map`
+ */
+@SerialVersionUID(3L)
+object Map extends MapFactory[Map] {
+
+ @SerialVersionUID(3L)
+ class WithDefault[K, +V](val underlying: Map[K, V], val defaultValue: K => V)
+ extends AbstractMap[K, V]
+ with MapOps[K, V, Map, WithDefault[K, V]] with Serializable {
+
+ def get(key: K): Option[V] = underlying.get(key)
+
+ override def default(key: K): V = defaultValue(key)
+
+ override def iterableFactory: IterableFactory[Iterable] = underlying.iterableFactory
+
+ def iterator: Iterator[(K, V)] = underlying.iterator
+
+ override def isEmpty: Boolean = underlying.isEmpty
+
+ override def mapFactory: MapFactory[Map] = underlying.mapFactory
+
+ override def concat [V2 >: V](xs: collection.IterableOnce[(K, V2)]): WithDefault[K, V2] =
+ new WithDefault(underlying.concat(xs), defaultValue)
+
+ def removed(key: K): WithDefault[K, V] = new WithDefault[K, V](underlying.removed(key), defaultValue)
+
+ def updated[V1 >: V](key: K, value: V1): WithDefault[K, V1] =
+ new WithDefault[K, V1](underlying.updated(key, value), defaultValue)
+
+ override def empty: WithDefault[K, V] = new WithDefault[K, V](underlying.empty, defaultValue)
+
+ override protected def fromSpecific(coll: collection.IterableOnce[(K, V)] @uncheckedVariance): WithDefault[K, V] =
+ new WithDefault[K, V](mapFactory.from(coll), defaultValue)
+
+ override protected def newSpecificBuilder: Builder[(K, V), WithDefault[K, V]] @uncheckedVariance =
+ Map.newBuilder.mapResult((p: Map[K, V]) => new WithDefault[K, V](p, defaultValue))
+ }
+
+ def empty[K, V]: Map[K, V] = EmptyMap.asInstanceOf[Map[K, V]]
+
+ def from[K, V](it: IterableOnce[(K, V)]): Map[K, V] =
+ it match {
+ case it: Iterable[_] if it.isEmpty => empty[K, V]
+ // Since IterableOnce[(K, V)] launders the variance of K,
+ // identify only our implementations which can be soundly substituted.
+ // For example, the ordering used by sorted maps would fail on widened key type. (scala/bug#12745)
+ // The following type test is not sufficient: case m: Map[K, V] => m
+ case m: HashMap[K, V] => m
+ case m: Map1[K, V] => m
+ case m: Map2[K, V] => m
+ case m: Map3[K, V] => m
+ case m: Map4[K, V] => m
+ //case m: WithDefault[K, V] => m // cf SortedMap.WithDefault
+ //case m: SeqMap[K, V] => SeqMap.from(it) // inlined here to avoid hard dependency
+ case m: ListMap[K, V] => m
+ case m: TreeSeqMap[K, V] => m
+ case m: VectorMap[K, V] => m
+ case m: SeqMap1[K, V] => m
+ case m: SeqMap2[K, V] => m
+ case m: SeqMap3[K, V] => m
+ case m: SeqMap4[K, V] => m
+
+ // Maps with a reified key type must be rebuilt, such as `SortedMap` and `IntMap`.
+ case _ => newBuilder[K, V].addAll(it).result()
+ }
+
+ def newBuilder[K, V]: Builder[(K, V), Map[K, V]] = new MapBuilderImpl
+
+ @SerialVersionUID(3L)
+ private object EmptyMap extends AbstractMap[Any, Nothing] with Serializable {
+ override def size: Int = 0
+ override def knownSize: Int = 0
+ override def isEmpty: Boolean = true
+ override def apply(key: Any) = throw new NoSuchElementException("key not found: " + key)
+ override def contains(key: Any) = false
+ def get(key: Any): Option[Nothing] = None
+ override def getOrElse [V1](key: Any, default: => V1): V1 = default
+ def iterator: Iterator[(Any, Nothing)] = Iterator.empty
+ override def keysIterator: Iterator[Any] = Iterator.empty
+ override def valuesIterator: Iterator[Nothing] = Iterator.empty
+ def updated [V1] (key: Any, value: V1): Map[Any, V1] = new Map1(key, value)
+ def removed(key: Any): Map[Any, Nothing] = this
+ override def concat[V2 >: Nothing](suffix: IterableOnce[(Any, V2)]): Map[Any, V2] = suffix match {
+ case m: immutable.Map[Any, V2] => m
+ case _ => super.concat(suffix)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ final class Map1[K, +V](key1: K, value1: V) extends AbstractMap[K, V] with StrictOptimizedIterableOps[(K, V), Iterable, Map[K, V]] with Serializable {
+ override def size: Int = 1
+ override def knownSize: Int = 1
+ override def isEmpty: Boolean = false
+ override def apply(key: K): V = if (key == key1) value1 else throw new NoSuchElementException("key not found: " + key)
+ override def contains(key: K): Boolean = key == key1
+ def get(key: K): Option[V] =
+ if (key == key1) Some(value1) else None
+ override def getOrElse [V1 >: V](key: K, default: => V1): V1 =
+ if (key == key1) value1 else default
+ def iterator: Iterator[(K, V)] = Iterator.single((key1, value1))
+ override def keysIterator: Iterator[K] = Iterator.single(key1)
+ override def valuesIterator: Iterator[V] = Iterator.single(value1)
+ def updated[V1 >: V](key: K, value: V1): Map[K, V1] =
+ if (key == key1) new Map1(key1, value)
+ else new Map2(key1, value1, key, value)
+ def removed(key: K): Map[K, V] =
+ if (key == key1) Map.empty else this
+ override def foreach[U](f: ((K, V)) => U): Unit = {
+ f((key1, value1))
+ }
+ override def exists(p: ((K, V)) => Boolean): Boolean = p((key1, value1))
+ override def forall(p: ((K, V)) => Boolean): Boolean = p((key1, value1))
+ override protected[collection] def filterImpl(pred: ((K, V)) => Boolean, isFlipped: Boolean): Map[K, V] =
+ if (pred((key1, value1)) != isFlipped) this else Map.empty
+ override def transform[W](f: (K, V) => W): Map[K, W] = {
+ val walue1 = f(key1, value1)
+ if (walue1.asInstanceOf[AnyRef] eq value1.asInstanceOf[AnyRef]) this.asInstanceOf[Map[K, W]]
+ else new Map1(key1, walue1)
+ }
+ override def hashCode(): Int = {
+ import scala.util.hashing.MurmurHash3
+ var a, b = 0
+ val N = 1
+ var c = 1
+
+ var h = MurmurHash3.tuple2Hash(key1, value1)
+ a += h
+ b ^= h
+ c *= h | 1
+
+ h = MurmurHash3.mapSeed
+ h = MurmurHash3.mix(h, a)
+ h = MurmurHash3.mix(h, b)
+ h = MurmurHash3.mixLast(h, c)
+ MurmurHash3.finalizeHash(h, N)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ final class Map2[K, +V](key1: K, value1: V, key2: K, value2: V) extends AbstractMap[K, V] with StrictOptimizedIterableOps[(K, V), Iterable, Map[K, V]] with Serializable {
+ override def size: Int = 2
+ override def knownSize: Int = 2
+ override def isEmpty: Boolean = false
+ override def apply(key: K): V =
+ if (key == key1) value1
+ else if (key == key2) value2
+ else throw new NoSuchElementException("key not found: " + key)
+ override def contains(key: K): Boolean = (key == key1) || (key == key2)
+ def get(key: K): Option[V] =
+ if (key == key1) Some(value1)
+ else if (key == key2) Some(value2)
+ else None
+ override def getOrElse [V1 >: V](key: K, default: => V1): V1 =
+ if (key == key1) value1
+ else if (key == key2) value2
+ else default
+ def iterator: Iterator[(K, V)] = new Map2Iterator[(K, V)] {
+ override protected def nextResult(k: K, v: V): (K, V) = (k, v)
+ }
+ override def keysIterator: Iterator[K] = new Map2Iterator[K] {
+ override protected def nextResult(k: K, v: V): K = k
+ }
+ override def valuesIterator: Iterator[V] = new Map2Iterator[V] {
+ override protected def nextResult(k: K, v: V): V = v
+ }
+
+ private abstract class Map2Iterator[A] extends AbstractIterator[A] {
+ private[this] var i = 0
+ override def hasNext: Boolean = i < 2
+ override def next(): A = {
+ val result = i match {
+ case 0 => nextResult(key1, value1)
+ case 1 => nextResult(key2, value2)
+ case _ => Iterator.empty.next()
+ }
+ i += 1
+ result
+ }
+ override def drop(n: Int): Iterator[A] = { i += n; this }
+ protected def nextResult(k: K, v: V @uncheckedVariance): A
+ }
+ def updated[V1 >: V](key: K, value: V1): Map[K, V1] =
+ if (key == key1) new Map2(key1, value, key2, value2)
+ else if (key == key2) new Map2(key1, value1, key2, value)
+ else new Map3(key1, value1, key2, value2, key, value)
+ def removed(key: K): Map[K, V] =
+ if (key == key1) new Map1(key2, value2)
+ else if (key == key2) new Map1(key1, value1)
+ else this
+ override def foreach[U](f: ((K, V)) => U): Unit = {
+ f((key1, value1)); f((key2, value2))
+ }
+ override def exists(p: ((K, V)) => Boolean): Boolean = p((key1, value1)) || p((key2, value2))
+ override def forall(p: ((K, V)) => Boolean): Boolean = p((key1, value1)) && p((key2, value2))
+ override protected[collection] def filterImpl(pred: ((K, V)) => Boolean, isFlipped: Boolean): Map[K, V] = {
+ var k1 = null.asInstanceOf[K]
+ var v1 = null.asInstanceOf[V]
+ var n = 0
+ if (pred((key1, value1)) != isFlipped) { {k1 = key1; v1 = value1}; n += 1}
+ if (pred((key2, value2)) != isFlipped) { if (n == 0) {k1 = key2; v1 = value2}; n += 1}
+
+ n match {
+ case 0 => Map.empty
+ case 1 => new Map1(k1, v1)
+ case 2 => this
+ }
+ }
+ override def transform[W](f: (K, V) => W): Map[K, W] = {
+ val walue1 = f(key1, value1)
+ val walue2 = f(key2, value2)
+ if ((walue1.asInstanceOf[AnyRef] eq value1.asInstanceOf[AnyRef]) &&
+ (walue2.asInstanceOf[AnyRef] eq value2.asInstanceOf[AnyRef])) this.asInstanceOf[Map[K, W]]
+ else new Map2(key1, walue1, key2, walue2)
+ }
+ override def hashCode(): Int = {
+ import scala.util.hashing.MurmurHash3
+ var a, b = 0
+ val N = 2
+ var c = 1
+
+ var h = MurmurHash3.tuple2Hash(key1, value1)
+ a += h
+ b ^= h
+ c *= h | 1
+
+ h = MurmurHash3.tuple2Hash(key2, value2)
+ a += h
+ b ^= h
+ c *= h | 1
+
+ h = MurmurHash3.mapSeed
+ h = MurmurHash3.mix(h, a)
+ h = MurmurHash3.mix(h, b)
+ h = MurmurHash3.mixLast(h, c)
+ MurmurHash3.finalizeHash(h, N)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ class Map3[K, +V](key1: K, value1: V, key2: K, value2: V, key3: K, value3: V) extends AbstractMap[K, V] with StrictOptimizedIterableOps[(K, V), Iterable, Map[K, V]] with Serializable {
+ override def size: Int = 3
+ override def knownSize: Int = 3
+ override def isEmpty: Boolean = false
+ override def apply(key: K): V =
+ if (key == key1) value1
+ else if (key == key2) value2
+ else if (key == key3) value3
+ else throw new NoSuchElementException("key not found: " + key)
+ override def contains(key: K): Boolean = (key == key1) || (key == key2) || (key == key3)
+ def get(key: K): Option[V] =
+ if (key == key1) Some(value1)
+ else if (key == key2) Some(value2)
+ else if (key == key3) Some(value3)
+ else None
+ override def getOrElse [V1 >: V](key: K, default: => V1): V1 =
+ if (key == key1) value1
+ else if (key == key2) value2
+ else if (key == key3) value3
+ else default
+ def iterator: Iterator[(K, V)] = new Map3Iterator[(K, V)] {
+ override protected def nextResult(k: K, v: V): (K, V) = (k, v)
+ }
+ override def keysIterator: Iterator[K] = new Map3Iterator[K] {
+ override protected def nextResult(k: K, v: V): K = k
+ }
+ override def valuesIterator: Iterator[V] = new Map3Iterator[V] {
+ override protected def nextResult(k: K, v: V): V = v
+ }
+
+ private abstract class Map3Iterator[A] extends AbstractIterator[A] {
+ private[this] var i = 0
+ override def hasNext: Boolean = i < 3
+ override def next(): A = {
+ val result = i match {
+ case 0 => nextResult(key1, value1)
+ case 1 => nextResult(key2, value2)
+ case 2 => nextResult(key3, value3)
+ case _ => Iterator.empty.next()
+ }
+ i += 1
+ result
+ }
+ override def drop(n: Int): Iterator[A] = { i += n; this }
+ protected def nextResult(k: K, v: V @uncheckedVariance): A
+ }
+ def updated[V1 >: V](key: K, value: V1): Map[K, V1] =
+ if (key == key1) new Map3(key1, value, key2, value2, key3, value3)
+ else if (key == key2) new Map3(key1, value1, key2, value, key3, value3)
+ else if (key == key3) new Map3(key1, value1, key2, value2, key3, value)
+ else new Map4(key1, value1, key2, value2, key3, value3, key, value)
+ def removed(key: K): Map[K, V] =
+ if (key == key1) new Map2(key2, value2, key3, value3)
+ else if (key == key2) new Map2(key1, value1, key3, value3)
+ else if (key == key3) new Map2(key1, value1, key2, value2)
+ else this
+ override def foreach[U](f: ((K, V)) => U): Unit = {
+ f((key1, value1)); f((key2, value2)); f((key3, value3))
+ }
+ override def exists(p: ((K, V)) => Boolean): Boolean = p((key1, value1)) || p((key2, value2)) || p((key3, value3))
+ override def forall(p: ((K, V)) => Boolean): Boolean = p((key1, value1)) && p((key2, value2)) && p((key3, value3))
+ override protected[collection] def filterImpl(pred: ((K, V)) => Boolean, isFlipped: Boolean): Map[K, V] = {
+ var k1, k2 = null.asInstanceOf[K]
+ var v1, v2 = null.asInstanceOf[V]
+ var n = 0
+ if (pred((key1, value1)) != isFlipped) { { k1 = key1; v1 = value1 }; n += 1}
+ if (pred((key2, value2)) != isFlipped) { if (n == 0) { k1 = key2; v1 = value2 } else { k2 = key2; v2 = value2 }; n += 1}
+ if (pred((key3, value3)) != isFlipped) { if (n == 0) { k1 = key3; v1 = value3 } else if (n == 1) { k2 = key3; v2 = value3 }; n += 1}
+
+ n match {
+ case 0 => Map.empty
+ case 1 => new Map1(k1, v1)
+ case 2 => new Map2(k1, v1, k2, v2)
+ case 3 => this
+ }
+ }
+ override def transform[W](f: (K, V) => W): Map[K, W] = {
+ val walue1 = f(key1, value1)
+ val walue2 = f(key2, value2)
+ val walue3 = f(key3, value3)
+ if ((walue1.asInstanceOf[AnyRef] eq value1.asInstanceOf[AnyRef]) &&
+ (walue2.asInstanceOf[AnyRef] eq value2.asInstanceOf[AnyRef]) &&
+ (walue3.asInstanceOf[AnyRef] eq value3.asInstanceOf[AnyRef])) this.asInstanceOf[Map[K, W]]
+ else new Map3(key1, walue1, key2, walue2, key3, walue3)
+ }
+ override def hashCode(): Int = {
+ import scala.util.hashing.MurmurHash3
+ var a, b = 0
+ val N = 3
+ var c = 1
+
+ var h = MurmurHash3.tuple2Hash(key1, value1)
+ a += h
+ b ^= h
+ c *= h | 1
+
+ h = MurmurHash3.tuple2Hash(key2, value2)
+ a += h
+ b ^= h
+ c *= h | 1
+
+ h = MurmurHash3.tuple2Hash(key3, value3)
+ a += h
+ b ^= h
+ c *= h | 1
+
+ h = MurmurHash3.mapSeed
+ h = MurmurHash3.mix(h, a)
+ h = MurmurHash3.mix(h, b)
+ h = MurmurHash3.mixLast(h, c)
+ MurmurHash3.finalizeHash(h, N)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ final class Map4[K, +V](key1: K, value1: V, key2: K, value2: V, key3: K, value3: V, key4: K, value4: V)
+ extends AbstractMap[K, V] with StrictOptimizedIterableOps[(K, V), Iterable, Map[K, V]] with Serializable {
+
+ override def size: Int = 4
+ override def knownSize: Int = 4
+ override def isEmpty: Boolean = false
+ override def apply(key: K): V =
+ if (key == key1) value1
+ else if (key == key2) value2
+ else if (key == key3) value3
+ else if (key == key4) value4
+ else throw new NoSuchElementException("key not found: " + key)
+ override def contains(key: K): Boolean = (key == key1) || (key == key2) || (key == key3) || (key == key4)
+ def get(key: K): Option[V] =
+ if (key == key1) Some(value1)
+ else if (key == key2) Some(value2)
+ else if (key == key3) Some(value3)
+ else if (key == key4) Some(value4)
+ else None
+ override def getOrElse [V1 >: V](key: K, default: => V1): V1 =
+ if (key == key1) value1
+ else if (key == key2) value2
+ else if (key == key3) value3
+ else if (key == key4) value4
+ else default
+ def iterator: Iterator[(K, V)] = new Map4Iterator[(K, V)] {
+ override protected def nextResult(k: K, v: V): (K, V) = (k, v)
+ }
+ override def keysIterator: Iterator[K] = new Map4Iterator[K] {
+ override protected def nextResult(k: K, v: V): K = k
+ }
+ override def valuesIterator: Iterator[V] = new Map4Iterator[V] {
+ override protected def nextResult(k: K, v: V): V = v
+ }
+
+ private abstract class Map4Iterator[A] extends AbstractIterator[A] {
+ private[this] var i = 0
+ override def hasNext: Boolean = i < 4
+ override def next(): A = {
+ val result = i match {
+ case 0 => nextResult(key1, value1)
+ case 1 => nextResult(key2, value2)
+ case 2 => nextResult(key3, value3)
+ case 3 => nextResult(key4, value4)
+ case _ => Iterator.empty.next()
+ }
+ i += 1
+ result
+ }
+ override def drop(n: Int): Iterator[A] = { i += n; this }
+ protected def nextResult(k: K, v: V @uncheckedVariance): A
+ }
+ def updated[V1 >: V](key: K, value: V1): Map[K, V1] =
+ if (key == key1) new Map4(key1, value, key2, value2, key3, value3, key4, value4)
+ else if (key == key2) new Map4(key1, value1, key2, value, key3, value3, key4, value4)
+ else if (key == key3) new Map4(key1, value1, key2, value2, key3, value, key4, value4)
+ else if (key == key4) new Map4(key1, value1, key2, value2, key3, value3, key4, value)
+ else HashMap.empty[K, V1].updated(key1,value1).updated(key2, value2).updated(key3, value3).updated(key4, value4).updated(key, value)
+ def removed(key: K): Map[K, V] =
+ if (key == key1) new Map3(key2, value2, key3, value3, key4, value4)
+ else if (key == key2) new Map3(key1, value1, key3, value3, key4, value4)
+ else if (key == key3) new Map3(key1, value1, key2, value2, key4, value4)
+ else if (key == key4) new Map3(key1, value1, key2, value2, key3, value3)
+ else this
+ override def foreach[U](f: ((K, V)) => U): Unit = {
+ f((key1, value1)); f((key2, value2)); f((key3, value3)); f((key4, value4))
+ }
+ override def exists(p: ((K, V)) => Boolean): Boolean = p((key1, value1)) || p((key2, value2)) || p((key3, value3)) || p((key4, value4))
+ override def forall(p: ((K, V)) => Boolean): Boolean = p((key1, value1)) && p((key2, value2)) && p((key3, value3)) && p((key4, value4))
+ override protected[collection] def filterImpl(pred: ((K, V)) => Boolean, isFlipped: Boolean): Map[K, V] = {
+ var k1, k2, k3 = null.asInstanceOf[K]
+ var v1, v2, v3 = null.asInstanceOf[V]
+ var n = 0
+ if (pred((key1, value1)) != isFlipped) { { k1 = key1; v1 = value1 }; n += 1}
+ if (pred((key2, value2)) != isFlipped) { if (n == 0) { k1 = key2; v1 = value2 } else { k2 = key2; v2 = value2 }; n += 1}
+ if (pred((key3, value3)) != isFlipped) { if (n == 0) { k1 = key3; v1 = value3 } else if (n == 1) { k2 = key3; v2 = value3 } else { k3 = key3; v3 = value3}; n += 1}
+ if (pred((key4, value4)) != isFlipped) { if (n == 0) { k1 = key4; v1 = value4 } else if (n == 1) { k2 = key4; v2 = value4 } else if (n == 2) { k3 = key4; v3 = value4 }; n += 1}
+
+ n match {
+ case 0 => Map.empty
+ case 1 => new Map1(k1, v1)
+ case 2 => new Map2(k1, v1, k2, v2)
+ case 3 => new Map3(k1, v1, k2, v2, k3, v3)
+ case 4 => this
+ }
+ }
+ override def transform[W](f: (K, V) => W): Map[K, W] = {
+ val walue1 = f(key1, value1)
+ val walue2 = f(key2, value2)
+ val walue3 = f(key3, value3)
+ val walue4 = f(key4, value4)
+ if ((walue1.asInstanceOf[AnyRef] eq value1.asInstanceOf[AnyRef]) &&
+ (walue2.asInstanceOf[AnyRef] eq value2.asInstanceOf[AnyRef]) &&
+ (walue3.asInstanceOf[AnyRef] eq value3.asInstanceOf[AnyRef]) &&
+ (walue4.asInstanceOf[AnyRef] eq value4.asInstanceOf[AnyRef])) this.asInstanceOf[Map[K, W]]
+ else new Map4(key1, walue1, key2, walue2, key3, walue3, key4, walue4)
+ }
+ private[immutable] def buildTo[V1 >: V](builder: HashMapBuilder[K, V1]): builder.type =
+ builder.addOne(key1, value1).addOne(key2, value2).addOne(key3, value3).addOne(key4, value4)
+ override def hashCode(): Int = {
+ import scala.util.hashing.MurmurHash3
+ var a, b = 0
+ val N = 4
+ var c = 1
+
+ var h = MurmurHash3.tuple2Hash(key1, value1)
+ a += h
+ b ^= h
+ c *= h | 1
+
+ h = MurmurHash3.tuple2Hash(key2, value2)
+ a += h
+ b ^= h
+ c *= h | 1
+
+ h = MurmurHash3.tuple2Hash(key3, value3)
+ a += h
+ b ^= h
+ c *= h | 1
+
+ h = MurmurHash3.tuple2Hash(key4, value4)
+ a += h
+ b ^= h
+ c *= h | 1
+
+ h = MurmurHash3.mapSeed
+ h = MurmurHash3.mix(h, a)
+ h = MurmurHash3.mix(h, b)
+ h = MurmurHash3.mixLast(h, c)
+ MurmurHash3.finalizeHash(h, N)
+ }
+ }
+}
+
+/** Explicit instantiation of the `Map` trait to reduce class file size in subclasses. */
+abstract class AbstractMap[K, +V] extends scala.collection.AbstractMap[K, V] with Map[K, V]
+
+private[immutable] final class MapBuilderImpl[K, V] extends ReusableBuilder[(K, V), Map[K, V]] {
+ private[this] var elems: Map[K, V] = Map.empty
+ private[this] var switchedToHashMapBuilder: Boolean = false
+ private[this] var hashMapBuilder: HashMapBuilder[K, V] = _
+
+ private[immutable] def getOrElse[V0 >: V](key: K, value: V0): V0 =
+ if (hashMapBuilder ne null) hashMapBuilder.getOrElse(key, value)
+ else elems.getOrElse(key, value)
+
+ override def clear(): Unit = {
+ elems = Map.empty
+ if (hashMapBuilder != null) {
+ hashMapBuilder.clear()
+ }
+ switchedToHashMapBuilder = false
+ }
+
+ override def result(): Map[K, V] =
+ if (switchedToHashMapBuilder) hashMapBuilder.result() else elems
+
+ def addOne(key: K, value: V): this.type = {
+ if (switchedToHashMapBuilder) {
+ hashMapBuilder.addOne(key, value)
+ } else if (elems.size < 4) {
+ elems = elems.updated(key, value)
+ } else {
+ // assert(elems.size == 4)
+ if (elems.contains(key)) {
+ elems = elems.updated(key, value)
+ } else {
+ switchedToHashMapBuilder = true
+ if (hashMapBuilder == null) {
+ hashMapBuilder = new HashMapBuilder
+ }
+ elems.asInstanceOf[Map4[K, V]].buildTo(hashMapBuilder)
+ hashMapBuilder.addOne(key, value)
+ }
+ }
+
+ this
+ }
+
+ def addOne(elem: (K, V)) = addOne(elem._1, elem._2)
+
+ override def addAll(xs: IterableOnce[(K, V)]): this.type =
+ if (switchedToHashMapBuilder) {
+ hashMapBuilder.addAll(xs)
+ this
+ } else {
+ super.addAll(xs)
+ }
+}
diff --git a/library/src/scala/collection/immutable/NumericRange.scala b/library/src/scala/collection/immutable/NumericRange.scala
new file mode 100644
index 000000000000..78efb2adafca
--- /dev/null
+++ b/library/src/scala/collection/immutable/NumericRange.scala
@@ -0,0 +1,541 @@
+/*
+ * 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.immutable
+
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.{AbstractIterator, AnyStepper, IterableFactoryDefaults, Iterator, Stepper, StepperShape}
+import scala.collection.generic.CommonErrors
+
+/** `NumericRange` is a more generic version of the
+ * `Range` class which works with arbitrary types.
+ * It must be supplied with an `Integral` implementation of the
+ * range type.
+ *
+ * Factories for likely types include `Range.BigInt`, `Range.Long`,
+ * and `Range.BigDecimal`. `Range.Int` exists for completeness, but
+ * the `Int`-based `scala.Range` should be more performant.
+ *
+ * {{{
+ * val r1 = Range(0, 100, 1)
+ * val veryBig = Int.MaxValue.toLong + 1
+ * val r2 = Range.Long(veryBig, veryBig + 100, 1)
+ * assert(r1 sameElements r2.map(_ - veryBig))
+ * }}}
+ *
+ * @define Coll `NumericRange`
+ * @define coll numeric range
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+@SerialVersionUID(3L)
+sealed class NumericRange[T](
+ val start: T,
+ val end: T,
+ val step: T,
+ val isInclusive: Boolean
+)(implicit
+ num: Integral[T]
+)
+ extends AbstractSeq[T]
+ with IndexedSeq[T]
+ with IndexedSeqOps[T, IndexedSeq, IndexedSeq[T]]
+ with StrictOptimizedSeqOps[T, IndexedSeq, IndexedSeq[T]]
+ with IterableFactoryDefaults[T, IndexedSeq]
+ with Serializable { self =>
+
+ override def iterator: Iterator[T] = new NumericRange.NumericRangeIterator(this, num)
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[T, S]): S with EfficientSplit = {
+ import scala.collection.convert._
+ import impl._
+ val s = shape.shape match {
+ case StepperShape.IntShape => new IntNumericRangeStepper (this.asInstanceOf[NumericRange[Int]], 0, length)
+ case StepperShape.LongShape => new LongNumericRangeStepper (this.asInstanceOf[NumericRange[Long]], 0, length)
+ case _ => shape.parUnbox(new AnyNumericRangeStepper[T](this, 0, length).asInstanceOf[AnyStepper[T] with EfficientSplit])
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+
+ /** Note that NumericRange must be invariant so that constructs
+ * such as "1L to 10 by 5" do not infer the range type as AnyVal.
+ */
+ import num._
+
+ // See comment in Range for why this must be lazy.
+ override lazy val length: Int = NumericRange.count(start, end, step, isInclusive)
+ override lazy val isEmpty: Boolean = (
+ (num.gt(start, end) && num.gt(step, num.zero))
+ || (num.lt(start, end) && num.lt(step, num.zero))
+ || (num.equiv(start, end) && !isInclusive)
+ )
+ override def last: T =
+ if (isEmpty) Nil.head
+ else locationAfterN(length - 1)
+ override def init: NumericRange[T] =
+ if (isEmpty) Nil.init
+ else new NumericRange(start, end - step, step, isInclusive)
+
+ override def head: T = if (isEmpty) Nil.head else start
+ override def tail: NumericRange[T] =
+ if (isEmpty) Nil.tail
+ else if(isInclusive) new NumericRange.Inclusive(start + step, end, step)
+ else new NumericRange.Exclusive(start + step, end, step)
+
+ /** Create a new range with the start and end values of this range and
+ * a new `step`.
+ */
+ def by(newStep: T): NumericRange[T] = copy(start, end, newStep)
+
+
+ /** Create a copy of this range.
+ */
+ def copy(start: T, end: T, step: T): NumericRange[T] =
+ new NumericRange(start, end, step, isInclusive)
+
+ @throws[IndexOutOfBoundsException]
+ def apply(idx: Int): T = {
+ if (idx < 0 || idx >= length)
+ throw CommonErrors.indexOutOfBounds(index = idx, max = length - 1)
+ else locationAfterN(idx)
+ }
+
+ override def foreach[@specialized(Specializable.Unit) U](f: T => U): Unit = {
+ var count = 0
+ var current = start
+ while (count < length) {
+ f(current)
+ current += step
+ count += 1
+ }
+ }
+
+ private[this] def indexOfTyped(elem: T, from: Int): Int =
+ posOf(elem) match {
+ case pos if pos >= from => pos
+ case _ => -1
+ }
+
+ final override def indexOf[B >: T](elem: B, from: Int): Int =
+ try indexOfTyped(elem.asInstanceOf[T], from)
+ catch { case _: ClassCastException => super.indexOf(elem, from) }
+
+ private[this] def lastIndexOfTyped(elem: T, end: Int): Int =
+ posOf(elem) match {
+ case pos if pos <= end => pos
+ case _ => -1
+ }
+
+ final override def lastIndexOf[B >: T](elem: B, end: Int = length - 1): Int =
+ try lastIndexOfTyped(elem.asInstanceOf[T], end)
+ catch { case _: ClassCastException => super.lastIndexOf(elem, end) }
+
+ private[this] def posOf(i: T): Int =
+ /*
+ If i is in this NumericRange, its position can simply be calculated by taking the amount of values up till i.
+ NumericRange.count does this in an most efficient manner.
+ Note that the contains() method throws an exception if the range has more than Int.MaxValue elements, but so did
+ the original indexOf / lastIndexOf functions, so no functionality changed. */
+ if (contains(i)) {
+ /* Because of zero indexing, the count is always one higher than the index. This can be simply solved by setting
+ isInclusive = false. */
+ NumericRange.count(this.start, i, this.step, isInclusive = false)
+ } else -1
+
+ // TODO: these private methods are straight copies from Range, duplicated
+ // to guard against any (most likely illusory) performance drop. They should
+ // be eliminated one way or another.
+
+ // Tests whether a number is within the endpoints, without testing
+ // whether it is a member of the sequence (i.e. when step > 1.)
+ private def isWithinBoundaries(elem: T) = !isEmpty && (
+ (step > zero && start <= elem && elem <= last ) ||
+ (step < zero && last <= elem && elem <= start)
+ )
+ // Methods like apply throw exceptions on invalid n, but methods like take/drop
+ // are forgiving: therefore the checks are with the methods.
+ private def locationAfterN(n: Int): T = start + (step * fromInt(n))
+
+ private def crossesTheEndAfterN(n: Int): Boolean = {
+ // if we're sure that subtraction in the context of T won't overflow, we use this function
+ // to calculate the length of the range
+ def unsafeRangeLength(r: NumericRange[T]): T = {
+ val diff = num.minus(r.end, r.start)
+ val quotient = num.quot(diff, r.step)
+ val remainder = num.rem(diff, r.step)
+ if (!r.isInclusive && num.equiv(remainder, num.zero))
+ num.max(quotient, num.zero)
+ else
+ num.max(num.plus(quotient, num.one), num.zero)
+ }
+
+ // detects whether value can survive a bidirectional trip to -and then from- Int.
+ def fitsInInteger(value: T): Boolean = num.equiv(num.fromInt(num.toInt(value)), value)
+
+ val stepIsInTheSameDirectionAsStartToEndVector =
+ (num.gt(end, start) && num.gt(step, num.zero)) || (num.lt(end, start) && num.sign(step) == -num.one)
+
+ if (num.equiv(start, end) || n <= 0 || !stepIsInTheSameDirectionAsStartToEndVector) return n >= 1
+
+ val sameSign = num.equiv(num.sign(start), num.sign(end))
+
+ if (sameSign) { // subtraction is safe
+ val len = unsafeRangeLength(this)
+ if (fitsInInteger(len)) n >= num.toInt(len) else num.gteq(num.fromInt(n), len)
+ } else {
+ // split to two ranges, which subtraction is safe in both of them (around zero)
+ val stepsRemainderToZero = num.rem(start, step)
+ val walksOnZero = num.equiv(stepsRemainderToZero, num.zero)
+ val closestToZero = if (walksOnZero) -step else stepsRemainderToZero
+
+ /*
+ When splitting into two ranges, we should be super-careful about one of the sides hitting MinValue of T,
+ so we take two steps smaller than zero to ensure unsafeRangeLength won't overflow (taking one step may overflow depending on the step).
+ Same thing happens for MaxValue from zero, so we take one step further to ensure the safety of unsafeRangeLength.
+ After performing such operation, there are some elements remaining in between and around zero,
+ which their length is represented by carry.
+ */
+ val (l: NumericRange[T], r: NumericRange[T], carry: Int) =
+ if (num.lt(start, num.zero)) {
+ if (walksOnZero) {
+ val twoStepsAfterLargestNegativeNumber = num.plus(closestToZero, num.times(step, num.fromInt(2)))
+ (NumericRange(start, closestToZero, step), copy(twoStepsAfterLargestNegativeNumber, end, step), 2)
+ } else {
+ (NumericRange(start, closestToZero, step), copy(num.plus(closestToZero, step), end, step), 1)
+ }
+ } else {
+ if (walksOnZero) {
+ val twoStepsAfterZero = num.times(step, num.fromInt(2))
+ (copy(twoStepsAfterZero, end, step), NumericRange.inclusive(start, -step, step), 2)
+ } else {
+ val twoStepsAfterSmallestPositiveNumber = num.plus(closestToZero, num.times(step, num.fromInt(2)))
+ (copy(twoStepsAfterSmallestPositiveNumber, end, step), NumericRange.inclusive(start, closestToZero, step), 2)
+ }
+ }
+
+ val leftLength = unsafeRangeLength(l)
+ val rightLength = unsafeRangeLength(r)
+
+ // instead of `n >= rightLength + leftLength + curry` which may cause addition overflow,
+ // this can be used `(n - leftLength - curry) >= rightLength` (Both in Int and T, depends on whether the lengths fit in Int)
+ if (fitsInInteger(leftLength) && fitsInInteger(rightLength))
+ n - num.toInt(leftLength) - carry >= num.toInt(rightLength)
+ else
+ num.gteq(num.minus(num.minus(num.fromInt(n), leftLength), num.fromInt(carry)), rightLength)
+ }
+ }
+
+ // When one drops everything. Can't ever have unchecked operations
+ // like "end + 1" or "end - 1" because ranges involving Int.{ MinValue, MaxValue }
+ // will overflow. This creates an exclusive range where start == end
+ // based on the given value.
+ private def newEmptyRange(value: T) = NumericRange(value, value, step)
+
+ override def take(n: Int): NumericRange[T] = {
+ if (n <= 0 || isEmpty) newEmptyRange(start)
+ else if (crossesTheEndAfterN(n)) this
+ else new NumericRange.Inclusive(start, locationAfterN(n - 1), step)
+ }
+
+ override def drop(n: Int): NumericRange[T] = {
+ if (n <= 0 || isEmpty) this
+ else if (crossesTheEndAfterN(n)) newEmptyRange(end)
+ else copy(locationAfterN(n), end, step)
+ }
+
+ override def splitAt(n: Int): (NumericRange[T], NumericRange[T]) = (take(n), drop(n))
+
+ override def reverse: NumericRange[T] =
+ if (isEmpty) this
+ else {
+ val newStep = -step
+ if (num.sign(newStep) == num.sign(step)) {
+ throw new ArithmeticException("number type is unsigned, and .reverse requires a negative step")
+ } else new NumericRange.Inclusive(last, start, newStep)
+ }
+
+ import NumericRange.defaultOrdering
+
+ override def min[T1 >: T](implicit ord: Ordering[T1]): T =
+ // We can take the fast path:
+ // - If the Integral of this NumericRange is also the requested Ordering
+ // (Integral <: Ordering). This can happen for custom Integral types.
+ // - The Ordering is the default Ordering of a well-known Integral type.
+ if ((ord eq num) || defaultOrdering.get(num).exists(ord eq _)) {
+ if (num.sign(step) > zero) head
+ else last
+ } else super.min(ord)
+
+ override def max[T1 >: T](implicit ord: Ordering[T1]): T =
+ // See comment for fast path in min().
+ if ((ord eq num) || defaultOrdering.get(num).exists(ord eq _)) {
+ if (num.sign(step) > zero) last
+ else head
+ } else super.max(ord)
+
+ // a well-typed contains method.
+ def containsTyped(x: T): Boolean =
+ isWithinBoundaries(x) && (((x - start) % step) == zero)
+
+ override def contains[A1 >: T](x: A1): Boolean =
+ try containsTyped(x.asInstanceOf[T])
+ catch { case _: ClassCastException => false }
+
+ override def sum[B >: T](implicit num: Numeric[B]): B = {
+ if (isEmpty) num.zero
+ else if (size == 1) head
+ else {
+ // If there is no overflow, use arithmetic series formula
+ // a + ... (n terms total) ... + b = n*(a+b)/2
+ if ((num eq scala.math.Numeric.IntIsIntegral)||
+ (num eq scala.math.Numeric.ShortIsIntegral)||
+ (num eq scala.math.Numeric.ByteIsIntegral)||
+ (num eq scala.math.Numeric.CharIsIntegral)) {
+ // We can do math with no overflow in a Long--easy
+ val exact = (size * ((num toLong head) + (num toInt last))) / 2
+ num fromInt exact.toInt
+ }
+ else if (num eq scala.math.Numeric.LongIsIntegral) {
+ // Uh-oh, might be overflow, so we have to divide before we overflow.
+ // Either numRangeElements or (head + last) must be even, so divide the even one before multiplying
+ val a = head.toLong
+ val b = last.toLong
+ val ans =
+ if ((size & 1) == 0) (size / 2) * (a + b)
+ else size * {
+ // Sum is even, but we might overflow it, so divide in pieces and add back remainder
+ val ha = a/2
+ val hb = b/2
+ ha + hb + ((a - 2*ha) + (b - 2*hb)) / 2
+ }
+ ans.asInstanceOf[B]
+ }
+ else if ((num eq scala.math.Numeric.BigIntIsIntegral) ||
+ (num eq scala.math.Numeric.BigDecimalAsIfIntegral)) {
+ // No overflow, so we can use arithmetic series formula directly
+ // (not going to worry about running out of memory)
+ val numAsIntegral = num.asInstanceOf[Integral[B]]
+ import numAsIntegral._
+ ((num fromInt size) * (head + last)) / (num fromInt 2)
+ }
+ else {
+ // User provided custom Numeric, so we cannot rely on arithmetic series formula (e.g. won't work on something like Z_6)
+ if (isEmpty) num.zero
+ else {
+ var acc = num.zero
+ var i = head
+ var idx = 0
+ while(idx < length) {
+ acc = num.plus(acc, i)
+ i = i + step
+ idx = idx + 1
+ }
+ acc
+ }
+ }
+ }
+ }
+
+ override lazy val hashCode: Int = super.hashCode()
+ override protected final def applyPreferredMaxLength: Int = Int.MaxValue
+
+ override def equals(other: Any): Boolean = other match {
+ case x: NumericRange[_] =>
+ (x canEqual this) && (length == x.length) && (
+ (isEmpty) || // all empty sequences are equal
+ (start == x.start && last == x.last) // same length and same endpoints implies equality
+ )
+ case _ =>
+ super.equals(other)
+ }
+
+ override def toString: String = {
+ val empty = if (isEmpty) "empty " else ""
+ val preposition = if (isInclusive) "to" else "until"
+ val stepped = if (step == 1) "" else s" by $step"
+ s"${empty}NumericRange $start $preposition $end$stepped"
+ }
+
+ override protected[this] def className = "NumericRange"
+}
+
+/** A companion object for numeric ranges.
+ * @define Coll `NumericRange`
+ * @define coll numeric range
+ */
+object NumericRange {
+ private def bigDecimalCheckUnderflow[T](start: T, end: T, step: T)(implicit num: Integral[T]): Unit = {
+ def FAIL(boundary: T, step: T): Unit = {
+ val msg = boundary match {
+ case bd: BigDecimal => s"Precision ${bd.mc.getPrecision}"
+ case _ => "Precision"
+ }
+ throw new IllegalArgumentException(
+ s"$msg inadequate to represent steps of size $step near $boundary"
+ )
+ }
+ if (num.minus(num.plus(start, step), start) != step) FAIL(start, step)
+ if (num.minus(end, num.minus(end, step)) != step) FAIL(end, step)
+ }
+
+ /** Calculates the number of elements in a range given start, end, step, and
+ * whether or not it is inclusive. Throws an exception if step == 0 or
+ * the number of elements exceeds the maximum Int.
+ */
+ def count[T](start: T, end: T, step: T, isInclusive: Boolean)(implicit num: Integral[T]): Int = {
+ val zero = num.zero
+ val upward = num.lt(start, end)
+ val posStep = num.gt(step, zero)
+
+ if (step == zero) throw new IllegalArgumentException("step cannot be 0.")
+ else if (start == end) if (isInclusive) 1 else 0
+ else if (upward != posStep) 0
+ else {
+ /* We have to be frightfully paranoid about running out of range.
+ * We also can't assume that the numbers will fit in a Long.
+ * We will assume that if a > 0, -a can be represented, and if
+ * a < 0, -a+1 can be represented. We also assume that if we
+ * can't fit in Int, we can represent 2*Int.MaxValue+3 (at least).
+ * And we assume that numbers wrap rather than cap when they overflow.
+ */
+ // Check whether we can short-circuit by deferring to Int range.
+ val startint = num.toInt(start)
+ if (start == num.fromInt(startint)) {
+ val endint = num.toInt(end)
+ if (end == num.fromInt(endint)) {
+ val stepint = num.toInt(step)
+ if (step == num.fromInt(stepint)) {
+ return {
+ if (isInclusive) Range.inclusive(startint, endint, stepint).length
+ else Range (startint, endint, stepint).length
+ }
+ }
+ }
+ }
+ // If we reach this point, deferring to Int failed.
+ // Numbers may be big.
+ if (num.isInstanceOf[Numeric.BigDecimalAsIfIntegral]) {
+ bigDecimalCheckUnderflow(start, end, step) // Throw exception if math is inaccurate (including no progress at all)
+ }
+ val one = num.one
+ val limit = num.fromInt(Int.MaxValue)
+ def check(t: T): T =
+ if (num.gt(t, limit)) throw new IllegalArgumentException("More than Int.MaxValue elements.")
+ else t
+ // If the range crosses zero, it might overflow when subtracted
+ val startside = num.sign(start)
+ val endside = num.sign(end)
+ num.toInt{
+ if (num.gteq(num.times(startside, endside), zero)) {
+ // We're sure we can subtract these numbers.
+ // Note that we do not use .rem because of different conventions for Long and BigInt
+ val diff = num.minus(end, start)
+ val quotient = check(num.quot(diff, step))
+ val remainder = num.minus(diff, num.times(quotient, step))
+ if (!isInclusive && zero == remainder) quotient else check(num.plus(quotient, one))
+ }
+ else {
+ // We might not even be able to subtract these numbers.
+ // Jump in three pieces:
+ // * start to -1 or 1, whichever is closer (waypointA)
+ // * one step, which will take us at least to 0 (ends at waypointB)
+ // * (except with really small numbers)
+ // * there to the end
+ val negone = num.fromInt(-1)
+ val startlim = if (posStep) negone else one
+ //Use start value if the start value is closer to zero than startlim
+ // * e.g. .5 is closer to zero than 1 and -.5 is closer to zero than -1
+ val startdiff = {
+ if ((posStep && num.lt(startlim, start)) || (!posStep && num.gt(startlim, start)))
+ start
+ else
+ num.minus(startlim, start)
+ }
+ val startq = check(num.quot(startdiff, step))
+ val waypointA = if (startq == zero) start else num.plus(start, num.times(startq, step))
+ val waypointB = num.plus(waypointA, step)
+ check {
+ if (num.lt(waypointB, end) != upward) {
+ // No last piece
+ if (isInclusive && waypointB == end) num.plus(startq, num.fromInt(2))
+ else num.plus(startq, one)
+ }
+ else {
+ // There is a last piece
+ val enddiff = num.minus(end,waypointB)
+ val endq = check(num.quot(enddiff, step))
+ val last = if (endq == zero) waypointB else num.plus(waypointB, num.times(endq, step))
+ // Now we have to tally up all the pieces
+ // 1 for the initial value
+ // startq steps to waypointA
+ // 1 step to waypointB
+ // endq steps to the end (one less if !isInclusive and last==end)
+ num.plus(startq, num.plus(endq, if (!isInclusive && last==end) one else num.fromInt(2)))
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @SerialVersionUID(3L)
+ class Inclusive[T](start: T, end: T, step: T)(implicit num: Integral[T])
+ extends NumericRange(start, end, step, isInclusive = true) {
+ override def copy(start: T, end: T, step: T): Inclusive[T] =
+ NumericRange.inclusive(start, end, step)
+
+ def exclusive: Exclusive[T] = NumericRange(start, end, step)
+ }
+
+ @SerialVersionUID(3L)
+ class Exclusive[T](start: T, end: T, step: T)(implicit num: Integral[T])
+ extends NumericRange(start, end, step, isInclusive = false) {
+ override def copy(start: T, end: T, step: T): Exclusive[T] =
+ NumericRange(start, end, step)
+
+ def inclusive: Inclusive[T] = NumericRange.inclusive(start, end, step)
+ }
+
+ def apply[T](start: T, end: T, step: T)(implicit num: Integral[T]): Exclusive[T] =
+ new Exclusive(start, end, step)
+ def inclusive[T](start: T, end: T, step: T)(implicit num: Integral[T]): Inclusive[T] =
+ new Inclusive(start, end, step)
+
+ private[collection] val defaultOrdering = Map[Numeric[_], Ordering[_]](
+ Numeric.BigIntIsIntegral -> Ordering.BigInt,
+ Numeric.IntIsIntegral -> Ordering.Int,
+ Numeric.ShortIsIntegral -> Ordering.Short,
+ Numeric.ByteIsIntegral -> Ordering.Byte,
+ Numeric.CharIsIntegral -> Ordering.Char,
+ Numeric.LongIsIntegral -> Ordering.Long,
+ Numeric.BigDecimalAsIfIntegral -> Ordering.BigDecimal
+ )
+
+ @SerialVersionUID(3L)
+ private final class NumericRangeIterator[T](self: NumericRange[T], num: Integral[T]) extends AbstractIterator[T] with Serializable {
+ import num.mkNumericOps
+
+ private[this] var _hasNext = !self.isEmpty
+ private[this] var _next: T = self.start
+ private[this] val lastElement: T = if (_hasNext) self.last else self.start
+ override def knownSize: Int = if (_hasNext) num.toInt((lastElement - _next) / self.step) + 1 else 0
+ def hasNext: Boolean = _hasNext
+ def next(): T = {
+ if (!_hasNext) Iterator.empty.next()
+ val value = _next
+ _hasNext = value != lastElement
+ _next = num.plus(value, self.step)
+ value
+ }
+ }
+}
diff --git a/library/src/scala/collection/immutable/Queue.scala b/library/src/scala/collection/immutable/Queue.scala
new file mode 100644
index 000000000000..89def7096aea
--- /dev/null
+++ b/library/src/scala/collection/immutable/Queue.scala
@@ -0,0 +1,217 @@
+/*
+ * 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 scala.collection.generic.DefaultSerializable
+import scala.collection.mutable.{Builder, ListBuffer}
+
+/** `Queue` objects implement data structures that allow to
+ * insert and retrieve elements in a first-in-first-out (FIFO) manner.
+ *
+ * `Queue` is implemented as a pair of `List`s, one containing the ''in'' elements and the other the ''out'' elements.
+ * Elements are added to the ''in'' list and removed from the ''out'' list. When the ''out'' list runs dry, the
+ * queue is pivoted by replacing the ''out'' list by ''in.reverse'', and ''in'' by ''Nil''.
+ *
+ * Adding items to the queue always has cost `O(1)`. Removing items has cost `O(1)`, except in the case
+ * where a pivot is required, in which case, a cost of `O(n)` is incurred, where `n` is the number of elements in the queue. When this happens,
+ * `n` remove operations with `O(1)` cost are guaranteed. Removing an item is on average `O(1)`.
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-immutable-collection-classes.html#immutable-queues "Scala's Collection Library overview"]]
+ * section on `Immutable Queues` for more information.
+ *
+ * @define Coll `immutable.Queue`
+ * @define coll immutable queue
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+
+sealed class Queue[+A] protected(protected val in: List[A], protected val out: List[A])
+ extends AbstractSeq[A]
+ with LinearSeq[A]
+ with LinearSeqOps[A, Queue, Queue[A]]
+ with StrictOptimizedLinearSeqOps[A, Queue, Queue[A]]
+ with StrictOptimizedSeqOps[A, Queue, Queue[A]]
+ with IterableFactoryDefaults[A, Queue]
+ with DefaultSerializable {
+
+ override def iterableFactory: SeqFactory[Queue] = Queue
+
+ /** Returns the `n`-th element of this queue.
+ * The first element is at position `0`.
+ *
+ * @param n index of the element to return
+ * @return the element at position `n` in this queue.
+ * @throws NoSuchElementException if the queue is too short.
+ */
+ override def apply(n: Int): A = {
+ def indexOutOfRange(): Nothing = throw new IndexOutOfBoundsException(n.toString)
+
+ var index = 0
+ var curr = out
+
+ while (index < n && curr.nonEmpty) {
+ index += 1
+ curr = curr.tail
+ }
+
+ if (index == n) {
+ if (curr.nonEmpty) curr.head
+ else if (in.nonEmpty) in.last
+ else indexOutOfRange()
+ } else {
+ val indexFromBack = n - index
+ val inLength = in.length
+ if (indexFromBack >= inLength) indexOutOfRange()
+ else in(inLength - indexFromBack - 1)
+ }
+ }
+
+ /** Returns the elements in the list as an iterator
+ */
+ override def iterator: Iterator[A] = out.iterator.concat(in.reverse)
+
+ /** Checks if the queue is empty.
+ *
+ * @return true, iff there is no element in the queue.
+ */
+ override def isEmpty: Boolean = in.isEmpty && out.isEmpty
+
+ override def head: A =
+ if (out.nonEmpty) out.head
+ else if (in.nonEmpty) in.last
+ else throw new NoSuchElementException("head on empty queue")
+
+ override def tail: Queue[A] =
+ if (out.nonEmpty) new Queue(in, out.tail)
+ else if (in.nonEmpty) new Queue(Nil, in.reverse.tail)
+ else throw new NoSuchElementException("tail on empty queue")
+
+ override def last: A =
+ if (in.nonEmpty) in.head
+ else if (out.nonEmpty) out.last
+ else throw new NoSuchElementException("last on empty queue")
+
+ /* This is made to avoid inefficient implementation of iterator. */
+ override def forall(p: A => Boolean): Boolean =
+ in.forall(p) && out.forall(p)
+
+ /* This is made to avoid inefficient implementation of iterator. */
+ override def exists(p: A => Boolean): Boolean =
+ in.exists(p) || out.exists(p)
+
+ override protected[this] def className = "Queue"
+
+ /** Returns the length of the queue. */
+ override def length: Int = in.length + out.length
+
+ override def prepended[B >: A](elem: B): Queue[B] = new Queue(in, elem :: out)
+
+ override def appended[B >: A](elem: B): Queue[B] = enqueue(elem)
+
+ override def appendedAll[B >: A](that: scala.collection.IterableOnce[B]): Queue[B] = {
+ val newIn = that match {
+ case that: Queue[B] => that.in ++ (that.out reverse_::: this.in)
+ case that: List[B] => that reverse_::: this.in
+ case _ =>
+ var result: List[B] = this.in
+ val iter = that.iterator
+ while (iter.hasNext) {
+ result = iter.next() :: result
+ }
+ result
+ }
+ if (newIn eq this.in) this else new Queue[B](newIn, this.out)
+ }
+
+ /** Creates a new queue with element added at the end
+ * of the old queue.
+ *
+ * @param elem the element to insert
+ */
+ def enqueue[B >: A](elem: B): Queue[B] = new Queue(elem :: in, out)
+
+ /** Creates a new queue with all elements provided by an `Iterable` object
+ * added at the end of the old queue.
+ *
+ * The elements are appended in the order they are given out by the
+ * iterator.
+ *
+ * @param iter an iterable object
+ */
+ @deprecated("Use `enqueueAll` instead of `enqueue` to enqueue a collection of elements", "2.13.0")
+ @`inline` final def enqueue[B >: A](iter: scala.collection.Iterable[B]) = enqueueAll(iter)
+
+ /** Creates a new queue with all elements provided by an `Iterable` object
+ * added at the end of the old queue.
+ *
+ * The elements are appended in the order they are given out by the
+ * iterator.
+ *
+ * @param iter an iterable object
+ */
+ def enqueueAll[B >: A](iter: scala.collection.Iterable[B]): Queue[B] = appendedAll(iter)
+
+ /** Returns a tuple with the first element in the queue,
+ * and a new queue with this element removed.
+ *
+ * @return the first element of the queue.
+ * @throws NoSuchElementException if the queue is empty
+ */
+ def dequeue: (A, Queue[A]) = out match {
+ case Nil if !in.isEmpty => val rev = in.reverse ; (rev.head, new Queue(Nil, rev.tail))
+ case x :: xs => (x, new Queue(in, xs))
+ case _ => throw new NoSuchElementException("dequeue on empty queue")
+ }
+
+ /** Optionally retrieves the first element and a queue of the remaining elements.
+ *
+ * @return A tuple of the first element of the queue, and a new queue with this element removed.
+ * If the queue is empty, `None` is returned.
+ */
+ def dequeueOption: Option[(A, Queue[A])] = if(isEmpty) None else Some(dequeue)
+
+ /** Returns the first element in the queue, or throws an error if there
+ * is no element contained in the queue.
+ *
+ * @throws NoSuchElementException if the queue is empty
+ * @return the first element.
+ */
+ def front: A = head
+
+ /** Returns a string representation of this queue.
+ */
+ override def toString(): String = mkString("Queue(", ", ", ")")
+}
+
+/** $factoryInfo
+ * @define Coll `immutable.Queue`
+ * @define coll immutable queue
+ */
+@SerialVersionUID(3L)
+object Queue extends StrictOptimizedSeqFactory[Queue] {
+ def newBuilder[A]: Builder[A, Queue[A]] = new ListBuffer[A] mapResult (x => new Queue[A](Nil, x))
+
+ def from[A](source: IterableOnce[A]): Queue[A] = source match {
+ case q: Queue[A] => q
+ case _ =>
+ val list = List.from(source)
+ if (list.isEmpty) empty
+ else new Queue(Nil, list)
+ }
+
+ def empty[A]: Queue[A] = EmptyQueue
+ override def apply[A](xs: A*): Queue[A] = new Queue[A](Nil, xs.toList)
+
+ private object EmptyQueue extends Queue[Nothing](Nil, Nil) { }
+}
diff --git a/library/src/scala/collection/immutable/Range.scala b/library/src/scala/collection/immutable/Range.scala
new file mode 100644
index 000000000000..92df921605f6
--- /dev/null
+++ b/library/src/scala/collection/immutable/Range.scala
@@ -0,0 +1,674 @@
+/*
+ * 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 collection.immutable
+
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.convert.impl.RangeStepper
+import scala.collection.generic.CommonErrors
+import scala.collection.{AbstractIterator, AnyStepper, IterableFactoryDefaults, Iterator, Stepper, StepperShape}
+import scala.util.hashing.MurmurHash3
+
+/** The `Range` class represents integer values in range
+ * ''[start;end)'' with non-zero step value `step`.
+ * It's a special case of an indexed sequence.
+ * For example:
+ *
+ * {{{
+ * val r1 = 0 until 10
+ * val r2 = r1.start until r1.end by r1.step + 1
+ * println(r2.length) // = 5
+ * }}}
+ *
+ * Ranges that contain more than `Int.MaxValue` elements can be created, but
+ * these overfull ranges have only limited capabilities. Any method that
+ * could require a collection of over `Int.MaxValue` length to be created, or
+ * could be asked to index beyond `Int.MaxValue` elements will throw an
+ * exception. Overfull ranges can safely be reduced in size by changing
+ * the step size (e.g. `by 3`) or taking/dropping elements. `contains`,
+ * `equals`, and access to the ends of the range (`head`, `last`, `tail`,
+ * `init`) are also permitted on overfull ranges.
+ *
+ * @param start the start of this range.
+ * @param end the end of the range. For exclusive ranges, e.g.
+ * `Range(0,3)` or `(0 until 3)`, this is one
+ * step past the last one in the range. For inclusive
+ * ranges, e.g. `Range.inclusive(0,3)` or `(0 to 3)`,
+ * it may be in the range if it is not skipped by the step size.
+ * To find the last element inside a non-empty range,
+ * use `last` instead.
+ * @param step the step for the range.
+ *
+ * @define coll range
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ * @define doesNotUseBuilders
+ * '''Note:''' this method does not use builders to construct a new range,
+ * and its complexity is O(1).
+ */
+@SerialVersionUID(3L)
+sealed abstract class Range(
+ val start: Int,
+ val end: Int,
+ val step: Int
+)
+ extends AbstractSeq[Int]
+ with IndexedSeq[Int]
+ with IndexedSeqOps[Int, IndexedSeq, IndexedSeq[Int]]
+ with StrictOptimizedSeqOps[Int, IndexedSeq, IndexedSeq[Int]]
+ with IterableFactoryDefaults[Int, IndexedSeq]
+ with Serializable { range =>
+
+ final override def iterator: Iterator[Int] = new RangeIterator(start, step, lastElement, isEmpty)
+
+ override final def stepper[S <: Stepper[_]](implicit shape: StepperShape[Int, S]): S with EfficientSplit = {
+ val st = new RangeStepper(start, step, 0, length)
+ 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[this] def gap = end.toLong - start.toLong
+ private[this] def isExact = gap % step == 0
+ private[this] def hasStub = isInclusive || !isExact
+ private[this] def longLength = gap / step + ( if (hasStub) 1 else 0 )
+
+ def isInclusive: Boolean
+
+ final override val isEmpty: Boolean = (
+ (start > end && step > 0)
+ || (start < end && step < 0)
+ || (start == end && !isInclusive)
+ )
+
+ private[this] val numRangeElements: Int = {
+ if (step == 0) throw new IllegalArgumentException("step cannot be 0.")
+ else if (isEmpty) 0
+ else {
+ val len = longLength
+ if (len > scala.Int.MaxValue) -1
+ else len.toInt
+ }
+ }
+
+ final def length = if (numRangeElements < 0) fail() else numRangeElements
+
+ // This field has a sensible value only for non-empty ranges
+ private[this] val lastElement = step match {
+ case 1 => if (isInclusive) end else end-1
+ case -1 => if (isInclusive) end else end+1
+ case _ =>
+ val remainder = (gap % step).toInt
+ if (remainder != 0) end - remainder
+ else if (isInclusive) end
+ else end - step
+ }
+
+ /** The last element of this range. This method will return the correct value
+ * even if there are too many elements to iterate over.
+ */
+ final override def last: Int =
+ if (isEmpty) throw Range.emptyRangeError("last") else lastElement
+ final override def head: Int =
+ if (isEmpty) throw Range.emptyRangeError("head") else start
+
+ /** Creates a new range containing all the elements of this range except the last one.
+ *
+ * $doesNotUseBuilders
+ *
+ * @return a new range consisting of all the elements of this range except the last one.
+ */
+ final override def init: Range =
+ if (isEmpty) throw Range.emptyRangeError("init") else dropRight(1)
+
+ /** Creates a new range containing all the elements of this range except the first one.
+ *
+ * $doesNotUseBuilders
+ *
+ * @return a new range consisting of all the elements of this range except the first one.
+ */
+ final override def tail: Range = {
+ if (isEmpty) throw Range.emptyRangeError("tail")
+ if (numRangeElements == 1) newEmptyRange(end)
+ else if(isInclusive) new Range.Inclusive(start + step, end, step)
+ else new Range.Exclusive(start + step, end, step)
+ }
+
+ override def map[B](f: Int => B): IndexedSeq[B] = {
+ validateMaxLength()
+ super.map(f)
+ }
+
+ final protected def copy(start: Int = start, end: Int = end, step: Int = step, isInclusive: Boolean = isInclusive): Range =
+ if(isInclusive) new Range.Inclusive(start, end, step) else new Range.Exclusive(start, end, step)
+
+ /** Create a new range with the `start` and `end` values of this range and
+ * a new `step`.
+ *
+ * @return a new range with a different step
+ */
+ final def by(step: Int): Range = copy(start, end, step)
+
+ // Check cannot be evaluated eagerly because we have a pattern where
+ // ranges are constructed like: "x to y by z" The "x to y" piece
+ // should not trigger an exception. So the calculation is delayed,
+ // which means it will not fail fast for those cases where failing was
+ // correct.
+ private[this] def validateMaxLength(): Unit = {
+ if (numRangeElements < 0)
+ fail()
+ }
+ private[this] def description = "%d %s %d by %s".format(start, if (isInclusive) "to" else "until", end, step)
+ private[this] def fail() = throw new IllegalArgumentException(description + ": seqs cannot contain more than Int.MaxValue elements.")
+
+ @throws[IndexOutOfBoundsException]
+ final def apply(idx: Int): Int = {
+ validateMaxLength()
+ if (idx < 0 || idx >= numRangeElements)
+ throw CommonErrors.indexOutOfBounds(index = idx, max = numRangeElements - 1)
+ else start + (step * idx)
+ }
+
+ /*@`inline`*/ final override def foreach[@specialized(Unit) U](f: Int => U): Unit = {
+ // Implementation chosen on the basis of favorable microbenchmarks
+ // Note--initialization catches step == 0 so we don't need to here
+ if (!isEmpty) {
+ var i = start
+ while (true) {
+ f(i)
+ if (i == lastElement) return
+ i += step
+ }
+ }
+ }
+
+ override final def indexOf[@specialized(Int) B >: Int](elem: B, from: Int = 0): Int =
+ elem match {
+ case i: Int =>
+ val pos = posOf(i)
+ if (pos >= from) pos else -1
+ case _ => super.indexOf(elem, from)
+ }
+
+ override final def lastIndexOf[@specialized(Int) B >: Int](elem: B, end: Int = length - 1): Int =
+ elem match {
+ case i: Int =>
+ val pos = posOf(i)
+ if (pos <= end) pos else -1
+ case _ => super.lastIndexOf(elem, end)
+ }
+
+ private[this] def posOf(i: Int): Int =
+ if (contains(i)) (i - start) / step else -1
+
+ override def sameElements[B >: Int](that: IterableOnce[B]): Boolean = that match {
+ case other: Range =>
+ (this.length : @annotation.switch) match {
+ case 0 => other.isEmpty
+ case 1 => other.length == 1 && this.start == other.start
+ case n => other.length == n && (
+ (this.start == other.start)
+ && (this.step == other.step)
+ )
+ }
+ case _ => super.sameElements(that)
+ }
+
+ /** Creates a new range containing the first `n` elements of this range.
+ *
+ * @param n the number of elements to take.
+ * @return a new range consisting of `n` first elements.
+ */
+ final override def take(n: Int): Range =
+ if (n <= 0 || isEmpty) newEmptyRange(start)
+ else if (n >= numRangeElements && numRangeElements >= 0) this
+ else {
+ // May have more than Int.MaxValue elements in range (numRangeElements < 0)
+ // but the logic is the same either way: take the first n
+ new Range.Inclusive(start, locationAfterN(n - 1), step)
+ }
+
+ /** Creates a new range containing all the elements of this range except the first `n` elements.
+ *
+ * @param n the number of elements to drop.
+ * @return a new range consisting of all the elements of this range except `n` first elements.
+ */
+ final override def drop(n: Int): Range =
+ if (n <= 0 || isEmpty) this
+ else if (n >= numRangeElements && numRangeElements >= 0) newEmptyRange(end)
+ else {
+ // May have more than Int.MaxValue elements (numRangeElements < 0)
+ // but the logic is the same either way: go forwards n steps, keep the rest
+ copy(locationAfterN(n), end, step)
+ }
+
+ /** Creates a new range consisting of the last `n` elements of the range.
+ *
+ * $doesNotUseBuilders
+ */
+ final override def takeRight(n: Int): Range = {
+ if (n <= 0) newEmptyRange(start)
+ else if (numRangeElements >= 0) drop(numRangeElements - n)
+ else {
+ // Need to handle over-full range separately
+ val y = last
+ val x = y - step.toLong*(n-1)
+ if ((step > 0 && x < start) || (step < 0 && x > start)) this
+ else Range.inclusive(x.toInt, y, step)
+ }
+ }
+
+ /** Creates a new range consisting of the initial `length - n` elements of the range.
+ *
+ * $doesNotUseBuilders
+ */
+ final override def dropRight(n: Int): Range = {
+ if (n <= 0) this
+ else if (numRangeElements >= 0) take(numRangeElements - n)
+ else {
+ // Need to handle over-full range separately
+ val y = last - step.toInt*n
+ if ((step > 0 && y < start) || (step < 0 && y > start)) newEmptyRange(start)
+ else Range.inclusive(start, y.toInt, step)
+ }
+ }
+
+ // Advance from the start while we meet the given test
+ private[this] def argTakeWhile(p: Int => Boolean): Long = {
+ if (isEmpty) start
+ else {
+ var current = start
+ val stop = last
+ while (current != stop && p(current)) current += step
+ if (current != stop || !p(current)) current
+ else current.toLong + step
+ }
+ }
+
+ final override def takeWhile(p: Int => Boolean): Range = {
+ val stop = argTakeWhile(p)
+ if (stop==start) newEmptyRange(start)
+ else {
+ val x = (stop - step).toInt
+ if (x == last) this
+ else Range.inclusive(start, x, step)
+ }
+ }
+
+ final override def dropWhile(p: Int => Boolean): Range = {
+ val stop = argTakeWhile(p)
+ if (stop == start) this
+ else {
+ val x = (stop - step).toInt
+ if (x == last) newEmptyRange(last)
+ else Range.inclusive(x + step, last, step)
+ }
+ }
+
+ final override def span(p: Int => Boolean): (Range, Range) = {
+ val border = argTakeWhile(p)
+ if (border == start) (newEmptyRange(start), this)
+ else {
+ val x = (border - step).toInt
+ if (x == last) (this, newEmptyRange(last))
+ else (Range.inclusive(start, x, step), Range.inclusive(x+step, last, step))
+ }
+ }
+
+ /** Creates a new range containing the elements starting at `from` up to but not including `until`.
+ *
+ * $doesNotUseBuilders
+ *
+ * @param from the element at which to start
+ * @param until the element at which to end (not included in the range)
+ * @return a new range consisting of a contiguous interval of values in the old range
+ */
+ final override def slice(from: Int, until: Int): Range =
+ if (from <= 0) take(until)
+ else if (until >= numRangeElements && numRangeElements >= 0) drop(from)
+ else {
+ val fromValue = locationAfterN(from)
+ if (from >= until) newEmptyRange(fromValue)
+ else Range.inclusive(fromValue, locationAfterN(until-1), step)
+ }
+
+ // Overridden only to refine the return type
+ final override def splitAt(n: Int): (Range, Range) = (take(n), drop(n))
+
+ // Methods like apply throw exceptions on invalid n, but methods like take/drop
+ // are forgiving: therefore the checks are with the methods.
+ private[this] def locationAfterN(n: Int) = start + (step * n)
+
+ // When one drops everything. Can't ever have unchecked operations
+ // like "end + 1" or "end - 1" because ranges involving Int.{ MinValue, MaxValue }
+ // will overflow. This creates an exclusive range where start == end
+ // based on the given value.
+ private[this] def newEmptyRange(value: Int) = new Range.Exclusive(value, value, step)
+
+ /** Returns the reverse of this range.
+ */
+ final override def reverse: Range =
+ if (isEmpty) this
+ else new Range.Inclusive(last, start, -step)
+
+ /** Make range inclusive.
+ */
+ final def inclusive: Range =
+ if (isInclusive) this
+ else new Range.Inclusive(start, end, step)
+
+ final def contains(x: Int): Boolean = {
+ if (x == end && !isInclusive) false
+ else if (step > 0) {
+ if (x < start || x > end) false
+ else (step == 1) || (Integer.remainderUnsigned(x - start, step) == 0)
+ }
+ else {
+ if (x < end || x > start) false
+ else (step == -1) || (Integer.remainderUnsigned(start - x, -step) == 0)
+ }
+ }
+ /* Seq#contains has a type parameter so the optimised contains above doesn't override it */
+ override final def contains[B >: Int](elem: B): Boolean = elem match {
+ case i: Int => this.contains(i)
+ case _ => super.contains(elem)
+ }
+
+ final override def sum[B >: Int](implicit num: Numeric[B]): Int = {
+ if (num eq scala.math.Numeric.IntIsIntegral) {
+ // this is normal integer range with usual addition. arithmetic series formula can be used
+ if (isEmpty) 0
+ else if (size == 1) head
+ else ((size * (head.toLong + last)) / 2).toInt
+ } else {
+ // user provided custom Numeric, we cannot rely on arithmetic series formula
+ if (isEmpty) num.toInt(num.zero)
+ else {
+ var acc = num.zero
+ var i = head
+ while (true) {
+ acc = num.plus(acc, i)
+ if (i == lastElement) return num.toInt(acc)
+ i = i + step
+ }
+ 0 // Never hit this--just to satisfy compiler since it doesn't know while(true) has type Nothing
+ }
+ }
+ }
+
+ final override def min[A1 >: Int](implicit ord: Ordering[A1]): Int =
+ if (ord eq Ordering.Int) {
+ if (step > 0) head
+ else last
+ } else if (Ordering.Int isReverseOf ord) {
+ if (step > 0) last
+ else head
+ } else super.min(ord)
+
+ final override def max[A1 >: Int](implicit ord: Ordering[A1]): Int =
+ if (ord eq Ordering.Int) {
+ if (step > 0) last
+ else head
+ } else if (Ordering.Int isReverseOf ord) {
+ if (step > 0) head
+ else last
+ } else super.max(ord)
+
+ override def tails: Iterator[Range] =
+ new AbstractIterator[Range] {
+ private[this] var i = 0
+ override def hasNext = i <= Range.this.length
+ override def next() = {
+ if (hasNext) {
+ val res = Range.this.drop(i)
+ i += 1
+ res
+ } else {
+ Iterator.empty.next()
+ }
+ }
+ }
+
+ override def inits: Iterator[Range] =
+ new AbstractIterator[Range] {
+ private[this] var i = 0
+ override def hasNext = i <= Range.this.length
+ override def next() = {
+ if (hasNext) {
+ val res = Range.this.dropRight(i)
+ i += 1
+ res
+ } else {
+ Iterator.empty.next()
+ }
+ }
+ }
+ override protected final def applyPreferredMaxLength: Int = Int.MaxValue
+
+ final override def equals(other: Any): Boolean = other match {
+ case x: Range =>
+ // Note: this must succeed for overfull ranges (length > Int.MaxValue)
+ if (isEmpty) x.isEmpty // empty sequences are equal
+ else // this is non-empty...
+ x.nonEmpty && start == x.start && { // ...so other must contain something and have same start
+ val l0 = last
+ (l0 == x.last && ( // And same end
+ start == l0 || step == x.step // And either the same step, or not take any steps
+ ))
+ }
+ case _ =>
+ super.equals(other)
+ }
+
+ final override def hashCode: Int =
+ if(length >= 2) MurmurHash3.rangeHash(start, step, lastElement)
+ else super.hashCode
+
+ final override def toString: String = {
+ val preposition = if (isInclusive) "to" else "until"
+ val stepped = if (step == 1) "" else s" by $step"
+ val prefix = if (isEmpty) "empty " else if (!isExact) "inexact " else ""
+ s"${prefix}Range $start $preposition $end$stepped"
+ }
+
+ override protected[this] def className = "Range"
+
+ override def distinct: Range = this
+
+ override def grouped(size: Int): Iterator[Range] = {
+ require(size >= 1, f"size=$size%d, but size must be positive")
+ if (isEmpty) {
+ Iterator.empty
+ } else {
+ val s = size
+ new AbstractIterator[Range] {
+ private[this] var i = 0
+ override def hasNext = Range.this.length > i
+ override def next() =
+ if (hasNext) {
+ val x = Range.this.slice(i, i + s)
+ i += s
+ x
+ } else {
+ Iterator.empty.next()
+ }
+ }
+ }
+ }
+
+ override def sorted[B >: Int](implicit ord: Ordering[B]): IndexedSeq[Int] =
+ if (ord eq Ordering.Int) {
+ if (step > 0) {
+ this
+ } else {
+ reverse
+ }
+ } else {
+ super.sorted(ord)
+ }
+}
+
+/**
+ * Companion object for ranges.
+ * @define Coll `Range`
+ * @define coll range
+ */
+object Range {
+
+ /** Counts the number of range elements.
+ * precondition: step != 0
+ * If the size of the range exceeds Int.MaxValue, the
+ * result will be negative.
+ */
+ def count(start: Int, end: Int, step: Int, isInclusive: Boolean): Int = {
+ if (step == 0)
+ throw new IllegalArgumentException("step cannot be 0.")
+
+ val isEmpty =
+ if (start == end) !isInclusive
+ else if (start < end) step < 0
+ else step > 0
+
+ if (isEmpty) 0
+ else {
+ // Counts with Longs so we can recognize too-large ranges.
+ val gap: Long = end.toLong - start.toLong
+ val jumps: Long = gap / step
+ // Whether the size of this range is one larger than the
+ // number of full-sized jumps.
+ val hasStub = isInclusive || (gap % step != 0)
+ val result: Long = jumps + ( if (hasStub) 1 else 0 )
+
+ if (result > scala.Int.MaxValue) -1
+ else result.toInt
+ }
+ }
+ def count(start: Int, end: Int, step: Int): Int =
+ count(start, end, step, isInclusive = false)
+
+ /** Make a range from `start` until `end` (exclusive) with given step value.
+ * @note step != 0
+ */
+ def apply(start: Int, end: Int, step: Int): Range.Exclusive = new Range.Exclusive(start, end, step)
+
+ /** Make a range from `start` until `end` (exclusive) with step value 1.
+ */
+ def apply(start: Int, end: Int): Range.Exclusive = new Range.Exclusive(start, end, 1)
+
+ /** Make an inclusive range from `start` to `end` with given step value.
+ * @note step != 0
+ */
+ def inclusive(start: Int, end: Int, step: Int): Range.Inclusive = new Range.Inclusive(start, end, step)
+
+ /** Make an inclusive range from `start` to `end` with step value 1.
+ */
+ def inclusive(start: Int, end: Int): Range.Inclusive = new Range.Inclusive(start, end, 1)
+
+ @SerialVersionUID(3L)
+ final class Inclusive(start: Int, end: Int, step: Int) extends Range(start, end, step) {
+ def isInclusive: Boolean = true
+ }
+
+ @SerialVersionUID(3L)
+ final class Exclusive(start: Int, end: Int, step: Int) extends Range(start, end, step) {
+ def isInclusive: Boolean = false
+ }
+
+ // BigInt and Long are straightforward generic ranges.
+ object BigInt {
+ def apply(start: BigInt, end: BigInt, step: BigInt): NumericRange.Exclusive[BigInt] = NumericRange(start, end, step)
+ def inclusive(start: BigInt, end: BigInt, step: BigInt): NumericRange.Inclusive[BigInt] = NumericRange.inclusive(start, end, step)
+ }
+
+ object Long {
+ def apply(start: Long, end: Long, step: Long): NumericRange.Exclusive[Long] = NumericRange(start, end, step)
+ def inclusive(start: Long, end: Long, step: Long): NumericRange.Inclusive[Long] = NumericRange.inclusive(start, end, step)
+ }
+
+ // BigDecimal uses an alternative implementation of Numeric in which
+ // it pretends to be Integral[T] instead of Fractional[T]. See Numeric for
+ // details. The intention is for it to throw an exception anytime
+ // imprecision or surprises might result from anything, although this may
+ // not yet be fully implemented.
+ object BigDecimal {
+ implicit val bigDecAsIntegral: Numeric.BigDecimalAsIfIntegral = Numeric.BigDecimalAsIfIntegral
+
+ def apply(start: BigDecimal, end: BigDecimal, step: BigDecimal): NumericRange.Exclusive[BigDecimal] =
+ NumericRange(start, end, step)
+ def inclusive(start: BigDecimal, end: BigDecimal, step: BigDecimal): NumericRange.Inclusive[BigDecimal] =
+ NumericRange.inclusive(start, end, step)
+ }
+
+ // As there is no appealing default step size for not-really-integral ranges,
+ // we offer a partially constructed object.
+ class Partial[T, U](private val f: T => U) extends AnyVal {
+ def by(x: T): U = f(x)
+ override def toString = "Range requires step"
+ }
+
+ // Illustrating genericity with Int Range, which should have the same behavior
+ // as the original Range class. However we leave the original Range
+ // indefinitely, for performance and because the compiler seems to bootstrap
+ // off it and won't do so with our parameterized version without modifications.
+ object Int {
+ def apply(start: Int, end: Int, step: Int): NumericRange.Exclusive[Int] = NumericRange(start, end, step)
+ def inclusive(start: Int, end: Int, step: Int): NumericRange.Inclusive[Int] = NumericRange.inclusive(start, end, step)
+ }
+
+ private def emptyRangeError(what: String): Throwable =
+ new NoSuchElementException(what + " on empty Range")
+}
+
+/**
+ * @param lastElement The last element included in the Range
+ * @param initiallyEmpty Whether the Range was initially empty or not
+ */
+@SerialVersionUID(3L)
+private class RangeIterator(
+ start: Int,
+ step: Int,
+ lastElement: Int,
+ initiallyEmpty: Boolean
+) extends AbstractIterator[Int] with Serializable {
+ private[this] var _hasNext: Boolean = !initiallyEmpty
+ private[this] var _next: Int = start
+ override def knownSize: Int = if (_hasNext) (lastElement - _next) / step + 1 else 0
+ def hasNext: Boolean = _hasNext
+ @throws[NoSuchElementException]
+ def next(): Int = {
+ if (!_hasNext) Iterator.empty.next()
+ val value = _next
+ _hasNext = value != lastElement
+ _next = value + step
+ value
+ }
+
+ override def drop(n: Int): Iterator[Int] = {
+ if (n > 0) {
+ val longPos = _next.toLong + step * n
+ if (step > 0) {
+ _next = Math.min(lastElement, longPos).toInt
+ _hasNext = longPos <= lastElement
+ }
+ else if (step < 0) {
+ _next = Math.max(lastElement, longPos).toInt
+ _hasNext = longPos >= lastElement
+ }
+ }
+ this
+ }
+}
diff --git a/library/src/scala/collection/immutable/RedBlackTree.scala b/library/src/scala/collection/immutable/RedBlackTree.scala
new file mode 100644
index 000000000000..d9ac41e1ce5b
--- /dev/null
+++ b/library/src/scala/collection/immutable/RedBlackTree.scala
@@ -0,0 +1,1244 @@
+/*
+ * 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 collection
+package immutable
+
+import scala.annotation.meta.{getter, setter}
+import scala.annotation.tailrec
+import scala.runtime.Statics.releaseFence
+
+/** An object containing the RedBlack tree implementation used by for `TreeMaps` and `TreeSets`.
+ *
+ * Implementation note: since efficiency is important for data structures this implementation
+ * uses `null` to represent empty trees. This also means pattern matching cannot
+ * easily be used. The API represented by the RedBlackTree object tries to hide these
+ * optimizations behind a reasonably clean API.
+ */
+private[collection] object RedBlackTree {
+ def validate[A](tree: Tree[A, _])(implicit ordering: Ordering[A]): tree.type = {
+ def impl(tree: Tree[A, _], keyProp: A => Boolean): Int = {
+ assert(keyProp(tree.key), s"key check failed: $tree")
+ if (tree.isRed) {
+ assert(tree.left == null || tree.left.isBlack, s"red-red left $tree")
+ assert(tree.right == null || tree.right.isBlack, s"red-red right $tree")
+ }
+ val leftBlacks = if (tree.left == null) 0 else impl(tree.left, k => keyProp(k) && ordering.compare(k, tree.key) < 0)
+ val rightBlacks = if (tree.right == null) 0 else impl(tree.right, k => keyProp(k) && ordering.compare(k, tree.key) > 0)
+ assert(leftBlacks == rightBlacks, s"not balanced: $tree")
+ leftBlacks + (if (tree.isBlack) 1 else 0)
+ }
+ if (tree != null) impl(tree, _ => true)
+ tree
+ }
+
+ def isEmpty(tree: Tree[_, _]): Boolean = tree eq null
+
+ def contains[A: Ordering](tree: Tree[A, _], x: A): Boolean = lookup(tree, x) ne null
+ def get[A: Ordering, B](tree: Tree[A, B], x: A): Option[B] = lookup(tree, x) match {
+ case null => None
+ case found => Some(found.value)
+ }
+
+ @tailrec
+ def lookup[A, B](tree: Tree[A, B], x: A)(implicit ordering: Ordering[A]): Tree[A, B] = if (tree eq null) null else {
+ val cmp = ordering.compare(x, tree.key)
+ if (cmp < 0) lookup(tree.left, x)
+ else if (cmp > 0) lookup(tree.right, x)
+ else tree
+ }
+ private[immutable] abstract class Helper[A](implicit val ordering: Ordering[A]) {
+ def beforePublish[B](tree: Tree[A, B]): Tree[A, B] = {
+ if (tree eq null) tree
+ else if (tree.isMutable) {
+ val res = tree.mutableBlack.makeImmutable
+ releaseFence()
+ res
+ } else tree.black
+ }
+ /** Create a new balanced tree where `newLeft` replaces `tree.left`.
+ * tree and newLeft are never null */
+ protected[this] final def mutableBalanceLeft[A1, B, B1 >: B](tree: Tree[A1, B], newLeft: Tree[A1, B1]): Tree[A1, B1] = {
+ // Parameter trees
+ // tree | newLeft
+ // -- KV R | nl.L nl.KV nl.R
+ // | nl.R.L nl.R.KV nl.R.R
+ //Note - unlike the immutable trees we can't consider tree.left eq newLeft
+ //as the balance operations may mutate the same object
+ //but that check was mostly to avoid the object creation
+ if (newLeft.isRed) {
+ val newLeft_left = newLeft.left
+ val newLeft_right = newLeft.right
+ if (isRedTree(newLeft_left)) {
+ // RED
+ // black(nl.L) nl.KV black
+ // nl.R KV R
+ val resultLeft = newLeft_left.mutableBlack
+ val resultRight = tree.mutableBlackWithLeft(newLeft_right)
+
+ newLeft.mutableWithLeftRight(resultLeft, resultRight)
+ } else if (isRedTree(newLeft_right)) {
+ // RED
+ // black nl.R.KV black
+ // nl.L nl.KV nl.R.L nl.R.R KV R
+
+ val newLeft_right_right = newLeft_right.right
+
+ val resultLeft = newLeft.mutableBlackWithRight(newLeft_right.left)
+ val resultRight = tree.mutableBlackWithLeft(newLeft_right_right)
+
+ newLeft_right.mutableWithLeftRight(resultLeft, resultRight)
+ } else {
+ // tree
+ // newLeft KV R
+ tree.mutableWithLeft(newLeft)
+ }
+ } else {
+ // tree
+ // newLeft KV R
+ tree.mutableWithLeft(newLeft)
+ }
+ }
+ /** Create a new balanced tree where `newRight` replaces `tree.right`.
+ * tree and newRight are never null */
+ protected[this] final def mutableBalanceRight[A1, B, B1 >: B](tree: Tree[A1, B], newRight: Tree[A1, B1]): Tree[A1, B1] = {
+ // Parameter trees
+ // tree | newRight
+ // L KV -- | nr.L nr.KV nr.R
+ // | nr.L.L nr.L.KV nr.L.R
+ //Note - unlike the immutable trees we can't consider tree.right eq newRight
+ //as the balance operations may mutate the same object
+ //but that check was mostly to avoid the object creation
+ if (newRight.isRed) {
+ val newRight_left = newRight.left
+ if (isRedTree(newRight_left)) {
+ // RED
+ // black nr.L.KV black
+ // L KV nr.L.L nr.L.R nr.KV nr.R
+
+ val resultLeft = tree.mutableBlackWithRight(newRight_left.left)
+ val resultRight = newRight.mutableBlackWithLeft(newRight_left.right)
+
+ newRight_left.mutableWithLeftRight(resultLeft, resultRight)
+
+ } else {
+ val newRight_right = newRight.right
+ if (isRedTree(newRight_right)) {
+ // RED
+ // black nr.KV black(nr.R)
+ // L KV nr.L
+
+ val resultLeft = tree.mutableBlackWithRight(newRight_left)
+ val resultRight = newRight_right.mutableBlack
+
+ newRight.mutableWithLeftRight(resultLeft, resultRight)
+ } else {
+ // tree
+ // L KV newRight
+ tree.mutableWithRight(newRight)
+ }
+ }
+ } else {
+ // tree
+ // L KV newRight
+ tree.mutableWithRight(newRight)
+ }
+ }
+ }
+ private[immutable] class SetHelper[A](implicit ordering: Ordering[A]) extends Helper[A] {
+ protected[this] final def mutableUpd(tree: Tree[A, Any], k: A): Tree[A, Any] =
+ if (tree eq null) {
+ mutableRedTree(k, (), null, null)
+ } else if (k.asInstanceOf[AnyRef] eq tree.key.asInstanceOf[AnyRef]) {
+ tree
+ } else {
+ val cmp = ordering.compare(k, tree.key)
+ if (cmp < 0)
+ mutableBalanceLeft(tree, mutableUpd(tree.left, k))
+ else if (cmp > 0)
+ mutableBalanceRight(tree, mutableUpd(tree.right, k))
+ else tree
+ }
+ }
+ private[immutable] class MapHelper[A, B](implicit ordering: Ordering[A]) extends Helper[A] {
+ protected[this] final def mutableUpd[B1 >: B](tree: Tree[A, B], k: A, v: B1): Tree[A, B1] =
+ if (tree eq null) {
+ mutableRedTree(k, v, null, null)
+ } else if (k.asInstanceOf[AnyRef] eq tree.key.asInstanceOf[AnyRef]) {
+ tree.mutableWithV(v)
+ } else {
+ val cmp = ordering.compare(k, tree.key)
+ if (cmp < 0)
+ mutableBalanceLeft(tree, mutableUpd(tree.left, k, v))
+ else if (cmp > 0)
+ mutableBalanceRight(tree, mutableUpd(tree.right, k, v))
+ else tree.mutableWithV(v)
+ }
+ }
+
+ def count(tree: Tree[_, _]) = if (tree eq null) 0 else tree.count
+ def update[A: Ordering, B, B1 >: B](tree: Tree[A, B], k: A, v: B1, overwrite: Boolean): Tree[A, B1] = blacken(upd(tree, k, v, overwrite))
+ def delete[A: Ordering, B](tree: Tree[A, B], k: A): Tree[A, B] = blacken(del(tree, k))
+ def rangeImpl[A: Ordering, B](tree: Tree[A, B], from: Option[A], until: Option[A]): Tree[A, B] = (from, until) match {
+ case (Some(from), Some(until)) => this.range(tree, from, until)
+ case (Some(from), None) => this.from(tree, from)
+ case (None, Some(until)) => this.until(tree, until)
+ case (None, None) => tree
+ }
+ def range[A: Ordering, B](tree: Tree[A, B], from: A, until: A): Tree[A, B] = blacken(doRange(tree, from, until))
+ def from[A: Ordering, B](tree: Tree[A, B], from: A): Tree[A, B] = blacken(doFrom(tree, from))
+ def to[A: Ordering, B](tree: Tree[A, B], to: A): Tree[A, B] = blacken(doTo(tree, to))
+ def until[A: Ordering, B](tree: Tree[A, B], key: A): Tree[A, B] = blacken(doUntil(tree, key))
+
+ def drop[A: Ordering, B](tree: Tree[A, B], n: Int): Tree[A, B] = blacken(doDrop(tree, n))
+ def take[A: Ordering, B](tree: Tree[A, B], n: Int): Tree[A, B] = blacken(doTake(tree, n))
+ def slice[A: Ordering, B](tree: Tree[A, B], from: Int, until: Int): Tree[A, B] = blacken(doSlice(tree, from, until))
+
+ def smallest[A, B](tree: Tree[A, B]): Tree[A, B] = {
+ if (tree eq null) throw new NoSuchElementException("empty tree")
+ var result = tree
+ while (result.left ne null) result = result.left
+ result
+ }
+ def greatest[A, B](tree: Tree[A, B]): Tree[A, B] = {
+ if (tree eq null) throw new NoSuchElementException("empty tree")
+ var result = tree
+ while (result.right ne null) result = result.right
+ result
+ }
+
+ def tail[A, B](tree: Tree[A, B]): Tree[A, B] = {
+ def _tail(tree: Tree[A, B]): Tree[A, B] =
+ if (tree eq null) throw new NoSuchElementException("empty tree")
+ else {
+ val tl = tree.left
+ if (tl eq null) tree.right
+ else if (tl.isBlack) balLeft(tree, _tail(tl), tree.right)
+ else tree.redWithLeft(_tail(tree.left))
+ }
+ blacken(_tail(tree))
+ }
+
+ def init[A, B](tree: Tree[A, B]): Tree[A, B] = {
+ def _init(tree: Tree[A, B]): Tree[A, B] =
+ if (tree eq null) throw new NoSuchElementException("empty tree")
+ else {
+ val tr = tree.right
+ if (tr eq null) tree.left
+ else if (tr.isBlack) balRight(tree, tree.left, _init(tr))
+ else tree.redWithRight(_init(tr))
+ }
+ blacken(_init(tree))
+ }
+
+ /**
+ * Returns the smallest node with a key larger than or equal to `x`. Returns `null` if there is no such node.
+ */
+ def minAfter[A, B](tree: Tree[A, B], x: A)(implicit ordering: Ordering[A]): Tree[A, B] = if (tree eq null) null else {
+ val cmp = ordering.compare(x, tree.key)
+ if (cmp == 0) tree
+ else if (cmp < 0) {
+ val l = minAfter(tree.left, x)
+ if (l != null) l else tree
+ } else minAfter(tree.right, x)
+ }
+
+ /**
+ * Returns the largest node with a key smaller than `x`. Returns `null` if there is no such node.
+ */
+ def maxBefore[A, B](tree: Tree[A, B], x: A)(implicit ordering: Ordering[A]): Tree[A, B] = if (tree eq null) null else {
+ val cmp = ordering.compare(x, tree.key)
+ if (cmp <= 0) maxBefore(tree.left, x)
+ else {
+ val r = maxBefore(tree.right, x)
+ if (r != null) r else tree
+ }
+ }
+
+ def foreach[A,B,U](tree:Tree[A,B], f:((A,B)) => U):Unit = if (tree ne null) _foreach(tree,f)
+
+ def keysEqual[A: Ordering, X, Y](a: Tree[A, X], b: Tree[A, Y]): Boolean = {
+ if (a eq b) true
+ else if (a eq null) false
+ else if (b eq null) false
+ else a.count == b.count && (new EqualsIterator(a)).sameKeys(new EqualsIterator(b))
+ }
+ def valuesEqual[A: Ordering, X, Y](a: Tree[A, X], b: Tree[A, Y]): Boolean = {
+ if (a eq b) true
+ else if (a eq null) false
+ else if (b eq null) false
+ else a.count == b.count && (new EqualsIterator(a)).sameValues(new EqualsIterator(b))
+ }
+ def entriesEqual[A: Ordering, X, Y](a: Tree[A, X], b: Tree[A, Y]): Boolean = {
+ if (a eq b) true
+ else if (a eq null) false
+ else if (b eq null) false
+ else a.count == b.count && (new EqualsIterator(a)).sameEntries(new EqualsIterator(b))
+ }
+
+ private[this] def _foreach[A, B, U](tree: Tree[A, B], f: ((A, B)) => U): Unit = {
+ if (tree.left ne null) _foreach(tree.left, f)
+ f((tree.key, tree.value))
+ if (tree.right ne null) _foreach(tree.right, f)
+ }
+
+ def foreachKey[A, U](tree:Tree[A,_], f: A => U):Unit = if (tree ne null) _foreachKey(tree,f)
+
+ private[this] def _foreachKey[A, U](tree: Tree[A, _], f: A => U): Unit = {
+ if (tree.left ne null) _foreachKey(tree.left, f)
+ f((tree.key))
+ if (tree.right ne null) _foreachKey(tree.right, f)
+ }
+
+ def foreachEntry[A, B, U](tree:Tree[A,B], f: (A, B) => U):Unit = if (tree ne null) _foreachEntry(tree,f)
+
+ private[this] def _foreachEntry[A, B, U](tree: Tree[A, B], f: (A, B) => U): Unit = {
+ if (tree.left ne null) _foreachEntry(tree.left, f)
+ f(tree.key, tree.value)
+ if (tree.right ne null) _foreachEntry(tree.right, f)
+ }
+
+ def iterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None): Iterator[(A, B)] = new EntriesIterator(tree, start)
+ def keysIterator[A: Ordering](tree: Tree[A, _], start: Option[A] = None): Iterator[A] = new KeysIterator(tree, start)
+ def valuesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None): Iterator[B] = new ValuesIterator(tree, start)
+
+ @tailrec
+ def nth[A, B](tree: Tree[A, B], n: Int): Tree[A, B] = {
+ val count = this.count(tree.left)
+ if (n < count) nth(tree.left, n)
+ else if (n > count) nth(tree.right, n - count - 1)
+ else tree
+ }
+
+ def isBlack(tree: Tree[_, _]) = (tree eq null) || tree.isBlack
+
+ @`inline` private[this] def isRedTree(tree: Tree[_, _]) = (tree ne null) && tree.isRed
+ @`inline` private[this] def isBlackTree(tree: Tree[_, _]) = (tree ne null) && tree.isBlack
+
+ private[this] def blacken[A, B](t: Tree[A, B]): Tree[A, B] = if (t eq null) null else t.black
+
+ // Blacken if the tree is red and has a red child. This is necessary when using methods such as `upd` or `updNth`
+ // for building subtrees. Use `blacken` instead when building top-level trees.
+ private[this] def maybeBlacken[A, B](t: Tree[A, B]): Tree[A, B] =
+ if(isBlack(t)) t else if(isRedTree(t.left) || isRedTree(t.right)) t.black else t
+
+ private[this] def mkTree[A, B](isBlack: Boolean, key: A, value: B, left: Tree[A, B], right: Tree[A, B]) = {
+ val sizeAndColour = sizeOf(left) + sizeOf(right) + 1 | (if(isBlack) initialBlackCount else initialRedCount)
+ new Tree(key, value.asInstanceOf[AnyRef], left, right, sizeAndColour)
+ }
+
+ /** Create a new balanced tree where `newLeft` replaces `tree.left`. */
+ private[this] def balanceLeft[A, B1](tree: Tree[A, B1], newLeft: Tree[A, B1]): Tree[A, B1] = {
+ // Parameter trees
+ // tree | newLeft
+ // -- KV R | nl.L nl.KV nl.R
+ // | nl.R.L nl.R.KV nl.R.R
+ if (tree.left eq newLeft) tree
+ else {
+ if (newLeft.isRed) {
+ val newLeft_left = newLeft.left
+ val newLeft_right = newLeft.right
+ if (isRedTree(newLeft_left)) {
+ // RED
+ // black(nl.L) nl.KV black
+ // nl.R KV R
+ val resultLeft = newLeft_left.black
+ val resultRight = tree.blackWithLeft(newLeft_right)
+
+ newLeft.withLeftRight(resultLeft, resultRight)
+ } else if (isRedTree(newLeft_right)) {
+ // RED
+ // black nl.R.KV black
+ // nl.L nl.KV nl.R.L nl.R.R KV R
+ val newLeft_right_right = newLeft_right.right
+
+ val resultLeft = newLeft.blackWithRight(newLeft_right.left)
+ val resultRight = tree.blackWithLeft(newLeft_right_right)
+
+ newLeft_right.withLeftRight(resultLeft, resultRight)
+ } else {
+ // tree
+ // newLeft KV R
+ tree.withLeft(newLeft)
+ }
+ } else {
+ // tree
+ // newLeft KV R
+ tree.withLeft(newLeft)
+ }
+ }
+ }
+ /** Create a new balanced tree where `newRight` replaces `tree.right`. */
+ private[this] def balanceRight[A, B1](tree: Tree[A, B1], newRight: Tree[A, B1]): Tree[A, B1] = {
+ // Parameter trees
+ // tree | newRight
+ // L KV -- | nr.L nr.KV nr.R
+ // | nr.L.L nr.L.KV nr.L.R
+ if (tree.right eq newRight) tree
+ else {
+ if (newRight.isRed) {
+ val newRight_left = newRight.left
+ if (isRedTree(newRight_left)) {
+ // RED
+ // black nr.L.KV black
+ // L KV nr.L.L nr.L.R nr.KV nr.R
+ val resultLeft = tree.blackWithRight(newRight_left.left)
+ val resultRight = newRight.blackWithLeft(newRight_left.right)
+
+ newRight_left.withLeftRight(resultLeft, resultRight)
+ } else {
+ val newRight_right = newRight.right
+ if (isRedTree(newRight_right)) {
+ // RED
+ // black nr.KV black(nr.R)
+ // L KV nr.L
+ val resultLeft = tree.blackWithRight(newRight_left)
+ val resultRight = newRight_right.black
+
+ newRight.withLeftRight(resultLeft, resultRight)
+ } else {
+ // tree
+ // L KV newRight
+ tree.withRight(newRight)
+ }
+ }
+ } else {
+ // tree
+ // L KV newRight
+ tree.withRight(newRight)
+ }
+ }
+ }
+
+ private[this] def upd[A, B, B1 >: B](tree: Tree[A, B], k: A, v: B1, overwrite: Boolean)(implicit ordering: Ordering[A]): Tree[A, B1] = if (tree eq null) {
+ RedTree(k, v, null, null)
+ } else if (k.asInstanceOf[AnyRef] eq tree.key.asInstanceOf[AnyRef]) {
+ if (overwrite)
+ tree.withV(v)
+ else tree
+ } else {
+ val cmp = ordering.compare(k, tree.key)
+ if (cmp < 0)
+ balanceLeft(tree, upd(tree.left, k, v, overwrite))
+ else if (cmp > 0)
+ balanceRight(tree, upd(tree.right, k, v, overwrite))
+ else if (overwrite && (v.asInstanceOf[AnyRef] ne tree.value.asInstanceOf[AnyRef]))
+ tree.withV(v)
+ else tree
+ }
+ private[this] def updNth[A, B, B1 >: B](tree: Tree[A, B], idx: Int, k: A, v: B1): Tree[A, B1] = if (tree eq null) {
+ RedTree(k, v, null, null)
+ } else {
+ val rank = count(tree.left) + 1
+ if (idx < rank)
+ balanceLeft(tree, updNth(tree.left, idx, k, v))
+ else if (idx > rank)
+ balanceRight(tree, updNth(tree.right, idx - rank, k, v))
+ else tree
+ }
+
+ private[this] def doFrom[A, B](tree: Tree[A, B], from: A)(implicit ordering: Ordering[A]): Tree[A, B] = {
+ if (tree eq null) return null
+ if (ordering.lt(tree.key, from)) return doFrom(tree.right, from)
+ val newLeft = doFrom(tree.left, from)
+ if (newLeft eq tree.left) tree
+ else if (newLeft eq null) maybeBlacken(upd(tree.right, tree.key, tree.value, overwrite = false))
+ else join(newLeft, tree.key, tree.value, tree.right)
+ }
+ private[this] def doTo[A, B](tree: Tree[A, B], to: A)(implicit ordering: Ordering[A]): Tree[A, B] = {
+ if (tree eq null) return null
+ if (ordering.lt(to, tree.key)) return doTo(tree.left, to)
+ val newRight = doTo(tree.right, to)
+ if (newRight eq tree.right) tree
+ else if (newRight eq null) maybeBlacken(upd(tree.left, tree.key, tree.value, overwrite = false))
+ else join(tree.left, tree.key, tree.value, newRight)
+ }
+ private[this] def doUntil[A, B](tree: Tree[A, B], until: A)(implicit ordering: Ordering[A]): Tree[A, B] = {
+ if (tree eq null) return null
+ if (ordering.lteq(until, tree.key)) return doUntil(tree.left, until)
+ val newRight = doUntil(tree.right, until)
+ if (newRight eq tree.right) tree
+ else if (newRight eq null) maybeBlacken(upd(tree.left, tree.key, tree.value, overwrite = false))
+ else join(tree.left, tree.key, tree.value, newRight)
+ }
+
+ private[this] def doRange[A, B](tree: Tree[A, B], from: A, until: A)(implicit ordering: Ordering[A]): Tree[A, B] = {
+ if (tree eq null) return null
+ if (ordering.lt(tree.key, from)) return doRange(tree.right, from, until)
+ if (ordering.lteq(until, tree.key)) return doRange(tree.left, from, until)
+ val newLeft = doFrom(tree.left, from)
+ val newRight = doUntil(tree.right, until)
+ if ((newLeft eq tree.left) && (newRight eq tree.right)) tree
+ else if (newLeft eq null) upd(newRight, tree.key, tree.value, overwrite = false)
+ else if (newRight eq null) upd(newLeft, tree.key, tree.value, overwrite = false)
+ else join(newLeft, tree.key, tree.value, newRight)
+ }
+
+ private[this] def doDrop[A, B](tree: Tree[A, B], n: Int): Tree[A, B] =
+ if((tree eq null) || (n <= 0)) tree
+ else if(n >= tree.count) null
+ else {
+ val l = count(tree.left)
+ if(n > l) doDrop(tree.right, n-l-1)
+ else if(n == l) join(null, tree.key, tree.value, tree.right)
+ else join(doDrop(tree.left, n), tree.key, tree.value, tree.right)
+ }
+
+ private[this] def doTake[A, B](tree: Tree[A, B], n: Int): Tree[A, B] =
+ if((tree eq null) || (n <= 0)) null
+ else if(n >= tree.count) tree
+ else {
+ val l = count(tree.left)
+ if(n <= l) doTake(tree.left, n)
+ else if(n == l+1) maybeBlacken(updNth(tree.left, n, tree.key, tree.value))
+ else join(tree.left, tree.key, tree.value, doTake(tree.right, n-l-1))
+ }
+
+ private[this] def doSlice[A, B](tree: Tree[A, B], from: Int, until: Int): Tree[A, B] =
+ if((tree eq null) || (from >= until) || (from >= tree.count) || (until <= 0)) null
+ else if((from <= 0) && (until >= tree.count)) tree
+ else {
+ val l = count(tree.left)
+ if(until <= l) doSlice(tree.left, from, until)
+ else if(from > l) doSlice(tree.right, from-l-1, until-l-1)
+ else join(doDrop(tree.left, from), tree.key, tree.value, doTake(tree.right, until-l-1))
+ }
+
+ /*
+ * Forcing direct fields access using the @`inline` annotation helps speed up
+ * various operations (especially smallest/greatest and update/delete).
+ *
+ * Unfortunately the direct field access is not guaranteed to work (but
+ * works on the current implementation of the Scala compiler).
+ *
+ * An alternative is to implement the these classes using plain old Java code...
+ *
+ * Mutability
+ * This implementation encodes both mutable and immutable trees.
+ * Mutable trees are never exposed to the user code but we get significant reductions in both CPU and allocations
+ * by maintaining a mutable tree during internal operations, e.g. a builder building a Tree, and the other bulk
+ * API such as filter or ++
+ *
+ * Mutable trees are only used within the confines of this bulk operation and not shared
+ * Mutable trees may transition to become immutable by calling beforePublish
+ * Mutable trees may have child nodes (left and right) which are immutable Trees (this promotes structural sharing)
+ *
+ * Immutable trees may only child nodes (left and right) which are immutable Trees, and as such the immutable
+ * trees the entire transitive subtree is immutable
+ *
+ * Colour, mutablity and size encoding
+ * The colour of the Tree, its mutablity and size are all encoded in the _count field
+ * The colour is encoded in the top bit (31) of the _count. This allows a mutable tree to change colour without
+ * additional allocation
+ * The mutable trees always have bits 0 .. 30 (inclusive) set to 0
+ * The immutable trees always have bits 0 .. 30 containing the size of the transitive subtree
+ *
+ * Naming
+ * All of the methods that can yield a mutable result have "mutable" on their name, and generally there
+ * is another method similarly named with doesn't. This is to aid safety and to reduce the cognitive load when
+ * reviewing changes. e.g.
+ * def upd(...) will update an immutable Tree, producing an immutable Tree
+ * def mutableUpd(...) will update a mutable or immutable Tree and may return a mutable or immutable Tree
+ * a method that has mutable in its name may return a immutable tree if the operation can reuse the existing tree
+ *
+ */
+ private[immutable] final class Tree[A, +B](
+ @(`inline` @getter @setter) private var _key: A,
+ @(`inline` @getter @setter) private var _value: AnyRef,
+ @(`inline` @getter @setter) private var _left: Tree[A, _],
+ @(`inline` @getter @setter) private var _right: Tree[A, _],
+ @(`inline` @getter @setter) private var _count: Int)
+ {
+ @`inline` private[RedBlackTree] def isMutable: Boolean = (_count & colourMask) == 0
+ // read only APIs
+ @`inline` private[RedBlackTree] final def count = {
+ //devTimeAssert((_count & 0x7FFFFFFF) != 0)
+ _count & colourMask
+ }
+ //retain the colour, and mark as mutable
+ @`inline` private def mutableRetainingColour = _count & colourBit
+
+ //inlined here to avoid outer object null checks
+ @`inline` private[RedBlackTree] final def sizeOf(tree:Tree[_,_]) = if (tree eq null) 0 else tree.count
+ @`inline` private[immutable] final def key = _key
+ @`inline` private[immutable] final def value = _value.asInstanceOf[B]
+ @`inline` private[immutable] final def left = _left.asInstanceOf[Tree[A, B]]
+ @`inline` private[immutable] final def right = _right.asInstanceOf[Tree[A, B]]
+ //Note - only used in tests outside RedBlackTree
+ @`inline` private[immutable] final def isBlack = _count < 0
+ //Note - only used in tests outside RedBlackTree
+ @`inline` private[immutable] final def isRed = _count >= 0
+
+ override def toString: String = s"${if(isRed) "RedTree" else "BlackTree"}($key, $value, $left, $right)"
+
+ //mutable APIs
+ private[RedBlackTree] def makeImmutable: this.type = {
+ def makeImmutableImpl(): Unit = {
+ if (isMutable) {
+ var size = 1
+ if (_left ne null) {
+ _left.makeImmutable
+ size += _left.count
+ }
+ if (_right ne null) {
+ _right.makeImmutable
+ size += _right.count
+ }
+ _count |= size //retains colour
+ }
+ }
+ makeImmutableImpl()
+ this
+ }
+
+ private[RedBlackTree] def mutableBlack: Tree[A, B] = {
+ if (isBlack) this
+ else if (isMutable) {
+ _count = initialBlackCount
+ this
+ }
+ else new Tree(_key, _value, _left, _right, initialBlackCount)
+ }
+// private[RedBlackTree] def mutableRed: Tree[A, B] = {
+// if (isRed) this
+// else if (mutable) {
+// _count = initialRedCount
+// this
+// }
+// else new Tree(_key, _value, _left, _right, initialRedCount)
+// }
+
+ private[RedBlackTree] def mutableWithV[B1 >: B](newValue: B1): Tree[A, B1] = {
+ if (newValue.asInstanceOf[AnyRef] eq _value.asInstanceOf[AnyRef]) this
+ else if (isMutable) {
+ _value = newValue.asInstanceOf[AnyRef]
+ this
+ } else new Tree(_key, newValue.asInstanceOf[AnyRef], _left, _right, mutableRetainingColour)
+ }
+
+ private[RedBlackTree] def mutableWithLeft[B1 >: B](newLeft: Tree[A, B1]): Tree[A, B1] = {
+ if (_left eq newLeft) this
+ else if (isMutable) {
+ _left = newLeft
+ this
+ } else new Tree(_key, _value, newLeft, _right, mutableRetainingColour)
+ }
+ private[RedBlackTree] def mutableWithRight[B1 >: B](newRight: Tree[A, B1]): Tree[A, B1] = {
+ if (_right eq newRight) this
+ else if (isMutable) {
+ _right = newRight
+ this
+ } else new Tree(_key, _value, _left, newRight, mutableRetainingColour)
+ }
+ private[RedBlackTree] def mutableWithLeftRight[B1 >: B](newLeft: Tree[A, B1], newRight: Tree[A, B1]): Tree[A, B1] = {
+ if ((_left eq newLeft) && (_right eq newRight)) this
+ else if (isMutable) {
+ _left = newLeft
+ _right = newRight
+ this
+ } else new Tree(_key, _value, newLeft, newRight, mutableRetainingColour)
+ }
+ private[RedBlackTree] def mutableBlackWithLeft[B1 >: B](newLeft: Tree[A, B1]): Tree[A, B1] = {
+ if ((_left eq newLeft) && isBlack) this
+ else if (isMutable) {
+ _count = initialBlackCount
+ _left = newLeft
+ this
+ } else new Tree(_key, _value, newLeft, _right, initialBlackCount)
+ }
+ private[RedBlackTree] def mutableBlackWithRight[B1 >: B](newRight: Tree[A, B1]): Tree[A, B1] = {
+ if ((_right eq newRight) && isBlack) this
+ else if (isMutable) {
+ _count = initialBlackCount
+ _right = newRight
+ this
+ } else new Tree(_key, _value, _left, newRight, initialBlackCount)
+ }
+
+ private[RedBlackTree] def black: Tree[A, B] = {
+ //assertNotMutable(this)
+ if (isBlack) this
+ else new Tree(_key, _value, _left, _right, _count ^ colourBit)
+ }
+ private[RedBlackTree] def red: Tree[A, B] = {
+ //assertNotMutable(this)
+ if (isRed) this
+ else new Tree(_key, _value, _left, _right, _count ^ colourBit)
+ }
+ private[RedBlackTree] def withKV[B1 >: B](newKey: A, newValue: B1): Tree[A, B1] = {
+ //assertNotMutable(this)
+ if ((newKey.asInstanceOf[AnyRef] eq _key.asInstanceOf[AnyRef]) &&
+ (newValue.asInstanceOf[AnyRef] eq _value.asInstanceOf[AnyRef])) this
+ else new Tree(newKey, newValue.asInstanceOf[AnyRef], _left, _right, _count)
+ }
+ private[RedBlackTree] def withV[B1 >: B](newValue: B1): Tree[A, B1] = {
+ //assertNotMutable(this)
+ if (newValue.asInstanceOf[AnyRef] eq _value.asInstanceOf[AnyRef]) this
+ else new Tree(_key, newValue.asInstanceOf[AnyRef], _left, _right, _count)
+ }
+
+ private[RedBlackTree] def withLeft[B1 >: B](newLeft: Tree[A, B1]): Tree[A, B1] = {
+ //assertNotMutable(this)
+ //assertNotMutable(newLeft)
+ if (newLeft eq _left) this
+ else {
+ val size = sizeOf(newLeft) + sizeOf(_right) + 1
+ new Tree(key, value.asInstanceOf[AnyRef], newLeft, _right, (_count & colourBit) | size)
+ }
+ }
+ private[RedBlackTree] def withRight[B1 >: B](newRight: Tree[A, B1]): Tree[A, B1] = {
+ //assertNotMutable(this)
+ //assertNotMutable(newRight)
+ if (newRight eq _right) this
+ else {
+ val size = sizeOf(_left) + sizeOf(newRight) + 1
+ new Tree(key, value.asInstanceOf[AnyRef], _left, newRight, (_count & colourBit) | size)
+ }
+ }
+ private[RedBlackTree] def blackWithLeft[B1 >: B](newLeft: Tree[A, B1]): Tree[A, B1] = {
+ //assertNotMutable(this)
+ //assertNotMutable(newLeft)
+ if ((newLeft eq _left) && isBlack) this
+ else {
+ val size = sizeOf(newLeft) + sizeOf(_right) + 1
+ new Tree(key, value.asInstanceOf[AnyRef], newLeft, _right, initialBlackCount | size)
+ }
+ }
+ private[RedBlackTree] def redWithLeft[B1 >: B](newLeft: Tree[A, B1]): Tree[A, B1] = {
+ //assertNotMutable(this)
+ //assertNotMutable(newLeft)
+ if ((newLeft eq _left) && isRed) this
+ else {
+ val size = sizeOf(newLeft) + sizeOf(_right) + 1
+ new Tree(key, value.asInstanceOf[AnyRef], newLeft, _right, initialRedCount | size)
+ }
+ }
+ private[RedBlackTree] def blackWithRight[B1 >: B](newRight: Tree[A, B1]): Tree[A, B1] = {
+ //assertNotMutable(this)
+ //assertNotMutable(newRight)
+ if ((newRight eq _right) && isBlack) this
+ else {
+ val size = sizeOf(_left) + sizeOf(newRight) + 1
+ new Tree(key, value.asInstanceOf[AnyRef], _left, newRight, initialBlackCount | size)
+ }
+ }
+ private[RedBlackTree] def redWithRight[B1 >: B](newRight: Tree[A, B1]): Tree[A, B1] = {
+ //assertNotMutable(this)
+ //assertNotMutable(newLeft)
+ if ((newRight eq _right) && isRed) this
+ else {
+ val size = sizeOf(_left) + sizeOf(newRight) + 1
+ new Tree(key, value.asInstanceOf[AnyRef], _left, newRight, initialRedCount | size)
+ }
+ }
+ private[RedBlackTree] def withLeftRight[B1 >: B](newLeft: Tree[A, B1], newRight: Tree[A, B1]): Tree[A, B1] = {
+ //assertNotMutable(this)
+ //assertNotMutable(newLeft)
+ //assertNotMutable(newRight)
+ if ((newLeft eq _left) && (newRight eq _right)) this
+ else {
+ val size = sizeOf(newLeft) + sizeOf(newRight) + 1
+ new Tree(key, value.asInstanceOf[AnyRef], newLeft, newRight, (_count & colourBit) | size)
+ }
+ }
+ private[RedBlackTree] def redWithLeftRight[B1 >: B](newLeft: Tree[A, B1], newRight: Tree[A, B1]): Tree[A, B1] = {
+ //assertNotMutable(this)
+ //assertNotMutable(newLeft)
+ //assertNotMutable(newRight)
+ if ((newLeft eq _left) && (newRight eq _right) && isRed) this
+ else {
+ val size = sizeOf(newLeft) + sizeOf(newRight) + 1
+ new Tree(key, value.asInstanceOf[AnyRef], newLeft, newRight, initialRedCount | size)
+ }
+ }
+ private[RedBlackTree] def blackWithLeftRight[B1 >: B](newLeft: Tree[A, B1], newRight: Tree[A, B1]): Tree[A, B1] = {
+ //assertNotMutable(this)
+ //assertNotMutable(newLeft)
+ //assertNotMutable(newRight)
+ if ((newLeft eq _left) && (newRight eq _right) && isBlack) this
+ else {
+ val size = sizeOf(newLeft) + sizeOf(newRight) + 1
+ new Tree(key, value.asInstanceOf[AnyRef], newLeft, newRight, initialBlackCount | size)
+ }
+ }
+ }
+ //see #Tree docs "Colour, mutablity and size encoding"
+ //we make these final vals because the optimiser inlines them, without reference to the enclosing module
+ private[RedBlackTree] final val colourBit = 0x80000000
+ private[RedBlackTree] final val colourMask = ~colourBit
+ private[RedBlackTree] final val initialBlackCount = colourBit
+ private[RedBlackTree] final val initialRedCount = 0
+
+ @`inline` private[RedBlackTree] def mutableRedTree[A, B](key: A, value: B, left: Tree[A, B], right: Tree[A, B]) = new Tree[A,B](key, value.asInstanceOf[AnyRef], left, right, initialRedCount)
+ @`inline` private[RedBlackTree] def mutableBlackTree[A, B](key: A, value: B, left: Tree[A, B], right: Tree[A, B]) = new Tree[A,B](key, value.asInstanceOf[AnyRef], left, right, initialBlackCount)
+
+ /** create a new immutable red tree.
+ * left and right may be null
+ */
+ private[immutable] def RedTree[A, B](key: A, value: B, left: Tree[A, B], right: Tree[A, B]): Tree[A, B] = {
+ //assertNotMutable(left)
+ //assertNotMutable(right)
+ val size = sizeOf(left) + sizeOf(right) + 1
+ new Tree(key, value.asInstanceOf[AnyRef], left, right, initialRedCount | size)
+ }
+ private[immutable] def BlackTree[A, B](key: A, value: B, left: Tree[A, B], right: Tree[A, B]): Tree[A, B] = {
+ //assertNotMutable(left)
+ //assertNotMutable(right)
+ val size = sizeOf(left) + sizeOf(right) + 1
+ new Tree(key, value.asInstanceOf[AnyRef], left, right, initialBlackCount | size)
+ }
+ @`inline` private def sizeOf(tree:Tree[_,_]) = if (tree eq null) 0 else tree.count
+ //immutable APIs
+ //assertions - uncomment decls and callers when changing functionality
+ // private def devTimeAssert(assertion: Boolean) = {
+ // //uncomment this during development of the functionality
+ // assert(assertion)
+ // }
+ // private def assertNotMutable(t:Tree[_,_]) = {
+ // devTimeAssert ((t eq null) || t.count > 0)
+ // }
+ private[this] abstract class TreeIterator[A, B, R](root: Tree[A, B], start: Option[A])(protected implicit val ordering: Ordering[A]) extends AbstractIterator[R] {
+ protected[this] def nextResult(tree: Tree[A, B]): R
+
+ override def hasNext: Boolean = lookahead ne null
+
+ @throws[NoSuchElementException]
+ override def next(): R = {
+ val tree = lookahead
+ if(tree ne null) {
+ lookahead = findLeftMostOrPopOnEmpty(goRight(tree))
+ nextResult(tree)
+ } else Iterator.empty.next()
+ }
+
+ @tailrec
+ protected final def findLeftMostOrPopOnEmpty(tree: Tree[A, B]): Tree[A, B] =
+ if (tree eq null) popNext()
+ else if (tree.left eq null) tree
+ else findLeftMostOrPopOnEmpty(goLeft(tree))
+
+ @`inline` private[this] def pushNext(tree: Tree[A, B]): Unit = {
+ stackOfNexts(index) = tree
+ index += 1
+ }
+ @`inline` protected final def popNext(): Tree[A, B] = if (index == 0) null else {
+ index -= 1
+ stackOfNexts(index)
+ }
+
+ protected[this] val stackOfNexts = if (root eq null) null else {
+ /*
+ * According to "Ralf Hinze. Constructing red-black trees" [https://www.cs.ox.ac.uk/ralf.hinze/publications/#P5]
+ * the maximum height of a red-black tree is 2*log_2(n + 2) - 2.
+ *
+ * According to {@see Integer#numberOfLeadingZeros} ceil(log_2(n)) = (32 - Integer.numberOfLeadingZeros(n - 1))
+ *
+ * Although we don't store the deepest nodes in the path during iteration,
+ * we potentially do so in `startFrom`.
+ */
+ val maximumHeight = 2 * (32 - Integer.numberOfLeadingZeros(root.count + 2 - 1)) - 2
+ new Array[Tree[A, B]](maximumHeight)
+ }
+ private[this] var index = 0
+ protected var lookahead: Tree[A, B] = if (start.isDefined) startFrom(start.get) else findLeftMostOrPopOnEmpty(root)
+
+ /**
+ * Find the leftmost subtree whose key is equal to the given key, or if no such thing,
+ * the leftmost subtree with the key that would be "next" after it according
+ * to the ordering. Along the way build up the iterator's path stack so that "next"
+ * functionality works.
+ */
+ private[this] def startFrom(key: A) : Tree[A,B] = if (root eq null) null else {
+ @tailrec def find(tree: Tree[A, B]): Tree[A, B] =
+ if (tree eq null) popNext()
+ else find(
+ if (ordering.lteq(key, tree.key)) goLeft(tree)
+ else goRight(tree)
+ )
+ find(root)
+ }
+
+ @`inline` private[this] def goLeft(tree: Tree[A, B]) = {
+ pushNext(tree)
+ tree.left
+ }
+
+ @`inline` protected final def goRight(tree: Tree[A, B]) = tree.right
+ }
+
+ private[this] class EqualsIterator[A: Ordering, B](tree: Tree[A, B]) extends TreeIterator[A, B, Unit](tree, None) {
+ override def nextResult(tree: Tree[A, B]): Nothing = ???
+
+ def sameKeys[X](that:EqualsIterator[A,X]): Boolean = {
+ var equal = true
+ while (equal && (this.lookahead ne null) && (that.lookahead ne null)) {
+ if (this.lookahead eq that.lookahead) {
+ this.lookahead = this.popNext()
+ that.lookahead = that.popNext()
+ } else {
+ equal = (this.lookahead.key.asInstanceOf[AnyRef] eq that.lookahead.key.asInstanceOf[AnyRef]) ||
+ ordering.equiv(this.lookahead.key, that.lookahead.key)
+ this.lookahead = this.findLeftMostOrPopOnEmpty(this.goRight(this.lookahead))
+ that.lookahead = that.findLeftMostOrPopOnEmpty(that.goRight(that.lookahead))
+ }
+ }
+ equal && (this.lookahead eq null) && (that.lookahead eq null)
+ }
+ def sameValues[X](that:EqualsIterator[A,X]): Boolean = {
+ var equal = true
+ while (equal && (this.lookahead ne null) && (that.lookahead ne null)) {
+ if (this.lookahead eq that.lookahead) {
+ this.lookahead = this.popNext()
+ that.lookahead = that.popNext()
+ } else {
+ equal = this.lookahead.value == that.lookahead.value
+ this.lookahead = this.findLeftMostOrPopOnEmpty(this.goRight(this.lookahead))
+ that.lookahead = that.findLeftMostOrPopOnEmpty(that.goRight(that.lookahead))
+ }
+ }
+ equal && (this.lookahead eq null) && (that.lookahead eq null)
+ }
+ def sameEntries[X](that:EqualsIterator[A,X]): Boolean = {
+ var equal = true
+ while (equal && (this.lookahead ne null) && (that.lookahead ne null)) {
+ if (this.lookahead eq that.lookahead) {
+ this.lookahead = this.popNext()
+ that.lookahead = that.popNext()
+ } else {
+ equal = ((this.lookahead.key.asInstanceOf[AnyRef] eq that.lookahead.key.asInstanceOf[AnyRef]) ||
+ ordering.equiv(this.lookahead.key, that.lookahead.key)) && this.lookahead.value == that.lookahead.value
+ this.lookahead = this.findLeftMostOrPopOnEmpty(this.goRight(this.lookahead))
+ that.lookahead = that.findLeftMostOrPopOnEmpty(that.goRight(that.lookahead))
+ }
+ }
+ equal && (this.lookahead eq null) && (that.lookahead eq null)
+ }
+ }
+ private[this] class EntriesIterator[A: Ordering, B](tree: Tree[A, B], focus: Option[A]) extends TreeIterator[A, B, (A, B)](tree, focus) {
+ override def nextResult(tree: Tree[A, B]) = (tree.key, tree.value)
+ }
+
+ private[this] class KeysIterator[A: Ordering, B](tree: Tree[A, B], focus: Option[A]) extends TreeIterator[A, B, A](tree, focus) {
+ override def nextResult(tree: Tree[A, B]) = tree.key
+ }
+
+ private[this] class ValuesIterator[A: Ordering, B](tree: Tree[A, B], focus: Option[A]) extends TreeIterator[A, B, B](tree, focus) {
+ override def nextResult(tree: Tree[A, B]) = tree.value
+ }
+
+ /** Build a Tree suitable for a TreeSet from an ordered sequence of keys */
+ def fromOrderedKeys[A](xs: Iterator[A], size: Int): Tree[A, Null] = {
+ val maxUsedDepth = 32 - Integer.numberOfLeadingZeros(size) // maximum depth of non-leaf nodes
+ def f(level: Int, size: Int): Tree[A, Null] = size match {
+ case 0 => null
+ case 1 => mkTree(level != maxUsedDepth || level == 1, xs.next(), null, null, null)
+ case n =>
+ val leftSize = (size-1)/2
+ val left = f(level+1, leftSize)
+ val x = xs.next()
+ val right = f(level+1, size-1-leftSize)
+ BlackTree(x, null, left, right)
+ }
+ f(1, size)
+ }
+
+ /** Build a Tree suitable for a TreeMap from an ordered sequence of key/value pairs */
+ def fromOrderedEntries[A, B](xs: Iterator[(A, B)], size: Int): Tree[A, B] = {
+ val maxUsedDepth = 32 - Integer.numberOfLeadingZeros(size) // maximum depth of non-leaf nodes
+ def f(level: Int, size: Int): Tree[A, B] = size match {
+ case 0 => null
+ case 1 =>
+ val (k, v) = xs.next()
+ mkTree(level != maxUsedDepth || level == 1, k, v, null, null)
+ case n =>
+ val leftSize = (size-1)/2
+ val left = f(level+1, leftSize)
+ val (k, v) = xs.next()
+ val right = f(level+1, size-1-leftSize)
+ BlackTree(k, v, left, right)
+ }
+ f(1, size)
+ }
+
+ def transform[A, B, C](t: Tree[A, B], f: (A, B) => C): Tree[A, C] =
+ if(t eq null) null
+ else {
+ val k = t.key
+ val v = t.value
+ val l = t.left
+ val r = t.right
+ val l2 = transform(l, f)
+ val v2 = f(k, v)
+ val r2 = transform(r, f)
+ if((v2.asInstanceOf[AnyRef] eq v.asInstanceOf[AnyRef])
+ && (l2 eq l)
+ && (r2 eq r)) t.asInstanceOf[Tree[A, C]]
+ else mkTree(t.isBlack, k, v2, l2, r2)
+ }
+
+ def filterEntries[A, B](t: Tree[A, B], f: (A, B) => Boolean): Tree[A, B] = if(t eq null) null else {
+ def fk(t: Tree[A, B]): Tree[A, B] = {
+ val k = t.key
+ val v = t.value
+ val l = t.left
+ val r = t.right
+ val l2 = if(l eq null) null else fk(l)
+ val keep = f(k, v)
+ val r2 = if(r eq null) null else fk(r)
+ if(!keep) join2(l2, r2)
+ else if((l2 eq l) && (r2 eq r)) t
+ else join(l2, k, v, r2)
+ }
+ blacken(fk(t))
+ }
+
+ private[this] val null2 = (null, null)
+
+ def partitionEntries[A, B](t: Tree[A, B], p: (A, B) => Boolean): (Tree[A, B], Tree[A, B]) = if(t eq null) (null, null) else {
+ if (t eq null) null2
+ else {
+ object partitioner {
+ var tmpk, tmpd = null: Tree[A, B] // shared vars to avoid returning tuples from fk
+ def fk(t: Tree[A, B]): Unit = {
+ val k = t.key
+ val v = t.value
+ val l = t.left
+ val r = t.right
+ var l2k, l2d, r2k, r2d = null: Tree[A, B]
+ if (l ne null) {
+ fk(l)
+ l2k = tmpk
+ l2d = tmpd
+ }
+ val keep = p(k, v)
+ if (r ne null) {
+ fk(r)
+ r2k = tmpk
+ r2d = tmpd
+ }
+ val jk =
+ if (!keep) join2(l2k, r2k)
+ else if ((l2k eq l) && (r2k eq r)) t
+ else join(l2k, k, v, r2k)
+ val jd =
+ if (keep) join2(l2d, r2d)
+ else if ((l2d eq l) && (r2d eq r)) t
+ else join(l2d, k, v, r2d)
+ tmpk = jk
+ tmpd = jd
+ }
+ }
+
+ partitioner.fk(t)
+ (blacken(partitioner.tmpk), blacken(partitioner.tmpd))
+ }
+ }
+
+ // Based on Stefan Kahrs' Haskell version of Okasaki's Red&Black Trees
+ // Constructing Red-Black Trees, Ralf Hinze: [[https://www.cs.ox.ac.uk/ralf.hinze/publications/WAAAPL99b.ps.gz]]
+ // Red-Black Trees in a Functional Setting, Chris Okasaki: [[https://wiki.rice.edu/confluence/download/attachments/2761212/Okasaki-Red-Black.pdf]] */
+
+ private[this] def del[A, B](tree: Tree[A, B], k: A)(implicit ordering: Ordering[A]): Tree[A, B] = if (tree eq null) null else {
+ val cmp = ordering.compare(k, tree.key)
+ if (cmp < 0) {
+ val newLeft = del(tree.left, k)
+ if (newLeft eq tree.left) tree
+ else if (isBlackTree(tree.left)) balLeft(tree, newLeft, tree.right)
+ else tree.redWithLeft(newLeft)
+ } else if (cmp > 0) {
+ val newRight = del(tree.right, k)
+ if (newRight eq tree.right) tree
+ else if (isBlackTree(tree.right)) balRight(tree, tree.left, newRight)
+ else tree.redWithRight(newRight)
+ } else append(tree.left, tree.right)
+ }
+
+ private[this] def balance[A, B](tree: Tree[A,B], tl: Tree[A, B], tr: Tree[A, B]): Tree[A, B] =
+ if (isRedTree(tl)) {
+ if (isRedTree(tr)) tree.redWithLeftRight(tl.black, tr.black)
+ else if (isRedTree(tl.left)) tl.withLeftRight(tl.left.black, tree.blackWithLeftRight(tl.right, tr))
+ else if (isRedTree(tl.right)) tl.right.withLeftRight(tl.blackWithRight(tl.right.left), tree.blackWithLeftRight(tl.right.right, tr))
+ else tree.blackWithLeftRight(tl, tr)
+ } else if (isRedTree(tr)) {
+ if (isRedTree(tr.right)) tr.withLeftRight(tree.blackWithLeftRight(tl, tr.left), tr.right.black)
+ else if (isRedTree(tr.left)) tr.left.withLeftRight(tree.blackWithLeftRight(tl, tr.left.left), tr.blackWithLeftRight(tr.left.right, tr.right))
+ else tree.blackWithLeftRight(tl, tr)
+ } else tree.blackWithLeftRight(tl, tr)
+
+ private[this] def balLeft[A, B](tree: Tree[A,B], tl: Tree[A, B], tr: Tree[A, B]): Tree[A, B] =
+ if (isRedTree(tl)) tree.redWithLeftRight(tl.black, tr)
+ else if (isBlackTree(tr)) balance(tree, tl, tr.red)
+ else if (isRedTree(tr) && isBlackTree(tr.left))
+ tr.left.redWithLeftRight(tree.blackWithLeftRight(tl, tr.left.left), balance(tr, tr.left.right, tr.right.red))
+ else sys.error("Defect: invariance violation")
+
+ private[this] def balRight[A, B](tree: Tree[A,B], tl: Tree[A, B], tr: Tree[A, B]): Tree[A, B] =
+ if (isRedTree(tr)) tree.redWithLeftRight(tl, tr.black)
+ else if (isBlackTree(tl)) balance(tree, tl.red, tr)
+ else if (isRedTree(tl) && isBlackTree(tl.right))
+ tl.right.redWithLeftRight(balance(tl, tl.left.red, tl.right.left), tree.blackWithLeftRight(tl.right.right, tr))
+ else sys.error("Defect: invariance violation")
+
+ /** `append` is similar to `join2` but requires that both subtrees have the same black height */
+ private[this] def append[A, B](tl: Tree[A, B], tr: Tree[A, B]): Tree[A, B] = {
+ if (tl eq null) tr
+ else if (tr eq null) tl
+ else if (tl.isRed) {
+ if (tr.isRed) {
+ //tl is red, tr is red
+ val bc = append(tl.right, tr.left)
+ if (isRedTree(bc)) bc.withLeftRight(tl.withRight(bc.left), tr.withLeft(bc.right))
+ else tl.withRight(tr.withLeft(bc))
+ } else {
+ //tl is red, tr is black
+ tl.withRight(append(tl.right, tr))
+ }
+ } else {
+ if (tr.isBlack) {
+ //tl is black tr is black
+ val bc = append(tl.right, tr.left)
+ if (isRedTree(bc)) bc.withLeftRight(tl.withRight(bc.left), tr.withLeft(bc.right))
+ else balLeft(tl, tl.left, tr.withLeft(bc))
+ } else {
+ //tl is black tr is red
+ tr.withLeft(append(tl, tr.left))
+ }
+ }
+ }
+
+
+ // Bulk operations based on "Just Join for Parallel Ordered Sets" (https://www.cs.cmu.edu/~guyb/papers/BFS16.pdf)
+ // We don't store the black height in the tree so we pass it down into the join methods and derive the black height
+ // of child nodes from it. Where possible the black height is used directly instead of deriving the rank from it.
+ // Our trees are supposed to have a black root so we always blacken as the last step of union/intersect/difference.
+
+ def union[A, B](t1: Tree[A, B], t2: Tree[A, B])(implicit ordering: Ordering[A]): Tree[A, B] = blacken(_union(t1, t2))
+
+ def intersect[A, B](t1: Tree[A, B], t2: Tree[A, B])(implicit ordering: Ordering[A]): Tree[A, B] = blacken(_intersect(t1, t2))
+
+ def difference[A, B](t1: Tree[A, B], t2: Tree[A, _])(implicit ordering: Ordering[A]): Tree[A, B] =
+ blacken(_difference(t1, t2.asInstanceOf[Tree[A, B]]))
+
+ /** Compute the rank from a tree and its black height */
+ @`inline` private[this] def rank(t: Tree[_, _], bh: Int): Int = {
+ if(t eq null) 0
+ else if(t.isBlack) 2*(bh-1)
+ else 2*bh-1
+ }
+
+ private[this] def joinRight[A, B](tl: Tree[A, B], k: A, v: B, tr: Tree[A, B], bhtl: Int, rtr: Int): Tree[A, B] = {
+ val rtl = rank(tl, bhtl)
+ if(rtl == (rtr/2)*2) RedTree(k, v, tl, tr)
+ else {
+ val tlBlack = isBlackTree(tl)
+ val bhtlr = if(tlBlack) bhtl-1 else bhtl
+ val ttr = joinRight(tl.right, k, v, tr, bhtlr, rtr)
+ if(tlBlack && isRedTree(ttr) && isRedTree(ttr.right))
+ RedTree(ttr.key, ttr.value,
+ BlackTree(tl.key, tl.value, tl.left, ttr.left),
+ ttr.right.black)
+ else mkTree(tlBlack, tl.key, tl.value, tl.left, ttr)
+ }
+ }
+
+ private[this] def joinLeft[A, B](tl: Tree[A, B], k: A, v: B, tr: Tree[A, B], rtl: Int, bhtr: Int): Tree[A, B] = {
+ val rtr = rank(tr, bhtr)
+ if(rtr == (rtl/2)*2) RedTree(k, v, tl, tr)
+ else {
+ val trBlack = isBlackTree(tr)
+ val bhtrl = if(trBlack) bhtr-1 else bhtr
+ val ttl = joinLeft(tl, k, v, tr.left, rtl, bhtrl)
+ if(trBlack && isRedTree(ttl) && isRedTree(ttl.left))
+ RedTree(ttl.key, ttl.value,
+ ttl.left.black,
+ BlackTree(tr.key, tr.value, ttl.right, tr.right))
+ else mkTree(trBlack, tr.key, tr.value, ttl, tr.right)
+ }
+ }
+
+ private[this] def join[A, B](tl: Tree[A, B], k: A, v: B, tr: Tree[A, B]): Tree[A, B] = {
+ @tailrec def h(t: Tree[_, _], i: Int): Int =
+ if(t eq null) i+1 else h(t.left, if(t.isBlack) i+1 else i)
+ val bhtl = h(tl, 0)
+ val bhtr = h(tr, 0)
+ if(bhtl > bhtr) {
+ val tt = joinRight(tl, k, v, tr, bhtl, rank(tr, bhtr))
+ if(isRedTree(tt) && isRedTree(tt.right)) tt.black
+ else tt
+ } else if(bhtr > bhtl) {
+ val tt = joinLeft(tl, k, v, tr, rank(tl, bhtl), bhtr)
+ if(isRedTree(tt) && isRedTree(tt.left)) tt.black
+ else tt
+ } else mkTree(isRedTree(tl) || isRedTree(tr), k, v, tl, tr)
+ }
+
+ private[this] def split[A, B](t: Tree[A, B], k2: A)(implicit ordering: Ordering[A]): (Tree[A, B], Tree[A, B], Tree[A, B], A) =
+ if(t eq null) (null, null, null, k2)
+ else {
+ val cmp = ordering.compare(k2, t.key)
+ if(cmp == 0) (t.left, t, t.right, t.key)
+ else if(cmp < 0) {
+ val (ll, b, lr, k1) = split(t.left, k2)
+ (ll, b, join(lr, t.key, t.value, t.right), k1)
+ } else {
+ val (rl, b, rr, k1) = split(t.right, k2)
+ (join(t.left, t.key, t.value, rl), b, rr, k1)
+ }
+ }
+
+ private[this] def splitLast[A, B](t: Tree[A, B]): (Tree[A, B], A, B) =
+ if(t.right eq null) (t.left, t.key, t.value)
+ else {
+ val (tt, kk, vv) = splitLast(t.right)
+ (join(t.left, t.key, t.value, tt), kk, vv)
+ }
+
+ private[this] def join2[A, B](tl: Tree[A, B], tr: Tree[A, B]): Tree[A, B] =
+ if(tl eq null) tr
+ else if(tr eq null) tl
+ else {
+ val (ttl, k, v) = splitLast(tl)
+ join(ttl, k, v, tr)
+ }
+
+ private[this] def _union[A, B](t1: Tree[A, B], t2: Tree[A, B])(implicit ordering: Ordering[A]): Tree[A, B] =
+ if((t1 eq null) || (t1 eq t2)) t2
+ else if(t2 eq null) t1
+ else {
+ val (l1, _, r1, k1) = split(t1, t2.key)
+ val tl = _union(l1, t2.left)
+ val tr = _union(r1, t2.right)
+ join(tl, k1, t2.value, tr)
+ }
+
+ private[this] def _intersect[A, B](t1: Tree[A, B], t2: Tree[A, B])(implicit ordering: Ordering[A]): Tree[A, B] =
+ if((t1 eq null) || (t2 eq null)) null
+ else if (t1 eq t2) t1
+ else {
+ val (l1, b, r1, k1) = split(t1, t2.key)
+ val tl = _intersect(l1, t2.left)
+ val tr = _intersect(r1, t2.right)
+ if(b ne null) join(tl, k1, t2.value, tr)
+ else join2(tl, tr)
+ }
+
+ private[this] def _difference[A, B](t1: Tree[A, B], t2: Tree[A, B])(implicit ordering: Ordering[A]): Tree[A, B] =
+ if((t1 eq null) || (t2 eq null)) t1
+ else if (t1 eq t2) null
+ else {
+ val (l1, _, r1, _) = split(t1, t2.key)
+ val tl = _difference(l1, t2.left)
+ val tr = _difference(r1, t2.right)
+ join2(tl, tr)
+ }
+}
diff --git a/library/src/scala/collection/immutable/Seq.scala b/library/src/scala/collection/immutable/Seq.scala
new file mode 100644
index 000000000000..81a40c1c375b
--- /dev/null
+++ b/library/src/scala/collection/immutable/Seq.scala
@@ -0,0 +1,155 @@
+/*
+ * 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 collection
+package immutable
+
+trait Seq[+A] extends Iterable[A]
+ with collection.Seq[A]
+ with SeqOps[A, Seq, Seq[A]]
+ with IterableFactoryDefaults[A, Seq] {
+
+ override final def toSeq: this.type = this
+
+ override def iterableFactory: SeqFactory[Seq] = Seq
+}
+
+/**
+ * @define coll immutable sequence
+ * @define Coll `immutable.Seq`
+ */
+trait SeqOps[+A, +CC[_], +C] extends Any with collection.SeqOps[A, CC, C]
+
+/**
+ * $factoryInfo
+ * @define coll immutable sequence
+ * @define Coll `immutable.Seq`
+ */
+@SerialVersionUID(3L)
+object Seq extends SeqFactory.Delegate[Seq](List) {
+ override def from[E](it: IterableOnce[E]): Seq[E] = it match {
+ case s: Seq[E] => s
+ case _ => super.from(it)
+ }
+}
+
+/** Base trait for immutable indexed sequences that have efficient `apply` and `length` */
+trait IndexedSeq[+A] extends Seq[A]
+ with collection.IndexedSeq[A]
+ with IndexedSeqOps[A, IndexedSeq, IndexedSeq[A]]
+ with IterableFactoryDefaults[A, IndexedSeq] {
+
+ final override def toIndexedSeq: IndexedSeq[A] = this
+
+ override def canEqual(that: Any): Boolean = that match {
+ case otherIndexedSeq: IndexedSeq[_] => length == otherIndexedSeq.length && super.canEqual(that)
+ case _ => super.canEqual(that)
+ }
+
+
+ override def sameElements[B >: A](o: IterableOnce[B]): Boolean = o match {
+ case that: IndexedSeq[_] =>
+ (this eq that) || {
+ val length = this.length
+ var equal = length == that.length
+ if (equal) {
+ var index = 0
+ // some IndexedSeq apply is less efficient than using Iterators
+ // e.g. Vector so we can compare the first few with apply and the rest with an iterator
+ // but if apply is more efficient than Iterators then we can use the apply for all the comparison
+ // we default to the minimum preferred length
+ val maxApplyCompare = {
+ val preferredLength = Math.min(applyPreferredMaxLength, that.applyPreferredMaxLength)
+ if (length > (preferredLength.toLong << 1)) preferredLength else length
+ }
+ while (index < maxApplyCompare && equal) {
+ equal = this (index) == that(index)
+ index += 1
+ }
+ if ((index < length) && equal) {
+ val thisIt = this.iterator.drop(index)
+ val thatIt = that.iterator.drop(index)
+ while (equal && thisIt.hasNext) {
+ equal = thisIt.next() == thatIt.next()
+ }
+ }
+ }
+ equal
+ }
+ case _ => super.sameElements(o)
+ }
+
+ /** a hint to the runtime when scanning values
+ * [[apply]] is preferred for scan with a max index less than this value
+ * [[iterator]] is preferred for scans above this range
+ * @return a hint about when to use [[apply]] or [[iterator]]
+ */
+ protected def applyPreferredMaxLength: Int = IndexedSeqDefaults.defaultApplyPreferredMaxLength
+
+ override def iterableFactory: SeqFactory[IndexedSeq] = IndexedSeq
+}
+
+object IndexedSeqDefaults {
+ val defaultApplyPreferredMaxLength: Int =
+ try System.getProperty(
+ "scala.collection.immutable.IndexedSeq.defaultApplyPreferredMaxLength", "64").toInt
+ catch {
+ case _: SecurityException => 64
+ }
+}
+
+@SerialVersionUID(3L)
+object IndexedSeq extends SeqFactory.Delegate[IndexedSeq](Vector) {
+ override def from[E](it: IterableOnce[E]): IndexedSeq[E] = it match {
+ case is: IndexedSeq[E] => is
+ case _ => super.from(it)
+ }
+}
+
+/** Base trait for immutable indexed Seq operations */
+trait IndexedSeqOps[+A, +CC[_], +C]
+ extends SeqOps[A, CC, C]
+ with collection.IndexedSeqOps[A, CC, C] {
+
+ override def slice(from: Int, until: Int): C = {
+ // since we are immutable we can just share the same collection
+ if (from <= 0 && until >= length) coll
+ else super.slice(from, until)
+ }
+
+}
+
+/** Base trait for immutable linear sequences that have efficient `head` and `tail` */
+trait LinearSeq[+A]
+ extends Seq[A]
+ with collection.LinearSeq[A]
+ with LinearSeqOps[A, LinearSeq, LinearSeq[A]]
+ with IterableFactoryDefaults[A, LinearSeq] {
+
+ override def iterableFactory: SeqFactory[LinearSeq] = LinearSeq
+}
+
+@SerialVersionUID(3L)
+object LinearSeq extends SeqFactory.Delegate[LinearSeq](List) {
+ override def from[E](it: IterableOnce[E]): LinearSeq[E] = it match {
+ case ls: LinearSeq[E] => ls
+ case _ => super.from(it)
+ }
+}
+
+trait LinearSeqOps[+A, +CC[X] <: LinearSeq[X], +C <: LinearSeq[A] with LinearSeqOps[A, CC, C]]
+ extends Any with SeqOps[A, CC, C]
+ with collection.LinearSeqOps[A, CC, C]
+
+/** Explicit instantiation of the `Seq` trait to reduce class file size in subclasses. */
+abstract class AbstractSeq[+A] extends scala.collection.AbstractSeq[A] with Seq[A]
diff --git a/library/src/scala/collection/immutable/SeqMap.scala b/library/src/scala/collection/immutable/SeqMap.scala
new file mode 100644
index 000000000000..03daef1481a8
--- /dev/null
+++ b/library/src/scala/collection/immutable/SeqMap.scala
@@ -0,0 +1,284 @@
+/*
+ * 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 collection
+package immutable
+
+import scala.collection.mutable.{Builder, ReusableBuilder}
+
+/** A base trait for ordered, immutable maps.
+ *
+ * Note that the [[equals]] method for [[SeqMap]] compares key-value pairs
+ * without regard to ordering.
+ *
+ * All behavior is defined in terms of the abstract methods in `SeqMap`.
+ * It is sufficient for concrete subclasses to implement those methods.
+ * Methods that return a new map, in particular [[removed]] and [[updated]], must preserve ordering.
+ *
+ * @tparam K the type of the keys contained in this linked map.
+ * @tparam V the type of the values associated with the keys in this linked map.
+ *
+ * @define coll immutable seq map
+ * @define Coll `immutable.SeqMap`
+ */
+
+trait SeqMap[K, +V]
+ extends Map[K, V]
+ with collection.SeqMap[K, V]
+ with MapOps[K, V, SeqMap, SeqMap[K, V]]
+ with MapFactoryDefaults[K, V, SeqMap, Iterable] {
+ override def mapFactory: MapFactory[SeqMap] = SeqMap
+}
+
+
+object SeqMap extends MapFactory[SeqMap] {
+ def empty[K, V]: SeqMap[K, V] = EmptySeqMap.asInstanceOf[SeqMap[K, V]]
+
+ def from[K, V](it: collection.IterableOnce[(K, V)]): SeqMap[K, V] =
+ it match {
+ //case sm: SeqMap[K, V] => sm
+ case m: ListMap[K, V] => m
+ case m: TreeSeqMap[K, V] => m
+ case m: VectorMap[K, V] => m
+ case m: SeqMap1[K, V] => m
+ case m: SeqMap2[K, V] => m
+ case m: SeqMap3[K, V] => m
+ case m: SeqMap4[K, V] => m
+ case it: Iterable[_] if it.isEmpty => empty[K, V]
+ case _ => (newBuilder[K, V] ++= it).result()
+ }
+
+ def newBuilder[K, V]: Builder[(K, V), SeqMap[K, V]] = new SeqMapBuilderImpl
+
+ @SerialVersionUID(3L)
+ private object EmptySeqMap extends SeqMap[Any, Nothing] with Serializable {
+ override def size: Int = 0
+ override def knownSize: Int = 0
+ override def apply(key: Any) = throw new NoSuchElementException("key not found: " + key)
+ override def contains(key: Any) = false
+ def get(key: Any): Option[Nothing] = None
+ override def getOrElse [V1](key: Any, default: => V1): V1 = default
+ def iterator: Iterator[(Any, Nothing)] = Iterator.empty
+ def updated [V1] (key: Any, value: V1): SeqMap[Any, V1] = new SeqMap1(key, value)
+ def removed(key: Any): SeqMap[Any, Nothing] = this
+ }
+
+ @SerialVersionUID(3L)
+ private[immutable] final class SeqMap1[K, +V](key1: K, value1: V) extends SeqMap[K,V] with Serializable {
+ override def size: Int = 1
+ override def knownSize: Int = 1
+ override def apply(key: K) = if (key == key1) value1 else throw new NoSuchElementException("key not found: " + key)
+ override def contains(key: K) = key == key1
+ def get(key: K): Option[V] =
+ if (key == key1) Some(value1) else None
+ override def getOrElse [V1 >: V](key: K, default: => V1): V1 =
+ if (key == key1) value1 else default
+ def iterator = Iterator.single((key1, value1))
+ def updated[V1 >: V](key: K, value: V1): SeqMap[K, V1] =
+ if (key == key1) new SeqMap1(key1, value)
+ else new SeqMap2(key1, value1, key, value)
+ def removed(key: K): SeqMap[K, V] =
+ if (key == key1) SeqMap.empty else this
+ override def foreach[U](f: ((K, V)) => U): Unit = {
+ f((key1, value1))
+ }
+ override def foreachEntry[U](f: (K, V) => U): Unit = {
+ f(key1, value1)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ private[immutable] final class SeqMap2[K, +V](key1: K, value1: V, key2: K, value2: V) extends SeqMap[K,V] with Serializable {
+ override def size: Int = 2
+ override def knownSize: Int = 2
+ override def apply(key: K) =
+ if (key == key1) value1
+ else if (key == key2) value2
+ else throw new NoSuchElementException("key not found: " + key)
+ override def contains(key: K) = (key == key1) || (key == key2)
+ def get(key: K): Option[V] =
+ if (key == key1) Some(value1)
+ else if (key == key2) Some(value2)
+ else None
+ override def getOrElse [V1 >: V](key: K, default: => V1): V1 =
+ if (key == key1) value1
+ else if (key == key2) value2
+ else default
+ def iterator = ((key1, value1) :: (key2, value2) :: Nil).iterator
+ def updated[V1 >: V](key: K, value: V1): SeqMap[K, V1] =
+ if (key == key1) new SeqMap2(key1, value, key2, value2)
+ else if (key == key2) new SeqMap2(key1, value1, key2, value)
+ else new SeqMap3(key1, value1, key2, value2, key, value)
+ def removed(key: K): SeqMap[K, V] =
+ if (key == key1) new SeqMap1(key2, value2)
+ else if (key == key2) new SeqMap1(key1, value1)
+ else this
+ override def foreach[U](f: ((K, V)) => U): Unit = {
+ f((key1, value1)); f((key2, value2))
+ }
+ override def foreachEntry[U](f: (K, V) => U): Unit = {
+ f(key1, value1)
+ f(key2, value2)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ private[immutable] class SeqMap3[K, +V](key1: K, value1: V, key2: K, value2: V, key3: K, value3: V) extends SeqMap[K,V] with Serializable {
+ override def size: Int = 3
+ override def knownSize: Int = 3
+ override def apply(key: K) =
+ if (key == key1) value1
+ else if (key == key2) value2
+ else if (key == key3) value3
+ else throw new NoSuchElementException("key not found: " + key)
+ override def contains(key: K) = (key == key1) || (key == key2) || (key == key3)
+ def get(key: K): Option[V] =
+ if (key == key1) Some(value1)
+ else if (key == key2) Some(value2)
+ else if (key == key3) Some(value3)
+ else None
+ override def getOrElse [V1 >: V](key: K, default: => V1): V1 =
+ if (key == key1) value1
+ else if (key == key2) value2
+ else if (key == key3) value3
+ else default
+ def iterator = ((key1, value1) :: (key2, value2) :: (key3, value3) :: Nil).iterator
+ def updated[V1 >: V](key: K, value: V1): SeqMap[K, V1] =
+ if (key == key1) new SeqMap3(key1, value, key2, value2, key3, value3)
+ else if (key == key2) new SeqMap3(key1, value1, key2, value, key3, value3)
+ else if (key == key3) new SeqMap3(key1, value1, key2, value2, key3, value)
+ else new SeqMap4(key1, value1, key2, value2, key3, value3, key, value)
+ def removed(key: K): SeqMap[K, V] =
+ if (key == key1) new SeqMap2(key2, value2, key3, value3)
+ else if (key == key2) new SeqMap2(key1, value1, key3, value3)
+ else if (key == key3) new SeqMap2(key1, value1, key2, value2)
+ else this
+ override def foreach[U](f: ((K, V)) => U): Unit = {
+ f((key1, value1)); f((key2, value2)); f((key3, value3))
+ }
+ override def foreachEntry[U](f: (K, V) => U): Unit = {
+ f(key1, value1)
+ f(key2, value2)
+ f(key3, value3)
+ }
+ }
+
+ @SerialVersionUID(3L)
+ private[immutable] final class SeqMap4[K, +V](key1: K, value1: V, key2: K, value2: V, key3: K, value3: V, key4: K, value4: V) extends SeqMap[K,V] with Serializable {
+ override def size: Int = 4
+ override def knownSize: Int = 4
+ override def apply(key: K) =
+ if (key == key1) value1
+ else if (key == key2) value2
+ else if (key == key3) value3
+ else if (key == key4) value4
+ else throw new NoSuchElementException("key not found: " + key)
+ override def contains(key: K) = (key == key1) || (key == key2) || (key == key3) || (key == key4)
+ def get(key: K): Option[V] =
+ if (key == key1) Some(value1)
+ else if (key == key2) Some(value2)
+ else if (key == key3) Some(value3)
+ else if (key == key4) Some(value4)
+ else None
+ override def getOrElse [V1 >: V](key: K, default: => V1): V1 =
+ if (key == key1) value1
+ else if (key == key2) value2
+ else if (key == key3) value3
+ else if (key == key4) value4
+ else default
+ def iterator = ((key1, value1) :: (key2, value2) :: (key3, value3) :: (key4, value4) :: Nil).iterator
+ def updated[V1 >: V](key: K, value: V1): SeqMap[K, V1] =
+ if (key == key1) new SeqMap4(key1, value, key2, value2, key3, value3, key4, value4)
+ else if (key == key2) new SeqMap4(key1, value1, key2, value, key3, value3, key4, value4)
+ else if (key == key3) new SeqMap4(key1, value1, key2, value2, key3, value, key4, value4)
+ else if (key == key4) new SeqMap4(key1, value1, key2, value2, key3, value3, key4, value)
+ else {
+ // Directly create the elements for performance reasons
+ val fields = Vector(key1, key2, key3, key4, key)
+ val underlying: Map[K, (Int, V1)] =
+ HashMap(
+ (key1, (0, value1)),
+ (key2, (1, value2)),
+ (key3, (2, value3)),
+ (key4, (3, value4)),
+ (key, (4, value))
+ )
+ new VectorMap(fields, underlying)
+ }
+ def removed(key: K): SeqMap[K, V] =
+ if (key == key1) new SeqMap3(key2, value2, key3, value3, key4, value4)
+ else if (key == key2) new SeqMap3(key1, value1, key3, value3, key4, value4)
+ else if (key == key3) new SeqMap3(key1, value1, key2, value2, key4, value4)
+ else if (key == key4) new SeqMap3(key1, value1, key2, value2, key3, value3)
+ else this
+ override def foreach[U](f: ((K, V)) => U): Unit = {
+ f((key1, value1)); f((key2, value2)); f((key3, value3)); f((key4, value4))
+ }
+ override def foreachEntry[U](f: (K, V) => U): Unit = {
+ f(key1, value1)
+ f(key2, value2)
+ f(key3, value3)
+ f(key4, value4)
+ }
+
+ private[SeqMap] def buildTo[V1 >: V](builder: Builder[(K, V1), SeqMap[K, V1]]): builder.type =
+ builder.addOne((key1, value1)).addOne((key2, value2)).addOne((key3, value3)).addOne((key4, value4))
+ }
+
+ private final class SeqMapBuilderImpl[K, V] extends ReusableBuilder[(K, V), SeqMap[K, V]] {
+ private[this] var elems: SeqMap[K, V] = SeqMap.empty
+ private[this] var switchedToVectorMapBuilder: Boolean = false
+ private[this] var vectorMapBuilder: VectorMapBuilder[K, V] = _
+
+ override def clear(): Unit = {
+ elems = SeqMap.empty
+ if (vectorMapBuilder != null) {
+ vectorMapBuilder.clear()
+ }
+ switchedToVectorMapBuilder = false
+ }
+
+ override def result(): SeqMap[K, V] =
+ if (switchedToVectorMapBuilder) vectorMapBuilder.result() else elems
+
+ def addOne(elem: (K, V)) = {
+ if (switchedToVectorMapBuilder) {
+ vectorMapBuilder.addOne(elem)
+ } else if (elems.size < 4) {
+ elems = elems + elem
+ } else {
+ // assert(elems.size == 4)
+ if (elems.contains(elem._1)) {
+ elems = elems + elem // will not increase the size of the map
+ } else {
+ switchedToVectorMapBuilder = true
+ if (vectorMapBuilder == null) {
+ vectorMapBuilder = new VectorMapBuilder
+ }
+ elems.asInstanceOf[SeqMap4[K, V]].buildTo(vectorMapBuilder)
+ vectorMapBuilder.addOne(elem)
+ }
+ }
+
+ this
+ }
+
+ override def addAll(xs: IterableOnce[(K, V)]): this.type =
+ if (switchedToVectorMapBuilder) {
+ vectorMapBuilder.addAll(xs)
+ this
+ } else {
+ super.addAll(xs)
+ }
+ }
+}
diff --git a/library/src/scala/collection/immutable/Set.scala b/library/src/scala/collection/immutable/Set.scala
new file mode 100644
index 000000000000..e8509b58016e
--- /dev/null
+++ b/library/src/scala/collection/immutable/Set.scala
@@ -0,0 +1,407 @@
+/*
+ * 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 collection
+package immutable
+
+import scala.collection.immutable.Set.Set4
+import scala.collection.mutable.{Builder, ReusableBuilder}
+
+/** Base trait for immutable set collections */
+trait Set[A] extends Iterable[A]
+ with collection.Set[A]
+ with SetOps[A, Set, Set[A]]
+ with IterableFactoryDefaults[A, Set] {
+ override def iterableFactory: IterableFactory[Set] = Set
+}
+
+/** Base trait for immutable set operations
+ *
+ * @define coll immutable set
+ * @define Coll `immutable.Set`
+ */
+trait SetOps[A, +CC[X], +C <: SetOps[A, CC, C]]
+ extends collection.SetOps[A, CC, C] {
+
+ /** Creates a new set with an additional element, unless the element is
+ * already present.
+ *
+ * @param elem the element to be added
+ * @return a new set that contains all elements of this set and that also
+ * contains `elem`.
+ */
+ def incl(elem: A): C
+
+ /** Alias for `incl` */
+ override final def + (elem: A): C = incl(elem) // like in collection.Set but not deprecated
+
+ /** Creates a new set with a given element removed from this set.
+ *
+ * @param elem the element to be removed
+ * @return a new set that contains all elements of this set but that does not
+ * contain `elem`.
+ */
+ def excl(elem: A): C
+
+ /** Alias for `excl` */
+ @`inline` final override def - (elem: A): C = excl(elem)
+
+ def diff(that: collection.Set[A]): C =
+ foldLeft(empty)((result, elem) => if (that contains elem) result else result + elem)
+
+ /** Creates a new $coll from this $coll by removing all elements of another
+ * collection.
+ *
+ * @param that the collection containing the elements to remove.
+ * @return a new $coll with the given elements removed, omitting duplicates.
+ */
+ def removedAll(that: IterableOnce[A]): C = that.iterator.foldLeft[C](coll)(_ - _)
+
+ /** Alias for removedAll */
+ override final def -- (that: IterableOnce[A]): C = removedAll(that)
+}
+
+trait StrictOptimizedSetOps[A, +CC[X], +C <: SetOps[A, CC, C]]
+ extends SetOps[A, CC, C]
+ with collection.StrictOptimizedSetOps[A, CC, C]
+ with StrictOptimizedIterableOps[A, CC, C] {
+
+ override def concat(that: collection.IterableOnce[A]): C = {
+ var result: C = coll
+ val it = that.iterator
+ while (it.hasNext) result = result + it.next()
+ result
+ }
+}
+
+/**
+ * $factoryInfo
+ * @define coll immutable set
+ * @define Coll `immutable.Set`
+ */
+@SerialVersionUID(3L)
+object Set extends IterableFactory[Set] {
+
+ def empty[A]: Set[A] = EmptySet.asInstanceOf[Set[A]]
+
+ def from[E](it: collection.IterableOnce[E]): Set[E] =
+ it match {
+ case _ if it.knownSize == 0 => empty[E]
+ // Since IterableOnce[E] launders the variance of E,
+ // identify only our implementations which can be soundly substituted.
+ // It's not sufficient to match `SortedSet[E]` to rebuild and `Set[E]` to retain.
+ case s: HashSet[E] => s
+ case s: ListSet[E] => s
+ case s: Set1[E] => s
+ case s: Set2[E] => s
+ case s: Set3[E] => s
+ case s: Set4[E] => s
+ case s: HashMap[E @unchecked, _]#HashKeySet => s
+ case s: MapOps[E, Any, Map, Map[E, Any]]#ImmutableKeySet @unchecked => s
+ // We also want `SortedSet` (and subclasses, such as `BitSet`)
+ // to rebuild themselves, to avoid element type widening issues.
+ case _ => newBuilder[E].addAll(it).result()
+ }
+
+ def newBuilder[A]: Builder[A, Set[A]] = new SetBuilderImpl[A]
+
+ /** An optimized representation for immutable empty sets */
+ @SerialVersionUID(3L)
+ private object EmptySet extends AbstractSet[Any] with Serializable {
+ override def size: Int = 0
+ override def isEmpty = true
+ override def knownSize: Int = size
+ override def filter(pred: Any => Boolean): Set[Any] = this
+ override def filterNot(pred: Any => Boolean): Set[Any] = this
+ override def removedAll(that: IterableOnce[Any]): Set[Any] = this
+ override def diff(that: collection.Set[Any]): Set[Any] = this
+ override def subsetOf(that: collection.Set[Any]): Boolean = true
+ override def intersect(that: collection.Set[Any]): Set[Any] = this
+ override def view: View[Any] = View.empty
+ def contains(elem: Any): Boolean = false
+ def incl(elem: Any): Set[Any] = new Set1(elem)
+ def excl(elem: Any): Set[Any] = this
+ def iterator: Iterator[Any] = Iterator.empty
+ override def foreach[U](f: Any => U): Unit = ()
+ }
+ private[collection] def emptyInstance: Set[Any] = EmptySet
+
+ @SerialVersionUID(3L)
+ private abstract class SetNIterator[A](n: Int) extends AbstractIterator[A] with Serializable {
+ private[this] var current = 0
+ private[this] var remainder = n
+ override def knownSize: Int = remainder
+ def hasNext = remainder > 0
+ def apply(i: Int): A
+ def next(): A =
+ if (hasNext) {
+ val r = apply(current)
+ current += 1
+ remainder -= 1
+ r
+ } else Iterator.empty.next()
+
+ override def drop(n: Int): Iterator[A] = {
+ if (n > 0) {
+ current += n
+ remainder = Math.max(0, remainder - n)
+ }
+ this
+ }
+ }
+
+ /** An optimized representation for immutable sets of size 1 */
+ @SerialVersionUID(3L)
+ final class Set1[A] private[collection] (elem1: A) extends AbstractSet[A] with StrictOptimizedIterableOps[A, Set, Set[A]] with Serializable {
+ override def size: Int = 1
+ override def isEmpty = false
+ override def knownSize: Int = size
+ def contains(elem: A): Boolean = elem == elem1
+ def incl(elem: A): Set[A] =
+ if (contains(elem)) this
+ else new Set2(elem1, elem)
+ def excl(elem: A): Set[A] =
+ if (elem == elem1) Set.empty
+ else this
+ def iterator: Iterator[A] = Iterator.single(elem1)
+ override def foreach[U](f: A => U): Unit = f(elem1)
+ override def exists(p: A => Boolean): Boolean = p(elem1)
+ override def forall(p: A => Boolean): Boolean = p(elem1)
+ override protected[collection] def filterImpl(pred: A => Boolean, isFlipped: Boolean): Set[A] =
+ if (pred(elem1) != isFlipped) this else Set.empty
+
+ override def find(p: A => Boolean): Option[A] =
+ if (p(elem1)) Some(elem1)
+ else None
+ override def head: A = elem1
+ override def tail: Set[A] = Set.empty
+ }
+
+ /** An optimized representation for immutable sets of size 2 */
+ @SerialVersionUID(3L)
+ final class Set2[A] private[collection] (elem1: A, elem2: A) extends AbstractSet[A] with StrictOptimizedIterableOps[A, Set, Set[A]] with Serializable {
+ override def size: Int = 2
+ override def isEmpty = false
+ override def knownSize: Int = size
+ def contains(elem: A): Boolean = elem == elem1 || elem == elem2
+ def incl(elem: A): Set[A] =
+ if (contains(elem)) this
+ else new Set3(elem1, elem2, elem)
+ def excl(elem: A): Set[A] =
+ if (elem == elem1) new Set1(elem2)
+ else if (elem == elem2) new Set1(elem1)
+ else this
+ def iterator: Iterator[A] = new SetNIterator[A](size) {
+ def apply(i: Int) = getElem(i)
+ }
+ private def getElem(i: Int) = i match { case 0 => elem1 case 1 => elem2 }
+
+ override def foreach[U](f: A => U): Unit = {
+ f(elem1); f(elem2)
+ }
+ override def exists(p: A => Boolean): Boolean = {
+ p(elem1) || p(elem2)
+ }
+ override def forall(p: A => Boolean): Boolean = {
+ p(elem1) && p(elem2)
+ }
+ override protected[collection] def filterImpl(pred: A => Boolean, isFlipped: Boolean): Set[A] = {
+ var r1: A = null.asInstanceOf[A]
+ var n = 0
+ if (pred(elem1) != isFlipped) { r1 = elem1; n += 1}
+ if (pred(elem2) != isFlipped) { if (n == 0) r1 = elem2; n += 1}
+
+ n match {
+ case 0 => Set.empty
+ case 1 => new Set1(r1)
+ case 2 => this
+ }
+ }
+ override def find(p: A => Boolean): Option[A] = {
+ if (p(elem1)) Some(elem1)
+ else if (p(elem2)) Some(elem2)
+ else None
+ }
+ override def head: A = elem1
+ override def tail: Set[A] = new Set1(elem2)
+ }
+
+ /** An optimized representation for immutable sets of size 3 */
+ @SerialVersionUID(3L)
+ final class Set3[A] private[collection] (elem1: A, elem2: A, elem3: A) extends AbstractSet[A] with StrictOptimizedIterableOps[A, Set, Set[A]] with Serializable {
+ override def size: Int = 3
+ override def isEmpty = false
+ override def knownSize: Int = size
+ def contains(elem: A): Boolean =
+ elem == elem1 || elem == elem2 || elem == elem3
+ def incl(elem: A): Set[A] =
+ if (contains(elem)) this
+ else new Set4(elem1, elem2, elem3, elem)
+ def excl(elem: A): Set[A] =
+ if (elem == elem1) new Set2(elem2, elem3)
+ else if (elem == elem2) new Set2(elem1, elem3)
+ else if (elem == elem3) new Set2(elem1, elem2)
+ else this
+ def iterator: Iterator[A] = new SetNIterator[A](size) {
+ def apply(i: Int) = getElem(i)
+ }
+ private def getElem(i: Int) = i match { case 0 => elem1 case 1 => elem2 case 2 => elem3 }
+
+ override def foreach[U](f: A => U): Unit = {
+ f(elem1); f(elem2); f(elem3)
+ }
+ override def exists(p: A => Boolean): Boolean = {
+ p(elem1) || p(elem2) || p(elem3)
+ }
+ override def forall(p: A => Boolean): Boolean = {
+ p(elem1) && p(elem2) && p(elem3)
+ }
+ override protected[collection] def filterImpl(pred: A => Boolean, isFlipped: Boolean): Set[A] = {
+ var r1, r2: A = null.asInstanceOf[A]
+ var n = 0
+ if (pred(elem1) != isFlipped) { r1 = elem1; n += 1}
+ if (pred(elem2) != isFlipped) { if (n == 0) r1 = elem2 else r2 = elem2; n += 1}
+ if (pred(elem3) != isFlipped) { if (n == 0) r1 = elem3 else if (n == 1) r2 = elem3; n += 1}
+
+ n match {
+ case 0 => Set.empty
+ case 1 => new Set1(r1)
+ case 2 => new Set2(r1, r2)
+ case 3 => this
+ }
+ }
+ override def find(p: A => Boolean): Option[A] = {
+ if (p(elem1)) Some(elem1)
+ else if (p(elem2)) Some(elem2)
+ else if (p(elem3)) Some(elem3)
+ else None
+ }
+ override def head: A = elem1
+ override def tail: Set[A] = new Set2(elem2, elem3)
+ }
+
+ /** An optimized representation for immutable sets of size 4 */
+ @SerialVersionUID(3L)
+ final class Set4[A] private[collection] (elem1: A, elem2: A, elem3: A, elem4: A) extends AbstractSet[A] with StrictOptimizedIterableOps[A, Set, Set[A]] with Serializable {
+ override def size: Int = 4
+ override def isEmpty = false
+ override def knownSize: Int = size
+ def contains(elem: A): Boolean =
+ elem == elem1 || elem == elem2 || elem == elem3 || elem == elem4
+ def incl(elem: A): Set[A] =
+ if (contains(elem)) this
+ else HashSet.empty[A] + elem1 + elem2 + elem3 + elem4 + elem
+ def excl(elem: A): Set[A] =
+ if (elem == elem1) new Set3(elem2, elem3, elem4)
+ else if (elem == elem2) new Set3(elem1, elem3, elem4)
+ else if (elem == elem3) new Set3(elem1, elem2, elem4)
+ else if (elem == elem4) new Set3(elem1, elem2, elem3)
+ else this
+ def iterator: Iterator[A] = new SetNIterator[A](size) {
+ def apply(i: Int) = getElem(i)
+ }
+ private def getElem(i: Int) = i match { case 0 => elem1 case 1 => elem2 case 2 => elem3 case 3 => elem4 }
+
+ override def foreach[U](f: A => U): Unit = {
+ f(elem1); f(elem2); f(elem3); f(elem4)
+ }
+ override def exists(p: A => Boolean): Boolean = {
+ p(elem1) || p(elem2) || p(elem3) || p(elem4)
+ }
+ override def forall(p: A => Boolean): Boolean = {
+ p(elem1) && p(elem2) && p(elem3) && p(elem4)
+ }
+ override protected[collection] def filterImpl(pred: A => Boolean, isFlipped: Boolean): Set[A] = {
+ var r1, r2, r3: A = null.asInstanceOf[A]
+ var n = 0
+ if (pred(elem1) != isFlipped) { r1 = elem1; n += 1}
+ if (pred(elem2) != isFlipped) { if (n == 0) r1 = elem2 else r2 = elem2; n += 1}
+ if (pred(elem3) != isFlipped) { if (n == 0) r1 = elem3 else if (n == 1) r2 = elem3 else r3 = elem3; n += 1}
+ if (pred(elem4) != isFlipped) { if (n == 0) r1 = elem4 else if (n == 1) r2 = elem4 else if (n == 2) r3 = elem4; n += 1}
+
+ n match {
+ case 0 => Set.empty
+ case 1 => new Set1(r1)
+ case 2 => new Set2(r1, r2)
+ case 3 => new Set3(r1, r2, r3)
+ case 4 => this
+ }
+ }
+
+ override def find(p: A => Boolean): Option[A] = {
+ if (p(elem1)) Some(elem1)
+ else if (p(elem2)) Some(elem2)
+ else if (p(elem3)) Some(elem3)
+ else if (p(elem4)) Some(elem4)
+ else None
+ }
+ override def head: A = elem1
+ override def tail: Set[A] = new Set3(elem2, elem3, elem4)
+
+ private[immutable] def buildTo(builder: Builder[A, Set[A]]): builder.type =
+ builder.addOne(elem1).addOne(elem2).addOne(elem3).addOne(elem4)
+ }
+}
+
+/** Explicit instantiation of the `Set` trait to reduce class file size in subclasses. */
+abstract class AbstractSet[A] extends scala.collection.AbstractSet[A] with Set[A]
+
+/** Builder for Set.
+ * $multipleResults
+ */
+private final class SetBuilderImpl[A] extends ReusableBuilder[A, Set[A]] {
+ private[this] var elems: Set[A] = Set.empty
+ private[this] var switchedToHashSetBuilder: Boolean = false
+ private[this] var hashSetBuilder: HashSetBuilder[A] = _
+
+ override def clear(): Unit = {
+ elems = Set.empty
+ if (hashSetBuilder != null) {
+ hashSetBuilder.clear()
+ }
+ switchedToHashSetBuilder = false
+ }
+
+ override def result(): Set[A] =
+ if (switchedToHashSetBuilder) hashSetBuilder.result() else elems
+
+ def addOne(elem: A) = {
+ if (switchedToHashSetBuilder) {
+ hashSetBuilder.addOne(elem)
+ } else if (elems.size < 4) {
+ elems = elems + elem
+ } else {
+ // assert(elems.size == 4)
+ if (elems.contains(elem)) {
+ () // do nothing
+ } else {
+ switchedToHashSetBuilder = true
+ if (hashSetBuilder == null) {
+ hashSetBuilder = new HashSetBuilder
+ }
+ elems.asInstanceOf[Set4[A]].buildTo(hashSetBuilder)
+ hashSetBuilder.addOne(elem)
+ }
+ }
+
+ this
+ }
+
+ override def addAll(xs: IterableOnce[A]): this.type =
+ if (switchedToHashSetBuilder) {
+ hashSetBuilder.addAll(xs)
+ this
+ } else {
+ super.addAll(xs)
+ }
+}
diff --git a/library/src/scala/collection/immutable/SortedMap.scala b/library/src/scala/collection/immutable/SortedMap.scala
new file mode 100644
index 000000000000..120ae23ae024
--- /dev/null
+++ b/library/src/scala/collection/immutable/SortedMap.scala
@@ -0,0 +1,177 @@
+/*
+ * 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 collection
+package immutable
+
+import scala.annotation.unchecked.uncheckedVariance
+import scala.collection.mutable.Builder
+
+/** An immutable map whose key-value pairs are sorted according to an [[scala.math.Ordering]] on the keys.
+ *
+ * Allows for range queries to be performed on its keys, and implementations must guarantee that traversal happens in
+ * sorted order, according to the map's [[scala.math.Ordering]].
+ *
+ * @example {{{
+ * import scala.collection.immutable.SortedMap
+ *
+ * // Make a SortedMap via the companion object factory
+ * val weekdays = SortedMap(
+ * 2 -> "Monday",
+ * 3 -> "Tuesday",
+ * 4 -> "Wednesday",
+ * 5 -> "Thursday",
+ * 6 -> "Friday"
+ * )
+ * // TreeMap(2 -> Monday, 3 -> Tuesday, 4 -> Wednesday, 5 -> Thursday, 6 -> Friday)
+ *
+ * val days = weekdays ++ List(1 -> "Sunday", 7 -> "Saturday")
+ * // TreeMap(1 -> Sunday, 2 -> Monday, 3 -> Tuesday, 4 -> Wednesday, 5 -> Thursday, 6 -> Friday, 7 -> Saturday)
+ *
+ * val day3 = days.get(3) // Some("Tuesday")
+ *
+ * val rangeOfDays = days.range(2, 5) // TreeMap(2 -> Monday, 3 -> Tuesday, 4 -> Wednesday)
+ *
+ * val daysUntil2 = days.rangeUntil(2) // TreeMap(1 -> Sunday)
+ * val daysTo2 = days.rangeTo(2) // TreeMap(1 -> Sunday, 2 -> Monday)
+ * val daysAfter5 = days.rangeFrom(5) // TreeMap(5 -> Thursday, 6 -> Friday, 7 -> Saturday)
+ * }}}
+ *
+ * @tparam K the type of the keys contained in this tree map.
+ * @tparam V the type of the values associated with the keys.
+ */
+trait SortedMap[K, +V]
+ extends Map[K, V]
+ with collection.SortedMap[K, V]
+ with SortedMapOps[K, V, SortedMap, SortedMap[K, V]]
+ with SortedMapFactoryDefaults[K, V, SortedMap, Iterable, Map] {
+
+ override def unsorted: Map[K, V] = this
+
+ override def sortedMapFactory: SortedMapFactory[SortedMap] = SortedMap
+
+ /** The same map with a given default function.
+ * Note: The default is only used for `apply`. Other methods like `get`, `contains`, `iterator`, `keys`, etc.
+ * are not affected by `withDefault`.
+ *
+ * Invoking transformer methods (e.g. `map`) will not preserve the default value.
+ *
+ * @param d the function mapping keys to values, used for non-present keys
+ * @return a wrapper of the map with a default value
+ */
+ override def withDefault[V1 >: V](d: K => V1): SortedMap[K, V1] = new SortedMap.WithDefault[K, V1](this, d)
+
+ /** The same map with a given default value.
+ * Note: The default is only used for `apply`. Other methods like `get`, `contains`, `iterator`, `keys`, etc.
+ * are not affected by `withDefaultValue`.
+ *
+ * Invoking transformer methods (e.g. `map`) will not preserve the default value.
+ *
+ * @param d default value used for non-present keys
+ * @return a wrapper of the map with a default value
+ */
+ override def withDefaultValue[V1 >: V](d: V1): SortedMap[K, V1] = new SortedMap.WithDefault[K, V1](this, _ => d)
+}
+
+trait SortedMapOps[K, +V, +CC[X, +Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], +C <: SortedMapOps[K, V, CC, C]]
+ extends MapOps[K, V, Map, C] with collection.SortedMapOps[K, V, CC, C] { self =>
+
+ protected def coll: C with CC[K, V]
+
+ def unsorted: Map[K, V]
+
+ override def keySet: SortedSet[K] = new ImmutableKeySortedSet
+
+ /** The implementation class of the set returned by `keySet` */
+ protected class ImmutableKeySortedSet extends AbstractSet[K] with SortedSet[K] with GenKeySet with GenKeySortedSet {
+ def rangeImpl(from: Option[K], until: Option[K]): SortedSet[K] = {
+ val map = self.rangeImpl(from, until)
+ new map.ImmutableKeySortedSet
+ }
+ def incl(elem: K): SortedSet[K] = fromSpecific(this).incl(elem)
+ def excl(elem: K): SortedSet[K] = fromSpecific(this).excl(elem)
+ }
+
+ // We override these methods to fix their return type (which would be `Map` otherwise)
+ def updated[V1 >: V](key: K, value: V1): CC[K, V1]
+ @`inline` final override def +[V1 >: V](kv: (K, V1)): CC[K, V1] = updated(kv._1, kv._2)
+ override def updatedWith[V1 >: V](key: K)(remappingFunction: Option[V] => Option[V1]): CC[K, V1] = {
+ // Implementation has been copied from `MapOps`
+ val previousValue = this.get(key)
+ remappingFunction(previousValue) match {
+ case None => previousValue.fold(coll)(_ => this.removed(key).coll)
+ case Some(nextValue) =>
+ if (previousValue.exists(_.asInstanceOf[AnyRef] eq nextValue.asInstanceOf[AnyRef])) coll
+ else coll.updated(key, nextValue)
+ }
+ }
+ override def transform[W](f: (K, V) => W): CC[K, W] = map({ case (k, v) => (k, f(k, v)) })(ordering)
+}
+
+trait StrictOptimizedSortedMapOps[K, +V, +CC[X, +Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], +C <: SortedMapOps[K, V, CC, C]]
+ extends SortedMapOps[K, V, CC, C]
+ with collection.StrictOptimizedSortedMapOps[K, V, CC, C]
+ with StrictOptimizedMapOps[K, V, Map, C] {
+
+ override def concat[V2 >: V](xs: collection.IterableOnce[(K, V2)]): CC[K, V2] = {
+ var result: CC[K, V2] = coll
+ val it = xs.iterator
+ while (it.hasNext) result = result + it.next()
+ result
+ }
+}
+
+@SerialVersionUID(3L)
+object SortedMap extends SortedMapFactory.Delegate[SortedMap](TreeMap) {
+
+ override def from[K: Ordering, V](it: IterableOnce[(K, V)]): SortedMap[K, V] = it match {
+ case sm: SortedMap[K, V] if Ordering[K] == sm.ordering => sm
+ case _ => super.from(it)
+ }
+
+ final class WithDefault[K, +V](underlying: SortedMap[K, V], defaultValue: K => V)
+ extends Map.WithDefault[K, V](underlying, defaultValue)
+ with SortedMap[K, V]
+ with SortedMapOps[K, V, SortedMap, WithDefault[K, V]] with Serializable {
+
+ implicit def ordering: Ordering[K] = underlying.ordering
+
+ override def sortedMapFactory: SortedMapFactory[SortedMap] = underlying.sortedMapFactory
+
+ def iteratorFrom(start: K): scala.collection.Iterator[(K, V)] = underlying.iteratorFrom(start)
+
+ def keysIteratorFrom(start: K): scala.collection.Iterator[K] = underlying.keysIteratorFrom(start)
+
+ def rangeImpl(from: Option[K], until: Option[K]): WithDefault[K, V] =
+ new WithDefault[K, V](underlying.rangeImpl(from, until), defaultValue)
+
+ // Need to override following methods to match type signatures of `SortedMap.WithDefault`
+ // for operations preserving default value
+
+ override def updated[V1 >: V](key: K, value: V1): WithDefault[K, V1] =
+ new WithDefault[K, V1](underlying.updated(key, value), defaultValue)
+
+ override def concat [V2 >: V](xs: collection.IterableOnce[(K, V2)]): WithDefault[K, V2] =
+ new WithDefault( underlying.concat(xs) , defaultValue)
+
+ override def removed(key: K): WithDefault[K, V] = new WithDefault[K, V](underlying.removed(key), defaultValue)
+
+ override def empty: WithDefault[K, V] = new WithDefault[K, V](underlying.empty, defaultValue)
+
+ override protected def fromSpecific(coll: scala.collection.IterableOnce[(K, V)] @uncheckedVariance): WithDefault[K, V] =
+ new WithDefault[K, V](sortedMapFactory.from(coll), defaultValue)
+
+ override protected def newSpecificBuilder: Builder[(K, V), WithDefault[K, V]] @uncheckedVariance =
+ SortedMap.newBuilder.mapResult((p: SortedMap[K, V]) => new WithDefault[K, V](p, defaultValue))
+ }
+}
diff --git a/library/src/scala/collection/immutable/SortedSet.scala b/library/src/scala/collection/immutable/SortedSet.scala
new file mode 100644
index 000000000000..2eda00ac6b2f
--- /dev/null
+++ b/library/src/scala/collection/immutable/SortedSet.scala
@@ -0,0 +1,57 @@
+/*
+ * 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 collection
+package immutable
+
+/** Base trait for sorted sets */
+trait SortedSet[A]
+ extends Set[A]
+ with collection.SortedSet[A]
+ with SortedSetOps[A, SortedSet, SortedSet[A]]
+ with SortedSetFactoryDefaults[A, SortedSet, Set] {
+
+ override def unsorted: Set[A] = this
+
+ override def sortedIterableFactory: SortedIterableFactory[SortedSet] = SortedSet
+}
+
+/**
+ * @define coll immutable sorted set
+ * @define Coll `immutable.SortedSet`
+ */
+trait SortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]]
+ extends SetOps[A, Set, C]
+ with collection.SortedSetOps[A, CC, C] {
+
+ def unsorted: Set[A]
+}
+
+trait StrictOptimizedSortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]]
+ extends SortedSetOps[A, CC, C]
+ with collection.StrictOptimizedSortedSetOps[A, CC, C]
+ with StrictOptimizedSetOps[A, Set, C] {
+}
+
+/**
+ * $factoryInfo
+ * @define coll immutable sorted set
+ * @define Coll `immutable.SortedSet`
+ */
+@SerialVersionUID(3L)
+object SortedSet extends SortedIterableFactory.Delegate[SortedSet](TreeSet) {
+ override def from[E: Ordering](it: IterableOnce[E]): SortedSet[E] = it match {
+ case ss: SortedSet[E] if Ordering[E] == ss.ordering => ss
+ case _ => super.from(it)
+ }
+}
diff --git a/library/src/scala/collection/immutable/Stream.scala b/library/src/scala/collection/immutable/Stream.scala
new file mode 100644
index 000000000000..898a988735c6
--- /dev/null
+++ b/library/src/scala/collection/immutable/Stream.scala
@@ -0,0 +1,569 @@
+/*
+ * 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 collection
+package immutable
+
+import java.io.{ObjectInputStream, ObjectOutputStream}
+import java.lang.{StringBuilder => JStringBuilder}
+
+import scala.annotation.tailrec
+import scala.annotation.unchecked.uncheckedVariance
+import scala.collection.generic.SerializeEnd
+import scala.collection.mutable.{ArrayBuffer, StringBuilder}
+import scala.language.implicitConversions
+import Stream.cons
+
+@deprecated("Use LazyList (which is fully lazy) instead of Stream (which has a lazy tail only)", "2.13.0")
+@SerialVersionUID(3L)
+sealed abstract class Stream[+A] extends AbstractSeq[A]
+ with LinearSeq[A]
+ with LinearSeqOps[A, Stream, Stream[A]]
+ with IterableFactoryDefaults[A, Stream]
+ with Serializable {
+ def tail: Stream[A]
+
+ /** Forces evaluation of the whole `Stream` and returns it.
+ *
+ * @note Often we use `Stream`s to represent an infinite set or series. If
+ * that's the case for your particular `Stream` then this function will never
+ * return and will probably crash the VM with an `OutOfMemory` exception.
+ * This function will not hang on a finite cycle, however.
+ *
+ * @return The fully realized `Stream`.
+ */
+ def force: this.type
+
+ override def iterableFactory: SeqFactory[Stream] = Stream
+
+ override protected[this] def className: String = "Stream"
+
+ /** Apply the given function `f` to each element of this linear sequence
+ * (while respecting the order of the elements).
+ *
+ * @param f The treatment to apply to each element.
+ * @note Overridden here as final to trigger tail-call optimization, which
+ * replaces 'this' with 'tail' at each iteration. This is absolutely
+ * necessary for allowing the GC to collect the underlying Stream as elements
+ * are consumed.
+ * @note This function will force the realization of the entire Stream
+ * unless the `f` throws an exception.
+ */
+ @tailrec
+ override final def foreach[U](f: A => U): Unit = {
+ if (!this.isEmpty) {
+ f(head)
+ tail.foreach(f)
+ }
+ }
+
+ @tailrec
+ override final def find(p: A => Boolean): Option[A] = {
+ if(isEmpty) None
+ else if(p(head)) Some(head)
+ else tail.find(p)
+ }
+
+ override def take(n: Int): Stream[A] = {
+ if (n <= 0 || isEmpty) Stream.empty
+ else if (n == 1) new Stream.Cons(head, Stream.empty)
+ else new Stream.Cons(head, tail.take(n - 1))
+ }
+
+ /** Stream specialization of foldLeft which allows GC to collect along the
+ * way.
+ *
+ * @tparam B The type of value being accumulated.
+ * @param z The initial value seeded into the function `op`.
+ * @param op The operation to perform on successive elements of the `Stream`.
+ * @return The accumulated value from successive applications of `op`.
+ */
+ @tailrec
+ override final def foldLeft[B](z: B)(op: (B, A) => B): B = {
+ if (this.isEmpty) z
+ else tail.foldLeft(op(z, head))(op)
+ }
+
+ /** The stream resulting from the concatenation of this stream with the argument stream.
+ * @param rest The collection that gets appended to this stream
+ * @return The stream containing elements of this stream and the iterable object.
+ */
+ @deprecated("The `append` operation has been renamed `lazyAppendedAll`", "2.13.0")
+ @inline final def append[B >: A](rest: => IterableOnce[B]): Stream[B] = lazyAppendedAll(rest)
+
+ protected[this] def writeReplace(): AnyRef =
+ if(nonEmpty && tailDefined) new Stream.SerializationProxy[A](this) else this
+
+ /** Prints elements of this stream one by one, separated by commas. */
+ @deprecated(message = """Use print(stream.force.mkString(", ")) instead""", since = "2.13.0")
+ @inline def print(): Unit = Console.print(this.force.mkString(", "))
+
+ /** Prints elements of this stream one by one, separated by `sep`.
+ * @param sep The separator string printed between consecutive elements.
+ */
+ @deprecated(message = "Use print(stream.force.mkString(sep)) instead", since = "2.13.0")
+ @inline def print(sep: String): Unit = Console.print(this.force.mkString(sep))
+
+ /** The stream resulting from the concatenation of this stream with the argument stream.
+ *
+ * @param suffix The collection that gets appended to this stream
+ * @return The stream containing elements of this stream and the iterable object.
+ */
+ def lazyAppendedAll[B >: A](suffix: => collection.IterableOnce[B]): Stream[B] =
+ if (isEmpty) iterableFactory.from(suffix) else cons[B](head, tail.lazyAppendedAll(suffix))
+
+ override def scanLeft[B](z: B)(op: (B, A) => B): Stream[B] =
+ if (isEmpty) z +: iterableFactory.empty
+ else cons(z, tail.scanLeft(op(z, head))(op))
+
+ /** Stream specialization of reduceLeft which allows GC to collect
+ * along the way.
+ *
+ * @tparam B The type of value being accumulated.
+ * @param f The operation to perform on successive elements of the `Stream`.
+ * @return The accumulated value from successive applications of `f`.
+ */
+ override final def reduceLeft[B >: A](f: (B, A) => B): B = {
+ if (this.isEmpty) throw new UnsupportedOperationException("empty.reduceLeft")
+ else {
+ var reducedRes: B = this.head
+ var left: Stream[A] = this.tail
+ while (!left.isEmpty) {
+ reducedRes = f(reducedRes, left.head)
+ left = left.tail
+ }
+ reducedRes
+ }
+ }
+
+ override def partition(p: A => Boolean): (Stream[A], Stream[A]) = (filter(p(_)), filterNot(p(_)))
+
+ override def filter(pred: A => Boolean): Stream[A] = filterImpl(pred, isFlipped = false)
+
+ override def filterNot(pred: A => Boolean): Stream[A] = filterImpl(pred, isFlipped = true)
+
+ private[immutable] def filterImpl(p: A => Boolean, isFlipped: Boolean): Stream[A] = {
+ // optimization: drop leading prefix of elems for which f returns false
+ // var rest = this dropWhile (!p(_)) - forget DRY principle - GC can't collect otherwise
+ var rest: Stream[A] = coll
+ while (rest.nonEmpty && p(rest.head) == isFlipped) rest = rest.tail
+ // private utility func to avoid `this` on stack (would be needed for the lazy arg)
+ if (rest.nonEmpty) Stream.filteredTail(rest, p, isFlipped)
+ else iterableFactory.empty
+ }
+
+ /** A `collection.WithFilter` which allows GC of the head of stream during processing */
+ override final def withFilter(p: A => Boolean): collection.WithFilter[A, Stream] =
+ Stream.withFilter(coll, p)
+
+ override final def prepended[B >: A](elem: B): Stream[B] = cons(elem, coll)
+
+ override final def map[B](f: A => B): Stream[B] =
+ if (isEmpty) iterableFactory.empty
+ else cons(f(head), tail.map(f))
+
+ @tailrec override final def collect[B](pf: PartialFunction[A, B]): Stream[B] =
+ if(isEmpty) Stream.empty
+ else {
+ var newHead: B = null.asInstanceOf[B]
+ val runWith = pf.runWith((b: B) => newHead = b)
+ if(runWith(head)) Stream.collectedTail(newHead, this, pf)
+ else tail.collect(pf)
+ }
+
+ @tailrec override final def collectFirst[B](pf: PartialFunction[A, B]): Option[B] =
+ if(isEmpty) None
+ else {
+ var newHead: B = null.asInstanceOf[B]
+ val runWith = pf.runWith((b: B) => newHead = b)
+ if(runWith(head)) Some(newHead)
+ else tail.collectFirst(pf)
+ }
+
+ // optimisations are not for speed, but for functionality
+ // see tickets #153, #498, #2147, and corresponding tests in run/ (as well as run/stream_flatmap_odds.scala)
+ override final def flatMap[B](f: A => IterableOnce[B]): Stream[B] =
+ if (isEmpty) iterableFactory.empty
+ else {
+ // establish !prefix.isEmpty || nonEmptyPrefix.isEmpty
+ var nonEmptyPrefix: Stream[A] = coll
+ var prefix = iterableFactory.from(f(nonEmptyPrefix.head))
+ while (!nonEmptyPrefix.isEmpty && prefix.isEmpty) {
+ nonEmptyPrefix = nonEmptyPrefix.tail
+ if(!nonEmptyPrefix.isEmpty)
+ prefix = iterableFactory.from(f(nonEmptyPrefix.head))
+ }
+
+ if (nonEmptyPrefix.isEmpty) iterableFactory.empty
+ else prefix.lazyAppendedAll(nonEmptyPrefix.tail.flatMap(f))
+ }
+
+ override final def zip[B](that: collection.IterableOnce[B]): Stream[(A, B)] =
+ if (this.isEmpty || that.isEmpty) iterableFactory.empty
+ else {
+ val thatIterable = that match {
+ case that: collection.Iterable[B] => that
+ case _ => LazyList.from(that)
+ }
+ cons[(A, B)]((this.head, thatIterable.head), this.tail.zip(thatIterable.tail))
+ }
+
+ override final def zipWithIndex: Stream[(A, Int)] = this.zip(LazyList.from(0))
+
+ protected def tailDefined: Boolean
+
+ /** Appends all elements of this $coll to a string builder using start, end, and separator strings.
+ * The written text begins with the string `start` and ends with the string `end`.
+ * Inside, the string representations (w.r.t. the method `toString`)
+ * of all elements of this $coll are separated by the string `sep`.
+ *
+ * Undefined elements are represented with `"_"`, an undefined tail is represented with `"<not computed>"`,
+ * and cycles are represented with `"<cycle>"`.
+ *
+ * @param sb the string builder to which elements are appended.
+ * @param start the starting string.
+ * @param sep the separator string.
+ * @param end the ending string.
+ * @return the string builder `b` to which elements were appended.
+ */
+ override def addString(sb: StringBuilder, start: String, sep: String, end: String): sb.type = {
+ force
+ addStringNoForce(sb.underlying, start, sep, end)
+ sb
+ }
+
+ private[this] def addStringNoForce(b: JStringBuilder, start: String, sep: String, end: String): b.type = {
+ b.append(start)
+ if (nonEmpty) {
+ b.append(head)
+ var cursor = this
+ def appendCursorElement(): Unit = b.append(sep).append(cursor.head)
+ if (tailDefined) { // If tailDefined, also !isEmpty
+ var scout = tail
+ if (cursor ne scout) {
+ cursor = scout
+ if (scout.tailDefined) {
+ scout = scout.tail
+ // Use 2x 1x iterator trick for cycle detection; slow iterator can add strings
+ while ((cursor ne scout) && scout.tailDefined) {
+ appendCursorElement()
+ cursor = cursor.tail
+ scout = scout.tail
+ if (scout.tailDefined) scout = scout.tail
+ }
+ }
+ }
+ if (!scout.tailDefined) { // Not a cycle, scout hit an end
+ while (cursor ne scout) {
+ appendCursorElement()
+ cursor = cursor.tail
+ }
+ if (cursor.nonEmpty) {
+ appendCursorElement()
+ }
+ }
+ else {
+ // Cycle.
+ // If we have a prefix of length P followed by a cycle of length C,
+ // the scout will be at position (P%C) in the cycle when the cursor
+ // enters it at P. They'll then collide when the scout advances another
+ // C - (P%C) ahead of the cursor.
+ // If we run the scout P farther, then it will be at the start of
+ // the cycle: (C - (P%C) + (P%C)) == C == 0. So if another runner
+ // starts at the beginning of the prefix, they'll collide exactly at
+ // the start of the loop.
+ var runner = this
+ var k = 0
+ while (runner ne scout) {
+ runner = runner.tail
+ scout = scout.tail
+ k += 1
+ }
+ // Now runner and scout are at the beginning of the cycle. Advance
+ // cursor, adding to string, until it hits; then we'll have covered
+ // everything once. If cursor is already at beginning, we'd better
+ // advance one first unless runner didn't go anywhere (in which case
+ // we've already looped once).
+ if ((cursor eq scout) && (k > 0)) {
+ appendCursorElement()
+ cursor = cursor.tail
+ }
+ while (cursor ne scout) {
+ appendCursorElement()
+ cursor = cursor.tail
+ }
+ }
+ }
+ if (cursor.nonEmpty) {
+ // Either undefined or cyclic; we can check with tailDefined
+ if (!cursor.tailDefined) b.append(sep).append("")
+ else b.append(sep).append("")
+ }
+ }
+ b.append(end)
+ b
+ }
+
+ /**
+ * @return a string representation of this collection. Undefined elements are
+ * represented with `"_"`, an undefined tail is represented with `"<not computed>"`,
+ * and cycles are represented with `"<cycle>"`
+ *
+ * Examples:
+ *
+ * - `"Stream(_, <not computed>)"`, a non-empty stream, whose head has not been
+ * evaluated ;
+ * - `"Stream(_, 1, _, <not computed>)"`, a stream with at least three elements,
+ * the second one has been evaluated ;
+ * - `"Stream(1, 2, 3, <cycle>)"`, an infinite stream that contains
+ * a cycle at the fourth element.
+ */
+ override def toString = addStringNoForce(new JStringBuilder(className), "(", ", ", ")").toString
+
+ @deprecated("Check .knownSize instead of .hasDefiniteSize for more actionable information (see scaladoc for details)", "2.13.0")
+ override def hasDefiniteSize: Boolean = isEmpty || {
+ if (!tailDefined) false
+ else {
+ // Two-iterator trick (2x & 1x speed) for cycle detection.
+ var those = this
+ var these = tail
+ while (those ne these) {
+ if (these.isEmpty) return true
+ if (!these.tailDefined) return false
+ these = these.tail
+ if (these.isEmpty) return true
+ if (!these.tailDefined) return false
+ these = these.tail
+ if (those eq these) return false
+ those = those.tail
+ }
+ false // Cycle detected
+ }
+ }
+}
+
+@deprecated("Use LazyList (which is fully lazy) instead of Stream (which has a lazy tail only)", "2.13.0")
+@SerialVersionUID(3L)
+object Stream extends SeqFactory[Stream] {
+
+ /* !!! #11997 This `object cons` must be defined lexically *before* `class Cons` below.
+ * Otherwise it prevents Scala.js from building on Windows.
+ */
+ /** An alternative way of building and matching Streams using Stream.cons(hd, tl).
+ */
+ object cons {
+ /** A stream consisting of a given first element and remaining elements
+ * @param hd The first element of the result stream
+ * @param tl The remaining elements of the result stream
+ */
+ def apply[A](hd: A, tl: => Stream[A]): Stream[A] = new Cons(hd, tl)
+
+ /** Maps a stream to its head and tail */
+ def unapply[A](xs: Stream[A]): Option[(A, Stream[A])] = #::.unapply(xs)
+ }
+
+ //@SerialVersionUID(3L) //TODO Putting an annotation on Stream.empty causes a cyclic dependency in unpickling
+ object Empty extends Stream[Nothing] {
+ override def isEmpty: Boolean = true
+ override def head: Nothing = throw new NoSuchElementException("head of empty stream")
+ override def tail: Stream[Nothing] = throw new UnsupportedOperationException("tail of empty stream")
+ /** Forces evaluation of the whole `Stream` and returns it.
+ *
+ * @note Often we use `Stream`s to represent an infinite set or series. If
+ * that's the case for your particular `Stream` then this function will never
+ * return and will probably crash the VM with an `OutOfMemory` exception.
+ * This function will not hang on a finite cycle, however.
+ *
+ * @return The fully realized `Stream`.
+ */
+ def force: this.type = this
+ override def knownSize: Int = 0
+ protected def tailDefined: Boolean = false
+ }
+
+ @SerialVersionUID(3L)
+ final class Cons[A](override val head: A, tl: => Stream[A]) extends Stream[A] {
+ override def isEmpty: Boolean = false
+ @volatile private[this] var tlVal: Stream[A] = _
+ @volatile private[this] var tlGen = () => tl
+ protected def tailDefined: Boolean = tlGen eq null
+ override def tail: Stream[A] = {
+ if (!tailDefined)
+ synchronized {
+ if (!tailDefined) {
+ tlVal = tlGen()
+ tlGen = null
+ }
+ }
+ tlVal
+ }
+
+ /** Forces evaluation of the whole `Stream` and returns it.
+ *
+ * @note Often we use `Stream`s to represent an infinite set or series. If
+ * that's the case for your particular `Stream` then this function will never
+ * return and will probably crash the VM with an `OutOfMemory` exception.
+ * This function will not hang on a finite cycle, however.
+ *
+ * @return The fully realized `Stream`.
+ */
+ def force: this.type = {
+ // Use standard 2x 1x iterator trick for cycle detection ("those" is slow one)
+ var these, those: Stream[A] = this
+ if (!these.isEmpty) these = these.tail
+ while (those ne these) {
+ if (these.isEmpty) return this
+ these = these.tail
+ if (these.isEmpty) return this
+ these = these.tail
+ if (these eq those) return this
+ those = those.tail
+ }
+ this
+ }
+
+ }
+
+ implicit def toDeferrer[A](l: => Stream[A]): Deferrer[A] = new Deferrer[A](() => l)
+
+ final class Deferrer[A] private[Stream] (private val l: () => Stream[A]) extends AnyVal {
+ /** Construct a Stream consisting of a given first element followed by elements
+ * from another Stream.
+ */
+ def #:: [B >: A](elem: B): Stream[B] = new Cons(elem, l())
+ /** Construct a Stream consisting of the concatenation of the given Stream and
+ * another Stream.
+ */
+ def #:::[B >: A](prefix: Stream[B]): Stream[B] = prefix lazyAppendedAll l()
+ }
+
+ object #:: {
+ def unapply[A](s: Stream[A]): Option[(A, Stream[A])] =
+ if (s.nonEmpty) Some((s.head, s.tail)) else None
+ }
+
+ def from[A](coll: collection.IterableOnce[A]): Stream[A] = coll match {
+ case coll: Stream[A] => coll
+ case _ => fromIterator(coll.iterator)
+ }
+
+ /**
+ * @return A `Stream[A]` that gets its elements from the given `Iterator`.
+ *
+ * @param it Source iterator
+ * @tparam A type of elements
+ */
+ // Note that the resulting `Stream` will be effectively iterable more than once because
+ // `Stream` memoizes its elements
+ def fromIterator[A](it: Iterator[A]): Stream[A] =
+ if (it.hasNext) {
+ new Stream.Cons(it.next(), fromIterator(it))
+ } else Stream.Empty
+
+ def empty[A]: Stream[A] = Empty
+
+ override def newBuilder[A]: mutable.Builder[A, Stream[A]] = ArrayBuffer.newBuilder[A].mapResult(array => from(array))
+
+ private[immutable] def withFilter[A](l: Stream[A] @uncheckedVariance, p: A => Boolean): collection.WithFilter[A, Stream] =
+ new WithFilter[A](l, p)
+
+ private[this] final class WithFilter[A](l: Stream[A] @uncheckedVariance, p: A => Boolean) extends collection.WithFilter[A, Stream] {
+ private[this] var s = l // set to null to allow GC after filtered
+ private[this] lazy val filtered: Stream[A] = { val f = s.filter(p); s = null.asInstanceOf[Stream[A]]; f } // don't set to null if throw during filter
+ def map[B](f: A => B): Stream[B] = filtered.map(f)
+ def flatMap[B](f: A => IterableOnce[B]): Stream[B] = filtered.flatMap(f)
+ def foreach[U](f: A => U): Unit = filtered.foreach(f)
+ def withFilter(q: A => Boolean): collection.WithFilter[A, Stream] = new WithFilter(filtered, q)
+ }
+
+ /** An infinite Stream that repeatedly applies a given function to a start value.
+ *
+ * @param start the start value of the Stream
+ * @param f the function that's repeatedly applied
+ * @return the Stream returning the infinite sequence of values `start, f(start), f(f(start)), ...`
+ */
+ def iterate[A](start: A)(f: A => A): Stream[A] = {
+ cons(start, iterate(f(start))(f))
+ }
+
+ /**
+ * Create an infinite Stream starting at `start` and incrementing by
+ * step `step`.
+ *
+ * @param start the start value of the Stream
+ * @param step the increment value of the Stream
+ * @return the Stream starting at value `start`.
+ */
+ def from(start: Int, step: Int): Stream[Int] =
+ cons(start, from(start + step, step))
+
+ /**
+ * Create an infinite Stream starting at `start` and incrementing by `1`.
+ *
+ * @param start the start value of the Stream
+ * @return the Stream starting at value `start`.
+ */
+ def from(start: Int): Stream[Int] = from(start, 1)
+
+ /**
+ * Create an infinite Stream containing the given element expression (which
+ * is computed for each occurrence).
+ *
+ * @param elem the element composing the resulting Stream
+ * @return the Stream containing an infinite number of elem
+ */
+ def continually[A](elem: => A): Stream[A] = cons(elem, continually(elem))
+
+
+ private[Stream] def filteredTail[A](stream: Stream[A] @uncheckedVariance, p: A => Boolean, isFlipped: Boolean) = {
+ cons(stream.head, stream.tail.filterImpl(p, isFlipped))
+ }
+
+ private[Stream] def collectedTail[A, B](head: B, stream: Stream[A] @uncheckedVariance, pf: PartialFunction[A, B]) = {
+ cons(head, stream.tail.collect(pf))
+ }
+
+ /** This serialization proxy is used for Streams which start with a sequence of evaluated cons cells.
+ * The forced sequence is serialized in a compact, sequential format, followed by the unevaluated tail, which uses
+ * standard Java serialization to store the complete structure of unevaluated thunks. This allows the serialization
+ * of long evaluated streams without exhausting the stack through recursive serialization of cons cells.
+ */
+ @SerialVersionUID(3L)
+ class SerializationProxy[A](@transient protected var coll: Stream[A]) extends Serializable {
+
+ private[this] def writeObject(out: ObjectOutputStream): Unit = {
+ out.defaultWriteObject()
+ var these = coll
+ while(these.nonEmpty && these.tailDefined) {
+ out.writeObject(these.head)
+ these = these.tail
+ }
+ out.writeObject(SerializeEnd)
+ out.writeObject(these)
+ }
+
+ private[this] def readObject(in: ObjectInputStream): Unit = {
+ in.defaultReadObject()
+ val init = new ArrayBuffer[A]
+ var initRead = false
+ while (!initRead) in.readObject match {
+ case SerializeEnd => initRead = true
+ case a => init += a.asInstanceOf[A]
+ }
+ val tail = in.readObject().asInstanceOf[Stream[A]]
+ coll = (init ++: tail)
+ }
+
+ protected[this] def readResolve(): Any = coll
+ }
+}
diff --git a/library/src/scala/collection/immutable/StrictOptimizedSeqOps.scala b/library/src/scala/collection/immutable/StrictOptimizedSeqOps.scala
new file mode 100644
index 000000000000..90b803d54e70
--- /dev/null
+++ b/library/src/scala/collection/immutable/StrictOptimizedSeqOps.scala
@@ -0,0 +1,84 @@
+/*
+ * 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 collection
+package immutable
+
+import scala.collection.generic.CommonErrors
+
+/** Trait that overrides operations to take advantage of strict builders.
+ */
+trait StrictOptimizedSeqOps[+A, +CC[_], +C]
+ extends Any
+ with SeqOps[A, CC, C]
+ with collection.StrictOptimizedSeqOps[A, CC, C]
+ with StrictOptimizedIterableOps[A, CC, C] {
+
+ override def distinctBy[B](f: A => B): C = {
+ if (lengthCompare(1) <= 0) coll
+ else {
+ val builder = newSpecificBuilder
+ val seen = mutable.HashSet.empty[B]
+ val it = this.iterator
+ var different = false
+ while (it.hasNext) {
+ val next = it.next()
+ if (seen.add(f(next))) builder += next else different = true
+ }
+ if (different) builder.result() else coll
+ }
+ }
+
+ override def updated[B >: A](index: Int, elem: B): CC[B] = {
+ if (index < 0)
+ throw (
+ if (knownSize >= 0) CommonErrors.indexOutOfBounds(index = index, max = knownSize)
+ else CommonErrors.indexOutOfBounds(index = index)
+ )
+ val b = iterableFactory.newBuilder[B]
+ b.sizeHint(this)
+ var i = 0
+ val it = iterator
+ while (i < index && it.hasNext) {
+ b += it.next()
+ i += 1
+ }
+ if (!it.hasNext)
+ throw CommonErrors.indexOutOfBounds(index = index, max = i - 1)
+ b += elem
+ it.next()
+ while (it.hasNext) b += it.next()
+ b.result()
+ }
+
+ override def patch[B >: A](from: Int, other: IterableOnce[B], replaced: Int): CC[B] = {
+ val b = iterableFactory.newBuilder[B]
+ var i = 0
+ val it = iterator
+ while (i < from && it.hasNext) {
+ b += it.next()
+ i += 1
+ }
+ b ++= other
+ i = replaced
+ while (i > 0 && it.hasNext) {
+ it.next()
+ i -= 1
+ }
+ while (it.hasNext) b += it.next()
+ b.result()
+ }
+
+ override def sorted[B >: A](implicit ord: Ordering[B]): C = super.sorted(ord)
+
+}
diff --git a/library/src/scala/collection/immutable/TreeMap.scala b/library/src/scala/collection/immutable/TreeMap.scala
new file mode 100644
index 000000000000..ff836499e779
--- /dev/null
+++ b/library/src/scala/collection/immutable/TreeMap.scala
@@ -0,0 +1,370 @@
+/*
+ * 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 collection
+package immutable
+
+import scala.annotation.tailrec
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.generic.DefaultSerializable
+import scala.collection.immutable.{RedBlackTree => RB}
+import scala.collection.mutable.ReusableBuilder
+import scala.runtime.AbstractFunction2
+
+/** An immutable SortedMap whose values are stored in a red-black tree.
+ *
+ * This class is optimal when range queries will be performed,
+ * or when traversal in order of an ordering is desired.
+ * If you only need key lookups, and don't care in which order key-values
+ * are traversed in, consider using * [[scala.collection.immutable.HashMap]],
+ * which will generally have better performance. If you need insertion order,
+ * consider a * [[scala.collection.immutable.SeqMap]], which does not need to
+ * have an ordering supplied.
+ *
+ * @example {{{
+ * import scala.collection.immutable.TreeMap
+ *
+ * // Make a TreeMap via the companion object factory
+ * val weekdays = TreeMap(
+ * 2 -> "Monday",
+ * 3 -> "Tuesday",
+ * 4 -> "Wednesday",
+ * 5 -> "Thursday",
+ * 6 -> "Friday"
+ * )
+ * // TreeMap(2 -> Monday, 3 -> Tuesday, 4 -> Wednesday, 5 -> Thursday, 6 -> Friday)
+ *
+ * val days = weekdays ++ List(1 -> "Sunday", 7 -> "Saturday")
+ * // TreeMap(1 -> Sunday, 2 -> Monday, 3 -> Tuesday, 4 -> Wednesday, 5 -> Thursday, 6 -> Friday, 7 -> Saturday)
+ *
+ * val day3 = days.get(3) // Some("Tuesday")
+ *
+ * val rangeOfDays = days.range(2, 5) // TreeMap(2 -> Monday, 3 -> Tuesday, 4 -> Wednesday)
+ *
+ * val daysUntil2 = days.rangeUntil(2) // TreeMap(1 -> Sunday)
+ * val daysTo2 = days.rangeTo(2) // TreeMap(1 -> Sunday, 2 -> Monday)
+ * val daysAfter5 = days.rangeFrom(5) // TreeMap(5 -> Thursday, 6 -> Friday, 7 -> Saturday)
+ * }}}
+ *
+ * @tparam K the type of the keys contained in this tree map.
+ * @tparam V the type of the values associated with the keys.
+ * @param ordering the implicit ordering used to compare objects of type `A`.
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-immutable-collection-classes.html#red-black-trees "Scala's Collection Library overview"]]
+ * section on `Red-Black Trees` for more information.
+ *
+ * @define Coll immutable.TreeMap
+ * @define coll immutable tree map
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+final class TreeMap[K, +V] private (private val tree: RB.Tree[K, V])(implicit val ordering: Ordering[K])
+ extends AbstractMap[K, V]
+ with SortedMap[K, V]
+ with StrictOptimizedSortedMapOps[K, V, TreeMap, TreeMap[K, V]]
+ with SortedMapFactoryDefaults[K, V, TreeMap, Iterable, Map]
+ with DefaultSerializable {
+
+ def this()(implicit ordering: Ordering[K]) = this(null)(ordering)
+ private[immutable] def tree0: RB.Tree[K, V] = tree
+
+ private[this] def newMapOrSelf[V1 >: V](t: RB.Tree[K, V1]): TreeMap[K, V1] = if(t eq tree) this else new TreeMap[K, V1](t)
+
+ override def sortedMapFactory: SortedMapFactory[TreeMap] = TreeMap
+
+ def iterator: Iterator[(K, V)] = RB.iterator(tree)
+
+ def keysIteratorFrom(start: K): Iterator[K] = RB.keysIterator(tree, Some(start))
+
+ override def keySet: TreeSet[K] = new TreeSet(tree)(ordering)
+
+ def iteratorFrom(start: K): Iterator[(K, V)] = RB.iterator(tree, Some(start))
+
+ override def valuesIteratorFrom(start: K): Iterator[V] = RB.valuesIterator(tree, Some(start))
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[(K, V), S]): S with EfficientSplit =
+ shape.parUnbox(
+ scala.collection.convert.impl.AnyBinaryTreeStepper.from[(K, V), RB.Tree[K, V]](
+ size, tree, _.left, _.right, x => (x.key, x.value)
+ )
+ )
+
+ override def keyStepper[S <: Stepper[_]](implicit shape: StepperShape[K, S]): S with EfficientSplit = {
+ import scala.collection.convert.impl._
+ type T = RB.Tree[K, V]
+ val s = shape.shape match {
+ case StepperShape.IntShape => IntBinaryTreeStepper.from[T] (size, tree, _.left, _.right, _.key.asInstanceOf[Int])
+ case StepperShape.LongShape => LongBinaryTreeStepper.from[T] (size, tree, _.left, _.right, _.key.asInstanceOf[Long])
+ case StepperShape.DoubleShape => DoubleBinaryTreeStepper.from[T](size, tree, _.left, _.right, _.key.asInstanceOf[Double])
+ case _ => shape.parUnbox(AnyBinaryTreeStepper.from[K, T](size, tree, _.left, _.right, _.key))
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ override def valueStepper[S <: Stepper[_]](implicit shape: StepperShape[V, S]): S with EfficientSplit = {
+ import scala.collection.convert.impl._
+ type T = RB.Tree[K, V]
+ val s = shape.shape match {
+ case StepperShape.IntShape => IntBinaryTreeStepper.from[T] (size, tree, _.left, _.right, _.value.asInstanceOf[Int])
+ case StepperShape.LongShape => LongBinaryTreeStepper.from[T] (size, tree, _.left, _.right, _.value.asInstanceOf[Long])
+ case StepperShape.DoubleShape => DoubleBinaryTreeStepper.from[T] (size, tree, _.left, _.right, _.value.asInstanceOf[Double])
+ case _ => shape.parUnbox(AnyBinaryTreeStepper.from[V, T] (size, tree, _.left, _.right, _.value.asInstanceOf[V]))
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ def get(key: K): Option[V] = RB.get(tree, key)
+ override def getOrElse[V1 >: V](key: K, default: => V1): V1 = {
+ val resultOrNull = RB.lookup(tree, key)
+ if (resultOrNull eq null) default
+ else resultOrNull.value
+ }
+
+ def removed(key: K): TreeMap[K,V] =
+ newMapOrSelf(RB.delete(tree, key))
+
+ def updated[V1 >: V](key: K, value: V1): TreeMap[K, V1] =
+ newMapOrSelf(RB.update(tree, key, value, overwrite = true))
+
+ override def concat[V1 >: V](that: collection.IterableOnce[(K, V1)]): TreeMap[K, V1] =
+ newMapOrSelf(that match {
+ case tm: TreeMap[K, V] @unchecked if ordering == tm.ordering =>
+ RB.union(tree, tm.tree)
+ case ls: LinearSeq[(K,V1)] =>
+ if (ls.isEmpty) tree //to avoid the creation of the adder
+ else {
+ val adder = new Adder[V1]
+ adder.addAll(ls)
+ adder.finalTree
+ }
+ case _ =>
+ val adder = new Adder[V1]
+ val it = that.iterator
+ while (it.hasNext) {
+ adder.apply(it.next())
+ }
+ adder.finalTree
+ })
+
+ override def removedAll(keys: IterableOnce[K]): TreeMap[K, V] = keys match {
+ case ts: TreeSet[K] if ordering == ts.ordering =>
+ newMapOrSelf(RB.difference(tree, ts.tree))
+ case _ => super.removedAll(keys)
+ }
+
+ /** A new TreeMap with the entry added is returned,
+ * assuming that key is not in the TreeMap.
+ *
+ * @tparam V1 type of the values of the new bindings, a supertype of `V`
+ * @param key the key to be inserted
+ * @param value the value to be associated with `key`
+ * @return a new $coll with the inserted binding, if it wasn't present in the map
+ */
+ @deprecated("Use `updated` instead", "2.13.0")
+ def insert[V1 >: V](key: K, value: V1): TreeMap[K, V1] = {
+ assert(!RB.contains(tree, key))
+ updated(key, value)
+ }
+
+ def rangeImpl(from: Option[K], until: Option[K]): TreeMap[K, V] = newMapOrSelf(RB.rangeImpl(tree, from, until))
+
+ override def minAfter(key: K): Option[(K, V)] = RB.minAfter(tree, key) match {
+ case null => Option.empty
+ case x => Some((x.key, x.value))
+ }
+
+ override def maxBefore(key: K): Option[(K, V)] = RB.maxBefore(tree, key) match {
+ case null => Option.empty
+ case x => Some((x.key, x.value))
+ }
+
+ override def range(from: K, until: K): TreeMap[K,V] = newMapOrSelf(RB.range(tree, from, until))
+
+ override def foreach[U](f: ((K, V)) => U): Unit = RB.foreach(tree, f)
+ override def foreachEntry[U](f: (K, V) => U): Unit = RB.foreachEntry(tree, f)
+ override def size: Int = RB.count(tree)
+ override def knownSize: Int = size
+
+ override def isEmpty = size == 0
+
+ override def firstKey: K = RB.smallest(tree).key
+
+ override def lastKey: K = RB.greatest(tree).key
+
+ override def head: (K, V) = {
+ val smallest = RB.smallest(tree)
+ (smallest.key, smallest.value)
+ }
+
+ override def last: (K, V) = {
+ val greatest = RB.greatest(tree)
+ (greatest.key, greatest.value)
+ }
+
+ override def tail: TreeMap[K, V] = new TreeMap(RB.tail(tree))
+
+ override def init: TreeMap[K, V] = new TreeMap(RB.init(tree))
+
+ override def drop(n: Int): TreeMap[K, V] = {
+ if (n <= 0) this
+ else if (n >= size) empty
+ else new TreeMap(RB.drop(tree, n))
+ }
+
+ override def take(n: Int): TreeMap[K, V] = {
+ if (n <= 0) empty
+ else if (n >= size) this
+ else new TreeMap(RB.take(tree, n))
+ }
+
+ override def slice(from: Int, until: Int) = {
+ if (until <= from) empty
+ else if (from <= 0) take(until)
+ else if (until >= size) drop(from)
+ else new TreeMap(RB.slice(tree, from, until))
+ }
+
+ override def dropRight(n: Int): TreeMap[K, V] = take(size - math.max(n, 0))
+
+ override def takeRight(n: Int): TreeMap[K, V] = drop(size - math.max(n, 0))
+
+ private[this] def countWhile(p: ((K, V)) => Boolean): Int = {
+ var result = 0
+ val it = iterator
+ while (it.hasNext && p(it.next())) result += 1
+ result
+ }
+
+ override def dropWhile(p: ((K, V)) => Boolean): TreeMap[K, V] = drop(countWhile(p))
+
+ override def takeWhile(p: ((K, V)) => Boolean): TreeMap[K, V] = take(countWhile(p))
+
+ override def span(p: ((K, V)) => Boolean): (TreeMap[K, V], TreeMap[K, V]) = splitAt(countWhile(p))
+
+ override def filter(f: ((K, V)) => Boolean): TreeMap[K, V] =
+ newMapOrSelf(RB.filterEntries[K, V](tree, (k, v) => f((k, v))))
+
+ override def partition(p: ((K, V)) => Boolean): (TreeMap[K, V], TreeMap[K, V]) = {
+ val (l, r) = RB.partitionEntries[K, V](tree, (k, v) => p((k, v)))
+ (newMapOrSelf(l), newMapOrSelf(r))
+ }
+
+ override def transform[W](f: (K, V) => W): TreeMap[K, W] = {
+ val t2 = RB.transform[K, V, W](tree, f)
+ if(t2 eq tree) this.asInstanceOf[TreeMap[K, W]]
+ else new TreeMap(t2)
+ }
+
+ private final class Adder[B1 >: V]
+ extends RB.MapHelper[K, B1] with Function1[(K, B1), Unit] {
+ private var currentMutableTree: RB.Tree[K,B1] = tree0
+ def finalTree = beforePublish(currentMutableTree)
+ override def apply(kv: (K, B1)): Unit = {
+ currentMutableTree = mutableUpd(currentMutableTree, kv._1, kv._2)
+ }
+ @tailrec def addAll(ls: LinearSeq[(K, B1)]): Unit = {
+ if (!ls.isEmpty) {
+ val kv = ls.head
+ currentMutableTree = mutableUpd(currentMutableTree, kv._1, kv._2)
+ addAll(ls.tail)
+ }
+ }
+ }
+ override def equals(obj: Any): Boolean = obj match {
+ case that: TreeMap[K @unchecked, _] if ordering == that.ordering => RB.entriesEqual(tree, that.tree)
+ case _ => super.equals(obj)
+ }
+
+ override protected[this] def className = "TreeMap"
+}
+
+/** $factoryInfo
+ * @define Coll immutable.TreeMap
+ * @define coll immutable tree map
+ */
+@SerialVersionUID(3L)
+object TreeMap extends SortedMapFactory[TreeMap] {
+
+ def empty[K : Ordering, V]: TreeMap[K, V] = new TreeMap()
+
+ def from[K, V](it: IterableOnce[(K, V)])(implicit ordering: Ordering[K]): TreeMap[K, V] =
+ it match {
+ case tm: TreeMap[K, V] if ordering == tm.ordering => tm
+ case sm: scala.collection.SortedMap[K, V] if ordering == sm.ordering =>
+ new TreeMap[K, V](RB.fromOrderedEntries(sm.iterator, sm.size))
+ case _ =>
+ var t: RB.Tree[K, V] = null
+ val i = it.iterator
+ while (i.hasNext) {
+ val (k, v) = i.next()
+ t = RB.update(t, k, v, overwrite = true)
+ }
+ new TreeMap[K, V](t)
+ }
+
+ def newBuilder[K, V](implicit ordering: Ordering[K]): ReusableBuilder[(K, V), TreeMap[K, V]] = new TreeMapBuilder[K, V]
+
+ private class TreeMapBuilder[K, V](implicit ordering: Ordering[K])
+ extends RB.MapHelper[K, V]
+ with ReusableBuilder[(K, V), TreeMap[K, V]] {
+ type Tree = RB.Tree[K, V]
+ private var tree:Tree = null
+
+ def addOne(elem: (K, V)): this.type = {
+ tree = mutableUpd(tree, elem._1, elem._2)
+ this
+ }
+ private object adder extends AbstractFunction2[K, V, Unit] {
+ // we cache tree to avoid the outer access to tree
+ // in the hot path (apply)
+ private[this] var accumulator :Tree = null
+ def addForEach(hasForEach: collection.Map[K, V]): Unit = {
+ accumulator = tree
+ hasForEach.foreachEntry(this)
+ tree = accumulator
+ // be friendly to GC
+ accumulator = null
+ }
+
+ override def apply(key: K, value: V): Unit = {
+ accumulator = mutableUpd(accumulator, key, value)
+ }
+ }
+
+ override def addAll(xs: IterableOnce[(K, V)]): this.type = {
+ xs match {
+ // TODO consider writing a mutable-safe union for TreeSet/TreeMap builder ++=
+ // for the moment we have to force immutability before the union
+ // which will waste some time and space
+ // calling `beforePublish` makes `tree` immutable
+ case ts: TreeMap[K, V] if ts.ordering == ordering =>
+ if (tree eq null) tree = ts.tree0
+ else tree = RB.union(beforePublish(tree), ts.tree0)
+ case that: collection.Map[K, V] =>
+ //add avoiding creation of tuples
+ adder.addForEach(that)
+ case _ =>
+ super.addAll(xs)
+ }
+ this
+ }
+
+ override def clear(): Unit = {
+ tree = null
+ }
+
+ override def result(): TreeMap[K, V] = new TreeMap[K, V](beforePublish(tree))
+ }
+}
diff --git a/library/src/scala/collection/immutable/TreeSeqMap.scala b/library/src/scala/collection/immutable/TreeSeqMap.scala
new file mode 100644
index 000000000000..4eaa8487b6ff
--- /dev/null
+++ b/library/src/scala/collection/immutable/TreeSeqMap.scala
@@ -0,0 +1,650 @@
+/*
+ * 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 collection
+package immutable
+
+import scala.annotation.tailrec
+
+/** This class implements an immutable map that preserves order using
+ * a hash map for the key to value mapping to provide efficient lookup,
+ * and a tree for the ordering of the keys to provide efficient
+ * insertion/modification order traversal and destructuring.
+ *
+ * By default insertion order (`TreeSeqMap.OrderBy.Insertion`)
+ * is used, but modification order (`TreeSeqMap.OrderBy.Modification`)
+ * can be used instead if so specified at creation.
+ *
+ * The `orderingBy(orderBy: TreeSeqMap.OrderBy): TreeSeqMap[K, V]` method
+ * can be used to switch to the specified ordering for the returned map.
+ *
+ * A key can be manually refreshed (i.e. placed at the end) via the
+ * `refresh(key: K): TreeSeqMap[K, V]` method (regardless of the ordering in
+ * use).
+ *
+ * Internally, an ordinal counter is increased for each insertion/modification
+ * and then the current ordinal is used as key in the tree map. After 2^32^
+ * insertions/modifications the entire map is copied (thus resetting the ordinal
+ * counter).
+ *
+ * @tparam K the type of the keys contained in this map.
+ * @tparam V the type of the values associated with the keys in this map.
+ * @define coll immutable tree seq map
+ * @define Coll `immutable.TreeSeqMap`
+ */
+final class TreeSeqMap[K, +V] private (
+ private val ordering: TreeSeqMap.Ordering[K],
+ private val mapping: TreeSeqMap.Mapping[K, V],
+ private val ordinal: Int,
+ val orderedBy: TreeSeqMap.OrderBy)
+ extends AbstractMap[K, V]
+ with SeqMap[K, V]
+ with MapOps[K, V, TreeSeqMap, TreeSeqMap[K, V]]
+ with StrictOptimizedIterableOps[(K, V), Iterable, TreeSeqMap[K, V]]
+ with StrictOptimizedMapOps[K, V, TreeSeqMap, TreeSeqMap[K, V]]
+ with MapFactoryDefaults[K, V, TreeSeqMap, Iterable] {
+
+ import TreeSeqMap._
+
+ override protected[this] def className: String = "TreeSeqMap"
+
+ override def mapFactory: MapFactory[TreeSeqMap] = TreeSeqMap
+
+ override val size = mapping.size
+
+ override def knownSize: Int = size
+
+ override def isEmpty = size == 0
+
+ /*
+ // This should have been overridden in 2.13.0 but wasn't so it will have to wait since it is not forwards compatible
+ // Now handled in inherited method from scala.collection.MapFactoryDefaults instead.
+ override def empty = TreeSeqMap.empty[K, V](orderedBy)
+ */
+
+ def orderingBy(orderBy: OrderBy): TreeSeqMap[K, V] = {
+ if (orderBy == this.orderedBy) this
+ else if (isEmpty) TreeSeqMap.empty(orderBy)
+ else new TreeSeqMap(ordering, mapping, ordinal, orderBy)
+ }
+
+ def updated[V1 >: V](key: K, value: V1): TreeSeqMap[K, V1] = {
+ mapping.get(key) match {
+ case e if ordinal == -1 && (orderedBy == OrderBy.Modification || e.isEmpty) =>
+ // Reinsert into fresh instance to restart ordinal counting, expensive but only done after 2^32 updates.
+ TreeSeqMap.empty[K, V1](orderedBy) ++ this + (key -> value)
+ case Some((o, _)) if orderedBy == OrderBy.Insertion =>
+ new TreeSeqMap(
+ ordering.include(o, key),
+ mapping.updated[(Int, V1)](key, (o, value)),
+ ordinal, // Do not increment the ordinal since the key is already present, i.e. o <= ordinal.
+ orderedBy)
+ case Some((o, _)) =>
+ val o1 = increment(ordinal)
+ new TreeSeqMap(
+ ordering.exclude(o).append(o1, key),
+ mapping.updated[(Int, V1)](key, (o1, value)),
+ o1,
+ orderedBy)
+ case None =>
+ val o1 = increment(ordinal)
+ new TreeSeqMap(
+ ordering.append(o1, key),
+ mapping.updated[(Int, V1)](key, (o1, value)),
+ o1,
+ orderedBy)
+ }
+ }
+
+ def removed(key: K): TreeSeqMap[K, V] = {
+ mapping.get(key) match {
+ case Some((o, _)) =>
+ new TreeSeqMap(
+ ordering.exclude(o),
+ mapping.removed(key),
+ ordinal,
+ orderedBy)
+ case None =>
+ this
+ }
+ }
+
+ def refresh(key: K): TreeSeqMap[K, V] = {
+ mapping.get(key) match {
+ case Some((o, _)) =>
+ val o1 = increment(ordinal)
+ new TreeSeqMap(
+ ordering.exclude(o).append(o1, key),
+ mapping,
+ o1,
+ orderedBy)
+ case None =>
+ this
+ }
+ }
+
+ def get(key: K): Option[V] = mapping.get(key).map(value)
+
+ def iterator: Iterator[(K, V)] = new AbstractIterator[(K, V)] {
+ private[this] val iter = ordering.iterator
+
+ override def hasNext: Boolean = iter.hasNext
+
+ override def next(): (K, V) = binding(iter.next())
+ }
+
+ override def keysIterator: Iterator[K] = new AbstractIterator[K] {
+ private[this] val iter = ordering.iterator
+
+ override def hasNext: Boolean = iter.hasNext
+
+ override def next(): K = iter.next()
+ }
+
+ override def valuesIterator: Iterator[V] = new AbstractIterator[V] {
+ private[this] val iter = ordering.iterator
+
+ override def hasNext: Boolean = iter.hasNext
+
+ override def next(): V = value(binding(iter.next()))
+ }
+
+ override def contains(key: K): Boolean = mapping.contains(key)
+
+ override def head: (K, V) = binding(ordering.head)
+
+ override def headOption = ordering.headOption.map(binding)
+
+ override def last: (K, V) = binding(ordering.last)
+
+ override def lastOption: Option[(K, V)] = ordering.lastOption.map(binding)
+
+ override def tail: TreeSeqMap[K, V] = {
+ val (head, tail) = ordering.headTail
+ new TreeSeqMap(tail, mapping.removed(head), ordinal, orderedBy)
+ }
+
+ override def init: TreeSeqMap[K, V] = {
+ val (init, last) = ordering.initLast
+ new TreeSeqMap(init, mapping.removed(last), ordinal, orderedBy)
+ }
+
+ override def slice(from: Int, until: Int): TreeSeqMap[K, V] = {
+ val sz = size
+ if (sz == 0 || from >= until) TreeSeqMap.empty[K, V](orderedBy)
+ else {
+ val sz = size
+ val f = if (from >= 0) from else 0
+ val u = if (until <= sz) until else sz
+ val l = u - f
+ if (l <= 0) TreeSeqMap.empty[K, V](orderedBy)
+ else if (l > sz / 2) {
+ // Remove front and rear incrementally if majority of elements are to be kept
+ val (front, rest) = ordering.splitAt(f)
+ val (ong, rear) = rest.splitAt(l)
+ var mng = this.mapping
+ val frontIter = front.iterator
+ while (frontIter.hasNext) {
+ mng = mng - frontIter.next()
+ }
+ val rearIter = rear.iterator
+ while (rearIter.hasNext) {
+ mng = mng - rearIter.next()
+ }
+ new TreeSeqMap(ong, mng, ordinal, orderedBy)
+ } else {
+ // Populate with builder otherwise
+ val bdr = newBuilder[K, V](orderedBy)
+ val iter = ordering.iterator
+ var i = 0
+ while (i < f) {
+ iter.next()
+ i += 1
+ }
+ while (i < u) {
+ val k = iter.next()
+ bdr.addOne((k, mapping(k)._2))
+ i += 1
+ }
+ bdr.result()
+ }
+ }
+ }
+
+ override def map[K2, V2](f: ((K, V)) => (K2, V2)): TreeSeqMap[K2, V2] = {
+ val bdr = newBuilder[K2, V2](orderedBy)
+ val iter = ordering.iterator
+ while (iter.hasNext) {
+ val k = iter.next()
+ val (_, v) = mapping(k)
+ val (k2, v2) = f((k, v))
+ bdr.addOne((k2, v2))
+ }
+ bdr.result()
+ }
+
+ override def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): TreeSeqMap[K2, V2] = {
+ val bdr = newBuilder[K2, V2](orderedBy)
+ val iter = ordering.iterator
+ while (iter.hasNext) {
+ val k = iter.next()
+ val (_, v) = mapping(k)
+ val jter = f((k, v)).iterator
+ while (jter.hasNext) {
+ val (k2, v2) = jter.next()
+ bdr.addOne((k2, v2))
+ }
+ }
+ bdr.result()
+ }
+
+ override def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)]): TreeSeqMap[K2, V2] = {
+ val bdr = newBuilder[K2, V2](orderedBy)
+ val iter = ordering.iterator
+ while (iter.hasNext) {
+ val k = iter.next()
+ val (_, v) = mapping(k)
+ pf.runWith({ case (k2, v2) => bdr.addOne((k2, v2)) })((k, v))
+ }
+ bdr.result()
+ }
+
+ override def concat[V2 >: V](suffix: IterableOnce[(K, V2)]): TreeSeqMap[K, V2] = {
+ var ong: Ordering[K] = ordering
+ var mng: Mapping[K, V2] = mapping
+ var ord = increment(ordinal)
+ val iter = suffix.iterator
+ while (iter.hasNext) {
+ val (k, v2) = iter.next()
+ mng.get(k) match {
+ case Some((o, v)) =>
+ if (orderedBy == OrderBy.Insertion && v != v2) mng = mng.updated(k, (o, v2))
+ else if (orderedBy == OrderBy.Modification) {
+ mng = mng.updated(k, (ord, v2))
+ ong = ong.exclude(o).append(ord, k)
+ ord = increment(ord)
+ }
+ case None =>
+ mng = mng.updated(k, (ord, v2))
+ ong = ong.append(ord, k)
+ ord = increment(ord)
+ }
+ }
+ new TreeSeqMap[K, V2](ong, mng, ord, orderedBy)
+ }
+
+ @`inline` private[this] def value(p: (_, V)) = p._2
+ @`inline` private[this] def binding(k: K) = mapping(k).copy(_1 = k)
+}
+object TreeSeqMap extends MapFactory[TreeSeqMap] {
+ sealed trait OrderBy
+ object OrderBy {
+ case object Insertion extends OrderBy
+ case object Modification extends OrderBy
+ }
+
+ private val EmptyByInsertion = new TreeSeqMap[Nothing, Nothing](Ordering.empty, HashMap.empty, 0, OrderBy.Insertion)
+ private val EmptyByModification = new TreeSeqMap[Nothing, Nothing](Ordering.empty, HashMap.empty, 0, OrderBy.Modification)
+ val Empty = EmptyByInsertion
+ def empty[K, V]: TreeSeqMap[K, V] = empty(OrderBy.Insertion)
+ def empty[K, V](orderBy: OrderBy): TreeSeqMap[K, V] = {
+ if (orderBy == OrderBy.Modification) EmptyByModification
+ else EmptyByInsertion
+ }.asInstanceOf[TreeSeqMap[K, V]]
+
+ def from[K, V](it: collection.IterableOnce[(K, V)]): TreeSeqMap[K, V] =
+ it match {
+ case om: TreeSeqMap[K, V] => om
+ case _ => (newBuilder[K, V] ++= it).result()
+ }
+
+ @inline private def increment(ord: Int) = if (ord == Int.MaxValue) Int.MinValue else ord + 1
+
+ def newBuilder[K, V]: mutable.Builder[(K, V), TreeSeqMap[K, V]] = newBuilder(OrderBy.Insertion)
+ def newBuilder[K, V](orderedBy: OrderBy): mutable.Builder[(K, V), TreeSeqMap[K, V]] = new Builder[K, V](orderedBy)
+
+ final class Builder[K, V](orderedBy: OrderBy) extends mutable.Builder[(K, V), TreeSeqMap[K, V]] {
+ private[this] val bdr = new MapBuilderImpl[K, (Int, V)]
+ private[this] var ong = Ordering.empty[K]
+ private[this] var ord = 0
+ private[this] var aliased: TreeSeqMap[K, V] = _
+
+ override def addOne(elem: (K, V)): this.type = addOne(elem._1, elem._2)
+ def addOne(key: K, value: V): this.type = {
+ if (aliased ne null) {
+ aliased = aliased.updated(key, value)
+ } else {
+ bdr.getOrElse(key, null) match {
+ case (o, v) =>
+ if (orderedBy == OrderBy.Insertion && v != value) bdr.addOne(key, (o, value))
+ else if (orderedBy == OrderBy.Modification) {
+ bdr.addOne(key, (ord, value))
+ ong = ong.exclude(o).appendInPlace(ord, key)
+ ord = increment(ord)
+ }
+ case null =>
+ bdr.addOne(key, (ord, value))
+ ong = ong.appendInPlace(ord, key)
+ ord = increment(ord)
+ }
+ }
+ this
+ }
+
+ override def clear(): Unit = {
+ ong = Ordering.empty
+ ord = 0
+ bdr.clear()
+ aliased = null
+ }
+
+ override def result(): TreeSeqMap[K, V] = {
+ if (aliased eq null) {
+ aliased = new TreeSeqMap(ong, bdr.result(), ord, orderedBy)
+ }
+ aliased
+ }
+ }
+
+ private type Mapping[K, +V] = Map[K, (Int, V)]
+ @annotation.unused
+ private val Mapping = Map
+
+ /* The ordering implementation below is an adapted version of immutable.IntMap. */
+ private[immutable] object Ordering {
+ import scala.collection.generic.BitOperations.Int.{Int => _, _}
+
+ @inline private[immutable] def toBinaryString(i: Int): String = s"$i/${i.toBinaryString}"
+
+ def empty[T] : Ordering[T] = Zero
+
+ def apply[T](elems: (Int, T)*): Ordering[T] =
+ elems.foldLeft(empty[T])((x, y) => x.include(y._1, y._2))
+
+ // Iterator over a non-empty Ordering.
+ final class Iterator[+V](it: Ordering[V]) {
+ // Basically this uses a simple stack to emulate conversion over the tree. However
+ // because we know that Ints are at least 32 bits we can have at most 32 Bins and
+ // one Tip sitting on the tree at any point. Therefore we know the maximum stack
+ // depth is 33
+ private[this] var index = 0
+ private[this] val buffer = new Array[AnyRef](33)
+
+ private[this] def pop = {
+ index -= 1
+ buffer(index).asInstanceOf[Ordering[V]]
+ }
+
+ private[this] def push[V2 >: V](x: Ordering[V2]): Unit = {
+ buffer(index) = x.asInstanceOf[AnyRef]
+ index += 1
+ }
+
+ if (it != Zero) push(it)
+
+ def hasNext = index > 0
+ @tailrec
+ def next(): V =
+ if (!hasNext) scala.collection.Iterator.empty.next()
+ else pop match {
+ case Bin(_,_, Tip(_, v), right) =>
+ push(right)
+ v
+ case Bin(_, _, left, right) =>
+ push(right)
+ push(left)
+ next()
+ case Tip(_, v) => v
+ // This should never happen. We don't allow Ordering.Zero in subtrees of the Ordering
+ // and don't return an Ordering.Iterator for Ordering.Zero.
+ case Zero => throw new IllegalStateException("empty subtree not allowed")
+ }
+ }
+
+ object Iterator {
+ val Empty = new Iterator[Nothing](Ordering.empty[Nothing])
+ def empty[V]: Iterator[V] = Empty.asInstanceOf[Iterator[V]]
+ }
+
+ case object Zero extends Ordering[Nothing] {
+ // Important! Without this equals method in place, an infinite
+ // loop from Map.equals => size => pattern-match-on-Nil => equals
+ // develops. Case objects and custom equality don't mix without
+ // careful handling.
+ override def equals(that : Any): Boolean = that match {
+ case _: this.type => true
+ case _: Ordering[_] => false // The only empty Orderings are eq Nil
+ case _ => super.equals(that)
+ }
+ protected def format(sb: StringBuilder, prefix: String, subPrefix: String): Unit = sb ++= s"${prefix}Ø"
+ }
+
+ final case class Tip[+T](ord: Int, value: T) extends Ordering[T] {
+ def withValue[S](s: S) =
+ if (s.asInstanceOf[AnyRef] eq value.asInstanceOf[AnyRef]) this.asInstanceOf[Tip[S]]
+ else Tip(ord, s)
+ protected def format(sb: StringBuilder, prefix: String, subPrefix: String): Unit = sb ++= s"${prefix}Tip(${toBinaryString(ord)} -> $value)\n"
+ }
+
+ final case class Bin[+T](prefix: Int, mask: Int, left: Ordering[T], var right: Ordering[T] @scala.annotation.unchecked.uncheckedVariance) extends Ordering[T] {
+ def bin[S](left: Ordering[S], right: Ordering[S]): Ordering[S] = {
+ if ((this.left eq left) && (this.right eq right)) this.asInstanceOf[Bin[S]]
+ else Bin[S](prefix, mask, left, right)
+ }
+ protected def format(sb: StringBuilder, prefix: String, subPrefix: String): Unit = {
+ sb ++= s"${prefix}Bin(${toBinaryString(this.prefix)}:${toBinaryString(mask)})\n"
+ left.format(sb, subPrefix + "├── ", subPrefix + "│ ")
+ right.format(sb, subPrefix + "└── ", subPrefix + " ")
+ }
+ }
+
+ private def branchMask(i: Int, j: Int) = highestOneBit(i ^ j)
+
+ private def join[T](p1: Int, t1: Ordering[T], p2: Int, t2: Ordering[T]): Ordering[T] = {
+ val m = branchMask(p1, p2)
+ val p = mask(p1, m)
+ if (zero(p1, m)) Bin(p, m, t1, t2)
+ else Bin(p, m, t2, t1)
+ }
+
+ private def bin[T](prefix: Int, mask: Int, left: Ordering[T], right: Ordering[T]): Ordering[T] = (left, right) match {
+ case (l, Zero) => l
+ case (Zero, r) => r
+ case (l, r) => Bin(prefix, mask, l, r)
+ }
+ }
+
+ sealed abstract class Ordering[+T] {
+ import Ordering._
+ import scala.annotation.tailrec
+ import scala.collection.generic.BitOperations.Int._
+
+ override final def toString: String = format
+ final def format: String = {
+ val sb = new StringBuilder
+ format(sb, "", "")
+ sb.toString()
+ }
+ protected def format(sb: StringBuilder, prefix: String, subPrefix: String): Unit
+
+ @tailrec
+ final def head: T = this match {
+ case Zero => throw new NoSuchElementException("head of empty map")
+ case Tip(k, v) => v
+ case Bin(_, _, l, _) => l.head
+ }
+
+ @tailrec
+ final def headOption: Option[T] = this match {
+ case Zero => None
+ case Tip(_, v) => Some(v)
+ case Bin(_, _, l, _) => l.headOption
+ }
+
+ @tailrec
+ final def last: T = this match {
+ case Zero => throw new NoSuchElementException("last of empty map")
+ case Tip(_, v) => v
+ case Bin(_, _, _, r) => r.last
+ }
+
+ @tailrec
+ final def lastOption: Option[T] = this match {
+ case Zero => None
+ case Tip(_, v) => Some(v)
+ case Bin(_, _, _, r) => r.lastOption
+ }
+
+ @tailrec
+ final def ordinal: Int = this match {
+ case Zero => 0
+ case Tip(o, _) => o
+ case Bin(_, _, _, r) => r.ordinal
+ }
+
+ final def tail: Ordering[T] = this match {
+ case Zero => throw new NoSuchElementException("tail of empty map")
+ case Tip(_, _) => Zero
+ case Bin(p, m, l, r) => bin(p, m, l.tail, r)
+ }
+
+ final def headTail: (T, Ordering[T]) = this match {
+ case Zero => throw new NoSuchElementException("init of empty map")
+ case Tip(_, v) => (v, Zero)
+ case Bin(p, m, l, r) =>
+ val (head, tail) = l.headTail
+ (head, bin(p, m, tail, r))
+ }
+
+ final def init: Ordering[T] = this match {
+ case Zero => throw new NoSuchElementException("init of empty map")
+ case Tip(_, _) => Zero
+ case Bin(p, m, l, r) =>
+ bin(p, m, l, r.init)
+ }
+
+ final def initLast: (Ordering[T], T) = this match {
+ case Zero => throw new NoSuchElementException("init of empty map")
+ case Tip(_, v) => (Zero, v)
+ case Bin(p, m, l, r) =>
+ val (init, last) = r.initLast
+ (bin(p, m, l, init), last)
+ }
+
+ final def iterator: Iterator[T] = this match {
+ case Zero => Iterator.empty
+ case _ => new Iterator(this)
+ }
+
+ final def include[S >: T](ordinal: Int, value: S): Ordering[S] = this match {
+ case Zero =>
+ Tip(ordinal, value)
+ case Tip(o, _) =>
+ if (ordinal == o) Tip(ordinal, value)
+ else join(ordinal, Tip(ordinal, value), o, this)
+ case Bin(p, m, l, r) =>
+ if (!hasMatch(ordinal, p, m)) join(ordinal, Tip(ordinal, value), p, this)
+ else if (zero(ordinal, m)) Bin(p, m, l.include(ordinal, value), r)
+ else Bin(p, m, l, r.include(ordinal, value))
+ }
+
+ final def append[S >: T](ordinal: Int, value: S): Ordering[S] = this match {
+ case Zero =>
+ Tip(ordinal, value)
+ case Tip(o, _) =>
+ if (ordinal == o) Tip(ordinal, value)
+ else join(ordinal, Tip(ordinal, value), o, this)
+ case Bin(p, m, l, r) =>
+ if (!hasMatch(ordinal, p, m)) join(ordinal, Tip(ordinal, value), p, this)
+ else if (zero(ordinal, m)) throw new IllegalArgumentException(s"Append called with ordinal out of range: $ordinal is not greater than current max ordinal ${this.ordinal}")
+ else Bin(p, m, l, r.append(ordinal, value))
+ }
+
+ @inline private[collection] final def appendInPlace[S >: T](ordinal: Int, value: S): Ordering[S] = appendInPlace1(null, ordinal, value)
+ private[collection] final def appendInPlace1[S >: T](parent: Bin[S], ordinal: Int, value: S): Ordering[S] = this match {
+ case Zero =>
+ Tip(ordinal, value)
+ case Tip(o, _) if o >= ordinal =>
+ throw new IllegalArgumentException(s"Append called with ordinal out of range: $o is not greater than current max ordinal ${this.ordinal}")
+ case Tip(o, _) if parent == null =>
+ join(ordinal, Tip(ordinal, value), o, this)
+ case Tip(o, _) =>
+ parent.right = join(ordinal, Tip(ordinal, value), o, this)
+ parent
+ case b @ Bin(p, m, _, r) =>
+ if (!hasMatch(ordinal, p, m)) {
+ val b2 = join(ordinal, Tip(ordinal, value), p, this)
+ if (parent != null) {
+ parent.right = b2
+ parent
+ } else b2
+ } else if (zero(ordinal, m)) throw new IllegalArgumentException(s"Append called with ordinal out of range: $ordinal is not greater than current max ordinal ${this.ordinal}")
+ else {
+ r.appendInPlace1(b, ordinal, value)
+ this
+ }
+ }
+
+ final def exclude(ordinal: Int): Ordering[T] = this match {
+ case Zero =>
+ Zero
+ case Tip(o, _) =>
+ if (ordinal == o) Zero
+ else this
+ case Bin(p, m, l, r) =>
+ if (!hasMatch(ordinal, p, m)) this
+ else if (zero(ordinal, m)) bin(p, m, l.exclude(ordinal), r)
+ else bin(p, m, l, r.exclude(ordinal))
+ }
+
+ final def splitAt(n: Int): (Ordering[T], Ordering[T]) = {
+ var rear = Ordering.empty[T]
+ var i = n
+ (modifyOrRemove { (o, v) =>
+ i -= 1
+ if (i >= 0) Some(v)
+ else {
+ rear = rear.appendInPlace(o, v)
+ None
+ }
+ }, rear)
+ }
+
+ /**
+ * A combined transform and filter function. Returns an `Ordering` such that
+ * for each `(key, value)` mapping in this map, if `f(key, value) == None`
+ * the map contains no mapping for key, and if `f(key, value) == Some(x)` the
+ * map contains `(key, x)`.
+ *
+ * @tparam S The type of the values in the resulting `LongMap`.
+ * @param f The transforming function.
+ * @return The modified map.
+ */
+ final def modifyOrRemove[S](f: (Int, T) => Option[S]): Ordering[S] = this match {
+ case Zero => Zero
+ case Tip(key, value) =>
+ f(key, value) match {
+ case None => Zero
+ case Some(value2) =>
+ // hack to preserve sharing
+ if (value.asInstanceOf[AnyRef] eq value2.asInstanceOf[AnyRef]) this.asInstanceOf[Ordering[S]]
+ else Tip(key, value2)
+ }
+ case Bin(prefix, mask, left, right) =>
+ val l = left.modifyOrRemove(f)
+ val r = right.modifyOrRemove(f)
+ if ((left eq l) && (right eq r)) this.asInstanceOf[Ordering[S]]
+ else bin(prefix, mask, l, r)
+ }
+ }
+}
diff --git a/library/src/scala/collection/immutable/TreeSet.scala b/library/src/scala/collection/immutable/TreeSet.scala
new file mode 100644
index 000000000000..4348f62ece74
--- /dev/null
+++ b/library/src/scala/collection/immutable/TreeSet.scala
@@ -0,0 +1,296 @@
+/*
+ * 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 collection
+package immutable
+
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.generic.DefaultSerializable
+import scala.collection.mutable.ReusableBuilder
+import scala.collection.immutable.{RedBlackTree => RB}
+import scala.runtime.AbstractFunction1
+
+
+/** This class implements immutable sorted sets using a tree.
+ *
+ * @tparam A the type of the elements contained in this tree set
+ * @param ordering the implicit ordering used to compare objects of type `A`
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-immutable-collection-classes.html#red-black-trees "Scala's Collection Library overview"]]
+ * section on `Red-Black Trees` for more information.
+ *
+ * @define Coll `immutable.TreeSet`
+ * @define coll immutable tree set
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+final class TreeSet[A] private[immutable] (private[immutable] val tree: RB.Tree[A, Any])(implicit val ordering: Ordering[A])
+ extends AbstractSet[A]
+ with SortedSet[A]
+ with SortedSetOps[A, TreeSet, TreeSet[A]]
+ with StrictOptimizedSortedSetOps[A, TreeSet, TreeSet[A]]
+ with SortedSetFactoryDefaults[A, TreeSet, Set]
+ with DefaultSerializable {
+
+ if (ordering eq null) throw new NullPointerException("ordering must not be null")
+
+ def this()(implicit ordering: Ordering[A]) = this(null)(ordering)
+
+ override def sortedIterableFactory: TreeSet.type = TreeSet
+
+ private[this] def newSetOrSelf(t: RB.Tree[A, Any]) = if(t eq tree) this else new TreeSet[A](t)
+
+ override def size: Int = RB.count(tree)
+
+ override def isEmpty = size == 0
+
+ override def head: A = RB.smallest(tree).key
+
+ override def last: A = RB.greatest(tree).key
+
+ override def tail: TreeSet[A] = new TreeSet(RB.tail(tree))
+
+ override def init: TreeSet[A] = new TreeSet(RB.init(tree))
+
+ override def min[A1 >: A](implicit ord: Ordering[A1]): A = {
+ if ((ord eq ordering) && nonEmpty) {
+ head
+ } else {
+ super.min(ord)
+ }
+ }
+
+ override def max[A1 >: A](implicit ord: Ordering[A1]): A = {
+ if ((ord eq ordering) && nonEmpty) {
+ last
+ } else {
+ super.max(ord)
+ }
+ }
+
+ override def drop(n: Int): TreeSet[A] = {
+ if (n <= 0) this
+ else if (n >= size) empty
+ else new TreeSet(RB.drop(tree, n))
+ }
+
+ override def take(n: Int): TreeSet[A] = {
+ if (n <= 0) empty
+ else if (n >= size) this
+ else new TreeSet(RB.take(tree, n))
+ }
+
+ override def slice(from: Int, until: Int): TreeSet[A] = {
+ if (until <= from) empty
+ else if (from <= 0) take(until)
+ else if (until >= size) drop(from)
+ else new TreeSet(RB.slice(tree, from, until))
+ }
+
+ override def dropRight(n: Int): TreeSet[A] = take(size - math.max(n, 0))
+
+ override def takeRight(n: Int): TreeSet[A] = drop(size - math.max(n, 0))
+
+ private[this] def countWhile(p: A => Boolean): Int = {
+ var result = 0
+ val it = iterator
+ while (it.hasNext && p(it.next())) result += 1
+ result
+ }
+ override def dropWhile(p: A => Boolean): TreeSet[A] = drop(countWhile(p))
+
+ override def takeWhile(p: A => Boolean): TreeSet[A] = take(countWhile(p))
+
+ override def span(p: A => Boolean): (TreeSet[A], TreeSet[A]) = splitAt(countWhile(p))
+
+ override def foreach[U](f: A => U): Unit = RB.foreachKey(tree, f)
+
+ override def minAfter(key: A): Option[A] = {
+ val v = RB.minAfter(tree, key)
+ if (v eq null) Option.empty else Some(v.key)
+ }
+
+ override def maxBefore(key: A): Option[A] = {
+ val v = RB.maxBefore(tree, key)
+ if (v eq null) Option.empty else Some(v.key)
+ }
+
+ def iterator: Iterator[A] = RB.keysIterator(tree)
+
+ def iteratorFrom(start: A): Iterator[A] = RB.keysIterator(tree, Some(start))
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit = {
+ import scala.collection.convert.impl._
+ type T = RB.Tree[A, Any]
+ val s = shape.shape match {
+ case StepperShape.IntShape => IntBinaryTreeStepper.from[T] (size, tree, _.left, _.right, _.key.asInstanceOf[Int])
+ case StepperShape.LongShape => LongBinaryTreeStepper.from[T] (size, tree, _.left, _.right, _.key.asInstanceOf[Long])
+ case StepperShape.DoubleShape => DoubleBinaryTreeStepper.from[T](size, tree, _.left, _.right, _.key.asInstanceOf[Double])
+ case _ => shape.parUnbox(AnyBinaryTreeStepper.from[A, T](size, tree, _.left, _.right, _.key))
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ /** Checks if this set contains element `elem`.
+ *
+ * @param elem the element to check for membership.
+ * @return true, iff `elem` is contained in this set.
+ */
+ def contains(elem: A): Boolean = RB.contains(tree, elem)
+
+ override def range(from: A, until: A): TreeSet[A] = newSetOrSelf(RB.range(tree, from, until))
+
+ def rangeImpl(from: Option[A], until: Option[A]): TreeSet[A] = newSetOrSelf(RB.rangeImpl(tree, from, until))
+
+ /** Creates a new `TreeSet` with the entry added.
+ *
+ * @param elem a new element to add.
+ * @return a new $coll containing `elem` and all the elements of this $coll.
+ */
+ def incl(elem: A): TreeSet[A] =
+ newSetOrSelf(RB.update(tree, elem, null, overwrite = false))
+
+ /** Creates a new `TreeSet` with the entry removed.
+ *
+ * @param elem a new element to add.
+ * @return a new $coll containing all the elements of this $coll except `elem`.
+ */
+ def excl(elem: A): TreeSet[A] =
+ newSetOrSelf(RB.delete(tree, elem))
+
+ override def concat(that: collection.IterableOnce[A]): TreeSet[A] = {
+ val t = that match {
+ case ts: TreeSet[A] if ordering == ts.ordering =>
+ RB.union(tree, ts.tree)
+ case _ =>
+ val it = that.iterator
+ var t = tree
+ while (it.hasNext) t = RB.update(t, it.next(), null, overwrite = false)
+ t
+ }
+ newSetOrSelf(t)
+ }
+
+ override def removedAll(that: IterableOnce[A]): TreeSet[A] = that match {
+ case ts: TreeSet[A] if ordering == ts.ordering =>
+ newSetOrSelf(RB.difference(tree, ts.tree))
+ case _ =>
+ //TODO add an implementation of a mutable subtractor similar to TreeMap
+ //but at least this doesn't create a TreeSet for each iteration
+ object sub extends AbstractFunction1[A, Unit] {
+ var currentTree = tree
+ override def apply(k: A): Unit = {
+ currentTree = RB.delete(currentTree, k)
+ }
+ }
+ that.iterator.foreach(sub)
+ newSetOrSelf(sub.currentTree)
+ }
+
+ override def intersect(that: collection.Set[A]): TreeSet[A] = that match {
+ case ts: TreeSet[A] if ordering == ts.ordering =>
+ newSetOrSelf(RB.intersect(tree, ts.tree))
+ case _ =>
+ super.intersect(that)
+ }
+
+ override def diff(that: collection.Set[A]): TreeSet[A] = that match {
+ case ts: TreeSet[A] if ordering == ts.ordering =>
+ newSetOrSelf(RB.difference(tree, ts.tree))
+ case _ =>
+ super.diff(that)
+ }
+
+ override def filter(f: A => Boolean): TreeSet[A] = newSetOrSelf(RB.filterEntries[A, Any](tree, {(k, _) => f(k)}))
+
+ override def partition(p: A => Boolean): (TreeSet[A], TreeSet[A]) = {
+ val (l, r) = RB.partitionEntries(tree, {(a:A, _: Any) => p(a)})
+ (newSetOrSelf(l), newSetOrSelf(r))
+ }
+
+ override def equals(obj: Any): Boolean = obj match {
+ case that: TreeSet[A @unchecked] if ordering == that.ordering => RB.keysEqual(tree, that.tree)
+ case _ => super.equals(obj)
+ }
+
+ override protected[this] def className = "TreeSet"
+}
+
+/**
+ * $factoryInfo
+ *
+ * @define Coll `immutable.TreeSet`
+ * @define coll immutable tree set
+ */
+@SerialVersionUID(3L)
+object TreeSet extends SortedIterableFactory[TreeSet] {
+
+ def empty[A: Ordering]: TreeSet[A] = new TreeSet[A]
+
+ def from[E](it: scala.collection.IterableOnce[E])(implicit ordering: Ordering[E]): TreeSet[E] =
+ it match {
+ case ts: TreeSet[E] if ordering == ts.ordering => ts
+ case ss: scala.collection.SortedSet[E] if ordering == ss.ordering =>
+ new TreeSet[E](RB.fromOrderedKeys(ss.iterator, ss.size))
+ case r: Range if (ordering eq Ordering.Int) || (Ordering.Int isReverseOf ordering) =>
+ val it = if((ordering eq Ordering.Int) == (r.step > 0)) r.iterator else r.reverseIterator
+ val tree = RB.fromOrderedKeys(it.asInstanceOf[Iterator[E]], r.size)
+ // The cast is needed to compile with Dotty:
+ // Dotty doesn't infer that E =:= Int, since instantiation of covariant GADTs is unsound
+ new TreeSet[E](tree)
+ case _ =>
+ var t: RB.Tree[E, Null] = null
+ val i = it.iterator
+ while (i.hasNext) t = RB.update(t, i.next(), null, overwrite = false)
+ new TreeSet[E](t)
+ }
+
+ def newBuilder[A](implicit ordering: Ordering[A]): ReusableBuilder[A, TreeSet[A]] = new TreeSetBuilder[A]
+ private class TreeSetBuilder[A](implicit ordering: Ordering[A])
+ extends RB.SetHelper[A]
+ with ReusableBuilder[A, TreeSet[A]] {
+ type Tree = RB.Tree[A, Any]
+ private [this] var tree:RB.Tree[A, Any] = null
+
+ override def addOne(elem: A): this.type = {
+ tree = mutableUpd(tree, elem)
+ this
+ }
+
+ override def addAll(xs: IterableOnce[A]): this.type = {
+ xs match {
+ // TODO consider writing a mutable-safe union for TreeSet/TreeMap builder ++=
+ // for the moment we have to force immutability before the union
+ // which will waste some time and space
+ // calling `beforePublish` makes `tree` immutable
+ case ts: TreeSet[A] if ts.ordering == ordering =>
+ if (tree eq null) tree = ts.tree
+ else tree = RB.union(beforePublish(tree), ts.tree)(ordering)
+ case ts: TreeMap[A @unchecked, _] if ts.ordering == ordering =>
+ if (tree eq null) tree = ts.tree0
+ else tree = RB.union(beforePublish(tree), ts.tree0)(ordering)
+ case _ =>
+ super.addAll(xs)
+ }
+ this
+ }
+
+ override def clear(): Unit = {
+ tree = null
+ }
+
+ override def result(): TreeSet[A] = new TreeSet[A](beforePublish(tree))(ordering)
+ }
+}
diff --git a/library/src/scala/collection/immutable/Vector.scala b/library/src/scala/collection/immutable/Vector.scala
new file mode 100644
index 000000000000..f38cdbc77b5d
--- /dev/null
+++ b/library/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/src/scala/collection/immutable/VectorMap.scala b/library/src/scala/collection/immutable/VectorMap.scala
new file mode 100644
index 000000000000..361427a86c53
--- /dev/null
+++ b/library/src/scala/collection/immutable/VectorMap.scala
@@ -0,0 +1,278 @@
+/*
+ * 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 collection
+package immutable
+
+import scala.annotation.{nowarn, tailrec}
+
+/** This class implements immutable maps using a vector/map-based data structure, which preserves insertion order.
+ *
+ * Unlike `ListMap`, `VectorMap` has amortized effectively constant lookup at the expense
+ * of using extra memory and generally lower performance for other operations
+ *
+ * @tparam K the type of the keys contained in this vector map.
+ * @tparam V the type of the values associated with the keys in this vector map.
+ *
+ * @define coll immutable vector map
+ * @define Coll `immutable.VectorMap`
+ */
+final class VectorMap[K, +V] private (
+ private[immutable] val fields: Vector[Any], // K | Tombstone | Null
+ private[immutable] val underlying: Map[K, (Int, V)],
+ dropped: Int)
+ extends AbstractMap[K, V]
+ with SeqMap[K, V]
+ with StrictOptimizedMapOps[K, V, VectorMap, VectorMap[K, V]]
+ with MapFactoryDefaults[K, V, VectorMap, Iterable] {
+
+ import VectorMap._
+
+ override protected[this] def className: String = "VectorMap"
+
+ private[immutable] def this(fields: Vector[K], underlying: Map[K, (Int, V)]) = this(fields, underlying, 0)
+
+ override val size = underlying.size
+
+ override def knownSize: Int = size
+
+ override def isEmpty: Boolean = size == 0
+
+ def updated[V1 >: V](key: K, value: V1): VectorMap[K, V1] = {
+ underlying.get(key) match {
+ case Some((slot, _)) =>
+ new VectorMap(fields, underlying.updated[(Int, V1)](key, (slot, value)), dropped)
+ case None =>
+ new VectorMap(fields :+ key, underlying.updated[(Int, V1)](key, (fields.length + dropped, value)), dropped)
+ }
+ }
+
+ override def withDefault[V1 >: V](d: K => V1): Map[K, V1] =
+ new Map.WithDefault(this, d)
+
+ override def withDefaultValue[V1 >: V](d: V1): Map[K, V1] =
+ new Map.WithDefault[K, V1](this, _ => d)
+
+ def get(key: K): Option[V] = underlying.get(key) match {
+ case Some(v) => Some(v._2)
+ case None => None
+ }
+
+ @tailrec
+ private def nextValidField(slot: Int): (Int, K) = {
+ if (slot >= fields.size) (-1, null.asInstanceOf[K])
+ else fields(slot) match {
+ case Tombstone(distance) => nextValidField(slot + distance)
+ case k /*: K | Null */ => (slot, k.asInstanceOf[K])
+ }
+ }
+
+ def iterator: Iterator[(K, V)] = new AbstractIterator[(K, V)] {
+ private[this] val fieldsLength = fields.length
+ private[this] var slot = -1
+ private[this] var key: K = null.asInstanceOf[K]
+
+ private[this] def advance(): Unit = {
+ val nextSlot = slot + 1
+ if (nextSlot >= fieldsLength) {
+ slot = fieldsLength
+ key = null.asInstanceOf[K]
+ } else {
+ nextValidField(nextSlot) match {
+ case (-1, _) =>
+ slot = fieldsLength
+ key = null.asInstanceOf[K]
+ case (s, k) =>
+ slot = s
+ key = k
+ }
+ }
+ }
+
+ advance()
+
+ override def hasNext: Boolean = slot < fieldsLength
+
+ override def next(): (K, V) =
+ if (!hasNext) Iterator.empty.next()
+ else {
+ val result = (key, underlying(key)._2)
+ advance()
+ result
+ }
+ }
+
+ // No-Op overrides to allow for more efficient steppers in a minor release.
+ // Refining the return type to `S with EfficientSplit` is binary compatible.
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[(K, V), S]): S = super.stepper(shape)
+
+ override def keyStepper[S <: Stepper[_]](implicit shape: StepperShape[K, S]): S = super.keyStepper(shape)
+
+ override def valueStepper[S <: Stepper[_]](implicit shape: StepperShape[V, S]): S = super.valueStepper(shape)
+
+
+ def removed(key: K): VectorMap[K, V] = {
+ if (isEmpty) empty
+ else {
+ var fs = fields
+ val sz = fs.size
+ underlying.get(key) match {
+ case Some(_) if size == 1 => empty
+ case Some((slot, _)) =>
+ val s = slot - dropped
+
+ // Calculate next of kin
+ val next =
+ if (s < sz - 1) fs(s + 1) match {
+ case Tombstone(d) => s + d + 1
+ case _ => s + 1
+ } else s + 1
+
+ fs = fs.updated(s, Tombstone(next - s))
+
+ // Calculate first index of preceding tombstone sequence
+ val first =
+ if (s > 0) {
+ fs(s - 1) match {
+ case Tombstone(d) if d < 0 => if (s + d >= 0) s + d else 0
+ case Tombstone(d) if d == 1 => s - 1
+ case Tombstone(d) => throw new IllegalStateException("tombstone indicate wrong position: " + d)
+ case _ => s
+ }
+ }else s
+ fs = fs.updated(first, Tombstone(next - first))
+
+ // Calculate last index of succeeding tombstone sequence
+ val last = next - 1
+ if (last != first) {
+ fs = fs.updated(last, Tombstone(first - 1 - last))
+ }
+ new VectorMap(fs, underlying - key, dropped)
+ case _ =>
+ this
+ }
+ }
+ }
+
+ override def mapFactory: MapFactory[VectorMap] = VectorMap
+
+ override def contains(key: K): Boolean = underlying.contains(key)
+
+ override def head: (K, V) = iterator.next()
+
+ override def last: (K, V) = {
+ if (isEmpty) throw new UnsupportedOperationException("empty.last")
+ val lastSlot = fields.length - 1
+ val last = fields.last match {
+ case Tombstone(d) if d < 0 => fields(lastSlot + d).asInstanceOf[K]
+ case Tombstone(d) if d == 1 => fields(lastSlot - 1).asInstanceOf[K]
+ case Tombstone(d) => throw new IllegalStateException("tombstone indicate wrong position: " + d)
+ case k => k.asInstanceOf[K]
+ }
+ (last, underlying(last)._2)
+ }
+
+ override def lastOption: Option[(K, V)] = {
+ if (isEmpty) None
+ else Some(last)
+ }
+
+ override def tail: VectorMap[K, V] = {
+ if (isEmpty) throw new UnsupportedOperationException("empty.tail")
+ val (slot, key) = nextValidField(0)
+ new VectorMap(fields.drop(slot + 1), underlying - key, dropped + slot + 1)
+ }
+
+ override def init: VectorMap[K, V] = {
+ if (isEmpty) throw new UnsupportedOperationException("empty.init")
+ val lastSlot = fields.size - 1
+ val (slot, key) = fields.last match {
+ case Tombstone(d) if d < 0 => (lastSlot + d, fields(lastSlot + d).asInstanceOf[K])
+ case Tombstone(d) if d == 1 => (lastSlot - 1, fields(lastSlot - 1).asInstanceOf[K])
+ case Tombstone(d) => throw new IllegalStateException("tombstone indicate wrong position: " + d)
+ case k => (lastSlot, k.asInstanceOf[K])
+ }
+ new VectorMap(fields.dropRight(fields.size - slot), underlying - key, dropped)
+ }
+
+ /** A [[Vector]] of the keys contained by this map.
+ *
+ * @return a [[Vector]] of the keys contained by this map.
+ */
+ @nowarn("msg=overriding method keys")
+ override def keys: Vector[K] = keysIterator.toVector
+
+ override def values: Iterable[V] = new Iterable[V] with IterableFactoryDefaults[V, Iterable] {
+ override def iterator: Iterator[V] = keysIterator.map(underlying(_)._2)
+ }
+}
+
+object VectorMap extends MapFactory[VectorMap] {
+ //Class to mark deleted slots in 'fields'.
+ //When one or more consecutive slots are deleted, the 'distance' of the first 'Tombstone'
+ // represents the distance to the location of the next undeleted slot (or the last slot in 'fields' +1 if it does not exist).
+ //When two or more consecutive slots are deleted, the 'distance' of the trailing 'Tombstone'
+ // represents the distance to the location of the previous undeleted slot ( or -1 if it does not exist) multiplied by -1.
+ //For other deleted slots, it simply indicates that they have been deleted.
+ private[VectorMap] final case class Tombstone(distance: Int)
+
+ private[this] final val EmptyMap: VectorMap[Nothing, Nothing] =
+ new VectorMap[Nothing, Nothing](Vector.empty[Nothing], HashMap.empty[Nothing, (Int, Nothing)])
+
+ def empty[K, V]: VectorMap[K, V] = EmptyMap.asInstanceOf[VectorMap[K, V]]
+
+ def from[K, V](it: collection.IterableOnce[(K, V)]): VectorMap[K, V] =
+ it match {
+ case vm: VectorMap[K, V] => vm
+ case _ => (newBuilder[K, V] ++= it).result()
+ }
+
+ def newBuilder[K, V]: mutable.Builder[(K, V), VectorMap[K, V]] = new VectorMapBuilder[K, V]
+}
+
+private[immutable] final class VectorMapBuilder[K, V] extends mutable.Builder[(K, V), VectorMap[K, V]] {
+ private[this] val vectorBuilder = new VectorBuilder[K]
+ private[this] val mapBuilder = new MapBuilderImpl[K, (Int, V)]
+ private[this] var aliased: VectorMap[K, V] = _
+
+ override def clear(): Unit = {
+ vectorBuilder.clear()
+ mapBuilder.clear()
+ aliased = null
+ }
+
+ override def result(): VectorMap[K, V] = {
+ if (aliased eq null) {
+ aliased = new VectorMap(vectorBuilder.result(), mapBuilder.result())
+ }
+ aliased
+ }
+ def addOne(key: K, value: V): this.type = {
+ if (aliased ne null) {
+ aliased = aliased.updated(key, value)
+ } else {
+ mapBuilder.getOrElse(key, null) match {
+ case (slot, _) =>
+ mapBuilder.addOne(key, (slot, value))
+ case null =>
+ val vectorSize = vectorBuilder.size
+ vectorBuilder.addOne(key)
+ mapBuilder.addOne(key, (vectorSize, value))
+ }
+ }
+ this
+ }
+
+ override def addOne(elem: (K, V)): this.type = addOne(elem._1, elem._2)
+}
diff --git a/library/src/scala/collection/immutable/WrappedString.scala b/library/src/scala/collection/immutable/WrappedString.scala
new file mode 100644
index 000000000000..a6c0256fe800
--- /dev/null
+++ b/library/src/scala/collection/immutable/WrappedString.scala
@@ -0,0 +1,139 @@
+/*
+ * 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 scala.Predef.{wrapString => _, assert}
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.convert.impl.CharStringStepper
+import scala.collection.mutable.{Builder, StringBuilder}
+
+/**
+ * This class serves as a wrapper augmenting `String`s with all the operations
+ * found in indexed sequences.
+ *
+ * The difference between this class and `StringOps` is that calling transformer
+ * methods such as `filter` and `map` will yield an object of type `WrappedString`
+ * rather than a `String`.
+ *
+ * @param self a string contained within this wrapped string
+ *
+ * @define Coll `WrappedString`
+ * @define coll wrapped string
+ */
+@SerialVersionUID(3L)
+final class WrappedString(private val self: String) extends AbstractSeq[Char] with IndexedSeq[Char]
+ with IndexedSeqOps[Char, IndexedSeq, WrappedString]
+ with Serializable {
+
+ def apply(i: Int): Char = self.charAt(i)
+
+ override protected def fromSpecific(coll: scala.collection.IterableOnce[Char]): WrappedString = WrappedString.fromSpecific(coll)
+ override protected def newSpecificBuilder: Builder[Char, WrappedString] = WrappedString.newBuilder
+ override def empty: WrappedString = WrappedString.empty
+
+ override def slice(from: Int, until: Int): WrappedString = {
+ val start = if (from < 0) 0 else from
+ if (until <= start || start >= self.length)
+ return WrappedString.empty
+
+ val end = if (until > length) length else until
+ new WrappedString(self.substring(start, end))
+ }
+ override def length = self.length
+ override def toString = self
+ override def view: StringView = new StringView(self)
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Char, S]): S with EfficientSplit = {
+ val st = new CharStringStepper(self, 0, self.length)
+ val r =
+ if (shape.shape == StepperShape.CharShape) st
+ else {
+ assert(shape.shape == StepperShape.ReferenceShape, s"unexpected StepperShape: $shape")
+ AnyStepper.ofParIntStepper(st)
+ }
+ r.asInstanceOf[S with EfficientSplit]
+ }
+
+ override def startsWith[B >: Char](that: IterableOnce[B], offset: Int = 0): Boolean =
+ that match {
+ case s: WrappedString => self.startsWith(s.self, offset)
+ case _ => super.startsWith(that, offset)
+ }
+
+ override def endsWith[B >: Char](that: collection.Iterable[B]): Boolean =
+ that match {
+ case s: WrappedString => self.endsWith(s.self)
+ case _ => super.endsWith(that)
+ }
+
+ override def indexOf[B >: Char](elem: B, from: Int = 0): Int = elem match {
+ case c: Char => self.indexOf(c, from)
+ case _ => super.indexOf(elem, from)
+ }
+
+ override def lastIndexOf[B >: Char](elem: B, end: Int = length - 1): Int =
+ elem match {
+ case c: Char => self.lastIndexOf(c, end)
+ case _ => super.lastIndexOf(elem, end)
+ }
+
+ override def copyToArray[B >: Char](xs: Array[B], start: Int, len: Int): Int =
+ (xs: Any) match {
+ case chs: Array[Char] =>
+ val copied = IterableOnce.elemsToCopyToArray(length, chs.length, start, len)
+ self.getChars(0, copied, chs, start)
+ copied
+ case _ => super.copyToArray(xs, start, len)
+ }
+
+ override def appendedAll[B >: Char](suffix: IterableOnce[B]): IndexedSeq[B] =
+ suffix match {
+ case s: WrappedString => new WrappedString(self concat s.self)
+ case _ => super.appendedAll(suffix)
+ }
+
+ override def sameElements[B >: Char](o: IterableOnce[B]) = o match {
+ case s: WrappedString => self == s.self
+ case _ => super.sameElements(o)
+ }
+
+ override protected[this] def className = "WrappedString"
+
+ override protected final def applyPreferredMaxLength: Int = Int.MaxValue
+ override def equals(other: Any): Boolean = other match {
+ case that: WrappedString =>
+ this.self == that.self
+ case _ =>
+ super.equals(other)
+ }
+}
+
+/** A companion object for wrapped strings.
+ */
+@SerialVersionUID(3L)
+object WrappedString extends SpecificIterableFactory[Char, WrappedString] {
+ def fromSpecific(it: IterableOnce[Char]): WrappedString = {
+ val b = newBuilder
+ b.sizeHint(it)
+ b ++= it
+ b.result()
+ }
+ val empty: WrappedString = new WrappedString("")
+ def newBuilder: Builder[Char, WrappedString] =
+ new StringBuilder().mapResult(x => new WrappedString(x))
+
+ implicit class UnwrapOp(private val value: WrappedString) extends AnyVal {
+ def unwrap: String = value.self
+ }
+}
diff --git a/library/src/scala/collection/immutable/package.scala b/library/src/scala/collection/immutable/package.scala
new file mode 100644
index 000000000000..6a92c8cef284
--- /dev/null
+++ b/library/src/scala/collection/immutable/package.scala
@@ -0,0 +1,29 @@
+/*
+ * 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 object immutable {
+ type StringOps = scala.collection.StringOps
+ val StringOps = scala.collection.StringOps
+ type StringView = scala.collection.StringView
+ val StringView = scala.collection.StringView
+
+ @deprecated("Use Iterable instead of Traversable", "2.13.0")
+ type Traversable[+X] = Iterable[X]
+ @deprecated("Use Iterable instead of Traversable", "2.13.0")
+ val Traversable = Iterable
+
+ @deprecated("Use Map instead of DefaultMap", "2.13.0")
+ type DefaultMap[K, +V] = scala.collection.immutable.Map[K, V]
+}
diff --git a/library/src/scala/collection/mutable/AnyRefMap.scala b/library/src/scala/collection/mutable/AnyRefMap.scala
new file mode 100644
index 000000000000..9ad433309b10
--- /dev/null
+++ b/library/src/scala/collection/mutable/AnyRefMap.scala
@@ -0,0 +1,627 @@
+/*
+ * 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 collection
+package mutable
+
+import scala.annotation.meta.companionClass
+import scala.annotation.nowarn
+import scala.collection.generic.DefaultSerializationProxy
+import scala.language.implicitConversions
+
+/** This class implements mutable maps with `AnyRef` keys based on a hash table with open addressing.
+ *
+ * Basic map operations on single entries, including `contains` and `get`,
+ * are typically significantly faster with `AnyRefMap` than [[HashMap]].
+ * Note that numbers and characters are not handled specially in AnyRefMap;
+ * only plain `equals` and `hashCode` are used in comparisons.
+ *
+ * Methods that traverse or regenerate the map, including `foreach` and `map`,
+ * are not in general faster than with `HashMap`. The methods `foreachKey`,
+ * `foreachValue`, `mapValuesNow`, and `transformValues` are, however, faster
+ * than alternative ways to achieve the same functionality.
+ *
+ * Maps with open addressing may become less efficient at lookup after
+ * repeated addition/removal of elements. Although `AnyRefMap` makes a
+ * decent attempt to remain efficient regardless, calling `repack`
+ * on a map that will no longer have elements removed but will be
+ * used heavily may save both time and storage space.
+ *
+ * This map is not intended to contain more than 2^29^ entries (approximately
+ * 500 million). The maximum capacity is 2^30^, but performance will degrade
+ * rapidly as 2^30^ is approached.
+ *
+ */
+@(deprecated @companionClass)("Use `scala.collection.mutable.HashMap` instead for better performance.", since = "2.13.16")
+class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initialBufferSize: Int, initBlank: Boolean)
+ extends AbstractMap[K, V]
+ with MapOps[K, V, Map, AnyRefMap[K, V]]
+ with StrictOptimizedIterableOps[(K, V), Iterable, AnyRefMap[K, V]]
+ with Serializable {
+
+ import AnyRefMap._
+ def this() = this(AnyRefMap.exceptionDefault, 16, initBlank = true)
+
+ /** Creates a new `AnyRefMap` that returns default values according to a supplied key-value mapping. */
+ def this(defaultEntry: K => V) = this(defaultEntry, 16, initBlank = true)
+
+ /** Creates a new `AnyRefMap` with an initial buffer of specified size.
+ *
+ * An `AnyRefMap` can typically contain half as many elements as its buffer size
+ * before it requires resizing.
+ */
+ def this(initialBufferSize: Int) = this(AnyRefMap.exceptionDefault, initialBufferSize, initBlank = true)
+
+ /** Creates a new `AnyRefMap` with specified default values and initial buffer size. */
+ def this(defaultEntry: K => V, initialBufferSize: Int) = this(defaultEntry, initialBufferSize, initBlank = true)
+
+ private[this] var mask = 0
+ private[this] var _size = 0
+ private[this] var _vacant = 0
+ private[this] var _hashes: Array[Int] = null
+ private[this] var _keys: Array[AnyRef] = null
+ private[this] var _values: Array[AnyRef] = null
+
+ if (initBlank) defaultInitialize(initialBufferSize)
+
+ private[this] def defaultInitialize(n: Int): Unit = {
+ mask =
+ if (n<0) 0x7
+ else (((1 << (32 - java.lang.Integer.numberOfLeadingZeros(n-1))) - 1) & 0x3FFFFFFF) | 0x7
+ _hashes = new Array[Int](mask+1)
+ _keys = new Array[AnyRef](mask+1)
+ _values = new Array[AnyRef](mask+1)
+ }
+
+ private[collection] def initializeTo(
+ m: Int, sz: Int, vc: Int, hz: Array[Int], kz: Array[AnyRef], vz: Array[AnyRef]
+ ): Unit = {
+ mask = m; _size = sz; _vacant = vc; _hashes = hz; _keys = kz; _values = vz
+ }
+
+ override protected def fromSpecific(coll: scala.collection.IterableOnce[(K, V)]): AnyRefMap[K,V] = {
+ var sz = coll.knownSize
+ if(sz < 0) sz = 4
+ val arm = new AnyRefMap[K, V](sz * 2)
+ coll.iterator.foreach{ case (k,v) => arm(k) = v }
+ if (arm.size < (sz>>3)) arm.repack()
+ arm
+ }
+ override protected def newSpecificBuilder: Builder[(K, V), AnyRefMap[K,V]] = new AnyRefMapBuilder
+
+ override def size: Int = _size
+ override def knownSize: Int = size
+ override def isEmpty: Boolean = _size == 0
+ override def empty: AnyRefMap[K,V] = new AnyRefMap(defaultEntry)
+
+ private def imbalanced: Boolean =
+ (_size + _vacant) > 0.5*mask || _vacant > _size
+
+ private def hashOf(key: K): Int = {
+ // Note: this method must not return 0 or Int.MinValue, as these indicate no element
+ if (key eq null) 0x41081989
+ else {
+ val h = key.hashCode
+ // Part of the MurmurHash3 32 bit finalizer
+ val i = (h ^ (h >>> 16)) * 0x85EBCA6B
+ val j = (i ^ (i >>> 13)) & 0x7FFFFFFF
+ if (j==0) 0x41081989 else j
+ }
+ }
+
+ private def seekEntry(h: Int, k: AnyRef): Int = {
+ var e = h & mask
+ var x = 0
+ var g = 0
+ val hashes = _hashes
+ val keys = _keys
+ while ({ g = hashes(e); g != 0}) {
+ if (g == h && { val q = keys(e); (q eq k) || ((q ne null) && (q equals k)) }) return e
+ x += 1
+ e = (e + 2*(x+1)*x - 3) & mask
+ }
+ e | MissingBit
+ }
+
+ @`inline` private def seekEntryOrOpen(h: Int, k: AnyRef): Int = {
+ var e = h & mask
+ var x = 0
+ var g = 0
+ var o = -1
+ while ({ g = _hashes(e); g != 0}) {
+ if (g == h && { val q = _keys(e); (q eq k) || ((q ne null) && (q equals k)) }) return e
+ else if (o == -1 && g+g == 0) o = e
+ x += 1
+ e = (e + 2*(x+1)*x - 3) & mask
+ }
+ if (o >= 0) o | MissVacant else e | MissingBit
+ }
+
+ override def contains(key: K): Boolean = seekEntry(hashOf(key), key) >= 0
+
+ override def get(key: K): Option[V] = {
+ val i = seekEntry(hashOf(key), key)
+ if (i < 0) None else Some(_values(i).asInstanceOf[V])
+ }
+
+ override def getOrElse[V1 >: V](key: K, default: => V1): V1 = {
+ val i = seekEntry(hashOf(key), key)
+ if (i < 0) default else _values(i).asInstanceOf[V]
+ }
+
+ override def getOrElseUpdate(key: K, defaultValue: => V): V = {
+ val h = hashOf(key)
+ var i = seekEntryOrOpen(h, key)
+ if (i < 0) {
+ val value = {
+ val ohs = _hashes
+ val j = i & IndexMask
+ val oh = ohs(j)
+ val ans = defaultValue
+ // Evaluating `defaultValue` may change the map
+ // - repack: the array is different
+ // - element added at `j`: since `i < 0`, the key was missing and `oh` is either 0 or MinValue.
+ // If `defaultValue` added an element at `j` then `_hashes(j)` must be different now.
+ // (`hashOf` never returns 0 or MinValue.)
+ if (ohs.ne(_hashes) || oh != _hashes(j)) {
+ i = seekEntryOrOpen(h, key)
+ if (i >= 0) _size -= 1
+ }
+ ans
+ }
+ _size += 1
+ val j = i & IndexMask
+ _hashes(j) = h
+ _keys(j) = key.asInstanceOf[AnyRef]
+ _values(j) = value.asInstanceOf[AnyRef]
+ if ((i & VacantBit) != 0) _vacant -= 1
+ else if (imbalanced) repack()
+ value
+ }
+ else _values(i).asInstanceOf[V]
+ }
+
+ /** Retrieves the value associated with a key, or the default for that type if none exists
+ * (null for AnyRef, 0 for floats and integers).
+ *
+ * Note: this is the fastest way to retrieve a value that may or
+ * may not exist, if the default null/zero is acceptable. For key/value
+ * pairs that do exist, `apply` (i.e. `map(key)`) is equally fast.
+ */
+ def getOrNull(key: K): V = {
+ val i = seekEntry(hashOf(key), key)
+ (if (i < 0) null else _values(i)).asInstanceOf[V]
+ }
+
+ /** Retrieves the value associated with a key.
+ * If the key does not exist in the map, the `defaultEntry` for that key
+ * will be returned instead; an exception will be thrown if no
+ * `defaultEntry` was supplied.
+ */
+ override def apply(key: K): V = {
+ val i = seekEntry(hashOf(key), key)
+ if (i < 0) defaultEntry(key) else _values(i).asInstanceOf[V]
+ }
+
+ /** Defers to defaultEntry to find a default value for the key. Throws an
+ * exception if no other default behavior was specified.
+ */
+ override def default(key: K): V = defaultEntry(key)
+
+ private def repack(newMask: Int): Unit = {
+ val oh = _hashes
+ val ok = _keys
+ val ov = _values
+ mask = newMask
+ _hashes = new Array[Int](mask+1)
+ _keys = new Array[AnyRef](mask+1)
+ _values = new Array[AnyRef](mask+1)
+ _vacant = 0
+ var i = 0
+ while (i < oh.length) {
+ val h = oh(i)
+ if (h+h != 0) {
+ var e = h & mask
+ var x = 0
+ while (_hashes(e) != 0) { x += 1; e = (e + 2*(x+1)*x - 3) & mask }
+ _hashes(e) = h
+ _keys(e) = ok(i)
+ _values(e) = ov(i)
+ }
+ i += 1
+ }
+ }
+
+ /** Repacks the contents of this `AnyRefMap` for maximum efficiency of lookup.
+ *
+ * For maps that undergo a complex creation process with both addition and
+ * removal of keys, and then are used heavily with no further removal of
+ * elements, calling `repack` after the end of the creation can result in
+ * improved performance. Repacking takes time proportional to the number
+ * of entries in the map.
+ */
+ def repack(): Unit = {
+ var m = mask
+ if (_size + _vacant >= 0.5*mask && !(_vacant > 0.2*mask)) m = ((m << 1) + 1) & IndexMask
+ while (m > 8 && 8*_size < m) m = m >>> 1
+ repack(m)
+ }
+
+ override def put(key: K, value: V): Option[V] = {
+ val h = hashOf(key)
+ val i = seekEntryOrOpen(h, key)
+ if (i < 0) {
+ val j = i & IndexMask
+ _hashes(j) = h
+ _keys(j) = key
+ _values(j) = value.asInstanceOf[AnyRef]
+ _size += 1
+ if ((i & VacantBit) != 0) _vacant -= 1
+ else if (imbalanced) repack()
+ None
+ }
+ else {
+ val ans = Some(_values(i).asInstanceOf[V])
+ _hashes(i) = h
+ _values(i) = value.asInstanceOf[AnyRef]
+ ans
+ }
+ }
+
+ /** Updates the map to include a new key-value pair.
+ *
+ * This is the fastest way to add an entry to an `AnyRefMap`.
+ */
+ override def update(key: K, value: V): Unit = {
+ val h = hashOf(key)
+ val i = seekEntryOrOpen(h, key)
+ if (i < 0) {
+ val j = i & IndexMask
+ _hashes(j) = h
+ _keys(j) = key
+ _values(j) = value.asInstanceOf[AnyRef]
+ _size += 1
+ if ((i & VacantBit) != 0) _vacant -= 1
+ else if (imbalanced) repack()
+ }
+ else {
+ _hashes(i) = h
+ _values(i) = value.asInstanceOf[AnyRef]
+ }
+ }
+
+ /** Adds a new key/value pair to this map and returns the map. */
+ @deprecated("Use `addOne` or `update` instead; infix operations with an operand of multiple args will be deprecated", "2.13.3")
+ def +=(key: K, value: V): this.type = { update(key, value); this }
+
+ /** Adds a new key/value pair to this map and returns the map. */
+ @inline final def addOne(key: K, value: V): this.type = { update(key, value); this }
+
+ @inline override final def addOne(kv: (K, V)): this.type = { update(kv._1, kv._2); this }
+
+ def subtractOne(key: K): this.type = {
+ val i = seekEntry(hashOf(key), key)
+ if (i >= 0) {
+ _size -= 1
+ _vacant += 1
+ _hashes(i) = Int.MinValue
+ _keys(i) = null
+ _values(i) = null
+ }
+ this
+ }
+
+ def iterator: Iterator[(K, V)] = new AnyRefMapIterator[(K, V)] {
+ protected def nextResult(k: K, v: V) = (k, v)
+ }
+ override def keysIterator: Iterator[K] = new AnyRefMapIterator[K] {
+ protected def nextResult(k: K, v: V) = k
+ }
+ override def valuesIterator: Iterator[V] = new AnyRefMapIterator[V] {
+ protected def nextResult(k: K, v: V) = v
+ }
+
+ private abstract class AnyRefMapIterator[A] extends AbstractIterator[A] {
+ private[this] val hz = _hashes
+ private[this] val kz = _keys
+ private[this] val vz = _values
+
+ private[this] var index = 0
+
+ def hasNext: Boolean = index= hz.length) return false
+ h = hz(index)
+ }
+ true
+ }
+
+ def next(): A = {
+ if (hasNext) {
+ val ans = nextResult(kz(index).asInstanceOf[K], vz(index).asInstanceOf[V])
+ index += 1
+ ans
+ }
+ else throw new NoSuchElementException("next")
+ }
+
+ protected def nextResult(k: K, v: V): A
+ }
+
+
+ override def foreach[U](f: ((K,V)) => U): Unit = {
+ var i = 0
+ var e = _size
+ while (e > 0) {
+ while(i < _hashes.length && { val h = _hashes(i); h+h == 0 && i < _hashes.length}) i += 1
+ if (i < _hashes.length) {
+ f((_keys(i).asInstanceOf[K], _values(i).asInstanceOf[V]))
+ i += 1
+ e -= 1
+ }
+ else return
+ }
+ }
+
+ override def foreachEntry[U](f: (K,V) => U): Unit = {
+ var i = 0
+ var e = _size
+ while (e > 0) {
+ while(i < _hashes.length && { val h = _hashes(i); h+h == 0 && i < _hashes.length}) i += 1
+ if (i < _hashes.length) {
+ f(_keys(i).asInstanceOf[K], _values(i).asInstanceOf[V])
+ i += 1
+ e -= 1
+ }
+ else return
+ }
+ }
+
+ override def clone(): AnyRefMap[K, V] = {
+ val hz = java.util.Arrays.copyOf(_hashes, _hashes.length)
+ val kz = java.util.Arrays.copyOf(_keys, _keys.length)
+ val vz = java.util.Arrays.copyOf(_values, _values.length)
+ val arm = new AnyRefMap[K, V](defaultEntry, 1, initBlank = false)
+ arm.initializeTo(mask, _size, _vacant, hz, kz, vz)
+ arm
+ }
+
+ @deprecated("Consider requiring an immutable Map or fall back to Map.concat", "2.13.0")
+ override def + [V1 >: V](kv: (K, V1)): AnyRefMap[K, V1] = AnyRefMap.from(new View.Appended(this, kv))
+
+ @deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
+ override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): AnyRefMap[K, V1] = {
+ val m = this + elem1 + elem2
+ if(elems.isEmpty) m else m.concat(elems)
+ }
+
+ override def concat[V2 >: V](xs: scala.collection.IterableOnce[(K, V2)]): AnyRefMap[K, V2] = {
+ val arm = clone().asInstanceOf[AnyRefMap[K, V2]]
+ xs.iterator.foreach(kv => arm += kv)
+ arm
+ }
+
+ override def ++[V2 >: V](xs: scala.collection.IterableOnce[(K, V2)]): AnyRefMap[K, V2] = concat(xs)
+
+ @deprecated("Use m.clone().addOne(k,v) instead of m.updated(k, v)", "2.13.0")
+ override def updated[V1 >: V](key: K, value: V1): AnyRefMap[K, V1] =
+ clone().asInstanceOf[AnyRefMap[K, V1]].addOne(key, value)
+
+ private[this] def foreachElement[A,B](elems: Array[AnyRef], f: A => B): Unit = {
+ var i,j = 0
+ while (i < _hashes.length & j < _size) {
+ val h = _hashes(i)
+ if (h+h != 0) {
+ j += 1
+ f(elems(i).asInstanceOf[A])
+ }
+ i += 1
+ }
+ }
+
+ /** Applies a function to all keys of this map. */
+ def foreachKey[A](f: K => A): Unit = foreachElement[K,A](_keys, f)
+
+ /** Applies a function to all values of this map. */
+ def foreachValue[A](f: V => A): Unit = foreachElement[V,A](_values, f)
+
+ /** Creates a new `AnyRefMap` with different values.
+ * Unlike `mapValues`, this method generates a new
+ * collection immediately.
+ */
+ def mapValuesNow[V1](f: V => V1): AnyRefMap[K, V1] = {
+ val arm = new AnyRefMap[K,V1](AnyRefMap.exceptionDefault, 1, initBlank = false)
+ val hz = java.util.Arrays.copyOf(_hashes, _hashes.length)
+ val kz = java.util.Arrays.copyOf(_keys, _keys.length)
+ val vz = new Array[AnyRef](_values.length)
+ var i,j = 0
+ while (i < _hashes.length & j < _size) {
+ val h = _hashes(i)
+ if (h+h != 0) {
+ j += 1
+ vz(i) = f(_values(i).asInstanceOf[V]).asInstanceOf[AnyRef]
+ }
+ i += 1
+ }
+ arm.initializeTo(mask, _size, _vacant, hz, kz, vz)
+ arm
+ }
+
+ /** Applies a transformation function to all values stored in this map.
+ * Note: the default, if any, is not transformed.
+ */
+ @deprecated("Use transformValuesInPlace instead of transformValues", "2.13.0")
+ @`inline` final def transformValues(f: V => V): this.type = transformValuesInPlace(f)
+
+ /** Applies a transformation function to all values stored in this map.
+ * Note: the default, if any, is not transformed.
+ */
+ def transformValuesInPlace(f: V => V): this.type = {
+ var i,j = 0
+ while (i < _hashes.length & j < _size) {
+ val h = _hashes(i)
+ if (h+h != 0) {
+ j += 1
+ _values(i) = f(_values(i).asInstanceOf[V]).asInstanceOf[AnyRef]
+ }
+ i += 1
+ }
+ this
+ }
+
+ // The implicit dummy parameter is necessary to distinguish these methods from the base methods they overload (not override).
+ // Previously, in Scala 2, f took `K with AnyRef` scala/bug#11035
+ /**
+ * An overload of `map` which produces an `AnyRefMap`.
+ *
+ * @param f the mapping function must produce a key-value pair where the key is an `AnyRef`
+ * @param dummy an implicit placeholder for purposes of distinguishing the (erased) signature of this method
+ */
+ def map[K2 <: AnyRef, V2](f: ((K, V)) => (K2, V2))(implicit dummy: DummyImplicit): AnyRefMap[K2, V2] =
+ AnyRefMap.from(new View.Map(this, f))
+ /**
+ * An overload of `flatMap` which produces an `AnyRefMap`.
+ *
+ * @param f the mapping function must produce key-value pairs where the key is an `AnyRef`
+ * @param dummy an implicit placeholder for purposes of distinguishing the (erased) signature of this method
+ */
+ def flatMap[K2 <: AnyRef, V2](f: ((K, V)) => IterableOnce[(K2, V2)])(implicit dummy: DummyImplicit): AnyRefMap[K2, V2] =
+ AnyRefMap.from(new View.FlatMap(this, f))
+ /**
+ * An overload of `collect` which produces an `AnyRefMap`.
+ *
+ * @param pf the mapping function must produce a key-value pair where the key is an `AnyRef`
+ * @param dummy an implicit placeholder for purposes of distinguishing the (erased) signature of this method
+ */
+ def collect[K2 <: AnyRef, V2](pf: PartialFunction[(K, V), (K2, V2)])(implicit dummy: DummyImplicit): AnyRefMap[K2, V2] =
+ strictOptimizedCollect(AnyRefMap.newBuilder[K2, V2], pf)
+
+ override def clear(): Unit = {
+ import java.util.Arrays.fill
+ fill(_keys, null)
+ fill(_values, null)
+ fill(_hashes, 0)
+ _size = 0
+ _vacant = 0
+ }
+
+ protected[this] def writeReplace(): AnyRef = new DefaultSerializationProxy(AnyRefMap.toFactory[K, V](AnyRefMap), this)
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix = "AnyRefMap"
+}
+
+@deprecated("Use `scala.collection.mutable.HashMap` instead for better performance.", since = "2.13.16")
+object AnyRefMap {
+ private final val IndexMask = 0x3FFFFFFF
+ private final val MissingBit = 0x80000000
+ private final val VacantBit = 0x40000000
+ private final val MissVacant = 0xC0000000
+
+ private class ExceptionDefault extends (Any => Nothing) with Serializable {
+ def apply(k: Any): Nothing = throw new NoSuchElementException(if (k == null) "(null)" else k.toString)
+ }
+ private val exceptionDefault = new ExceptionDefault
+
+ /** A builder for instances of `AnyRefMap`.
+ *
+ * This builder can be reused to create multiple instances.
+ */
+ final class AnyRefMapBuilder[K <: AnyRef, V] extends ReusableBuilder[(K, V), AnyRefMap[K, V]] {
+ private[collection] var elems: AnyRefMap[K, V] = new AnyRefMap[K, V]
+ def addOne(entry: (K, V)): this.type = {
+ elems += entry
+ this
+ }
+ def clear(): Unit = elems = new AnyRefMap[K, V]
+ def result(): AnyRefMap[K, V] = elems
+ override def knownSize: Int = elems.knownSize
+ }
+
+ /** Creates a new `AnyRefMap` with zero or more key/value pairs. */
+ def apply[K <: AnyRef, V](elems: (K, V)*): AnyRefMap[K, V] = buildFromIterableOnce(elems)
+
+ def newBuilder[K <: AnyRef, V]: ReusableBuilder[(K, V), AnyRefMap[K, V]] = new AnyRefMapBuilder[K, V]
+
+ private def buildFromIterableOnce[K <: AnyRef, V](elems: IterableOnce[(K, V)]): AnyRefMap[K, V] = {
+ var sz = elems.knownSize
+ if(sz < 0) sz = 4
+ val arm = new AnyRefMap[K, V](sz * 2)
+ elems.iterator.foreach{ case (k,v) => arm(k) = v }
+ if (arm.size < (sz>>3)) arm.repack()
+ arm
+ }
+
+ /** Creates a new empty `AnyRefMap`. */
+ def empty[K <: AnyRef, V]: AnyRefMap[K, V] = new AnyRefMap[K, V]
+
+ /** Creates a new empty `AnyRefMap` with the supplied default */
+ def withDefault[K <: AnyRef, V](default: K => V): AnyRefMap[K, V] = new AnyRefMap[K, V](default)
+
+ /** Creates a new `AnyRefMap` from an existing source collection. A source collection
+ * which is already an `AnyRefMap` gets cloned.
+ *
+ * @param source Source collection
+ * @tparam K the type of the keys
+ * @tparam V the type of the values
+ * @return a new `AnyRefMap` with the elements of `source`
+ */
+ def from[K <: AnyRef, V](source: IterableOnce[(K, V)]): AnyRefMap[K, V] = source match {
+ case source: AnyRefMap[_, _] => source.clone().asInstanceOf[AnyRefMap[K, V]]
+ case _ => buildFromIterableOnce(source)
+ }
+
+ /** Creates a new `AnyRefMap` from arrays of keys and values.
+ * Equivalent to but more efficient than `AnyRefMap((keys zip values): _*)`.
+ */
+ def fromZip[K <: AnyRef, V](keys: Array[K], values: Array[V]): AnyRefMap[K, V] = {
+ val sz = math.min(keys.length, values.length)
+ val arm = new AnyRefMap[K, V](sz * 2)
+ var i = 0
+ while (i < sz) { arm(keys(i)) = values(i); i += 1 }
+ if (arm.size < (sz>>3)) arm.repack()
+ arm
+ }
+
+ /** Creates a new `AnyRefMap` from keys and values.
+ * Equivalent to but more efficient than `AnyRefMap((keys zip values): _*)`.
+ */
+ def fromZip[K <: AnyRef, V](keys: Iterable[K], values: Iterable[V]): AnyRefMap[K, V] = {
+ val sz = math.min(keys.size, values.size)
+ val arm = new AnyRefMap[K, V](sz * 2)
+ val ki = keys.iterator
+ val vi = values.iterator
+ while (ki.hasNext && vi.hasNext) arm(ki.next()) = vi.next()
+ if (arm.size < (sz >> 3)) arm.repack()
+ arm
+ }
+
+ implicit def toFactory[K <: AnyRef, V](dummy: AnyRefMap.type): Factory[(K, V), AnyRefMap[K, V]] = ToFactory.asInstanceOf[Factory[(K, V), AnyRefMap[K, V]]]
+
+ @SerialVersionUID(3L)
+ private[this] object ToFactory extends Factory[(AnyRef, AnyRef), AnyRefMap[AnyRef, AnyRef]] with Serializable {
+ def fromSpecific(it: IterableOnce[(AnyRef, AnyRef)]): AnyRefMap[AnyRef, AnyRef] = AnyRefMap.from[AnyRef, AnyRef](it)
+ def newBuilder: Builder[(AnyRef, AnyRef), AnyRefMap[AnyRef, AnyRef]] = AnyRefMap.newBuilder[AnyRef, AnyRef]
+ }
+
+ implicit def toBuildFrom[K <: AnyRef, V](factory: AnyRefMap.type): BuildFrom[Any, (K, V), AnyRefMap[K, V]] = ToBuildFrom.asInstanceOf[BuildFrom[Any, (K, V), AnyRefMap[K, V]]]
+ private[this] object ToBuildFrom extends BuildFrom[Any, (AnyRef, AnyRef), AnyRefMap[AnyRef, AnyRef]] {
+ def fromSpecific(from: Any)(it: IterableOnce[(AnyRef, AnyRef)]): AnyRefMap[AnyRef, AnyRef] = AnyRefMap.from(it)
+ def newBuilder(from: Any): ReusableBuilder[(AnyRef, AnyRef), AnyRefMap[AnyRef, AnyRef]] = AnyRefMap.newBuilder[AnyRef, AnyRef]
+ }
+
+ implicit def iterableFactory[K <: AnyRef, V]: Factory[(K, V), AnyRefMap[K, V]] = toFactory[K, V](this)
+ implicit def buildFromAnyRefMap[K <: AnyRef, V]: BuildFrom[AnyRefMap[_, _], (K, V), AnyRefMap[K, V]] = toBuildFrom(this)
+}
diff --git a/library/src/scala/collection/mutable/ArrayBuffer.scala b/library/src/scala/collection/mutable/ArrayBuffer.scala
new file mode 100644
index 000000000000..035c35c88a26
--- /dev/null
+++ b/library/src/scala/collection/mutable/ArrayBuffer.scala
@@ -0,0 +1,401 @@
+/*
+ * 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 collection
+package mutable
+
+import java.util.Arrays
+import scala.annotation.{nowarn, tailrec}
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.generic.{CommonErrors, DefaultSerializable}
+import scala.runtime.PStatics.VM_MaxArraySize
+
+/** An implementation of the `Buffer` class using an array to
+ * represent the assembled sequence internally. Append, update and random
+ * access take constant time (amortized time). Prepends and removes are
+ * linear in the buffer size.
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-mutable-collection-classes.html#array-buffers "Scala's Collection Library overview"]]
+ * section on `Array Buffers` for more information.
+
+ *
+ * @tparam A the type of this arraybuffer's elements.
+ *
+ * @define Coll `mutable.ArrayBuffer`
+ * @define coll array buffer
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+@SerialVersionUID(-1582447879429021880L)
+class ArrayBuffer[A] private (initialElements: Array[AnyRef], initialSize: Int)
+ extends AbstractBuffer[A]
+ with IndexedBuffer[A]
+ with IndexedSeqOps[A, ArrayBuffer, ArrayBuffer[A]]
+ with StrictOptimizedSeqOps[A, ArrayBuffer, ArrayBuffer[A]]
+ with IterableFactoryDefaults[A, ArrayBuffer]
+ with DefaultSerializable {
+
+ def this() = this(new Array[AnyRef](ArrayBuffer.DefaultInitialSize), 0)
+
+ def this(initialSize: Int) = this(new Array[AnyRef](initialSize max 1), 0)
+
+ @transient private[this] var mutationCount: Int = 0
+
+ // needs to be `private[collection]` or `protected[collection]` for parallel-collections
+ protected[collection] var array: Array[AnyRef] = initialElements
+ protected var size0 = initialSize
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit = {
+ import scala.collection.convert.impl._
+ shape.parUnbox(new ObjectArrayStepper(array, 0, length).asInstanceOf[AnyStepper[A] with EfficientSplit])
+ }
+
+ override def knownSize: Int = super[IndexedSeqOps].knownSize
+
+ /** Ensure that the internal array has at least `n` cells. */
+ protected def ensureSize(n: Int): Unit = {
+ array = ArrayBuffer.ensureSize(array, size0, n)
+ }
+
+ /** Uses the given size to resize internal storage, if necessary.
+ *
+ * @param size Expected maximum number of elements.
+ */
+ def sizeHint(size: Int): Unit =
+ if(size > length && size >= 1) ensureSize(size)
+
+ /** Reduce length to `n`, nulling out all dropped elements */
+ private def reduceToSize(n: Int): Unit = {
+ mutationCount += 1
+ Arrays.fill(array, n, size0, null)
+ size0 = n
+ }
+
+ /** Trims the ArrayBuffer to an appropriate size for the current
+ * number of elements (rounding up to the next natural size),
+ * which may replace the array by a shorter one.
+ * This allows releasing some unused memory.
+ */
+ def trimToSize(): Unit = {
+ resize(length)
+ }
+
+ /** Trims the `array` buffer size down to either a power of 2
+ * or Int.MaxValue while keeping first `requiredLength` elements.
+ */
+ private def resize(requiredLength: Int): Unit =
+ array = ArrayBuffer.downsize(array, requiredLength)
+
+ @inline private def checkWithinBounds(lo: Int, hi: Int) = {
+ if (lo < 0) throw CommonErrors.indexOutOfBounds(index = lo, max = size0 - 1)
+ if (hi > size0) throw CommonErrors.indexOutOfBounds(index = hi - 1, max = size0 - 1)
+ }
+
+ def apply(n: Int): A = {
+ checkWithinBounds(n, n + 1)
+ array(n).asInstanceOf[A]
+ }
+
+ def update(@deprecatedName("n", "2.13.0") index: Int, elem: A): Unit = {
+ checkWithinBounds(index, index + 1)
+ mutationCount += 1
+ array(index) = elem.asInstanceOf[AnyRef]
+ }
+
+ def length = size0
+
+ // TODO: return `IndexedSeqView` rather than `ArrayBufferView`
+ override def view: ArrayBufferView[A] = new ArrayBufferView(this, () => mutationCount)
+
+ override def iterableFactory: SeqFactory[ArrayBuffer] = ArrayBuffer
+
+ /** Note: This does not actually resize the internal representation.
+ * See clearAndShrink if you want to also resize internally
+ */
+ def clear(): Unit = reduceToSize(0)
+
+ /**
+ * Clears this buffer and shrinks to @param size (rounding up to the next
+ * natural size)
+ * @param size
+ */
+ def clearAndShrink(size: Int = ArrayBuffer.DefaultInitialSize): this.type = {
+ clear()
+ resize(size)
+ this
+ }
+
+ def addOne(elem: A): this.type = {
+ mutationCount += 1
+ val newSize = size0 + 1
+ ensureSize(newSize)
+ size0 = newSize
+ this(size0 - 1) = elem
+ this
+ }
+
+ // Overridden to use array copying for efficiency where possible.
+ override def addAll(elems: IterableOnce[A]): this.type = {
+ elems match {
+ case elems: ArrayBuffer[_] =>
+ val elemsLength = elems.size0
+ if (elemsLength > 0) {
+ mutationCount += 1
+ ensureSize(size0 + elemsLength)
+ Array.copy(elems.array, 0, array, length, elemsLength)
+ size0 = length + elemsLength
+ }
+ case _ => super.addAll(elems)
+ }
+ this
+ }
+
+ def insert(@deprecatedName("n", "2.13.0") index: Int, elem: A): Unit = {
+ checkWithinBounds(index, index)
+ mutationCount += 1
+ ensureSize(size0 + 1)
+ Array.copy(array, index, array, index + 1, size0 - index)
+ size0 += 1
+ this(index) = elem
+ }
+
+ def prepend(elem: A): this.type = {
+ insert(0, elem)
+ this
+ }
+
+ def insertAll(@deprecatedName("n", "2.13.0") index: Int, elems: IterableOnce[A]): Unit = {
+ checkWithinBounds(index, index)
+ elems match {
+ case elems: collection.Iterable[A] =>
+ val elemsLength = elems.size
+ if (elemsLength > 0) {
+ mutationCount += 1
+ ensureSize(size0 + elemsLength)
+ val len = size0
+ Array.copy(array, index, array, index + elemsLength, len - index)
+ // if `elems eq this`, this copy is safe because
+ // - `elems.array eq this.array`
+ // - we didn't overwrite the values being inserted after moving them in
+ // the previous line
+ // - `copyElemsToArray` will call `System.arraycopy`
+ // - `System.arraycopy` will effectively "read" all the values before
+ // overwriting any of them when two arrays are the same reference
+ val actual = IterableOnce.copyElemsToArray(elems, array.asInstanceOf[Array[Any]], index, elemsLength)
+ if (actual != elemsLength) throw new IllegalStateException(s"Copied $actual of $elemsLength")
+ size0 = len + elemsLength // update size AFTER the copy, in case we're inserting a proxy
+ }
+ case _ => insertAll(index, ArrayBuffer.from(elems))
+ }
+ }
+
+ /** Note: This does not actually resize the internal representation.
+ * See trimToSize if you want to also resize internally
+ */
+ def remove(@deprecatedName("n", "2.13.0") index: Int): A = {
+ checkWithinBounds(index, index + 1)
+ val res = this(index)
+ Array.copy(array, index + 1, array, index, size0 - (index + 1))
+ reduceToSize(size0 - 1)
+ res
+ }
+
+ /** Note: This does not actually resize the internal representation.
+ * See trimToSize if you want to also resize internally
+ */
+ def remove(@deprecatedName("n", "2.13.0") index: Int, count: Int): Unit =
+ if (count > 0) {
+ checkWithinBounds(index, index + count)
+ Array.copy(array, index + count, array, index, size0 - (index + count))
+ reduceToSize(size0 - count)
+ } else if (count < 0) {
+ throw new IllegalArgumentException("removing negative number of elements: " + count)
+ }
+
+ @deprecated("Use 'this' instance instead", "2.13.0")
+ @deprecatedOverriding("ArrayBuffer[A] no longer extends Builder[A, ArrayBuffer[A]]", "2.13.0")
+ @inline def result(): this.type = this
+
+ @deprecated("Use 'new GrowableBuilder(this).mapResult(f)' instead", "2.13.0")
+ @deprecatedOverriding("ArrayBuffer[A] no longer extends Builder[A, ArrayBuffer[A]]", "2.13.0")
+ @inline def mapResult[NewTo](f: (ArrayBuffer[A]) => NewTo): Builder[A, NewTo] = new GrowableBuilder[A, ArrayBuffer[A]](this).mapResult(f)
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix = "ArrayBuffer"
+
+ override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = {
+ val copied = IterableOnce.elemsToCopyToArray(length, xs.length, start, len)
+ if(copied > 0) {
+ Array.copy(array, 0, xs, start, copied)
+ }
+ copied
+ }
+
+ /** Sorts this $coll in place according to an Ordering.
+ *
+ * @see [[scala.collection.mutable.IndexedSeqOps.sortInPlace]]
+ * @param ord the ordering to be used to compare elements.
+ * @return modified input $coll sorted according to the ordering `ord`.
+ */
+ override def sortInPlace[B >: A]()(implicit ord: Ordering[B]): this.type = {
+ if (length > 1) {
+ mutationCount += 1
+ scala.util.Sorting.stableSort(array.asInstanceOf[Array[B]], 0, length)
+ }
+ this
+ }
+
+ @tailrec private def foldl[B](start: Int, end: Int, z: B, op: (B, A) => B): B =
+ if (start == end) z
+ else foldl(start + 1, end, op(z, array(start).asInstanceOf[A]), op)
+
+ @tailrec private def foldr[B](start: Int, end: Int, z: B, op: (A, B) => B): B =
+ if (start == end) z
+ else foldr(start, end - 1, op(array(end - 1).asInstanceOf[A], z), op)
+
+ override def foldLeft[B](z: B)(op: (B, A) => B): B = foldl(0, length, z, op)
+
+ override def foldRight[B](z: B)(op: (A, B) => B): B = foldr(0, length, z, op)
+
+ override def reduceLeft[B >: A](op: (B, A) => B): B = if (length > 0) foldl(1, length, array(0).asInstanceOf[B], op) else super.reduceLeft(op)
+
+ override def reduceRight[B >: A](op: (A, B) => B): B = if (length > 0) foldr(0, length - 1, array(length - 1).asInstanceOf[B], op) else super.reduceRight(op)
+}
+
+/**
+ * Factory object for the `ArrayBuffer` class.
+ *
+ * $factoryInfo
+ *
+ * @define coll array buffer
+ * @define Coll `mutable.ArrayBuffer`
+ */
+@SerialVersionUID(3L)
+object ArrayBuffer extends StrictOptimizedSeqFactory[ArrayBuffer] {
+ final val DefaultInitialSize = 16
+ private[this] val emptyArray = new Array[AnyRef](0)
+
+ def from[B](coll: collection.IterableOnce[B]): ArrayBuffer[B] = {
+ val k = coll.knownSize
+ if (k >= 0) {
+ // Avoid reallocation of buffer if length is known
+ val array = ensureSize(emptyArray, 0, k) // don't duplicate sizing logic, and check VM array size limit
+ val actual = IterableOnce.copyElemsToArray(coll, array.asInstanceOf[Array[Any]])
+ if (actual != k) throw new IllegalStateException(s"Copied $actual of $k")
+ new ArrayBuffer[B](array, k)
+ }
+ else new ArrayBuffer[B] ++= coll
+ }
+
+ def newBuilder[A]: Builder[A, ArrayBuffer[A]] = new GrowableBuilder[A, ArrayBuffer[A]](empty[A]) {
+ override def sizeHint(size: Int): Unit = elems.sizeHint(size)
+ }
+
+ def empty[A]: ArrayBuffer[A] = new ArrayBuffer[A]()
+
+ /**
+ * The increased size for an array-backed collection.
+ *
+ * @param arrayLen the length of the backing array
+ * @param targetLen the minimum length to resize up to
+ * @return
+ * - `-1` if no resizing is needed, else
+ * - `VM_MaxArraySize` if `arrayLen` is too large to be doubled, else
+ * - `max(targetLen, arrayLen * 2, DefaultInitialSize)`.
+ * - Throws an exception if `targetLen` exceeds `VM_MaxArraySize` or is negative (overflow).
+ */
+ private[mutable] def resizeUp(arrayLen: Int, targetLen: Int): Int =
+ if (targetLen < 0) throw new RuntimeException(s"Overflow while resizing array of array-backed collection. Requested length: $targetLen; current length: $arrayLen; increase: ${targetLen - arrayLen}")
+ else if (targetLen <= arrayLen) -1
+ else if (targetLen > VM_MaxArraySize) throw new RuntimeException(s"Array of array-backed collection exceeds VM length limit of $VM_MaxArraySize. Requested length: $targetLen; current length: $arrayLen")
+ else if (arrayLen > VM_MaxArraySize / 2) VM_MaxArraySize
+ else math.max(targetLen, math.max(arrayLen * 2, DefaultInitialSize))
+
+ // if necessary, copy (curSize elements of) the array to a new array of capacity n.
+ // Should use Array.copyOf(array, resizeEnsuring(array.length))?
+ private def ensureSize(array: Array[AnyRef], curSize: Int, targetSize: Int): Array[AnyRef] = {
+ val newLen = resizeUp(array.length, targetSize)
+ if (newLen < 0) array
+ else {
+ val res = new Array[AnyRef](newLen)
+ System.arraycopy(array, 0, res, 0, curSize)
+ res
+ }
+ }
+
+ /**
+ * @param arrayLen the length of the backing array
+ * @param targetLen the length to resize down to, if smaller than `arrayLen`
+ * @return -1 if no resizing is needed, or the size for the new array otherwise
+ */
+ private def resizeDown(arrayLen: Int, targetLen: Int): Int =
+ if (targetLen >= arrayLen) -1 else math.max(targetLen, 0)
+ private def downsize(array: Array[AnyRef], targetSize: Int): Array[AnyRef] = {
+ val newLen = resizeDown(array.length, targetSize)
+ if (newLen < 0) array
+ else if (newLen == 0) emptyArray
+ else {
+ val res = new Array[AnyRef](newLen)
+ System.arraycopy(array, 0, res, 0, targetSize)
+ res
+ }
+ }
+}
+
+// TODO: use `CheckedIndexedSeqView.Id` once we can change the return type of `ArrayBuffer#view`
+final class ArrayBufferView[A] private[mutable](underlying: ArrayBuffer[A], mutationCount: () => Int)
+ extends AbstractIndexedSeqView[A] {
+ @deprecated("never intended to be public; call ArrayBuffer#view instead", since = "2.13.7")
+ def this(array: Array[AnyRef], length: Int) = {
+ // this won't actually track mutation, but it would be a pain to have the implementation
+ // check if we have a method to get the current mutation count or not on every method and
+ // change what it does based on that. hopefully no one ever calls this.
+ this({
+ val _array = array
+ val _length = length
+ new ArrayBuffer[A](0) {
+ this.array = _array
+ this.size0 = _length
+ }
+ }, () => 0)
+ }
+
+ @deprecated("never intended to be public", since = "2.13.7")
+ def array: Array[AnyRef] = underlying.toArray[Any].asInstanceOf[Array[AnyRef]]
+
+ @throws[IndexOutOfBoundsException]
+ def apply(n: Int): A = underlying(n)
+ def length: Int = underlying.length
+ override protected[this] def className = "ArrayBufferView"
+
+ // we could inherit all these from `CheckedIndexedSeqView`, except this class is public
+ override def iterator: Iterator[A] = new CheckedIndexedSeqView.CheckedIterator(this, mutationCount())
+ override def reverseIterator: Iterator[A] = new CheckedIndexedSeqView.CheckedReverseIterator(this, mutationCount())
+
+ override def appended[B >: A](elem: B): IndexedSeqView[B] = new CheckedIndexedSeqView.Appended(this, elem)(mutationCount)
+ override def prepended[B >: A](elem: B): IndexedSeqView[B] = new CheckedIndexedSeqView.Prepended(elem, this)(mutationCount)
+ override def take(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.Take(this, n)(mutationCount)
+ override def takeRight(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.TakeRight(this, n)(mutationCount)
+ override def drop(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.Drop(this, n)(mutationCount)
+ override def dropRight(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.DropRight(this, n)(mutationCount)
+ override def map[B](f: A => B): IndexedSeqView[B] = new CheckedIndexedSeqView.Map(this, f)(mutationCount)
+ override def reverse: IndexedSeqView[A] = new CheckedIndexedSeqView.Reverse(this)(mutationCount)
+ override def slice(from: Int, until: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.Slice(this, from, until)(mutationCount)
+ override def tapEach[U](f: A => U): IndexedSeqView[A] = new CheckedIndexedSeqView.Map(this, { (a: A) => f(a); a})(mutationCount)
+
+ override def concat[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new CheckedIndexedSeqView.Concat(this, suffix)(mutationCount)
+ override def appendedAll[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new CheckedIndexedSeqView.Concat(this, suffix)(mutationCount)
+ override def prependedAll[B >: A](prefix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new CheckedIndexedSeqView.Concat(prefix, this)(mutationCount)
+}
diff --git a/library/src/scala/collection/mutable/ArrayBuilder.scala b/library/src/scala/collection/mutable/ArrayBuilder.scala
new file mode 100644
index 000000000000..e962dd024836
--- /dev/null
+++ b/library/src/scala/collection/mutable/ArrayBuilder.scala
@@ -0,0 +1,536 @@
+/*
+ * 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 mutable
+
+import scala.collection.mutable.ArrayBuffer.resizeUp
+import scala.reflect.ClassTag
+
+/** A builder class for arrays.
+ *
+ * @tparam T the type of the elements for the builder.
+ */
+@SerialVersionUID(3L)
+sealed abstract class ArrayBuilder[T]
+ extends ReusableBuilder[T, Array[T]]
+ with Serializable {
+ protected[this] var capacity: Int = 0
+ protected[this] def elems: Array[T] // may not be allocated at size = capacity = 0
+ protected var size: Int = 0
+
+ /** Current number of elements. */
+ def length: Int = size
+
+ /** Current number of elements. */
+ override def knownSize: Int = size
+
+ protected[this] final def ensureSize(size: Int): Unit = {
+ val newLen = resizeUp(capacity, size)
+ if (newLen > 0) resize(newLen)
+ }
+
+ override final def sizeHint(size: Int): Unit = if (capacity < size) resize(size)
+
+ def clear(): Unit = size = 0
+
+ protected[this] def resize(size: Int): Unit
+
+ /** Add all elements of an array. */
+ def addAll(xs: Array[_ <: T]): this.type = addAll(xs, 0, xs.length)
+
+ /** Add a slice of an array. */
+ def addAll(xs: Array[_ <: T], offset: Int, length: Int): this.type = {
+ val offset1 = offset.max(0)
+ val length1 = length.max(0)
+ val effectiveLength = length1.min(xs.length - offset1)
+ doAddAll(xs, offset1, effectiveLength)
+ }
+
+ private def doAddAll(xs: Array[_ <: T], offset: Int, length: Int): this.type = {
+ if (length > 0) {
+ ensureSize(this.size + length)
+ Array.copy(xs, offset, elems, this.size, length)
+ size += length
+ }
+ this
+ }
+
+ override def addAll(xs: IterableOnce[T]): this.type = {
+ val k = xs.knownSize
+ if (k > 0) {
+ ensureSize(this.size + k)
+ val actual = IterableOnce.copyElemsToArray(xs, elems, this.size)
+ if (actual != k) throw new IllegalStateException(s"Copied $actual of $k")
+ size += k
+ } else if (k < 0) super.addAll(xs)
+ this
+ }
+}
+
+/** A companion object for array builders.
+ */
+object ArrayBuilder {
+
+ /** Creates a new arraybuilder of type `T`.
+ *
+ * @tparam T type of the elements for the array builder, with a `ClassTag` context bound.
+ * @return a new empty array builder.
+ */
+ @inline def make[T: ClassTag]: ArrayBuilder[T] = {
+ val tag = implicitly[ClassTag[T]]
+ tag.runtimeClass match {
+ case java.lang.Byte.TYPE => new ArrayBuilder.ofByte().asInstanceOf[ArrayBuilder[T]]
+ case java.lang.Short.TYPE => new ArrayBuilder.ofShort().asInstanceOf[ArrayBuilder[T]]
+ case java.lang.Character.TYPE => new ArrayBuilder.ofChar().asInstanceOf[ArrayBuilder[T]]
+ case java.lang.Integer.TYPE => new ArrayBuilder.ofInt().asInstanceOf[ArrayBuilder[T]]
+ case java.lang.Long.TYPE => new ArrayBuilder.ofLong().asInstanceOf[ArrayBuilder[T]]
+ case java.lang.Float.TYPE => new ArrayBuilder.ofFloat().asInstanceOf[ArrayBuilder[T]]
+ case java.lang.Double.TYPE => new ArrayBuilder.ofDouble().asInstanceOf[ArrayBuilder[T]]
+ case java.lang.Boolean.TYPE => new ArrayBuilder.ofBoolean().asInstanceOf[ArrayBuilder[T]]
+ case java.lang.Void.TYPE => new ArrayBuilder.ofUnit().asInstanceOf[ArrayBuilder[T]]
+ case _ => new ArrayBuilder.ofRef[T with AnyRef]()(tag.asInstanceOf[ClassTag[T with AnyRef]]).asInstanceOf[ArrayBuilder[T]]
+ }
+ }
+
+ /** A class for array builders for arrays of reference types.
+ *
+ * This builder can be reused.
+ *
+ * @tparam T type of elements for the array builder, subtype of `AnyRef` with a `ClassTag` context bound.
+ */
+ @SerialVersionUID(3L)
+ final class ofRef[T <: AnyRef](implicit ct: ClassTag[T]) extends ArrayBuilder[T] {
+
+ protected var elems: Array[T] = _
+
+ private def mkArray(size: Int): Array[T] = {
+ if (capacity == size && capacity > 0) elems
+ else if (elems eq null) new Array[T](size)
+ else java.util.Arrays.copyOf[T](elems, size)
+ }
+
+ protected[this] def resize(size: Int): Unit = {
+ elems = mkArray(size)
+ capacity = size
+ }
+
+ def addOne(elem: T): this.type = {
+ ensureSize(size + 1)
+ elems(size) = elem
+ size += 1
+ this
+ }
+
+ def result(): Array[T] = {
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ val res = elems
+ elems = null
+ res
+ }
+ else mkArray(size)
+ }
+
+ override def clear(): Unit = {
+ super.clear()
+ if(elems ne null) java.util.Arrays.fill(elems.asInstanceOf[Array[AnyRef]], null)
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case x: ofRef[_] => (size == x.size) && (elems == x.elems)
+ case _ => false
+ }
+
+ override def toString = "ArrayBuilder.ofRef"
+ }
+
+ /** A class for array builders for arrays of `byte`s. It can be reused. */
+ @SerialVersionUID(3L)
+ final class ofByte extends ArrayBuilder[Byte] {
+
+ protected var elems: Array[Byte] = _
+
+ private def mkArray(size: Int): Array[Byte] = {
+ val newelems = new Array[Byte](size)
+ if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size)
+ newelems
+ }
+
+ protected[this] def resize(size: Int): Unit = {
+ elems = mkArray(size)
+ capacity = size
+ }
+
+ def addOne(elem: Byte): this.type = {
+ ensureSize(size + 1)
+ elems(size) = elem
+ size += 1
+ this
+ }
+
+ def result(): Array[Byte] = {
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ val res = elems
+ elems = null
+ res
+ }
+ else mkArray(size)
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case x: ofByte => (size == x.size) && (elems == x.elems)
+ case _ => false
+ }
+
+ override def toString = "ArrayBuilder.ofByte"
+ }
+
+ /** A class for array builders for arrays of `short`s. It can be reused. */
+ @SerialVersionUID(3L)
+ final class ofShort extends ArrayBuilder[Short] {
+
+ protected var elems: Array[Short] = _
+
+ private def mkArray(size: Int): Array[Short] = {
+ val newelems = new Array[Short](size)
+ if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size)
+ newelems
+ }
+
+ protected[this] def resize(size: Int): Unit = {
+ elems = mkArray(size)
+ capacity = size
+ }
+
+ def addOne(elem: Short): this.type = {
+ ensureSize(size + 1)
+ elems(size) = elem
+ size += 1
+ this
+ }
+
+ def result(): Array[Short] = {
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ val res = elems
+ elems = null
+ res
+ }
+ else mkArray(size)
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case x: ofShort => (size == x.size) && (elems == x.elems)
+ case _ => false
+ }
+
+ override def toString = "ArrayBuilder.ofShort"
+ }
+
+ /** A class for array builders for arrays of `char`s. It can be reused. */
+ @SerialVersionUID(3L)
+ final class ofChar extends ArrayBuilder[Char] {
+
+ protected var elems: Array[Char] = _
+
+ private def mkArray(size: Int): Array[Char] = {
+ val newelems = new Array[Char](size)
+ if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size)
+ newelems
+ }
+
+ protected[this] def resize(size: Int): Unit = {
+ elems = mkArray(size)
+ capacity = size
+ }
+
+ def addOne(elem: Char): this.type = {
+ ensureSize(size + 1)
+ elems(size) = elem
+ size += 1
+ this
+ }
+
+ def result(): Array[Char] = {
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ val res = elems
+ elems = null
+ res
+ }
+ else mkArray(size)
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case x: ofChar => (size == x.size) && (elems == x.elems)
+ case _ => false
+ }
+
+ override def toString = "ArrayBuilder.ofChar"
+ }
+
+ /** A class for array builders for arrays of `int`s. It can be reused. */
+ @SerialVersionUID(3L)
+ final class ofInt extends ArrayBuilder[Int] {
+
+ protected var elems: Array[Int] = _
+
+ private def mkArray(size: Int): Array[Int] = {
+ val newelems = new Array[Int](size)
+ if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size)
+ newelems
+ }
+
+ protected[this] def resize(size: Int): Unit = {
+ elems = mkArray(size)
+ capacity = size
+ }
+
+ def addOne(elem: Int): this.type = {
+ ensureSize(size + 1)
+ elems(size) = elem
+ size += 1
+ this
+ }
+
+ def result(): Array[Int] = {
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ val res = elems
+ elems = null
+ res
+ }
+ else mkArray(size)
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case x: ofInt => (size == x.size) && (elems == x.elems)
+ case _ => false
+ }
+
+ override def toString = "ArrayBuilder.ofInt"
+ }
+
+ /** A class for array builders for arrays of `long`s. It can be reused. */
+ @SerialVersionUID(3L)
+ final class ofLong extends ArrayBuilder[Long] {
+
+ protected var elems: Array[Long] = _
+
+ private def mkArray(size: Int): Array[Long] = {
+ val newelems = new Array[Long](size)
+ if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size)
+ newelems
+ }
+
+ protected[this] def resize(size: Int): Unit = {
+ elems = mkArray(size)
+ capacity = size
+ }
+
+ def addOne(elem: Long): this.type = {
+ ensureSize(size + 1)
+ elems(size) = elem
+ size += 1
+ this
+ }
+
+ def result(): Array[Long] = {
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ val res = elems
+ elems = null
+ res
+ }
+ else mkArray(size)
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case x: ofLong => (size == x.size) && (elems == x.elems)
+ case _ => false
+ }
+
+ override def toString = "ArrayBuilder.ofLong"
+ }
+
+ /** A class for array builders for arrays of `float`s. It can be reused. */
+ @SerialVersionUID(3L)
+ final class ofFloat extends ArrayBuilder[Float] {
+
+ protected var elems: Array[Float] = _
+
+ private def mkArray(size: Int): Array[Float] = {
+ val newelems = new Array[Float](size)
+ if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size)
+ newelems
+ }
+
+ protected[this] def resize(size: Int): Unit = {
+ elems = mkArray(size)
+ capacity = size
+ }
+
+ def addOne(elem: Float): this.type = {
+ ensureSize(size + 1)
+ elems(size) = elem
+ size += 1
+ this
+ }
+
+ def result(): Array[Float] = {
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ val res = elems
+ elems = null
+ res
+ }
+ else mkArray(size)
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case x: ofFloat => (size == x.size) && (elems == x.elems)
+ case _ => false
+ }
+
+ override def toString = "ArrayBuilder.ofFloat"
+ }
+
+ /** A class for array builders for arrays of `double`s. It can be reused. */
+ @SerialVersionUID(3L)
+ final class ofDouble extends ArrayBuilder[Double] {
+
+ protected var elems: Array[Double] = _
+
+ private def mkArray(size: Int): Array[Double] = {
+ val newelems = new Array[Double](size)
+ if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size)
+ newelems
+ }
+
+ protected[this] def resize(size: Int): Unit = {
+ elems = mkArray(size)
+ capacity = size
+ }
+
+ def addOne(elem: Double): this.type = {
+ ensureSize(size + 1)
+ elems(size) = elem
+ size += 1
+ this
+ }
+
+ def result(): Array[Double] = {
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ val res = elems
+ elems = null
+ res
+ }
+ else mkArray(size)
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case x: ofDouble => (size == x.size) && (elems == x.elems)
+ case _ => false
+ }
+
+ override def toString = "ArrayBuilder.ofDouble"
+ }
+
+ /** A class for array builders for arrays of `boolean`s. It can be reused. */
+ @SerialVersionUID(3L)
+ class ofBoolean extends ArrayBuilder[Boolean] {
+
+ protected var elems: Array[Boolean] = _
+
+ private def mkArray(size: Int): Array[Boolean] = {
+ val newelems = new Array[Boolean](size)
+ if (this.size > 0) Array.copy(elems, 0, newelems, 0, this.size)
+ newelems
+ }
+
+ protected[this] def resize(size: Int): Unit = {
+ elems = mkArray(size)
+ capacity = size
+ }
+
+ def addOne(elem: Boolean): this.type = {
+ ensureSize(size + 1)
+ elems(size) = elem
+ size += 1
+ this
+ }
+
+ def result(): Array[Boolean] = {
+ if (capacity != 0 && capacity == size) {
+ capacity = 0
+ val res = elems
+ elems = null
+ res
+ }
+ else mkArray(size)
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case x: ofBoolean => (size == x.size) && (elems == x.elems)
+ case _ => false
+ }
+
+ override def toString = "ArrayBuilder.ofBoolean"
+ }
+
+ /** A class for array builders for arrays of `Unit` type. It can be reused. */
+ @SerialVersionUID(3L)
+ final class ofUnit extends ArrayBuilder[Unit] {
+
+ protected def elems: Array[Unit] = throw new UnsupportedOperationException()
+
+ def addOne(elem: Unit): this.type = {
+ val newSize = size + 1
+ ensureSize(newSize)
+ size = newSize
+ this
+ }
+
+ override def addAll(xs: IterableOnce[Unit]): this.type = {
+ val newSize = size + xs.iterator.size
+ ensureSize(newSize)
+ size = newSize
+ this
+ }
+
+ override def addAll(xs: Array[_ <: Unit], offset: Int, length: Int): this.type = {
+ val newSize = size + length
+ ensureSize(newSize)
+ size = newSize
+ this
+ }
+
+ def result() = {
+ val ans = new Array[Unit](size)
+ var i = 0
+ while (i < size) { ans(i) = (); i += 1 }
+ ans
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case x: ofUnit => (size == x.size)
+ case _ => false
+ }
+
+ protected[this] def resize(size: Int): Unit = capacity = size
+
+ override def toString = "ArrayBuilder.ofUnit"
+ }
+}
diff --git a/library/src/scala/collection/mutable/ArrayDeque.scala b/library/src/scala/collection/mutable/ArrayDeque.scala
new file mode 100644
index 000000000000..d7fbf932fc53
--- /dev/null
+++ b/library/src/scala/collection/mutable/ArrayDeque.scala
@@ -0,0 +1,648 @@
+/*
+ * 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 collection
+package mutable
+
+import scala.annotation.nowarn
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.generic.{CommonErrors, DefaultSerializable}
+import scala.reflect.ClassTag
+
+/** An implementation of a double-ended queue that internally uses a resizable circular buffer.
+ *
+ * Append, prepend, removeHead, removeLast and random-access (indexed-lookup and indexed-replacement)
+ * take amortized constant time. In general, removals and insertions at i-th index are O(min(i, n-i))
+ * and thus insertions and removals from end/beginning are fast.
+ *
+ * @note Subclasses ''must'' override the `ofArray` protected method to return a more specific type.
+ *
+ * @tparam A the type of this ArrayDeque's elements.
+ *
+ * @define Coll `mutable.ArrayDeque`
+ * @define coll array deque
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+class ArrayDeque[A] protected (
+ protected var array: Array[AnyRef],
+ private[ArrayDeque] var start: Int,
+ private[ArrayDeque] var end: Int
+) extends AbstractBuffer[A]
+ with IndexedBuffer[A]
+ with IndexedSeqOps[A, ArrayDeque, ArrayDeque[A]]
+ with StrictOptimizedSeqOps[A, ArrayDeque, ArrayDeque[A]]
+ with IterableFactoryDefaults[A, ArrayDeque]
+ with ArrayDequeOps[A, ArrayDeque, ArrayDeque[A]]
+ with Cloneable[ArrayDeque[A]]
+ with DefaultSerializable {
+
+ reset(array, start, end)
+
+ private[this] def reset(array: Array[AnyRef], start: Int, end: Int) = {
+ assert((array.length & (array.length - 1)) == 0, s"Array.length must be power of 2")
+ requireBounds(idx = start, until = array.length)
+ requireBounds(idx = end, until = array.length)
+ this.array = array
+ this.start = start
+ this.end = end
+ }
+
+ def this(initialSize: Int = ArrayDeque.DefaultInitialSize) = this(ArrayDeque.alloc(initialSize), start = 0, end = 0)
+
+ override def knownSize: Int = super[IndexedSeqOps].knownSize
+
+ // No-Op override to allow for more efficient stepper in a minor release.
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit = super.stepper(shape)
+
+ def apply(idx: Int): A = {
+ requireBounds(idx)
+ _get(idx)
+ }
+
+ def update(idx: Int, elem: A): Unit = {
+ requireBounds(idx)
+ _set(idx, elem)
+ }
+
+ def addOne(elem: A): this.type = {
+ ensureSize(length + 1)
+ appendAssumingCapacity(elem)
+ }
+
+ def prepend(elem: A): this.type = {
+ ensureSize(length + 1)
+ prependAssumingCapacity(elem)
+ }
+
+ @inline private[ArrayDeque] def appendAssumingCapacity(elem: A): this.type = {
+ array(end) = elem.asInstanceOf[AnyRef]
+ end = end_+(1)
+ this
+ }
+
+ @inline private[ArrayDeque] def prependAssumingCapacity(elem: A): this.type = {
+ start = start_-(1)
+ array(start) = elem.asInstanceOf[AnyRef]
+ this
+ }
+
+ override def prependAll(elems: IterableOnce[A]): this.type = {
+ val it = elems.iterator
+ if (it.nonEmpty) {
+ val n = length
+ // The following code resizes the current collection at most once and traverses elems at most twice
+ elems.knownSize match {
+ // Size is too expensive to compute AND we can traverse it only once - can't do much but retry with an IndexedSeq
+ case srcLength if srcLength < 0 => prependAll(it.to(IndexedSeq: Factory[A, IndexedSeq[A]] /* type ascription needed by Dotty */))
+
+ // We know for sure we need to resize to hold everything, might as well resize and memcopy upfront
+ case srcLength if mustGrow(srcLength + n) =>
+ val finalLength = srcLength + n
+ val array2 = ArrayDeque.alloc(finalLength)
+ @annotation.unused val copied = it.copyToArray(array2.asInstanceOf[Array[A]])
+ //assert(copied == srcLength)
+ copySliceToArray(srcStart = 0, dest = array2, destStart = srcLength, maxItems = n)
+ reset(array = array2, start = 0, end = finalLength)
+
+ // Just fill up from (start - srcLength) to (start - 1) and move back start
+ case srcLength =>
+ // Optimized version of `elems.zipWithIndex.foreach((elem, i) => _set(i - srcLength, elem))`
+ var i = 0
+ while(i < srcLength) {
+ _set(i - srcLength, it.next())
+ i += 1
+ }
+ start = start_-(srcLength)
+ }
+ }
+ this
+ }
+
+ override def addAll(elems: IterableOnce[A]): this.type = {
+ elems.knownSize match {
+ case srcLength if srcLength > 0 =>
+ ensureSize(srcLength + length)
+ elems.iterator.foreach(appendAssumingCapacity)
+ case _ => elems.iterator.foreach(+=)
+ }
+ this
+ }
+
+ def insert(idx: Int, elem: A): Unit = {
+ requireBounds(idx, length+1)
+ val n = length
+ if (idx == 0) {
+ prepend(elem)
+ } else if (idx == n) {
+ addOne(elem)
+ } else {
+ val finalLength = n + 1
+ if (mustGrow(finalLength)) {
+ val array2 = ArrayDeque.alloc(finalLength)
+ copySliceToArray(srcStart = 0, dest = array2, destStart = 0, maxItems = idx)
+ array2(idx) = elem.asInstanceOf[AnyRef]
+ copySliceToArray(srcStart = idx, dest = array2, destStart = idx + 1, maxItems = n)
+ reset(array = array2, start = 0, end = finalLength)
+ } else if (n <= idx * 2) {
+ var i = n - 1
+ while(i >= idx) {
+ _set(i + 1, _get(i))
+ i -= 1
+ }
+ end = end_+(1)
+ i += 1
+ _set(i, elem)
+ } else {
+ var i = 0
+ while(i < idx) {
+ _set(i - 1, _get(i))
+ i += 1
+ }
+ start = start_-(1)
+ _set(i, elem)
+ }
+ }
+ }
+
+ def insertAll(idx: Int, elems: IterableOnce[A]): Unit = {
+ requireBounds(idx, length+1)
+ val n = length
+ if (idx == 0) {
+ prependAll(elems)
+ } else if (idx == n) {
+ addAll(elems)
+ } else {
+ // Get both an iterator and the length of the source (by copying the source to an IndexedSeq if needed)
+ val (it, srcLength) = {
+ val _srcLength = elems.knownSize
+ if (_srcLength >= 0) (elems.iterator, _srcLength)
+ else {
+ val indexed = IndexedSeq.from(elems)
+ (indexed.iterator, indexed.size)
+ }
+ }
+ if (it.nonEmpty) {
+ val finalLength = srcLength + n
+ // Either we resize right away or move prefix left or suffix right
+ if (mustGrow(finalLength)) {
+ val array2 = ArrayDeque.alloc(finalLength)
+ copySliceToArray(srcStart = 0, dest = array2, destStart = 0, maxItems = idx)
+ @annotation.unused val copied = it.copyToArray(array2.asInstanceOf[Array[A]], idx)
+ //assert(copied == srcLength)
+ copySliceToArray(srcStart = idx, dest = array2, destStart = idx + srcLength, maxItems = n)
+ reset(array = array2, start = 0, end = finalLength)
+ } else if (2*idx >= n) { // Cheaper to shift the suffix right
+ var i = n - 1
+ while(i >= idx) {
+ _set(i + srcLength, _get(i))
+ i -= 1
+ }
+ end = end_+(srcLength)
+ while(it.hasNext) {
+ i += 1
+ _set(i, it.next())
+ }
+ } else { // Cheaper to shift prefix left
+ var i = 0
+ while(i < idx) {
+ _set(i - srcLength, _get(i))
+ i += 1
+ }
+ start = start_-(srcLength)
+ while(it.hasNext) {
+ _set(i, it.next())
+ i += 1
+ }
+ }
+ }
+ }
+ }
+
+ def remove(idx: Int, count: Int): Unit = {
+ if (count > 0) {
+ requireBounds(idx)
+ val n = length
+ val removals = Math.min(n - idx, count)
+ val finalLength = n - removals
+ val suffixStart = idx + removals
+ // If we know we can resize after removing, do it right away using arrayCopy
+ // Else, choose the shorter: either move the prefix (0 until idx) right OR the suffix (idx+removals until n) left
+ if (shouldShrink(finalLength)) {
+ val array2 = ArrayDeque.alloc(finalLength)
+ copySliceToArray(srcStart = 0, dest = array2, destStart = 0, maxItems = idx)
+ copySliceToArray(srcStart = suffixStart, dest = array2, destStart = idx, maxItems = n)
+ reset(array = array2, start = 0, end = finalLength)
+ } else if (2*idx <= finalLength) { // Cheaper to move the prefix right
+ var i = suffixStart - 1
+ while(i >= removals) {
+ _set(i, _get(i - removals))
+ i -= 1
+ }
+ while(i >= 0) {
+ _set(i, null.asInstanceOf[A])
+ i -= 1
+ }
+ start = start_+(removals)
+ } else { // Cheaper to move the suffix left
+ var i = idx
+ while(i < finalLength) {
+ _set(i, _get(i + removals))
+ i += 1
+ }
+ while(i < n) {
+ _set(i, null.asInstanceOf[A])
+ i += 1
+ }
+ end = end_-(removals)
+ }
+ } else {
+ require(count == 0, s"removing negative number of elements: $count")
+ }
+ }
+
+ def remove(idx: Int): A = {
+ val elem = this(idx)
+ remove(idx, 1)
+ elem
+ }
+
+ override def subtractOne(elem: A): this.type = {
+ val idx = indexOf(elem)
+ if (idx >= 0) remove(idx, 1) //TODO: SeqOps should be fluent API
+ this
+ }
+
+ /**
+ *
+ * @param resizeInternalRepr If this is set, resize the internal representation to reclaim space once in a while
+ * @return
+ */
+ def removeHeadOption(resizeInternalRepr: Boolean = false): Option[A] =
+ if (isEmpty) None else Some(removeHeadAssumingNonEmpty(resizeInternalRepr))
+
+ /**
+ * Unsafely remove the first element (throws exception when empty)
+ * See also removeHeadOption()
+ *
+ * @param resizeInternalRepr If this is set, resize the internal representation to reclaim space once in a while
+ * @throws NoSuchElementException when empty
+ * @return
+ */
+ def removeHead(resizeInternalRepr: Boolean = false): A =
+ if (isEmpty) throw new NoSuchElementException(s"empty collection") else removeHeadAssumingNonEmpty(resizeInternalRepr)
+
+ @inline private[this] def removeHeadAssumingNonEmpty(resizeInternalRepr: Boolean = false): A = {
+ val elem = array(start)
+ array(start) = null
+ start = start_+(1)
+ if (resizeInternalRepr) resize(length)
+ elem.asInstanceOf[A]
+ }
+
+ /**
+ *
+ * @param resizeInternalRepr If this is set, resize the internal representation to reclaim space once in a while
+ * @return
+ */
+ def removeLastOption(resizeInternalRepr: Boolean = false): Option[A] =
+ if (isEmpty) None else Some(removeLastAssumingNonEmpty(resizeInternalRepr))
+
+ /**
+ * Unsafely remove the last element (throws exception when empty)
+ * See also removeLastOption()
+ *
+ * @param resizeInternalRepr If this is set, resize the internal representation to reclaim space once in a while
+ * @throws NoSuchElementException when empty
+ * @return
+ */
+ def removeLast(resizeInternalRepr: Boolean = false): A =
+ if (isEmpty) throw new NoSuchElementException(s"empty collection") else removeLastAssumingNonEmpty(resizeInternalRepr)
+
+ @`inline` private[this] def removeLastAssumingNonEmpty(resizeInternalRepr: Boolean = false): A = {
+ end = end_-(1)
+ val elem = array(end)
+ array(end) = null
+ if (resizeInternalRepr) resize(length)
+ elem.asInstanceOf[A]
+ }
+
+ /**
+ * Remove all elements from this collection and return the elements while emptying this data structure
+ * @return
+ */
+ def removeAll(): scala.collection.immutable.Seq[A] = {
+ val elems = scala.collection.immutable.Seq.newBuilder[A]
+ elems.sizeHint(length)
+ while(nonEmpty) {
+ elems += removeHeadAssumingNonEmpty()
+ }
+ elems.result()
+ }
+
+ /**
+ * Remove all elements from this collection and return the elements in reverse while emptying this data structure
+ * @return
+ */
+ def removeAllReverse(): scala.collection.immutable.Seq[A] = {
+ val elems = scala.collection.immutable.Seq.newBuilder[A]
+ elems.sizeHint(length)
+ while(nonEmpty) {
+ elems += removeLastAssumingNonEmpty()
+ }
+ elems.result()
+ }
+
+ /**
+ * Returns and removes all elements from the left of this queue which satisfy the given predicate
+ *
+ * @param f the predicate used for choosing elements
+ * @return
+ */
+ def removeHeadWhile(f: A => Boolean): scala.collection.immutable.Seq[A] = {
+ val elems = scala.collection.immutable.Seq.newBuilder[A]
+ while(headOption.exists(f)) {
+ elems += removeHeadAssumingNonEmpty()
+ }
+ elems.result()
+ }
+
+ /**
+ * Returns and removes all elements from the right of this queue which satisfy the given predicate
+ *
+ * @param f the predicate used for choosing elements
+ * @return
+ */
+ def removeLastWhile(f: A => Boolean): scala.collection.immutable.Seq[A] = {
+ val elems = scala.collection.immutable.Seq.newBuilder[A]
+ while(lastOption.exists(f)) {
+ elems += removeLastAssumingNonEmpty()
+ }
+ elems.result()
+ }
+
+ /** Returns the first element which satisfies the given predicate after or at some start index
+ * and removes this element from the collections
+ *
+ * @param p the predicate used for choosing the first element
+ * @param from the start index
+ * @return the first element of the queue for which p yields true
+ */
+ def removeFirst(p: A => Boolean, from: Int = 0): Option[A] = {
+ val i = indexWhere(p, from)
+ if (i < 0) None else Some(remove(i))
+ }
+
+ /** Returns all elements in this collection which satisfy the given predicate
+ * and removes those elements from this collections.
+ *
+ * @param p the predicate used for choosing elements
+ * @return a sequence of all elements in the queue for which
+ * p yields true.
+ */
+ def removeAll(p: A => Boolean): scala.collection.immutable.Seq[A] = {
+ val res = scala.collection.immutable.Seq.newBuilder[A]
+ var i, j = 0
+ while (i < size) {
+ if (p(this(i))) {
+ res += this(i)
+ } else {
+ if (i != j) {
+ this(j) = this(i)
+ }
+ j += 1
+ }
+ i += 1
+ }
+ if (i != j) takeInPlace(j)
+ res.result()
+ }
+
+ @inline def ensureSize(hint: Int) = if (hint > length && mustGrow(hint)) resize(hint)
+
+ def length = end_-(start)
+
+ override def isEmpty = start == end
+
+ override protected def klone(): ArrayDeque[A] = new ArrayDeque(array.clone(), start = start, end = end)
+
+ override def iterableFactory: SeqFactory[ArrayDeque] = ArrayDeque
+
+ /**
+ * Note: This does not actually resize the internal representation.
+ * See clearAndShrink if you want to also resize internally
+ */
+ def clear(): Unit = {
+ while(nonEmpty) {
+ removeHeadAssumingNonEmpty()
+ }
+ }
+
+ /**
+ * Clears this buffer and shrinks to @param size
+ *
+ * @param size
+ * @return
+ */
+ def clearAndShrink(size: Int = ArrayDeque.DefaultInitialSize): this.type = {
+ reset(array = ArrayDeque.alloc(size), start = 0, end = 0)
+ this
+ }
+
+ protected def ofArray(array: Array[AnyRef], end: Int): ArrayDeque[A] =
+ new ArrayDeque[A](array, start = 0, end)
+
+ override def copyToArray[B >: A](dest: Array[B], destStart: Int, len: Int): Int = {
+ val copied = IterableOnce.elemsToCopyToArray(length, dest.length, destStart, len)
+ if (copied > 0) {
+ copySliceToArray(srcStart = 0, dest = dest, destStart = destStart, maxItems = len)
+ }
+ copied
+ }
+
+ override def toArray[B >: A: ClassTag]: Array[B] =
+ copySliceToArray(srcStart = 0, dest = new Array[B](length), destStart = 0, maxItems = length)
+
+ /**
+ * Trims the capacity of this ArrayDeque's instance to be the current size
+ */
+ def trimToSize(): Unit = resize(length)
+
+ // Utils for common modular arithmetic:
+ @inline protected def start_+(idx: Int) = (start + idx) & (array.length - 1)
+ @inline private[this] def start_-(idx: Int) = (start - idx) & (array.length - 1)
+ @inline private[this] def end_+(idx: Int) = (end + idx) & (array.length - 1)
+ @inline private[this] def end_-(idx: Int) = (end - idx) & (array.length - 1)
+
+ // Note: here be overflow dragons! This is used for int overflow
+ // assumptions in resize(). Use caution changing.
+ @inline private[this] def mustGrow(len: Int) = {
+ len >= array.length
+ }
+
+ // Assumes that 0 <= len < array.length!
+ @inline private[this] def shouldShrink(len: Int) = {
+ // To avoid allocation churn, only shrink when array is large
+ // and less than 2/5 filled.
+ array.length > ArrayDeque.StableSize && array.length - len - (len >> 1) > len
+ }
+
+ // Assumes that 0 <= len < array.length!
+ @inline private[this] def canShrink(len: Int) = {
+ array.length > ArrayDeque.DefaultInitialSize && array.length - len > len
+ }
+
+ @inline private[this] def _get(idx: Int): A = array(start_+(idx)).asInstanceOf[A]
+
+ @inline private[this] def _set(idx: Int, elem: A) = array(start_+(idx)) = elem.asInstanceOf[AnyRef]
+
+ // Assumes that 0 <= len.
+ private[this] def resize(len: Int) = if (mustGrow(len) || canShrink(len)) {
+ val n = length
+ val array2 = copySliceToArray(srcStart = 0, dest = ArrayDeque.alloc(len), destStart = 0, maxItems = n)
+ reset(array = array2, start = 0, end = n)
+ }
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix = "ArrayDeque"
+}
+
+/**
+ * $factoryInfo
+ * @define coll array deque
+ * @define Coll `ArrayDeque`
+ */
+@SerialVersionUID(3L)
+object ArrayDeque extends StrictOptimizedSeqFactory[ArrayDeque] {
+
+ def from[B](coll: collection.IterableOnce[B]): ArrayDeque[B] = {
+ val s = coll.knownSize
+ if (s >= 0) {
+ val array = alloc(s)
+ val actual = IterableOnce.copyElemsToArray(coll, array.asInstanceOf[Array[Any]])
+ if (actual != s) throw new IllegalStateException(s"Copied $actual of $s")
+ new ArrayDeque[B](array, start = 0, end = s)
+ } else new ArrayDeque[B]() ++= coll
+ }
+
+ def newBuilder[A]: Builder[A, ArrayDeque[A]] =
+ new GrowableBuilder[A, ArrayDeque[A]](empty) {
+ override def sizeHint(size: Int): Unit = {
+ elems.ensureSize(size)
+ }
+ }
+
+ def empty[A]: ArrayDeque[A] = new ArrayDeque[A]()
+
+ final val DefaultInitialSize = 16
+
+ /**
+ * We try to not repeatedly resize arrays smaller than this
+ */
+ private[ArrayDeque] final val StableSize = 128
+
+ /**
+ * Allocates an array whose size is next power of 2 > `len`
+ * Largest possible len is 1<<30 - 1
+ *
+ * @param len
+ * @return
+ */
+ private[mutable] def alloc(len: Int) = {
+ require(len >= 0, s"Non-negative array size required")
+ val size = (1 << 31) >>> java.lang.Integer.numberOfLeadingZeros(len) << 1
+ require(size >= 0, s"ArrayDeque too big - cannot allocate ArrayDeque of length $len")
+ new Array[AnyRef](Math.max(size, DefaultInitialSize))
+ }
+}
+
+trait ArrayDequeOps[A, +CC[_], +C <: AnyRef] extends StrictOptimizedSeqOps[A, CC, C] {
+ protected def array: Array[AnyRef]
+
+ final override def clone(): C = klone()
+
+ protected def klone(): C
+
+ protected def ofArray(array: Array[AnyRef], end: Int): C
+
+ protected def start_+(idx: Int): Int
+
+ @inline protected final def requireBounds(idx: Int, until: Int = length): Unit =
+ if (idx < 0 || idx >= until)
+ throw CommonErrors.indexOutOfBounds(index = idx, max = until - 1)
+
+ /**
+ * This is a more general version of copyToArray - this also accepts a srcStart unlike copyToArray
+ * This copies maxItems elements from this collections srcStart to dest's destStart
+ * If we reach the end of either collections before we could copy maxItems, we simply stop copying
+ *
+ * @param dest
+ * @param srcStart
+ * @param destStart
+ * @param maxItems
+ */
+ def copySliceToArray(srcStart: Int, dest: Array[_], destStart: Int, maxItems: Int): dest.type = {
+ requireBounds(destStart, dest.length+1)
+ val toCopy = Math.min(maxItems, Math.min(length - srcStart, dest.length - destStart))
+ if (toCopy > 0) {
+ requireBounds(srcStart)
+ val startIdx = start_+(srcStart)
+ val block1 = Math.min(toCopy, array.length - startIdx)
+ Array.copy(src = array, srcPos = startIdx, dest = dest, destPos = destStart, length = block1)
+ val block2 = toCopy - block1
+ if (block2 > 0) Array.copy(src = array, srcPos = 0, dest = dest, destPos = destStart + block1, length = block2)
+ }
+ dest
+ }
+
+ override def reverse: C = {
+ val n = length
+ val arr = ArrayDeque.alloc(n)
+ var i = 0
+ while(i < n) {
+ arr(i) = this(n - i - 1).asInstanceOf[AnyRef]
+ i += 1
+ }
+ ofArray(arr, n)
+ }
+
+ override def slice(from: Int, until: Int): C = {
+ val n = length
+ val left = Math.max(0, Math.min(n, from))
+ val right = Math.max(0, Math.min(n, until))
+ val len = right - left
+ if (len <= 0) {
+ empty
+ } else if (len >= n) {
+ klone()
+ } else {
+ val array2 = copySliceToArray(srcStart = left, dest = ArrayDeque.alloc(len), destStart = 0, maxItems = len)
+ ofArray(array2, len)
+ }
+ }
+
+ override def sliding(window: Int, step: Int): Iterator[C] = {
+ require(window > 0 && step > 0, s"window=$window and step=$step, but both must be positive")
+ length match {
+ case 0 => Iterator.empty
+ case n if n <= window => Iterator.single(slice(0, length))
+ case n =>
+ val lag = if (window > step) window - step else 0
+ Iterator.range(start = 0, end = n - lag, step = step).map(i => slice(i, i + window))
+ }
+ }
+
+ override def grouped(n: Int): Iterator[C] = sliding(n, n)
+}
diff --git a/library/src/scala/collection/mutable/ArraySeq.scala b/library/src/scala/collection/mutable/ArraySeq.scala
new file mode 100644
index 000000000000..0537092d0b13
--- /dev/null
+++ b/library/src/scala/collection/mutable/ArraySeq.scala
@@ -0,0 +1,353 @@
+/*
+ * 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 mutable
+import java.util.Arrays
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.convert.impl._
+import scala.reflect.ClassTag
+import scala.util.hashing.MurmurHash3
+
+/**
+ * A collection representing `Array[T]`. Unlike `ArrayBuffer` it is always backed by the same
+ * underlying `Array`, therefore it is not growable or shrinkable.
+ *
+ * @tparam T type of the elements in this wrapped array.
+ *
+ * @define Coll `ArraySeq`
+ * @define coll wrapped array
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+@SerialVersionUID(3L)
+sealed abstract class ArraySeq[T]
+ extends AbstractSeq[T]
+ with IndexedSeq[T]
+ with IndexedSeqOps[T, ArraySeq, ArraySeq[T]]
+ with StrictOptimizedSeqOps[T, ArraySeq, ArraySeq[T]]
+ with Serializable {
+
+ override def iterableFactory: scala.collection.SeqFactory[ArraySeq] = ArraySeq.untagged
+
+ override protected def fromSpecific(coll: scala.collection.IterableOnce[T]): ArraySeq[T] = {
+ val b = ArrayBuilder.make(using elemTag).asInstanceOf[ArrayBuilder[T]]
+ b.sizeHint(coll, delta = 0)
+ b ++= coll
+ ArraySeq.make(b.result())
+ }
+ override protected def newSpecificBuilder: Builder[T, ArraySeq[T]] = ArraySeq.newBuilder(using elemTag).asInstanceOf[Builder[T, ArraySeq[T]]]
+ override def empty: ArraySeq[T] = ArraySeq.empty(using elemTag.asInstanceOf[ClassTag[T]])
+
+ /** The tag of the element type. This does not have to be equal to the element type of this ArraySeq. A primitive
+ * ArraySeq can be backed by an array of boxed values and a reference ArraySeq can be backed by an array of a supertype
+ * or subtype of the element type. */
+ def elemTag: ClassTag[_]
+
+ /** Update element at given index */
+ def update(@deprecatedName("idx", "2.13.0") index: Int, elem: T): Unit
+
+ /** The underlying array. Its element type does not have to be equal to the element type of this ArraySeq. A primitive
+ * ArraySeq can be backed by an array of boxed values and a reference ArraySeq can be backed by an array of a supertype
+ * or subtype of the element type. */
+ def array: Array[_]
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[T, S]): S with EfficientSplit
+
+ override protected[this] def className = "ArraySeq"
+
+ /** Clones this object, including the underlying Array. */
+ override def clone(): ArraySeq[T] = ArraySeq.make(array.clone()).asInstanceOf[ArraySeq[T]]
+
+ override def copyToArray[B >: T](xs: Array[B], start: Int, len: Int): Int = {
+ val copied = IterableOnce.elemsToCopyToArray(length, xs.length, start, len)
+ if(copied > 0) {
+ Array.copy(array, 0, xs, start, copied)
+ }
+ copied
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case that: ArraySeq[_] if this.array.length != that.array.length =>
+ false
+ case _ =>
+ super.equals(other)
+ }
+
+ override def sorted[B >: T](implicit ord: Ordering[B]): ArraySeq[T] =
+ ArraySeq.make(array.sorted(ord.asInstanceOf[Ordering[Any]])).asInstanceOf[ArraySeq[T]]
+
+ override def sortInPlace[B >: T]()(implicit ord: Ordering[B]): this.type = {
+ if (length > 1) scala.util.Sorting.stableSort(array.asInstanceOf[Array[B]])
+ this
+ }
+}
+
+/** A companion object used to create instances of `ArraySeq`.
+ */
+@SerialVersionUID(3L)
+object ArraySeq extends StrictOptimizedClassTagSeqFactory[ArraySeq] { self =>
+ val untagged: SeqFactory[ArraySeq] = new ClassTagSeqFactory.AnySeqDelegate(self)
+
+ // This is reused for all calls to empty.
+ private[this] val EmptyArraySeq = new ofRef[AnyRef](new Array[AnyRef](0))
+ def empty[T : ClassTag]: ArraySeq[T] = EmptyArraySeq.asInstanceOf[ArraySeq[T]]
+
+ def from[A : ClassTag](it: scala.collection.IterableOnce[A]): ArraySeq[A] = make(Array.from[A](it))
+
+ def newBuilder[A : ClassTag]: Builder[A, ArraySeq[A]] = ArrayBuilder.make[A].mapResult(make)
+
+ /**
+ * Wrap an existing `Array` into a `ArraySeq` of the proper primitive specialization type
+ * without copying.
+ *
+ * Note that an array containing boxed primitives can be converted to a `ArraySeq` without
+ * copying. For example, `val a: Array[Any] = Array(1)` is an array of `Object` at runtime,
+ * containing `Integer`s. An `ArraySeq[Int]` can be obtained with a cast:
+ * `ArraySeq.make(a).asInstanceOf[ArraySeq[Int]]`. The values are still
+ * boxed, the resulting instance is an [[ArraySeq.ofRef]]. Writing
+ * `ArraySeq.make(a.asInstanceOf[Array[Int]])` does not work, it throws a `ClassCastException`
+ * at runtime.
+ */
+ def make[T](x: Array[T]): ArraySeq[T] = ((x: @unchecked) match {
+ case null => null
+ case x: Array[AnyRef] => new ofRef[AnyRef](x)
+ case x: Array[Int] => new ofInt(x)
+ case x: Array[Double] => new ofDouble(x)
+ case x: Array[Long] => new ofLong(x)
+ case x: Array[Float] => new ofFloat(x)
+ case x: Array[Char] => new ofChar(x)
+ case x: Array[Byte] => new ofByte(x)
+ case x: Array[Short] => new ofShort(x)
+ case x: Array[Boolean] => new ofBoolean(x)
+ case x: Array[Unit] => new ofUnit(x)
+ }).asInstanceOf[ArraySeq[T]]
+
+ @SerialVersionUID(3L)
+ final class ofRef[T <: AnyRef](val array: Array[T]) extends ArraySeq[T] {
+ def elemTag: ClassTag[T] = ClassTag[T](array.getClass.getComponentType)
+ def length: Int = array.length
+ def apply(index: Int): T = array(index)
+ def update(index: Int, elem: T): Unit = { array(index) = elem }
+ override def hashCode = MurmurHash3.arraySeqHash(array)
+ override def equals(that: Any) = that match {
+ case that: ofRef[_] =>
+ Array.equals(
+ this.array.asInstanceOf[Array[AnyRef]],
+ that.array.asInstanceOf[Array[AnyRef]])
+ case _ => super.equals(that)
+ }
+ override def iterator: Iterator[T] = new ArrayOps.ArrayIterator[T](array)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[T, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ new ObjectArrayStepper(array, 0, array.length)
+ else shape.parUnbox(new ObjectArrayStepper(array, 0, array.length).asInstanceOf[AnyStepper[T] with EfficientSplit])
+ ).asInstanceOf[S with EfficientSplit]
+ }
+
+ @SerialVersionUID(3L)
+ final class ofByte(val array: Array[Byte]) extends ArraySeq[Byte] {
+ // Type erases to `ManifestFactory.ByteManifest`, but can't annotate that because it's not accessible
+ def elemTag: ClassTag.Byte.type = ClassTag.Byte
+ def length: Int = array.length
+ def apply(index: Int): Byte = array(index)
+ def update(index: Int, elem: Byte): Unit = { array(index) = elem }
+ override def hashCode = MurmurHash3.arraySeqHash(array)
+ override def equals(that: Any) = that match {
+ case that: ofByte => Arrays.equals(array, that.array)
+ case _ => super.equals(that)
+ }
+ override def iterator: Iterator[Byte] = new ArrayOps.ArrayIterator[Byte](array)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Byte, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParIntStepper(new WidenedByteArrayStepper(array, 0, array.length))
+ else new WidenedByteArrayStepper(array, 0, array.length)
+ ).asInstanceOf[S with EfficientSplit]
+ }
+
+ @SerialVersionUID(3L)
+ final class ofShort(val array: Array[Short]) extends ArraySeq[Short] {
+ // Type erases to `ManifestFactory.ShortManifest`, but can't annotate that because it's not accessible
+ def elemTag: ClassTag.Short.type = ClassTag.Short
+ def length: Int = array.length
+ def apply(index: Int): Short = array(index)
+ def update(index: Int, elem: Short): Unit = { array(index) = elem }
+ override def hashCode = MurmurHash3.arraySeqHash(array)
+ override def equals(that: Any) = that match {
+ case that: ofShort => Arrays.equals(array, that.array)
+ case _ => super.equals(that)
+ }
+ override def iterator: Iterator[Short] = new ArrayOps.ArrayIterator[Short](array)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Short, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParIntStepper(new WidenedShortArrayStepper(array, 0, array.length))
+ else new WidenedShortArrayStepper(array, 0, array.length)
+ ).asInstanceOf[S with EfficientSplit]
+ }
+
+ @SerialVersionUID(3L)
+ final class ofChar(val array: Array[Char]) extends ArraySeq[Char] {
+ // Type erases to `ManifestFactory.CharManifest`, but can't annotate that because it's not accessible
+ def elemTag: ClassTag.Char.type = ClassTag.Char
+ def length: Int = array.length
+ def apply(index: Int): Char = array(index)
+ def update(index: Int, elem: Char): Unit = { array(index) = elem }
+ override def hashCode = MurmurHash3.arraySeqHash(array)
+ override def equals(that: Any) = that match {
+ case that: ofChar => Arrays.equals(array, that.array)
+ case _ => super.equals(that)
+ }
+ override def iterator: Iterator[Char] = new ArrayOps.ArrayIterator[Char](array)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Char, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParIntStepper(new WidenedCharArrayStepper(array, 0, array.length))
+ else new WidenedCharArrayStepper(array, 0, array.length)
+ ).asInstanceOf[S with EfficientSplit]
+
+ override def addString(sb: StringBuilder, start: String, sep: String, end: String): sb.type = {
+ val jsb = sb.underlying
+ if (start.length != 0) jsb.append(start)
+ val len = array.length
+ if (len != 0) {
+ if (sep.isEmpty) jsb.append(array)
+ else {
+ jsb.ensureCapacity(jsb.length + len + end.length + (len - 1) * sep.length)
+ jsb.append(array(0))
+ var i = 1
+ while (i < len) {
+ jsb.append(sep)
+ jsb.append(array(i))
+ i += 1
+ }
+ }
+ }
+ if (end.length != 0) jsb.append(end)
+ sb
+ }
+ }
+
+ @SerialVersionUID(3L)
+ final class ofInt(val array: Array[Int]) extends ArraySeq[Int] {
+ // Type erases to `ManifestFactory.IntManifest`, but can't annotate that because it's not accessible
+ def elemTag: ClassTag.Int.type = ClassTag.Int
+ def length: Int = array.length
+ def apply(index: Int): Int = array(index)
+ def update(index: Int, elem: Int): Unit = { array(index) = elem }
+ override def hashCode = MurmurHash3.arraySeqHash(array)
+ override def equals(that: Any) = that match {
+ case that: ofInt => Arrays.equals(array, that.array)
+ case _ => super.equals(that)
+ }
+ override def iterator: Iterator[Int] = new ArrayOps.ArrayIterator[Int](array)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Int, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParIntStepper(new IntArrayStepper(array, 0, array.length))
+ else new IntArrayStepper(array, 0, array.length)
+ ).asInstanceOf[S with EfficientSplit]
+ }
+
+ @SerialVersionUID(3L)
+ final class ofLong(val array: Array[Long]) extends ArraySeq[Long] {
+ // Type erases to `ManifestFactory.LongManifest`, but can't annotate that because it's not accessible
+ def elemTag: ClassTag.Long.type = ClassTag.Long
+ def length: Int = array.length
+ def apply(index: Int): Long = array(index)
+ def update(index: Int, elem: Long): Unit = { array(index) = elem }
+ override def hashCode = MurmurHash3.arraySeqHash(array)
+ override def equals(that: Any) = that match {
+ case that: ofLong => Arrays.equals(array, that.array)
+ case _ => super.equals(that)
+ }
+ override def iterator: Iterator[Long] = new ArrayOps.ArrayIterator[Long](array)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Long, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParLongStepper(new LongArrayStepper(array, 0, array.length))
+ else new LongArrayStepper(array, 0, array.length)
+ ).asInstanceOf[S with EfficientSplit]
+ }
+
+ @SerialVersionUID(3L)
+ final class ofFloat(val array: Array[Float]) extends ArraySeq[Float] {
+ // Type erases to `ManifestFactory.FloatManifest`, but can't annotate that because it's not accessible
+ def elemTag: ClassTag.Float.type = ClassTag.Float
+ def length: Int = array.length
+ def apply(index: Int): Float = array(index)
+ def update(index: Int, elem: Float): Unit = { array(index) = elem }
+ override def hashCode = MurmurHash3.arraySeqHash(array)
+ override def equals(that: Any) = that match {
+ case that: ofFloat => Arrays.equals(array, that.array)
+ case _ => super.equals(that)
+ }
+ override def iterator: Iterator[Float] = new ArrayOps.ArrayIterator[Float](array)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Float, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParDoubleStepper(new WidenedFloatArrayStepper(array, 0, array.length))
+ else new WidenedFloatArrayStepper(array, 0, array.length)
+ ).asInstanceOf[S with EfficientSplit]
+ }
+
+ @SerialVersionUID(3L)
+ final class ofDouble(val array: Array[Double]) extends ArraySeq[Double] {
+ // Type erases to `ManifestFactory.DoubleManifest`, but can't annotate that because it's not accessible
+ def elemTag: ClassTag.Double.type = ClassTag.Double
+ def length: Int = array.length
+ def apply(index: Int): Double = array(index)
+ def update(index: Int, elem: Double): Unit = { array(index) = elem }
+ override def hashCode = MurmurHash3.arraySeqHash(array)
+ override def equals(that: Any) = that match {
+ case that: ofDouble => Arrays.equals(array, that.array)
+ case _ => super.equals(that)
+ }
+ override def iterator: Iterator[Double] = new ArrayOps.ArrayIterator[Double](array)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Double, S]): S with EfficientSplit = (
+ if(shape.shape == StepperShape.ReferenceShape)
+ AnyStepper.ofParDoubleStepper(new DoubleArrayStepper(array, 0, array.length))
+ else new DoubleArrayStepper(array, 0, array.length)
+ ).asInstanceOf[S with EfficientSplit]
+ }
+
+ @SerialVersionUID(3L)
+ final class ofBoolean(val array: Array[Boolean]) extends ArraySeq[Boolean] {
+ // Type erases to `ManifestFactory.BooleanManifest`, but can't annotate that because it's not accessible
+ def elemTag: ClassTag.Boolean.type = ClassTag.Boolean
+ def length: Int = array.length
+ def apply(index: Int): Boolean = array(index)
+ def update(index: Int, elem: Boolean): Unit = { array(index) = elem }
+ override def hashCode = MurmurHash3.arraySeqHash(array)
+ override def equals(that: Any) = that match {
+ case that: ofBoolean => Arrays.equals(array, that.array)
+ case _ => super.equals(that)
+ }
+ override def iterator: Iterator[Boolean] = new ArrayOps.ArrayIterator[Boolean](array)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Boolean, S]): S with EfficientSplit =
+ new BoxedBooleanArrayStepper(array, 0, array.length).asInstanceOf[S with EfficientSplit]
+ }
+
+ @SerialVersionUID(3L)
+ final class ofUnit(val array: Array[Unit]) extends ArraySeq[Unit] {
+ // Type erases to `ManifestFactory.UnitManifest`, but can't annotate that because it's not accessible
+ def elemTag: ClassTag.Unit.type = ClassTag.Unit
+ def length: Int = array.length
+ def apply(index: Int): Unit = array(index)
+ def update(index: Int, elem: Unit): Unit = { array(index) = elem }
+ override def hashCode = MurmurHash3.arraySeqHash(array)
+ override def equals(that: Any) = that match {
+ case that: ofUnit => array.length == that.array.length
+ case _ => super.equals(that)
+ }
+ override def iterator: Iterator[Unit] = new ArrayOps.ArrayIterator[Unit](array)
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[Unit, S]): S with EfficientSplit =
+ new ObjectArrayStepper[AnyRef](array.asInstanceOf[Array[AnyRef]], 0, array.length).asInstanceOf[S with EfficientSplit]
+ }
+}
diff --git a/library/src/scala/collection/mutable/BitSet.scala b/library/src/scala/collection/mutable/BitSet.scala
new file mode 100644
index 000000000000..ba77d7161a0b
--- /dev/null
+++ b/library/src/scala/collection/mutable/BitSet.scala
@@ -0,0 +1,392 @@
+/*
+ * 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 collection
+package mutable
+
+import scala.collection.immutable.Range
+import BitSetOps.{LogWL, MaxSize}
+import scala.annotation.implicitNotFound
+
+/**
+ * A class for mutable bitsets.
+ *
+ * $bitsetinfo
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-mutable-collection-classes.html#mutable-bitsets "Scala's Collection Library overview"]]
+ * section on `Mutable Bitsets` for more information.
+ *
+ * @define Coll `BitSet`
+ * @define coll bitset
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+class BitSet(protected[collection] final var elems: Array[Long])
+ extends AbstractSet[Int]
+ with SortedSet[Int]
+ with SortedSetOps[Int, SortedSet, BitSet]
+ with StrictOptimizedIterableOps[Int, Set, BitSet]
+ with StrictOptimizedSortedSetOps[Int, SortedSet, BitSet]
+ with collection.BitSet
+ with collection.BitSetOps[BitSet]
+ with Serializable {
+
+ def this(initSize: Int) = this(new Array[Long](math.max((initSize + 63) >> 6, 1)))
+
+ def this() = this(0)
+
+ override protected def fromSpecific(coll: IterableOnce[Int]): BitSet = bitSetFactory.fromSpecific(coll)
+ override protected def newSpecificBuilder: Builder[Int, BitSet] = bitSetFactory.newBuilder
+ override def empty: BitSet = bitSetFactory.empty
+
+ def bitSetFactory: BitSet.type = BitSet
+
+ override def unsorted: Set[Int] = this
+
+ protected[collection] final def nwords: Int = elems.length
+
+ protected[collection] final def word(idx: Int): Long =
+ if (idx < nwords) elems(idx) else 0L
+
+ protected[collection] def fromBitMaskNoCopy(elems: Array[Long]): BitSet =
+ if (elems.length == 0) empty
+ else new BitSet(elems)
+
+ def addOne(elem: Int): this.type = {
+ require(elem >= 0)
+ if (!contains(elem)) {
+ val idx = elem >> LogWL
+ updateWord(idx, word(idx) | (1L << elem))
+ }
+ this
+ }
+
+ def subtractOne(elem: Int): this.type = {
+ require(elem >= 0)
+ if (contains(elem)) {
+ val idx = elem >> LogWL
+ updateWord(idx, word(idx) & ~(1L << elem))
+ }
+ this
+ }
+
+ def clear(): Unit = {
+ elems = new Array[Long](elems.length)
+ }
+
+ protected final def updateWord(idx: Int, w: Long): Unit = {
+ ensureCapacity(idx)
+ elems(idx) = w
+ }
+
+ protected final def ensureCapacity(idx: Int): Unit = {
+ require(idx < MaxSize)
+ if (idx >= nwords) {
+ var newlen = nwords
+ while (idx >= newlen) newlen = math.min(newlen * 2, MaxSize)
+ val elems1 = new Array[Long](newlen)
+ Array.copy(elems, 0, elems1, 0, nwords)
+ elems = elems1
+ }
+ }
+
+ def unconstrained: collection.Set[Int] = this
+
+ /** Updates this bitset to the union with another bitset by performing a bitwise "or".
+ *
+ * @param other the bitset to form the union with.
+ * @return the bitset itself.
+ */
+ def |= (other: collection.BitSet): this.type = {
+ ensureCapacity(other.nwords - 1)
+ var i = 0
+ val othernwords = other.nwords
+ while (i < othernwords) {
+ elems(i) = elems(i) | other.word(i)
+ i += 1
+ }
+ this
+ }
+ /** Updates this bitset to the intersection with another bitset by performing a bitwise "and".
+ *
+ * @param other the bitset to form the intersection with.
+ * @return the bitset itself.
+ */
+ def &= (other: collection.BitSet): this.type = {
+ // Different from other operations: no need to ensure capacity because
+ // anything beyond the capacity is 0. Since we use other.word which is 0
+ // off the end, we also don't need to make sure we stay in bounds there.
+ var i = 0
+ val thisnwords = nwords
+ while (i < thisnwords) {
+ elems(i) = elems(i) & other.word(i)
+ i += 1
+ }
+ this
+ }
+ /** Updates this bitset to the symmetric difference with another bitset by performing a bitwise "xor".
+ *
+ * @param other the bitset to form the symmetric difference with.
+ * @return the bitset itself.
+ */
+ def ^= (other: collection.BitSet): this.type = {
+ ensureCapacity(other.nwords - 1)
+ var i = 0
+ val othernwords = other.nwords
+ while (i < othernwords) {
+
+ elems(i) = elems(i) ^ other.word(i)
+ i += 1
+ }
+ this
+ }
+ /** Updates this bitset to the difference with another bitset by performing a bitwise "and-not".
+ *
+ * @param other the bitset to form the difference with.
+ * @return the bitset itself.
+ */
+ def &~= (other: collection.BitSet): this.type = {
+ var i = 0
+ val max = Math.min(nwords, other.nwords)
+ while (i < max) {
+ elems(i) = elems(i) & ~other.word(i)
+ i += 1
+ }
+ this
+ }
+
+ override def clone(): BitSet = new BitSet(java.util.Arrays.copyOf(elems, elems.length))
+
+ def toImmutable: immutable.BitSet = immutable.BitSet.fromBitMask(elems)
+
+ override def map(f: Int => Int): BitSet = strictOptimizedMap(newSpecificBuilder, f)
+ override def map[B](f: Int => B)(implicit @implicitNotFound(collection.BitSet.ordMsg) ev: Ordering[B]): SortedSet[B] =
+ super[StrictOptimizedSortedSetOps].map(f)
+
+ override def flatMap(f: Int => IterableOnce[Int]): BitSet = strictOptimizedFlatMap(newSpecificBuilder, f)
+ override def flatMap[B](f: Int => IterableOnce[B])(implicit @implicitNotFound(collection.BitSet.ordMsg) ev: Ordering[B]): SortedSet[B] =
+ super[StrictOptimizedSortedSetOps].flatMap(f)
+
+ override def collect(pf: PartialFunction[Int, Int]): BitSet = strictOptimizedCollect(newSpecificBuilder, pf)
+ override def collect[B](pf: scala.PartialFunction[Int, B])(implicit @implicitNotFound(collection.BitSet.ordMsg) ev: Ordering[B]): SortedSet[B] =
+ super[StrictOptimizedSortedSetOps].collect(pf)
+
+ // necessary for disambiguation
+ override def zip[B](that: IterableOnce[B])(implicit @implicitNotFound(collection.BitSet.zipOrdMsg) ev: Ordering[(Int, B)]): SortedSet[(Int, B)] =
+ super.zip(that)
+
+ override def addAll(xs: IterableOnce[Int]): this.type = xs match {
+ case bs: collection.BitSet =>
+ this |= bs
+ case range: Range =>
+ if (range.nonEmpty) {
+ val start = range.min
+ if (start >= 0) {
+ val end = range.max
+ val endIdx = end >> LogWL
+ ensureCapacity(endIdx)
+
+ if (range.step == 1 || range.step == -1) {
+ val startIdx = start >> LogWL
+ val wordStart = startIdx * BitSetOps.WordLength
+ val wordMask = -1L << (start - wordStart)
+
+ if (endIdx > startIdx) {
+ elems(startIdx) |= wordMask
+ java.util.Arrays.fill(elems, startIdx + 1, endIdx, -1L)
+ elems(endIdx) |= -1L >>> (BitSetOps.WordLength - (end - endIdx * BitSetOps.WordLength) - 1)
+ } else elems(endIdx) |= (wordMask & (-1L >>> (BitSetOps.WordLength - (end - wordStart) - 1)))
+ } else super.addAll(range)
+ } else super.addAll(range)
+ }
+ this
+
+ case sorted: collection.SortedSet[Int] =>
+ // if `sorted` is using the regular Int ordering, ensure capacity for the largest
+ // element up front to avoid multiple resizing allocations
+ if (sorted.nonEmpty) {
+ val ord = sorted.ordering
+ if (ord eq Ordering.Int) {
+ ensureCapacity(sorted.lastKey >> LogWL)
+ } else if (ord eq Ordering.Int.reverse) {
+ ensureCapacity(sorted.firstKey >> LogWL)
+ }
+ val iter = sorted.iterator
+ while (iter.hasNext) {
+ addOne(iter.next())
+ }
+ }
+
+ this
+
+ case other =>
+ super.addAll(other)
+ }
+
+ override def subsetOf(that: collection.Set[Int]): Boolean = that match {
+ case bs: collection.BitSet =>
+ val thisnwords = this.nwords
+ val bsnwords = bs.nwords
+ val minWords = Math.min(thisnwords, bsnwords)
+
+ // if any bits are set to `1` in words out of range of `bs`, then this is not a subset. Start there
+ var i = bsnwords
+ while (i < thisnwords) {
+ if (word(i) != 0L) return false
+ i += 1
+ }
+
+ // the higher range of `this` is all `0`s, fall back to lower range
+ var j = 0
+ while (j < minWords) {
+ if ((word(j) & ~bs.word(j)) != 0L) return false
+ j += 1
+ }
+
+ true
+ case other =>
+ super.subsetOf(other)
+ }
+
+ override def subtractAll(xs: IterableOnce[Int]): this.type = xs match {
+ case bs: collection.BitSet => this &~= bs
+ case other => super.subtractAll(other)
+ }
+
+ protected[this] def writeReplace(): AnyRef = new BitSet.SerializationProxy(this)
+
+ override def diff(that: collection.Set[Int]): BitSet = that match {
+ case bs: collection.BitSet =>
+ /*
+ * Algorithm:
+ *
+ * We iterate, word-by-word, backwards from the shortest of the two bitsets (this, or bs) i.e. the one with
+ * the fewer words.
+ *
+ * Array Shrinking:
+ * If `this` is not longer than `bs`, then since we must iterate through the full array of words,
+ * we can track the new highest index word which is non-zero, at little additional cost. At the end, the new
+ * Array[Long] allocated for the returned BitSet will only be of size `maxNonZeroIndex + 1`
+ */
+
+ val bsnwords = bs.nwords
+ val thisnwords = nwords
+ if (bsnwords >= thisnwords) {
+ // here, we may have opportunity to shrink the size of the array
+ // so, track the highest index which is non-zero. That ( + 1 ) will be our new array length
+ var i = thisnwords - 1
+ var currentWord = 0L
+
+ while (i >= 0 && currentWord == 0L) {
+ val oldWord = word(i)
+ currentWord = oldWord & ~bs.word(i)
+ i -= 1
+ }
+
+ if (i < 0) {
+ fromBitMaskNoCopy(Array(currentWord))
+ } else {
+ val minimumNonZeroIndex: Int = i + 1
+ val newArray = elems.take(minimumNonZeroIndex + 1)
+ newArray(i + 1) = currentWord
+ while (i >= 0) {
+ newArray(i) = word(i) & ~bs.word(i)
+ i -= 1
+ }
+ fromBitMaskNoCopy(newArray)
+ }
+ } else {
+ // here, there is no opportunity to shrink the array size, no use in tracking highest non-zero index
+ val newElems = elems.clone()
+ var i = bsnwords - 1
+ while (i >= 0) {
+ newElems(i) = word(i) & ~bs.word(i)
+ i -= 1
+ }
+ fromBitMaskNoCopy(newElems)
+ }
+ case _ => super.diff(that)
+ }
+
+ override def filterImpl(pred: Int => Boolean, isFlipped: Boolean): BitSet = {
+ // We filter the BitSet from highest to lowest, so we can determine exactly the highest non-zero word
+ // index which lets us avoid:
+ // * over-allocating -- the resulting array will be exactly the right size
+ // * multiple resizing allocations -- the array is allocated one time, not log(n) times.
+ var i = nwords - 1
+ var newArray: Array[Long] = null
+ while (i >= 0) {
+ val w = BitSetOps.computeWordForFilter(pred, isFlipped, word(i), i)
+ if (w != 0L) {
+ if (newArray eq null) {
+ newArray = new Array(i + 1)
+ }
+ newArray(i) = w
+ }
+ i -= 1
+ }
+ if (newArray eq null) {
+ empty
+ } else {
+ fromBitMaskNoCopy(newArray)
+ }
+ }
+
+ override def filterInPlace(p: Int => Boolean): this.type = {
+ val thisnwords = nwords
+ var i = 0
+ while (i < thisnwords) {
+ elems(i) = BitSetOps.computeWordForFilter(p, isFlipped = false, elems(i), i)
+ i += 1
+ }
+ this
+ }
+
+ override def toBitMask: Array[Long] = elems.clone()
+}
+
+@SerialVersionUID(3L)
+object BitSet extends SpecificIterableFactory[Int, BitSet] {
+
+ def fromSpecific(it: scala.collection.IterableOnce[Int]): BitSet = Growable.from(empty, it)
+
+ def empty: BitSet = new BitSet()
+
+ def newBuilder: Builder[Int, BitSet] = new GrowableBuilder(empty)
+
+ /** A bitset containing all the bits in an array */
+ def fromBitMask(elems: Array[Long]): BitSet = {
+ val len = elems.length
+ if (len == 0) empty
+ else {
+ val a = java.util.Arrays.copyOf(elems, len)
+ new BitSet(a)
+ }
+ }
+
+ /** A bitset containing all the bits in an array, wrapping the existing
+ * array without copying.
+ */
+ def fromBitMaskNoCopy(elems: Array[Long]): BitSet = {
+ val len = elems.length
+ if (len == 0) empty
+ else new BitSet(elems)
+ }
+
+ @SerialVersionUID(3L)
+ private final class SerializationProxy(coll: BitSet) extends scala.collection.BitSet.SerializationProxy(coll) {
+ protected[this] def readResolve(): Any = BitSet.fromBitMaskNoCopy(elems)
+ }
+}
diff --git a/library/src/scala/collection/mutable/Buffer.scala b/library/src/scala/collection/mutable/Buffer.scala
new file mode 100644
index 000000000000..1a0151273894
--- /dev/null
+++ b/library/src/scala/collection/mutable/Buffer.scala
@@ -0,0 +1,314 @@
+/*
+ * 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 mutable
+
+import scala.annotation.nowarn
+
+
+/** A `Buffer` is a growable and shrinkable `Seq`. */
+trait Buffer[A]
+ extends Seq[A]
+ with SeqOps[A, Buffer, Buffer[A]]
+ with Growable[A]
+ with Shrinkable[A]
+ with IterableFactoryDefaults[A, Buffer] {
+
+ override def iterableFactory: SeqFactory[Buffer] = Buffer
+
+ override def knownSize: Int = super[Seq].knownSize
+
+ //TODO Prepend is a logical choice for a readable name of `+=:` but it conflicts with the renaming of `append` to `add`
+ /** Prepends a single element at the front of this $coll.
+ *
+ * @param elem the element to $add.
+ * @return the $coll itself
+ */
+ def prepend(elem: A): this.type
+
+ /** Appends the given elements to this buffer.
+ *
+ * @param elem the element to append.
+ * @return this $coll
+ */
+ @`inline` final def append(elem: A): this.type = addOne(elem)
+
+ @deprecated("Use appendAll instead", "2.13.0")
+ @`inline` final def append(elems: A*): this.type = addAll(elems)
+
+ /** Appends the elements contained in a iterable object to this buffer.
+ * @param elems the iterable object containing the elements to append.
+ * @return this $coll
+ */
+ @`inline` final def appendAll(@deprecatedName("xs") elems: IterableOnce[A]): this.type = addAll(elems)
+
+ /** Alias for `prepend` */
+ @`inline` final def +=: (elem: A): this.type = prepend(elem)
+
+ /** Prepends the elements contained in a iterable object to this buffer.
+ * @param elems the iterable object containing the elements to append.
+ * @return this $coll
+ */
+ def prependAll(elems: IterableOnce[A]): this.type = { insertAll(0, elems); this }
+
+ @deprecated("Use prependAll instead", "2.13.0")
+ @`inline` final def prepend(elems: A*): this.type = prependAll(elems)
+
+ /** Alias for `prependAll` */
+ @inline final def ++=:(elems: IterableOnce[A]): this.type = prependAll(elems)
+
+ /** Inserts a new element at a given index into this buffer.
+ *
+ * @param idx the index where the new elements is inserted.
+ * @param elem the element to insert.
+ * @throws IndexOutOfBoundsException if the index `idx` is not in the valid range
+ * `0 <= idx <= length`.
+ */
+ @throws[IndexOutOfBoundsException]
+ def insert(idx: Int, elem: A): Unit
+
+ /** Inserts new elements at the index `idx`. Opposed to method
+ * `update`, this method will not replace an element with a new
+ * one. Instead, it will insert a new element at index `idx`.
+ *
+ * @param idx the index where a new element will be inserted.
+ * @param elems the iterable object providing all elements to insert.
+ * @throws IndexOutOfBoundsException if `idx` is out of bounds.
+ */
+ @throws[IndexOutOfBoundsException]
+ def insertAll(idx: Int, elems: IterableOnce[A]): Unit
+
+ /** Removes the element at a given index position.
+ *
+ * @param idx the index which refers to the element to delete.
+ * @return the element that was formerly at index `idx`.
+ */
+ @throws[IndexOutOfBoundsException]
+ def remove(idx: Int): A
+
+ /** Removes the element on a given index position. It takes time linear in
+ * the buffer size.
+ *
+ * @param idx the index which refers to the first element to remove.
+ * @param count the number of elements to remove.
+ * @throws IndexOutOfBoundsException if the index `idx` is not in the valid range
+ * `0 <= idx <= length - count` (with `count > 0`).
+ * @throws IllegalArgumentException if `count < 0`.
+ */
+ @throws[IndexOutOfBoundsException]
+ @throws[IllegalArgumentException]
+ def remove(idx: Int, count: Int): Unit
+
+ /** Removes a single element from this buffer, at its first occurrence.
+ * If the buffer does not contain that element, it is unchanged.
+ *
+ * @param x the element to remove.
+ * @return the buffer itself
+ */
+ def subtractOne (x: A): this.type = {
+ val i = indexOf(x)
+ if (i != -1) remove(i)
+ this
+ }
+
+ /** Removes the first ''n'' elements of this buffer.
+ *
+ * @param n the number of elements to remove from the beginning
+ * of this buffer.
+ */
+ @deprecated("use dropInPlace instead", since = "2.13.4")
+ def trimStart(n: Int): Unit = dropInPlace(n)
+
+ /** Removes the last ''n'' elements of this buffer.
+ *
+ * @param n the number of elements to remove from the end
+ * of this buffer.
+ */
+ @deprecated("use dropRightInPlace instead", since = "2.13.4")
+ def trimEnd(n: Int): Unit = dropRightInPlace(n)
+
+ /** Replaces a slice of elements in this $coll by another sequence of elements.
+ *
+ * Patching at negative indices is the same as patching starting at 0.
+ * Patching at indices at or larger than the length of the original $coll appends the patch to the end.
+ * If the `replaced` count would exceed the available elements, the difference in excess is ignored.
+ *
+ * @param from the index of the first replaced element
+ * @param patch the replacement sequence
+ * @param replaced the number of elements to drop in the original $coll
+ * @return this $coll
+ */
+ def patchInPlace(from: Int, patch: scala.collection.IterableOnce[A], replaced: Int): this.type
+
+ // +=, ++=, clear inherited from Growable
+ // Per remark of @ichoran, we should preferably not have these:
+ //
+ // def +=:(elem: A): this.type = { insert(0, elem); this }
+ // def +=:(elem1: A, elem2: A, elems: A*): this.type = elem1 +=: elem2 +=: elems ++=: this
+ // def ++=:(elems: IterableOnce[A]): this.type = { insertAll(0, elems); this }
+
+ /** Removes the first `n` elements from this $coll.
+ *
+ * @param n the number of elements to remove
+ * @return this $coll
+ *
+ */
+ def dropInPlace(n: Int): this.type = { remove(0, normalized(n)); this }
+
+ /** Removes the last `n` elements from this $coll.
+ *
+ * @param n the number of elements to remove
+ * @return this $coll
+ *
+ */
+ def dropRightInPlace(n: Int): this.type = {
+ val norm = normalized(n)
+ remove(length - norm, norm)
+ this
+ }
+
+ /** Retains the first `n` elements from this $coll and removes the rest.
+ *
+ * @param n the number of elements to retain
+ * @return this $coll
+ *
+ */
+ def takeInPlace(n: Int): this.type = {
+ val norm = normalized(n)
+ remove(norm, length - norm)
+ this
+ }
+
+ /** Retains the last `n` elements from this $coll and removes the rest.
+ *
+ * @param n the number of elements to retain
+ * @return this $coll
+ *
+ */
+ def takeRightInPlace(n: Int): this.type = { remove(0, length - normalized(n)); this }
+
+ /** Retains the specified slice from this $coll and removes the rest.
+ *
+ * @param start the lowest index to include
+ * @param end the lowest index to exclude
+ * @return this $coll
+ *
+ */
+ def sliceInPlace(start: Int, end: Int): this.type = takeInPlace(end).dropInPlace(start)
+
+ private def normalized(n: Int): Int = math.min(math.max(n, 0), length)
+
+ /** Drops the longest prefix of elements that satisfy a predicate.
+ *
+ * @param p The predicate used to test elements.
+ * @return this $coll
+ * @see [[dropWhile]]
+ */
+ def dropWhileInPlace(p: A => Boolean): this.type = {
+ val idx = indexWhere(!p(_))
+ if (idx < 0) { clear(); this } else dropInPlace(idx)
+ }
+
+ /** Retains the longest prefix of elements that satisfy a predicate.
+ *
+ * @param p The predicate used to test elements.
+ * @return this $coll
+ * @see [[takeWhile]]
+ */
+ def takeWhileInPlace(p: A => Boolean): this.type = {
+ val idx = indexWhere(!p(_))
+ if (idx < 0) this else takeInPlace(idx)
+ }
+
+ /** Append the given element to this $coll until a target length is reached.
+ *
+ * @param len the target length
+ * @param elem the padding value
+ * @return this $coll
+ */
+ def padToInPlace(len: Int, elem: A): this.type = {
+ while (length < len) +=(elem)
+ this
+ }
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix = "Buffer"
+}
+
+trait IndexedBuffer[A] extends IndexedSeq[A]
+ with IndexedSeqOps[A, IndexedBuffer, IndexedBuffer[A]]
+ with Buffer[A]
+ with IterableFactoryDefaults[A, IndexedBuffer] {
+
+ override def iterableFactory: SeqFactory[IndexedBuffer] = IndexedBuffer
+
+ /** Replace the contents of this $coll with the flatmapped result.
+ *
+ * @param f the mapping function
+ * @return this $coll
+ */
+ def flatMapInPlace(f: A => IterableOnce[A]): this.type = {
+ // There's scope for a better implementation which copies elements in place.
+ var i = 0
+ val s = size
+ val newElems = new Array[IterableOnce[A]](s)
+ while (i < s) { newElems(i) = f(this(i)); i += 1 }
+ clear()
+ i = 0
+ while (i < s) { ++=(newElems(i)); i += 1 }
+ this
+ }
+
+ /** Replace the contents of this $coll with the filtered result.
+ *
+ * @param f the filtering function
+ * @return this $coll
+ */
+ def filterInPlace(p: A => Boolean): this.type = {
+ var i, j = 0
+ while (i < size) {
+ if (p(apply(i))) {
+ if (i != j) {
+ this(j) = this(i)
+ }
+ j += 1
+ }
+ i += 1
+ }
+
+ if (i == j) this else takeInPlace(j)
+ }
+
+ def patchInPlace(from: Int, patch: scala.collection.IterableOnce[A], replaced: Int): this.type = {
+ val replaced0 = math.min(math.max(replaced, 0), length)
+ val i = math.min(math.max(from, 0), length)
+ var j = 0
+ val iter = patch.iterator
+ while (iter.hasNext && j < replaced0 && i + j < length) {
+ update(i + j, iter.next())
+ j += 1
+ }
+ if (iter.hasNext) insertAll(i + j, iter)
+ else if (j < replaced0) remove(i + j, math.min(replaced0 - j, length - i - j))
+ this
+ }
+}
+
+@SerialVersionUID(3L)
+object Buffer extends SeqFactory.Delegate[Buffer](ArrayBuffer)
+
+@SerialVersionUID(3L)
+object IndexedBuffer extends SeqFactory.Delegate[IndexedBuffer](ArrayBuffer)
+
+/** Explicit instantiation of the `Buffer` trait to reduce class file size in subclasses. */
+abstract class AbstractBuffer[A] extends AbstractSeq[A] with Buffer[A]
diff --git a/library/src/scala/collection/mutable/Builder.scala b/library/src/scala/collection/mutable/Builder.scala
new file mode 100644
index 000000000000..e59fc8639104
--- /dev/null
+++ b/library/src/scala/collection/mutable/Builder.scala
@@ -0,0 +1,103 @@
+/*
+ * 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.mutable
+
+/** Base trait for collection builders.
+ *
+ * After calling `result()` the behavior of a Builder (which is not also a [[scala.collection.mutable.ReusableBuilder]])
+ * is undefined. No further methods should be called. It is common for mutable collections to be their own non-reusable
+ * Builder, in which case `result()` simply returns `this`.
+ *
+ * @see [[scala.collection.mutable.ReusableBuilder]] for Builders which can be reused after calling `result()`
+ */
+trait Builder[-A, +To] extends Growable[A] { self =>
+
+ /** Clears the contents of this builder.
+ * After execution of this method the builder will contain no elements.
+ */
+ def clear(): Unit
+
+ /** Result collection consisting of all elements appended so far. */
+ def result(): To
+
+ /** Gives a hint how many elements are expected to be added in total
+ * by the time `result` is called.
+ *
+ * Some builder classes will optimize their representation based on the hint.
+ * However, builder implementations are required to work correctly even if the hint is
+ * wrong, e.g., a different number of elements is added, or the hint is out of range.
+ *
+ * The default implementation simply ignores the hint.
+ *
+ * @param size the hint how many elements will be added.
+ */
+ def sizeHint(size: Int): Unit = ()
+
+ /** Gives a hint that the `result` of this builder is expected
+ * to have the same size as the given collection, plus some delta.
+ *
+ * This method provides a hint only if the collection has a known size,
+ * as specified by the following pseudocode:
+ *
+ * {{{
+ * if (coll.knownSize != -1)
+ * if (coll.knownSize + delta <= 0) sizeHint(0)
+ * else sizeHint(coll.knownSize + delta)
+ * }}}
+ *
+ * If the delta is negative and the result size is known to be negative,
+ * then the size hint is issued at zero.
+ *
+ * Some builder classes will optimize their representation based on the hint.
+ * However, builder implementations are required to work correctly even if the hint is
+ * wrong, i.e., if a different number of elements is added.
+ *
+ * @param coll the collection which serves as a hint for the result's size.
+ * @param delta a correction to add to the `coll.size` to produce the size hint (zero if omitted).
+ */
+ final def sizeHint(coll: scala.collection.IterableOnce[_], delta: Int = 0): Unit =
+ coll.knownSize match {
+ case -1 =>
+ case sz => sizeHint(0 max sz + delta)
+ }
+
+ /** Gives a hint how many elements are expected to be added
+ * when the next `result` is called, together with an upper bound
+ * given by the size of some other collection. Some builder classes
+ * will optimize their representation based on the hint. However,
+ * builder implementations are still required to work correctly even if the hint is
+ * wrong, i.e. a different number of elements is added.
+ *
+ * @param size the hint how many elements will be added.
+ * @param boundingColl the bounding collection. If it is
+ * an IndexedSeqLike, then sizes larger
+ * than collection's size are reduced.
+ */
+ // should probably be `boundingColl: IterableOnce[_]`, but binary compatibility
+ final def sizeHintBounded(size: Int, boundingColl: scala.collection.Iterable[_]): Unit = {
+ val s = boundingColl.knownSize
+ if (s != -1) {
+ sizeHint(scala.math.min(s, size))
+ }
+ }
+
+ /** A builder resulting from this builder by mapping the result using `f`. */
+ def mapResult[NewTo](f: To => NewTo): Builder[A, NewTo] = new Builder[A, NewTo] {
+ def addOne(x: A): this.type = { self += x; this }
+ def clear(): Unit = self.clear()
+ override def addAll(xs: IterableOnce[A]): this.type = { self ++= xs; this }
+ override def sizeHint(size: Int): Unit = self.sizeHint(size)
+ def result(): NewTo = f(self.result())
+ override def knownSize: Int = self.knownSize
+ }
+}
diff --git a/library/src/scala/collection/mutable/CheckedIndexedSeqView.scala b/library/src/scala/collection/mutable/CheckedIndexedSeqView.scala
new file mode 100644
index 000000000000..6953dd0ed660
--- /dev/null
+++ b/library/src/scala/collection/mutable/CheckedIndexedSeqView.scala
@@ -0,0 +1,117 @@
+/*
+ * 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 collection
+package mutable
+
+private[mutable] trait CheckedIndexedSeqView[+A] extends IndexedSeqView[A] {
+ protected val mutationCount: () => Int
+
+ override def iterator: Iterator[A] = new CheckedIndexedSeqView.CheckedIterator(this, mutationCount())
+ override def reverseIterator: Iterator[A] = new CheckedIndexedSeqView.CheckedReverseIterator(this, mutationCount())
+
+ override def appended[B >: A](elem: B): IndexedSeqView[B] = new CheckedIndexedSeqView.Appended(this, elem)(mutationCount)
+ override def prepended[B >: A](elem: B): IndexedSeqView[B] = new CheckedIndexedSeqView.Prepended(elem, this)(mutationCount)
+ override def take(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.Take(this, n)(mutationCount)
+ override def takeRight(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.TakeRight(this, n)(mutationCount)
+ override def drop(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.Drop(this, n)(mutationCount)
+ override def dropRight(n: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.DropRight(this, n)(mutationCount)
+ override def map[B](f: A => B): IndexedSeqView[B] = new CheckedIndexedSeqView.Map(this, f)(mutationCount)
+ override def reverse: IndexedSeqView[A] = new CheckedIndexedSeqView.Reverse(this)(mutationCount)
+ override def slice(from: Int, until: Int): IndexedSeqView[A] = new CheckedIndexedSeqView.Slice(this, from, until)(mutationCount)
+ override def tapEach[U](f: A => U): IndexedSeqView[A] = new CheckedIndexedSeqView.Map(this, { (a: A) => f(a); a})(mutationCount)
+
+ override def concat[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new CheckedIndexedSeqView.Concat(this, suffix)(mutationCount)
+ override def appendedAll[B >: A](suffix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new CheckedIndexedSeqView.Concat(this, suffix)(mutationCount)
+ override def prependedAll[B >: A](prefix: IndexedSeqView.SomeIndexedSeqOps[B]): IndexedSeqView[B] = new CheckedIndexedSeqView.Concat(prefix, this)(mutationCount)
+}
+
+private[mutable] object CheckedIndexedSeqView {
+ import IndexedSeqView.SomeIndexedSeqOps
+
+ @SerialVersionUID(3L)
+ private[mutable] class CheckedIterator[A](self: IndexedSeqView[A], mutationCount: => Int)
+ extends IndexedSeqView.IndexedSeqViewIterator[A](self) {
+ private[this] val expectedCount = mutationCount
+ override def hasNext: Boolean = {
+ MutationTracker.checkMutationsForIteration(expectedCount, mutationCount)
+ super.hasNext
+ }
+ }
+
+ @SerialVersionUID(3L)
+ private[mutable] class CheckedReverseIterator[A](self: IndexedSeqView[A], mutationCount: => Int)
+ extends IndexedSeqView.IndexedSeqViewReverseIterator[A](self) {
+ private[this] val expectedCount = mutationCount
+ override def hasNext: Boolean = {
+ MutationTracker.checkMutationsForIteration(expectedCount, mutationCount)
+ super.hasNext
+ }
+ }
+
+ @SerialVersionUID(3L)
+ class Id[+A](underlying: SomeIndexedSeqOps[A])(protected val mutationCount: () => Int)
+ extends IndexedSeqView.Id(underlying) with CheckedIndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class Appended[+A](underlying: SomeIndexedSeqOps[A], elem: A)(protected val mutationCount: () => Int)
+ extends IndexedSeqView.Appended(underlying, elem) with CheckedIndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class Prepended[+A](elem: A, underlying: SomeIndexedSeqOps[A])(protected val mutationCount: () => Int)
+ extends IndexedSeqView.Prepended(elem, underlying) with CheckedIndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class Concat[A](prefix: SomeIndexedSeqOps[A], suffix: SomeIndexedSeqOps[A])(protected val mutationCount: () => Int)
+ extends IndexedSeqView.Concat[A](prefix, suffix) with CheckedIndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class Take[A](underlying: SomeIndexedSeqOps[A], n: Int)(protected val mutationCount: () => Int)
+ extends IndexedSeqView.Take(underlying, n) with CheckedIndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class TakeRight[A](underlying: SomeIndexedSeqOps[A], n: Int)(protected val mutationCount: () => Int)
+ extends IndexedSeqView.TakeRight(underlying, n) with CheckedIndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class Drop[A](underlying: SomeIndexedSeqOps[A], n: Int)(protected val mutationCount: () => Int)
+ extends IndexedSeqView.Drop[A](underlying, n) with CheckedIndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class DropRight[A](underlying: SomeIndexedSeqOps[A], n: Int)(protected val mutationCount: () => Int)
+ extends IndexedSeqView.DropRight[A](underlying, n) with CheckedIndexedSeqView[A]
+
+ @SerialVersionUID(3L)
+ class Map[A, B](underlying: SomeIndexedSeqOps[A], f: A => B)(protected val mutationCount: () => Int)
+ extends IndexedSeqView.Map(underlying, f) with CheckedIndexedSeqView[B]
+
+ @SerialVersionUID(3L)
+ class Reverse[A](underlying: SomeIndexedSeqOps[A])(protected val mutationCount: () => Int)
+ extends IndexedSeqView.Reverse[A](underlying) with CheckedIndexedSeqView[A] {
+ override def reverse: IndexedSeqView[A] = underlying match {
+ case x: IndexedSeqView[A] => x
+ case _ => super.reverse
+ }
+ }
+
+ @SerialVersionUID(3L)
+ class Slice[A](underlying: SomeIndexedSeqOps[A], from: Int, until: Int)(protected val mutationCount: () => Int)
+ extends AbstractIndexedSeqView[A] with CheckedIndexedSeqView[A] {
+ protected val lo = from max 0
+ protected val hi = (until max 0) min underlying.length
+ protected val len = (hi - lo) max 0
+ @throws[IndexOutOfBoundsException]
+ def apply(i: Int): A = underlying(lo + i)
+ def length: Int = len
+ }
+}
diff --git a/library/src/scala/collection/mutable/Cloneable.scala b/library/src/scala/collection/mutable/Cloneable.scala
new file mode 100644
index 000000000000..5c11faea155e
--- /dev/null
+++ b/library/src/scala/collection/mutable/Cloneable.scala
@@ -0,0 +1,22 @@
+/*
+ * 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.mutable
+
+
+/** A trait for cloneable collections.
+ *
+ * @tparam C Type of the collection, covariant and with reference types as upperbound.
+ */
+trait Cloneable[+C <: AnyRef] extends scala.Cloneable {
+ override def clone(): C = super.clone().asInstanceOf[C]
+}
diff --git a/library/src/scala/collection/mutable/CollisionProofHashMap.scala b/library/src/scala/collection/mutable/CollisionProofHashMap.scala
new file mode 100644
index 000000000000..f56e679df2d2
--- /dev/null
+++ b/library/src/scala/collection/mutable/CollisionProofHashMap.scala
@@ -0,0 +1,887 @@
+/*
+ * 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 mutable
+
+import scala.{unchecked => uc}
+import scala.annotation.{implicitNotFound, tailrec, unused}
+import scala.annotation.unchecked.uncheckedVariance
+import scala.collection.generic.DefaultSerializationProxy
+import scala.runtime.Statics
+
+/** This class implements mutable maps using a hashtable with red-black trees in the buckets for good
+ * worst-case performance on hash collisions. An `Ordering` is required for the element type. Equality
+ * as determined by the `Ordering` has to be consistent with `equals` and `hashCode`. Universal equality
+ * of numeric types is not supported (similar to `AnyRefMap`).
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-mutable-collection-classes.html#hash-tables "Scala's Collection Library overview"]]
+ * section on `Hash Tables` for more information.
+ *
+ * @define Coll `mutable.CollisionProofHashMap`
+ * @define coll mutable collision-proof hash map
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+final class CollisionProofHashMap[K, V](initialCapacity: Int, loadFactor: Double)(implicit ordering: Ordering[K])
+ extends AbstractMap[K, V]
+ with MapOps[K, V, Map, CollisionProofHashMap[K, V]] //--
+ with StrictOptimizedIterableOps[(K, V), Iterable, CollisionProofHashMap[K, V]]
+ with StrictOptimizedMapOps[K, V, Map, CollisionProofHashMap[K, V]] { //--
+
+ private[this] final def sortedMapFactory: SortedMapFactory[CollisionProofHashMap] = CollisionProofHashMap
+
+ def this()(implicit ordering: Ordering[K]) = this(CollisionProofHashMap.defaultInitialCapacity, CollisionProofHashMap.defaultLoadFactor)(ordering)
+
+ import CollisionProofHashMap.Node
+ private[this] type RBNode = CollisionProofHashMap.RBNode[K, V]
+ private[this] type LLNode = CollisionProofHashMap.LLNode[K, V]
+
+ /** The actual hash table. */
+ private[this] var table: Array[Node] = new Array[Node](tableSizeFor(initialCapacity))
+
+ /** The next size value at which to resize (capacity * load factor). */
+ private[this] var threshold: Int = newThreshold(table.length)
+
+ private[this] var contentSize = 0
+
+ override def size: Int = contentSize
+
+ @`inline` private[this] final def computeHash(o: K): Int = {
+ val h = if(o.asInstanceOf[AnyRef] eq null) 0 else o.hashCode
+ h ^ (h >>> 16)
+ }
+
+ @`inline` private[this] final def index(hash: Int) = hash & (table.length - 1)
+
+ override protected def fromSpecific(coll: IterableOnce[(K, V)] @uncheckedVariance): CollisionProofHashMap[K, V] @uncheckedVariance = CollisionProofHashMap.from(coll)
+ override protected def newSpecificBuilder: Builder[(K, V), CollisionProofHashMap[K, V]] @uncheckedVariance = CollisionProofHashMap.newBuilder[K, V]
+
+ override def empty: CollisionProofHashMap[K, V] = new CollisionProofHashMap[K, V]
+
+ override def contains(key: K): Boolean = findNode(key) ne null
+
+ def get(key: K): Option[V] = findNode(key) match {
+ case null => None
+ case nd => Some(nd match {
+ case nd: LLNode @uc => nd.value
+ case nd: RBNode @uc => nd.value
+ })
+ }
+
+ @throws[NoSuchElementException]
+ override def apply(key: K): V = findNode(key) match {
+ case null => default(key)
+ case nd => nd match {
+ case nd: LLNode @uc => nd.value
+ case nd: RBNode @uc => nd.value
+ }
+ }
+
+ override def getOrElse[V1 >: V](key: K, default: => V1): V1 = {
+ val nd = findNode(key)
+ if (nd eq null) default else nd match {
+ case nd: LLNode @uc => nd.value
+ case n => n.asInstanceOf[RBNode].value
+ }
+ }
+
+ @`inline` private[this] def findNode(elem: K): Node = {
+ val hash = computeHash(elem)
+ table(index(hash)) match {
+ case null => null
+ case n: LLNode @uc => n.getNode(elem, hash)
+ case n => n.asInstanceOf[RBNode].getNode(elem, hash)
+ }
+ }
+
+ override def sizeHint(size: Int): Unit = {
+ val target = tableSizeFor(((size + 1).toDouble / loadFactor).toInt)
+ if(target > table.length) {
+ if(size == 0) reallocTable(target)
+ else growTable(target)
+ }
+ }
+
+ override def update(key: K, value: V): Unit = put0(key, value, getOld = false)
+
+ override def put(key: K, value: V): Option[V] = put0(key, value, getOld = true) match {
+ case null => None
+ case sm => sm
+ }
+
+ def addOne(elem: (K, V)): this.type = { put0(elem._1, elem._2, getOld = false); this }
+
+ @`inline` private[this] def put0(key: K, value: V, getOld: Boolean): Some[V] = {
+ if(contentSize + 1 >= threshold) growTable(table.length * 2)
+ val hash = computeHash(key)
+ val idx = index(hash)
+ put0(key, value, getOld, hash, idx)
+ }
+
+ private[this] def put0(key: K, value: V, getOld: Boolean, hash: Int, idx: Int): Some[V] = {
+ val res = table(idx) match {
+ case n: RBNode @uc =>
+ insert(n, idx, key, hash, value)
+ case _old =>
+ val old: LLNode = _old.asInstanceOf[LLNode]
+ if(old eq null) {
+ table(idx) = new LLNode(key, hash, value, null)
+ } else {
+ var remaining = CollisionProofHashMap.treeifyThreshold
+ var prev: LLNode = null
+ var n = old
+ while((n ne null) && n.hash <= hash && remaining > 0) {
+ if(n.hash == hash && key == n.key) {
+ val old = n.value
+ n.value = value
+ return (if(getOld) Some(old) else null)
+ }
+ prev = n
+ n = n.next
+ remaining -= 1
+ }
+ if(remaining == 0) {
+ treeify(old, idx)
+ return put0(key, value, getOld, hash, idx)
+ }
+ if(prev eq null) table(idx) = new LLNode(key, hash, value, old)
+ else prev.next = new LLNode(key, hash, value, prev.next)
+ }
+ true
+ }
+ if(res) contentSize += 1
+ if(res) Some(null.asInstanceOf[V]) else null //TODO
+ }
+
+ private[this] def treeify(old: LLNode, idx: Int): Unit = {
+ table(idx) = CollisionProofHashMap.leaf(old.key, old.hash, old.value, red = false, null)
+ var n: LLNode = old.next
+ while(n ne null) {
+ val root = table(idx).asInstanceOf[RBNode]
+ insertIntoExisting(root, idx, n.key, n.hash, n.value, root)
+ n = n.next
+ }
+ }
+
+ override def addAll(xs: IterableOnce[(K, V)]): this.type = {
+ sizeHint(xs, delta = contentSize)
+ super.addAll(xs)
+ }
+
+ // returns the old value or Statics.pfMarker if not found
+ private[this] def remove0(elem: K) : Any = {
+ val hash = computeHash(elem)
+ val idx = index(hash)
+ table(idx) match {
+ case null => Statics.pfMarker
+ case t: RBNode @uc =>
+ val v = delete(t, idx, elem, hash)
+ if(v.asInstanceOf[AnyRef] ne Statics.pfMarker) contentSize -= 1
+ v
+ case nd: LLNode @uc if nd.hash == hash && nd.key == elem =>
+ // first element matches
+ table(idx) = nd.next
+ contentSize -= 1
+ nd.value
+ case nd: LLNode @uc =>
+ // find an element that matches
+ var prev = nd
+ var next = nd.next
+ while((next ne null) && next.hash <= hash) {
+ if(next.hash == hash && next.key == elem) {
+ prev.next = next.next
+ contentSize -= 1
+ return next.value
+ }
+ prev = next
+ next = next.next
+ }
+ Statics.pfMarker
+ }
+ }
+
+ private[this] abstract class MapIterator[R] extends AbstractIterator[R] {
+ protected[this] def extract(node: LLNode): R
+ protected[this] def extract(node: RBNode): R
+
+ private[this] var i = 0
+ private[this] var node: Node = null
+ private[this] val len = table.length
+
+ def hasNext: Boolean = {
+ if(node ne null) true
+ else {
+ while(i < len) {
+ val n = table(i)
+ i += 1
+ n match {
+ case null =>
+ case n: RBNode @uc =>
+ node = CollisionProofHashMap.minNodeNonNull(n)
+ return true
+ case n: LLNode @uc =>
+ node = n
+ return true
+ }
+ }
+ false
+ }
+ }
+
+ def next(): R =
+ if(!hasNext) Iterator.empty.next()
+ else node match {
+ case n: RBNode @uc =>
+ val r = extract(n)
+ node = CollisionProofHashMap.successor(n )
+ r
+ case n: LLNode @uc =>
+ val r = extract(n)
+ node = n.next
+ r
+ }
+ }
+
+ override def keysIterator: Iterator[K] = {
+ if (isEmpty) Iterator.empty
+ else new MapIterator[K] {
+ protected[this] def extract(node: LLNode) = node.key
+ protected[this] def extract(node: RBNode) = node.key
+ }
+ }
+
+ override def iterator: Iterator[(K, V)] = {
+ if (isEmpty) Iterator.empty
+ else new MapIterator[(K, V)] {
+ protected[this] def extract(node: LLNode) = (node.key, node.value)
+ protected[this] def extract(node: RBNode) = (node.key, node.value)
+ }
+ }
+
+ private[this] def growTable(newlen: Int) = {
+ var oldlen = table.length
+ table = java.util.Arrays.copyOf(table, newlen)
+ threshold = newThreshold(table.length)
+ while(oldlen < newlen) {
+ var i = 0
+ while (i < oldlen) {
+ val old = table(i)
+ if(old ne null) splitBucket(old, i, i + oldlen, oldlen)
+ i += 1
+ }
+ oldlen *= 2
+ }
+ }
+
+ @`inline` private[this] def reallocTable(newlen: Int) = {
+ table = new Array(newlen)
+ threshold = newThreshold(table.length)
+ }
+
+ @`inline` private[this] def splitBucket(tree: Node, lowBucket: Int, highBucket: Int, mask: Int): Unit = tree match {
+ case t: LLNode @uc => splitBucket(t, lowBucket, highBucket, mask)
+ case t: RBNode @uc => splitBucket(t, lowBucket, highBucket, mask)
+ }
+
+ private[this] def splitBucket(list: LLNode, lowBucket: Int, highBucket: Int, mask: Int): Unit = {
+ val preLow: LLNode = new LLNode(null.asInstanceOf[K], 0, null.asInstanceOf[V], null)
+ val preHigh: LLNode = new LLNode(null.asInstanceOf[K], 0, null.asInstanceOf[V], null)
+ //preLow.next = null
+ //preHigh.next = null
+ var lastLow: LLNode = preLow
+ var lastHigh: LLNode = preHigh
+ var n = list
+ while(n ne null) {
+ val next = n.next
+ if((n.hash & mask) == 0) { // keep low
+ lastLow.next = n
+ lastLow = n
+ } else { // move to high
+ lastHigh.next = n
+ lastHigh = n
+ }
+ n = next
+ }
+ lastLow.next = null
+ if(list ne preLow.next) table(lowBucket) = preLow.next
+ if(preHigh.next ne null) {
+ table(highBucket) = preHigh.next
+ lastHigh.next = null
+ }
+ }
+
+ private[this] def splitBucket(tree: RBNode, lowBucket: Int, highBucket: Int, mask: Int): Unit = {
+ var lowCount, highCount = 0
+ tree.foreachNode((n: RBNode) => if((n.hash & mask) != 0) highCount += 1 else lowCount += 1)
+ if(highCount != 0) {
+ if(lowCount == 0) {
+ table(lowBucket) = null
+ table(highBucket) = tree
+ } else {
+ table(lowBucket) = fromNodes(new CollisionProofHashMap.RBNodesIterator(tree).filter(n => (n.hash & mask) == 0), lowCount)
+ table(highBucket) = fromNodes(new CollisionProofHashMap.RBNodesIterator(tree).filter(n => (n.hash & mask) != 0), highCount)
+ }
+ }
+ }
+
+ private[this] def tableSizeFor(capacity: Int) =
+ (Integer.highestOneBit((capacity-1).max(4))*2).min(1 << 30)
+
+ private[this] def newThreshold(size: Int) = (size.toDouble * loadFactor).toInt
+
+ override def clear(): Unit = {
+ java.util.Arrays.fill(table.asInstanceOf[Array[AnyRef]], null)
+ contentSize = 0
+ }
+
+ override def remove(key: K): Option[V] = {
+ val v = remove0(key)
+ if(v.asInstanceOf[AnyRef] eq Statics.pfMarker) None else Some(v.asInstanceOf[V])
+ }
+
+ def subtractOne(elem: K): this.type = { remove0(elem); this }
+
+ override def knownSize: Int = size
+
+ override def isEmpty: Boolean = size == 0
+
+ override def foreach[U](f: ((K, V)) => U): Unit = {
+ val len = table.length
+ var i = 0
+ while(i < len) {
+ val n = table(i)
+ if(n ne null) n match {
+ case n: LLNode @uc => n.foreach(f)
+ case n: RBNode @uc => n.foreach(f)
+ }
+ i += 1
+ }
+ }
+
+ override def foreachEntry[U](f: (K, V) => U): Unit = {
+ val len = table.length
+ var i = 0
+ while(i < len) {
+ val n = table(i)
+ if(n ne null) n match {
+ case n: LLNode @uc => n.foreachEntry(f)
+ case n: RBNode @uc => n.foreachEntry(f)
+ }
+ i += 1
+ }
+ }
+
+ protected[this] def writeReplace(): AnyRef = new DefaultSerializationProxy(new CollisionProofHashMap.DeserializationFactory[K, V](table.length, loadFactor, ordering), this)
+
+ override protected[this] def className = "CollisionProofHashMap"
+
+ override def getOrElseUpdate(key: K, defaultValue: => V): V = {
+ val hash = computeHash(key)
+ val idx = index(hash)
+ table(idx) match {
+ case null => ()
+ case n: LLNode @uc =>
+ val nd = n.getNode(key, hash)
+ if(nd != null) return nd.value
+ case n =>
+ val nd = n.asInstanceOf[RBNode].getNode(key, hash)
+ if(nd != null) return nd.value
+ }
+ val table0 = table
+ val default = defaultValue
+ if(contentSize + 1 >= threshold) growTable(table.length * 2)
+ // Avoid recomputing index if the `defaultValue()` or new element hasn't triggered a table resize.
+ val newIdx = if (table0 eq table) idx else index(hash)
+ put0(key, default, getOld = false, hash, newIdx)
+ default
+ }
+
+ ///////////////////// Overrides code from SortedMapOps
+
+ /** Builds a new `CollisionProofHashMap` by applying a function to all elements of this $coll.
+ *
+ * @param f the function to apply to each element.
+ * @return a new $coll resulting from applying the given function
+ * `f` to each element of this $coll and collecting the results.
+ */
+ def map[K2, V2](f: ((K, V)) => (K2, V2))
+ (implicit @implicitNotFound(CollisionProofHashMap.ordMsg) ordering: Ordering[K2]): CollisionProofHashMap[K2, V2] =
+ sortedMapFactory.from(new View.Map[(K, V), (K2, V2)](this, f))
+
+ /** Builds a new `CollisionProofHashMap` by applying a function to all elements of this $coll
+ * and using the elements of the resulting collections.
+ *
+ * @param f the function to apply to each element.
+ * @return a new $coll resulting from applying the given collection-valued function
+ * `f` to each element of this $coll and concatenating the results.
+ */
+ def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)])
+ (implicit @implicitNotFound(CollisionProofHashMap.ordMsg) ordering: Ordering[K2]): CollisionProofHashMap[K2, V2] =
+ sortedMapFactory.from(new View.FlatMap(this, f))
+
+ /** Builds a new sorted map by applying a partial function to all elements of this $coll
+ * on which the function is defined.
+ *
+ * @param pf the partial function which filters and maps the $coll.
+ * @return a new $coll resulting from applying the given partial function
+ * `pf` to each element on which it is defined and collecting the results.
+ * The order of the elements is preserved.
+ */
+ def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)])
+ (implicit @implicitNotFound(CollisionProofHashMap.ordMsg) ordering: Ordering[K2]): CollisionProofHashMap[K2, V2] =
+ sortedMapFactory.from(new View.Collect(this, pf))
+
+ override def concat[V2 >: V](suffix: IterableOnce[(K, V2)]): CollisionProofHashMap[K, V2] = sortedMapFactory.from(suffix match {
+ case it: Iterable[(K, V2)] => new View.Concat(this, it)
+ case _ => iterator.concat(suffix.iterator)
+ })
+
+ /** Alias for `concat` */
+ @`inline` override final def ++ [V2 >: V](xs: IterableOnce[(K, V2)]): CollisionProofHashMap[K, V2] = concat(xs)
+
+ @deprecated("Consider requiring an immutable Map or fall back to Map.concat", "2.13.0")
+ override def + [V1 >: V](kv: (K, V1)): CollisionProofHashMap[K, V1] =
+ sortedMapFactory.from(new View.Appended(this, kv))
+
+ @deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
+ override def + [V1 >: V](elem1: (K, V1), elem2: (K, V1), elems: (K, V1)*): CollisionProofHashMap[K, V1] =
+ sortedMapFactory.from(new View.Concat(new View.Appended(new View.Appended(this, elem1), elem2), elems))
+
+ ///////////////////// RedBlackTree code derived from mutable.RedBlackTree:
+
+ @`inline` private[this] def isRed(node: RBNode) = (node ne null) && node.red
+ @`inline` private[this] def isBlack(node: RBNode) = (node eq null) || !node.red
+
+ @unused @`inline` private[this] def compare(key: K, hash: Int, node: LLNode): Int = {
+ val i = hash - node.hash
+ if(i != 0) i else ordering.compare(key, node.key)
+ }
+
+ @`inline` private[this] def compare(key: K, hash: Int, node: RBNode): Int = {
+ /*val i = hash - node.hash
+ if(i != 0) i else*/ ordering.compare(key, node.key)
+ }
+
+ // ---- insertion ----
+
+ @tailrec private[this] final def insertIntoExisting(_root: RBNode, bucket: Int, key: K, hash: Int, value: V, x: RBNode): Boolean = {
+ val cmp = compare(key, hash, x)
+ if(cmp == 0) {
+ x.value = value
+ false
+ } else {
+ val next = if(cmp < 0) x.left else x.right
+ if(next eq null) {
+ val z = CollisionProofHashMap.leaf(key, hash, value, red = true, x)
+ if (cmp < 0) x.left = z else x.right = z
+ table(bucket) = fixAfterInsert(_root, z)
+ return true
+ }
+ else insertIntoExisting(_root, bucket, key, hash, value, next)
+ }
+ }
+
+ private[this] final def insert(tree: RBNode, bucket: Int, key: K, hash: Int, value: V): Boolean = {
+ if(tree eq null) {
+ table(bucket) = CollisionProofHashMap.leaf(key, hash, value, red = false, null)
+ true
+ } else insertIntoExisting(tree, bucket, key, hash, value, tree)
+ }
+
+ private[this] def fixAfterInsert(_root: RBNode, node: RBNode): RBNode = {
+ var root = _root
+ var z = node
+ while (isRed(z.parent)) {
+ if (z.parent eq z.parent.parent.left) {
+ val y = z.parent.parent.right
+ if (isRed(y)) {
+ z.parent.red = false
+ y.red = false
+ z.parent.parent.red = true
+ z = z.parent.parent
+ } else {
+ if (z eq z.parent.right) {
+ z = z.parent
+ root = rotateLeft(root, z)
+ }
+ z.parent.red = false
+ z.parent.parent.red = true
+ root = rotateRight(root, z.parent.parent)
+ }
+ } else { // symmetric cases
+ val y = z.parent.parent.left
+ if (isRed(y)) {
+ z.parent.red = false
+ y.red = false
+ z.parent.parent.red = true
+ z = z.parent.parent
+ } else {
+ if (z eq z.parent.left) {
+ z = z.parent
+ root = rotateRight(root, z)
+ }
+ z.parent.red = false
+ z.parent.parent.red = true
+ root = rotateLeft(root, z.parent.parent)
+ }
+ }
+ }
+ root.red = false
+ root
+ }
+
+ // ---- deletion ----
+
+ // returns the old value or Statics.pfMarker if not found
+ private[this] def delete(_root: RBNode, bucket: Int, key: K, hash: Int): Any = {
+ var root = _root
+ val z = root.getNode(key, hash: Int)
+ if (z ne null) {
+ val oldValue = z.value
+ var y = z
+ var yIsRed = y.red
+ var x: RBNode = null
+ var xParent: RBNode = null
+
+ if (z.left eq null) {
+ x = z.right
+ root = transplant(root, z, z.right)
+ xParent = z.parent
+ }
+ else if (z.right eq null) {
+ x = z.left
+ root = transplant(root, z, z.left)
+ xParent = z.parent
+ }
+ else {
+ y = CollisionProofHashMap.minNodeNonNull(z.right)
+ yIsRed = y.red
+ x = y.right
+
+ if (y.parent eq z) xParent = y
+ else {
+ xParent = y.parent
+ root = transplant(root, y, y.right)
+ y.right = z.right
+ y.right.parent = y
+ }
+ root = transplant(root, z, y)
+ y.left = z.left
+ y.left.parent = y
+ y.red = z.red
+ }
+
+ if (!yIsRed) root = fixAfterDelete(root, x, xParent)
+ if(root ne _root) table(bucket) = root
+ oldValue
+ } else Statics.pfMarker
+ }
+
+ private[this] def fixAfterDelete(_root: RBNode, node: RBNode, parent: RBNode): RBNode = {
+ var root = _root
+ var x = node
+ var xParent = parent
+ while ((x ne root) && isBlack(x)) {
+ if (x eq xParent.left) {
+ var w = xParent.right
+ // assert(w ne null)
+
+ if (w.red) {
+ w.red = false
+ xParent.red = true
+ root = rotateLeft(root, xParent)
+ w = xParent.right
+ }
+ if (isBlack(w.left) && isBlack(w.right)) {
+ w.red = true
+ x = xParent
+ } else {
+ if (isBlack(w.right)) {
+ w.left.red = false
+ w.red = true
+ root = rotateRight(root, w)
+ w = xParent.right
+ }
+ w.red = xParent.red
+ xParent.red = false
+ w.right.red = false
+ root = rotateLeft(root, xParent)
+ x = root
+ }
+ } else { // symmetric cases
+ var w = xParent.left
+ // assert(w ne null)
+
+ if (w.red) {
+ w.red = false
+ xParent.red = true
+ root = rotateRight(root, xParent)
+ w = xParent.left
+ }
+ if (isBlack(w.right) && isBlack(w.left)) {
+ w.red = true
+ x = xParent
+ } else {
+ if (isBlack(w.left)) {
+ w.right.red = false
+ w.red = true
+ root = rotateLeft(root, w)
+ w = xParent.left
+ }
+ w.red = xParent.red
+ xParent.red = false
+ w.left.red = false
+ root = rotateRight(root, xParent)
+ x = root
+ }
+ }
+ xParent = x.parent
+ }
+ if (x ne null) x.red = false
+ root
+ }
+
+ // ---- helpers ----
+
+ @`inline` private[this] def rotateLeft(_root: RBNode, x: RBNode): RBNode = {
+ var root = _root
+ val y = x.right
+ x.right = y.left
+
+ val xp = x.parent
+ if (y.left ne null) y.left.parent = x
+ y.parent = xp
+
+ if (xp eq null) root = y
+ else if (x eq xp.left) xp.left = y
+ else xp.right = y
+
+ y.left = x
+ x.parent = y
+ root
+ }
+
+ @`inline` private[this] def rotateRight(_root: RBNode, x: RBNode): RBNode = {
+ var root = _root
+ val y = x.left
+ x.left = y.right
+
+ val xp = x.parent
+ if (y.right ne null) y.right.parent = x
+ y.parent = xp
+
+ if (xp eq null) root = y
+ else if (x eq xp.right) xp.right = y
+ else xp.left = y
+
+ y.right = x
+ x.parent = y
+ root
+ }
+
+ /**
+ * Transplant the node `from` to the place of node `to`. This is done by setting `from` as a child of `to`'s previous
+ * parent and setting `from`'s parent to the `to`'s previous parent. The children of `from` are left unchanged.
+ */
+ private[this] def transplant(_root: RBNode, to: RBNode, from: RBNode): RBNode = {
+ var root = _root
+ if (to.parent eq null) root = from
+ else if (to eq to.parent.left) to.parent.left = from
+ else to.parent.right = from
+ if (from ne null) from.parent = to.parent
+ root
+ }
+
+ // building
+
+ def fromNodes(xs: Iterator[Node], size: Int): RBNode = {
+ val maxUsedDepth = 32 - Integer.numberOfLeadingZeros(size) // maximum depth of non-leaf nodes
+ def f(level: Int, size: Int): RBNode = size match {
+ case 0 => null
+ case 1 =>
+ val nn = xs.next()
+ val (key, hash, value) = nn match {
+ case nn: LLNode @uc => (nn.key, nn.hash, nn.value)
+ case nn: RBNode @uc => (nn.key, nn.hash, nn.value)
+ }
+ new RBNode(key, hash, value, level == maxUsedDepth && level != 1, null, null, null)
+ case n =>
+ val leftSize = (size-1)/2
+ val left = f(level+1, leftSize)
+ val nn = xs.next()
+ val right = f(level+1, size-1-leftSize)
+ val (key, hash, value) = nn match {
+ case nn: LLNode @uc => (nn.key, nn.hash, nn.value)
+ case nn: RBNode @uc => (nn.key, nn.hash, nn.value)
+ }
+ val n = new RBNode(key, hash, value, red = false, left, right, null)
+ if(left ne null) left.parent = n
+ right.parent = n
+ n
+ }
+ f(1, size)
+ }
+}
+
+/**
+ * $factoryInfo
+ * @define Coll `mutable.CollisionProofHashMap`
+ * @define coll mutable collision-proof hash map
+ */
+@SerialVersionUID(3L)
+object CollisionProofHashMap extends SortedMapFactory[CollisionProofHashMap] {
+ private[collection] final val ordMsg = "No implicit Ordering[${K2}] found to build a CollisionProofHashMap[${K2}, ${V2}]. You may want to upcast to a Map[${K}, ${V}] first by calling `unsorted`."
+
+ def from[K : Ordering, V](it: scala.collection.IterableOnce[(K, V)]): CollisionProofHashMap[K, V] = {
+ val k = it.knownSize
+ val cap = if(k > 0) ((k + 1).toDouble / defaultLoadFactor).toInt else defaultInitialCapacity
+ new CollisionProofHashMap[K, V](cap, defaultLoadFactor) ++= it
+ }
+
+ def empty[K : Ordering, V]: CollisionProofHashMap[K, V] = new CollisionProofHashMap[K, V]
+
+ def newBuilder[K : Ordering, V]: Builder[(K, V), CollisionProofHashMap[K, V]] = newBuilder(defaultInitialCapacity, defaultLoadFactor)
+
+ def newBuilder[K : Ordering, V](initialCapacity: Int, loadFactor: Double): Builder[(K, V), CollisionProofHashMap[K, V]] =
+ new GrowableBuilder[(K, V), CollisionProofHashMap[K, V]](new CollisionProofHashMap[K, V](initialCapacity, loadFactor)) {
+ override def sizeHint(size: Int) = elems.sizeHint(size)
+ }
+
+ /** The default load factor for the hash table */
+ final def defaultLoadFactor: Double = 0.75
+
+ /** The default initial capacity for the hash table */
+ final def defaultInitialCapacity: Int = 16
+
+ @SerialVersionUID(3L)
+ private final class DeserializationFactory[K, V](val tableLength: Int, val loadFactor: Double, val ordering: Ordering[K]) extends Factory[(K, V), CollisionProofHashMap[K, V]] with Serializable {
+ def fromSpecific(it: IterableOnce[(K, V)]): CollisionProofHashMap[K, V] = new CollisionProofHashMap[K, V](tableLength, loadFactor)(ordering) ++= it
+ def newBuilder: Builder[(K, V), CollisionProofHashMap[K, V]] = CollisionProofHashMap.newBuilder(tableLength, loadFactor)(using ordering)
+ }
+
+ @unused @`inline` private def compare[K, V](key: K, hash: Int, node: LLNode[K, V])(implicit ord: Ordering[K]): Int = {
+ val i = hash - node.hash
+ if(i != 0) i else ord.compare(key, node.key)
+ }
+
+ @`inline` private def compare[K, V](key: K, hash: Int, node: RBNode[K, V])(implicit ord: Ordering[K]): Int = {
+ /*val i = hash - node.hash
+ if(i != 0) i else*/ ord.compare(key, node.key)
+ }
+
+ private final val treeifyThreshold = 8
+
+ // Superclass for RBNode and LLNode to help the JIT with optimizing instance checks, but no shared common fields.
+ // Keeping calls monomorphic where possible and dispatching manually where needed is faster.
+ sealed abstract class Node
+
+ /////////////////////////// Red-Black Tree Node
+
+ final class RBNode[K, V](var key: K, var hash: Int, var value: V, var red: Boolean, var left: RBNode[K, V], var right: RBNode[K, V], var parent: RBNode[K, V]) extends Node {
+ override def toString: String = "RBNode(" + key + ", " + hash + ", " + value + ", " + red + ", " + left + ", " + right + ")"
+
+ @tailrec def getNode(k: K, h: Int)(implicit ord: Ordering[K]): RBNode[K, V] = {
+ val cmp = compare(k, h, this)
+ if (cmp < 0) {
+ if(left ne null) left.getNode(k, h) else null
+ } else if (cmp > 0) {
+ if(right ne null) right.getNode(k, h) else null
+ } else this
+ }
+
+ def foreach[U](f: ((K, V)) => U): Unit = {
+ if(left ne null) left.foreach(f)
+ f((key, value))
+ if(right ne null) right.foreach(f)
+ }
+
+ def foreachEntry[U](f: (K, V) => U): Unit = {
+ if(left ne null) left.foreachEntry(f)
+ f(key, value)
+ if(right ne null) right.foreachEntry(f)
+ }
+
+ def foreachNode[U](f: RBNode[K, V] => U): Unit = {
+ if(left ne null) left.foreachNode(f)
+ f(this)
+ if(right ne null) right.foreachNode(f)
+ }
+ }
+
+ @`inline` private def leaf[A, B](key: A, hash: Int, value: B, red: Boolean, parent: RBNode[A, B]): RBNode[A, B] =
+ new RBNode(key, hash, value, red, null, null, parent)
+
+ @tailrec private def minNodeNonNull[A, B](node: RBNode[A, B]): RBNode[A, B] =
+ if (node.left eq null) node else minNodeNonNull(node.left)
+
+ /**
+ * Returns the node that follows `node` in an in-order tree traversal. If `node` has the maximum key (and is,
+ * therefore, the last node), this method returns `null`.
+ */
+ private def successor[A, B](node: RBNode[A, B]): RBNode[A, B] = {
+ if (node.right ne null) minNodeNonNull(node.right)
+ else {
+ var x = node
+ var y = x.parent
+ while ((y ne null) && (x eq y.right)) {
+ x = y
+ y = y.parent
+ }
+ y
+ }
+ }
+
+ private final class RBNodesIterator[A, B](tree: RBNode[A, B])(implicit @unused ord: Ordering[A]) extends AbstractIterator[RBNode[A, B]] {
+ private[this] var nextNode: RBNode[A, B] = if(tree eq null) null else minNodeNonNull(tree)
+
+ def hasNext: Boolean = nextNode ne null
+
+ @throws[NoSuchElementException]
+ def next(): RBNode[A, B] = nextNode match {
+ case null => Iterator.empty.next()
+ case node =>
+ nextNode = successor(node)
+ node
+ }
+ }
+
+ /////////////////////////// Linked List Node
+
+ private final class LLNode[K, V](var key: K, var hash: Int, var value: V, var next: LLNode[K, V]) extends Node {
+ override def toString = s"LLNode($key, $value, $hash) -> $next"
+
+ private[this] def eq(a: Any, b: Any): Boolean =
+ if(a.asInstanceOf[AnyRef] eq null) b.asInstanceOf[AnyRef] eq null else a.asInstanceOf[AnyRef].equals(b)
+
+ @tailrec def getNode(k: K, h: Int)(implicit ord: Ordering[K]): LLNode[K, V] = {
+ if(h == hash && eq(k, key) /*ord.compare(k, key) == 0*/) this
+ else if((next eq null) || (hash > h)) null
+ else next.getNode(k, h)
+ }
+
+ @tailrec def foreach[U](f: ((K, V)) => U): Unit = {
+ f((key, value))
+ if(next ne null) next.foreach(f)
+ }
+
+ @tailrec def foreachEntry[U](f: (K, V) => U): Unit = {
+ f(key, value)
+ if(next ne null) next.foreachEntry(f)
+ }
+
+ @tailrec def foreachNode[U](f: LLNode[K, V] => U): Unit = {
+ f(this)
+ if(next ne null) next.foreachNode(f)
+ }
+ }
+}
diff --git a/library/src/scala/collection/mutable/Growable.scala b/library/src/scala/collection/mutable/Growable.scala
new file mode 100644
index 000000000000..b2d4806089dc
--- /dev/null
+++ b/library/src/scala/collection/mutable/Growable.scala
@@ -0,0 +1,101 @@
+/*
+ * 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 collection
+package mutable
+
+/** This trait forms part of collections that can be augmented
+ * using a `+=` operator and that can be cleared of all elements using
+ * a `clear` method.
+ *
+ * @define coll growable collection
+ * @define Coll `Growable`
+ * @define add add
+ * @define Add Add
+ */
+trait Growable[-A] extends Clearable {
+
+ /** ${Add}s a single element to this $coll.
+ *
+ * @param elem the element to $add.
+ * @return the $coll itself
+ */
+ def addOne(elem: A): this.type
+
+ /** Alias for `addOne` */
+ @inline final def += (elem: A): this.type = addOne(elem)
+
+ //TODO This causes a conflict in StringBuilder; looks like a compiler bug
+ //@deprecated("Use addOne or += instead of append", "2.13.0")
+ //@`inline` final def append(elem: A): Unit = addOne(elem)
+
+ /** ${Add}s two or more elements to this $coll.
+ *
+ * @param elem1 the first element to $add.
+ * @param elem2 the second element to $add.
+ * @param elems the remaining elements to $add.
+ * @return the $coll itself
+ */
+ @deprecated("Use `++=` aka `addAll` instead of varargs `+=`; infix operations with an operand of multiple args will be deprecated", "2.13.0")
+ @inline final def += (elem1: A, elem2: A, elems: A*): this.type = this += elem1 += elem2 ++= (elems: IterableOnce[A])
+
+ /** ${Add}s all elements produced by an IterableOnce to this $coll.
+ *
+ * @param elems the IterableOnce producing the elements to $add.
+ * @return the $coll itself.
+ */
+ def addAll(@deprecatedName("xs") elems: IterableOnce[A]): this.type = {
+ if (elems.asInstanceOf[AnyRef] eq this) addAll(Buffer.from(elems)) // avoid mutating under our own iterator
+ else {
+ val it = elems.iterator
+ while (it.hasNext) {
+ addOne(it.next())
+ }
+ }
+ this
+ }
+
+ /** Alias for `addAll` */
+ @inline final def ++= (@deprecatedName("xs") elems: IterableOnce[A]): this.type = addAll(elems)
+
+ /** The number of elements in the collection under construction, if it can be cheaply computed, -1 otherwise.
+ *
+ * @return The number of elements. The default implementation always returns -1.
+ */
+ def knownSize: Int = -1
+}
+
+object Growable {
+
+ /**
+ * Fills a `Growable` instance with the elements of a given iterable
+ * @param empty Instance to fill
+ * @param it Elements to add
+ * @tparam A Element type
+ * @return The filled instance
+ */
+ def from[A](empty: Growable[A], it: collection.IterableOnce[A]): empty.type = empty ++= it
+
+}
+
+/** This trait forms part of collections that can be cleared
+ * with a clear() call.
+ *
+ * @define coll collection
+ */
+trait Clearable {
+ /** Clears the $coll's contents. After this operation, the
+ * $coll is empty.
+ */
+ def clear(): Unit
+}
diff --git a/library/src/scala/collection/mutable/GrowableBuilder.scala b/library/src/scala/collection/mutable/GrowableBuilder.scala
new file mode 100644
index 000000000000..247bc58da150
--- /dev/null
+++ b/library/src/scala/collection/mutable/GrowableBuilder.scala
@@ -0,0 +1,37 @@
+/*
+ * 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 collection.mutable
+
+
+/** The canonical builder for collections that are growable, i.e. that support an
+ * efficient `+=` method which adds an element to the collection.
+ *
+ * GrowableBuilders can produce only a single instance of the collection they are growing.
+ *
+ * @define Coll `GrowingBuilder`
+ * @define coll growing builder
+ */
+class GrowableBuilder[Elem, To <: Growable[Elem]](protected val elems: To)
+ extends Builder[Elem, To] {
+
+ def clear(): Unit = elems.clear()
+
+ def result(): To = elems
+
+ def addOne(elem: Elem): this.type = { elems += elem; this }
+
+ override def addAll(xs: IterableOnce[Elem]): this.type = { elems.addAll(xs); this }
+
+ override def knownSize: Int = elems.knownSize
+}
diff --git a/library/src/scala/collection/mutable/HashMap.scala b/library/src/scala/collection/mutable/HashMap.scala
new file mode 100644
index 000000000000..86aa9541c4e3
--- /dev/null
+++ b/library/src/scala/collection/mutable/HashMap.scala
@@ -0,0 +1,654 @@
+/*
+ * 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 mutable
+
+import scala.annotation.{nowarn, tailrec}
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.generic.DefaultSerializationProxy
+import scala.util.hashing.MurmurHash3
+
+/** This class implements mutable maps using a hashtable.
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-mutable-collection-classes.html#hash-tables "Scala's Collection Library overview"]]
+ * section on `Hash Tables` for more information.
+ *
+ * @tparam K the type of the keys contained in this hash map.
+ * @tparam V the type of the values assigned to keys in this hash map.
+ *
+ * @define Coll `mutable.HashMap`
+ * @define coll mutable hash map
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+@deprecatedInheritance("HashMap will be made final; use .withDefault for the common use case of computing a default value", "2.13.0")
+class HashMap[K, V](initialCapacity: Int, loadFactor: Double)
+ extends AbstractMap[K, V]
+ with MapOps[K, V, HashMap, HashMap[K, V]]
+ with StrictOptimizedIterableOps[(K, V), Iterable, HashMap[K, V]]
+ with StrictOptimizedMapOps[K, V, HashMap, HashMap[K, V]]
+ with MapFactoryDefaults[K, V, HashMap, Iterable]
+ with Serializable {
+
+ /* The HashMap class holds the following invariant:
+ * - For each i between 0 and table.length, the bucket at table(i) only contains keys whose hash-index is i.
+ * - Every bucket is sorted in ascendent hash order
+ * - The sum of the lengths of all buckets is equal to contentSize.
+ */
+ def this() = this(HashMap.defaultInitialCapacity, HashMap.defaultLoadFactor)
+
+ import HashMap.Node
+
+ /** The actual hash table. */
+ private[this] var table = new Array[Node[K, V]](tableSizeFor(initialCapacity))
+
+ /** The next size value at which to resize (capacity * load factor). */
+ private[this] var threshold: Int = newThreshold(table.length)
+
+ private[this] var contentSize = 0
+
+ override def size: Int = contentSize
+
+ /** Performs the inverse operation of improveHash. In this case, it happens to be identical to improveHash*/
+ @`inline` private[collection] def unimproveHash(improvedHash: Int): Int = improveHash(improvedHash)
+
+ /** Computes the improved hash of an original (`any.##`) hash. */
+ @`inline` private[this] def improveHash(originalHash: Int): Int = {
+ // Improve the hash by xoring the high 16 bits into the low 16 bits just in case entropy is skewed towards the
+ // high-value bits. We only use the lowest bits to determine the hash bucket. This is the same improvement
+ // algorithm as in java.util.HashMap.
+ //
+ // This function is also its own inverse. That is, for all ints i, improveHash(improveHash(i)) = i
+ // this allows us to retrieve the original hash when we need it, for instance when appending to an immutable.HashMap
+ // and that is why unimproveHash simply forwards to this method
+ originalHash ^ (originalHash >>> 16)
+ }
+
+ /** Computes the improved hash of this key */
+ @`inline` private[this] def computeHash(o: K): Int = improveHash(o.##)
+
+ @`inline` private[this] def index(hash: Int) = hash & (table.length - 1)
+
+ override def contains(key: K): Boolean = findNode(key) ne null
+
+ @`inline` private[this] def findNode(key: K): Node[K, V] = {
+ val hash = computeHash(key)
+ table(index(hash)) match {
+ case null => null
+ case nd => nd.findNode(key, hash)
+ }
+ }
+
+ override def sizeHint(size: Int): Unit = {
+ val target = tableSizeFor(((size + 1).toDouble / loadFactor).toInt)
+ if(target > table.length) growTable(target)
+ }
+
+ override def addAll(xs: IterableOnce[(K, V)]): this.type = {
+ sizeHint(xs)
+
+ xs match {
+ case hm: immutable.HashMap[K, V] =>
+ hm.foreachWithHash((k, v, h) => put0(k, v, improveHash(h), getOld = false))
+ this
+ case hm: mutable.HashMap[K, V] =>
+ val iter = hm.nodeIterator
+ while (iter.hasNext) {
+ val next = iter.next()
+ put0(next.key, next.value, next.hash, getOld = false)
+ }
+ this
+ case lhm: mutable.LinkedHashMap[K, V] =>
+ val iter = lhm.entryIterator
+ while (iter.hasNext) {
+ val entry = iter.next()
+ put0(entry.key, entry.value, entry.hash, getOld = false)
+ }
+ this
+ case thatMap: Map[K, V] =>
+ thatMap.foreachEntry { (key: K, value: V) =>
+ put0(key, value, improveHash(key.##), getOld = false)
+ }
+ this
+ case _ =>
+ super.addAll(xs)
+ }
+ }
+
+ // Override updateWith for performance, so we can do the update while hashing
+ // the input key only once and performing one lookup into the hash table
+ override def updateWith(key: K)(remappingFunction: Option[V] => Option[V]): Option[V] = {
+ if (getClass != classOf[HashMap[_, _]]) {
+ // subclasses of HashMap might customise `get` ...
+ super.updateWith(key)(remappingFunction)
+ } else {
+ val hash = computeHash(key)
+ val indexedHash = index(hash)
+
+ var foundNode: Node[K, V] = null
+ var previousNode: Node[K, V] = null
+ table(indexedHash) match {
+ case null =>
+ case nd =>
+ @tailrec
+ def findNode(prev: Node[K, V], nd: Node[K, V], k: K, h: Int): Unit = {
+ if (h == nd.hash && k == nd.key) {
+ previousNode = prev
+ foundNode = nd
+ }
+ else if ((nd.next eq null) || (nd.hash > h)) ()
+ else findNode(nd, nd.next, k, h)
+ }
+
+ findNode(null, nd, key, hash)
+ }
+
+ val previousValue = foundNode match {
+ case null => None
+ case nd => Some(nd.value)
+ }
+
+ val nextValue = remappingFunction(previousValue)
+
+ (previousValue, nextValue) match {
+ case (None, None) => // do nothing
+
+ case (Some(_), None) =>
+ if (previousNode != null) previousNode.next = foundNode.next
+ else table(indexedHash) = foundNode.next
+ contentSize -= 1
+
+ case (None, Some(value)) =>
+ val newIndexedHash =
+ if (contentSize + 1 >= threshold) {
+ growTable(table.length * 2)
+ index(hash)
+ } else indexedHash
+ put0(key, value, getOld = false, hash, newIndexedHash)
+
+ case (Some(_), Some(newValue)) => foundNode.value = newValue
+ }
+ nextValue
+ }
+ }
+
+ override def subtractAll(xs: IterableOnce[K]): this.type = {
+ if (size == 0) {
+ return this
+ }
+
+ xs match {
+ case hs: immutable.HashSet[K] =>
+ hs.foreachWithHashWhile { (k, h) =>
+ remove0(k, improveHash(h))
+ size > 0
+ }
+ this
+ case hs: mutable.HashSet[K] =>
+ val iter = hs.nodeIterator
+ while (iter.hasNext) {
+ val next = iter.next()
+ remove0(next.key, next.hash)
+ if (size == 0) return this
+ }
+ this
+ case lhs: mutable.LinkedHashSet[K] =>
+ val iter = lhs.entryIterator
+ while (iter.hasNext) {
+ val next = iter.next()
+ remove0(next.key, next.hash)
+ if (size == 0) return this
+ }
+ this
+ case _ => super.subtractAll(xs)
+ }
+ }
+
+ /** Adds a key-value pair to this map
+ *
+ * @param key the key to add
+ * @param value the value to add
+ * @param hash the **improved** hashcode of `key` (see computeHash)
+ * @param getOld if true, then the previous value for `key` will be returned, otherwise, false
+ */
+ private[this] def put0(key: K, value: V, hash: Int, getOld: Boolean): Some[V] = {
+ if(contentSize + 1 >= threshold) growTable(table.length * 2)
+ val idx = index(hash)
+ put0(key, value, getOld, hash, idx)
+ }
+
+ private[this] def put0(key: K, value: V, getOld: Boolean): Some[V] = {
+ if(contentSize + 1 >= threshold) growTable(table.length * 2)
+ val hash = computeHash(key)
+ val idx = index(hash)
+ put0(key, value, getOld, hash, idx)
+ }
+
+
+ private[this] def put0(key: K, value: V, getOld: Boolean, hash: Int, idx: Int): Some[V] = {
+ table(idx) match {
+ case null =>
+ table(idx) = new Node[K, V](key, hash, value, null)
+ case old =>
+ var prev: Node[K, V] = null
+ var n = old
+ while((n ne null) && n.hash <= hash) {
+ if(n.hash == hash && key == n.key) {
+ val old = n.value
+ n.value = value
+ return if(getOld) Some(old) else null
+ }
+ prev = n
+ n = n.next
+ }
+ if(prev eq null) table(idx) = new Node(key, hash, value, old)
+ else prev.next = new Node(key, hash, value, prev.next)
+ }
+ contentSize += 1
+ null
+ }
+
+ private def remove0(elem: K) : Node[K, V] = remove0(elem, computeHash(elem))
+
+ /** Removes a key from this map if it exists
+ *
+ * @param elem the element to remove
+ * @param hash the **improved** hashcode of `element` (see computeHash)
+ * @return the node that contained element if it was present, otherwise null
+ */
+ private[this] def remove0(elem: K, hash: Int) : Node[K, V] = {
+ val idx = index(hash)
+ table(idx) match {
+ case null => null
+ case nd if nd.hash == hash && nd.key == elem =>
+ // first element matches
+ table(idx) = nd.next
+ contentSize -= 1
+ nd
+ case nd =>
+ // find an element that matches
+ var prev = nd
+ var next = nd.next
+ while((next ne null) && next.hash <= hash) {
+ if(next.hash == hash && next.key == elem) {
+ prev.next = next.next
+ contentSize -= 1
+ return next
+ }
+ prev = next
+ next = next.next
+ }
+ null
+ }
+ }
+
+ private[this] abstract class HashMapIterator[A] extends AbstractIterator[A] {
+ private[this] var i = 0
+ private[this] var node: Node[K, V] = null
+ private[this] val len = table.length
+
+ protected[this] def extract(nd: Node[K, V]): A
+
+ def hasNext: Boolean = {
+ if(node ne null) true
+ else {
+ while(i < len) {
+ val n = table(i)
+ i += 1
+ if(n ne null) { node = n; return true }
+ }
+ false
+ }
+ }
+
+ def next(): A =
+ if(!hasNext) Iterator.empty.next()
+ else {
+ val r = extract(node)
+ node = node.next
+ r
+ }
+ }
+
+ override def iterator: Iterator[(K, V)] =
+ if(size == 0) Iterator.empty
+ else new HashMapIterator[(K, V)] {
+ protected[this] def extract(nd: Node[K, V]) = (nd.key, nd.value)
+ }
+
+ override def keysIterator: Iterator[K] =
+ if(size == 0) Iterator.empty
+ else new HashMapIterator[K] {
+ protected[this] def extract(nd: Node[K, V]) = nd.key
+ }
+
+ override def valuesIterator: Iterator[V] =
+ if(size == 0) Iterator.empty
+ else new HashMapIterator[V] {
+ protected[this] def extract(nd: Node[K, V]) = nd.value
+ }
+
+
+ /** Returns an iterator over the nodes stored in this HashMap */
+ private[collection] def nodeIterator: Iterator[Node[K, V]] =
+ if(size == 0) Iterator.empty
+ else new HashMapIterator[Node[K, V]] {
+ protected[this] def extract(nd: Node[K, V]) = nd
+ }
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[(K, V), S]): S with EfficientSplit =
+ shape.
+ parUnbox(new convert.impl.AnyTableStepper[(K, V), Node[K, V]](size, table, _.next, node => (node.key, node.value), 0, table.length)).
+ asInstanceOf[S with EfficientSplit]
+
+ override def keyStepper[S <: Stepper[_]](implicit shape: StepperShape[K, S]): S with EfficientSplit = {
+ import convert.impl._
+ val s = shape.shape match {
+ case StepperShape.IntShape => new IntTableStepper[Node[K, V]] (size, table, _.next, _.key.asInstanceOf[Int], 0, table.length)
+ case StepperShape.LongShape => new LongTableStepper[Node[K, V]] (size, table, _.next, _.key.asInstanceOf[Long], 0, table.length)
+ case StepperShape.DoubleShape => new DoubleTableStepper[Node[K, V]](size, table, _.next, _.key.asInstanceOf[Double], 0, table.length)
+ case _ => shape.parUnbox(new AnyTableStepper[K, Node[K, V]](size, table, _.next, _.key, 0, table.length))
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ override def valueStepper[S <: Stepper[_]](implicit shape: StepperShape[V, S]): S with EfficientSplit = {
+ import convert.impl._
+ val s = shape.shape match {
+ case StepperShape.IntShape => new IntTableStepper[Node[K, V]] (size, table, _.next, _.value.asInstanceOf[Int], 0, table.length)
+ case StepperShape.LongShape => new LongTableStepper[Node[K, V]] (size, table, _.next, _.value.asInstanceOf[Long], 0, table.length)
+ case StepperShape.DoubleShape => new DoubleTableStepper[Node[K, V]](size, table, _.next, _.value.asInstanceOf[Double], 0, table.length)
+ case _ => shape.parUnbox(new AnyTableStepper[V, Node[K, V]](size, table, _.next, _.value, 0, table.length))
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ private[this] def growTable(newlen: Int) = {
+ if (newlen < 0)
+ throw new RuntimeException(s"new HashMap table size $newlen exceeds maximum")
+ var oldlen = table.length
+ threshold = newThreshold(newlen)
+ if(size == 0) table = new Array(newlen)
+ else {
+ table = java.util.Arrays.copyOf(table, newlen)
+ val preLow: Node[K, V] = new Node(null.asInstanceOf[K], 0, null.asInstanceOf[V], null)
+ val preHigh: Node[K, V] = new Node(null.asInstanceOf[K], 0, null.asInstanceOf[V], null)
+ // Split buckets until the new length has been reached. This could be done more
+ // efficiently when growing an already filled table to more than double the size.
+ while(oldlen < newlen) {
+ var i = 0
+ while (i < oldlen) {
+ val old = table(i)
+ if(old ne null) {
+ preLow.next = null
+ preHigh.next = null
+ var lastLow: Node[K, V] = preLow
+ var lastHigh: Node[K, V] = preHigh
+ var n = old
+ while(n ne null) {
+ val next = n.next
+ if((n.hash & oldlen) == 0) { // keep low
+ lastLow.next = n
+ lastLow = n
+ } else { // move to high
+ lastHigh.next = n
+ lastHigh = n
+ }
+ n = next
+ }
+ lastLow.next = null
+ if(old ne preLow.next) table(i) = preLow.next
+ if(preHigh.next ne null) {
+ table(i + oldlen) = preHigh.next
+ lastHigh.next = null
+ }
+ }
+ i += 1
+ }
+ oldlen *= 2
+ }
+ }
+ }
+
+ private[this] def tableSizeFor(capacity: Int) =
+ (Integer.highestOneBit((capacity-1).max(4))*2).min(1 << 30)
+
+ private[this] def newThreshold(size: Int) = (size.toDouble * loadFactor).toInt
+
+ override def clear(): Unit = {
+ java.util.Arrays.fill(table.asInstanceOf[Array[AnyRef]], null)
+ contentSize = 0
+ }
+
+ def get(key: K): Option[V] = findNode(key) match {
+ case null => None
+ case nd => Some(nd.value)
+ }
+
+ @throws[NoSuchElementException]
+ override def apply(key: K): V = findNode(key) match {
+ case null => default(key)
+ case nd => nd.value
+ }
+
+ override def getOrElse[V1 >: V](key: K, default: => V1): V1 = {
+ if (getClass != classOf[HashMap[_, _]]) {
+ // subclasses of HashMap might customise `get` ...
+ super.getOrElse(key, default)
+ } else {
+ // .. but in the common case, we can avoid the Option boxing.
+ val nd = findNode(key)
+ if (nd eq null) default else nd.value
+ }
+ }
+
+ override def getOrElseUpdate(key: K, defaultValue: => V): V = {
+ if (getClass != classOf[HashMap[_, _]]) {
+ // subclasses of HashMap might customise `get` ...
+ super.getOrElseUpdate(key, defaultValue)
+ } else {
+ val hash = computeHash(key)
+ val idx = index(hash)
+ val nd = table(idx) match {
+ case null => null
+ case nd => nd.findNode(key, hash)
+ }
+ if(nd != null) nd.value
+ else {
+ val table0 = table
+ val default = defaultValue
+ if(contentSize + 1 >= threshold) growTable(table.length * 2)
+ // Avoid recomputing index if the `defaultValue()` or new element hasn't triggered a table resize.
+ val newIdx = if (table0 eq table) idx else index(hash)
+ put0(key, default, getOld = false, hash, newIdx)
+ default
+ }
+ }
+ }
+
+ override def put(key: K, value: V): Option[V] = put0(key, value, getOld = true) match {
+ case null => None
+ case sm => sm
+ }
+
+ override def remove(key: K): Option[V] = remove0(key) match {
+ case null => None
+ case nd => Some(nd.value)
+ }
+
+ override def update(key: K, value: V): Unit = put0(key, value, getOld = false)
+
+ def addOne(elem: (K, V)): this.type = { put0(elem._1, elem._2, getOld = false); this }
+
+ def subtractOne(elem: K): this.type = { remove0(elem); this }
+
+ override def knownSize: Int = size
+
+ override def isEmpty: Boolean = size == 0
+
+ override def foreach[U](f: ((K, V)) => U): Unit = {
+ val len = table.length
+ var i = 0
+ while(i < len) {
+ val n = table(i)
+ if(n ne null) n.foreach(f)
+ i += 1
+ }
+ }
+
+ override def foreachEntry[U](f: (K, V) => U): Unit = {
+ val len = table.length
+ var i = 0
+ while(i < len) {
+ val n = table(i)
+ if(n ne null) n.foreachEntry(f)
+ i += 1
+ }
+ }
+
+ protected[this] def writeReplace(): AnyRef = new DefaultSerializationProxy(new mutable.HashMap.DeserializationFactory[K, V](table.length, loadFactor), this)
+
+ override def filterInPlace(p: (K, V) => Boolean): this.type = {
+ if (nonEmpty) {
+ var bucket = 0
+
+ while (bucket < table.length) {
+ var head = table(bucket)
+
+ while ((head ne null) && !p(head.key, head.value)) {
+ head = head.next
+ contentSize -= 1
+ }
+
+ if (head ne null) {
+ var prev = head
+ var next = head.next
+
+ while (next ne null) {
+ if (p(next.key, next.value)) {
+ prev = next
+ } else {
+ prev.next = next.next
+ contentSize -= 1
+ }
+ next = next.next
+ }
+ }
+
+ table(bucket) = head
+ bucket += 1
+ }
+ }
+ this
+ }
+
+ // TODO: rename to `mapValuesInPlace` and override the base version (not binary compatible)
+ private[mutable] def mapValuesInPlaceImpl(f: (K, V) => V): this.type = {
+ val len = table.length
+ var i = 0
+ while (i < len) {
+ var n = table(i)
+ while (n ne null) {
+ n.value = f(n.key, n.value)
+ n = n.next
+ }
+ i += 1
+ }
+ this
+ }
+
+ override def mapFactory: MapFactory[HashMap] = HashMap
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix = "HashMap"
+
+ override def hashCode: Int = {
+ if (isEmpty) MurmurHash3.emptyMapHash
+ else {
+ val tupleHashIterator = new HashMapIterator[Any] {
+ var hash: Int = 0
+ override def hashCode: Int = hash
+ override protected[this] def extract(nd: Node[K, V]): Any = {
+ hash = MurmurHash3.tuple2Hash(unimproveHash(nd.hash), nd.value.##)
+ this
+ }
+ }
+ MurmurHash3.unorderedHash(tupleHashIterator, MurmurHash3.mapSeed)
+ }
+ }
+}
+
+/**
+ * $factoryInfo
+ * @define Coll `mutable.HashMap`
+ * @define coll mutable hash map
+ */
+@SerialVersionUID(3L)
+object HashMap extends MapFactory[HashMap] {
+
+ def empty[K, V]: HashMap[K, V] = new HashMap[K, V]
+
+ def from[K, V](it: collection.IterableOnce[(K, V)]): HashMap[K, V] = {
+ val k = it.knownSize
+ val cap = if(k > 0) ((k + 1).toDouble / defaultLoadFactor).toInt else defaultInitialCapacity
+ new HashMap[K, V](cap, defaultLoadFactor).addAll(it)
+ }
+
+ def newBuilder[K, V]: Builder[(K, V), HashMap[K, V]] = newBuilder(defaultInitialCapacity, defaultLoadFactor)
+
+ def newBuilder[K, V](initialCapacity: Int, loadFactor: Double): Builder[(K, V), HashMap[K, V]] =
+ new GrowableBuilder[(K, V), HashMap[K, V]](new HashMap[K, V](initialCapacity, loadFactor)) {
+ override def sizeHint(size: Int) = elems.sizeHint(size)
+ }
+
+ /** The default load factor for the hash table */
+ final def defaultLoadFactor: Double = 0.75
+
+ /** The default initial capacity for the hash table */
+ final def defaultInitialCapacity: Int = 16
+
+ @SerialVersionUID(3L)
+ private final class DeserializationFactory[K, V](val tableLength: Int, val loadFactor: Double) extends Factory[(K, V), HashMap[K, V]] with Serializable {
+ def fromSpecific(it: IterableOnce[(K, V)]): HashMap[K, V] = new HashMap[K, V](tableLength, loadFactor).addAll(it)
+ def newBuilder: Builder[(K, V), HashMap[K, V]] = HashMap.newBuilder(tableLength, loadFactor)
+ }
+
+ private[collection] final class Node[K, V](_key: K, _hash: Int, private[this] var _value: V, private[this] var _next: Node[K, V]) {
+ def key: K = _key
+ def hash: Int = _hash
+ def value: V = _value
+ def value_= (v: V): Unit = _value = v
+ def next: Node[K, V] = _next
+ def next_= (n: Node[K, V]): Unit = _next = n
+
+ @tailrec
+ def findNode(k: K, h: Int): Node[K, V] =
+ if(h == _hash && k == _key) this
+ else if((_next eq null) || (_hash > h)) null
+ else _next.findNode(k, h)
+
+ @tailrec
+ def foreach[U](f: ((K, V)) => U): Unit = {
+ f((_key, _value))
+ if(_next ne null) _next.foreach(f)
+ }
+
+ @tailrec
+ def foreachEntry[U](f: (K, V) => U): Unit = {
+ f(_key, _value)
+ if(_next ne null) _next.foreachEntry(f)
+ }
+
+ override def toString = s"Node($key, $value, $hash) -> $next"
+ }
+}
diff --git a/library/src/scala/collection/mutable/HashSet.scala b/library/src/scala/collection/mutable/HashSet.scala
new file mode 100644
index 000000000000..9f0abbfa6cfd
--- /dev/null
+++ b/library/src/scala/collection/mutable/HashSet.scala
@@ -0,0 +1,456 @@
+/*
+ * 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 mutable
+
+import scala.annotation.tailrec
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.generic.DefaultSerializationProxy
+import scala.util.hashing.MurmurHash3
+
+/** This class implements mutable sets using a hashtable.
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-mutable-collection-classes.html#hash-tables "Scala's Collection Library overview"]]
+ * section on `Hash Tables` for more information.
+ *
+ * @define Coll `mutable.HashSet`
+ * @define coll mutable hash set
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+final class HashSet[A](initialCapacity: Int, loadFactor: Double)
+ extends AbstractSet[A]
+ with SetOps[A, HashSet, HashSet[A]]
+ with StrictOptimizedIterableOps[A, HashSet, HashSet[A]]
+ with IterableFactoryDefaults[A, HashSet]
+ with Serializable {
+
+ def this() = this(HashSet.defaultInitialCapacity, HashSet.defaultLoadFactor)
+
+ import HashSet.Node
+
+ /* The Hashset class holds the following invariant:
+ * - For each i between 0 and table.length, the bucket at table(i) only contains elements whose hash-index is i.
+ * - Every bucket is sorted in ascendent hash order
+ * - The sum of the lengths of all buckets is equal to contentSize.
+ */
+ /** The actual hash table. */
+ private[this] var table = new Array[Node[A]](tableSizeFor(initialCapacity))
+
+ /** The next size value at which to resize (capacity * load factor). */
+ private[this] var threshold: Int = newThreshold(table.length)
+
+ private[this] var contentSize = 0
+
+ override def size: Int = contentSize
+
+ /** Performs the inverse operation of improveHash. In this case, it happens to be identical to improveHash*/
+ @`inline` private[collection] def unimproveHash(improvedHash: Int): Int = improveHash(improvedHash)
+
+ /** Computes the improved hash of an original (`any.##`) hash. */
+ private[this] def improveHash(originalHash: Int): Int = {
+ // Improve the hash by xoring the high 16 bits into the low 16 bits just in case entropy is skewed towards the
+ // high-value bits. We only use the lowest bits to determine the hash bucket. This is the same improvement
+ // algorithm as in java.util.HashMap.
+ originalHash ^ (originalHash >>> 16)
+ }
+
+ /** Computes the improved hash of this element */
+ @`inline` private[this] def computeHash(o: A): Int = improveHash(o.##)
+
+ @`inline` private[this] def index(hash: Int) = hash & (table.length - 1)
+
+ override def contains(elem: A): Boolean = findNode(elem) ne null
+
+ @`inline` private[this] def findNode(elem: A): Node[A] = {
+ val hash = computeHash(elem)
+ table(index(hash)) match {
+ case null => null
+ case nd => nd.findNode(elem, hash)
+ }
+ }
+
+ override def sizeHint(size: Int): Unit = {
+ val target = tableSizeFor(((size + 1).toDouble / loadFactor).toInt)
+ if(target > table.length) growTable(target)
+ }
+
+ override def add(elem: A) : Boolean = {
+ if(contentSize + 1 >= threshold) growTable(table.length * 2)
+ addElem(elem, computeHash(elem))
+ }
+
+ override def addAll(xs: IterableOnce[A]): this.type = {
+ sizeHint(xs, delta = 0)
+ xs match {
+ case hs: immutable.HashSet[A] =>
+ hs.foreachWithHash((k, h) => addElem(k, improveHash(h)))
+ this
+ case hs: mutable.HashSet[A] =>
+ val iter = hs.nodeIterator
+ while (iter.hasNext) {
+ val next = iter.next()
+ addElem(next.key, next.hash)
+ }
+ this
+ case lhs: mutable.LinkedHashSet[A] =>
+ val iter = lhs.entryIterator
+ while (iter.hasNext) {
+ val next = iter.next()
+ addElem(next.key, next.hash)
+ }
+ this
+ case _ => super.addAll(xs)
+ }
+ }
+
+ override def subtractAll(xs: IterableOnce[A]): this.type = {
+ if (size == 0) {
+ return this
+ }
+
+ xs match {
+ case hs: immutable.HashSet[A] =>
+ hs.foreachWithHashWhile { (k, h) =>
+ remove(k, improveHash(h))
+ size > 0
+ }
+ this
+ case hs: mutable.HashSet[A] =>
+ val iter = hs.nodeIterator
+ while (iter.hasNext) {
+ val next = iter.next()
+ remove(next.key, next.hash)
+ if (size == 0) return this
+ }
+ this
+ case lhs: mutable.LinkedHashSet[A] =>
+ val iter = lhs.entryIterator
+ while (iter.hasNext) {
+ val next = iter.next()
+ remove(next.key, next.hash)
+ if (size == 0) return this
+ }
+ this
+ case _ => super.subtractAll(xs)
+ }
+ }
+
+ /** Adds an element to this set
+ * @param elem element to add
+ * @param hash the **improved** hash of `elem` (see computeHash)
+ */
+ private[this] def addElem(elem: A, hash: Int) : Boolean = {
+ val idx = index(hash)
+ table(idx) match {
+ case null =>
+ table(idx) = new Node(elem, hash, null)
+ case old =>
+ var prev: Node[A] = null
+ var n = old
+ while((n ne null) && n.hash <= hash) {
+ if(n.hash == hash && elem == n.key) return false
+ prev = n
+ n = n.next
+ }
+ if(prev eq null)
+ table(idx) = new Node(elem, hash, old)
+ else
+ prev.next = new Node(elem, hash, prev.next)
+ }
+ contentSize += 1
+ true
+ }
+
+ private[this] def remove(elem: A, hash: Int): Boolean = {
+ val idx = index(hash)
+ table(idx) match {
+ case null => false
+ case nd if nd.hash == hash && nd.key == elem =>
+ // first element matches
+ table(idx) = nd.next
+ contentSize -= 1
+ true
+ case nd =>
+ // find an element that matches
+ var prev = nd
+ var next = nd.next
+ while((next ne null) && next.hash <= hash) {
+ if(next.hash == hash && next.key == elem) {
+ prev.next = next.next
+ contentSize -= 1
+ return true
+ }
+ prev = next
+ next = next.next
+ }
+ false
+ }
+ }
+
+ override def remove(elem: A) : Boolean = remove(elem, computeHash(elem))
+
+ private[this] abstract class HashSetIterator[B] extends AbstractIterator[B] {
+ private[this] var i = 0
+ private[this] var node: Node[A] = null
+ private[this] val len = table.length
+
+ protected[this] def extract(nd: Node[A]): B
+
+ def hasNext: Boolean = {
+ if(node ne null) true
+ else {
+ while(i < len) {
+ val n = table(i)
+ i += 1
+ if(n ne null) { node = n; return true }
+ }
+ false
+ }
+ }
+
+ def next(): B =
+ if(!hasNext) Iterator.empty.next()
+ else {
+ val r = extract(node)
+ node = node.next
+ r
+ }
+ }
+
+ override def iterator: Iterator[A] = new HashSetIterator[A] {
+ override protected[this] def extract(nd: Node[A]): A = nd.key
+ }
+
+ /** Returns an iterator over the nodes stored in this HashSet */
+ private[collection] def nodeIterator: Iterator[Node[A]] = new HashSetIterator[Node[A]] {
+ override protected[this] def extract(nd: Node[A]): Node[A] = nd
+ }
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit = {
+ import convert.impl._
+ val s = shape.shape match {
+ case StepperShape.IntShape => new IntTableStepper[Node[A]] (size, table, _.next, _.key.asInstanceOf[Int], 0, table.length)
+ case StepperShape.LongShape => new LongTableStepper[Node[A]] (size, table, _.next, _.key.asInstanceOf[Long], 0, table.length)
+ case StepperShape.DoubleShape => new DoubleTableStepper[Node[A]](size, table, _.next, _.key.asInstanceOf[Double], 0, table.length)
+ case _ => shape.parUnbox(new AnyTableStepper[A, Node[A]](size, table, _.next, _.key, 0, table.length))
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ private[this] def growTable(newlen: Int) = {
+ var oldlen = table.length
+ threshold = newThreshold(newlen)
+ if(size == 0) table = new Array(newlen)
+ else {
+ table = java.util.Arrays.copyOf(table, newlen)
+ val preLow: Node[A] = new Node(null.asInstanceOf[A], 0, null)
+ val preHigh: Node[A] = new Node(null.asInstanceOf[A], 0, null)
+ // Split buckets until the new length has been reached. This could be done more
+ // efficiently when growing an already filled table to more than double the size.
+ while(oldlen < newlen) {
+ var i = 0
+ while (i < oldlen) {
+ val old = table(i)
+ if(old ne null) {
+ preLow.next = null
+ preHigh.next = null
+ var lastLow: Node[A] = preLow
+ var lastHigh: Node[A] = preHigh
+ var n = old
+ while(n ne null) {
+ val next = n.next
+ if((n.hash & oldlen) == 0) { // keep low
+ lastLow.next = n
+ lastLow = n
+ } else { // move to high
+ lastHigh.next = n
+ lastHigh = n
+ }
+ n = next
+ }
+ lastLow.next = null
+ if(old ne preLow.next) table(i) = preLow.next
+ if(preHigh.next ne null) {
+ table(i + oldlen) = preHigh.next
+ lastHigh.next = null
+ }
+ }
+ i += 1
+ }
+ oldlen *= 2
+ }
+ }
+ }
+
+ override def filterInPlace(p: A => Boolean): this.type = {
+ if (nonEmpty) {
+ var bucket = 0
+
+ while (bucket < table.length) {
+ var head = table(bucket)
+
+ while ((head ne null) && !p(head.key)) {
+ head = head.next
+ contentSize -= 1
+ }
+
+ if (head ne null) {
+ var prev = head
+ var next = head.next
+
+ while (next ne null) {
+ if (p(next.key)) {
+ prev = next
+ } else {
+ prev.next = next.next
+ contentSize -= 1
+ }
+ next = next.next
+ }
+ }
+
+ table(bucket) = head
+ bucket += 1
+ }
+ }
+ this
+ }
+
+ /*
+ private[mutable] def checkTable(): Unit = {
+ var i = 0
+ var count = 0
+ var prev: Node[A] = null
+ while(i < table.length) {
+ var n = table(i)
+ prev = null
+ while(n != null) {
+ count += 1
+ assert(index(n.hash) == i)
+ if(prev ne null) assert(prev.hash <= n.hash)
+ prev = n
+ n = n.next
+ }
+ i += 1
+ }
+ assert(contentSize == count)
+ }
+ */
+
+ private[this] def tableSizeFor(capacity: Int) =
+ (Integer.highestOneBit((capacity-1).max(4))*2).min(1 << 30)
+
+ private[this] def newThreshold(size: Int) = (size.toDouble * loadFactor).toInt
+
+ def clear(): Unit = {
+ java.util.Arrays.fill(table.asInstanceOf[Array[AnyRef]], null)
+ contentSize = 0
+ }
+
+ override def iterableFactory: IterableFactory[HashSet] = HashSet
+
+ @`inline` def addOne(elem: A): this.type = { add(elem); this }
+
+ @`inline` def subtractOne(elem: A): this.type = { remove(elem); this }
+
+ override def knownSize: Int = size
+
+ override def isEmpty: Boolean = size == 0
+
+ override def foreach[U](f: A => U): Unit = {
+ val len = table.length
+ var i = 0
+ while(i < len) {
+ val n = table(i)
+ if(n ne null) n.foreach(f)
+ i += 1
+ }
+ }
+
+ protected[this] def writeReplace(): AnyRef = new DefaultSerializationProxy(new HashSet.DeserializationFactory[A](table.length, loadFactor), this)
+
+ override protected[this] def className = "HashSet"
+
+ override def hashCode: Int = {
+ val setIterator = this.iterator
+ val hashIterator: Iterator[Any] =
+ if (setIterator.isEmpty) setIterator
+ else new HashSetIterator[Any] {
+ var hash: Int = 0
+ override def hashCode: Int = hash
+ override protected[this] def extract(nd: Node[A]): Any = {
+ hash = unimproveHash(nd.hash)
+ this
+ }
+ }
+ MurmurHash3.unorderedHash(hashIterator, MurmurHash3.setSeed)
+ }
+}
+
+/**
+ * $factoryInfo
+ * @define Coll `mutable.HashSet`
+ * @define coll mutable hash set
+ */
+@SerialVersionUID(3L)
+object HashSet extends IterableFactory[HashSet] {
+
+ def from[B](it: scala.collection.IterableOnce[B]): HashSet[B] = {
+ val k = it.knownSize
+ val cap = if(k > 0) ((k + 1).toDouble / defaultLoadFactor).toInt else defaultInitialCapacity
+ new HashSet[B](cap, defaultLoadFactor) ++= it
+ }
+
+ def empty[A]: HashSet[A] = new HashSet[A]
+
+ def newBuilder[A]: Builder[A, HashSet[A]] = newBuilder(defaultInitialCapacity, defaultLoadFactor)
+
+ def newBuilder[A](initialCapacity: Int, loadFactor: Double): Builder[A, HashSet[A]] =
+ new GrowableBuilder[A, HashSet[A]](new HashSet[A](initialCapacity, loadFactor)) {
+ override def sizeHint(size: Int) = elems.sizeHint(size)
+ }
+
+ /** The default load factor for the hash table */
+ final def defaultLoadFactor: Double = 0.75
+
+ /** The default initial capacity for the hash table */
+ final def defaultInitialCapacity: Int = 16
+
+ @SerialVersionUID(3L)
+ private final class DeserializationFactory[A](val tableLength: Int, val loadFactor: Double) extends Factory[A, HashSet[A]] with Serializable {
+ def fromSpecific(it: IterableOnce[A]): HashSet[A] = new HashSet[A](tableLength, loadFactor) ++= it
+ def newBuilder: Builder[A, HashSet[A]] = HashSet.newBuilder(tableLength, loadFactor)
+ }
+
+ private[collection] final class Node[K](_key: K, _hash: Int, private[this] var _next: Node[K]) {
+ def key: K = _key
+ def hash: Int = _hash
+ def next: Node[K] = _next
+ def next_= (n: Node[K]): Unit = _next = n
+
+ @tailrec
+ def findNode(k: K, h: Int): Node[K] =
+ if(h == _hash && k == _key) this
+ else if((_next eq null) || (_hash > h)) null
+ else _next.findNode(k, h)
+
+ @tailrec
+ def foreach[U](f: K => U): Unit = {
+ f(_key)
+ if(_next ne null) _next.foreach(f)
+ }
+
+ override def toString = s"Node($key, $hash) -> $next"
+ }
+}
diff --git a/library/src/scala/collection/mutable/HashTable.scala b/library/src/scala/collection/mutable/HashTable.scala
new file mode 100644
index 000000000000..d58f6e01b7ac
--- /dev/null
+++ b/library/src/scala/collection/mutable/HashTable.scala
@@ -0,0 +1,417 @@
+/*
+ * 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 collection.mutable
+
+import collection.{AbstractIterator, Iterator}
+
+import java.lang.Integer.{numberOfLeadingZeros, rotateRight}
+import scala.util.hashing.byteswap32
+
+import java.lang.Integer
+
+/** This class can be used to construct data structures that are based
+ * on hashtables. Class `HashTable[A]` implements a hashtable
+ * that maps keys of type `A` to values of the fully abstract
+ * member type `Entry`. Classes that make use of `HashTable`
+ * have to provide an implementation for `Entry`.
+ *
+ * There are mainly two parameters that affect the performance of a hashtable:
+ * the initial size and the load factor. The size
+ * refers to the number of buckets in the hashtable, and the load
+ * factor is a measure of how full the hashtable is allowed to get before
+ * its size is automatically doubled. Both parameters may be changed by
+ * overriding the corresponding values in class `HashTable`.
+ *
+ * @tparam A type of the elements contained in this hash table.
+ */
+// Not used in the standard library, but used in scala-parallel-collections
+private[collection] trait HashTable[A, B, Entry >: Null <: HashEntry[A, Entry]] extends HashTable.HashUtils[A] {
+ // Replacing Entry type parameter by abstract type member here allows to not expose to public
+ // implementation-specific entry classes such as `DefaultEntry` or `LinkedEntry`.
+ // However, I'm afraid it's too late now for such breaking change.
+ import HashTable._
+
+ protected var _loadFactor = defaultLoadFactor
+
+ /** The actual hash table.
+ */
+ protected[collection] var table: Array[HashEntry[A, Entry]] = new Array(initialCapacity)
+
+ /** The number of mappings contained in this hash table.
+ */
+ protected[collection] var tableSize: Int = 0
+
+ final def size: Int = tableSize
+
+ /** The next size value at which to resize (capacity * load factor).
+ */
+ protected[collection] var threshold: Int = initialThreshold(_loadFactor)
+
+ /** The array keeping track of the number of elements in 32 element blocks.
+ */
+ protected var sizemap: Array[Int] = null
+
+ protected var seedvalue: Int = tableSizeSeed
+
+ protected def tableSizeSeed = Integer.bitCount(table.length - 1)
+
+ /** The initial size of the hash table.
+ */
+ protected def initialSize: Int = 16
+
+ /** The initial threshold.
+ */
+ private def initialThreshold(_loadFactor: Int): Int = newThreshold(_loadFactor, initialCapacity)
+
+ private def initialCapacity = capacity(initialSize)
+
+ private def lastPopulatedIndex = {
+ var idx = table.length - 1
+ while (table(idx) == null && idx > 0)
+ idx -= 1
+
+ idx
+ }
+
+ /**
+ * Initializes the collection from the input stream. `readEntry` will be called for each
+ * entry to be read from the input stream.
+ */
+ private[collection] def init(in: java.io.ObjectInputStream, readEntry: => Entry): Unit = {
+ _loadFactor = in.readInt()
+ assert(_loadFactor > 0)
+
+ val size = in.readInt()
+ tableSize = 0
+ assert(size >= 0)
+
+ seedvalue = in.readInt()
+
+ val smDefined = in.readBoolean()
+
+ table = new Array(capacity(sizeForThreshold(_loadFactor, size)))
+ threshold = newThreshold(_loadFactor, table.length)
+
+ if (smDefined) sizeMapInit(table.length) else sizemap = null
+
+ var index = 0
+ while (index < size) {
+ addEntry(readEntry)
+ index += 1
+ }
+ }
+
+ /**
+ * Serializes the collection to the output stream by saving the load factor, collection
+ * size and collection entries. `writeEntry` is responsible for writing an entry to the stream.
+ *
+ * `foreachEntry` determines the order in which the key/value pairs are saved to the stream. To
+ * deserialize, `init` should be used.
+ */
+ private[collection] def serializeTo(out: java.io.ObjectOutputStream, writeEntry: Entry => Unit): Unit = {
+ out.writeInt(_loadFactor)
+ out.writeInt(tableSize)
+ out.writeInt(seedvalue)
+ out.writeBoolean(isSizeMapDefined)
+
+ foreachEntry(writeEntry)
+ }
+
+ /** Find entry with given key in table, null if not found.
+ */
+ final def findEntry(key: A): Entry =
+ findEntry0(key, index(elemHashCode(key)))
+
+ protected[collection] final def findEntry0(key: A, h: Int): Entry = {
+ var e = table(h).asInstanceOf[Entry]
+ while (e != null && !elemEquals(e.key, key)) e = e.next
+ e
+ }
+
+ /** Add entry to table
+ * pre: no entry with same key exists
+ */
+ protected[collection] final def addEntry(e: Entry): Unit = {
+ addEntry0(e, index(elemHashCode(e.key)))
+ }
+
+ protected[collection] final def addEntry0(e: Entry, h: Int): Unit = {
+ e.next = table(h).asInstanceOf[Entry]
+ table(h) = e
+ tableSize = tableSize + 1
+ nnSizeMapAdd(h)
+ if (tableSize > threshold)
+ resize(2 * table.length)
+ }
+
+ /** Find entry with given key in table, or add new one if not found.
+ * May be somewhat faster then `findEntry`/`addEntry` pair as it
+ * computes entry's hash index only once.
+ * Returns entry found in table or null.
+ * New entries are created by calling `createNewEntry` method.
+ */
+ def findOrAddEntry(key: A, value: B): Entry = {
+ val h = index(elemHashCode(key))
+ val e = findEntry0(key, h)
+ if (e ne null) e else { addEntry0(createNewEntry(key, value), h); null }
+ }
+
+ /** Creates new entry to be immediately inserted into the hashtable.
+ * This method is guaranteed to be called only once and in case that the entry
+ * will be added. In other words, an implementation may be side-effecting.
+ */
+ def createNewEntry(key: A, value: B): Entry
+
+ /** Remove entry from table if present.
+ */
+ final def removeEntry(key: A) : Entry = {
+ removeEntry0(key, index(elemHashCode(key)))
+ }
+ /** Remove entry from table if present.
+ */
+ private[collection] final def removeEntry0(key: A, h: Int) : Entry = {
+ var e = table(h).asInstanceOf[Entry]
+ if (e != null) {
+ if (elemEquals(e.key, key)) {
+ table(h) = e.next
+ tableSize = tableSize - 1
+ nnSizeMapRemove(h)
+ e.next = null
+ return e
+ } else {
+ var e1 = e.next
+ while (e1 != null && !elemEquals(e1.key, key)) {
+ e = e1
+ e1 = e1.next
+ }
+ if (e1 != null) {
+ e.next = e1.next
+ tableSize = tableSize - 1
+ nnSizeMapRemove(h)
+ e1.next = null
+ return e1
+ }
+ }
+ }
+ null
+ }
+
+ /** An iterator returning all entries.
+ */
+ def entriesIterator: Iterator[Entry] = new AbstractIterator[Entry] {
+ val iterTable = table
+ var idx = lastPopulatedIndex
+ var es = iterTable(idx)
+
+ def hasNext = es != null
+ def next() = {
+ val res = es
+ es = es.next
+ while (es == null && idx > 0) {
+ idx = idx - 1
+ es = iterTable(idx)
+ }
+ res.asInstanceOf[Entry]
+ }
+ }
+
+ /** Avoid iterator for a 2x faster traversal. */
+ def foreachEntry[U](f: Entry => U): Unit = {
+ val iterTable = table
+ var idx = lastPopulatedIndex
+ var es = iterTable(idx)
+
+ while (es != null) {
+ val next = es.next // Cache next in case f removes es.
+ f(es.asInstanceOf[Entry])
+ es = next
+
+ while (es == null && idx > 0) {
+ idx -= 1
+ es = iterTable(idx)
+ }
+ }
+ }
+
+ /** Remove all entries from table
+ */
+ def clearTable(): Unit = {
+ var i = table.length - 1
+ while (i >= 0) { table(i) = null; i = i - 1 }
+ tableSize = 0
+ nnSizeMapReset(0)
+ }
+
+ private def resize(newSize: Int): Unit = {
+ val oldTable = table
+ table = new Array(newSize)
+ nnSizeMapReset(table.length)
+ var i = oldTable.length - 1
+ while (i >= 0) {
+ var e = oldTable(i)
+ while (e != null) {
+ val h = index(elemHashCode(e.key))
+ val e1 = e.next
+ e.next = table(h).asInstanceOf[Entry]
+ table(h) = e
+ e = e1
+ nnSizeMapAdd(h)
+ }
+ i = i - 1
+ }
+ threshold = newThreshold(_loadFactor, newSize)
+ }
+
+ /* Size map handling code */
+
+ /*
+ * The following three sizeMap* functions (Add, Remove, Reset)
+ * are used to update the size map of the hash table.
+ *
+ * The size map logically divides the hash table into `sizeMapBucketSize` element buckets
+ * by keeping an integer entry for each such bucket. Each integer entry simply denotes
+ * the number of elements in the corresponding bucket.
+ * Best understood through an example, see:
+ * table = [/, 1, /, 6, 90, /, -3, 5] (8 entries)
+ * sizemap = [ 2 | 3 ] (2 entries)
+ * where sizeMapBucketSize == 4.
+ *
+ * By default the size map is not initialized, so these methods don't do anything, thus,
+ * their impact on hash table performance is negligible. However, if the hash table
+ * is converted into a parallel hash table, the size map is initialized, as it will be needed
+ * there.
+ */
+ protected final def nnSizeMapAdd(h: Int) = if (sizemap ne null) {
+ sizemap(h >> sizeMapBucketBitSize) += 1
+ }
+
+ protected final def nnSizeMapRemove(h: Int) = if (sizemap ne null) {
+ sizemap(h >> sizeMapBucketBitSize) -= 1
+ }
+
+ protected final def nnSizeMapReset(tableLength: Int) = if (sizemap ne null) {
+ val nsize = calcSizeMapSize(tableLength)
+ if (sizemap.length != nsize) sizemap = new Array[Int](nsize)
+ else java.util.Arrays.fill(sizemap, 0)
+ }
+
+ private[collection] final def totalSizeMapBuckets = if (sizeMapBucketSize < table.length) 1 else table.length / sizeMapBucketSize
+
+ protected final def calcSizeMapSize(tableLength: Int) = (tableLength >> sizeMapBucketBitSize) + 1
+
+ // discards the previous sizemap and only allocates a new one
+ protected def sizeMapInit(tableLength: Int): Unit = {
+ sizemap = new Array[Int](calcSizeMapSize(tableLength))
+ }
+
+ // discards the previous sizemap and populates the new one
+ protected final def sizeMapInitAndRebuild() = {
+ sizeMapInit(table.length)
+
+ // go through the buckets, count elements
+ var tableidx = 0
+ var bucketidx = 0
+ val tbl = table
+ var tableuntil = 0
+ if (tbl.length < sizeMapBucketSize) tableuntil = tbl.length else tableuntil = sizeMapBucketSize
+ val totalbuckets = totalSizeMapBuckets
+ while (bucketidx < totalbuckets) {
+ var currbucketsize = 0
+ while (tableidx < tableuntil) {
+ var e = tbl(tableidx)
+ while (e ne null) {
+ currbucketsize += 1
+ e = e.next
+ }
+ tableidx += 1
+ }
+ sizemap(bucketidx) = currbucketsize
+ tableuntil += sizeMapBucketSize
+ bucketidx += 1
+ }
+ }
+
+ private[collection] def printSizeMap() = {
+ println(sizemap.to(collection.immutable.List))
+ }
+
+ protected final def sizeMapDisable() = sizemap = null
+
+ protected final def isSizeMapDefined = sizemap ne null
+
+ // override to automatically initialize the size map
+ protected def alwaysInitSizeMap = false
+
+ /* End of size map handling code */
+
+ protected def elemEquals(key1: A, key2: A): Boolean = (key1 == key2)
+
+ /**
+ * Note: we take the most significant bits of the hashcode, not the lower ones
+ * this is of crucial importance when populating the table in parallel
+ */
+ protected[collection] final def index(hcode: Int): Int = {
+ val ones = table.length - 1
+ val exponent = Integer.numberOfLeadingZeros(ones)
+ (improve(hcode, seedvalue) >>> exponent) & ones
+ }
+}
+
+private[collection] object HashTable {
+ /** The load factor for the hash table (in 0.001 step).
+ */
+ private[collection] final def defaultLoadFactor: Int = 750 // corresponds to 75%
+ private[collection] final def loadFactorDenum = 1000 // should be loadFactorDenom, but changing that isn't binary compatible
+
+ private[collection] final def newThreshold(_loadFactor: Int, size: Int) = ((size.toLong * _loadFactor) / loadFactorDenum).toInt
+
+ private[collection] final def sizeForThreshold(_loadFactor: Int, thr: Int) = ((thr.toLong * loadFactorDenum) / _loadFactor).toInt
+
+ private[collection] final def capacity(expectedSize: Int) = nextPositivePowerOfTwo(expectedSize)
+
+ trait HashUtils[KeyType] {
+ protected final def sizeMapBucketBitSize = 5
+ // so that:
+ protected final def sizeMapBucketSize = 1 << sizeMapBucketBitSize
+
+ protected[collection] def elemHashCode(key: KeyType) = key.##
+
+ /**
+ * Defer to a high-quality hash in [[scala.util.hashing]].
+ * The goal is to distribute across bins as well as possible even if a hash code has low entropy at some bits.
+ *
+ * OLD VERSION - quick, but bad for sequence 0-10000 - little entropy in higher bits - since 2003
+ * {{{
+ * var h: Int = hcode + ~(hcode << 9)
+ * h = h ^ (h >>> 14)
+ * h = h + (h << 4)
+ * h ^ (h >>> 10)
+ * }}}
+ * the rest of the computation is due to SI-5293
+ */
+ protected final def improve(hcode: Int, seed: Int): Int = rotateRight(byteswap32(hcode), seed)
+ }
+
+ /**
+ * Returns a power of two >= `target`.
+ */
+ private[collection] def nextPositivePowerOfTwo(target: Int): Int = 1 << -numberOfLeadingZeros(target - 1)
+}
+
+/** Class used internally.
+ */
+private[collection] trait HashEntry[A, E <: HashEntry[A, E]] {
+ val key: A
+ var next: E = _
+}
diff --git a/library/src/scala/collection/mutable/ImmutableBuilder.scala b/library/src/scala/collection/mutable/ImmutableBuilder.scala
new file mode 100644
index 000000000000..3907cfd55305
--- /dev/null
+++ b/library/src/scala/collection/mutable/ImmutableBuilder.scala
@@ -0,0 +1,31 @@
+/*
+ * 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 collection
+package mutable
+
+
+/**
+ * Reusable builder for immutable collections
+ */
+abstract class ImmutableBuilder[-A, C <: IterableOnce[_]](empty: C)
+ extends ReusableBuilder[A, C] {
+
+ protected var elems: C = empty
+
+ def clear(): Unit = { elems = empty }
+
+ def result(): C = elems
+
+ override def knownSize: Int = elems.knownSize
+}
diff --git a/library/src/scala/collection/mutable/IndexedSeq.scala b/library/src/scala/collection/mutable/IndexedSeq.scala
new file mode 100644
index 000000000000..464bc00d45db
--- /dev/null
+++ b/library/src/scala/collection/mutable/IndexedSeq.scala
@@ -0,0 +1,83 @@
+/*
+ * 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 mutable
+
+trait IndexedSeq[T] extends Seq[T]
+ with scala.collection.IndexedSeq[T]
+ with IndexedSeqOps[T, IndexedSeq, IndexedSeq[T]]
+ with IterableFactoryDefaults[T, IndexedSeq] {
+
+ override def iterableFactory: SeqFactory[IndexedSeq] = IndexedSeq
+}
+
+@SerialVersionUID(3L)
+object IndexedSeq extends SeqFactory.Delegate[IndexedSeq](ArrayBuffer)
+
+trait IndexedSeqOps[A, +CC[_], +C <: AnyRef]
+ extends scala.collection.IndexedSeqOps[A, CC, C]
+ with SeqOps[A, CC, C] {
+
+ /** Modifies this $coll by applying a function to all elements of this $coll.
+ *
+ * @param f the function to apply to each element.
+ * @return this $coll modified by replacing all elements with the
+ * result of applying the given function `f` to each element
+ * of this $coll.
+ */
+ def mapInPlace(f: A => A): this.type = {
+ var i = 0
+ val siz = size
+ while (i < siz) { this(i) = f(this(i)); i += 1 }
+ this
+ }
+
+ /** Sorts this $coll in place according to an Ordering.
+ *
+ * @see [[scala.collection.SeqOps.sorted]]
+ * @param ord the ordering to be used to compare elements.
+ * @return modified input $coll sorted according to the ordering `ord`.
+ */
+ def sortInPlace[B >: A]()(implicit ord: Ordering[B]): this.type = {
+ val len = this.length
+ if (len > 1) {
+ val arr = new Array[AnyRef](len)
+ var i = 0
+ for (x <- this) {
+ arr(i) = x.asInstanceOf[AnyRef]
+ i += 1
+ }
+ java.util.Arrays.sort(arr, ord.asInstanceOf[Ordering[Object]])
+ i = 0
+ while (i < arr.length) {
+ update(i, arr(i).asInstanceOf[A])
+ i += 1
+ }
+ }
+ this
+ }
+
+ /** Sorts this $coll in place according to a comparison function.
+ *
+ * @see [[scala.collection.SeqOps.sortWith]]
+ */
+ def sortInPlaceWith(lt: (A, A) => Boolean): this.type = sortInPlace()(Ordering.fromLessThan(lt))
+
+ /** Sorts this $coll in place according to the Ordering which results from transforming
+ * an implicitly given Ordering with a transformation function.
+ *
+ * @see [[scala.collection.SeqOps.sortBy]]
+ */
+ def sortInPlaceBy[B](f: A => B)(implicit ord: Ordering[B]): this.type = sortInPlace()(ord on f)
+
+}
diff --git a/library/src/scala/collection/mutable/Iterable.scala b/library/src/scala/collection/mutable/Iterable.scala
new file mode 100644
index 000000000000..c84d0e6ec675
--- /dev/null
+++ b/library/src/scala/collection/mutable/Iterable.scala
@@ -0,0 +1,34 @@
+/*
+ * 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.mutable
+
+import scala.collection.{IterableFactory, IterableFactoryDefaults}
+
+trait Iterable[A]
+ extends collection.Iterable[A]
+ with collection.IterableOps[A, Iterable, Iterable[A]]
+ with IterableFactoryDefaults[A, Iterable] {
+
+ override def iterableFactory: IterableFactory[Iterable] = Iterable
+}
+
+/**
+ * $factoryInfo
+ * @define coll mutable collection
+ * @define Coll `mutable.Iterable`
+ */
+@SerialVersionUID(3L)
+object Iterable extends IterableFactory.Delegate[Iterable](ArrayBuffer)
+
+/** Explicit instantiation of the `Iterable` trait to reduce class file size in subclasses. */
+abstract class AbstractIterable[A] extends scala.collection.AbstractIterable[A] with Iterable[A]
diff --git a/library/src/scala/collection/mutable/LinkedHashMap.scala b/library/src/scala/collection/mutable/LinkedHashMap.scala
new file mode 100644
index 000000000000..d529fee42596
--- /dev/null
+++ b/library/src/scala/collection/mutable/LinkedHashMap.scala
@@ -0,0 +1,509 @@
+/*
+ * 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 collection
+package mutable
+
+import scala.annotation.{nowarn, tailrec}
+import scala.collection.generic.DefaultSerializable
+import scala.util.hashing.MurmurHash3
+
+
+/** This class implements mutable maps using a hashtable.
+ * The iterator and all traversal methods of this class visit elements in the order they were inserted.
+ *
+ * @tparam K the type of the keys contained in this hash map.
+ * @tparam V the type of the values assigned to keys in this hash map.
+ *
+ * @define Coll `LinkedHashMap`
+ * @define coll linked hash map
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ * @define orderDependent
+ * @define orderDependentFold
+ */
+@deprecatedInheritance("LinkedHashMap will be made final; use .withDefault for the common use case of computing a default value", "2.13.11")
+class LinkedHashMap[K, V]
+ extends AbstractMap[K, V]
+ with SeqMap[K, V]
+ with MapOps[K, V, LinkedHashMap, LinkedHashMap[K, V]]
+ with StrictOptimizedIterableOps[(K, V), Iterable, LinkedHashMap[K, V]]
+ with StrictOptimizedMapOps[K, V, LinkedHashMap, LinkedHashMap[K, V]]
+ with MapFactoryDefaults[K, V, LinkedHashMap, Iterable]
+ with DefaultSerializable {
+
+ override def mapFactory: MapFactory[LinkedHashMap] = LinkedHashMap
+
+ // stepper / keyStepper / valueStepper are not overridden to use XTableStepper because that stepper
+ // would not return the elements in insertion order
+
+ private[collection] type Entry = LinkedHashMap.LinkedEntry[K, V]
+
+ private[collection] def _firstEntry: Entry = firstEntry
+
+ protected var firstEntry: Entry = null
+
+ protected var lastEntry: Entry = null
+
+ /* Uses the same implementation as mutable.HashMap. The hashtable holds the following invariant:
+ * - For each i between 0 and table.length, the bucket at table(i) only contains keys whose hash-index is i.
+ * - Every bucket is sorted in ascendant hash order
+ * - The sum of the lengths of all buckets is equal to contentSize.
+ */
+ private[this] var table = new Array[Entry](tableSizeFor(LinkedHashMap.defaultinitialSize))
+
+ private[this] var threshold: Int = newThreshold(table.length)
+
+ private[this] var contentSize = 0
+
+ override def last: (K, V) =
+ if (size > 0) (lastEntry.key, lastEntry.value)
+ else throw new NoSuchElementException("Cannot call .last on empty LinkedHashMap")
+
+ override def lastOption: Option[(K, V)] =
+ if (size > 0) Some((lastEntry.key, lastEntry.value))
+ else None
+
+ override def head: (K, V) =
+ if (size > 0) (firstEntry.key, firstEntry.value)
+ else throw new NoSuchElementException("Cannot call .head on empty LinkedHashMap")
+
+ override def headOption: Option[(K, V)] =
+ if (size > 0) Some((firstEntry.key, firstEntry.value))
+ else None
+
+ override def size = contentSize
+ override def knownSize: Int = size
+ override def isEmpty: Boolean = size == 0
+
+ def get(key: K): Option[V] = {
+ val e = findEntry(key)
+ if (e == null) None
+ else Some(e.value)
+ }
+ override def sizeHint(size: Int): Unit = {
+ val target = tableSizeFor(((size + 1).toDouble / LinkedHashMap.defaultLoadFactor).toInt)
+ if (target > table.length) growTable(target)
+ }
+
+ override def contains(key: K): Boolean = {
+ if (getClass eq classOf[LinkedHashMap[_, _]])
+ findEntry(key) != null
+ else
+ super.contains(key) // A subclass might override `get`, use the default implementation `contains`.
+ }
+
+ override def put(key: K, value: V): Option[V] = put0(key, value, getOld = true) match {
+ case null => None
+ case sm => sm
+ }
+
+ override def update(key: K, value: V): Unit = put0(key, value, getOld = false)
+
+ override def remove(key: K): Option[V] = removeEntry0(key) match {
+ case null => None
+ case nd => Some(nd.value)
+ }
+
+ override def getOrElse[V1 >: V](key: K, default: => V1): V1 = {
+ if (getClass != classOf[LinkedHashMap[_, _]]) {
+ // subclasses of LinkedHashMap might customise `get` ...
+ super.getOrElse(key, default)
+ } else {
+ // .. but in the common case, we can avoid the Option boxing.
+ val nd = findEntry(key)
+ if (nd eq null) default else nd.value
+ }
+ }
+
+ override def getOrElseUpdate(key: K, defaultValue: => V): V = {
+ if (getClass != classOf[LinkedHashMap[_, _]]) {
+ // subclasses of LinkedHashMap might customise `get` ...
+ super.getOrElseUpdate(key, defaultValue)
+ } else {
+ val hash = computeHash(key)
+ val idx = index(hash)
+ val nd = table(idx) match {
+ case null => null
+ case nd => nd.findEntry(key, hash)
+ }
+ if (nd != null) nd.value
+ else {
+ val table0 = table
+ val default = defaultValue
+ if (contentSize + 1 >= threshold) growTable(table.length * 2)
+ // Avoid recomputing index if the `defaultValue()` or new element hasn't triggered a table resize.
+ val newIdx = if (table0 eq table) idx else index(hash)
+ put0(key, default, getOld = false, hash, newIdx)
+ default
+ }
+ }
+ }
+
+ private[this] def removeEntry0(elem: K): Entry = removeEntry0(elem, computeHash(elem))
+
+ /** Removes a key from this map if it exists
+ *
+ * @param elem the element to remove
+ * @param hash the **improved** hashcode of `element` (see computeHash)
+ * @return the node that contained element if it was present, otherwise null
+ */
+ private[this] def removeEntry0(elem: K, hash: Int): Entry = {
+ val idx = index(hash)
+ table(idx) match {
+ case null => null
+ case nd if nd.hash == hash && nd.key == elem =>
+ // first element matches
+ table(idx) = nd.next
+ deleteEntry(nd)
+ contentSize -= 1
+ nd
+ case nd =>
+ // find an element that matches
+ var prev = nd
+ var next = nd.next
+ while ((next ne null) && next.hash <= hash) {
+ if (next.hash == hash && next.key == elem) {
+ prev.next = next.next
+ deleteEntry(next)
+ contentSize -= 1
+ return next
+ }
+ prev = next
+ next = next.next
+ }
+ null
+ }
+ }
+
+ /** Computes the improved hash of an original (`any.##`) hash. */
+ @`inline` private[this] def improveHash(originalHash: Int): Int = {
+ originalHash ^ (originalHash >>> 16)
+ }
+ @`inline` private[collection] def unimproveHash(improvedHash: Int): Int = improveHash(improvedHash)
+
+ /** Computes the improved hash of this key */
+ @`inline` private[this] def computeHash(o: K): Int = improveHash(o.##)
+
+ @`inline` private[this] def index(hash: Int) = hash & (table.length - 1)
+
+ @`inline` private[this] def findEntry(key: K): Entry = {
+ val hash = computeHash(key)
+ table(index(hash)) match {
+ case null => null
+ case nd => nd.findEntry(key, hash)
+ }
+ }
+
+ def addOne(kv: (K, V)): this.type = {
+ put(kv._1, kv._2)
+ this
+ }
+
+ def subtractOne(key: K): this.type = {
+ remove(key)
+ this
+ }
+
+ private[this] abstract class LinkedHashMapIterator[T] extends AbstractIterator[T] {
+ private[this] var cur = firstEntry
+ def extract(nd: Entry): T
+ def hasNext: Boolean = cur ne null
+ def next(): T =
+ if (hasNext) { val r = extract(cur); cur = cur.later; r }
+ else Iterator.empty.next()
+ }
+
+ def iterator: Iterator[(K, V)] =
+ if (size == 0) Iterator.empty
+ else new LinkedHashMapIterator[(K, V)] {
+ def extract(nd: Entry): (K, V) = (nd.key, nd.value)
+ }
+
+ protected class LinkedKeySet extends KeySet {
+ override def iterableFactory: IterableFactory[collection.Set] = LinkedHashSet
+ }
+
+ override def keySet: collection.Set[K] = new LinkedKeySet
+
+ override def keysIterator: Iterator[K] =
+ if (size == 0) Iterator.empty
+ else new LinkedHashMapIterator[K] {
+ def extract(nd: Entry): K = nd.key
+ }
+
+ private[collection] def entryIterator: Iterator[Entry] =
+ if (size == 0) Iterator.empty
+ else new LinkedHashMapIterator[Entry] {
+ def extract(nd: Entry): Entry = nd
+ }
+
+
+ // Override updateWith for performance, so we can do the update while hashing
+ // the input key only once and performing one lookup into the hash table
+ override def updateWith(key: K)(remappingFunction: Option[V] => Option[V]): Option[V] = {
+ if (getClass != classOf[LinkedHashMap[_, _]]) {
+ // subclasses of LinkedHashMap might customise `get` ...
+ super.updateWith(key)(remappingFunction)
+ } else {
+ val hash = computeHash(key)
+ val indexedHash = index(hash)
+
+ var foundEntry: Entry = null
+ var previousEntry: Entry = null
+ table(indexedHash) match {
+ case null =>
+ case nd =>
+ @tailrec
+ def findEntry(prev: Entry, nd: Entry, k: K, h: Int): Unit = {
+ if (h == nd.hash && k == nd.key) {
+ previousEntry = prev
+ foundEntry = nd
+ }
+ else if ((nd.next eq null) || (nd.hash > h)) ()
+ else findEntry(nd, nd.next, k, h)
+ }
+
+ findEntry(null, nd, key, hash)
+ }
+
+ val previousValue = foundEntry match {
+ case null => None
+ case nd => Some(nd.value)
+ }
+
+ val nextValue = remappingFunction(previousValue)
+
+ (previousValue, nextValue) match {
+ case (None, None) => // do nothing
+
+ case (Some(_), None) =>
+ if (previousEntry != null) previousEntry.next = foundEntry.next
+ else table(indexedHash) = foundEntry.next
+ deleteEntry(foundEntry)
+ contentSize -= 1
+
+ case (None, Some(value)) =>
+ val newIndexedHash =
+ if (contentSize + 1 >= threshold) {
+ growTable(table.length * 2)
+ index(hash)
+ } else indexedHash
+ put0(key, value, getOld = false, hash, newIndexedHash)
+
+ case (Some(_), Some(newValue)) => foundEntry.value = newValue
+ }
+ nextValue
+ }
+ }
+
+ override def valuesIterator: Iterator[V] =
+ if (size == 0) Iterator.empty
+ else new LinkedHashMapIterator[V] {
+ def extract(nd: Entry): V = nd.value
+ }
+
+
+ override def foreach[U](f: ((K, V)) => U): Unit = {
+ var cur = firstEntry
+ while (cur ne null) {
+ f((cur.key, cur.value))
+ cur = cur.later
+ }
+ }
+
+ override def foreachEntry[U](f: (K, V) => U): Unit = {
+ var cur = firstEntry
+ while (cur ne null) {
+ f(cur.key, cur.value)
+ cur = cur.later
+ }
+ }
+
+ override def clear(): Unit = {
+ java.util.Arrays.fill(table.asInstanceOf[Array[AnyRef]], null)
+ contentSize = 0
+ firstEntry = null
+ lastEntry = null
+ }
+
+ private[this] def tableSizeFor(capacity: Int) =
+ (Integer.highestOneBit((capacity - 1).max(4)) * 2).min(1 << 30)
+
+ private[this] def newThreshold(size: Int) = (size.toDouble * LinkedHashMap.defaultLoadFactor).toInt
+
+ /*create a new entry. If table is empty(firstEntry is null), then the
+ * new entry will be the firstEntry. If not, just set the new entry to
+ * be the lastEntry.
+ * */
+ private[this] def createNewEntry(key: K, hash: Int, value: V): Entry = {
+ val e = new Entry(key, hash, value)
+ if (firstEntry eq null) firstEntry = e
+ else {
+ lastEntry.later = e
+ e.earlier = lastEntry
+ }
+ lastEntry = e
+ e
+ }
+
+ /** Delete the entry from the LinkedHashMap, set the `earlier` and `later` pointers correctly */
+ private[this] def deleteEntry(e: Entry): Unit = {
+ if (e.earlier eq null) firstEntry = e.later
+ else e.earlier.later = e.later
+ if (e.later eq null) lastEntry = e.earlier
+ else e.later.earlier = e.earlier
+ e.earlier = null
+ e.later = null
+ e.next = null
+ }
+
+ private[this] def put0(key: K, value: V, getOld: Boolean): Some[V] = {
+ if (contentSize + 1 >= threshold) growTable(table.length * 2)
+ val hash = computeHash(key)
+ val idx = index(hash)
+ put0(key, value, getOld, hash, idx)
+ }
+
+ private[this] def put0(key: K, value: V, getOld: Boolean, hash: Int, idx: Int): Some[V] = {
+ table(idx) match {
+ case null =>
+ table(idx) = createNewEntry(key, hash, value)
+ case old =>
+ var prev: Entry = null
+ var n = old
+ while ((n ne null) && n.hash <= hash) {
+ if (n.hash == hash && key == n.key) {
+ val old = n.value
+ n.value = value
+ return if (getOld) Some(old) else null
+ }
+ prev = n
+ n = n.next
+ }
+ val nnode = createNewEntry(key, hash, value)
+ if (prev eq null) {
+ nnode.next = old
+ table(idx) = nnode
+ } else {
+ nnode.next = prev.next
+ prev.next = nnode
+ }
+ }
+ contentSize += 1
+ null
+ }
+
+ private[this] def growTable(newlen: Int): Unit = {
+ if (newlen < 0)
+ throw new RuntimeException(s"new hash table size $newlen exceeds maximum")
+ var oldlen = table.length
+ threshold = newThreshold(newlen)
+ if (size == 0) table = new Array(newlen)
+ else {
+ table = java.util.Arrays.copyOf(table, newlen)
+ val preLow = new Entry(null.asInstanceOf[K], 0, null.asInstanceOf[V])
+ val preHigh = new Entry(null.asInstanceOf[K], 0, null.asInstanceOf[V])
+ // Split buckets until the new length has been reached. This could be done more
+ // efficiently when growing an already filled table to more than double the size.
+ while (oldlen < newlen) {
+ var i = 0
+ while (i < oldlen) {
+ val old = table(i)
+ if (old ne null) {
+ preLow.next = null
+ preHigh.next = null
+ var lastLow = preLow
+ var lastHigh = preHigh
+ var n = old
+ while (n ne null) {
+ val next = n.next
+ if ((n.hash & oldlen) == 0) { // keep low
+ lastLow.next = n
+ lastLow = n
+ } else { // move to high
+ lastHigh.next = n
+ lastHigh = n
+ }
+ n = next
+ }
+ lastLow.next = null
+ if (old ne preLow.next) table(i) = preLow.next
+ if (preHigh.next ne null) {
+ table(i + oldlen) = preHigh.next
+ lastHigh.next = null
+ }
+ }
+ i += 1
+ }
+ oldlen *= 2
+ }
+ }
+ }
+
+ override def hashCode: Int = {
+ if (isEmpty) MurmurHash3.emptyMapHash
+ else {
+ val tupleHashIterator = new LinkedHashMapIterator[Any] {
+ var hash: Int = 0
+ override def hashCode: Int = hash
+ override def extract(nd: Entry): Any = {
+ hash = MurmurHash3.tuple2Hash(unimproveHash(nd.hash), nd.value.##)
+ this
+ }
+ }
+ MurmurHash3.unorderedHash(tupleHashIterator, MurmurHash3.mapSeed)
+ }
+ }
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix = "LinkedHashMap"
+}
+
+/** $factoryInfo
+ * @define Coll `LinkedHashMap`
+ * @define coll linked hash map
+ */
+@SerialVersionUID(3L)
+object LinkedHashMap extends MapFactory[LinkedHashMap] {
+
+ def empty[K, V] = new LinkedHashMap[K, V]
+
+ def from[K, V](it: collection.IterableOnce[(K, V)]) = {
+ val newlhm = empty[K, V]
+ newlhm.sizeHint(it, delta = 0)
+ newlhm.addAll(it)
+ newlhm
+ }
+
+ def newBuilder[K, V]: GrowableBuilder[(K, V), LinkedHashMap[K, V]] = new GrowableBuilder(empty[K, V])
+
+ /** Class for the linked hash map entry, used internally.
+ */
+ private[mutable] final class LinkedEntry[K, V](val key: K, val hash: Int, var value: V) {
+ var earlier: LinkedEntry[K, V] = null
+ var later: LinkedEntry[K, V] = null
+ var next: LinkedEntry[K, V] = null
+
+ @tailrec
+ final def findEntry(k: K, h: Int): LinkedEntry[K, V] =
+ if (h == hash && k == key) this
+ else if ((next eq null) || (hash > h)) null
+ else next.findEntry(k, h)
+ }
+
+ /** The default load factor for the hash table */
+ private[collection] final def defaultLoadFactor: Double = 0.75
+
+ /** The default initial capacity for the hash table */
+ private[collection] final def defaultinitialSize: Int = 16
+}
diff --git a/library/src/scala/collection/mutable/LinkedHashSet.scala b/library/src/scala/collection/mutable/LinkedHashSet.scala
new file mode 100644
index 000000000000..1a189d607010
--- /dev/null
+++ b/library/src/scala/collection/mutable/LinkedHashSet.scala
@@ -0,0 +1,348 @@
+/*
+ * 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 collection
+package mutable
+
+import scala.annotation.{nowarn, tailrec}
+import scala.collection.generic.DefaultSerializable
+import scala.util.hashing.MurmurHash3
+
+/** This class implements mutable sets using a hashtable.
+ * The iterator and all traversal methods of this class visit elements in the order they were inserted.
+ *
+ * @tparam A the type of the elements contained in this set.
+ *
+ * @define Coll `LinkedHashSet`
+ * @define coll linked hash set
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ * @define orderDependent
+ * @define orderDependentFold
+ */
+@deprecatedInheritance("LinkedHashSet will be made final", "2.13.11")
+class LinkedHashSet[A]
+ extends AbstractSet[A]
+ with SetOps[A, LinkedHashSet, LinkedHashSet[A]]
+ with StrictOptimizedIterableOps[A, LinkedHashSet, LinkedHashSet[A]]
+ with IterableFactoryDefaults[A, LinkedHashSet]
+ with DefaultSerializable {
+
+ override def iterableFactory: IterableFactory[LinkedHashSet] = LinkedHashSet
+
+ // stepper is not overridden to use XTableStepper because that stepper would not return the
+ // elements in insertion order
+
+ /*private*/ type Entry = LinkedHashSet.Entry[A]
+
+ protected var firstEntry: Entry = null
+
+ protected var lastEntry: Entry = null
+
+ /* Uses the same implementation as mutable.HashSet. The hashtable holds the following invariant:
+ * - For each i between 0 and table.length, the bucket at table(i) only contains keys whose hash-index is i.
+ * - Every bucket is sorted in ascendant hash order
+ * - The sum of the lengths of all buckets is equal to contentSize.
+ */
+ private[this] var table = new Array[Entry](tableSizeFor(LinkedHashSet.defaultinitialSize))
+
+ private[this] var threshold: Int = newThreshold(table.length)
+
+ private[this] var contentSize = 0
+
+ override def last: A =
+ if (size > 0) lastEntry.key
+ else throw new NoSuchElementException("Cannot call .last on empty LinkedHashSet")
+
+ override def lastOption: Option[A] =
+ if (size > 0) Some(lastEntry.key)
+ else None
+
+ override def head: A =
+ if (size > 0) firstEntry.key
+ else throw new NoSuchElementException("Cannot call .head on empty LinkedHashSet")
+
+ override def headOption: Option[A] =
+ if (size > 0) Some(firstEntry.key)
+ else None
+
+ override def size: Int = contentSize
+ override def knownSize: Int = size
+ override def isEmpty: Boolean = size == 0
+
+ def contains(elem: A): Boolean = findEntry(elem) ne null
+
+ override def sizeHint(size: Int): Unit = {
+ val target = tableSizeFor(((size + 1).toDouble / LinkedHashSet.defaultLoadFactor).toInt)
+ if (target > table.length) growTable(target)
+ }
+
+ override def add(elem: A): Boolean = {
+ if (contentSize + 1 >= threshold) growTable(table.length * 2)
+ val hash = computeHash(elem)
+ put0(elem, hash, index(hash))
+ }
+
+ def addOne(elem: A): this.type = {
+ add(elem)
+ this
+ }
+
+ def subtractOne(elem: A): this.type = {
+ remove(elem)
+ this
+ }
+
+ override def remove(elem: A): Boolean = remove0(elem, computeHash(elem))
+
+ private[this] abstract class LinkedHashSetIterator[T] extends AbstractIterator[T] {
+ private[this] var cur = firstEntry
+ def extract(nd: Entry): T
+ def hasNext: Boolean = cur ne null
+ def next(): T =
+ if (hasNext) { val r = extract(cur); cur = cur.later; r }
+ else Iterator.empty.next()
+ }
+
+ def iterator: Iterator[A] = new LinkedHashSetIterator[A] {
+ override def extract(nd: Entry): A = nd.key
+ }
+
+ private[collection] def entryIterator: Iterator[Entry] = new LinkedHashSetIterator[Entry] {
+ override def extract(nd: Entry): Entry = nd
+ }
+
+ override def foreach[U](f: A => U): Unit = {
+ var cur = firstEntry
+ while (cur ne null) {
+ f(cur.key)
+ cur = cur.later
+ }
+ }
+
+ override def clear(): Unit = {
+ java.util.Arrays.fill(table.asInstanceOf[Array[AnyRef]], null)
+ contentSize = 0
+ firstEntry = null
+ lastEntry = null
+ }
+
+ private[this] def tableSizeFor(capacity: Int) =
+ (Integer.highestOneBit((capacity - 1).max(4)) * 2).min(1 << 30)
+
+ private[this] def newThreshold(size: Int) = (size.toDouble * LinkedHashSet.defaultLoadFactor).toInt
+
+ @`inline` private[this] def improveHash(originalHash: Int): Int = {
+ originalHash ^ (originalHash >>> 16)
+ }
+
+ @`inline` private[collection] def unimproveHash(improvedHash: Int): Int = improveHash(improvedHash)
+
+ /** Computes the improved hash of this key */
+ @`inline` private[this] def computeHash(o: A): Int = improveHash(o.##)
+
+ @`inline` private[this] def index(hash: Int) = hash & (table.length - 1)
+
+ @`inline` private[this] def findEntry(key: A): Entry = {
+ val hash = computeHash(key)
+ table(index(hash)) match {
+ case null => null
+ case nd => nd.findEntry(key, hash)
+ }
+ }
+
+ /*create a new entry. If table is empty(firstEntry is null), then the
+ * new entry will be the firstEntry. If not, just set the new entry to
+ * be the lastEntry.
+ * */
+ private[this] def createNewEntry(key: A, hash: Int): Entry = {
+ val e = new Entry(key, hash)
+ if (firstEntry eq null) firstEntry = e
+ else {
+ lastEntry.later = e
+ e.earlier = lastEntry
+ }
+ lastEntry = e
+ e
+ }
+
+ /** Delete the entry from the LinkedHashSet, set the `earlier` and `later` pointers correctly */
+ private[this] def deleteEntry(e: Entry): Unit = {
+ if (e.earlier eq null) firstEntry = e.later
+ else e.earlier.later = e.later
+ if (e.later eq null) lastEntry = e.earlier
+ else e.later.earlier = e.earlier
+ e.earlier = null
+ e.later = null
+ e.next = null
+ }
+
+ private[this] def put0(elem: A, hash: Int, idx: Int): Boolean = {
+ table(idx) match {
+ case null =>
+ table(idx) = createNewEntry(elem, hash)
+ case old =>
+ var prev: Entry = null
+ var n = old
+ while ((n ne null) && n.hash <= hash) {
+ if (n.hash == hash && elem == n.key) return false
+ prev = n
+ n = n.next
+ }
+ val nnode = createNewEntry(elem, hash)
+ if (prev eq null) {
+ nnode.next = old
+ table(idx) = nnode
+ } else {
+ nnode.next = prev.next
+ prev.next = nnode
+ }
+ }
+ contentSize += 1
+ true
+ }
+
+ private[this] def remove0(elem: A, hash: Int): Boolean = {
+ val idx = index(hash)
+ table(idx) match {
+ case null => false
+ case nd if nd.hash == hash && nd.key == elem =>
+ // first element matches
+ table(idx) = nd.next
+ deleteEntry(nd)
+ contentSize -= 1
+ true
+ case nd =>
+ // find an element that matches
+ var prev = nd
+ var next = nd.next
+ while ((next ne null) && next.hash <= hash) {
+ if (next.hash == hash && next.key == elem) {
+ prev.next = next.next
+ deleteEntry(next)
+ contentSize -= 1
+ return true
+ }
+ prev = next
+ next = next.next
+ }
+ false
+ }
+ }
+
+ private[this] def growTable(newlen: Int): Unit = {
+ if (newlen < 0)
+ throw new RuntimeException(s"new hash table size $newlen exceeds maximum")
+ var oldlen = table.length
+ threshold = newThreshold(newlen)
+ if (size == 0) table = new Array(newlen)
+ else {
+ table = java.util.Arrays.copyOf(table, newlen)
+ val preLow = new Entry(null.asInstanceOf[A], 0)
+ val preHigh = new Entry(null.asInstanceOf[A], 0)
+ // Split buckets until the new length has been reached. This could be done more
+ // efficiently when growing an already filled table to more than double the size.
+ while (oldlen < newlen) {
+ var i = 0
+ while (i < oldlen) {
+ val old = table(i)
+ if (old ne null) {
+ preLow.next = null
+ preHigh.next = null
+ var lastLow = preLow
+ var lastHigh = preHigh
+ var n = old
+ while (n ne null) {
+ val next = n.next
+ if ((n.hash & oldlen) == 0) { // keep low
+ lastLow.next = n
+ lastLow = n
+ } else { // move to high
+ lastHigh.next = n
+ lastHigh = n
+ }
+ n = next
+ }
+ lastLow.next = null
+ if (old ne preLow.next) table(i) = preLow.next
+ if (preHigh.next ne null) {
+ table(i + oldlen) = preHigh.next
+ lastHigh.next = null
+ }
+ }
+ i += 1
+ }
+ oldlen *= 2
+ }
+ }
+ }
+
+ override def hashCode: Int = {
+ val setHashIterator =
+ if (isEmpty) this.iterator
+ else {
+ new LinkedHashSetIterator[Any] {
+ var hash: Int = 0
+ override def hashCode: Int = hash
+ override def extract(nd: Entry): Any = {
+ hash = unimproveHash(nd.hash)
+ this
+ }
+ }
+ }
+ MurmurHash3.unorderedHash(setHashIterator, MurmurHash3.setSeed)
+ }
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix = "LinkedHashSet"
+}
+
+/** $factoryInfo
+ * @define Coll `LinkedHashSet`
+ * @define coll linked hash set
+ */
+@SerialVersionUID(3L)
+object LinkedHashSet extends IterableFactory[LinkedHashSet] {
+
+ override def empty[A]: LinkedHashSet[A] = new LinkedHashSet[A]
+
+ def from[E](it: collection.IterableOnce[E]) = {
+ val newlhs = empty[E]
+ newlhs.sizeHint(it, delta = 0)
+ newlhs.addAll(it)
+ newlhs
+ }
+
+ def newBuilder[A]: GrowableBuilder[A, LinkedHashSet[A]] = new GrowableBuilder(empty[A])
+
+ /** Class for the linked hash set entry, used internally.
+ */
+ private[mutable] final class Entry[A](val key: A, val hash: Int) {
+ var earlier: Entry[A] = null
+ var later: Entry[A] = null
+ var next: Entry[A] = null
+
+ @tailrec
+ final def findEntry(k: A, h: Int): Entry[A] =
+ if (h == hash && k == key) this
+ else if ((next eq null) || (hash > h)) null
+ else next.findEntry(k, h)
+ }
+
+ /** The default load factor for the hash table */
+ private[collection] final def defaultLoadFactor: Double = 0.75
+
+ /** The default initial capacity for the hash table */
+ private[collection] final def defaultinitialSize: Int = 16
+}
+
diff --git a/library/src/scala/collection/mutable/ListBuffer.scala b/library/src/scala/collection/mutable/ListBuffer.scala
new file mode 100644
index 000000000000..273704592abd
--- /dev/null
+++ b/library/src/scala/collection/mutable/ListBuffer.scala
@@ -0,0 +1,420 @@
+/*
+ * 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 mutable
+
+import scala.annotation.{nowarn, tailrec}
+import scala.collection.generic.CommonErrors
+import scala.collection.immutable.{::, List, Nil}
+import java.lang.{IllegalArgumentException, IndexOutOfBoundsException}
+
+import scala.collection.generic.DefaultSerializable
+import scala.runtime.Statics.releaseFence
+
+/** A `Buffer` implementation backed by a list. It provides constant time
+ * prepend and append. Most other operations are linear.
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-mutable-collection-classes.html#list-buffers "Scala's Collection Library overview"]]
+ * section on `List Buffers` for more information.
+ *
+ * @tparam A the type of this list buffer's elements.
+ *
+ * @define Coll `ListBuffer`
+ * @define coll list buffer
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+@SerialVersionUID(-8428291952499836345L)
+class ListBuffer[A]
+ extends AbstractBuffer[A]
+ with SeqOps[A, ListBuffer, ListBuffer[A]]
+ with StrictOptimizedSeqOps[A, ListBuffer, ListBuffer[A]]
+ with ReusableBuilder[A, immutable.List[A]]
+ with IterableFactoryDefaults[A, ListBuffer]
+ with DefaultSerializable {
+ @transient private[this] var mutationCount: Int = 0
+
+ private var first: List[A] = Nil
+ private var last0: ::[A] = null // last element (`last0` just because the name `last` is already taken)
+ private[this] var aliased = false
+ private[this] var len = 0
+
+ private type Predecessor[A0] = ::[A0] /*| Null*/
+
+ def iterator: Iterator[A] = new MutationTracker.CheckedIterator(first.iterator, mutationCount)
+
+ override def iterableFactory: SeqFactory[ListBuffer] = ListBuffer
+
+ @throws[IndexOutOfBoundsException]
+ def apply(i: Int) = first.apply(i)
+
+ def length = len
+ override def knownSize = len
+
+ override def isEmpty: Boolean = len == 0
+
+ private def copyElems(): Unit = {
+ val buf = new ListBuffer[A].freshFrom(this)
+ first = buf.first
+ last0 = buf.last0
+ aliased = false
+ }
+
+ // we only call this before mutating things, so it's
+ // a good place to track mutations for the iterator
+ private def ensureUnaliased(): Unit = {
+ mutationCount += 1
+ if (aliased) copyElems()
+ }
+
+ // Avoids copying where possible.
+ override def toList: List[A] = {
+ aliased = nonEmpty
+ // We've accumulated a number of mutations to `List.tail` by this stage.
+ // Make sure they are visible to threads that the client of this ListBuffer might be about
+ // to share this List with.
+ releaseFence()
+ first
+ }
+
+ def result(): immutable.List[A] = toList
+
+ /** Prepends the elements of this buffer to a given list
+ *
+ * @param xs the list to which elements are prepended
+ */
+ def prependToList(xs: List[A]): List[A] = {
+ if (isEmpty) xs
+ else {
+ ensureUnaliased()
+ last0.next = xs
+ toList
+ }
+ }
+
+ def clear(): Unit = {
+ mutationCount += 1
+ first = Nil
+ len = 0
+ last0 = null
+ aliased = false
+ }
+
+ final def addOne(elem: A): this.type = {
+ ensureUnaliased()
+ val last1 = new ::[A](elem, Nil)
+ if (len == 0) first = last1 else last0.next = last1
+ last0 = last1
+ len += 1
+ this
+ }
+
+ // MUST only be called on fresh instances
+ private def freshFrom(xs: IterableOnce[A]): this.type = {
+ val it = xs.iterator
+ if (it.hasNext) {
+ var len = 1
+ var last0 = new ::[A](it.next(), Nil)
+ first = last0
+ while (it.hasNext) {
+ val last1 = new ::[A](it.next(), Nil)
+ last0.next = last1
+ last0 = last1
+ len += 1
+ }
+ // copy local vars into instance
+ this.len = len
+ this.last0 = last0
+ }
+ this
+ }
+
+ override final def addAll(xs: IterableOnce[A]): this.type = {
+ val it = xs.iterator
+ if (it.hasNext) {
+ val fresh = new ListBuffer[A].freshFrom(it)
+ ensureUnaliased()
+ if (len == 0) first = fresh.first
+ else last0.next = fresh.first
+ last0 = fresh.last0
+ len += fresh.length
+ }
+ this
+ }
+
+ override def subtractOne(elem: A): this.type = {
+ ensureUnaliased()
+ if (isEmpty) {}
+ else if (first.head == elem) {
+ first = first.tail
+ reduceLengthBy(1)
+ }
+ else {
+ var cursor = first
+ while (!cursor.tail.isEmpty && cursor.tail.head != elem) {
+ cursor = cursor.tail
+ }
+ if (!cursor.tail.isEmpty) {
+ val z = cursor.asInstanceOf[::[A]]
+ if (z.next == last0)
+ last0 = z
+ z.next = cursor.tail.tail
+ reduceLengthBy(1)
+ }
+ }
+ this
+ }
+
+ /** Reduce the length of the buffer, and null out last0
+ * if this reduces the length to 0.
+ */
+ private def reduceLengthBy(num: Int): Unit = {
+ len -= num
+ if (len <= 0) // obviously shouldn't be < 0, but still better not to leak
+ last0 = null
+ }
+
+ private def locate(i: Int): Predecessor[A] =
+ if (i == 0) null
+ else if (i == len) last0
+ else {
+ var j = i - 1
+ var p = first
+ while (j > 0) {
+ p = p.tail
+ j -= 1
+ }
+ p.asInstanceOf[Predecessor[A]]
+ }
+
+ private def getNext(p: Predecessor[A]): List[A] =
+ if (p == null) first else p.next
+
+ def update(idx: Int, elem: A): Unit = {
+ ensureUnaliased()
+ if (idx < 0 || idx >= len) throw CommonErrors.indexOutOfBounds(index = idx, max = len - 1)
+ if (idx == 0) {
+ val newElem = new :: (elem, first.tail)
+ if (last0 eq first) {
+ last0 = newElem
+ }
+ first = newElem
+ } else {
+ // `p` can not be `null` because the case where `idx == 0` is handled above
+ val p = locate(idx)
+ val newElem = new :: (elem, p.tail.tail)
+ if (last0 eq p.tail) {
+ last0 = newElem
+ }
+ p.asInstanceOf[::[A]].next = newElem
+ }
+ }
+
+ def insert(idx: Int, elem: A): Unit = {
+ ensureUnaliased()
+ if (idx < 0 || idx > len) throw CommonErrors.indexOutOfBounds(index = idx, max = len - 1)
+ if (idx == len) addOne(elem)
+ else {
+ val p = locate(idx)
+ val nx = elem :: getNext(p)
+ if(p eq null) first = nx else p.next = nx
+ len += 1
+ }
+ }
+
+ def prepend(elem: A): this.type = {
+ insert(0, elem)
+ this
+ }
+
+ // `fresh` must be a `ListBuffer` that only we have access to
+ private def insertAfter(prev: Predecessor[A], fresh: ListBuffer[A]): Unit = {
+ if (!fresh.isEmpty) {
+ val follow = getNext(prev)
+ if (prev eq null) first = fresh.first else prev.next = fresh.first
+ fresh.last0.next = follow
+ if (follow.isEmpty) last0 = fresh.last0
+ len += fresh.length
+ }
+ }
+
+ def insertAll(idx: Int, elems: IterableOnce[A]): Unit = {
+ if (idx < 0 || idx > len) throw CommonErrors.indexOutOfBounds(index = idx, max = len - 1)
+ val it = elems.iterator
+ if (it.hasNext) {
+ if (idx == len) addAll(it)
+ else {
+ val fresh = new ListBuffer[A].freshFrom(it)
+ ensureUnaliased()
+ insertAfter(locate(idx), fresh)
+ }
+ }
+ }
+
+ def remove(idx: Int): A = {
+ ensureUnaliased()
+ if (idx < 0 || idx >= len) throw CommonErrors.indexOutOfBounds(index = idx, max = len - 1)
+ val p = locate(idx)
+ val nx = getNext(p)
+ if(p eq null) {
+ first = nx.tail
+ if(first.isEmpty) last0 = null
+ } else {
+ if(last0 eq nx) last0 = p
+ p.next = nx.tail
+ }
+ len -= 1
+ nx.head
+ }
+
+ def remove(idx: Int, count: Int): Unit =
+ if (count > 0) {
+ ensureUnaliased()
+ if (idx < 0 || idx + count > len) throw new IndexOutOfBoundsException(s"$idx to ${idx + count} is out of bounds (min 0, max ${len - 1})")
+ removeAfter(locate(idx), count)
+ } else if (count < 0) {
+ throw new IllegalArgumentException("removing negative number of elements: " + count)
+ }
+
+ private def removeAfter(prev: Predecessor[A], n: Int) = {
+ @tailrec def ahead(p: List[A], n: Int): List[A] =
+ if (n == 0) p else ahead(p.tail, n - 1)
+ val nx = ahead(getNext(prev), n)
+ if(prev eq null) first = nx else prev.next = nx
+ if(nx.isEmpty) last0 = prev
+ len -= n
+ }
+
+ /** Replace the contents of this $coll with the mapped result.
+ *
+ * @param f the mapping function
+ * @return this $coll
+ */
+ def mapInPlace(f: A => A): this.type = {
+ mutationCount += 1
+ val buf = new ListBuffer[A]
+ for (elem <- this) buf += f(elem)
+ first = buf.first
+ last0 = buf.last0
+ aliased = false // we just assigned from a new instance
+ this
+ }
+
+ /** Replace the contents of this $coll with the flatmapped result.
+ *
+ * @param f the mapping function
+ * @return this $coll
+ */
+ def flatMapInPlace(f: A => IterableOnce[A]): this.type = {
+ mutationCount += 1
+ var src = first
+ var dst: List[A] = null
+ last0 = null
+ len = 0
+ while(!src.isEmpty) {
+ val it = f(src.head).iterator
+ while(it.hasNext) {
+ val v = new ::(it.next(), Nil)
+ if(dst eq null) dst = v else last0.next = v
+ last0 = v
+ len += 1
+ }
+ src = src.tail
+ }
+ first = if(dst eq null) Nil else dst
+ aliased = false // we just rebuilt a fresh, unaliased instance
+ this
+ }
+
+ /** Replace the contents of this $coll with the filtered result.
+ *
+ * @param p the filtering predicate
+ * @return this $coll
+ */
+ def filterInPlace(p: A => Boolean): this.type = {
+ ensureUnaliased()
+ var prev: Predecessor[A] = null
+ var cur: List[A] = first
+ while (!cur.isEmpty) {
+ val follow = cur.tail
+ if (!p(cur.head)) {
+ if(prev eq null) first = follow
+ else prev.next = follow
+ len -= 1
+ } else {
+ prev = cur.asInstanceOf[Predecessor[A]]
+ }
+ cur = follow
+ }
+ last0 = prev
+ this
+ }
+
+ def patchInPlace(from: Int, patch: collection.IterableOnce[A], replaced: Int): this.type = {
+ val _len = len
+ val _from = math.max(from, 0) // normalized
+ val _replaced = math.max(replaced, 0) // normalized
+ val it = patch.iterator
+
+ val nonEmptyPatch = it.hasNext
+ val nonEmptyReplace = (_from < _len) && (_replaced > 0)
+
+ // don't want to add a mutation or check aliasing (potentially expensive)
+ // if there's no patching to do
+ if (nonEmptyPatch || nonEmptyReplace) {
+ val fresh = new ListBuffer[A].freshFrom(it)
+ ensureUnaliased()
+ val i = math.min(_from, _len)
+ val n = math.min(_replaced, _len)
+ val p = locate(i)
+ removeAfter(p, math.min(n, _len - i))
+ insertAfter(p, fresh)
+ }
+ this
+ }
+
+ /**
+ * Selects the last element.
+ *
+ * Runs in constant time.
+ *
+ * @return The last element of this $coll.
+ * @throws NoSuchElementException If the $coll is empty.
+ */
+ override def last: A = if (last0 eq null) throw new NoSuchElementException("last of empty ListBuffer") else last0.head
+
+ /**
+ * Optionally selects the last element.
+ *
+ * Runs in constant time.
+ *
+ * @return the last element of this $coll$ if it is nonempty, `None` if it is empty.
+ */
+ override def lastOption: Option[A] = if (last0 eq null) None else Some(last0.head)
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix = "ListBuffer"
+
+}
+
+@SerialVersionUID(3L)
+object ListBuffer extends StrictOptimizedSeqFactory[ListBuffer] {
+
+ def from[A](coll: collection.IterableOnce[A]): ListBuffer[A] = new ListBuffer[A].freshFrom(coll)
+
+ def newBuilder[A]: Builder[A, ListBuffer[A]] = new GrowableBuilder(empty[A])
+
+ def empty[A]: ListBuffer[A] = new ListBuffer[A]
+}
diff --git a/library/src/scala/collection/mutable/ListMap.scala b/library/src/scala/collection/mutable/ListMap.scala
new file mode 100644
index 000000000000..e1a273bfd5af
--- /dev/null
+++ b/library/src/scala/collection/mutable/ListMap.scala
@@ -0,0 +1,82 @@
+/*
+ * 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 mutable
+
+import scala.annotation.tailrec
+import scala.collection.generic.DefaultSerializable
+import scala.collection.immutable.List
+
+/** A simple mutable map backed by a list, so it preserves insertion order.
+ *
+ * @tparam K the type of the keys contained in this list map.
+ * @tparam V the type of the values assigned to keys in this list map.
+ *
+ * @define Coll `mutable.ListMap`
+ * @define coll mutable list map
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ * @define orderDependent
+ * @define orderDependentFold
+ */
+@deprecated("Use an immutable.ListMap assigned to a var instead of mutable.ListMap", "2.13.0")
+class ListMap[K, V]
+ extends AbstractMap[K, V]
+ with MapOps[K, V, ListMap, ListMap[K, V]]
+ with StrictOptimizedIterableOps[(K, V), Iterable, ListMap[K, V]]
+ with StrictOptimizedMapOps[K, V, ListMap, ListMap[K, V]]
+ with MapFactoryDefaults[K, V, ListMap, Iterable]
+ with DefaultSerializable {
+
+ override def mapFactory: MapFactory[ListMap] = ListMap
+
+ private[this] var elems: List[(K, V)] = List()
+ private[this] var siz: Int = 0
+
+ def get(key: K): Option[V] = elems find (_._1 == key) map (_._2)
+ def iterator: Iterator[(K, V)] = elems.iterator
+
+ final override def addOne(kv: (K, V)) = {
+ val (e, key0) = remove(kv._1, elems, List())
+ elems = (key0, kv._2) :: e
+ siz += 1; this
+ }
+
+ final override def subtractOne(key: K) = { elems = remove(key, elems, List())._1; this }
+
+ @tailrec
+ private def remove(key: K, elems: List[(K, V)], acc: List[(K, V)]): (List[(K, V)], K) = {
+ if (elems.isEmpty) (acc, key)
+ else if (elems.head._1 == key) { siz -= 1; (acc ::: elems.tail, elems.head._1) }
+ else remove(key, elems.tail, elems.head :: acc)
+ }
+
+ final override def clear(): Unit = { elems = List(); siz = 0 }
+
+ final override def size: Int = siz
+ override def knownSize: Int = size
+ override def isEmpty: Boolean = size == 0
+ override protected[this] def stringPrefix = "ListMap"
+}
+
+/** $factoryInfo
+ * @define Coll `mutable.ListMap`
+ * @define coll mutable list map
+ */
+@SerialVersionUID(3L)
+@deprecated("Use an immutable.ListMap assigned to a var instead of mutable.ListMap", "2.13.0")
+object ListMap extends MapFactory[ListMap] {
+ def empty[K, V]: ListMap[K, V] = new ListMap[K, V]
+ def from[K, V](it: IterableOnce[(K, V)]): ListMap[K,V] = Growable.from(empty[K, V], it)
+ def newBuilder[K, V]: Builder[(K, V), ListMap[K,V]] = new GrowableBuilder(empty[K, V])
+}
diff --git a/library/src/scala/collection/mutable/LongMap.scala b/library/src/scala/collection/mutable/LongMap.scala
new file mode 100644
index 000000000000..e36c337437e3
--- /dev/null
+++ b/library/src/scala/collection/mutable/LongMap.scala
@@ -0,0 +1,691 @@
+/*
+ * 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 mutable
+
+import scala.collection.generic.DefaultSerializationProxy
+import scala.language.implicitConversions
+
+/** This class implements mutable maps with `Long` keys based on a hash table with open addressing.
+ *
+ * Basic map operations on single entries, including `contains` and `get`,
+ * are typically substantially faster with `LongMap` than [[HashMap]]. Methods
+ * that act on the whole map, including `foreach` and `map` are not in
+ * general expected to be faster than with a generic map, save for those
+ * that take particular advantage of the internal structure of the map:
+ * `foreachKey`, `foreachValue`, `mapValuesNow`, and `transformValues`.
+ *
+ * Maps with open addressing may become less efficient at lookup after
+ * repeated addition/removal of elements. Although `LongMap` makes a
+ * decent attempt to remain efficient regardless, calling `repack`
+ * on a map that will no longer have elements removed but will be
+ * used heavily may save both time and storage space.
+ *
+ * This map is not intended to contain more than 2^29 entries (approximately
+ * 500 million). The maximum capacity is 2^30, but performance will degrade
+ * rapidly as 2^30 is approached.
+ *
+ */
+final class LongMap[V] private[collection] (defaultEntry: Long => V, initialBufferSize: Int, initBlank: Boolean)
+ extends AbstractMap[Long, V]
+ with MapOps[Long, V, Map, LongMap[V]]
+ with StrictOptimizedIterableOps[(Long, V), Iterable, LongMap[V]]
+ with Serializable {
+ import LongMap._
+
+ def this() = this(LongMap.exceptionDefault, 16, initBlank = true)
+
+ // TODO: override clear() with an optimization more tailored for efficiency.
+ override protected def fromSpecific(coll: scala.collection.IterableOnce[(Long, V)]): LongMap[V] = {
+ //TODO should this be the default implementation of this method in StrictOptimizedIterableOps?
+ val b = newSpecificBuilder
+ b.sizeHint(coll)
+ b.addAll(coll)
+ b.result()
+ }
+ override protected def newSpecificBuilder: Builder[(Long, V),LongMap[V]] = new GrowableBuilder(LongMap.empty[V])
+
+ /** Creates a new `LongMap` that returns default values according to a supplied key-value mapping. */
+ def this(defaultEntry: Long => V) = this(defaultEntry, 16, initBlank = true)
+
+ /** Creates a new `LongMap` with an initial buffer of specified size.
+ *
+ * A LongMap can typically contain half as many elements as its buffer size
+ * before it requires resizing.
+ */
+ def this(initialBufferSize: Int) = this(LongMap.exceptionDefault, initialBufferSize, initBlank = true)
+
+ /** Creates a new `LongMap` with specified default values and initial buffer size. */
+ def this(defaultEntry: Long => V, initialBufferSize: Int) = this(defaultEntry, initialBufferSize, initBlank = true)
+
+ private[this] var mask = 0
+ private[this] var extraKeys: Int = 0
+ private[this] var zeroValue: AnyRef = null
+ private[this] var minValue: AnyRef = null
+ private[this] var _size = 0
+ private[this] var _vacant = 0
+ private[this] var _keys: Array[Long] = null
+ private[this] var _values: Array[AnyRef] = null
+
+ if (initBlank) defaultInitialize(initialBufferSize)
+
+ private[this] def defaultInitialize(n: Int) = {
+ mask =
+ if (n<0) 0x7
+ else (((1 << (32 - java.lang.Integer.numberOfLeadingZeros(n-1))) - 1) & 0x3FFFFFFF) | 0x7
+ _keys = new Array[Long](mask+1)
+ _values = new Array[AnyRef](mask+1)
+ }
+
+ private[collection] def initializeTo(
+ m: Int, ek: Int, zv: AnyRef, mv: AnyRef, sz: Int, vc: Int, kz: Array[Long], vz: Array[AnyRef]
+ ): Unit = {
+ mask = m; extraKeys = ek; zeroValue = zv; minValue = mv; _size = sz; _vacant = vc; _keys = kz; _values = vz
+ }
+
+ override def size: Int = _size + (extraKeys+1)/2
+ override def knownSize: Int = size
+ override def isEmpty: Boolean = size == 0
+ override def empty: LongMap[V] = new LongMap()
+
+ private def imbalanced: Boolean =
+ (_size + _vacant) > 0.5*mask || _vacant > _size
+
+ private def toIndex(k: Long): Int = {
+ // Part of the MurmurHash3 32 bit finalizer
+ val h = ((k ^ (k >>> 32)) & 0xFFFFFFFFL).toInt
+ val x = (h ^ (h >>> 16)) * 0x85EBCA6B
+ (x ^ (x >>> 13)) & mask
+ }
+
+ private def seekEmpty(k: Long): Int = {
+ var e = toIndex(k)
+ var x = 0
+ while (_keys(e) != 0) { x += 1; e = (e + 2*(x+1)*x - 3) & mask }
+ e
+ }
+
+ private def seekEntry(k: Long): Int = {
+ var e = toIndex(k)
+ var x = 0
+ var q = 0L
+ while ({ q = _keys(e); if (q==k) return e; q != 0}) { x += 1; e = (e + 2*(x+1)*x - 3) & mask }
+ e | MissingBit
+ }
+
+ private def seekEntryOrOpen(k: Long): Int = {
+ var e = toIndex(k)
+ var x = 0
+ var q = 0L
+ while ({ q = _keys(e); if (q==k) return e; q+q != 0}) {
+ x += 1
+ e = (e + 2*(x+1)*x - 3) & mask
+ }
+ if (q == 0) return e | MissingBit
+ val o = e | MissVacant
+ while ({ q = _keys(e); if (q==k) return e; q != 0}) {
+ x += 1
+ e = (e + 2*(x+1)*x - 3) & mask
+ }
+ o
+ }
+
+ override def contains(key: Long): Boolean = {
+ if (key == -key) (((key>>>63).toInt+1) & extraKeys) != 0
+ else seekEntry(key) >= 0
+ }
+
+ override def get(key: Long): Option[V] = {
+ if (key == -key) {
+ if ((((key>>>63).toInt+1) & extraKeys) == 0) None
+ else if (key == 0) Some(zeroValue.asInstanceOf[V])
+ else Some(minValue.asInstanceOf[V])
+ }
+ else {
+ val i = seekEntry(key)
+ if (i < 0) None else Some(_values(i).asInstanceOf[V])
+ }
+ }
+
+ override def getOrElse[V1 >: V](key: Long, default: => V1): V1 = {
+ if (key == -key) {
+ if ((((key>>>63).toInt+1) & extraKeys) == 0) default
+ else if (key == 0) zeroValue.asInstanceOf[V1]
+ else minValue.asInstanceOf[V1]
+ }
+ else {
+ val i = seekEntry(key)
+ if (i < 0) default else _values(i).asInstanceOf[V1]
+ }
+ }
+
+ override def getOrElseUpdate(key: Long, defaultValue: => V): V = {
+ if (key == -key) {
+ val kbits = (key>>>63).toInt + 1
+ if ((kbits & extraKeys) == 0) {
+ val value = defaultValue
+ extraKeys |= kbits
+ if (key == 0) zeroValue = value.asInstanceOf[AnyRef]
+ else minValue = value.asInstanceOf[AnyRef]
+ value
+ }
+ else if (key == 0) zeroValue.asInstanceOf[V]
+ else minValue.asInstanceOf[V]
+ }
+ else {
+ var i = seekEntryOrOpen(key)
+ if (i < 0) {
+ val value = {
+ val oks = _keys
+ val j = i & IndexMask
+ val ok = oks(j)
+ val ans = defaultValue
+ // Evaluating `defaultValue` may change the map
+ // - repack: the array is different
+ // - element added at `j`: since `i < 0`, the key was missing and `ok` is either 0 or MinValue.
+ // If `defaultValue` added an element at `j` then `_keys(j)` must be different now.
+ // (`_keys` never contains 0 or MinValue.)
+ if (oks.ne(_keys) || ok != _keys(j)) {
+ i = seekEntryOrOpen(key)
+ if (i >= 0) _size -= 1
+ }
+ ans
+ }
+ _size += 1
+ val j = i & IndexMask
+ _keys(j) = key
+ _values(j) = value.asInstanceOf[AnyRef]
+ if ((i & VacantBit) != 0) _vacant -= 1
+ else if (imbalanced) repack()
+ value
+ }
+ else _values(i).asInstanceOf[V]
+ }
+ }
+
+ /** Retrieves the value associated with a key, or the default for that type if none exists
+ * (null for AnyRef, 0 for floats and integers).
+ *
+ * Note: this is the fastest way to retrieve a value that may or
+ * may not exist, if the default null/zero is acceptable. For key/value
+ * pairs that do exist, `apply` (i.e. `map(key)`) is equally fast.
+ */
+ def getOrNull(key: Long): V = {
+ if (key == -key) {
+ if ((((key>>>63).toInt+1) & extraKeys) == 0) null.asInstanceOf[V]
+ else if (key == 0) zeroValue.asInstanceOf[V]
+ else minValue.asInstanceOf[V]
+ }
+ else {
+ val i = seekEntry(key)
+ if (i < 0) null.asInstanceOf[V] else _values(i).asInstanceOf[V]
+ }
+ }
+
+ /** Retrieves the value associated with a key.
+ * If the key does not exist in the map, the `defaultEntry` for that key
+ * will be returned instead.
+ */
+ override def apply(key: Long): V = {
+ if (key == -key) {
+ if ((((key>>>63).toInt+1) & extraKeys) == 0) defaultEntry(key)
+ else if (key == 0) zeroValue.asInstanceOf[V]
+ else minValue.asInstanceOf[V]
+ }
+ else {
+ val i = seekEntry(key)
+ if (i < 0) defaultEntry(key) else _values(i).asInstanceOf[V]
+ }
+ }
+
+ /** The user-supplied default value for the key. Throws an exception
+ * if no other default behavior was specified.
+ */
+ override def default(key: Long) = defaultEntry(key)
+
+ private def repack(newMask: Int): Unit = {
+ val ok = _keys
+ val ov = _values
+ mask = newMask
+ _keys = new Array[Long](mask+1)
+ _values = new Array[AnyRef](mask+1)
+ _vacant = 0
+ var i = 0
+ while (i < ok.length) {
+ val k = ok(i)
+ if (k != -k) {
+ val j = seekEmpty(k)
+ _keys(j) = k
+ _values(j) = ov(i)
+ }
+ i += 1
+ }
+ }
+
+ /** Repacks the contents of this `LongMap` for maximum efficiency of lookup.
+ *
+ * For maps that undergo a complex creation process with both addition and
+ * removal of keys, and then are used heavily with no further removal of
+ * elements, calling `repack` after the end of the creation can result in
+ * improved performance. Repacking takes time proportional to the number
+ * of entries in the map.
+ */
+ def repack(): Unit = repack(repackMask(mask, _size = _size, _vacant = _vacant))
+
+ override def put(key: Long, value: V): Option[V] = {
+ if (key == -key) {
+ if (key == 0) {
+ val ans = if ((extraKeys&1) == 1) Some(zeroValue.asInstanceOf[V]) else None
+ zeroValue = value.asInstanceOf[AnyRef]
+ extraKeys |= 1
+ ans
+ }
+ else {
+ val ans = if ((extraKeys&2) == 1) Some(minValue.asInstanceOf[V]) else None
+ minValue = value.asInstanceOf[AnyRef]
+ extraKeys |= 2
+ ans
+ }
+ }
+ else {
+ val i = seekEntryOrOpen(key)
+ if (i < 0) {
+ val j = i & IndexMask
+ _keys(j) = key
+ _values(j) = value.asInstanceOf[AnyRef]
+ _size += 1
+ if ((i & VacantBit) != 0) _vacant -= 1
+ else if (imbalanced) repack()
+ None
+ }
+ else {
+ val ans = Some(_values(i).asInstanceOf[V])
+ _keys(i) = key
+ _values(i) = value.asInstanceOf[AnyRef]
+ ans
+ }
+ }
+ }
+
+ /** Updates the map to include a new key-value pair.
+ *
+ * This is the fastest way to add an entry to a `LongMap`.
+ */
+ override def update(key: Long, value: V): Unit = {
+ if (key == -key) {
+ if (key == 0) {
+ zeroValue = value.asInstanceOf[AnyRef]
+ extraKeys |= 1
+ }
+ else {
+ minValue = value.asInstanceOf[AnyRef]
+ extraKeys |= 2
+ }
+ }
+ else {
+ val i = seekEntryOrOpen(key)
+ if (i < 0) {
+ val j = i & IndexMask
+ _keys(j) = key
+ _values(j) = value.asInstanceOf[AnyRef]
+ _size += 1
+ if ((i & VacantBit) != 0) _vacant -= 1
+ else if (imbalanced) repack()
+ }
+ else {
+ _keys(i) = key
+ _values(i) = value.asInstanceOf[AnyRef]
+ }
+ }
+ }
+
+ /** Adds a new key/value pair to this map and returns the map. */
+ @deprecated("Use `addOne` or `update` instead; infix operations with an operand of multiple args will be deprecated", "2.13.3")
+ def +=(key: Long, value: V): this.type = { update(key, value); this }
+
+ /** Adds a new key/value pair to this map and returns the map. */
+ @inline final def addOne(key: Long, value: V): this.type = { update(key, value); this }
+
+ @inline override final def addOne(kv: (Long, V)): this.type = { update(kv._1, kv._2); this }
+
+ def subtractOne(key: Long): this.type = {
+ if (key == -key) {
+ if (key == 0L) {
+ extraKeys &= 0x2
+ zeroValue = null
+ }
+ else {
+ extraKeys &= 0x1
+ minValue = null
+ }
+ }
+ else {
+ val i = seekEntry(key)
+ if (i >= 0) {
+ _size -= 1
+ _vacant += 1
+ _keys(i) = Long.MinValue
+ _values(i) = null
+ }
+ }
+ this
+ }
+
+ def iterator: Iterator[(Long, V)] = new AbstractIterator[(Long, V)] {
+ private[this] val kz = _keys
+ private[this] val vz = _values
+
+ private[this] var nextPair: (Long, V) =
+ if (extraKeys==0) null
+ else if ((extraKeys&1)==1) (0L, zeroValue.asInstanceOf[V])
+ else (Long.MinValue, minValue.asInstanceOf[V])
+
+ private[this] var anotherPair: (Long, V) =
+ if (extraKeys==3) (Long.MinValue, minValue.asInstanceOf[V])
+ else null
+
+ private[this] var index = 0
+
+ def hasNext: Boolean = nextPair != null || (index < kz.length && {
+ var q = kz(index)
+ while (q == -q) {
+ index += 1
+ if (index >= kz.length) return false
+ q = kz(index)
+ }
+ nextPair = (kz(index), vz(index).asInstanceOf[V])
+ index += 1
+ true
+ })
+ def next() = {
+ if (nextPair == null && !hasNext) throw new NoSuchElementException("next")
+ val ans = nextPair
+ if (anotherPair != null) {
+ nextPair = anotherPair
+ anotherPair = null
+ }
+ else nextPair = null
+ ans
+ }
+ }
+
+ // TODO PERF override these for efficiency. See immutable.LongMap for how to organize the code.
+ override def keysIterator: Iterator[Long] = super.keysIterator
+ override def valuesIterator: Iterator[V] = super.valuesIterator
+
+ override def foreach[U](f: ((Long,V)) => U): Unit = {
+ if ((extraKeys & 1) == 1) f((0L, zeroValue.asInstanceOf[V]))
+ if ((extraKeys & 2) == 2) f((Long.MinValue, minValue.asInstanceOf[V]))
+ var i,j = 0
+ while (i < _keys.length & j < _size) {
+ val k = _keys(i)
+ if (k != -k) {
+ j += 1
+ f((k, _values(i).asInstanceOf[V]))
+ }
+ i += 1
+ }
+ }
+
+ override def foreachEntry[U](f: (Long,V) => U): Unit = {
+ if ((extraKeys & 1) == 1) f(0L, zeroValue.asInstanceOf[V])
+ if ((extraKeys & 2) == 2) f(Long.MinValue, minValue.asInstanceOf[V])
+ var i,j = 0
+ while (i < _keys.length & j < _size) {
+ val k = _keys(i)
+ if (k != -k) {
+ j += 1
+ f(k, _values(i).asInstanceOf[V])
+ }
+ i += 1
+ }
+ }
+
+ override def clone(): LongMap[V] = {
+ val kz = java.util.Arrays.copyOf(_keys, _keys.length)
+ val vz = java.util.Arrays.copyOf(_values, _values.length)
+ val lm = new LongMap[V](defaultEntry, 1, initBlank = false)
+ lm.initializeTo(mask, extraKeys, zeroValue, minValue, _size, _vacant, kz, vz)
+ lm
+ }
+
+ @deprecated("Consider requiring an immutable Map or fall back to Map.concat", "2.13.0")
+ override def +[V1 >: V](kv: (Long, V1)): LongMap[V1] = {
+ val lm = clone().asInstanceOf[LongMap[V1]]
+ lm += kv
+ lm
+ }
+
+ @deprecated("Use ++ with an explicit collection argument instead of + with varargs", "2.13.0")
+ override def + [V1 >: V](elem1: (Long, V1), elem2: (Long, V1), elems: (Long, V1)*): LongMap[V1] = {
+ val m = this + elem1 + elem2
+ if(elems.isEmpty) m else m.concat(elems)
+ }
+
+ override def concat[V1 >: V](xs: scala.collection.IterableOnce[(Long, V1)]): LongMap[V1] = {
+ val lm = clone().asInstanceOf[LongMap[V1]]
+ xs.iterator.foreach(kv => lm += kv)
+ lm
+ }
+
+ override def ++ [V1 >: V](xs: scala.collection.IterableOnce[(Long, V1)]): LongMap[V1] = concat(xs)
+
+ @deprecated("Use m.clone().addOne(k,v) instead of m.updated(k, v)", "2.13.0")
+ override def updated[V1 >: V](key: Long, value: V1): LongMap[V1] =
+ clone().asInstanceOf[LongMap[V1]].addOne(key, value)
+
+ /** Applies a function to all keys of this map. */
+ def foreachKey[A](f: Long => A): Unit = {
+ if ((extraKeys & 1) == 1) f(0L)
+ if ((extraKeys & 2) == 2) f(Long.MinValue)
+ var i,j = 0
+ while (i < _keys.length & j < _size) {
+ val k = _keys(i)
+ if (k != -k) {
+ j += 1
+ f(k)
+ }
+ i += 1
+ }
+ }
+
+ /** Applies a function to all values of this map. */
+ def foreachValue[A](f: V => A): Unit = {
+ if ((extraKeys & 1) == 1) f(zeroValue.asInstanceOf[V])
+ if ((extraKeys & 2) == 2) f(minValue.asInstanceOf[V])
+ var i,j = 0
+ while (i < _keys.length & j < _size) {
+ val k = _keys(i)
+ if (k != -k) {
+ j += 1
+ f(_values(i).asInstanceOf[V])
+ }
+ i += 1
+ }
+ }
+
+ /** Creates a new `LongMap` with different values.
+ * Unlike `mapValues`, this method generates a new
+ * collection immediately.
+ */
+ def mapValuesNow[V1](f: V => V1): LongMap[V1] = {
+ val zv = if ((extraKeys & 1) == 1) f(zeroValue.asInstanceOf[V]).asInstanceOf[AnyRef] else null
+ val mv = if ((extraKeys & 2) == 2) f(minValue.asInstanceOf[V]).asInstanceOf[AnyRef] else null
+ val lm = new LongMap[V1](LongMap.exceptionDefault, 1, initBlank = false)
+ val kz = java.util.Arrays.copyOf(_keys, _keys.length)
+ val vz = new Array[AnyRef](_values.length)
+ var i,j = 0
+ while (i < _keys.length & j < _size) {
+ val k = _keys(i)
+ if (k != -k) {
+ j += 1
+ vz(i) = f(_values(i).asInstanceOf[V]).asInstanceOf[AnyRef]
+ }
+ i += 1
+ }
+ lm.initializeTo(mask, extraKeys, zv, mv, _size, _vacant, kz, vz)
+ lm
+ }
+
+ /** Applies a transformation function to all values stored in this map.
+ * Note: the default, if any, is not transformed.
+ */
+ @deprecated("Use transformValuesInPlace instead of transformValues", "2.13.0")
+ @`inline` final def transformValues(f: V => V): this.type = transformValuesInPlace(f)
+
+ /** Applies a transformation function to all values stored in this map.
+ * Note: the default, if any, is not transformed.
+ */
+ def transformValuesInPlace(f: V => V): this.type = {
+ if ((extraKeys & 1) == 1) zeroValue = f(zeroValue.asInstanceOf[V]).asInstanceOf[AnyRef]
+ if ((extraKeys & 2) == 2) minValue = f(minValue.asInstanceOf[V]).asInstanceOf[AnyRef]
+ var i,j = 0
+ while (i < _keys.length & j < _size) {
+ val k = _keys(i)
+ if (k != -k) {
+ j += 1
+ _values(i) = f(_values(i).asInstanceOf[V]).asInstanceOf[AnyRef]
+ }
+ i += 1
+ }
+ this
+ }
+
+ /** An overload of `map` which produces a `LongMap`.
+ *
+ * @param f the mapping function
+ */
+ def map[V2](f: ((Long, V)) => (Long, V2)): LongMap[V2] = LongMap.from(new View.Map(coll, f))
+
+ /** An overload of `flatMap` which produces a `LongMap`.
+ *
+ * @param f the mapping function
+ */
+ def flatMap[V2](f: ((Long, V)) => IterableOnce[(Long, V2)]): LongMap[V2] = LongMap.from(new View.FlatMap(coll, f))
+
+ /** An overload of `collect` which produces a `LongMap`.
+ *
+ * @param pf the mapping function
+ */
+ def collect[V2](pf: PartialFunction[(Long, V), (Long, V2)]): LongMap[V2] =
+ strictOptimizedCollect(LongMap.newBuilder[V2], pf)
+
+ protected[this] def writeReplace(): AnyRef = new DefaultSerializationProxy(LongMap.toFactory[V](LongMap), this)
+
+ override protected[this] def className = "LongMap"
+}
+
+object LongMap {
+ private final val IndexMask = 0x3FFF_FFFF
+ private final val MissingBit = 0x8000_0000
+ private final val VacantBit = 0x4000_0000
+ private final val MissVacant = 0xC000_0000
+
+ private val exceptionDefault: Long => Nothing = (k: Long) => throw new NoSuchElementException(k.toString)
+
+ /** A builder for instances of `LongMap`.
+ *
+ * This builder can be reused to create multiple instances.
+ */
+ final class LongMapBuilder[V] extends ReusableBuilder[(Long, V), LongMap[V]] {
+ private[collection] var elems: LongMap[V] = new LongMap[V]
+ override def addOne(entry: (Long, V)): this.type = {
+ elems += entry
+ this
+ }
+ def clear(): Unit = elems = new LongMap[V]
+ def result(): LongMap[V] = elems
+ override def knownSize: Int = elems.knownSize
+ }
+
+ /** Creates a new `LongMap` with zero or more key/value pairs. */
+ def apply[V](elems: (Long, V)*): LongMap[V] = buildFromIterableOnce(elems)
+
+ private def buildFromIterableOnce[V](elems: IterableOnce[(Long, V)]): LongMap[V] = {
+ var sz = elems.knownSize
+ if(sz < 0) sz = 4
+ val lm = new LongMap[V](sz * 2)
+ elems.iterator.foreach{ case (k,v) => lm(k) = v }
+ if (lm.size < (sz>>3)) lm.repack()
+ lm
+ }
+
+ /** Creates a new empty `LongMap`. */
+ def empty[V]: LongMap[V] = new LongMap[V]
+
+ /** Creates a new empty `LongMap` with the supplied default */
+ def withDefault[V](default: Long => V): LongMap[V] = new LongMap[V](default)
+
+ /** Creates a new `LongMap` from an existing source collection. A source collection
+ * which is already a `LongMap` gets cloned.
+ *
+ * @param source Source collection
+ * @tparam A the type of the collection’s elements
+ * @return a new `LongMap` with the elements of `source`
+ */
+ def from[V](source: IterableOnce[(Long, V)]): LongMap[V] = source match {
+ case source: LongMap[_] => source.clone().asInstanceOf[LongMap[V]]
+ case _ => buildFromIterableOnce(source)
+ }
+
+ def newBuilder[V]: ReusableBuilder[(Long, V), LongMap[V]] = new LongMapBuilder[V]
+
+ /** Creates a new `LongMap` from arrays of keys and values.
+ * Equivalent to but more efficient than `LongMap((keys zip values): _*)`.
+ */
+ def fromZip[V](keys: Array[Long], values: Array[V]): LongMap[V] = {
+ val sz = math.min(keys.length, values.length)
+ val lm = new LongMap[V](sz * 2)
+ var i = 0
+ while (i < sz) { lm(keys(i)) = values(i); i += 1 }
+ if (lm.size < (sz>>3)) lm.repack()
+ lm
+ }
+
+ /** Creates a new `LongMap` from keys and values.
+ * Equivalent to but more efficient than `LongMap((keys zip values): _*)`.
+ */
+ def fromZip[V](keys: scala.collection.Iterable[Long], values: scala.collection.Iterable[V]): LongMap[V] = {
+ val sz = math.min(keys.size, values.size)
+ val lm = new LongMap[V](sz * 2)
+ val ki = keys.iterator
+ val vi = values.iterator
+ while (ki.hasNext && vi.hasNext) lm(ki.next()) = vi.next()
+ if (lm.size < (sz >> 3)) lm.repack()
+ lm
+ }
+
+ implicit def toFactory[V](dummy: LongMap.type): Factory[(Long, V), LongMap[V]] = ToFactory.asInstanceOf[Factory[(Long, V), LongMap[V]]]
+
+ @SerialVersionUID(3L)
+ private[this] object ToFactory extends Factory[(Long, AnyRef), LongMap[AnyRef]] with Serializable {
+ def fromSpecific(it: IterableOnce[(Long, AnyRef)]): LongMap[AnyRef] = LongMap.from[AnyRef](it)
+ def newBuilder: Builder[(Long, AnyRef), LongMap[AnyRef]] = LongMap.newBuilder[AnyRef]
+ }
+
+ implicit def toBuildFrom[V](factory: LongMap.type): BuildFrom[Any, (Long, V), LongMap[V]] = ToBuildFrom.asInstanceOf[BuildFrom[Any, (Long, V), LongMap[V]]]
+ private object ToBuildFrom extends BuildFrom[Any, (Long, AnyRef), LongMap[AnyRef]] {
+ def fromSpecific(from: Any)(it: IterableOnce[(Long, AnyRef)]) = LongMap.from(it)
+ def newBuilder(from: Any): ReusableBuilder[(Long, AnyRef), LongMap[AnyRef]] = LongMap.newBuilder[AnyRef]
+ }
+
+ implicit def iterableFactory[V]: Factory[(Long, V), LongMap[V]] = toFactory(this)
+ implicit def buildFromLongMap[V]: BuildFrom[LongMap[_], (Long, V), LongMap[V]] = toBuildFrom(this)
+
+ private def repackMask(mask: Int, _size: Int, _vacant: Int): Int = {
+ var m = mask
+ if (_size + _vacant >= 0.5*mask && !(_vacant > 0.2*mask)) m = ((m << 1) + 1) & IndexMask
+ while (m > 8 && _size < (m >>> 3)) m = m >>> 1
+ m /*.ensuring(_size <= _ + 1)*/
+ }
+}
diff --git a/library/src/scala/collection/mutable/Map.scala b/library/src/scala/collection/mutable/Map.scala
new file mode 100644
index 000000000000..8659b45e86e6
--- /dev/null
+++ b/library/src/scala/collection/mutable/Map.scala
@@ -0,0 +1,268 @@
+/*
+ * 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 collection
+package mutable
+
+/** Base type of mutable Maps */
+trait Map[K, V]
+ extends Iterable[(K, V)]
+ with collection.Map[K, V]
+ with MapOps[K, V, Map, Map[K, V]]
+ with Growable[(K, V)]
+ with Shrinkable[K]
+ with MapFactoryDefaults[K, V, Map, Iterable] {
+
+ override def mapFactory: scala.collection.MapFactory[Map] = Map
+
+ /*
+ //TODO consider keeping `remove` because it returns the removed entry
+ @deprecated("Use subtract or -= instead of remove", "2.13.0")
+ def remove(key: K): Option[V] = {
+ val old = get(key)
+ if(old.isDefined) subtract(key)
+ old
+ }
+ */
+
+ /** The same map with a given default function.
+ * Note: The default is only used for `apply`. Other methods like `get`, `contains`, `iterator`, `keys`, etc.
+ * are not affected by `withDefaultValue`.
+ *
+ * Invoking transformer methods (e.g. `map`) will not preserve the default value.
+ *
+ * @param d the function mapping keys to values, used for non-present keys
+ * @return a wrapper of the map with a default value
+ */
+ def withDefault(d: K => V): Map[K, V] = new Map.WithDefault[K, V](this, d)
+
+ /** The same map with a given default value.
+ * Note: The default is only used for `apply`. Other methods like `get`, `contains`, `iterator`, `keys`, etc.
+ * are not affected by `withDefaultValue`.
+ *
+ * Invoking transformer methods (e.g. `map`) will not preserve the default value.
+ *
+ * @param d default value used for non-present keys
+ * @return a wrapper of the map with a default value
+ */
+ def withDefaultValue(d: V): Map[K, V] = new Map.WithDefault[K, V](this, x => d)
+}
+
+/**
+ * @define coll mutable map
+ * @define Coll `mutable.Map`
+ */
+trait MapOps[K, V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C <: MapOps[K, V, CC, C]]
+ extends IterableOps[(K, V), Iterable, C]
+ with collection.MapOps[K, V, CC, C]
+ with Cloneable[C]
+ with Builder[(K, V), C]
+ with Growable[(K, V)]
+ with Shrinkable[K] {
+
+ def result(): C = coll
+
+ @deprecated("Use - or remove on an immutable Map", "2.13.0")
+ final def - (key: K): C = clone() -= key
+
+ @deprecated("Use -- or removeAll on an immutable Map", "2.13.0")
+ final def - (key1: K, key2: K, keys: K*): C = clone() -= key1 -= key2 --= keys
+
+ /** Adds a new key/value pair to this map and optionally returns previously bound value.
+ * If the map already contains a
+ * mapping for the key, it will be overridden by the new value.
+ *
+ * @param key the key to update
+ * @param value the new value
+ * @return an option value containing the value associated with the key
+ * before the `put` operation was executed, or `None` if `key`
+ * was not defined in the map before.
+ */
+ def put(key: K, value: V): Option[V] = {
+ val r = get(key)
+ update(key, value)
+ r
+ }
+
+ /** Adds a new key/value pair to this map.
+ * If the map already contains a
+ * mapping for the key, it will be overridden by the new value.
+ *
+ * @param key The key to update
+ * @param value The new value
+ */
+ def update(key: K, value: V): Unit = { coll += ((key, value)) }
+
+ /**
+ * Update a mapping for the specified key and its current optionally mapped value
+ * (`Some` if there is current mapping, `None` if not).
+ *
+ * If the remapping function returns `Some(v)`, the mapping is updated with the new value `v`.
+ * If the remapping function returns `None`, the mapping is removed (or remains absent if initially absent).
+ * If the function itself throws an exception, the exception is rethrown, and the current mapping is left unchanged.
+ *
+ * @param key the key value
+ * @param remappingFunction a function that receives current optionally mapped value and return a new mapping
+ * @return the new value associated with the specified key
+ */
+ def updateWith(key: K)(remappingFunction: Option[V] => Option[V]): Option[V] = {
+ val previousValue = this.get(key)
+ val nextValue = remappingFunction(previousValue)
+ (previousValue, nextValue) match {
+ case (None, None) => // do nothing
+ case (Some(_), None) => this.remove(key)
+ case (_, Some(v)) => this.update(key,v)
+ }
+ nextValue
+ }
+
+ /** If given key is already in this map, returns associated value.
+ *
+ * Otherwise, computes value from given expression `defaultValue`, stores with key
+ * in map and returns that value.
+ *
+ * Concurrent map implementations may evaluate the expression `defaultValue`
+ * multiple times, or may evaluate `defaultValue` without inserting the result.
+ *
+ * @param key the key to test
+ * @param defaultValue the computation yielding the value to associate with `key`, if
+ * `key` is previously unbound.
+ * @return the value associated with key (either previously or as a result
+ * of executing the method).
+ */
+ def getOrElseUpdate(key: K, @deprecatedName("op", since="2.13.13") defaultValue: => V): V =
+ get(key) match {
+ case Some(v) => v
+ case None => val d = defaultValue; this(key) = d; d
+ }
+
+ /** Removes a key from this map, returning the value associated previously
+ * with that key as an option.
+ * @param key the key to be removed
+ * @return an option value containing the value associated previously with `key`,
+ * or `None` if `key` was not defined in the map before.
+ */
+ def remove(key: K): Option[V] = {
+ val r = get(key)
+ if (r.isDefined) this -= key
+ r
+ }
+
+ def clear(): Unit = { keysIterator foreach -= }
+
+ override def clone(): C = empty ++= this
+
+ @deprecated("Use filterInPlace instead", "2.13.0")
+ @inline final def retain(p: (K, V) => Boolean): this.type = filterInPlace(p)
+
+ /** Retains only those mappings for which the predicate
+ * `p` returns `true`.
+ *
+ * @param p The test predicate
+ */
+ def filterInPlace(p: (K, V) => Boolean): this.type = {
+ if (!isEmpty) this match {
+ case tm: concurrent.Map[_, _] => tm.asInstanceOf[concurrent.Map[K, V]].filterInPlaceImpl(p)
+ case _ =>
+ val array = this.toArray[Any] // scala/bug#7269 toArray avoids ConcurrentModificationException
+ val arrayLength = array.length
+ var i = 0
+ while (i < arrayLength) {
+ val (k, v) = array(i).asInstanceOf[(K, V)]
+ if (!p(k, v)) {
+ this -= k
+ }
+ i += 1
+ }
+ }
+ this
+ }
+
+ @deprecated("Use mapValuesInPlace instead", "2.13.0")
+ @inline final def transform(f: (K, V) => V): this.type = mapValuesInPlace(f)
+
+ /** Applies a transformation function to all values contained in this map.
+ * The transformation function produces new values from existing keys
+ * associated values.
+ *
+ * @param f the transformation to apply
+ * @return the map itself.
+ */
+ def mapValuesInPlace(f: (K, V) => V): this.type = {
+ if (!isEmpty) this match {
+ case hm: mutable.HashMap[_, _] => hm.asInstanceOf[mutable.HashMap[K, V]].mapValuesInPlaceImpl(f)
+ case tm: concurrent.Map[_, _] => tm.asInstanceOf[concurrent.Map[K, V]].mapValuesInPlaceImpl(f)
+ case _ =>
+ val array = this.toArray[Any]
+ val arrayLength = array.length
+ var i = 0
+ while (i < arrayLength) {
+ val (k, v) = array(i).asInstanceOf[(K, V)]
+ update(k, f(k, v))
+ i += 1
+ }
+ }
+ this
+ }
+
+ @deprecated("Use m.clone().addOne((k,v)) instead of m.updated(k, v)", "2.13.0")
+ def updated[V1 >: V](key: K, value: V1): CC[K, V1] =
+ clone().asInstanceOf[CC[K, V1]].addOne((key, value))
+
+ override def knownSize: Int = super[IterableOps].knownSize
+}
+
+/**
+ * $factoryInfo
+ * @define coll mutable map
+ * @define Coll `mutable.Map`
+ */
+@SerialVersionUID(3L)
+object Map extends MapFactory.Delegate[Map](HashMap) {
+
+ @SerialVersionUID(3L)
+ class WithDefault[K, V](val underlying: Map[K, V], val defaultValue: K => V)
+ extends AbstractMap[K, V]
+ with MapOps[K, V, Map, WithDefault[K, V]] with Serializable {
+
+ override def default(key: K): V = defaultValue(key)
+
+ def iterator: scala.collection.Iterator[(K, V)] = underlying.iterator
+ override def isEmpty: Boolean = underlying.isEmpty
+ override def knownSize: Int = underlying.knownSize
+ override def mapFactory: MapFactory[Map] = underlying.mapFactory
+
+ override def clear(): Unit = underlying.clear()
+
+ def get(key: K): Option[V] = underlying.get(key)
+
+ def subtractOne(elem: K): WithDefault.this.type = { underlying.subtractOne(elem); this }
+
+ def addOne(elem: (K, V)): WithDefault.this.type = { underlying.addOne(elem); this }
+
+ override def concat[V2 >: V](suffix: collection.IterableOnce[(K, V2)]): Map[K, V2] =
+ underlying.concat(suffix).withDefault(defaultValue)
+
+ override def empty: WithDefault[K, V] = new WithDefault[K, V](underlying.empty, defaultValue)
+
+ override protected def fromSpecific(coll: scala.collection.IterableOnce[(K, V)]): WithDefault[K, V] =
+ new WithDefault[K, V](mapFactory.from(coll), defaultValue)
+
+ override protected def newSpecificBuilder: Builder[(K, V), WithDefault[K, V]] =
+ Map.newBuilder.mapResult((p: Map[K, V]) => new WithDefault[K, V](p, defaultValue))
+ }
+
+}
+
+/** Explicit instantiation of the `Map` trait to reduce class file size in subclasses. */
+abstract class AbstractMap[K, V] extends scala.collection.AbstractMap[K, V] with Map[K, V]
diff --git a/library/src/scala/collection/mutable/MultiMap.scala b/library/src/scala/collection/mutable/MultiMap.scala
new file mode 100644
index 000000000000..b06a99b15d51
--- /dev/null
+++ b/library/src/scala/collection/mutable/MultiMap.scala
@@ -0,0 +1,115 @@
+/*
+ * 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.mutable
+
+
+/** A trait for mutable maps with multiple values assigned to a key.
+ *
+ * This class is typically used as a mixin. It turns maps which map `K`
+ * to `Set[V]` objects into multimaps that map `K` to `V` objects.
+ *
+ * @example {{{
+ * // first import all necessary types from package `collection.mutable`
+ * import collection.mutable.{ HashMap, MultiMap, Set }
+ *
+ * // to create a `MultiMap` the easiest way is to mixin it into a normal
+ * // `Map` instance
+ * val mm = new HashMap[Int, Set[String]] with MultiMap[Int, String]
+ *
+ * // to add key-value pairs to a multimap it is important to use
+ * // the method `addBinding` because standard methods like `+` will
+ * // overwrite the complete key-value pair instead of adding the
+ * // value to the existing key
+ * mm.addBinding(1, "a")
+ * mm.addBinding(2, "b")
+ * mm.addBinding(1, "c")
+ *
+ * // mm now contains `Map(2 -> Set(b), 1 -> Set(c, a))`
+ *
+ * // to check if the multimap contains a value there is method
+ * // `entryExists`, which allows to traverse the including set
+ * mm.entryExists(1, _ == "a") == true
+ * mm.entryExists(1, _ == "b") == false
+ * mm.entryExists(2, _ == "b") == true
+ *
+ * // to remove a previous added value there is the method `removeBinding`
+ * mm.removeBinding(1, "a")
+ * mm.entryExists(1, _ == "a") == false
+ * }}}
+ *
+ * @define coll multimap
+ * @define Coll `MultiMap`
+ */
+@deprecated("Use a scala.collection.mutable.MultiDict in the scala-collection-contrib module", "2.13.0")
+trait MultiMap[K, V] extends Map[K, Set[V]] {
+ /** Creates a new set.
+ *
+ * Classes that use this trait as a mixin can override this method
+ * to have the desired implementation of sets assigned to new keys.
+ * By default this is `HashSet`.
+ *
+ * @return An empty set of values of type `V`.
+ */
+ protected def makeSet: Set[V] = new HashSet[V]
+
+ /** Assigns the specified `value` to a specified `key`. If the key
+ * already has a binding to equal to `value`, nothing is changed;
+ * otherwise a new binding is added for that `key`.
+ *
+ * @param key The key to which to bind the new value.
+ * @param value The value to bind to the key.
+ * @return A reference to this multimap.
+ */
+ def addBinding(key: K, value: V): this.type = {
+ get(key) match {
+ case None =>
+ val set = makeSet
+ set += value
+ this(key) = set
+ case Some(set) =>
+ set += value
+ }
+ this
+ }
+
+ /** Removes the binding of `value` to `key` if it exists, otherwise this
+ * operation doesn't have any effect.
+ *
+ * If this was the last value assigned to the specified key, the
+ * set assigned to that key will be removed as well.
+ *
+ * @param key The key of the binding.
+ * @param value The value to remove.
+ * @return A reference to this multimap.
+ */
+ def removeBinding(key: K, value: V): this.type = {
+ get(key) match {
+ case None =>
+ case Some(set) =>
+ set -= value
+ if (set.isEmpty) this -= key
+ }
+ this
+ }
+
+ /** Checks if there exists a binding to `key` such that it satisfies the predicate `p`.
+ *
+ * @param key The key for which the predicate is checked.
+ * @param p The predicate which a value assigned to the key must satisfy.
+ * @return A boolean if such a binding exists
+ */
+ def entryExists(key: K, p: V => Boolean): Boolean = get(key) match {
+ case None => false
+ case Some(set) => set exists p
+ }
+}
diff --git a/library/src/scala/collection/mutable/MutationTracker.scala b/library/src/scala/collection/mutable/MutationTracker.scala
new file mode 100644
index 000000000000..fe0314068a43
--- /dev/null
+++ b/library/src/scala/collection/mutable/MutationTracker.scala
@@ -0,0 +1,78 @@
+/*
+ * 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 collection
+package mutable
+
+import java.util.ConcurrentModificationException
+
+/**
+ * Utilities to check that mutations to a client that tracks
+ * its mutations have not occurred since a given point.
+ * [[Iterator `Iterator`]]s that perform this check automatically
+ * during iteration can be created by wrapping an `Iterator`
+ * in a [[MutationTracker.CheckedIterator `CheckedIterator`]],
+ * or by manually using the [[MutationTracker.checkMutations() `checkMutations`]]
+ * and [[MutationTracker.checkMutationsForIteration() `checkMutationsForIteration`]]
+ * methods.
+ */
+private object MutationTracker {
+
+ /**
+ * Checks whether or not the actual mutation count differs from
+ * the expected one, throwing an exception, if it does.
+ *
+ * @param expectedCount the expected mutation count
+ * @param actualCount the actual mutation count
+ * @param message the exception message in case of mutations
+ * @throws ConcurrentModificationException if the expected and actual
+ * mutation counts differ
+ */
+ @throws[ConcurrentModificationException]
+ def checkMutations(expectedCount: Int, actualCount: Int, message: String): Unit = {
+ if (actualCount != expectedCount) throw new ConcurrentModificationException(message)
+ }
+
+ /**
+ * Checks whether or not the actual mutation count differs from
+ * the expected one, throwing an exception, if it does. This method
+ * produces an exception message saying that it was called because a
+ * backing collection was mutated during iteration.
+ *
+ * @param expectedCount the expected mutation count
+ * @param actualCount the actual mutation count
+ * @throws ConcurrentModificationException if the expected and actual
+ * mutation counts differ
+ */
+ @throws[ConcurrentModificationException]
+ @inline def checkMutationsForIteration(expectedCount: Int, actualCount: Int): Unit =
+ checkMutations(expectedCount, actualCount, "mutation occurred during iteration")
+
+ /**
+ * An iterator wrapper that checks if the underlying collection has
+ * been mutated.
+ *
+ * @param underlying the underlying iterator
+ * @param mutationCount a by-name provider of the current mutation count
+ * @tparam A the type of the iterator's elements
+ */
+ final class CheckedIterator[A](underlying: Iterator[A], mutationCount: => Int) extends AbstractIterator[A] {
+ private[this] val expectedCount = mutationCount
+
+ def hasNext: Boolean = {
+ checkMutationsForIteration(expectedCount, mutationCount)
+ underlying.hasNext
+ }
+ def next(): A = underlying.next()
+ }
+}
diff --git a/library/src/scala/collection/mutable/OpenHashMap.scala b/library/src/scala/collection/mutable/OpenHashMap.scala
new file mode 100644
index 000000000000..5840a0abc954
--- /dev/null
+++ b/library/src/scala/collection/mutable/OpenHashMap.scala
@@ -0,0 +1,306 @@
+/*
+ * 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 mutable
+
+import java.lang.Integer.numberOfLeadingZeros
+import java.util.ConcurrentModificationException
+import scala.collection.generic.DefaultSerializable
+
+/**
+ * @define Coll `OpenHashMap`
+ * @define coll open hash map
+ */
+@deprecated("Use HashMap or one of the specialized versions (LongMap, AnyRefMap) instead of OpenHashMap", "2.13.0")
+@SerialVersionUID(3L)
+object OpenHashMap extends MapFactory[OpenHashMap] {
+
+ def empty[K, V] = new OpenHashMap[K, V]
+ def from[K, V](it: IterableOnce[(K, V)]): OpenHashMap[K,V] = empty ++= it
+
+ def newBuilder[K, V]: Builder[(K, V), OpenHashMap[K,V]] =
+ new GrowableBuilder[(K, V), OpenHashMap[K, V]](empty)
+
+ /** A hash table entry.
+ *
+ * The entry is occupied if and only if its `value` is a `Some`;
+ * deleted if and only if its `value` is `None`.
+ * If its `key` is not the default value of type `Key`, the entry is occupied.
+ * If the entry is occupied, `hash` contains the hash value of `key`.
+ */
+ final private class OpenEntry[Key, Value](var key: Key,
+ var hash: Int,
+ var value: Option[Value])
+
+ private[mutable] def nextPositivePowerOfTwo(target: Int): Int = 1 << -numberOfLeadingZeros(target - 1)
+}
+
+/** A mutable hash map based on an open addressing method. The precise scheme is
+ * undefined, but it should make a reasonable effort to ensure that an insert
+ * with consecutive hash codes is not unnecessarily penalised. In particular,
+ * mappings of consecutive integer keys should work without significant
+ * performance loss.
+ *
+ * @tparam Key type of the keys in this map.
+ * @tparam Value type of the values in this map.
+ * @param initialSize the initial size of the internal hash table.
+ *
+ * @define Coll `OpenHashMap`
+ * @define coll open hash map
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+@deprecated("Use HashMap or one of the specialized versions (LongMap, AnyRefMap) instead of OpenHashMap", "2.13.0")
+class OpenHashMap[Key, Value](initialSize : Int)
+ extends AbstractMap[Key, Value]
+ with MapOps[Key, Value, OpenHashMap, OpenHashMap[Key, Value]]
+ with StrictOptimizedIterableOps[(Key, Value), Iterable, OpenHashMap[Key, Value]]
+ with MapFactoryDefaults[Key, Value, OpenHashMap, Iterable]
+ with DefaultSerializable {
+
+ import OpenHashMap.OpenEntry
+ private type Entry = OpenEntry[Key, Value]
+
+ /** A default constructor creates a hashmap with initial size `8`.
+ */
+ def this() = this(8)
+
+ override def mapFactory: MapFactory[OpenHashMap] = OpenHashMap
+
+ private[this] val actualInitialSize = OpenHashMap.nextPositivePowerOfTwo(initialSize)
+
+ private[this] var mask = actualInitialSize - 1
+
+ /** The hash table.
+ *
+ * The table's entries are initialized to `null`, indication of an empty slot.
+ * A slot is either deleted or occupied if and only if the entry is non-`null`.
+ */
+ private[this] var table = new Array[Entry](actualInitialSize)
+
+ private[this] var _size = 0
+ private[this] var deleted = 0
+
+ // Used for tracking inserts so that iterators can determine if concurrent modification has occurred.
+ private[this] var modCount = 0
+
+ override def size = _size
+ override def knownSize: Int = size
+ private[this] def size_=(s : Int): Unit = _size = s
+ override def isEmpty: Boolean = _size == 0
+ /** Returns a mangled hash code of the provided key. */
+ protected def hashOf(key: Key) = {
+ var h = key.##
+ h ^= ((h >>> 20) ^ (h >>> 12))
+ h ^ (h >>> 7) ^ (h >>> 4)
+ }
+
+ /** Increase the size of the table.
+ * Copy only the occupied slots, effectively eliminating the deleted slots.
+ */
+ private[this] def growTable() = {
+ val oldSize = mask + 1
+ val newSize = 4 * oldSize
+ val oldTable = table
+ table = new Array[Entry](newSize)
+ mask = newSize - 1
+ oldTable.foreach( entry =>
+ if (entry != null && entry.value != None)
+ table(findIndex(entry.key, entry.hash)) = entry )
+ deleted = 0
+ }
+
+ /** Return the index of the first slot in the hash table (in probe order)
+ * that is, in order of preference, either occupied by the given key, deleted, or empty.
+ *
+ * @param hash hash value for `key`
+ */
+ private[this] def findIndex(key: Key, hash: Int): Int = {
+ var index = hash & mask
+ var j = 0
+
+ // Index of the first slot containing a deleted entry, or -1 if none found yet
+ var firstDeletedIndex = -1
+
+ var entry = table(index)
+ while (entry != null) {
+ if (entry.hash == hash && entry.key == key && entry.value != None)
+ return index
+
+ if (firstDeletedIndex == -1 && entry.value == None)
+ firstDeletedIndex = index
+
+ j += 1
+ index = (index + j) & mask
+ entry = table(index)
+ }
+
+ if (firstDeletedIndex == -1) index else firstDeletedIndex
+ }
+
+ // TODO refactor `put` to extract `findOrAddEntry` and implement this in terms of that to avoid Some boxing.
+ override def update(key: Key, value: Value): Unit = put(key, value)
+
+ @deprecatedOverriding("addOne should not be overridden in order to maintain consistency with put.", "2.11.0")
+ def addOne (kv: (Key, Value)): this.type = { put(kv._1, kv._2); this }
+
+ @deprecatedOverriding("subtractOne should not be overridden in order to maintain consistency with remove.", "2.11.0")
+ def subtractOne (key: Key): this.type = { remove(key); this }
+
+ override def put(key: Key, value: Value): Option[Value] =
+ put(key, hashOf(key), value)
+
+ private def put(key: Key, hash: Int, value: Value): Option[Value] = {
+ if (2 * (size + deleted) > mask) growTable()
+ val index = findIndex(key, hash)
+ val entry = table(index)
+ if (entry == null) {
+ table(index) = new OpenEntry(key, hash, Some(value))
+ modCount += 1
+ size += 1
+ None
+ } else {
+ val res = entry.value
+ if (entry.value == None) {
+ entry.key = key
+ entry.hash = hash
+ size += 1
+ deleted -= 1
+ modCount += 1
+ }
+ entry.value = Some(value)
+ res
+ }
+ }
+
+ /** Delete the hash table slot contained in the given entry. */
+ @`inline`
+ private[this] def deleteSlot(entry: Entry) = {
+ entry.key = null.asInstanceOf[Key]
+ entry.hash = 0
+ entry.value = None
+
+ size -= 1
+ deleted += 1
+ }
+
+ override def remove(key : Key): Option[Value] = {
+ val entry = table(findIndex(key, hashOf(key)))
+ if (entry != null && entry.value != None) {
+ val res = entry.value
+ deleteSlot(entry)
+ res
+ } else None
+ }
+
+ def get(key : Key) : Option[Value] = {
+ val hash = hashOf(key)
+ var index = hash & mask
+ var entry = table(index)
+ var j = 0
+ while(entry != null){
+ if (entry.hash == hash &&
+ entry.key == key){
+ return entry.value
+ }
+
+ j += 1
+ index = (index + j) & mask
+ entry = table(index)
+ }
+ None
+ }
+
+ /** An iterator over the elements of this map. Use of this iterator follows
+ * the same contract for concurrent modification as the foreach method.
+ *
+ * @return the iterator
+ */
+ def iterator: Iterator[(Key, Value)] = new OpenHashMapIterator[(Key, Value)] {
+ override protected def nextResult(node: Entry): (Key, Value) = (node.key, node.value.get)
+ }
+
+ override def keysIterator: Iterator[Key] = new OpenHashMapIterator[Key] {
+ override protected def nextResult(node: Entry): Key = node.key
+ }
+ override def valuesIterator: Iterator[Value] = new OpenHashMapIterator[Value] {
+ override protected def nextResult(node: Entry): Value = node.value.get
+ }
+
+ private abstract class OpenHashMapIterator[A] extends AbstractIterator[A] {
+ private[this] var index = 0
+ private[this] val initialModCount = modCount
+
+ private[this] def advance(): Unit = {
+ if (initialModCount != modCount) throw new ConcurrentModificationException
+ while((index <= mask) && (table(index) == null || table(index).value == None)) index+=1
+ }
+
+ def hasNext = {advance(); index <= mask }
+
+ def next() = {
+ advance()
+ val result = table(index)
+ index += 1
+ nextResult(result)
+ }
+ protected def nextResult(node: Entry): A
+ }
+
+ override def clone() = {
+ val it = new OpenHashMap[Key, Value]
+ foreachUndeletedEntry(entry => it.put(entry.key, entry.hash, entry.value.get))
+ it
+ }
+
+ /** Loop over the key, value mappings of this map.
+ *
+ * The behaviour of modifying the map during an iteration is as follows:
+ * - Deleting a mapping is always permitted.
+ * - Changing the value of mapping which is already present is permitted.
+ * - Anything else is not permitted. It will usually, but not always, throw an exception.
+ *
+ * @tparam U The return type of the specified function `f`, return result of which is ignored.
+ * @param f The function to apply to each key, value mapping.
+ */
+ override def foreach[U](f : ((Key, Value)) => U): Unit = {
+ val startModCount = modCount
+ foreachUndeletedEntry(entry => {
+ if (modCount != startModCount) throw new ConcurrentModificationException
+ f((entry.key, entry.value.get))}
+ )
+ }
+ override def foreachEntry[U](f : (Key, Value) => U): Unit = {
+ val startModCount = modCount
+ foreachUndeletedEntry(entry => {
+ if (modCount != startModCount) throw new ConcurrentModificationException
+ f(entry.key, entry.value.get)}
+ )
+ }
+
+ private[this] def foreachUndeletedEntry(f : Entry => Unit): Unit = {
+ table.foreach(entry => if (entry != null && entry.value != None) f(entry))
+ }
+
+ override def mapValuesInPlace(f : (Key, Value) => Value): this.type = {
+ foreachUndeletedEntry(entry => entry.value = Some(f(entry.key, entry.value.get)))
+ this
+ }
+
+ override def filterInPlace(f : (Key, Value) => Boolean): this.type = {
+ foreachUndeletedEntry(entry => if (!f(entry.key, entry.value.get)) deleteSlot(entry))
+ this
+ }
+
+ override protected[this] def stringPrefix = "OpenHashMap"
+}
diff --git a/library/src/scala/collection/mutable/PriorityQueue.scala b/library/src/scala/collection/mutable/PriorityQueue.scala
new file mode 100644
index 000000000000..147cffc22a95
--- /dev/null
+++ b/library/src/scala/collection/mutable/PriorityQueue.scala
@@ -0,0 +1,413 @@
+/*
+ * 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 mutable
+
+import scala.collection.generic.DefaultSerializationProxy
+import scala.math.Ordering
+
+/** A heap-based priority queue.
+ *
+ * To prioritize elements of type `A` there must be an implicit
+ * `Ordering[A]` available at creation. Elements are retrieved
+ * in priority order by using [[dequeue]] or [[dequeueAll]].
+ *
+ * If multiple elements have the same priority as determined by the ordering for this
+ * `PriorityQueue`, no guarantees are made regarding the order in which those elements
+ * are returned by `dequeue` or `dequeueAll`. In particular, that means this
+ * class does not guarantee first-in-first-out behavior, as may be
+ * incorrectly inferred from the fact that this data structure is
+ * called a "queue".
+ *
+ * Only the `dequeue` and `dequeueAll` methods will return elements in priority
+ * order (while removing elements from the heap). Standard collection methods
+ * such as `drop`, `iterator`, `toList` and `toString` use an arbitrary
+ * iteration order: they will traverse the heap or remove elements
+ * in whichever order seems most convenient.
+ *
+ * Therefore, printing a `PriorityQueue` will not show elements in priority order,
+ * though the highest-priority element will be printed first.
+ * To print the elements in order, it's necessary to `dequeue` them.
+ * To do this non-destructively, duplicate the `PriorityQueue` first;
+ * the `clone` method is a suitable way to obtain a disposable copy.
+ *
+ * Client keys are assumed to be immutable. Mutating keys may violate
+ * the invariant of the underlying heap-ordered tree. Note that [[clone]]
+ * does not rebuild the underlying tree.
+ *
+ * {{{
+ * scala> val pq = collection.mutable.PriorityQueue(1, 2, 5, 3, 7)
+ * val pq: scala.collection.mutable.PriorityQueue[Int] = PriorityQueue(7, 3, 5, 1, 2)
+ *
+ * scala> pq.toList // also not in order
+ * val res0: List[Int] = List(7, 3, 5, 1, 2)
+ *
+ * scala> pq.clone.dequeueAll
+ * val res1: Seq[Int] = ArraySeq(7, 5, 3, 2, 1)
+ * }}}
+ *
+ * @tparam A type of the elements in this priority queue.
+ * @param ord implicit ordering used to compare the elements of type `A`.
+ *
+ * @define Coll PriorityQueue
+ * @define coll priority queue
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+sealed class PriorityQueue[A](implicit val ord: Ordering[A])
+ extends AbstractIterable[A]
+ with Iterable[A]
+ with IterableOps[A, Iterable, PriorityQueue[A]]
+ with StrictOptimizedIterableOps[A, Iterable, PriorityQueue[A]]
+ with Builder[A, PriorityQueue[A]]
+ with Cloneable[PriorityQueue[A]]
+ with Growable[A]
+ with Serializable
+{
+
+ private class ResizableArrayAccess[A0] extends ArrayBuffer[A0] {
+ override def mapInPlace(f: A0 => A0): this.type = {
+ var i = 1 // see "we do not use array(0)" comment below (???)
+ val siz = this.size
+ while (i < siz) { this(i) = f(this(i)); i += 1 }
+ this
+ }
+
+ def p_size0 = size0
+ def p_size0_=(s: Int) = size0 = s
+ def p_array = array
+ def p_ensureSize(n: Int) = super.ensureSize(n)
+ def p_ensureAdditionalSize(n: Int) = super.ensureSize(size0 + n)
+ def p_swap(a: Int, b: Int): Unit = {
+ val h = array(a)
+ array(a) = array(b)
+ array(b) = h
+ }
+ }
+
+ private val resarr = new ResizableArrayAccess[A]
+
+ // we do not use array(0)
+ // storing the root of the heap at array(1) simplifies the calculations for
+ // parent and child indices: for a given index k, the parent of k is k / 2,
+ // the left child is k * 2, and the right child is k * 2 + 1
+ resarr.p_size0 += 1
+ /** Alias for [[size]]. */
+ def length: Int = resarr.length - 1 // adjust length accordingly
+ override def size: Int = length
+ override def knownSize: Int = length
+ override def isEmpty: Boolean = resarr.p_size0 < 2
+
+ // not eligible for EvidenceIterableFactoryDefaults since C != CC[A] (PriorityQueue[A] != Iterable[A])
+ override protected def fromSpecific(coll: scala.collection.IterableOnce[A]): PriorityQueue[A] = PriorityQueue.from(coll)
+ override protected def newSpecificBuilder: Builder[A, PriorityQueue[A]] = PriorityQueue.newBuilder
+ override def empty: PriorityQueue[A] = PriorityQueue.empty
+
+ /** Replace the contents of this $coll with the mapped result.
+ *
+ * @param f the mapping function
+ * @return this $coll
+ */
+ def mapInPlace(f: A => A): this.type = {
+ resarr.mapInPlace(f)
+ heapify(1)
+ this
+ }
+
+ def result() = this
+
+ private def toA(x: AnyRef): A = x.asInstanceOf[A]
+ protected def fixUp(as: Array[AnyRef], m: Int): Unit = {
+ var k: Int = m
+ // use `ord` directly to avoid allocating `OrderingOps`
+ while (k > 1 && ord.lt(toA(as(k / 2)), toA(as(k)))) {
+ resarr.p_swap(k, k / 2)
+ k = k / 2
+ }
+ }
+
+ protected def fixDown(as: Array[AnyRef], m: Int, n: Int): Boolean = {
+ // returns true if any swaps were done (used in heapify)
+ var k: Int = m
+ while (n >= 2 * k) {
+ var j = 2 * k
+ // use `ord` directly to avoid allocating `OrderingOps`
+ if (j < n && ord.lt(toA(as(j)), toA(as(j + 1))))
+ j += 1
+ if (ord.gteq(toA(as(k)), toA(as(j))))
+ return k != m
+ else {
+ val h = as(k)
+ as(k) = as(j)
+ as(j) = h
+ k = j
+ }
+ }
+ k != m
+ }
+
+ /** Inserts a single element into the priority queue.
+ *
+ * @param elem the element to insert.
+ * @return this $coll.
+ */
+ def addOne(elem: A): this.type = {
+ resarr.p_ensureAdditionalSize(1)
+ resarr.p_array(resarr.p_size0) = elem.asInstanceOf[AnyRef]
+ fixUp(resarr.p_array, resarr.p_size0)
+ resarr.p_size0 += 1
+ this
+ }
+
+ override def addAll(xs: IterableOnce[A]): this.type = {
+ val from = resarr.p_size0
+ for (x <- xs.iterator) unsafeAdd(x)
+ heapify(from)
+ this
+ }
+
+ private def unsafeAdd(elem: A): Unit = {
+ // like += but skips fixUp, which breaks the ordering invariant
+ // a series of unsafeAdds MUST be followed by heapify
+ resarr.p_ensureAdditionalSize(1)
+ resarr.p_array(resarr.p_size0) = elem.asInstanceOf[AnyRef]
+ resarr.p_size0 += 1
+ }
+
+ private def heapify(from: Int): Unit = {
+ // elements at indices 1..from-1 were already in heap order before any adds
+ // elements at indices from..n are newly added, their order must be fixed
+ val n = length
+
+ if (from <= 2) {
+ // no pre-existing order to maintain, do the textbook heapify algorithm
+ for (i <- n/2 to 1 by -1) fixDown(resarr.p_array, i, n)
+ }
+ else if (n - from < 4) {
+ // for very small adds, doing the simplest fix is faster
+ for (i <- from to n) fixUp(resarr.p_array, i)
+ }
+ else {
+ var min = from/2 // tracks the minimum element in the queue
+ val queue = scala.collection.mutable.Queue[Int](min)
+
+ // do fixDown on the parents of all the new elements
+ // except the parent of the first new element, which is in the queue
+ // (that parent is treated specially because it might be the root)
+ for (i <- n/2 until min by -1) {
+ if (fixDown(resarr.p_array, i, n)) {
+ // there was a swap, so also need to fixDown i's parent
+ val parent = i/2
+ if (parent < min) { // make sure same parent isn't added twice
+ min = parent
+ queue += parent
+ }
+ }
+ }
+
+ while (queue.nonEmpty) {
+ val i = queue.dequeue()
+ if (fixDown(resarr.p_array, i, n)) {
+ val parent = i/2
+ if (parent < min && parent > 0) {
+ // the "parent > 0" is to avoid adding the parent of the root
+ min = parent
+ queue += parent
+ }
+ }
+ }
+ }
+ }
+
+ /** Adds all elements provided by a `IterableOnce` object
+ * into the priority queue.
+ *
+ * @param xs a iterable object.
+ * @return a new priority queue containing elements of both `xs` and `this`.
+ */
+ def ++(xs: IterableOnce[A]): PriorityQueue[A] = { this.clone() ++= xs }
+
+ /** Adds all elements to the queue.
+ *
+ * @param elems the elements to add.
+ */
+ def enqueue(elems: A*): Unit = { this ++= elems }
+
+ /** Returns the element with the highest priority in the queue,
+ * and removes this element from the queue.
+ *
+ * @return the element with the highest priority.
+ * @throws NoSuchElementException if no element to remove from heap
+ */
+ def dequeue(): A =
+ if (resarr.p_size0 > 1) {
+ resarr.p_size0 = resarr.p_size0 - 1
+ val result = resarr.p_array(1)
+ resarr.p_array(1) = resarr.p_array(resarr.p_size0)
+ resarr.p_array(resarr.p_size0) = null // erase reference from array
+ fixDown(resarr.p_array, 1, resarr.p_size0 - 1)
+ toA(result)
+ } else
+ throw new NoSuchElementException("no element to remove from heap")
+
+ /** Dequeues all elements and returns them in a sequence, in priority order. */
+ def dequeueAll[A1 >: A]: immutable.Seq[A1] = {
+ val b = ArrayBuilder.make[Any]
+ b.sizeHint(size)
+ while (nonEmpty) {
+ b += dequeue()
+ }
+ immutable.ArraySeq.unsafeWrapArray(b.result()).asInstanceOf[immutable.ArraySeq[A1]]
+ }
+
+ /** Returns the element with the highest priority in the queue,
+ * or throws an error if there is no element contained in the queue.
+ *
+ * @return the element with the highest priority.
+ */
+ override def head: A = if (resarr.p_size0 > 1) toA(resarr.p_array(1)) else throw new NoSuchElementException("queue is empty")
+
+ /** Removes all elements from the queue. After this operation is completed,
+ * the queue will be empty.
+ */
+ def clear(): Unit = {
+ resarr.clear()
+ resarr.p_size0 = 1
+ }
+
+ /** Returns an iterator which yields all the elements.
+ *
+ * Note: The order of elements returned is undefined.
+ * If you want to traverse the elements in priority queue
+ * order, use `clone().dequeueAll.iterator`.
+ *
+ * @return an iterator over all the elements.
+ */
+ override def iterator: Iterator[A] = resarr.iterator.drop(1)
+
+ /** Returns the reverse of this priority queue. The new priority queue has
+ * the same elements as the original, but the opposite ordering.
+ *
+ * For example, the element with the highest priority in `pq` has the lowest
+ * priority in `pq.reverse`, and vice versa.
+ *
+ * Ties are handled arbitrarily. Elements with equal priority may or
+ * may not be reversed with respect to each other.
+ *
+ * @return the reversed priority queue.
+ */
+ def reverse: PriorityQueue[A] = {
+ val revq = new PriorityQueue[A]()(ord.reverse)
+ // copy the existing data into the new array backwards
+ // this won't put it exactly into the correct order,
+ // but will require less fixing than copying it in
+ // the original order
+ val n = resarr.p_size0
+ revq.resarr.p_ensureSize(n)
+ revq.resarr.p_size0 = n
+ val from = resarr.p_array
+ val to = revq.resarr.p_array
+ for (i <- 1 until n) to(i) = from(n-i)
+ revq.heapify(1)
+ revq
+ }
+
+
+ /** Returns an iterator which yields all the elements in the reverse order
+ * than that returned by the method `iterator`.
+ *
+ * Note: The order of elements returned is undefined.
+ *
+ * @return an iterator over all elements sorted in descending order.
+ */
+ def reverseIterator: Iterator[A] = new AbstractIterator[A] {
+ private[this] var i = resarr.p_size0 - 1
+ def hasNext: Boolean = i >= 1
+ def next(): A = {
+ val n = resarr.p_array(i)
+ i -= 1
+ toA(n)
+ }
+ }
+
+ /** Returns a regular queue containing the same elements.
+ *
+ * Note: the order of elements is undefined.
+ */
+ def toQueue: Queue[A] = new Queue[A] ++= this.iterator
+
+ /** Returns a textual representation of a queue as a string.
+ *
+ * @return the string representation of this queue.
+ */
+ override def toString() = toList.mkString("PriorityQueue(", ", ", ")")
+
+ /** Converts this $coll to a list.
+ *
+ * Note: the order of elements is undefined.
+ *
+ * @return a list containing all elements of this $coll.
+ */
+ override def toList: immutable.List[A] = immutable.List.from(this.iterator)
+
+ /** This method clones the priority queue.
+ *
+ * @return a priority queue with the same elements.
+ */
+ override def clone(): PriorityQueue[A] = {
+ val pq = new PriorityQueue[A]
+ val n = resarr.p_size0
+ pq.resarr.p_ensureSize(n)
+ java.lang.System.arraycopy(resarr.p_array, 1, pq.resarr.p_array, 1, n-1)
+ pq.resarr.p_size0 = n
+ pq
+ }
+
+ override def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Int = {
+ val copied = IterableOnce.elemsToCopyToArray(length, xs.length, start, len)
+ if (copied > 0) {
+ Array.copy(resarr.p_array, 1, xs, start, copied)
+ }
+ copied
+ }
+
+ @deprecated("Use `PriorityQueue` instead", "2.13.0")
+ def orderedCompanion: PriorityQueue.type = PriorityQueue
+
+ protected[this] def writeReplace(): AnyRef = new DefaultSerializationProxy(PriorityQueue.evidenceIterableFactory[A], this)
+
+ override protected[this] def className = "PriorityQueue"
+}
+
+
+@SerialVersionUID(3L)
+object PriorityQueue extends SortedIterableFactory[PriorityQueue] {
+ def newBuilder[A : Ordering]: Builder[A, PriorityQueue[A]] = {
+ new Builder[A, PriorityQueue[A]] {
+ val pq = new PriorityQueue[A]
+ def addOne(elem: A): this.type = { pq.unsafeAdd(elem); this }
+ def result(): PriorityQueue[A] = { pq.heapify(1); pq }
+ def clear(): Unit = pq.clear()
+ }
+ }
+
+ def empty[A : Ordering]: PriorityQueue[A] = new PriorityQueue[A]
+
+ def from[E : Ordering](it: IterableOnce[E]): PriorityQueue[E] = {
+ val b = newBuilder[E]
+ b ++= it
+ b.result()
+ }
+}
diff --git a/library/src/scala/collection/mutable/Queue.scala b/library/src/scala/collection/mutable/Queue.scala
new file mode 100644
index 000000000000..cc3dad2e2495
--- /dev/null
+++ b/library/src/scala/collection/mutable/Queue.scala
@@ -0,0 +1,138 @@
+/*
+ * 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 mutable
+
+import scala.annotation.nowarn
+import scala.collection.generic.DefaultSerializable
+
+
+/** `Queue` objects implement data structures that allow to
+ * insert and retrieve elements in a first-in-first-out (FIFO) manner.
+ *
+ * @define Coll `mutable.Queue`
+ * @define coll mutable queue
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+class Queue[A] protected (array: Array[AnyRef], start: Int, end: Int)
+ extends ArrayDeque[A](array, start, end)
+ with IndexedSeqOps[A, Queue, Queue[A]]
+ with StrictOptimizedSeqOps[A, Queue, Queue[A]]
+ with IterableFactoryDefaults[A, Queue]
+ with ArrayDequeOps[A, Queue, Queue[A]]
+ with Cloneable[Queue[A]]
+ with DefaultSerializable {
+
+ def this(initialSize: Int = ArrayDeque.DefaultInitialSize) =
+ this(ArrayDeque.alloc(initialSize), start = 0, end = 0)
+
+ override def iterableFactory: SeqFactory[Queue] = Queue
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix = "Queue"
+
+ /**
+ * Add elements to the end of this queue
+ *
+ * @param elem
+ * @return this
+ */
+ def enqueue(elem: A): this.type = this += elem
+
+ /** Enqueue two or more elements at the end of the queue. The last element
+ * of the sequence will be on end of the queue.
+ *
+ * @param elems the element sequence.
+ * @return this
+ */
+ def enqueue(elem1: A, elem2: A, elems: A*): this.type = enqueue(elem1).enqueue(elem2).enqueueAll(elems)
+
+ /** Enqueues all elements in the given iterable object into the queue. The
+ * last element in the iterable object will be on front of the new queue.
+ *
+ * @param elems the iterable object.
+ * @return this
+ */
+ def enqueueAll(elems: scala.collection.IterableOnce[A]): this.type = this ++= elems
+
+ /**
+ * Removes the first element from this queue and returns it
+ *
+ * @return
+ * @throws NoSuchElementException when queue is empty
+ */
+ def dequeue(): A = removeHead()
+
+ /** Returns the first element in the queue which satisfies the
+ * given predicate, and removes this element from the queue.
+ *
+ * @param p the predicate used for choosing the first element
+ * @return the first element of the queue for which p yields true
+ */
+ def dequeueFirst(p: A => Boolean): Option[A] =
+ removeFirst(p)
+
+ /** Returns all elements in the queue which satisfy the
+ * given predicate, and removes those elements from the queue.
+ *
+ * @param p the predicate used for choosing elements
+ * @return a sequence of all elements in the queue for which
+ * p yields true.
+ */
+ def dequeueAll(p: A => Boolean): scala.collection.immutable.Seq[A] =
+ removeAll(p)
+
+ /**
+ * Returns and dequeues all elements from the queue which satisfy the given predicate
+ *
+ * @param f the predicate used for choosing elements
+ * @return The removed elements
+ */
+ def dequeueWhile(f: A => Boolean): scala.collection.Seq[A] = removeHeadWhile(f)
+
+ /** Returns the first element in the queue, or throws an error if there
+ * is no element contained in the queue.
+ *
+ * @return the first element.
+ */
+ @`inline` final def front: A = head
+
+ override protected def klone(): Queue[A] = {
+ val bf = newSpecificBuilder
+ bf ++= this
+ bf.result()
+ }
+
+ override protected def ofArray(array: Array[AnyRef], end: Int): Queue[A] =
+ new Queue(array, start = 0, end)
+
+}
+
+/**
+ * $factoryInfo
+ * @define coll queue
+ * @define Coll `Queue`
+ */
+@SerialVersionUID(3L)
+object Queue extends StrictOptimizedSeqFactory[Queue] {
+
+ def from[A](source: IterableOnce[A]): Queue[A] = empty ++= source
+
+ def empty[A]: Queue[A] = new Queue
+
+ def newBuilder[A]: Builder[A, Queue[A]] = new GrowableBuilder[A, Queue[A]](empty)
+
+}
diff --git a/library/src/scala/collection/mutable/RedBlackTree.scala b/library/src/scala/collection/mutable/RedBlackTree.scala
new file mode 100644
index 000000000000..aca36f0271d8
--- /dev/null
+++ b/library/src/scala/collection/mutable/RedBlackTree.scala
@@ -0,0 +1,652 @@
+/*
+ * 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 collection.mutable
+
+import scala.annotation.tailrec
+import collection.{AbstractIterator, Iterator}
+import java.lang.String
+
+/**
+ * An object containing the red-black tree implementation used by mutable `TreeMaps`.
+ *
+ * The trees implemented in this object are *not* thread safe.
+ */
+private[collection] object RedBlackTree {
+
+ // ---- class structure ----
+
+ // For performance reasons, this implementation uses `null` references to represent leaves instead of a sentinel node.
+ // Currently, the internal nodes do not store their subtree size - only the tree object keeps track of their size.
+ // Therefore, while obtaining the size of the whole tree is O(1), knowing the number of entries inside a range is O(n)
+ // on the size of the range.
+
+ final class Tree[A, B](var root: Node[A, B], var size: Int) {
+ def treeCopy(): Tree[A, B] = new Tree(copyTree(root), size)
+ }
+
+ final class Node[A, B](var key: A, var value: B, var red: Boolean, var left: Node[A, B], var right: Node[A, B], var parent: Node[A, B]) {
+ override def toString: String = "Node(" + key + ", " + value + ", " + red + ", " + left + ", " + right + ")"
+ }
+
+ object Tree {
+ def empty[A, B]: Tree[A, B] = new Tree(null, 0)
+ }
+
+ object Node {
+
+ @`inline` def apply[A, B](key: A, value: B, red: Boolean,
+ left: Node[A, B], right: Node[A, B], parent: Node[A, B]): Node[A, B] =
+ new Node(key, value, red, left, right, parent)
+
+ @`inline` def leaf[A, B](key: A, value: B, red: Boolean, parent: Node[A, B]): Node[A, B] =
+ new Node(key, value, red, null, null, parent)
+
+ def unapply[A, B](t: Node[A, B]) = Some((t.key, t.value, t.left, t.right, t.parent))
+ }
+
+ // ---- getters ----
+
+ def isRed(node: Node[_, _]) = (node ne null) && node.red
+ def isBlack(node: Node[_, _]) = (node eq null) || !node.red
+
+ // ---- size ----
+
+ def size(node: Node[_, _]): Int = if (node eq null) 0 else 1 + size(node.left) + size(node.right)
+ def size(tree: Tree[_, _]): Int = tree.size
+ def isEmpty(tree: Tree[_, _]) = tree.root eq null
+ def clear(tree: Tree[_, _]): Unit = { tree.root = null; tree.size = 0 }
+
+ // ---- search ----
+
+ def get[A: Ordering, B](tree: Tree[A, B], key: A): Option[B] = getNode(tree.root, key) match {
+ case null => None
+ case node => Some(node.value)
+ }
+
+ @tailrec private[this] def getNode[A, B](node: Node[A, B], key: A)(implicit ord: Ordering[A]): Node[A, B] =
+ if (node eq null) null
+ else {
+ val cmp = ord.compare(key, node.key)
+ if (cmp < 0) getNode(node.left, key)
+ else if (cmp > 0) getNode(node.right, key)
+ else node
+ }
+
+ def contains[A: Ordering](tree: Tree[A, _], key: A): Boolean = getNode(tree.root, key) ne null
+
+ def min[A, B](tree: Tree[A, B]): Option[(A, B)] = minNode(tree.root) match {
+ case null => None
+ case node => Some((node.key, node.value))
+ }
+
+ def minKey[A](tree: Tree[A, _]): Option[A] = minNode(tree.root) match {
+ case null => None
+ case node => Some(node.key)
+ }
+
+ private def minNode[A, B](node: Node[A, B]): Node[A, B] =
+ if (node eq null) null else minNodeNonNull(node)
+
+ @tailrec def minNodeNonNull[A, B](node: Node[A, B]): Node[A, B] =
+ if (node.left eq null) node else minNodeNonNull(node.left)
+
+ def max[A, B](tree: Tree[A, B]): Option[(A, B)] = maxNode(tree.root) match {
+ case null => None
+ case node => Some((node.key, node.value))
+ }
+
+ def maxKey[A](tree: Tree[A, _]): Option[A] = maxNode(tree.root) match {
+ case null => None
+ case node => Some(node.key)
+ }
+
+ private def maxNode[A, B](node: Node[A, B]): Node[A, B] =
+ if (node eq null) null else maxNodeNonNull(node)
+
+ @tailrec def maxNodeNonNull[A, B](node: Node[A, B]): Node[A, B] =
+ if (node.right eq null) node else maxNodeNonNull(node.right)
+
+ /**
+ * Returns the first (lowest) map entry with a key equal or greater than `key`. Returns `None` if there is no such
+ * node.
+ */
+ def minAfter[A, B](tree: Tree[A, B], key: A)(implicit ord: Ordering[A]): Option[(A, B)] =
+ minNodeAfter(tree.root, key) match {
+ case null => None
+ case node => Some((node.key, node.value))
+ }
+
+ def minKeyAfter[A](tree: Tree[A, _], key: A)(implicit ord: Ordering[A]): Option[A] =
+ minNodeAfter(tree.root, key) match {
+ case null => None
+ case node => Some(node.key)
+ }
+
+ private[this] def minNodeAfter[A, B](node: Node[A, B], key: A)(implicit ord: Ordering[A]): Node[A, B] = {
+ if (node eq null) null
+ else {
+ var y: Node[A, B] = null
+ var x = node
+ var cmp = 1
+ while ((x ne null) && cmp != 0) {
+ y = x
+ cmp = ord.compare(key, x.key)
+ x = if (cmp < 0) x.left else x.right
+ }
+ if (cmp <= 0) y else successor(y)
+ }
+ }
+
+ /**
+ * Returns the last (highest) map entry with a key smaller than `key`. Returns `None` if there is no such node.
+ */
+ def maxBefore[A, B](tree: Tree[A, B], key: A)(implicit ord: Ordering[A]): Option[(A, B)] =
+ maxNodeBefore(tree.root, key) match {
+ case null => None
+ case node => Some((node.key, node.value))
+ }
+
+ def maxKeyBefore[A](tree: Tree[A, _], key: A)(implicit ord: Ordering[A]): Option[A] =
+ maxNodeBefore(tree.root, key) match {
+ case null => None
+ case node => Some(node.key)
+ }
+
+ private[this] def maxNodeBefore[A, B](node: Node[A, B], key: A)(implicit ord: Ordering[A]): Node[A, B] = {
+ if (node eq null) null
+ else {
+ var y: Node[A, B] = null
+ var x = node
+ var cmp = 1
+ while ((x ne null) && cmp != 0) {
+ y = x
+ cmp = ord.compare(key, x.key)
+ x = if (cmp < 0) x.left else x.right
+ }
+ if (cmp > 0) y else predecessor(y)
+ }
+ }
+
+ // ---- insertion ----
+
+ def insert[A, B](tree: Tree[A, B], key: A, value: B)(implicit ord: Ordering[A]): Unit = {
+ var y: Node[A, B] = null
+ var x = tree.root
+ var cmp = 1
+ while ((x ne null) && cmp != 0) {
+ y = x
+ cmp = ord.compare(key, x.key)
+ x = if (cmp < 0) x.left else x.right
+ }
+
+ if (cmp == 0) y.value = value
+ else {
+ val z = Node.leaf(key, value, red = true, y)
+
+ if (y eq null) tree.root = z
+ else if (cmp < 0) y.left = z
+ else y.right = z
+
+ fixAfterInsert(tree, z)
+ tree.size += 1
+ }
+ }
+
+ private[this] def fixAfterInsert[A, B](tree: Tree[A, B], node: Node[A, B]): Unit = {
+ var z = node
+ while (isRed(z.parent)) {
+ if (z.parent eq z.parent.parent.left) {
+ val y = z.parent.parent.right
+ if (isRed(y)) {
+ z.parent.red = false
+ y.red = false
+ z.parent.parent.red = true
+ z = z.parent.parent
+ } else {
+ if (z eq z.parent.right) {
+ z = z.parent
+ rotateLeft(tree, z)
+ }
+ z.parent.red = false
+ z.parent.parent.red = true
+ rotateRight(tree, z.parent.parent)
+ }
+ } else { // symmetric cases
+ val y = z.parent.parent.left
+ if (isRed(y)) {
+ z.parent.red = false
+ y.red = false
+ z.parent.parent.red = true
+ z = z.parent.parent
+ } else {
+ if (z eq z.parent.left) {
+ z = z.parent
+ rotateRight(tree, z)
+ }
+ z.parent.red = false
+ z.parent.parent.red = true
+ rotateLeft(tree, z.parent.parent)
+ }
+ }
+ }
+ tree.root.red = false
+ }
+
+ // ---- deletion ----
+
+ def delete[A, B](tree: Tree[A, B], key: A)(implicit ord: Ordering[A]): Unit = {
+ val z = getNode(tree.root, key)
+ if (z ne null) {
+ var y = z
+ var yIsRed = y.red
+ var x: Node[A, B] = null
+ var xParent: Node[A, B] = null
+
+ if (z.left eq null) {
+ x = z.right
+ transplant(tree, z, z.right)
+ xParent = z.parent
+ }
+ else if (z.right eq null) {
+ x = z.left
+ transplant(tree, z, z.left)
+ xParent = z.parent
+ }
+ else {
+ y = minNodeNonNull(z.right)
+ yIsRed = y.red
+ x = y.right
+
+ if (y.parent eq z) xParent = y
+ else {
+ xParent = y.parent
+ transplant(tree, y, y.right)
+ y.right = z.right
+ y.right.parent = y
+ }
+ transplant(tree, z, y)
+ y.left = z.left
+ y.left.parent = y
+ y.red = z.red
+ }
+
+ if (!yIsRed) fixAfterDelete(tree, x, xParent)
+ tree.size -= 1
+ }
+ }
+
+ private[this] def fixAfterDelete[A, B](tree: Tree[A, B], node: Node[A, B], parent: Node[A, B]): Unit = {
+ var x = node
+ var xParent = parent
+ while ((x ne tree.root) && isBlack(x)) {
+ if (x eq xParent.left) {
+ var w = xParent.right
+ // assert(w ne null)
+
+ if (w.red) {
+ w.red = false
+ xParent.red = true
+ rotateLeft(tree, xParent)
+ w = xParent.right
+ }
+ if (isBlack(w.left) && isBlack(w.right)) {
+ w.red = true
+ x = xParent
+ } else {
+ if (isBlack(w.right)) {
+ w.left.red = false
+ w.red = true
+ rotateRight(tree, w)
+ w = xParent.right
+ }
+ w.red = xParent.red
+ xParent.red = false
+ w.right.red = false
+ rotateLeft(tree, xParent)
+ x = tree.root
+ }
+ } else { // symmetric cases
+ var w = xParent.left
+ // assert(w ne null)
+
+ if (w.red) {
+ w.red = false
+ xParent.red = true
+ rotateRight(tree, xParent)
+ w = xParent.left
+ }
+ if (isBlack(w.right) && isBlack(w.left)) {
+ w.red = true
+ x = xParent
+ } else {
+ if (isBlack(w.left)) {
+ w.right.red = false
+ w.red = true
+ rotateLeft(tree, w)
+ w = xParent.left
+ }
+ w.red = xParent.red
+ xParent.red = false
+ w.left.red = false
+ rotateRight(tree, xParent)
+ x = tree.root
+ }
+ }
+ xParent = x.parent
+ }
+ if (x ne null) x.red = false
+ }
+
+ // ---- helpers ----
+
+ /**
+ * Returns the node that follows `node` in an in-order tree traversal. If `node` has the maximum key (and is,
+ * therefore, the last node), this method returns `null`.
+ */
+ private[this] def successor[A, B](node: Node[A, B]): Node[A, B] = {
+ if (node.right ne null) minNodeNonNull(node.right)
+ else {
+ var x = node
+ var y = x.parent
+ while ((y ne null) && (x eq y.right)) {
+ x = y
+ y = y.parent
+ }
+ y
+ }
+ }
+
+ /**
+ * Returns the node that precedes `node` in an in-order tree traversal. If `node` has the minimum key (and is,
+ * therefore, the first node), this method returns `null`.
+ */
+ private[this] def predecessor[A, B](node: Node[A, B]): Node[A, B] = {
+ if (node.left ne null) maxNodeNonNull(node.left)
+ else {
+ var x = node
+ var y = x.parent
+ while ((y ne null) && (x eq y.left)) {
+ x = y
+ y = y.parent
+ }
+ y
+ }
+ }
+
+ private[this] def rotateLeft[A, B](tree: Tree[A, B], x: Node[A, B]): Unit = if (x ne null) {
+ // assert(x.right ne null)
+ val y = x.right
+ x.right = y.left
+
+ if (y.left ne null) y.left.parent = x
+ y.parent = x.parent
+
+ if (x.parent eq null) tree.root = y
+ else if (x eq x.parent.left) x.parent.left = y
+ else x.parent.right = y
+
+ y.left = x
+ x.parent = y
+ }
+
+ private[this] def rotateRight[A, B](tree: Tree[A, B], x: Node[A, B]): Unit = if (x ne null) {
+ // assert(x.left ne null)
+ val y = x.left
+ x.left = y.right
+
+ if (y.right ne null) y.right.parent = x
+ y.parent = x.parent
+
+ if (x.parent eq null) tree.root = y
+ else if (x eq x.parent.right) x.parent.right = y
+ else x.parent.left = y
+
+ y.right = x
+ x.parent = y
+ }
+
+ /**
+ * Transplant the node `from` to the place of node `to`. This is done by setting `from` as a child of `to`'s previous
+ * parent and setting `from`'s parent to the `to`'s previous parent. The children of `from` are left unchanged.
+ */
+ private[this] def transplant[A, B](tree: Tree[A, B], to: Node[A, B], from: Node[A, B]): Unit = {
+ if (to.parent eq null) tree.root = from
+ else if (to eq to.parent.left) to.parent.left = from
+ else to.parent.right = from
+
+ if (from ne null) from.parent = to.parent
+ }
+
+ // ---- tree traversal ----
+
+ def foreach[A, B, U](tree: Tree[A, B], f: ((A, B)) => U): Unit = foreachNode(tree.root, f)
+
+ private[this] def foreachNode[A, B, U](node: Node[A, B], f: ((A, B)) => U): Unit =
+ if (node ne null) foreachNodeNonNull(node, f)
+
+ private[this] def foreachNodeNonNull[A, B, U](node: Node[A, B], f: ((A, B)) => U): Unit = {
+ if (node.left ne null) foreachNodeNonNull(node.left, f)
+ f((node.key, node.value))
+ if (node.right ne null) foreachNodeNonNull(node.right, f)
+ }
+
+ def foreachKey[A, U](tree: Tree[A, _], f: A => U): Unit = {
+ def g(node: Node[A, _]): Unit = {
+ val l = node.left
+ if(l ne null) g(l)
+ f(node.key)
+ val r = node.right
+ if(r ne null) g(r)
+ }
+ val r = tree.root
+ if(r ne null) g(r)
+ }
+
+ def foreachEntry[A, B, U](tree: Tree[A, B], f: (A, B) => U): Unit = {
+ def g(node: Node[A, B]): Unit = {
+ val l = node.left
+ if(l ne null) g(l)
+ f(node.key, node.value)
+ val r = node.right
+ if(r ne null) g(r)
+ }
+ val r = tree.root
+ if(r ne null) g(r)
+ }
+
+ def transform[A, B](tree: Tree[A, B], f: (A, B) => B): Unit = transformNode(tree.root, f)
+
+ private[this] def transformNode[A, B, U](node: Node[A, B], f: (A, B) => B): Unit =
+ if (node ne null) transformNodeNonNull(node, f)
+
+ private[this] def transformNodeNonNull[A, B, U](node: Node[A, B], f: (A, B) => B): Unit = {
+ if (node.left ne null) transformNodeNonNull(node.left, f)
+ node.value = f(node.key, node.value)
+ if (node.right ne null) transformNodeNonNull(node.right, f)
+ }
+
+ def iterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None, end: Option[A] = None): Iterator[(A, B)] =
+ new EntriesIterator(tree, start, end)
+
+ def keysIterator[A: Ordering](tree: Tree[A, _], start: Option[A] = None, end: Option[A] = None): Iterator[A] =
+ new KeysIterator(tree, start, end)
+
+ def valuesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A] = None, end: Option[A] = None): Iterator[B] =
+ new ValuesIterator(tree, start, end)
+
+ private[this] abstract class TreeIterator[A, B, R](tree: Tree[A, B], start: Option[A], end: Option[A])
+ (implicit ord: Ordering[A]) extends AbstractIterator[R] {
+
+ protected def nextResult(node: Node[A, B]): R
+
+ def hasNext: Boolean = nextNode ne null
+
+ @throws[NoSuchElementException]
+ def next(): R = nextNode match {
+ case null => throw new NoSuchElementException("next on empty iterator")
+ case node =>
+ nextNode = successor(node)
+ setNullIfAfterEnd()
+ nextResult(node)
+ }
+
+ private[this] var nextNode: Node[A, B] = start match {
+ case None => minNode(tree.root)
+ case Some(from) => minNodeAfter(tree.root, from)
+ }
+
+ private[this] def setNullIfAfterEnd(): Unit =
+ if (end.isDefined && (nextNode ne null) && ord.compare(nextNode.key, end.get) >= 0)
+ nextNode = null
+
+ setNullIfAfterEnd()
+ }
+
+ private[this] final class EntriesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A])
+ extends TreeIterator[A, B, (A, B)](tree, start, end) {
+
+ def nextResult(node: Node[A, B]) = (node.key, node.value)
+ }
+
+ private[this] final class KeysIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A])
+ extends TreeIterator[A, B, A](tree, start, end) {
+
+ def nextResult(node: Node[A, B]) = node.key
+ }
+
+ private[this] final class ValuesIterator[A: Ordering, B](tree: Tree[A, B], start: Option[A], end: Option[A])
+ extends TreeIterator[A, B, B](tree, start, end) {
+
+ def nextResult(node: Node[A, B]) = node.value
+ }
+
+ // ---- debugging ----
+
+ /**
+ * Checks if the tree is in a valid state. That happens if:
+ * - It is a valid binary search tree;
+ * - All red-black properties are satisfied;
+ * - All non-null nodes have their `parent` reference correct;
+ * - The size variable in `tree` corresponds to the actual size of the tree.
+ */
+ def isValid[A: Ordering, B](tree: Tree[A, B]): Boolean =
+ isValidBST(tree.root) && hasProperParentRefs(tree) && isValidRedBlackTree(tree) && size(tree.root) == tree.size
+
+ /**
+ * Returns true if all non-null nodes have their `parent` reference correct.
+ */
+ private[this] def hasProperParentRefs[A, B](tree: Tree[A, B]): Boolean = {
+
+ def hasProperParentRefs(node: Node[A, B]): Boolean = {
+ if (node eq null) true
+ else {
+ if ((node.left ne null) && (node.left.parent ne node) ||
+ (node.right ne null) && (node.right.parent ne node)) false
+ else hasProperParentRefs(node.left) && hasProperParentRefs(node.right)
+ }
+ }
+
+ if(tree.root eq null) true
+ else (tree.root.parent eq null) && hasProperParentRefs(tree.root)
+ }
+
+ /**
+ * Returns true if this node follows the properties of a binary search tree.
+ */
+ private[this] def isValidBST[A, B](node: Node[A, B])(implicit ord: Ordering[A]): Boolean = {
+ if (node eq null) true
+ else {
+ if ((node.left ne null) && (ord.compare(node.key, node.left.key) <= 0) ||
+ (node.right ne null) && (ord.compare(node.key, node.right.key) >= 0)) false
+ else isValidBST(node.left) && isValidBST(node.right)
+ }
+ }
+
+ /**
+ * Returns true if the tree has all the red-black tree properties: if the root node is black, if all children of red
+ * nodes are black and if the path from any node to any of its null children has the same number of black nodes.
+ */
+ private[this] def isValidRedBlackTree[A, B](tree: Tree[A, B]): Boolean = {
+
+ def noRedAfterRed(node: Node[A, B]): Boolean = {
+ if (node eq null) true
+ else if (node.red && (isRed(node.left) || isRed(node.right))) false
+ else noRedAfterRed(node.left) && noRedAfterRed(node.right)
+ }
+
+ def blackHeight(node: Node[A, B]): Int = {
+ if (node eq null) 1
+ else {
+ val lh = blackHeight(node.left)
+ val rh = blackHeight(node.right)
+
+ if (lh == -1 || lh != rh) -1
+ else if (isRed(node)) lh
+ else lh + 1
+ }
+ }
+
+ isBlack(tree.root) && noRedAfterRed(tree.root) && blackHeight(tree.root) >= 0
+ }
+
+ // building
+
+ /** Build a Tree suitable for a TreeSet from an ordered sequence of keys */
+ def fromOrderedKeys[A](xs: Iterator[A], size: Int): Tree[A, Null] = {
+ val maxUsedDepth = 32 - Integer.numberOfLeadingZeros(size) // maximum depth of non-leaf nodes
+ def f(level: Int, size: Int): Node[A, Null] = size match {
+ case 0 => null
+ case 1 => new Node(xs.next(), null, level == maxUsedDepth && level != 1, null, null, null)
+ case n =>
+ val leftSize = (size-1)/2
+ val left = f(level+1, leftSize)
+ val x = xs.next()
+ val right = f(level+1, size-1-leftSize)
+ val n = new Node(x, null, red = false, left, right, null)
+ if(left ne null) left.parent = n
+ right.parent = n
+ n
+ }
+ new Tree(f(1, size), size)
+ }
+
+ /** Build a Tree suitable for a TreeMap from an ordered sequence of key/value pairs */
+ def fromOrderedEntries[A, B](xs: Iterator[(A, B)], size: Int): Tree[A, B] = {
+ val maxUsedDepth = 32 - Integer.numberOfLeadingZeros(size) // maximum depth of non-leaf nodes
+ def f(level: Int, size: Int): Node[A, B] = size match {
+ case 0 => null
+ case 1 =>
+ val (k, v) = xs.next()
+ new Node(k, v, level == maxUsedDepth && level != 1, null, null, null)
+ case n =>
+ val leftSize = (size-1)/2
+ val left = f(level+1, leftSize)
+ val (k, v) = xs.next()
+ val right = f(level+1, size-1-leftSize)
+ val n = new Node(k, v, red = false, left, right, null)
+ if(left ne null) left.parent = n
+ right.parent = n
+ n
+ }
+ new Tree(f(1, size), size)
+ }
+
+ def copyTree[A, B](n: Node[A, B]): Node[A, B] =
+ if(n eq null) null else {
+ val c = new Node(n.key, n.value, n.red, copyTree(n.left), copyTree(n.right), null)
+ if(c.left != null) c.left.parent = c
+ if(c.right != null) c.right.parent = c
+ c
+ }
+}
diff --git a/library/src/scala/collection/mutable/ReusableBuilder.scala b/library/src/scala/collection/mutable/ReusableBuilder.scala
new file mode 100644
index 000000000000..c8565d6953f1
--- /dev/null
+++ b/library/src/scala/collection/mutable/ReusableBuilder.scala
@@ -0,0 +1,55 @@
+/*
+ * 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 collection
+package mutable
+
+
+/** `ReusableBuilder` is a marker trait that indicates that a `Builder`
+ * can be reused to build more than one instance of a collection. In
+ * particular, calling `result()` followed by `clear()` will produce a
+ * collection and reset the builder to begin building a new collection
+ * of the same type.
+ *
+ * In general no method other than `clear()` may be called after `result()`.
+ * It is up to subclasses to implement and to document other allowed sequences
+ * of operations (e.g. calling other methods after `result()` in order to obtain
+ * different snapshots of a collection under construction).
+ *
+ * @tparam Elem the type of elements that get added to the builder.
+ * @tparam To the type of collection that it produced.
+ *
+ * @define multipleResults
+ *
+ * This Builder can be reused after calling `result()` without an
+ * intermediate call to `clear()` in order to build multiple related results.
+ */
+trait ReusableBuilder[-Elem, +To] extends Builder[Elem, To] {
+ /** Clears the contents of this builder.
+ * After execution of this method, the builder will contain no elements.
+ *
+ * If executed immediately after a call to `result()`, this allows a new
+ * instance of the same type of collection to be built.
+ */
+ override def clear(): Unit // Note: overriding for Scaladoc only!
+
+ /** Produces a collection from the added elements.
+ *
+ * After a call to `result`, the behavior of all other methods is undefined
+ * save for `clear()`. If `clear()` is called, then the builder is reset and
+ * may be used to build another instance.
+ *
+ * @return a collection containing the elements added to this builder.
+ */
+ override def result(): To // Note: overriding for Scaladoc only!
+}
diff --git a/library/src/scala/collection/mutable/Seq.scala b/library/src/scala/collection/mutable/Seq.scala
new file mode 100644
index 000000000000..afabb834a63f
--- /dev/null
+++ b/library/src/scala/collection/mutable/Seq.scala
@@ -0,0 +1,67 @@
+/*
+ * 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.mutable
+
+import scala.collection.{IterableFactoryDefaults, SeqFactory}
+
+trait Seq[A]
+ extends Iterable[A]
+ with collection.Seq[A]
+ with SeqOps[A, Seq, Seq[A]]
+ with IterableFactoryDefaults[A, Seq] {
+
+ override def iterableFactory: SeqFactory[Seq] = Seq
+}
+
+/**
+ * $factoryInfo
+ * @define coll mutable sequence
+ * @define Coll `mutable.Seq`
+ */
+@SerialVersionUID(3L)
+object Seq extends SeqFactory.Delegate[Seq](ArrayBuffer)
+
+/**
+ * @define coll mutable sequence
+ * @define Coll `mutable.Seq`
+ */
+trait SeqOps[A, +CC[_], +C <: AnyRef]
+ extends collection.SeqOps[A, CC, C]
+ with Cloneable[C] {
+
+ override def clone(): C = {
+ val b = newSpecificBuilder
+ b ++= this
+ b.result()
+ }
+
+ /** Replaces element at given index with a new value.
+ *
+ * @param idx the index of the element to replace.
+ * @param elem the new value.
+ * @throws IndexOutOfBoundsException if the index is not valid.
+ */
+ @throws[IndexOutOfBoundsException]
+ def update(idx: Int, elem: A): Unit
+
+ @deprecated("Use `mapInPlace` on an `IndexedSeq` instead", "2.13.0")
+ @`inline`final def transform(f: A => A): this.type = {
+ var i = 0
+ val siz = size
+ while (i < siz) { this(i) = f(this(i)); i += 1 }
+ this
+ }
+}
+
+/** Explicit instantiation of the `Seq` trait to reduce class file size in subclasses. */
+abstract class AbstractSeq[A] extends scala.collection.AbstractSeq[A] with Seq[A]
diff --git a/library/src/scala/collection/mutable/SeqMap.scala b/library/src/scala/collection/mutable/SeqMap.scala
new file mode 100644
index 000000000000..dda2c47c3447
--- /dev/null
+++ b/library/src/scala/collection/mutable/SeqMap.scala
@@ -0,0 +1,38 @@
+/*
+ * 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 collection
+package mutable
+
+/**
+ * A generic trait for ordered mutable maps. Concrete classes have to provide
+ * functionality for the abstract methods in `SeqMap`.
+ *
+ * Note that when checking for equality [[SeqMap]] does not take into account
+ * ordering.
+ *
+ * @tparam K the type of the keys contained in this linked map.
+ * @tparam V the type of the values associated with the keys in this linked map.
+ *
+ * @define coll mutable Seq map
+ * @define Coll `mutable.SeqMap`
+ */
+
+trait SeqMap[K, V] extends Map[K, V]
+ with collection.SeqMap[K, V]
+ with MapOps[K, V, SeqMap, SeqMap[K, V]]
+ with MapFactoryDefaults[K, V, SeqMap, Iterable] {
+ override def mapFactory: MapFactory[SeqMap] = SeqMap
+}
+
+object SeqMap extends MapFactory.Delegate[SeqMap](LinkedHashMap)
diff --git a/library/src/scala/collection/mutable/Set.scala b/library/src/scala/collection/mutable/Set.scala
new file mode 100644
index 000000000000..cede5411a349
--- /dev/null
+++ b/library/src/scala/collection/mutable/Set.scala
@@ -0,0 +1,122 @@
+/*
+ * 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.mutable
+
+import scala.collection.{IterableFactory, IterableFactoryDefaults, IterableOps}
+
+/** Base trait for mutable sets */
+trait Set[A]
+ extends Iterable[A]
+ with collection.Set[A]
+ with SetOps[A, Set, Set[A]]
+ with IterableFactoryDefaults[A, Set] {
+
+ override def iterableFactory: IterableFactory[Set] = Set
+}
+
+/**
+ * @define coll mutable set
+ * @define Coll `mutable.Set`
+ */
+trait SetOps[A, +CC[X], +C <: SetOps[A, CC, C]]
+ extends collection.SetOps[A, CC, C]
+ with IterableOps[A, CC, C] // only needed so we can use super[IterableOps] below
+ with Cloneable[C]
+ with Builder[A, C]
+ with Growable[A]
+ with Shrinkable[A] {
+
+ def result(): C = coll
+
+ /** Check whether the set contains the given element, and add it if not.
+ *
+ * @param elem the element to be added
+ * @return true if the element was added
+ */
+ def add(elem: A): Boolean =
+ !contains(elem) && {
+ coll += elem; true
+ }
+
+ /** Updates the presence of a single element in this set.
+ *
+ * This method allows one to add or remove an element `elem`
+ * from this set depending on the value of parameter `included`.
+ * Typically, one would use the following syntax:
+ * {{{
+ * set(elem) = true // adds element
+ * set(elem) = false // removes element
+ * }}}
+ *
+ * @param elem the element to be added or removed
+ * @param included a flag indicating whether element should be included or excluded.
+ */
+ def update(elem: A, included: Boolean): Unit = {
+ if (included) add(elem)
+ else remove(elem)
+ }
+
+ /** Removes an element from this set.
+ *
+ * @param elem the element to be removed
+ * @return true if this set contained the element before it was removed
+ */
+ def remove(elem: A): Boolean = {
+ val res = contains(elem)
+ coll -= elem
+ res
+ }
+
+ def diff(that: collection.Set[A]): C =
+ foldLeft(empty)((result, elem) => if (that contains elem) result else result += elem)
+
+ @deprecated("Use filterInPlace instead", "2.13.0")
+ @inline final def retain(p: A => Boolean): Unit = filterInPlace(p)
+
+ /** Removes all elements from the set for which do not satisfy a predicate.
+ * @param p the predicate used to test elements. Only elements for
+ * which `p` returns `true` are retained in the set; all others
+ * are removed.
+ */
+ def filterInPlace(p: A => Boolean): this.type = {
+ if (nonEmpty) {
+ val array = this.toArray[Any] // scala/bug#7269 toArray avoids ConcurrentModificationException
+ val arrayLength = array.length
+ var i = 0
+ while (i < arrayLength) {
+ val elem = array(i).asInstanceOf[A]
+ if (!p(elem)) {
+ this -= elem
+ }
+ i += 1
+ }
+ }
+ this
+ }
+
+ override def clone(): C = empty ++= this
+
+ override def knownSize: Int = super[IterableOps].knownSize
+}
+
+/**
+ * $factoryInfo
+ * @define coll mutable set
+ * @define Coll `mutable.Set`
+ */
+@SerialVersionUID(3L)
+object Set extends IterableFactory.Delegate[Set](HashSet)
+
+
+/** Explicit instantiation of the `Set` trait to reduce class file size in subclasses. */
+abstract class AbstractSet[A] extends scala.collection.AbstractSet[A] with Set[A]
diff --git a/library/src/scala/collection/mutable/Shrinkable.scala b/library/src/scala/collection/mutable/Shrinkable.scala
new file mode 100644
index 000000000000..b068f61bf8f5
--- /dev/null
+++ b/library/src/scala/collection/mutable/Shrinkable.scala
@@ -0,0 +1,79 @@
+/*
+ * 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 collection.mutable
+
+import scala.annotation.tailrec
+
+/** This trait forms part of collections that can be reduced
+ * using a `-=` operator.
+ *
+ * @define coll shrinkable collection
+ * @define Coll `Shrinkable`
+ */
+trait Shrinkable[-A] {
+
+ /** Removes a single element from this $coll.
+ *
+ * @param elem the element to remove.
+ * @return the $coll itself
+ */
+ def subtractOne(elem: A): this.type
+
+ /** Alias for `subtractOne` */
+ @`inline` final def -= (elem: A): this.type = subtractOne(elem)
+
+ /** Removes two or more elements from this $coll.
+ *
+ * @param elem1 the first element to remove.
+ * @param elem2 the second element to remove.
+ * @param elems the remaining elements to remove.
+ * @return the $coll itself
+ */
+ @deprecated("Use `--=` aka `subtractAll` instead of varargs `-=`; infix operations with an operand of multiple args will be deprecated", "2.13.3")
+ def -= (elem1: A, elem2: A, elems: A*): this.type = {
+ this -= elem1
+ this -= elem2
+ this --= elems
+ }
+
+ /** Removes all elements produced by an iterator from this $coll.
+ *
+ * @param xs the iterator producing the elements to remove.
+ * @return the $coll itself
+ */
+ def subtractAll(xs: collection.IterableOnce[A]): this.type = {
+ @tailrec def loop(xs: collection.LinearSeq[A]): Unit = {
+ if (xs.nonEmpty) {
+ subtractOne(xs.head)
+ loop(xs.tail)
+ }
+ }
+ if (xs.asInstanceOf[AnyRef] eq this) { // avoid mutating under our own iterator
+ xs match {
+ case xs: Clearable => xs.clear()
+ case xs => subtractAll(Buffer.from(xs))
+ }
+ } else {
+ xs match {
+ case xs: collection.LinearSeq[A] => loop(xs)
+ case xs => xs.iterator.foreach(subtractOne)
+ }
+ }
+ this
+ }
+
+ /** Alias for `subtractAll` */
+ @`inline` final def --= (xs: collection.IterableOnce[A]): this.type = subtractAll(xs)
+
+}
diff --git a/library/src/scala/collection/mutable/SortedMap.scala b/library/src/scala/collection/mutable/SortedMap.scala
new file mode 100644
index 000000000000..1884840f91e2
--- /dev/null
+++ b/library/src/scala/collection/mutable/SortedMap.scala
@@ -0,0 +1,103 @@
+/*
+ * 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 collection.mutable
+
+import scala.collection.{SortedMapFactory, SortedMapFactoryDefaults}
+
+/**
+ * Base type for mutable sorted map collections
+ */
+trait SortedMap[K, V]
+ extends collection.SortedMap[K, V]
+ with Map[K, V]
+ with SortedMapOps[K, V, SortedMap, SortedMap[K, V]]
+ with SortedMapFactoryDefaults[K, V, SortedMap, Iterable, Map] {
+
+ override def unsorted: Map[K, V] = this
+
+ override def sortedMapFactory: SortedMapFactory[SortedMap] = SortedMap
+
+ /** The same sorted map with a given default function.
+ * Note: The default is only used for `apply`. Other methods like `get`, `contains`, `iterator`, `keys`, etc.
+ * are not affected by `withDefault`.
+ *
+ * Invoking transformer methods (e.g. `map`) will not preserve the default value.
+ *
+ * @param d the function mapping keys to values, used for non-present keys
+ * @return a wrapper of the map with a default value
+ */
+ override def withDefault(d: K => V): SortedMap[K, V] = new SortedMap.WithDefault[K, V](this, d)
+
+ /** The same map with a given default value.
+ * Note: The default is only used for `apply`. Other methods like `get`, `contains`, `iterator`, `keys`, etc.
+ * are not affected by `withDefaultValue`.
+ *
+ * Invoking transformer methods (e.g. `map`) will not preserve the default value.
+ *
+ * @param d default value used for non-present keys
+ * @return a wrapper of the map with a default value
+ */
+ override def withDefaultValue(d: V): SortedMap[K, V] = new SortedMap.WithDefault[K, V](this, _ => d)
+}
+
+trait SortedMapOps[K, V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], +C <: SortedMapOps[K, V, CC, C]]
+ extends collection.SortedMapOps[K, V, CC, C]
+ with MapOps[K, V, Map, C] {
+
+ def unsorted: Map[K, V]
+
+ @deprecated("Use m.clone().addOne((k,v)) instead of m.updated(k, v)", "2.13.0")
+ override def updated[V1 >: V](key: K, value: V1): CC[K, V1] =
+ clone().asInstanceOf[CC[K, V1]].addOne((key, value))
+}
+
+@SerialVersionUID(3L)
+object SortedMap extends SortedMapFactory.Delegate[SortedMap](TreeMap) {
+
+ @SerialVersionUID(3L)
+ final class WithDefault[K, V](underlying: SortedMap[K, V], defaultValue: K => V)
+ extends Map.WithDefault[K, V](underlying, defaultValue)
+ with SortedMap[K, V]
+ with SortedMapOps[K, V, SortedMap, WithDefault[K, V]]
+ with Serializable {
+
+ override def sortedMapFactory: SortedMapFactory[SortedMap] = underlying.sortedMapFactory
+
+ def iteratorFrom(start: K): scala.collection.Iterator[(K, V)] = underlying.iteratorFrom(start)
+
+ def keysIteratorFrom(start: K): scala.collection.Iterator[K] = underlying.keysIteratorFrom(start)
+
+ implicit def ordering: Ordering[K] = underlying.ordering
+
+ def rangeImpl(from: Option[K], until: Option[K]): WithDefault[K, V] =
+ new WithDefault[K, V](underlying.rangeImpl(from, until), defaultValue)
+
+ // Need to override following methods to match type signatures of `SortedMap.WithDefault`
+ // for operations preserving default value
+ override def subtractOne(elem: K): WithDefault.this.type = { underlying.subtractOne(elem); this }
+
+ override def addOne(elem: (K, V)): WithDefault.this.type = { underlying.addOne(elem); this }
+
+ override def empty: WithDefault[K, V] = new WithDefault[K, V](underlying.empty, defaultValue)
+
+ override def concat[V2 >: V](suffix: collection.IterableOnce[(K, V2)]): SortedMap[K, V2] =
+ underlying.concat(suffix).withDefault(defaultValue)
+
+ override protected def fromSpecific(coll: scala.collection.IterableOnce[(K, V)]): WithDefault[K, V] =
+ new WithDefault[K, V](sortedMapFactory.from(coll), defaultValue)
+
+ override protected def newSpecificBuilder: Builder[(K, V), WithDefault[K, V]] =
+ SortedMap.newBuilder.mapResult((p: SortedMap[K, V]) => new WithDefault[K, V](p, defaultValue))
+ }
+}
diff --git a/library/src/scala/collection/mutable/SortedSet.scala b/library/src/scala/collection/mutable/SortedSet.scala
new file mode 100644
index 000000000000..b5d9ee8feff6
--- /dev/null
+++ b/library/src/scala/collection/mutable/SortedSet.scala
@@ -0,0 +1,48 @@
+/*
+ * 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 collection
+package mutable
+
+/**
+ * Base type for mutable sorted set collections
+ */
+trait SortedSet[A]
+ extends Set[A]
+ with collection.SortedSet[A]
+ with SortedSetOps[A, SortedSet, SortedSet[A]]
+ with SortedSetFactoryDefaults[A, SortedSet, Set] {
+
+ override def unsorted: Set[A] = this
+
+ override def sortedIterableFactory: SortedIterableFactory[SortedSet] = SortedSet
+}
+
+/**
+ * @define coll mutable sorted set
+ * @define Coll `mutable.Sortedset`
+ */
+trait SortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]]
+ extends SetOps[A, Set, C]
+ with collection.SortedSetOps[A, CC, C] {
+
+ def unsorted: Set[A]
+}
+
+/**
+ * $factoryInfo
+ * @define coll mutable sorted set
+ * @define Coll `mutable.Sortedset`
+ */
+@SerialVersionUID(3L)
+object SortedSet extends SortedIterableFactory.Delegate[SortedSet](TreeSet)
diff --git a/library/src/scala/collection/mutable/Stack.scala b/library/src/scala/collection/mutable/Stack.scala
new file mode 100644
index 000000000000..01aacc22c65e
--- /dev/null
+++ b/library/src/scala/collection/mutable/Stack.scala
@@ -0,0 +1,142 @@
+/*
+ * 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.mutable
+
+import scala.annotation.{migration, nowarn}
+import scala.collection.generic.DefaultSerializable
+import scala.collection.{IterableFactoryDefaults, IterableOnce, SeqFactory, StrictOptimizedSeqFactory, StrictOptimizedSeqOps}
+
+/** A stack implements a data structure which allows to store and retrieve
+ * objects in a last-in-first-out (LIFO) fashion.
+ *
+ * Note that operations which consume and produce iterables preserve order,
+ * rather than reversing it (as would be expected from building a new stack
+ * by pushing an element at a time).
+ *
+ * @tparam A type of the elements contained in this stack.
+ *
+ * @define Coll `Stack`
+ * @define coll stack
+ * @define orderDependent
+ * @define orderDependentFold
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+@migration("Stack is now based on an ArrayDeque instead of a linked list", "2.13.0")
+class Stack[A] protected (array: Array[AnyRef], start: Int, end: Int)
+ extends ArrayDeque[A](array, start, end)
+ with IndexedSeqOps[A, Stack, Stack[A]]
+ with StrictOptimizedSeqOps[A, Stack, Stack[A]]
+ with IterableFactoryDefaults[A, Stack]
+ with ArrayDequeOps[A, Stack, Stack[A]]
+ with Cloneable[Stack[A]]
+ with DefaultSerializable {
+
+ def this(initialSize: Int = ArrayDeque.DefaultInitialSize) =
+ this(ArrayDeque.alloc(initialSize), start = 0, end = 0)
+
+ override def iterableFactory: SeqFactory[Stack] = Stack
+
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix = "Stack"
+
+ /**
+ * Add elements to the top of this stack
+ *
+ * @param elem
+ * @return
+ */
+ def push(elem: A): this.type = prepend(elem)
+
+ /** Push two or more elements onto the stack. The last element
+ * of the sequence will be on top of the new stack.
+ *
+ * @param elems the element sequence.
+ * @return the stack with the new elements on top.
+ */
+ def push(elem1: A, elem2: A, elems: A*): this.type = {
+ val k = elems.knownSize
+ ensureSize(length + (if(k >= 0) k + 2 else 3))
+ prepend(elem1).prepend(elem2).pushAll(elems)
+ }
+
+ /** Push all elements in the given iterable object onto the stack. The
+ * last element in the iterable object will be on top of the new stack.
+ *
+ * @param elems the iterable object.
+ * @return the stack with the new elements on top.
+ */
+ def pushAll(elems: scala.collection.IterableOnce[A]): this.type =
+ prependAll(elems match {
+ case it: scala.collection.Seq[A] => it.view.reverse
+ case it => IndexedSeq.from(it).view.reverse
+ })
+
+ /**
+ * Removes the top element from this stack and return it
+ *
+ * @return
+ * @throws NoSuchElementException when stack is empty
+ */
+ def pop(): A = removeHead()
+
+ /**
+ * Pop all elements from this stack and return it
+ *
+ * @return The removed elements
+ */
+ def popAll(): scala.collection.Seq[A] = removeAll()
+
+ /**
+ * Returns and removes all elements from the top of this stack which satisfy the given predicate
+ *
+ * @param f the predicate used for choosing elements
+ * @return The removed elements
+ */
+ def popWhile(f: A => Boolean): scala.collection.Seq[A] = removeHeadWhile(f)
+
+ /** Returns the top element of the stack. This method will not remove
+ * the element from the stack. An error is signaled if there is no
+ * element on the stack.
+ *
+ * @throws NoSuchElementException if the stack is empty
+ * @return the top element
+ */
+ @`inline` final def top: A = head
+
+ override protected def klone(): Stack[A] = {
+ val bf = newSpecificBuilder
+ bf ++= this
+ bf.result()
+ }
+
+ override protected def ofArray(array: Array[AnyRef], end: Int): Stack[A] =
+ new Stack(array, start = 0, end)
+
+}
+
+/**
+ * $factoryInfo
+ * @define coll stack
+ * @define Coll `Stack`
+ */
+@SerialVersionUID(3L)
+object Stack extends StrictOptimizedSeqFactory[Stack] {
+
+ def from[A](source: IterableOnce[A]): Stack[A] = empty ++= source
+
+ def empty[A]: Stack[A] = new Stack
+
+ def newBuilder[A]: Builder[A, Stack[A]] = new GrowableBuilder[A, Stack[A]](empty)
+
+}
diff --git a/library/src/scala/collection/mutable/StringBuilder.scala b/library/src/scala/collection/mutable/StringBuilder.scala
new file mode 100644
index 000000000000..ad9755389c48
--- /dev/null
+++ b/library/src/scala/collection/mutable/StringBuilder.scala
@@ -0,0 +1,495 @@
+/*
+ * 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.mutable
+
+import scala.collection.{IterableFactoryDefaults, IterableOnce}
+import scala.collection.immutable.WrappedString
+
+import scala.Predef.{ // unimport char-related implicit conversions to avoid triggering them accidentally
+ genericArrayOps => _,
+ charArrayOps => _,
+ genericWrapArray => _,
+ wrapCharArray => _,
+ wrapString => _,
+ //_
+}
+
+/** A builder of `String` which is also a mutable sequence of characters.
+ *
+ * This class provides an API mostly compatible with `java.lang.StringBuilder`,
+ * except where there are conflicts with the Scala collections API, such as the `reverse` method:
+ * [[reverse]] produces a new `StringBuilder`, and [[reverseInPlace]] mutates this builder.
+ *
+ * Mutating operations return either `this.type`, i.e., the current builder, or `Unit`.
+ *
+ * Other methods extract data or information from the builder without mutating it.
+ *
+ * The distinction is also reflected in naming conventions used by collections,
+ * such as `append`, which mutates, and `appended`, which does not, or `reverse`,
+ * which does not mutate, and `reverseInPlace`, which does.
+ *
+ * The `String` result may be obtained using either `result()` or `toString`.
+ *
+ * $multipleResults
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-mutable-collection-classes.html#stringbuilders "Scala's Collection Library overview"]]
+ * section on `StringBuilders` for more information.
+ *
+ * @define Coll `mutable.IndexedSeq`
+ * @define coll string builder
+ */
+@SerialVersionUID(3L)
+final class StringBuilder(val underlying: java.lang.StringBuilder) extends AbstractSeq[Char]
+ with ReusableBuilder[Char, String]
+ with IndexedSeq[Char]
+ with IndexedSeqOps[Char, IndexedSeq, StringBuilder]
+ with IterableFactoryDefaults[Char, IndexedSeq]
+ with java.lang.CharSequence
+ with Serializable {
+
+ def this() = this(new java.lang.StringBuilder)
+
+ /** Constructs a string builder with no characters in it and an
+ * initial capacity specified by the `capacity` argument.
+ *
+ * @param capacity the initial capacity.
+ * @throws java.lang.NegativeArraySizeException if capacity < 0.
+ */
+ def this(capacity: Int) = this(new java.lang.StringBuilder(capacity))
+
+ /** Constructs a string builder with initial characters
+ * equal to characters of `str`.
+ */
+ def this(str: String) = this(new java.lang.StringBuilder(str))
+
+ /** Constructs a string builder initialized with string value `initValue`
+ * and with additional character capacity `initCapacity`.
+ */
+ def this(initCapacity: Int, initValue: String) =
+ this(new java.lang.StringBuilder(initValue.length + initCapacity) append initValue)
+
+ // Methods required to make this an IndexedSeq:
+ def apply(i: Int): Char = underlying.charAt(i)
+
+ override protected def fromSpecific(coll: scala.collection.IterableOnce[Char]): StringBuilder =
+ new StringBuilder() appendAll coll
+
+ override protected def newSpecificBuilder: Builder[Char, StringBuilder] =
+ new GrowableBuilder(new StringBuilder())
+
+ override def empty: StringBuilder = new StringBuilder()
+
+ @inline def length: Int = underlying.length
+
+ def length_=(n: Int): Unit = underlying.setLength(n)
+
+ override def knownSize: Int = super[IndexedSeqOps].knownSize
+
+ def addOne(x: Char): this.type = { underlying.append(x); this }
+
+ def clear(): Unit = underlying.setLength(0)
+
+ /** Overloaded version of `addAll` that takes a string */
+ def addAll(s: String): this.type = { underlying.append(s); this }
+
+ /** Alias for `addAll` */
+ def ++= (s: String): this.type = addAll(s)
+
+ def result() = underlying.toString
+
+ override def toString: String = result()
+
+ override def toArray[B >: Char](implicit ct: scala.reflect.ClassTag[B]) =
+ ct.runtimeClass match {
+ case java.lang.Character.TYPE => toCharArray.asInstanceOf[Array[B]]
+ case _ => super.toArray
+ }
+
+ /** Returns the contents of this StringBuilder as an `Array[Char]`.
+ *
+ * @return An array with the characters from this builder.
+ */
+ def toCharArray: Array[Char] = {
+ val len = underlying.length
+ val arr = new Array[Char](len)
+ underlying.getChars(0, len, arr, 0)
+ arr
+ }
+
+ // append* methods delegate to the underlying java.lang.StringBuilder:
+
+ def appendAll(xs: String): this.type = {
+ underlying append xs
+ this
+ }
+
+ /** Appends the string representation of the given argument,
+ * which is converted to a String with `String.valueOf`.
+ *
+ * @param x an `Any` object.
+ * @return this StringBuilder.
+ */
+ def append(x: Any): this.type = {
+ underlying append String.valueOf(x)
+ this
+ }
+
+ /** Appends the given String to this sequence.
+ *
+ * @param s a String.
+ * @return this StringBuilder.
+ */
+ def append(s: String): this.type = {
+ underlying append s
+ this
+ }
+
+ /** Appends the given CharSequence to this sequence.
+ *
+ * @param cs a CharSequence.
+ * @return this StringBuilder.
+ */
+ def append(cs: java.lang.CharSequence): this.type = {
+ underlying.append(cs match {
+ // Both cases call into append(), but java SB
+ // looks up type at runtime and has fast path for SB.
+ case s: StringBuilder => s.underlying
+ case _ => cs
+ })
+ this
+ }
+
+ /** Appends the specified string builder to this sequence.
+ *
+ * @param s
+ * @return
+ */
+ def append(s: StringBuilder): this.type = {
+ underlying append s.underlying
+ this
+ }
+
+ /** Appends all the Chars in the given IterableOnce[Char] to this sequence.
+ *
+ * @param xs the characters to be appended.
+ * @return this StringBuilder.
+ */
+ def appendAll(xs: IterableOnce[Char]): this.type = {
+ xs match {
+ case x: WrappedString => underlying append x.unwrap
+ case x: ArraySeq.ofChar => underlying append x.array
+ case x: StringBuilder => underlying append x.underlying
+ case _ =>
+ val ks = xs.knownSize
+ if (ks != 0) {
+ val b = underlying
+ if (ks > 0) b.ensureCapacity(b.length + ks)
+ val it = xs.iterator
+ while (it.hasNext) { b append it.next() }
+ }
+ }
+ this
+ }
+
+ /** Appends all the Chars in the given Array[Char] to this sequence.
+ *
+ * @param xs the characters to be appended.
+ * @return a reference to this object.
+ */
+ def appendAll(xs: Array[Char]): this.type = {
+ underlying append xs
+ this
+ }
+
+ /** Appends a portion of the given Array[Char] to this sequence.
+ *
+ * @param xs the Array containing Chars to be appended.
+ * @param offset the index of the first Char to append.
+ * @param len the numbers of Chars to append.
+ * @return this StringBuilder.
+ */
+ def appendAll(xs: Array[Char], offset: Int, len: Int): this.type = {
+ underlying.append(xs, offset, len)
+ this
+ }
+
+ /** Append the String representation of the given primitive type
+ * to this sequence. The argument is converted to a String with
+ * String.valueOf.
+ *
+ * @param x a primitive value
+ * @return This StringBuilder.
+ */
+ def append(x: Boolean): this.type = { underlying append x ; this }
+ def append(x: Byte): this.type = append(x.toInt)
+ def append(x: Short): this.type = append(x.toInt)
+ def append(x: Int): this.type = { underlying append x ; this }
+ def append(x: Long): this.type = { underlying append x ; this }
+ def append(x: Float): this.type = { underlying append x ; this }
+ def append(x: Double): this.type = { underlying append x ; this }
+ def append(x: Char): this.type = { underlying append x ; this }
+
+ /** Remove a subsequence of Chars from this sequence, starting at the
+ * given start index (inclusive) and extending to the end index (exclusive)
+ * or to the end of the String, whichever comes first.
+ *
+ * @param start The beginning index, inclusive.
+ * @param end The ending index, exclusive.
+ * @return This StringBuilder.
+ * @throws StringIndexOutOfBoundsException if start < 0 || start > end
+ */
+ def delete(start: Int, end: Int): this.type = {
+ underlying.delete(start, end)
+ this
+ }
+
+ /** Replaces a subsequence of Chars with the given String. The semantics
+ * are as in delete, with the String argument then inserted at index 'start'.
+ *
+ * @param start The beginning index, inclusive.
+ * @param end The ending index, exclusive.
+ * @param str The String to be inserted at the start index.
+ * @return This StringBuilder.
+ * @throws StringIndexOutOfBoundsException if start < 0, start > length, or start > end
+ */
+ def replace(start: Int, end: Int, str: String): this.type = {
+ underlying.replace(start, end, str)
+ this
+ }
+
+ /** Inserts a subarray of the given Array[Char] at the given index
+ * of this sequence.
+ *
+ * @param index index at which to insert the subarray.
+ * @param str the Array from which Chars will be taken.
+ * @param offset the index of the first Char to insert.
+ * @param len the number of Chars from 'str' to insert.
+ * @return This StringBuilder.
+ *
+ * @throws StringIndexOutOfBoundsException if index < 0, index > length,
+ * offset < 0, len < 0, or (offset + len) > str.length.
+ */
+ def insertAll(index: Int, str: Array[Char], offset: Int, len: Int): this.type = {
+ underlying.insert(index, str, offset, len)
+ this
+ }
+
+ /** Inserts the String representation (via String.valueOf) of the given
+ * argument into this sequence at the given index.
+ *
+ * @param index the index at which to insert.
+ * @param x a value.
+ * @return this StringBuilder.
+ * @throws StringIndexOutOfBoundsException if the index is out of bounds.
+ */
+ def insert(index: Int, x: Any): this.type = insert(index, String.valueOf(x))
+
+ /** Inserts the String into this character sequence.
+ *
+ * @param index the index at which to insert.
+ * @param x a String.
+ * @return this StringBuilder.
+ * @throws StringIndexOutOfBoundsException if the index is out of bounds.
+ */
+ def insert(index: Int, x: String): this.type = {
+ underlying.insert(index, x)
+ this
+ }
+
+ /** Inserts the given Seq[Char] into this sequence at the given index.
+ *
+ * @param index the index at which to insert.
+ * @param xs the Seq[Char].
+ * @return this StringBuilder.
+ * @throws StringIndexOutOfBoundsException if the index is out of bounds.
+ */
+ def insertAll(index: Int, xs: IterableOnce[Char]): this.type =
+ insertAll(index, (ArrayBuilder.make[Char] ++= xs).result())
+
+ /** Inserts the given Array[Char] into this sequence at the given index.
+ *
+ * @param index the index at which to insert.
+ * @param xs the Array[Char].
+ * @return this StringBuilder.
+ * @throws StringIndexOutOfBoundsException if the index is out of bounds.
+ */
+ def insertAll(index: Int, xs: Array[Char]): this.type = {
+ underlying.insert(index, xs)
+ this
+ }
+
+ /** Calls String.valueOf on the given primitive value, and inserts the
+ * String at the given index.
+ *
+ * @param index the offset position.
+ * @param x a primitive value.
+ * @return this StringBuilder.
+ */
+ def insert(index: Int, x: Boolean): this.type = insert(index, String.valueOf(x))
+ def insert(index: Int, x: Byte): this.type = insert(index, x.toInt)
+ def insert(index: Int, x: Short): this.type = insert(index, x.toInt)
+ def insert(index: Int, x: Int): this.type = insert(index, String.valueOf(x))
+ def insert(index: Int, x: Long): this.type = insert(index, String.valueOf(x))
+ def insert(index: Int, x: Float): this.type = insert(index, String.valueOf(x))
+ def insert(index: Int, x: Double): this.type = insert(index, String.valueOf(x))
+ def insert(index: Int, x: Char): this.type = insert(index, String.valueOf(x))
+
+ /** Sets the length of the character sequence. If the current sequence
+ * is shorter than the given length, it is padded with nulls; if it is
+ * longer, it is truncated.
+ *
+ * @param len the new length
+ * @throws IndexOutOfBoundsException if the argument is negative.
+ */
+ def setLength(len: Int): Unit = underlying.setLength(len)
+
+ def update(idx: Int, elem: Char): Unit = underlying.setCharAt(idx, elem)
+
+
+ /** Like reverse, but destructively updates the target StringBuilder.
+ *
+ * @return the reversed StringBuilder (same as the target StringBuilder)
+ */
+ @deprecated("Use reverseInPlace instead", "2.13.0")
+ final def reverseContents(): this.type = reverseInPlace()
+
+ /** Like reverse, but destructively updates the target StringBuilder.
+ *
+ * @return the reversed StringBuilder (same as the target StringBuilder)
+ */
+ def reverseInPlace(): this.type = {
+ underlying.reverse()
+ this
+ }
+
+
+ /** Returns the current capacity, which is the size of the underlying array.
+ * A new array will be allocated if the current capacity is exceeded.
+ *
+ * @return the capacity
+ */
+ def capacity: Int = underlying.capacity
+
+ /** Ensure that the capacity is at least the given argument.
+ * If the argument is greater than the current capacity, new
+ * storage will be allocated with size equal to the given
+ * argument or to `(2 * capacity + 2)`, whichever is larger.
+ *
+ * @param newCapacity the minimum desired capacity.
+ */
+ def ensureCapacity(newCapacity: Int): Unit = { underlying.ensureCapacity(newCapacity) }
+
+ /** Returns the Char at the specified index, counting from 0 as in Arrays.
+ *
+ * @param index the index to look up
+ * @return the Char at the given index.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ def charAt(index: Int): Char = underlying.charAt(index)
+
+ /** Removes the Char at the specified index. The sequence is
+ * shortened by one.
+ *
+ * @param index The index to remove.
+ * @return This StringBuilder.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ def deleteCharAt(index: Int): this.type = {
+ underlying.deleteCharAt(index)
+ this
+ }
+
+ /** Update the sequence at the given index to hold the specified Char.
+ *
+ * @param index the index to modify.
+ * @param ch the new Char.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ def setCharAt(index: Int, ch: Char): this.type = {
+ underlying.setCharAt(index, ch)
+ this
+ }
+
+ /** Returns a new String made up of a subsequence of this sequence,
+ * beginning at the given index and extending to the end of the sequence.
+ *
+ * target.substring(start) is equivalent to target.drop(start)
+ *
+ * @param start The starting index, inclusive.
+ * @return The new String.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ def substring(start: Int): String = underlying.substring(start, length)
+
+ /** Returns a new String made up of a subsequence of this sequence,
+ * beginning at the start index (inclusive) and extending to the
+ * end index (exclusive).
+ *
+ * target.substring(start, end) is equivalent to target.slice(start, end).mkString
+ *
+ * @param start The beginning index, inclusive.
+ * @param end The ending index, exclusive.
+ * @return The new String.
+ * @throws StringIndexOutOfBoundsException If either index is out of bounds,
+ * or if start > end.
+ */
+ def substring(start: Int, end: Int): String = underlying.substring(start, end)
+
+ /** For implementing CharSequence.
+ */
+ def subSequence(start: Int, end: Int): java.lang.CharSequence =
+ underlying.substring(start, end)
+
+ /** Finds the index of the first occurrence of the specified substring.
+ *
+ * @param str the target string to search for
+ * @return the first applicable index where target occurs, or -1 if not found.
+ */
+ def indexOf(str: String): Int = underlying.indexOf(str)
+
+ /** Finds the index of the first occurrence of the specified substring.
+ *
+ * @param str the target string to search for
+ * @param fromIndex the smallest index in the source string to consider
+ * @return the first applicable index where target occurs, or -1 if not found.
+ */
+ def indexOf(str: String, fromIndex: Int): Int = underlying.indexOf(str, fromIndex)
+
+ /** Finds the index of the last occurrence of the specified substring.
+ *
+ * @param str the target string to search for
+ * @return the last applicable index where target occurs, or -1 if not found.
+ */
+ def lastIndexOf(str: String): Int = underlying.lastIndexOf(str)
+
+ /** Finds the index of the last occurrence of the specified substring.
+ *
+ * @param str the target string to search for
+ * @param fromIndex the smallest index in the source string to consider
+ * @return the last applicable index where target occurs, or -1 if not found.
+ */
+ def lastIndexOf(str: String, fromIndex: Int): Int = underlying.lastIndexOf(str, fromIndex)
+
+ /** Tests whether this builder is empty.
+ *
+ * This method is required for JDK15+ compatibility
+ *
+ * @return `true` if this builder contains nothing, `false` otherwise.
+ */
+ override def isEmpty: Boolean = underlying.length() == 0
+}
+
+object StringBuilder {
+ @deprecated("Use `new StringBuilder()` instead of `StringBuilder.newBuilder`", "2.13.0")
+ def newBuilder = new StringBuilder
+}
diff --git a/library/src/scala/collection/mutable/TreeMap.scala b/library/src/scala/collection/mutable/TreeMap.scala
new file mode 100644
index 000000000000..076239278299
--- /dev/null
+++ b/library/src/scala/collection/mutable/TreeMap.scala
@@ -0,0 +1,257 @@
+/*
+ * 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 collection
+package mutable
+
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.generic.DefaultSerializable
+import scala.collection.mutable.{RedBlackTree => RB}
+
+/**
+ * A mutable sorted map implemented using a mutable red-black tree as underlying data structure.
+ *
+ * @param ordering the implicit ordering used to compare objects of type `A`.
+ * @tparam K the type of the keys contained in this tree map.
+ * @tparam V the type of the values associated with the keys.
+ *
+ * @define Coll mutable.TreeMap
+ * @define coll mutable tree map
+ */
+sealed class TreeMap[K, V] private (tree: RB.Tree[K, V])(implicit val ordering: Ordering[K])
+ extends AbstractMap[K, V]
+ with SortedMap[K, V]
+ with SortedMapOps[K, V, TreeMap, TreeMap[K, V]]
+ with StrictOptimizedIterableOps[(K, V), Iterable, TreeMap[K, V]]
+ with StrictOptimizedMapOps[K, V, Map, TreeMap[K, V]]
+ with StrictOptimizedSortedMapOps[K, V, TreeMap, TreeMap[K, V]]
+ with SortedMapFactoryDefaults[K, V, TreeMap, Iterable, Map]
+ with DefaultSerializable {
+
+ override def sortedMapFactory: TreeMap.type = TreeMap
+
+ /**
+ * Creates an empty `TreeMap`.
+ * @param ord the implicit ordering used to compare objects of type `K`.
+ * @return an empty `TreeMap`.
+ */
+ def this()(implicit ord: Ordering[K]) = this(RB.Tree.empty)(ord)
+
+ def iterator: Iterator[(K, V)] = {
+ if (isEmpty) Iterator.empty
+ else RB.iterator(tree)
+ }
+
+ override def keysIterator: Iterator[K] = {
+ if (isEmpty) Iterator.empty
+ else RB.keysIterator(tree, None)
+ }
+
+ override def valuesIterator: Iterator[V] = {
+ if (isEmpty) Iterator.empty
+ else RB.valuesIterator(tree, None)
+ }
+
+ def keysIteratorFrom(start: K): Iterator[K] = {
+ if (isEmpty) Iterator.empty
+ else RB.keysIterator(tree, Some(start))
+ }
+
+ def iteratorFrom(start: K): Iterator[(K, V)] = {
+ if (isEmpty) Iterator.empty
+ else RB.iterator(tree, Some(start))
+ }
+
+ override def valuesIteratorFrom(start: K): Iterator[V] = {
+ if (isEmpty) Iterator.empty
+ else RB.valuesIterator(tree, Some(start))
+ }
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[(K, V), S]): S with EfficientSplit =
+ shape.parUnbox(
+ scala.collection.convert.impl.AnyBinaryTreeStepper.from[(K, V), RB.Node[K, V]](
+ size, tree.root, _.left, _.right, x => (x.key, x.value)
+ )
+ )
+
+ override def keyStepper[S <: Stepper[_]](implicit shape: StepperShape[K, S]): S with EfficientSplit = {
+ import scala.collection.convert.impl._
+ type T = RB.Node[K, V]
+ val s = shape.shape match {
+ case StepperShape.IntShape => IntBinaryTreeStepper.from[T] (size, tree.root, _.left, _.right, _.key.asInstanceOf[Int])
+ case StepperShape.LongShape => LongBinaryTreeStepper.from[T] (size, tree.root, _.left, _.right, _.key.asInstanceOf[Long])
+ case StepperShape.DoubleShape => DoubleBinaryTreeStepper.from[T](size, tree.root, _.left, _.right, _.key.asInstanceOf[Double])
+ case _ => shape.parUnbox(AnyBinaryTreeStepper.from[K, T](size, tree.root, _.left, _.right, _.key))
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ override def valueStepper[S <: Stepper[_]](implicit shape: StepperShape[V, S]): S with EfficientSplit = {
+ import scala.collection.convert.impl._
+ type T = RB.Node[K, V]
+ val s = shape.shape match {
+ case StepperShape.IntShape => IntBinaryTreeStepper.from[T] (size, tree.root, _.left, _.right, _.value.asInstanceOf[Int])
+ case StepperShape.LongShape => LongBinaryTreeStepper.from[T] (size, tree.root, _.left, _.right, _.value.asInstanceOf[Long])
+ case StepperShape.DoubleShape => DoubleBinaryTreeStepper.from[T] (size, tree.root, _.left, _.right, _.value.asInstanceOf[Double])
+ case _ => shape.parUnbox(AnyBinaryTreeStepper.from[V, T] (size, tree.root, _.left, _.right, _.value))
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ def addOne(elem: (K, V)): this.type = { RB.insert(tree, elem._1, elem._2); this }
+
+ def subtractOne(elem: K): this.type = { RB.delete(tree, elem); this }
+
+ override def clear(): Unit = RB.clear(tree)
+
+ def get(key: K): Option[V] = RB.get(tree, key)
+
+ /**
+ * Creates a ranged projection of this map. Any mutations in the ranged projection will update the original map and
+ * vice versa.
+ *
+ * Only entries with keys between this projection's key range will ever appear as elements of this map, independently
+ * of whether the entries are added through the original map or through this view. That means that if one inserts a
+ * key-value in a view whose key is outside the view's bounds, calls to `get` or `contains` will _not_ consider the
+ * newly added entry. Mutations are always reflected in the original map, though.
+ *
+ * @param from the lower bound (inclusive) of this projection wrapped in a `Some`, or `None` if there is no lower
+ * bound.
+ * @param until the upper bound (exclusive) of this projection wrapped in a `Some`, or `None` if there is no upper
+ * bound.
+ */
+ def rangeImpl(from: Option[K], until: Option[K]): TreeMap[K, V] = new TreeMapProjection(from, until)
+
+ override def foreach[U](f: ((K, V)) => U): Unit = RB.foreach(tree, f)
+ override def foreachEntry[U](f: (K, V) => U): Unit = RB.foreachEntry(tree, f)
+
+ override def size: Int = RB.size(tree)
+ override def knownSize: Int = size
+ override def isEmpty: Boolean = RB.isEmpty(tree)
+
+ override def contains(key: K): Boolean = RB.contains(tree, key)
+
+ override def head: (K, V) = RB.min(tree).get
+
+ override def last: (K, V) = RB.max(tree).get
+
+ override def minAfter(key: K): Option[(K, V)] = RB.minAfter(tree, key)
+
+ override def maxBefore(key: K): Option[(K, V)] = RB.maxBefore(tree, key)
+
+ override protected[this] def className: String = "TreeMap"
+
+
+ /**
+ * A ranged projection of a [[TreeMap]]. Mutations on this map affect the original map and vice versa.
+ *
+ * Only entries with keys between this projection's key range will ever appear as elements of this map, independently
+ * of whether the entries are added through the original map or through this view. That means that if one inserts a
+ * key-value in a view whose key is outside the view's bounds, calls to `get` or `contains` will _not_ consider the
+ * newly added entry. Mutations are always reflected in the original map, though.
+ *
+ * @param from the lower bound (inclusive) of this projection wrapped in a `Some`, or `None` if there is no lower
+ * bound.
+ * @param until the upper bound (exclusive) of this projection wrapped in a `Some`, or `None` if there is no upper
+ * bound.
+ */
+ private[this] final class TreeMapProjection(from: Option[K], until: Option[K]) extends TreeMap[K, V](tree) {
+
+ /**
+ * Given a possible new lower bound, chooses and returns the most constraining one (the maximum).
+ */
+ private[this] def pickLowerBound(newFrom: Option[K]): Option[K] = (from, newFrom) match {
+ case (Some(fr), Some(newFr)) => Some(ordering.max(fr, newFr))
+ case (None, _) => newFrom
+ case _ => from
+ }
+
+ /**
+ * Given a possible new upper bound, chooses and returns the most constraining one (the minimum).
+ */
+ private[this] def pickUpperBound(newUntil: Option[K]): Option[K] = (until, newUntil) match {
+ case (Some(unt), Some(newUnt)) => Some(ordering.min(unt, newUnt))
+ case (None, _) => newUntil
+ case _ => until
+ }
+
+ /**
+ * Returns true if the argument is inside the view bounds (between `from` and `until`).
+ */
+ private[this] def isInsideViewBounds(key: K): Boolean = {
+ val afterFrom = from.isEmpty || ordering.compare(from.get, key) <= 0
+ val beforeUntil = until.isEmpty || ordering.compare(key, until.get) < 0
+ afterFrom && beforeUntil
+ }
+
+ override def rangeImpl(from: Option[K], until: Option[K]): TreeMap[K, V] =
+ new TreeMapProjection(pickLowerBound(from), pickUpperBound(until))
+
+ override def get(key: K) = if (isInsideViewBounds(key)) RB.get(tree, key) else None
+
+ override def iterator = if (RB.size(tree) == 0) Iterator.empty else RB.iterator(tree, from, until)
+ override def keysIterator: Iterator[K] = if (RB.size(tree) == 0) Iterator.empty else RB.keysIterator(tree, from, until)
+ override def valuesIterator: Iterator[V] = if (RB.size(tree) == 0) Iterator.empty else RB.valuesIterator(tree, from, until)
+ override def keysIteratorFrom(start: K) = if (RB.size(tree) == 0) Iterator.empty else RB.keysIterator(tree, pickLowerBound(Some(start)), until)
+ override def iteratorFrom(start: K) = if (RB.size(tree) == 0) Iterator.empty else RB.iterator(tree, pickLowerBound(Some(start)), until)
+ override def valuesIteratorFrom(start: K) = if (RB.size(tree) == 0) Iterator.empty else RB.valuesIterator(tree, pickLowerBound(Some(start)), until)
+ override def size = if (RB.size(tree) == 0) 0 else iterator.length
+ override def knownSize: Int = if (RB.size(tree) == 0) 0 else -1
+ override def isEmpty = RB.size(tree) == 0 || !iterator.hasNext
+ override def contains(key: K) = isInsideViewBounds(key) && RB.contains(tree, key)
+
+ override def head = headOption.get
+ override def headOption = {
+ val entry = if (from.isDefined) RB.minAfter(tree, from.get) else RB.min(tree)
+ (entry, until) match {
+ case (Some(e), Some(unt)) if ordering.compare(e._1, unt) >= 0 => None
+ case _ => entry
+ }
+ }
+
+ override def last = lastOption.get
+ override def lastOption = {
+ val entry = if (until.isDefined) RB.maxBefore(tree, until.get) else RB.max(tree)
+ (entry, from) match {
+ case (Some(e), Some(fr)) if ordering.compare(e._1, fr) < 0 => None
+ case _ => entry
+ }
+ }
+
+ // Using the iterator should be efficient enough; if performance is deemed a problem later, specialized
+ // `foreach(f, from, until)` and `transform(f, from, until)` methods can be created in `RedBlackTree`. See
+ // https://github.com/scala/scala/pull/4608#discussion_r34307985 for a discussion about this.
+ override def foreach[U](f: ((K, V)) => U): Unit = iterator.foreach(f)
+
+ override def clone() = super.clone().rangeImpl(from, until)
+ }
+
+}
+
+/**
+ * $factoryInfo
+ *
+ * @define Coll mutable.TreeMap
+ * @define coll mutable tree map
+ */
+@SerialVersionUID(3L)
+object TreeMap extends SortedMapFactory[TreeMap] {
+
+ def from[K : Ordering, V](it: IterableOnce[(K, V)]): TreeMap[K, V] =
+ Growable.from(empty[K, V], it)
+
+ def empty[K : Ordering, V]: TreeMap[K, V] = new TreeMap[K, V]()
+
+ def newBuilder[K: Ordering, V]: Builder[(K, V), TreeMap[K, V]] = new GrowableBuilder(empty[K, V])
+
+}
diff --git a/library/src/scala/collection/mutable/TreeSet.scala b/library/src/scala/collection/mutable/TreeSet.scala
new file mode 100644
index 000000000000..9820af9037ca
--- /dev/null
+++ b/library/src/scala/collection/mutable/TreeSet.scala
@@ -0,0 +1,218 @@
+/*
+ * 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 collection.mutable
+
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.generic.DefaultSerializable
+import scala.collection.mutable.{RedBlackTree => RB}
+import scala.collection.{SortedIterableFactory, SortedSetFactoryDefaults, Stepper, StepperShape, StrictOptimizedIterableOps, StrictOptimizedSortedSetOps, mutable}
+
+/**
+ * A mutable sorted set implemented using a mutable red-black tree as underlying data structure.
+ *
+ * @param ordering the implicit ordering used to compare objects of type `A`.
+ * @tparam A the type of the keys contained in this tree set.
+ *
+ * @define Coll mutable.TreeSet
+ * @define coll mutable tree set
+ */
+// Original API designed in part by Lucien Pereira
+sealed class TreeSet[A] private (private val tree: RB.Tree[A, Null])(implicit val ordering: Ordering[A])
+ extends AbstractSet[A]
+ with SortedSet[A]
+ with SortedSetOps[A, TreeSet, TreeSet[A]]
+ with StrictOptimizedIterableOps[A, Set, TreeSet[A]]
+ with StrictOptimizedSortedSetOps[A, TreeSet, TreeSet[A]]
+ with SortedSetFactoryDefaults[A, TreeSet, Set]
+ with DefaultSerializable {
+
+ if (ordering eq null)
+ throw new NullPointerException("ordering must not be null")
+
+ /**
+ * Creates an empty `TreeSet`.
+ * @param ord the implicit ordering used to compare objects of type `A`.
+ * @return an empty `TreeSet`.
+ */
+ def this()(implicit ord: Ordering[A]) = this(RB.Tree.empty)(ord)
+
+ override def sortedIterableFactory: SortedIterableFactory[TreeSet] = TreeSet
+
+ def iterator: collection.Iterator[A] = RB.keysIterator(tree)
+
+ def iteratorFrom(start: A): collection.Iterator[A] = RB.keysIterator(tree, Some(start))
+
+ override def stepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit = {
+ import scala.collection.convert.impl._
+ type T = RB.Node[A, Null]
+ val s = shape.shape match {
+ case StepperShape.IntShape => IntBinaryTreeStepper.from[T] (size, tree.root, _.left, _.right, _.key.asInstanceOf[Int])
+ case StepperShape.LongShape => LongBinaryTreeStepper.from[T] (size, tree.root, _.left, _.right, _.key.asInstanceOf[Long])
+ case StepperShape.DoubleShape => DoubleBinaryTreeStepper.from[T](size, tree.root, _.left, _.right, _.key.asInstanceOf[Double])
+ case _ => shape.parUnbox(AnyBinaryTreeStepper.from[A, T](size, tree.root, _.left, _.right, _.key))
+ }
+ s.asInstanceOf[S with EfficientSplit]
+ }
+
+ def addOne(elem: A): this.type = {
+ RB.insert(tree, elem, null)
+ this
+ }
+
+ def subtractOne(elem: A): this.type = {
+ RB.delete(tree, elem)
+ this
+ }
+
+ def clear(): Unit = RB.clear(tree)
+
+ def contains(elem: A): Boolean = RB.contains(tree, elem)
+
+ def unconstrained: collection.Set[A] = this
+
+ def rangeImpl(from: Option[A], until: Option[A]): TreeSet[A] = new TreeSetProjection(from, until)
+
+ override protected[this] def className: String = "TreeSet"
+
+ override def size: Int = RB.size(tree)
+ override def knownSize: Int = size
+ override def isEmpty: Boolean = RB.isEmpty(tree)
+
+ override def head: A = RB.minKey(tree).get
+
+ override def last: A = RB.maxKey(tree).get
+
+ override def minAfter(key: A): Option[A] = RB.minKeyAfter(tree, key)
+
+ override def maxBefore(key: A): Option[A] = RB.maxKeyBefore(tree, key)
+
+ override def foreach[U](f: A => U): Unit = RB.foreachKey(tree, f)
+
+
+ /**
+ * A ranged projection of a [[TreeSet]]. Mutations on this set affect the original set and vice versa.
+ *
+ * Only keys between this projection's key range will ever appear as elements of this set, independently of whether
+ * the elements are added through the original set or through this view. That means that if one inserts an element in
+ * a view whose key is outside the view's bounds, calls to `contains` will _not_ consider the newly added element.
+ * Mutations are always reflected in the original set, though.
+ *
+ * @param from the lower bound (inclusive) of this projection wrapped in a `Some`, or `None` if there is no lower
+ * bound.
+ * @param until the upper bound (exclusive) of this projection wrapped in a `Some`, or `None` if there is no upper
+ * bound.
+ */
+ private[this] final class TreeSetProjection(from: Option[A], until: Option[A]) extends TreeSet[A](tree) {
+
+ /**
+ * Given a possible new lower bound, chooses and returns the most constraining one (the maximum).
+ */
+ private[this] def pickLowerBound(newFrom: Option[A]): Option[A] = (from, newFrom) match {
+ case (Some(fr), Some(newFr)) => Some(ordering.max(fr, newFr))
+ case (None, _) => newFrom
+ case _ => from
+ }
+
+ /**
+ * Given a possible new upper bound, chooses and returns the most constraining one (the minimum).
+ */
+ private[this] def pickUpperBound(newUntil: Option[A]): Option[A] = (until, newUntil) match {
+ case (Some(unt), Some(newUnt)) => Some(ordering.min(unt, newUnt))
+ case (None, _) => newUntil
+ case _ => until
+ }
+
+ /**
+ * Returns true if the argument is inside the view bounds (between `from` and `until`).
+ */
+ private[this] def isInsideViewBounds(key: A): Boolean = {
+ val afterFrom = from.isEmpty || ordering.compare(from.get, key) <= 0
+ val beforeUntil = until.isEmpty || ordering.compare(key, until.get) < 0
+ afterFrom && beforeUntil
+ }
+
+ override def rangeImpl(from: Option[A], until: Option[A]): TreeSet[A] =
+ new TreeSetProjection(pickLowerBound(from), pickUpperBound(until))
+
+ override def contains(key: A) = isInsideViewBounds(key) && RB.contains(tree, key)
+
+ override def iterator = RB.keysIterator(tree, from, until)
+ override def iteratorFrom(start: A) = RB.keysIterator(tree, pickLowerBound(Some(start)), until)
+
+ override def size = if (RB.size(tree) == 0) 0 else iterator.length
+ override def knownSize: Int = if (RB.size(tree) == 0) 0 else -1
+ override def isEmpty: Boolean = RB.size(tree) == 0 || !iterator.hasNext
+
+ override def head: A = headOption.get
+ override def headOption: Option[A] = {
+ val elem = if (from.isDefined) RB.minKeyAfter(tree, from.get) else RB.minKey(tree)
+ (elem, until) match {
+ case (Some(e), Some(unt)) if ordering.compare(e, unt) >= 0 => None
+ case _ => elem
+ }
+ }
+
+ override def last: A = lastOption.get
+ override def lastOption = {
+ val elem = if (until.isDefined) RB.maxKeyBefore(tree, until.get) else RB.maxKey(tree)
+ (elem, from) match {
+ case (Some(e), Some(fr)) if ordering.compare(e, fr) < 0 => None
+ case _ => elem
+ }
+ }
+
+ // Using the iterator should be efficient enough; if performance is deemed a problem later, a specialized
+ // `foreachKey(f, from, until)` method can be created in `RedBlackTree`. See
+ // https://github.com/scala/scala/pull/4608#discussion_r34307985 for a discussion about this.
+ override def foreach[U](f: A => U): Unit = iterator.foreach(f)
+
+ override def clone(): mutable.TreeSet[A] = super.clone().rangeImpl(from, until)
+
+ }
+
+}
+
+/**
+ * $factoryInfo
+ * @define Coll `mutable.TreeSet`
+ * @define coll mutable tree set
+ */
+@SerialVersionUID(3L)
+object TreeSet extends SortedIterableFactory[TreeSet] {
+
+ def empty[A : Ordering]: TreeSet[A] = new TreeSet[A]()
+
+ def from[E](it: IterableOnce[E])(implicit ordering: Ordering[E]): TreeSet[E] =
+ it match {
+ case ts: TreeSet[E] if ordering == ts.ordering =>
+ new TreeSet[E](ts.tree.treeCopy())
+ case ss: scala.collection.SortedSet[E] if ordering == ss.ordering =>
+ new TreeSet[E](RB.fromOrderedKeys(ss.iterator, ss.size))
+ case r: Range if (ordering eq Ordering.Int) || (ordering eq Ordering.Int.reverse) =>
+ val it = if((ordering eq Ordering.Int) == (r.step > 0)) r.iterator else r.reverseIterator
+ new TreeSet[E](RB.fromOrderedKeys(it.asInstanceOf[Iterator[E]], r.size))
+ case _ =>
+ val t: RB.Tree[E, Null] = RB.Tree.empty
+ val i = it.iterator
+ while (i.hasNext) RB.insert(t, i.next(), null)
+ new TreeSet[E](t)
+ }
+
+ def newBuilder[A](implicit ordering: Ordering[A]): Builder[A, TreeSet[A]] = new ReusableBuilder[A, TreeSet[A]] {
+ private[this] var tree: RB.Tree[A, Null] = RB.Tree.empty
+ def addOne(elem: A): this.type = { RB.insert(tree, elem, null); this }
+ def result(): TreeSet[A] = new TreeSet[A](tree)
+ def clear(): Unit = { tree = RB.Tree.empty }
+ }
+}
diff --git a/library/src/scala/collection/mutable/UnrolledBuffer.scala b/library/src/scala/collection/mutable/UnrolledBuffer.scala
new file mode 100644
index 000000000000..4aecac001505
--- /dev/null
+++ b/library/src/scala/collection/mutable/UnrolledBuffer.scala
@@ -0,0 +1,447 @@
+/*
+ * 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 mutable
+
+import scala.annotation.tailrec
+import scala.collection.generic.{CommonErrors, DefaultSerializable}
+import scala.reflect.ClassTag
+import scala.collection.immutable.Nil
+
+/** A buffer that stores elements in an unrolled linked list.
+ *
+ * Unrolled linked lists store elements in linked fixed size
+ * arrays.
+ *
+ * Unrolled buffers retain locality and low memory overhead
+ * properties of array buffers, but offer much more efficient
+ * element addition, since they never reallocate and copy the
+ * internal array.
+ *
+ * However, they provide `O(n/m)` complexity random access,
+ * where `n` is the number of elements, and `m` the size of
+ * internal array chunks.
+ *
+ * Ideal to use when:
+ * - elements are added to the buffer and then all of the
+ * elements are traversed sequentially
+ * - two unrolled buffers need to be concatenated (see `concat`)
+ *
+ * Better than singly linked lists for random access, but
+ * should still be avoided for such a purpose.
+ *
+ * @define coll unrolled buffer
+ * @define Coll `UnrolledBuffer`
+ *
+ */
+@SerialVersionUID(3L)
+sealed class UnrolledBuffer[T](implicit val tag: ClassTag[T])
+ extends AbstractBuffer[T]
+ with Buffer[T]
+ with Seq[T]
+ with SeqOps[T, UnrolledBuffer, UnrolledBuffer[T]]
+ with StrictOptimizedSeqOps[T, UnrolledBuffer, UnrolledBuffer[T]]
+ with EvidenceIterableFactoryDefaults[T, UnrolledBuffer, ClassTag]
+ with Builder[T, UnrolledBuffer[T]]
+ with DefaultSerializable {
+
+ import UnrolledBuffer.Unrolled
+
+ @transient private var headptr = newUnrolled
+ @transient private var lastptr = headptr
+ @transient private var sz = 0
+
+ private[collection] def headPtr = headptr
+ private[collection] def headPtr_=(head: Unrolled[T]) = headptr = head
+ private[collection] def lastPtr = lastptr
+ private[collection] def lastPtr_=(last: Unrolled[T]) = lastptr = last
+ private[collection] def size_=(s: Int) = sz = s
+
+ protected def evidenceIterableFactory: UnrolledBuffer.type = UnrolledBuffer
+ protected def iterableEvidence: ClassTag[T] = tag
+
+ override def iterableFactory: SeqFactory[UnrolledBuffer] = UnrolledBuffer.untagged
+
+ protected def newUnrolled = new Unrolled[T](this)
+
+ // The below would allow more flexible behavior without requiring inheritance
+ // that is risky because all the important internals are private.
+ // private var myLengthPolicy: Int => Int = x => x
+ //
+ // /** Specifies how the array lengths should vary.
+ // *
+ // * By default, `UnrolledBuffer` uses arrays of a fixed size. A length
+ // * policy can be given that changes this scheme to, for instance, an
+ // * exponential growth.
+ // *
+ // * @param nextLength computes the length of the next array from the length of the latest one
+ // */
+ // def setLengthPolicy(nextLength: Int => Int): Unit = { myLengthPolicy = nextLength }
+ private[collection] def calcNextLength(sz: Int) = sz // myLengthPolicy(sz)
+
+ def classTagCompanion: UnrolledBuffer.type = UnrolledBuffer
+
+ /** Concatenates the target unrolled buffer to this unrolled buffer.
+ *
+ * The specified buffer `that` is cleared after this operation. This is
+ * an O(1) operation.
+ *
+ * @param that the unrolled buffer whose elements are added to this buffer
+ */
+ def concat(that: UnrolledBuffer[T]) = {
+ // bind the two together
+ if (!lastptr.bind(that.headptr)) lastptr = that.lastPtr
+
+ // update size
+ sz += that.sz
+
+ // `that` is no longer usable, so clear it
+ // here we rely on the fact that `clear` allocates
+ // new nodes instead of modifying the previous ones
+ that.clear()
+
+ // return a reference to this
+ this
+ }
+
+ def addOne(elem: T) = {
+ lastptr = lastptr.append(elem)
+ sz += 1
+ this
+ }
+
+ def clear(): Unit = {
+ headptr = newUnrolled
+ lastptr = headptr
+ sz = 0
+ }
+
+ def iterator: Iterator[T] = new AbstractIterator[T] {
+ var pos: Int = -1
+ var node: Unrolled[T] = headptr
+ scan()
+
+ private def scan(): Unit = {
+ pos += 1
+ while (pos >= node.size) {
+ pos = 0
+ node = node.next
+ if (node eq null) return
+ }
+ }
+ def hasNext = node ne null
+ def next() = if (hasNext) {
+ val r = node.array(pos)
+ scan()
+ r
+ } else Iterator.empty.next()
+ }
+
+ // this should be faster than the iterator
+ override def foreach[U](f: T => U) = headptr.foreach(f)
+
+ def result() = this
+
+ def length = sz
+
+ override def knownSize: Int = sz
+
+ def apply(idx: Int) =
+ if (idx >= 0 && idx < sz) headptr(idx)
+ else throw CommonErrors.indexOutOfBounds(index = idx, max = sz - 1)
+
+ def update(idx: Int, newelem: T) =
+ if (idx >= 0 && idx < sz) headptr(idx) = newelem
+ else throw CommonErrors.indexOutOfBounds(index = idx, max = sz - 1)
+
+ /** Replace the contents of this $coll with the mapped result.
+ *
+ * @param f the mapping function
+ * @return this $coll
+ */
+ def mapInPlace(f: T => T): this.type = {
+ headptr.mapInPlace(f)
+ this
+ }
+
+ def remove(idx: Int) =
+ if (idx >= 0 && idx < sz) {
+ sz -= 1
+ headptr.remove(idx, this)
+ } else throw CommonErrors.indexOutOfBounds(index = idx, max = sz - 1)
+
+ @tailrec final def remove(idx: Int, count: Int): Unit =
+ if (count > 0) {
+ remove(idx)
+ remove(idx, count-1)
+ }
+
+ def prepend(elem: T) = {
+ headptr = headptr prepend elem
+ sz += 1
+ this
+ }
+
+ def insert(idx: Int, elem: T): Unit =
+ insertAll(idx, elem :: Nil)
+
+ def insertAll(idx: Int, elems: IterableOnce[T]): Unit =
+ if (idx >= 0 && idx <= sz) {
+ sz += headptr.insertAll(idx, elems, this)
+ } else throw CommonErrors.indexOutOfBounds(index = idx, max = sz - 1)
+
+ override def subtractOne(elem: T): this.type = {
+ if (headptr.subtractOne(elem, this)) {
+ sz -= 1
+ }
+ this
+ }
+
+ def patchInPlace(from: Int, patch: collection.IterableOnce[T], replaced: Int): this.type = {
+ remove(from, replaced)
+ insertAll(from, patch)
+ this
+ }
+
+ private def writeObject(out: java.io.ObjectOutputStream): Unit = {
+ out.defaultWriteObject
+ out writeInt sz
+ for (elem <- this) out writeObject elem
+ }
+
+ private def readObject(in: java.io.ObjectInputStream): Unit = {
+ in.defaultReadObject
+
+ val num = in.readInt
+
+ headPtr = newUnrolled
+ lastPtr = headPtr
+ sz = 0
+ var i = 0
+ while (i < num) {
+ this += in.readObject.asInstanceOf[T]
+ i += 1
+ }
+ }
+
+ override def clone(): UnrolledBuffer[T] = new UnrolledBuffer[T] ++= this
+
+ override protected[this] def className = "UnrolledBuffer"
+}
+
+
+@SerialVersionUID(3L)
+object UnrolledBuffer extends StrictOptimizedClassTagSeqFactory[UnrolledBuffer] { self =>
+
+ val untagged: SeqFactory[UnrolledBuffer] = new ClassTagSeqFactory.AnySeqDelegate(self)
+
+ def empty[A : ClassTag]: UnrolledBuffer[A] = new UnrolledBuffer[A]
+
+ def from[A : ClassTag](source: scala.collection.IterableOnce[A]): UnrolledBuffer[A] = newBuilder[A].addAll(source)
+
+ def newBuilder[A : ClassTag]: UnrolledBuffer[A] = new UnrolledBuffer[A]
+
+ final val waterline: Int = 50
+
+ final def waterlineDenom: Int = 100
+
+ @deprecated("Use waterlineDenom instead.", "2.13.0")
+ final val waterlineDelim: Int = waterlineDenom
+
+ private[collection] val unrolledlength = 32
+
+ /** Unrolled buffer node.
+ */
+ class Unrolled[T: ClassTag] private[collection] (var size: Int, var array: Array[T], var next: Unrolled[T], val buff: UnrolledBuffer[T] = null) {
+ private[collection] def this() = this(0, new Array[T](unrolledlength), null, null)
+ private[collection] def this(b: UnrolledBuffer[T]) = this(0, new Array[T](unrolledlength), null, b)
+
+ private def nextlength = if (buff eq null) unrolledlength else buff.calcNextLength(array.length)
+
+ // adds and returns itself or the new unrolled if full
+ @tailrec final def append(elem: T): Unrolled[T] = if (size < array.length) {
+ array(size) = elem
+ size += 1
+ this
+ } else {
+ next = new Unrolled[T](0, new Array[T](nextlength), null, buff)
+ next append elem
+ }
+ def foreach[U](f: T => U): Unit = {
+ var unrolled = this
+ var i = 0
+ while (unrolled ne null) {
+ val chunkarr = unrolled.array
+ val chunksz = unrolled.size
+ while (i < chunksz) {
+ val elem = chunkarr(i)
+ f(elem)
+ i += 1
+ }
+ i = 0
+ unrolled = unrolled.next
+ }
+ }
+ def mapInPlace(f: T => T): Unit = {
+ var unrolled = this
+ var i = 0
+ while (unrolled ne null) {
+ val chunkarr = unrolled.array
+ val chunksz = unrolled.size
+ while (i < chunksz) {
+ val elem = chunkarr(i)
+ chunkarr(i) = f(elem)
+ i += 1
+ }
+ i = 0
+ unrolled = unrolled.next
+ }
+ }
+ @tailrec final def apply(idx: Int): T =
+ if (idx < size) array(idx) else next.apply(idx - size)
+ @tailrec final def update(idx: Int, newelem: T): Unit =
+ if (idx < size) array(idx) = newelem else next.update(idx - size, newelem)
+ @tailrec final def locate(idx: Int): Unrolled[T] =
+ if (idx < size) this else next.locate(idx - size)
+ def prepend(elem: T) = if (size < array.length) {
+ // shift the elements of the array right
+ // then insert the element
+ shiftright()
+ array(0) = elem
+ size += 1
+ this
+ } else {
+ // allocate a new node and store element
+ // then make it point to this
+ val newhead = new Unrolled[T](buff)
+ newhead append elem
+ newhead.next = this
+ newhead
+ }
+ // shifts right assuming enough space
+ private def shiftright(): Unit = {
+ var i = size - 1
+ while (i >= 0) {
+ array(i + 1) = array(i)
+ i -= 1
+ }
+ }
+ // returns pointer to new last if changed
+ @tailrec final def remove(idx: Int, buffer: UnrolledBuffer[T]): T =
+ if (idx < size) {
+ // remove the element
+ // then try to merge with the next bucket
+ val r = array(idx)
+ shiftleft(idx)
+ size -= 1
+ if (tryMergeWithNext()) buffer.lastPtr = this
+ r
+ } else next.remove(idx - size, buffer)
+
+ @tailrec final def subtractOne(elem: T, buffer: UnrolledBuffer[T]): Boolean = {
+ var i = 0
+ while (i < size) {
+ if(array(i) == elem) {
+ remove(i, buffer)
+ return true
+ }
+ i += 1
+ }
+ if(next ne null) next.subtractOne(elem, buffer) else false
+ }
+
+ // shifts left elements after `leftb` (overwrites `leftb`)
+ private def shiftleft(leftb: Int): Unit = {
+ var i = leftb
+ while (i < (size - 1)) {
+ array(i) = array(i + 1)
+ i += 1
+ }
+ nullout(i, i + 1)
+ }
+ protected def tryMergeWithNext() = if (next != null && (size + next.size) < (array.length * waterline / waterlineDenom)) {
+ // copy the next array, then discard the next node
+ Array.copy(next.array, 0, array, size, next.size)
+ size = size + next.size
+ next = next.next
+ if (next eq null) true else false // checks if last node was thrown out
+ } else false
+
+ @tailrec final def insertAll(idx: Int, t: scala.collection.IterableOnce[T], buffer: UnrolledBuffer[T]): Int = {
+ if (idx < size) {
+ // divide this node at the appropriate position and insert all into head
+ // update new next
+ val newnextnode = new Unrolled[T](0, new Array(array.length), null, buff)
+ Array.copy(array, idx, newnextnode.array, 0, size - idx)
+ newnextnode.size = size - idx
+ newnextnode.next = next
+
+ // update this
+ nullout(idx, size)
+ size = idx
+ next = null
+
+ // insert everything from iterable to this
+ var curr = this
+ var appended = 0
+ for (elem <- t.iterator) {
+ curr = curr append elem
+ appended += 1
+ }
+ curr.next = newnextnode
+
+ // try to merge the last node of this with the newnextnode and fix tail pointer if needed
+ if (curr.tryMergeWithNext()) buffer.lastPtr = curr
+ else if (newnextnode.next eq null) buffer.lastPtr = newnextnode
+ appended
+ }
+ else if (idx == size || (next eq null)) {
+ var curr = this
+ var appended = 0
+ for (elem <- t.iterator) {
+ curr = curr append elem
+ appended += 1
+ }
+ appended
+ }
+ else next.insertAll(idx - size, t, buffer)
+ }
+
+ private def nullout(from: Int, until: Int): Unit = {
+ var idx = from
+ while (idx < until) {
+ array(idx) = null.asInstanceOf[T] // TODO find a way to assign a default here!!
+ idx += 1
+ }
+ }
+
+ // assumes this is the last node
+ // `thathead` and `thatlast` are head and last node
+ // of the other unrolled list, respectively
+ def bind(thathead: Unrolled[T]) = {
+ assert(next eq null)
+ next = thathead
+ tryMergeWithNext()
+ }
+
+ override def toString: String =
+ array.take(size).mkString("Unrolled@%08x".format(System.identityHashCode(this)) + "[" + size + "/" + array.length + "](", ", ", ")") + " -> " + (if (next ne null) next.toString else "")
+ }
+}
+
+// This is used by scala.collection.parallel.mutable.UnrolledParArrayCombiner:
+// Todo -- revisit whether inheritance is the best way to achieve this functionality
+private[collection] class DoublingUnrolledBuffer[T](implicit t: ClassTag[T]) extends UnrolledBuffer[T]()(t) {
+ override def calcNextLength(sz: Int) = if (sz < 10000) sz * 2 else sz
+ override protected def newUnrolled = new UnrolledBuffer.Unrolled[T](0, new Array[T](4), null, this)
+}
diff --git a/library/src/scala/collection/mutable/WeakHashMap.scala b/library/src/scala/collection/mutable/WeakHashMap.scala
new file mode 100644
index 000000000000..ae0230c8ab83
--- /dev/null
+++ b/library/src/scala/collection/mutable/WeakHashMap.scala
@@ -0,0 +1,55 @@
+/*
+ * 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 collection
+package mutable
+
+import scala.annotation.nowarn
+import scala.collection.convert.JavaCollectionWrappers.{JMapWrapper, JMapWrapperLike}
+
+/** A hash map with references to entries which are weakly reachable. Entries are
+ * removed from this map when the key is no longer (strongly) referenced. This class wraps
+ * `java.util.WeakHashMap`.
+ *
+ * @tparam K type of keys contained in this map
+ * @tparam V type of values associated with the keys
+ *
+ * @see [[https://docs.scala-lang.org/overviews/collections-2.13/concrete-mutable-collection-classes.html#weak-hash-maps "Scala's Collection Library overview"]]
+ * section on `Weak Hash Maps` for more information.
+ *
+ * @define Coll `WeakHashMap`
+ * @define coll weak hash map
+ * @define mayNotTerminateInf
+ * @define willNotTerminateInf
+ */
+@SerialVersionUID(3L)
+class WeakHashMap[K, V] extends JMapWrapper[K, V](new java.util.WeakHashMap)
+ with JMapWrapperLike[K, V, WeakHashMap, WeakHashMap[K, V]]
+ with MapFactoryDefaults[K, V, WeakHashMap, Iterable] {
+ override def empty = new WeakHashMap[K, V]
+ override def mapFactory: MapFactory[WeakHashMap] = WeakHashMap
+ @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
+ override protected[this] def stringPrefix = "WeakHashMap"
+}
+
+/** $factoryInfo
+ * @define Coll `WeakHashMap`
+ * @define coll weak hash map
+ */
+@SerialVersionUID(3L)
+object WeakHashMap extends MapFactory[WeakHashMap] {
+ def empty[K, V]: WeakHashMap[K,V] = new WeakHashMap[K, V]
+ def from[K, V](it: collection.IterableOnce[(K, V)]): WeakHashMap[K,V] = Growable.from(empty[K, V], it)
+ def newBuilder[K, V]: Builder[(K, V), WeakHashMap[K,V]] = new GrowableBuilder(WeakHashMap.empty[K, V])
+}
+
diff --git a/library/src/scala/collection/mutable/package.scala b/library/src/scala/collection/mutable/package.scala
new file mode 100644
index 000000000000..4ad5df4813d8
--- /dev/null
+++ b/library/src/scala/collection/mutable/package.scala
@@ -0,0 +1,41 @@
+/*
+ * 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 object mutable {
+ @deprecated("Use ArraySeq instead of WrappedArray; it can represent both, boxed and unboxed arrays", "2.13.0")
+ type WrappedArray[X] = ArraySeq[X]
+ @deprecated("Use ArraySeq instead of WrappedArray; it can represent both, boxed and unboxed arrays", "2.13.0")
+ val WrappedArray = ArraySeq
+ @deprecated("Use Iterable instead of Traversable", "2.13.0")
+ type Traversable[X] = Iterable[X]
+ @deprecated("Use Iterable instead of Traversable", "2.13.0")
+ val Traversable = Iterable
+ @deprecated("Use Stack instead of ArrayStack; it now uses an array-based implementation", "2.13.0")
+ type ArrayStack[X] = Stack[X]
+ @deprecated("Use Stack instead of ArrayStack; it now uses an array-based implementation", "2.13.0")
+ val ArrayStack = Stack
+
+ @deprecated("mutable.LinearSeq has been removed; use LinearSeq with mutable.Seq instead", "2.13.0")
+ type LinearSeq[X] = Seq[X] with scala.collection.LinearSeq[X]
+
+ @deprecated("GrowingBuilder has been renamed to GrowableBuilder", "2.13.0")
+ type GrowingBuilder[Elem, To <: Growable[Elem]] = GrowableBuilder[Elem, To]
+
+ @deprecated("IndexedOptimizedSeq has been renamed to IndexedSeq", "2.13.0")
+ type IndexedOptimizedSeq[A] = IndexedSeq[A]
+
+ @deprecated("IndexedOptimizedBuffer has been renamed to IndexedBuffer", "2.13.0")
+ type IndexedOptimizedBuffer[A] = IndexedBuffer[A]
+}
diff --git a/library/src/scala/collection/package.scala b/library/src/scala/collection/package.scala
new file mode 100644
index 000000000000..f6a89b5c288c
--- /dev/null
+++ b/library/src/scala/collection/package.scala
@@ -0,0 +1,80 @@
+/*
+ * 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 object collection {
+ @deprecated("Use Iterable instead of Traversable", "2.13.0")
+ type Traversable[+X] = Iterable[X]
+ @deprecated("Use Iterable instead of Traversable", "2.13.0")
+ val Traversable = Iterable
+ @deprecated("Use IterableOnce instead of TraversableOnce", "2.13.0")
+ type TraversableOnce[+X] = IterableOnce[X]
+ @deprecated("Use IterableOnce instead of TraversableOnce", "2.13.0")
+ val TraversableOnce = IterableOnce
+ @deprecated("Use SeqOps instead of SeqLike", "2.13.0")
+ type SeqLike[A, T] = SeqOps[A, Seq, T]
+ @deprecated("Use SeqOps (for the methods) or IndexedSeqOps (for fast indexed access) instead of ArrayLike", "2.13.0")
+ type ArrayLike[A] = SeqOps[A, Seq, Seq[A]]
+
+ @deprecated("Gen* collection types have been removed", "2.13.0")
+ type GenTraversableOnce[+X] = IterableOnce[X]
+ @deprecated("Gen* collection types have been removed", "2.13.0")
+ val GenTraversableOnce = IterableOnce
+ @deprecated("Gen* collection types have been removed", "2.13.0")
+ type GenTraversable[+X] = Iterable[X]
+ @deprecated("Gen* collection types have been removed", "2.13.0")
+ val GenTraversable = Iterable
+ @deprecated("Gen* collection types have been removed", "2.13.0")
+ type GenIterable[+X] = Iterable[X]
+ @deprecated("Gen* collection types have been removed", "2.13.0")
+ val GenIterable = Iterable
+ @deprecated("Gen* collection types have been removed", "2.13.0")
+ type GenSeq[+X] = Seq[X]
+ @deprecated("Gen* collection types have been removed", "2.13.0")
+ val GenSeq = Seq
+ @deprecated("Gen* collection types have been removed", "2.13.0")
+ type GenSet[X] = Set[X]
+ @deprecated("Gen* collection types have been removed", "2.13.0")
+ val GenSet = Set
+ @deprecated("Gen* collection types have been removed", "2.13.0")
+ type GenMap[K, +V] = Map[K, V]
+ @deprecated("Gen* collection types have been removed", "2.13.0")
+ val GenMap = Map
+
+ /** Needed to circumvent a difficulty between dotty and scalac concerning
+ * the right top type for a type parameter of kind * -> *.
+ * In Scalac, we can provide `Any`, as `Any` is kind-polymorphic. In dotty this is not allowed.
+ * In dotty, we can provide `[X] => Any`. But Scalac does not know lambda syntax.
+ */
+ private[scala] type AnyConstr[X] = Any
+
+ /** An extractor used to head/tail deconstruct sequences. */
+ object +: {
+ /** Splits a sequence into head +: tail.
+ * @return Some((head, tail)) if sequence is non-empty. None otherwise.
+ */
+ def unapply[A, CC[_] <: Seq[_], C <: SeqOps[A, CC, C]](t: C with SeqOps[A, CC, C]): Option[(A, C)] =
+ if(t.isEmpty) None
+ else Some(t.head -> t.tail)
+ }
+
+ /** An extractor used to init/last deconstruct sequences. */
+ object :+ {
+ /** Splits a sequence into init :+ last.
+ * @return Some((init, last)) if sequence is non-empty. None otherwise.
+ */
+ def unapply[A, CC[_] <: Seq[_], C <: SeqOps[A, CC, C]](t: C with SeqOps[A, CC, C]): Option[(C, A)] =
+ if(t.isEmpty) None
+ else Some(t.init -> t.last)
+ }
+}
diff --git a/library/src/scala/compat/Platform.scala b/library/src/scala/compat/Platform.scala
new file mode 100644
index 000000000000..b3ecb194a12c
--- /dev/null
+++ b/library/src/scala/compat/Platform.scala
@@ -0,0 +1,146 @@
+/*
+ * 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 compat
+
+@deprecated("Will be removed in the future.", since = "2.13.0")
+object Platform {
+
+ /** Thrown when a stack overflow occurs because a method or function recurses too deeply.
+ *
+ * On the JVM, this is a type alias for `java.lang.StackOverflowError`, which itself extends `java.lang.Error`.
+ * The same rules apply to catching a `java.lang.Error` as for Java, that it indicates a serious problem that a reasonable application should not try and catch.
+ */
+ @deprecated("Use `java.lang.StackOverflowError` instead.", since = "2.13.0")
+ type StackOverflowError = java.lang.StackOverflowError
+
+ /** This is a type alias for `java.util.ConcurrentModificationException`,
+ * which may be thrown by methods that detect an invalid modification of an object.
+ * For example, many common collection types do not allow modifying a collection
+ * while it is being iterated over.
+ */
+ @deprecated("Use `java.util.ConcurrentModificationException` instead.", since = "2.13.0")
+ type ConcurrentModificationException = java.util.ConcurrentModificationException
+
+ /** Copies `length` elements of array `src` starting at position `srcPos` to the
+ * array `dest` starting at position `destPos`. If `src`==`dest`, the copying will
+ * behave as if the elements copied from `src` were first copied to a temporary
+ * array before being copied back into the array at the destination positions.
+ *
+ * @param src A non-null array as source for the copy.
+ * @param srcPos The starting index in the source array.
+ * @param dest A non-null array as destination for the copy.
+ * @param destPos The starting index in the destination array.
+ * @param length The number of elements to be copied.
+ * @throws java.lang.NullPointerException If either `src` or `dest` are `null`.
+ * @throws java.lang.ArrayStoreException If either `src` or `dest` are not of type
+ * [java.lang.Array]; or if the element type of `src` is not
+ * compatible with that of `dest`.
+ * @throws java.lang.IndexOutOfBoundsException If either `srcPos` or `destPos` are
+ * outside of the bounds of their respective arrays; or if `length`
+ * is negative; or if there are less than `length` elements available
+ * after `srcPos` or `destPos` in `src` and `dest` respectively.
+ */
+ @inline
+ @deprecated("Use `java.lang.System#arraycopy` instead.", since = "2.13.0")
+ def arraycopy(src: AnyRef, srcPos: Int, dest: AnyRef, destPos: Int, length: Int): Unit = {
+ System.arraycopy(src, srcPos, dest, destPos, length)
+ }
+
+ /** Creates a new array of the specified type and given length.
+ *
+ * Note that if `elemClass` is a subclass of [[scala.AnyVal]] then the returned value is an Array of the corresponding java primitive type.
+ * For example, the following code `scala.compat.Platform.createArray(classOf[Int], 4)` returns an array of the java primitive type `int`.
+ *
+ * For a [[scala.AnyVal]] array, the values of the array are set to 0 for ''numeric value types'' ([[scala.Double]], [[scala.Float]], [[scala.Long]], [[scala.Int]], [[scala.Char]],
+ * [[scala.Short]], and [[scala.Byte]]), and `false` for [[scala.Boolean]]. Creation of an array of type [[scala.Unit]] is not possible.
+ *
+ * For subclasses of [[scala.AnyRef]], the values of the array are set to `null`.
+ *
+ * The caller must cast the returned value to the correct type.
+ *
+ * @example {{{
+ * val a = scala.compat.Platform.createArray(classOf[Int], 4).asInstanceOf[Array[Int]] // returns Array[Int](0, 0, 0, 0)
+ * }}}
+ *
+ * @param elemClass the `Class` object of the component type of the array
+ * @param length the length of the new array.
+ * @return an array of the given component type as an `AnyRef`.
+ * @throws java.lang.NullPointerException If `elemClass` is `null`.
+ * @throws java.lang.IllegalArgumentException if componentType is [[scala.Unit]] or `java.lang.Void.TYPE`
+ * @throws java.lang.NegativeArraySizeException if the specified length is negative
+ */
+ @inline
+ @deprecated("Use `java.lang.reflect.Array#newInstance` instead.", since = "2.13.0")
+ def createArray(elemClass: Class[_], length: Int): AnyRef =
+ java.lang.reflect.Array.newInstance(elemClass, length)
+
+ /** Assigns the value of 0 to each element in the array.
+ * @param arr A non-null Array[Int].
+ * @throws java.lang.NullPointerException If `arr` is `null`.
+ */
+ @inline
+ @deprecated("Use `java.util.Arrays#fill` instead.", since = "2.13.0")
+ def arrayclear(arr: Array[Int]): Unit = { java.util.Arrays.fill(arr, 0) }
+
+ /** Returns the `Class` object associated with the class or interface with the given string name using the current `ClassLoader`.
+ * On the JVM, invoking this method is equivalent to: `java.lang.Class.forName(name)`
+ *
+ * For more information, please see the Java documentation for [[java.lang.Class]].
+ *
+ * @param name the fully qualified name of the desired class.
+ * @return the `Class` object for the class with the specified name.
+ * @throws java.lang.LinkageError if the linkage fails
+ * @throws java.lang.ExceptionInInitializerError if the initialization provoked by this method fails
+ * @throws java.lang.ClassNotFoundException if the class cannot be located
+ * @example {{{
+ * val a = scala.compat.Platform.getClassForName("java.lang.Integer") // returns the Class[_] for java.lang.Integer
+ * }}}
+ */
+ @inline
+ @deprecated("Use `java.lang.Class#forName` instead.", since = "2.13.0")
+ def getClassForName(name: String): Class[_] = java.lang.Class.forName(name)
+
+ /** The default line separator.
+ *
+ * On the JVM, this is equivalent to calling the method:
+ * `java.lang.System.lineSeparator`
+ */
+ @deprecated("Use `java.lang.System#lineSeparator` instead.", since = "2.13.0")
+ val EOL: String = System.lineSeparator
+
+ /** The current time in milliseconds. The time is counted since 1 January 1970
+ * UTC.
+ *
+ * Note that the operating system timer used to obtain this value may be less
+ * precise than a millisecond.
+ */
+ @inline
+ @deprecated("Use `java.lang.System#currentTimeMillis` instead.", since = "2.13.0")
+ def currentTime: Long = System.currentTimeMillis()
+
+ /** Runs the garbage collector.
+ *
+ * This is a request that the underlying JVM runs the garbage collector.
+ * The results of this call depends heavily on the JVM used.
+ * The underlying JVM is free to ignore this request.
+ */
+ @inline
+ @deprecated("Use `java.lang.System#gc` instead.", since = "2.13.0")
+ def collectGarbage(): Unit = System.gc()
+
+ /** The name of the default character set encoding as a string */
+ @inline
+ @deprecated("Use `java.nio.charset.Charset.defaultCharset#name` instead.", since = "2.13.0")
+ def defaultCharsetName: String = java.nio.charset.Charset.defaultCharset.name
+}
diff --git a/library/src/scala/concurrent/Awaitable.scala b/library/src/scala/concurrent/Awaitable.scala
new file mode 100644
index 000000000000..1372e1614ac8
--- /dev/null
+++ b/library/src/scala/concurrent/Awaitable.scala
@@ -0,0 +1,69 @@
+/*
+ * 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.concurrent
+
+
+
+import scala.concurrent.duration.Duration
+
+
+
+/**
+ * An object that may eventually be completed with a result value of type `T` which may be
+ * awaited using blocking methods.
+ *
+ * The [[Await]] object provides methods that allow accessing the result of an `Awaitable`
+ * by blocking the current thread until the `Awaitable` has been completed or a timeout has
+ * occurred.
+ */
+trait Awaitable[+T] {
+
+ /**
+ * Await the "completed" state of this `Awaitable`.
+ *
+ * '''''This method should not be called directly; use [[Await.ready]] instead.'''''
+ *
+ * @param atMost
+ * maximum wait time, which may be negative (no waiting is done),
+ * [[scala.concurrent.duration.Duration.Inf Duration.Inf]] for unbounded waiting, or a finite positive
+ * duration
+ * @return this `Awaitable`
+ * @throws InterruptedException if the current thread is interrupted while waiting
+ * @throws TimeoutException if after waiting for the specified time this `Awaitable` is still not ready
+ * @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]]
+ */
+ @throws(classOf[TimeoutException])
+ @throws(classOf[InterruptedException])
+ def ready(atMost: Duration)(implicit permit: CanAwait): this.type
+
+ /**
+ * Await and return the result (of type `T`) of this `Awaitable`.
+ *
+ * '''''This method should not be called directly; use [[Await.result]] instead.'''''
+ *
+ * @param atMost
+ * maximum wait time, which may be negative (no waiting is done),
+ * [[scala.concurrent.duration.Duration.Inf Duration.Inf]] for unbounded waiting, or a finite positive
+ * duration
+ * @return the result value if the `Awaitable` is completed within the specific maximum wait time
+ * @throws InterruptedException if the current thread is interrupted while waiting
+ * @throws TimeoutException if after waiting for the specified time this `Awaitable` is still not ready
+ * @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]]
+ */
+ @throws(classOf[TimeoutException])
+ @throws(classOf[InterruptedException])
+ def result(atMost: Duration)(implicit permit: CanAwait): T
+}
+
+
+
diff --git a/library/src/scala/concurrent/BatchingExecutor.scala b/library/src/scala/concurrent/BatchingExecutor.scala
new file mode 100644
index 000000000000..ac197c89f8c1
--- /dev/null
+++ b/library/src/scala/concurrent/BatchingExecutor.scala
@@ -0,0 +1,270 @@
+/*
+ * 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.concurrent
+
+import java.util.concurrent.Executor
+import java.util.Objects
+import scala.util.control.NonFatal
+import scala.annotation.{switch, tailrec}
+
+/**
+ * Marker trait to indicate that a Runnable is Batchable by BatchingExecutors
+ */
+trait Batchable {
+ self: Runnable =>
+}
+
+private[concurrent] object BatchingExecutorStatics {
+ final val emptyBatchArray: Array[Runnable] = new Array[Runnable](0)
+
+ // Max number of Runnables executed nested before starting to batch (to prevent stack exhaustion)
+ final val syncPreBatchDepth = 16
+
+ // Max number of Runnables processed in one go (to prevent starvation of other tasks on the pool)
+ final val runLimit = 1024
+
+ object MissingParentBlockContext extends BlockContext {
+ override def blockOn[T](thunk: => T)(implicit permission: CanAwait): T =
+ try thunk finally throw new IllegalStateException("BUG in BatchingExecutor.Batch: parentBlockContext is null")
+ }
+}
+
+/**
+ * Mixin trait for an Executor
+ * which groups multiple nested `Runnable.run()` calls
+ * into a single Runnable passed to the original
+ * Executor. This can be a useful optimization
+ * because it bypasses the original context's task
+ * queue and keeps related (nested) code on a single
+ * thread which may improve CPU affinity. However,
+ * if tasks passed to the Executor are blocking
+ * or expensive, this optimization can prevent work-stealing
+ * and make performance worse.
+ * A batching executor can create deadlocks if code does
+ * not use `scala.concurrent.blocking` when it should,
+ * because tasks created within other tasks will block
+ * on the outer task completing.
+ * This executor may run tasks in any order, including LIFO order.
+ * There are no ordering guarantees.
+ *
+ * WARNING: Only use *EITHER* `submitAsyncBatched` OR `submitSyncBatched`!!
+ *
+ * When you implement this trait for async executors like thread pools,
+ * you're going to need to implement it something like the following:
+ *
+ * {{{
+ * final override def submitAsync(runnable: Runnable): Unit =
+ * super[SuperClass].execute(runnable) // To prevent reentrancy into `execute`
+ *
+ * final override def execute(runnable: Runnable): Unit =
+ * if (runnable.isInstanceOf[Batchable]) // Or other logic
+ * submitAsyncBatched(runnable)
+ * else
+ * submitAsync(runnable)
+ *
+ * final override def reportFailure(cause: Throwable): Unit = …
+ * }}}
+ *
+ * And if you want to implement if for a sync, trampolining, executor you're
+ * going to implement it something like this:
+ *
+ * {{{
+ * final override def submitAsync(runnable: Runnable): Unit = ()
+ *
+ * final override def execute(runnable: Runnable): Unit =
+ * submitSyncBatched(runnable) // You typically will want to batch everything
+ *
+ * final override def reportFailure(cause: Throwable): Unit =
+ * ExecutionContext.defaultReporter(cause) // Or choose something more fitting
+ * }}}
+ *
+ */
+private[concurrent] trait BatchingExecutor extends Executor {
+ private[this] final val _tasksLocal = new ThreadLocal[AnyRef]()
+
+ /*
+ * Batch implements a LIFO queue (stack) and is used as a trampolining Runnable.
+ * In order to conserve allocations, the first element in the batch is stored "unboxed" in
+ * the `first` field. Subsequent Runnables are stored in the array called `other`.
+ */
+ private[this] sealed abstract class AbstractBatch protected (protected final var first: Runnable, protected final var other: Array[Runnable], protected final var size: Int) {
+
+ private[this] final def ensureCapacity(curSize: Int): Array[Runnable] = {
+ val curOther = this.other
+ val curLen = curOther.length
+ if (curSize <= curLen) curOther
+ else {
+ val newLen = if (curLen == 0) 4 else curLen << 1
+
+ if (newLen <= curLen) throw new StackOverflowError("Space limit of asynchronous stack reached: " + curLen)
+ val newOther = new Array[Runnable](newLen)
+ System.arraycopy(curOther, 0, newOther, 0, curLen)
+ this.other = newOther
+ newOther
+ }
+ }
+
+ final def push(r: Runnable): Unit = {
+ val sz = this.size
+ if(sz == 0)
+ this.first = r
+ else
+ ensureCapacity(sz)(sz - 1) = r
+ this.size = sz + 1
+ }
+
+ @tailrec protected final def runN(n: Int): Unit =
+ if (n > 0)
+ (this.size: @switch) match {
+ case 0 =>
+ case 1 =>
+ val next = this.first
+ this.first = null
+ this.size = 0
+ next.run()
+ runN(n - 1)
+ case sz =>
+ val o = this.other
+ val next = o(sz - 2)
+ o(sz - 2) = null
+ this.size = sz - 1
+ next.run()
+ runN(n - 1)
+ }
+ }
+
+ private[this] final class AsyncBatch private(_first: Runnable, _other: Array[Runnable], _size: Int) extends AbstractBatch(_first, _other, _size) with Runnable with BlockContext with (BlockContext => Throwable) {
+ private[this] final var parentBlockContext: BlockContext = BatchingExecutorStatics.MissingParentBlockContext
+
+ final def this(runnable: Runnable) = this(runnable, BatchingExecutorStatics.emptyBatchArray, 1)
+
+ override final def run(): Unit = {
+ _tasksLocal.set(this) // This is later cleared in `apply` or `runWithoutResubmit`
+
+ val f = resubmit(BlockContext.usingBlockContext(this)(this))
+
+ if (f != null)
+ throw f
+ }
+
+ /* LOGIC FOR ASYNCHRONOUS BATCHES */
+ override final def apply(prevBlockContext: BlockContext): Throwable = try {
+ parentBlockContext = prevBlockContext
+ runN(BatchingExecutorStatics.runLimit)
+ null
+ } catch {
+ case t: Throwable => t // We are handling exceptions on the outside of this method
+ } finally {
+ parentBlockContext = BatchingExecutorStatics.MissingParentBlockContext
+ _tasksLocal.remove()
+ }
+
+ /* Attempts to resubmit this Batch to the underlying ExecutionContext,
+ * this only happens for Batches where `resubmitOnBlock` is `true`.
+ * Only attempt to resubmit when there are `Runnables` left to process.
+ * Note that `cause` can be `null`.
+ */
+ private[this] final def resubmit(cause: Throwable): Throwable =
+ if (this.size > 0) {
+ try { submitForExecution(this); cause } catch {
+ case inner: Throwable =>
+ if (NonFatal(inner)) {
+ val e = new ExecutionException("Non-fatal error occurred and resubmission failed, see suppressed exception.", cause)
+ e.addSuppressed(inner)
+ e
+ } else inner
+ }
+ } else cause // TODO: consider if NonFatals should simply be `reportFailure`:ed rather than rethrown
+
+ private[this] final def cloneAndClear(): AsyncBatch = {
+ val newBatch = new AsyncBatch(this.first, this.other, this.size)
+ this.first = null
+ this.other = BatchingExecutorStatics.emptyBatchArray
+ this.size = 0
+ newBatch
+ }
+
+ override final def blockOn[T](thunk: => T)(implicit permission: CanAwait): T = {
+ // If we know there will be blocking, we don't want to keep tasks queued up because it could deadlock.
+ if(this.size > 0)
+ submitForExecution(cloneAndClear()) // If this throws then we have bigger problems
+
+ parentBlockContext.blockOn(thunk) // Now delegate the blocking to the previous BC
+ }
+ }
+
+ private[this] final class SyncBatch(runnable: Runnable) extends AbstractBatch(runnable, BatchingExecutorStatics.emptyBatchArray, 1) with Runnable {
+ @tailrec override final def run(): Unit = {
+ try runN(BatchingExecutorStatics.runLimit) catch {
+ case ie: InterruptedException =>
+ reportFailure(ie) // TODO: Handle InterruptedException differently?
+ case f if NonFatal(f) =>
+ reportFailure(f)
+ }
+
+ if (this.size > 0)
+ run()
+ }
+ }
+
+ /** MUST throw a NullPointerException when `runnable` is null
+ * When implementing a sync BatchingExecutor, it is RECOMMENDED
+ * to implement this method as `runnable.run()`
+ */
+ protected def submitForExecution(runnable: Runnable): Unit
+
+ /** Reports that an asynchronous computation failed.
+ * See `ExecutionContext.reportFailure(throwable: Throwable)`
+ */
+ protected def reportFailure(throwable: Throwable): Unit
+
+ /**
+ * WARNING: Never use both `submitAsyncBatched` and `submitSyncBatched` in the same
+ * implementation of `BatchingExecutor`
+ */
+ protected final def submitAsyncBatched(runnable: Runnable): Unit = {
+ val b = _tasksLocal.get
+ if (b.isInstanceOf[AsyncBatch]) b.asInstanceOf[AsyncBatch].push(runnable)
+ else submitForExecution(new AsyncBatch(runnable))
+ }
+
+ /**
+ * WARNING: Never use both `submitAsyncBatched` and `submitSyncBatched` in the same
+ * implementation of `BatchingExecutor`
+ */
+ protected final def submitSyncBatched(runnable: Runnable): Unit = {
+ Objects.requireNonNull(runnable, "runnable is null")
+ val tl = _tasksLocal
+ val b = tl.get
+ if (b.isInstanceOf[SyncBatch]) b.asInstanceOf[SyncBatch].push(runnable)
+ else {
+ val i = if (b ne null) b.asInstanceOf[java.lang.Integer].intValue else 0
+ if (i < BatchingExecutorStatics.syncPreBatchDepth) {
+ tl.set(java.lang.Integer.valueOf(i + 1))
+ try submitForExecution(runnable) // User code so needs to be try-finally guarded here
+ catch {
+ case ie: InterruptedException =>
+ reportFailure(ie) // TODO: Handle InterruptedException differently?
+ case f if NonFatal(f) =>
+ reportFailure(f)
+ }
+ finally tl.set(b)
+ } else {
+ val batch = new SyncBatch(runnable)
+ tl.set(batch)
+ submitForExecution(batch)
+ tl.set(b) // Batch only throws fatals so no need for try-finally here
+ }
+ }
+ }
+}
diff --git a/library/src/scala/concurrent/BlockContext.scala b/library/src/scala/concurrent/BlockContext.scala
new file mode 100644
index 000000000000..37483c307fd0
--- /dev/null
+++ b/library/src/scala/concurrent/BlockContext.scala
@@ -0,0 +1,110 @@
+/*
+ * 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.concurrent
+
+/**
+ * A context to be notified by [[scala.concurrent.blocking]] when
+ * a thread is about to block. In effect this trait provides
+ * the implementation for [[scala.concurrent.Await]].
+ * [[scala.concurrent.Await.result]] and [[scala.concurrent.Await.ready]]
+ * locates an instance of `BlockContext` by first looking for one
+ * provided through [[BlockContext.withBlockContext]] and failing that,
+ * checking whether `Thread.currentThread` is an instance of `BlockContext`.
+ * So a thread pool can have its `java.lang.Thread` instances implement
+ * `BlockContext`. There's a default `BlockContext` used if the thread
+ * doesn't implement `BlockContext`.
+ *
+ * Typically, you'll want to chain to the previous `BlockContext`,
+ * like this:
+ * {{{
+ * val oldContext = BlockContext.current
+ * val myContext = new BlockContext {
+ * override def blockOn[T](thunk: => T)(implicit permission: CanAwait): T = {
+ * // you'd have code here doing whatever you need to do
+ * // when the thread is about to block.
+ * // Then you'd chain to the previous context:
+ * oldContext.blockOn(thunk)
+ * }
+ * }
+ * BlockContext.withBlockContext(myContext) {
+ * // then this block runs with myContext as the handler
+ * // for scala.concurrent.blocking
+ * }
+ * }}}
+ */
+trait BlockContext {
+
+ /** Used internally by the framework;
+ * Designates (and eventually executes) a thunk which potentially blocks the calling `java.lang.Thread`.
+ *
+ * Clients must use `scala.concurrent.blocking` or `scala.concurrent.Await` instead.
+ *
+ * In implementations of this method it is RECOMMENDED to first check if `permission` is `null` and
+ * if it is, throw an `IllegalArgumentException`.
+ *
+ * @throws IllegalArgumentException if the `permission` is `null`
+ */
+ def blockOn[T](thunk: => T)(implicit permission: CanAwait): T
+}
+
+object BlockContext {
+ private[this] object DefaultBlockContext extends BlockContext {
+ override final def blockOn[T](thunk: => T)(implicit permission: CanAwait): T = thunk
+ }
+
+ /**
+ * The default block context will execute the supplied thunk immediately.
+ * @return the `BlockContext` that will be used if no other is found.
+ **/
+ final def defaultBlockContext: BlockContext = DefaultBlockContext
+
+ private[this] final val contextLocal = new ThreadLocal[BlockContext]()
+
+ private[this] final def prefer(candidate: BlockContext): BlockContext =
+ if (candidate ne null) candidate
+ else {
+ val t = Thread.currentThread
+ if (t.isInstanceOf[BlockContext]) t.asInstanceOf[BlockContext]
+ else DefaultBlockContext
+ }
+
+ /**
+ * @return the `BlockContext` that would be used for the current `java.lang.Thread` at this point
+ **/
+ final def current: BlockContext = prefer(contextLocal.get)
+
+ /**
+ * Installs a current `BlockContext` around executing `body`.
+ **/
+ final def withBlockContext[T](blockContext: BlockContext)(body: => T): T = {
+ val old = contextLocal.get // can be null
+ if (old eq blockContext) body
+ else {
+ contextLocal.set(blockContext)
+ try body finally contextLocal.set(old)
+ }
+ }
+
+ /**
+ * Installs the BlockContext `blockContext` around the invocation to `f` and passes in the previously installed BlockContext to `f`.
+ * @return the value produced by applying `f`
+ **/
+ final def usingBlockContext[I, T](blockContext: BlockContext)(f: BlockContext => T): T = {
+ val old = contextLocal.get // can be null
+ if (old eq blockContext) f(prefer(old))
+ else {
+ contextLocal.set(blockContext)
+ try f(prefer(old)) finally contextLocal.set(old)
+ }
+ }
+}
diff --git a/library/src/scala/concurrent/Channel.scala b/library/src/scala/concurrent/Channel.scala
new file mode 100644
index 000000000000..a9ada60e3da0
--- /dev/null
+++ b/library/src/scala/concurrent/Channel.scala
@@ -0,0 +1,59 @@
+/*
+ * 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.concurrent
+
+/** This class provides a simple FIFO queue of data objects,
+ * which are read by one or more reader threads.
+ *
+ * @tparam A type of data exchanged
+ */
+@deprecated("Use `java.util.concurrent.LinkedTransferQueue` instead.", since = "2.13.0")
+class Channel[A] {
+ private class LinkedList {
+ var elem: A = _
+ var next: LinkedList = _
+ }
+ private[this] var written = new LinkedList // FIFO queue, realized through
+ private[this] var lastWritten = written // aliasing of a linked list
+ private[this] var nreaders = 0
+
+ /** Append a value to the FIFO queue to be read by `read`.
+ * This operation is nonblocking and can be executed by any thread.
+ *
+ * @param x object to enqueue to this channel
+ */
+ def write(x: A): Unit = synchronized {
+ lastWritten.elem = x
+ lastWritten.next = new LinkedList
+ lastWritten = lastWritten.next
+ if (nreaders > 0) notify()
+ }
+
+ /** Retrieve the next waiting object from the FIFO queue,
+ * blocking if necessary until an object is available.
+ *
+ * @return next object dequeued from this channel
+ */
+ def read: A = synchronized {
+ while (written.next == null) {
+ try {
+ nreaders += 1
+ wait()
+ }
+ finally nreaders -= 1
+ }
+ val x = written.elem
+ written = written.next
+ x
+ }
+}
diff --git a/library/src/scala/concurrent/DelayedLazyVal.scala b/library/src/scala/concurrent/DelayedLazyVal.scala
new file mode 100644
index 000000000000..1a450c3c0458
--- /dev/null
+++ b/library/src/scala/concurrent/DelayedLazyVal.scala
@@ -0,0 +1,47 @@
+/*
+ * 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.concurrent
+
+
+/** A `DelayedLazyVal` is a wrapper for lengthy computations which have a
+ * valid partially computed result.
+ *
+ * The first argument is a function for obtaining the result at any given
+ * point in time, and the second is the lengthy computation. Once the
+ * computation is complete, the `apply` method will stop recalculating it
+ * and return a fixed value from that point forward.
+ *
+ * @param f the function to obtain the current value at any point in time
+ * @param body the computation to run to completion in another thread
+ */
+@deprecated("`DelayedLazyVal` Will be removed in the future.", since = "2.13.0")
+class DelayedLazyVal[T](f: () => T, body: => Unit)(implicit exec: ExecutionContext){
+ @volatile private[this] var _isDone = false
+ private[this] lazy val complete = f()
+
+ /** Whether the computation is complete.
+ *
+ * @return true if the computation is complete.
+ */
+ def isDone: Boolean = _isDone
+
+ /** The current result of f(), or the final result if complete.
+ *
+ * @return the current value
+ */
+ def apply(): T = if (isDone) complete else f()
+
+ exec.execute(() => {
+ body; _isDone = true
+ })
+}
diff --git a/library/src/scala/concurrent/ExecutionContext.scala b/library/src/scala/concurrent/ExecutionContext.scala
new file mode 100644
index 000000000000..b132e2dee5b7
--- /dev/null
+++ b/library/src/scala/concurrent/ExecutionContext.scala
@@ -0,0 +1,295 @@
+/*
+ * 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.concurrent
+
+
+import java.util.concurrent.{ ExecutorService, Executor }
+import scala.annotation.implicitNotFound
+
+/**
+ * An `ExecutionContext` can execute program logic asynchronously,
+ * typically but not necessarily on a thread pool.
+ *
+ * A general purpose `ExecutionContext` must be asynchronous in executing
+ * any `Runnable` that is passed into its `execute`-method. A special purpose
+ * `ExecutionContext` may be synchronous but must only be passed to code that
+ * is explicitly safe to be run using a synchronously executing `ExecutionContext`.
+ *
+ * APIs such as `Future.onComplete` require you to provide a callback
+ * and an implicit `ExecutionContext`. The implicit `ExecutionContext`
+ * will be used to execute the callback.
+ *
+ * While it is possible to simply import
+ * `scala.concurrent.ExecutionContext.Implicits.global` to obtain an
+ * implicit `ExecutionContext`, application developers should carefully
+ * consider where they want to define the execution policy;
+ * ideally, one place per application — or per logically related section of code —
+ * will make a decision about which `ExecutionContext` to use.
+ * That is, you will mostly want to avoid hardcoding, especially via an import,
+ * `scala.concurrent.ExecutionContext.Implicits.global`.
+ * The recommended approach is to add `(implicit ec: ExecutionContext)` to methods,
+ * or class constructor parameters, which need an `ExecutionContext`.
+ *
+ * Then locally import a specific `ExecutionContext` in one place for the entire
+ * application or module, passing it implicitly to individual methods.
+ * Alternatively define a local implicit val with the required `ExecutionContext`.
+ *
+ * A custom `ExecutionContext` may be appropriate to execute code
+ * which blocks on IO or performs long-running computations.
+ * `ExecutionContext.fromExecutorService` and `ExecutionContext.fromExecutor`
+ * are good ways to create a custom `ExecutionContext`.
+ *
+ * The intent of `ExecutionContext` is to lexically scope code execution.
+ * That is, each method, class, file, package, or application determines
+ * how to run its own code. This avoids issues such as running
+ * application callbacks on a thread pool belonging to a networking library.
+ * The size of a networking library's thread pool can be safely configured,
+ * knowing that only that library's network operations will be affected.
+ * Application callback execution can be configured separately.
+ */
+@implicitNotFound("""Cannot find an implicit ExecutionContext. You might add
+an (implicit ec: ExecutionContext) parameter to your method.
+
+The ExecutionContext is used to configure how and on which
+thread pools asynchronous tasks (such as Futures) will run,
+so the specific ExecutionContext that is selected is important.
+
+If your application does not define an ExecutionContext elsewhere,
+consider using Scala's global ExecutionContext by defining
+the following:
+
+implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global""")
+trait ExecutionContext {
+
+ /** Runs a block of code on this execution context.
+ *
+ * @param runnable the task to execute
+ */
+ def execute(runnable: Runnable): Unit
+
+ /** Reports that an asynchronous computation failed.
+ *
+ * @param cause the cause of the failure
+ */
+ def reportFailure(@deprecatedName("t") cause: Throwable): Unit
+
+ /** Prepares for the execution of a task. Returns the prepared
+ * execution context. The recommended implementation of
+ * `prepare` is to return `this`.
+ *
+ * This method should no longer be overridden or called. It was
+ * originally expected that `prepare` would be called by
+ * all libraries that consume ExecutionContexts, in order to
+ * capture thread local context. However, this usage has proven
+ * difficult to implement in practice and instead it is
+ * now better to avoid using `prepare` entirely.
+ *
+ * Instead, if an `ExecutionContext` needs to capture thread
+ * local context, it should capture that context when it is
+ * constructed, so that it doesn't need any additional
+ * preparation later.
+ */
+ @deprecated("preparation of ExecutionContexts will be removed", "2.12.0")
+ // This cannot be removed until there is a suitable replacement
+ def prepare(): ExecutionContext = this
+}
+
+/**
+ * An [[ExecutionContext]] that is also a
+ * Java [[java.util.concurrent.Executor Executor]].
+ */
+trait ExecutionContextExecutor extends ExecutionContext with Executor
+
+/**
+ * An [[ExecutionContext]] that is also a
+ * Java [[java.util.concurrent.ExecutorService ExecutorService]].
+ */
+trait ExecutionContextExecutorService extends ExecutionContextExecutor with ExecutorService
+
+
+/** Contains factory methods for creating execution contexts.
+ */
+object ExecutionContext {
+ /**
+ * The global [[ExecutionContext]]. This default `ExecutionContext` implementation is backed by a work-stealing thread
+ * pool. It can be configured via the following system properties:
+ *
+ * - `scala.concurrent.context.minThreads` = defaults to "1"
+ * - `scala.concurrent.context.numThreads` = defaults to "x1" (i.e. the current number of available processors * 1)
+ * - `scala.concurrent.context.maxThreads` = defaults to "x1" (i.e. the current number of available processors * 1)
+ * - `scala.concurrent.context.maxExtraThreads` = defaults to "256"
+ *
+ * The pool size of threads is then `numThreads` bounded by `minThreads` on the lower end and `maxThreads` on the high end.
+ *
+ * The `maxExtraThreads` is the maximum number of extra threads to have at any given time to evade deadlock,
+ * see [[scala.concurrent.blocking]].
+ *
+ * The `global` execution context can be used explicitly, by defining an
+ * `implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global`, or by importing
+ * [[ExecutionContext.Implicits.global]].
+ *
+ * == Batching short-lived nested tasks ==
+ *
+ * Asynchronous code with short-lived nested tasks is executed more efficiently when using
+ * `ExecutionContext.opportunistic` (continue reading to learn why it is `private[scala]` and how to access it).
+ *
+ * `ExecutionContext.opportunistic` uses the same thread pool as `ExecutionContext.global`. It attempts to batch
+ * nested task and execute them on the same thread as the enclosing task. This is ideally suited to execute
+ * short-lived tasks as it reduces the overhead of context switching.
+ *
+ * WARNING: long-running and/or blocking tasks should be demarcated within [[scala.concurrent.blocking]]-blocks
+ * to ensure that any pending tasks in the current batch can be executed by another thread on `global`.
+ *
+ * === How to use ===
+ *
+ * This field is `private[scala]` to maintain binary compatibility. It was added in 2.13.4, code that references it
+ * directly fails to run with a 2.13.0-3 Scala library.
+ *
+ * Libraries should not reference this field directly because users of the library might be using an earlier Scala
+ * version. In order to use the batching `ExecutionContext` in a library, the code needs to fall back to `global`
+ * in case the `opportunistic` field is missing (example below). The resulting `ExecutionContext` has batching
+ * behavior in all Scala 2.13 versions (`global` is batching in 2.13.0-3).
+ *
+ * {{{
+ * implicit val ec: scala.concurrent.ExecutionContext = try {
+ * scala.concurrent.ExecutionContext.getClass
+ * .getDeclaredMethod("opportunistic")
+ * .invoke(scala.concurrent.ExecutionContext)
+ * .asInstanceOf[scala.concurrent.ExecutionContext]
+ * } catch {
+ * case _: NoSuchMethodException =>
+ * scala.concurrent.ExecutionContext.global
+ * }
+ * }}}
+ *
+ * Application authors can safely use the field because the Scala version at run time is the same as at compile time.
+ * Options to bypass the access restriction include:
+ *
+ * 1. Using a structural type (example below). This uses reflection at run time.
+ * 1. Writing a Scala `object` in the `scala` package (example below).
+ * 1. Writing a Java source file. This works because `private[scala]` is emitted as `public` in Java bytecode.
+ *
+ * {{{
+ * // Option 1
+ * implicit val ec: scala.concurrent.ExecutionContext =
+ * (scala.concurrent.ExecutionContext:
+ * {def opportunistic: scala.concurrent.ExecutionContextExecutor}
+ * ).opportunistic
+ *
+ * // Option 2
+ * package scala {
+ * object OpportunisticEC {
+ * implicit val ec: scala.concurrent.ExecutionContext =
+ * scala.concurrent.ExecutionContext.opportunistic
+ * }
+ * }
+ * }}}
+ *
+ * @return the global [[ExecutionContext]]
+ */
+ final lazy val global: ExecutionContextExecutor = impl.ExecutionContextImpl.fromExecutor(null: Executor)
+
+ /**
+ * WARNING: Only ever execute logic which will quickly return control to the caller.
+ *
+ * This `ExecutionContext` steals execution time from other threads by having its
+ * `Runnable`s run on the `Thread` which calls `execute` and then yielding back control
+ * to the caller after *all* its `Runnable`s have been executed.
+ * Nested invocations of `execute` will be trampolined to prevent uncontrolled stack space growth.
+ *
+ * When using `parasitic` with abstractions such as `Future` it will in many cases be non-deterministic
+ * as to which `Thread` will be executing the logic, as it depends on when/if that `Future` is completed.
+ *
+ * Do *not* call any blocking code in the `Runnable`s submitted to this `ExecutionContext`
+ * as it will prevent progress by other enqueued `Runnable`s and the calling `Thread`.
+ *
+ * Symptoms of misuse of this `ExecutionContext` include, but are not limited to, deadlocks
+ * and severe performance problems.
+ *
+ * Any `NonFatal` or `InterruptedException`s will be reported to the `defaultReporter`.
+ */
+ object parasitic extends ExecutionContextExecutor with BatchingExecutor {
+ override final def submitForExecution(runnable: Runnable): Unit = runnable.run()
+ override final def execute(runnable: Runnable): Unit = submitSyncBatched(runnable)
+ override final def reportFailure(t: Throwable): Unit = defaultReporter(t)
+ }
+
+ /**
+ * See [[ExecutionContext.global]].
+ */
+ private[scala] lazy val opportunistic: ExecutionContextExecutor = new ExecutionContextExecutor with BatchingExecutor {
+ final override def submitForExecution(runnable: Runnable): Unit = global.execute(runnable)
+
+ final override def execute(runnable: Runnable): Unit =
+ if ((!runnable.isInstanceOf[impl.Promise.Transformation[_,_]] || runnable.asInstanceOf[impl.Promise.Transformation[_,_]].benefitsFromBatching) && runnable.isInstanceOf[Batchable])
+ submitAsyncBatched(runnable)
+ else
+ submitForExecution(runnable)
+
+ override final def reportFailure(t: Throwable): Unit = global.reportFailure(t)
+ }
+
+ object Implicits {
+ /**
+ * An accessor that can be used to import the global `ExecutionContext` into the implicit scope,
+ * see [[ExecutionContext.global]].
+ */
+ implicit final def global: ExecutionContext = ExecutionContext.global
+ }
+
+ /** Creates an `ExecutionContext` from the given `ExecutorService`.
+ *
+ * @param e the `ExecutorService` to use. If `null`, a new `ExecutorService` is created with [[scala.concurrent.ExecutionContext$.global default configuration]].
+ * @param reporter a function for error reporting
+ * @return the `ExecutionContext` using the given `ExecutorService`
+ */
+ def fromExecutorService(e: ExecutorService, reporter: Throwable => Unit): ExecutionContextExecutorService =
+ impl.ExecutionContextImpl.fromExecutorService(e, reporter)
+
+ /** Creates an `ExecutionContext` from the given `ExecutorService` with the [[scala.concurrent.ExecutionContext$.defaultReporter default reporter]].
+ *
+ * If it is guaranteed that none of the executed tasks are blocking, a single-threaded `ExecutorService`
+ * can be used to create an `ExecutionContext` as follows:
+ *
+ * {{{
+ * import java.util.concurrent.Executors
+ * val ec = ExecutionContext.fromExecutorService(Executors.newSingleThreadExecutor())
+ * }}}
+ *
+ * @param e the `ExecutorService` to use. If `null`, a new `ExecutorService` is created with [[scala.concurrent.ExecutionContext$.global default configuration]].
+ * @return the `ExecutionContext` using the given `ExecutorService`
+ */
+ def fromExecutorService(e: ExecutorService): ExecutionContextExecutorService = fromExecutorService(e, defaultReporter)
+
+ /** Creates an `ExecutionContext` from the given `Executor`.
+ *
+ * @param e the `Executor` to use. If `null`, a new `Executor` is created with [[scala.concurrent.ExecutionContext$.global default configuration]].
+ * @param reporter a function for error reporting
+ * @return the `ExecutionContext` using the given `Executor`
+ */
+ def fromExecutor(e: Executor, reporter: Throwable => Unit): ExecutionContextExecutor =
+ impl.ExecutionContextImpl.fromExecutor(e, reporter)
+
+ /** Creates an `ExecutionContext` from the given `Executor` with the [[scala.concurrent.ExecutionContext$.defaultReporter default reporter]].
+ *
+ * @param e the `Executor` to use. If `null`, a new `Executor` is created with [[scala.concurrent.ExecutionContext$.global default configuration]].
+ * @return the `ExecutionContext` using the given `Executor`
+ */
+ def fromExecutor(e: Executor): ExecutionContextExecutor = fromExecutor(e, defaultReporter)
+
+ /** The default reporter simply prints the stack trace of the `Throwable` to [[java.lang.System#err System.err]].
+ *
+ * @return the function for error reporting
+ */
+ final val defaultReporter: Throwable => Unit = _.printStackTrace()
+}
diff --git a/library/src/scala/concurrent/Future.scala b/library/src/scala/concurrent/Future.scala
new file mode 100644
index 000000000000..371575918e1c
--- /dev/null
+++ b/library/src/scala/concurrent/Future.scala
@@ -0,0 +1,878 @@
+/*
+ * 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.concurrent
+
+import java.util.concurrent.atomic.AtomicReference
+import java.util.concurrent.locks.LockSupport
+
+import scala.util.control.{NonFatal, NoStackTrace}
+import scala.util.{Failure, Success, Try}
+import scala.concurrent.duration._
+import scala.collection.BuildFrom
+import scala.collection.mutable.{Builder, ArrayBuffer}
+import scala.reflect.ClassTag
+
+import scala.concurrent.ExecutionContext.parasitic
+
+/** A `Future` represents a value which may or may not be currently available,
+ * but will be available at some point, or an exception if that value could not be made available.
+ *
+ * Asynchronous computations are created by calling `Future.apply`, which yields instances of `Future`.
+ * Computations are executed using an `ExecutionContext`, which is usually supplied implicitly,
+ * and which is commonly backed by a thread pool.
+ *
+ * {{{
+ * import ExecutionContext.Implicits.global
+ * val s = "Hello"
+ * val f: Future[String] = Future {
+ * s + " future!"
+ * }
+ * f foreach {
+ * msg => println(msg)
+ * }
+ * }}}
+ *
+ * Note that the `global` context is convenient but restricted:
+ * "fatal" exceptions are reported only by printing a stack trace,
+ * and the underlying thread pool may be shared by a mix of jobs.
+ * For any nontrivial application, see the caveats explained at [[ExecutionContext]]
+ * and also the overview linked below, which explains
+ * [[https://docs.scala-lang.org/overviews/core/futures.html#exceptions exception handling]]
+ * in depth.
+ *
+ *
+ * @see [[https://docs.scala-lang.org/overviews/core/futures.html Futures and Promises]]
+ *
+ * @define multipleCallbacks
+ * Multiple callbacks may be registered; there is no guarantee that they will be
+ * executed in a particular order.
+ *
+ * @define caughtThrowables
+ * This future may contain a throwable object and this means that the future failed.
+ * Futures obtained through combinators have the same exception as the future they were obtained from.
+ * The following throwable objects are not contained in the future:
+ * - `Error` - fatal errors are not contained within futures
+ * - `InterruptedException` - not contained within futures
+ * - all `scala.util.control.ControlThrowable` except `NonLocalReturnControl` - not contained within futures
+ *
+ * Instead, the future is completed with an ExecutionException that has one of the exceptions above as its cause.
+ * If a future is failed with a `scala.runtime.NonLocalReturnControl`,
+ * it is completed with a value from that throwable instead.
+ *
+ * @define swallowsExceptions
+ * Since this method executes asynchronously and does not produce a return value,
+ * any non-fatal exceptions thrown will be reported to the `ExecutionContext`.
+ *
+ * @define nonDeterministic
+ * Note: using this method yields nondeterministic dataflow programs.
+ *
+ * @define forComprehensionExamples
+ * Example:
+ *
+ * {{{
+ * val f = Future { 5 }
+ * val g = Future { 3 }
+ * val h = for {
+ * x: Int <- f // returns Future(5)
+ * y: Int <- g // returns Future(3)
+ * } yield x + y
+ * }}}
+ *
+ * is translated to:
+ *
+ * {{{
+ * f flatMap { (x: Int) => g map { (y: Int) => x + y } }
+ * }}}
+ *
+ * @define callbackInContext
+ * The provided callback always runs in the provided implicit
+ *`ExecutionContext`, though there is no guarantee that the
+ * `execute()` method on the `ExecutionContext` will be called once
+ * per callback or that `execute()` will be called in the current
+ * thread. That is, the implementation may run multiple callbacks
+ * in a batch within a single `execute()` and it may run
+ * `execute()` either immediately or asynchronously.
+ * Completion of the Future must *happen-before* the invocation of the callback.
+ */
+trait Future[+T] extends Awaitable[T] {
+
+ /* Callbacks */
+
+ /** When this future is completed, either through an exception, or a value,
+ * apply the provided function.
+ *
+ * If the future has already been completed,
+ * this will either be applied immediately or be scheduled asynchronously.
+ *
+ * Note that the returned value of `f` will be discarded.
+ *
+ * $swallowsExceptions
+ * $multipleCallbacks
+ * $callbackInContext
+ *
+ * @tparam U only used to accept any return type of the given callback function
+ * @param f the function to be executed when this `Future` completes
+ * @group Callbacks
+ */
+ def onComplete[U](f: Try[T] => U)(implicit executor: ExecutionContext): Unit
+
+
+ /* Miscellaneous */
+
+ /** Returns whether the future had already been completed with
+ * a value or an exception.
+ *
+ * $nonDeterministic
+ *
+ * @return `true` if the future was completed, `false` otherwise
+ * @group Polling
+ */
+ def isCompleted: Boolean
+
+ /** The current value of this `Future`.
+ *
+ * $nonDeterministic
+ *
+ * If the future was not completed the returned value will be `None`.
+ * If the future was completed the value will be `Some(Success(t))`
+ * if it contained a valid result, or `Some(Failure(error))` if it contained
+ * an exception.
+ *
+ * @return `None` if the `Future` wasn't completed, `Some` if it was.
+ * @group Polling
+ */
+ def value: Option[Try[T]]
+
+
+ /* Projections */
+
+ /** The returned `Future` will be successfully completed with the `Throwable` of the original `Future`
+ * if the original `Future` fails.
+ *
+ * If the original `Future` is successful, the returned `Future` is failed with a `NoSuchElementException`.
+ *
+ * $caughtThrowables
+ *
+ * @return a failed projection of this `Future`.
+ * @group Transformations
+ */
+ def failed: Future[Throwable] = transform(Future.failedFun)(parasitic)
+
+
+ /* Monadic operations */
+
+ /** Asynchronously processes the value in the future once the value becomes available.
+ *
+ * WARNING: Will not be called if this future is never completed or if it is completed with a failure.
+ *
+ * $swallowsExceptions
+ *
+ * @tparam U only used to accept any return type of the given callback function
+ * @param f the function which will be executed if this `Future` completes with a result,
+ * the return value of `f` will be discarded.
+ * @group Callbacks
+ */
+ def foreach[U](f: T => U)(implicit executor: ExecutionContext): Unit = onComplete { _ foreach f }
+
+ /** Creates a new future by applying the 's' function to the successful result of
+ * this future, or the 'f' function to the failed result. If there is any non-fatal
+ * exception thrown when 's' or 'f' is applied, that exception will be propagated
+ * to the resulting future.
+ *
+ * @tparam S the type of the returned `Future`
+ * @param s function that transforms a successful result of the receiver into a successful result of the returned future
+ * @param f function that transforms a failure of the receiver into a failure of the returned future
+ * @return a `Future` that will be completed with the transformed value
+ * @group Transformations
+ */
+ def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] =
+ transform {
+ t =>
+ if (t.isInstanceOf[Success[T]]) t map s
+ else throw f(t.asInstanceOf[Failure[T]].exception) // will throw fatal errors!
+ }
+
+ /** Creates a new Future by applying the specified function to the result
+ * of this Future. If there is any non-fatal exception thrown when 'f'
+ * is applied then that exception will be propagated to the resulting future.
+ *
+ * @tparam S the type of the returned `Future`
+ * @param f function that transforms the result of this future
+ * @return a `Future` that will be completed with the transformed value
+ * @group Transformations
+ */
+ def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S]
+
+ /** Creates a new Future by applying the specified function, which produces a Future, to the result
+ * of this Future. If there is any non-fatal exception thrown when 'f'
+ * is applied then that exception will be propagated to the resulting future.
+ *
+ * @tparam S the type of the returned `Future`
+ * @param f function that transforms the result of this future
+ * @return a `Future` that will be completed with the transformed value
+ * @group Transformations
+ */
+ def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S]
+
+
+ /** Creates a new future by applying a function to the successful result of
+ * this future. If this future is completed with an exception then the new
+ * future will also contain this exception.
+ *
+ * Example:
+ *
+ * {{{
+ * val f = Future { "The future" }
+ * val g = f map { x: String => x + " is now!" }
+ * }}}
+ *
+ * Note that a for comprehension involving a `Future`
+ * may expand to include a call to `map` and or `flatMap`
+ * and `withFilter`. See [[scala.concurrent.Future#flatMap]] for an example of such a comprehension.
+ *
+ *
+ * @tparam S the type of the returned `Future`
+ * @param f the function which will be applied to the successful result of this `Future`
+ * @return a `Future` which will be completed with the result of the application of the function
+ * @group Transformations
+ */
+ def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = transform(_ map f)
+
+ /** Creates a new future by applying a function to the successful result of
+ * this future, and returns the result of the function as the new future.
+ * If this future is completed with an exception then the new future will
+ * also contain this exception.
+ *
+ * $forComprehensionExamples
+ *
+ * @tparam S the type of the returned `Future`
+ * @param f the function which will be applied to the successful result of this `Future`
+ * @return a `Future` which will be completed with the result of the application of the function
+ * @group Transformations
+ */
+ def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = transformWith {
+ t =>
+ if(t.isInstanceOf[Success[T]]) f(t.asInstanceOf[Success[T]].value)
+ else this.asInstanceOf[Future[S]] // Safe cast
+ }
+
+ /** Creates a new future with one level of nesting flattened, this method is equivalent
+ * to `flatMap(identity)`.
+ *
+ * @tparam S the type of the returned `Future`
+ * @group Transformations
+ */
+ def flatten[S](implicit ev: T <:< Future[S]): Future[S] = flatMap(ev)(parasitic)
+
+ /** Creates a new future by filtering the value of the current future with a predicate.
+ *
+ * If the current future contains a value which satisfies the predicate, the new future will also hold that value.
+ * Otherwise, the resulting future will fail with a `NoSuchElementException`.
+ *
+ * If the current future fails, then the resulting future also fails.
+ *
+ * Example:
+ * {{{
+ * val f = Future { 5 }
+ * val g = f filter { _ % 2 == 1 }
+ * val h = f filter { _ % 2 == 0 }
+ * g foreach println // Eventually prints 5
+ * Await.result(h, Duration.Zero) // throw a NoSuchElementException
+ * }}}
+ *
+ * @param p the predicate to apply to the successful result of this `Future`
+ * @return a `Future` which will hold the successful result of this `Future` if it matches the predicate or a `NoSuchElementException`
+ * @group Transformations
+ */
+ def filter(p: T => Boolean)(implicit executor: ExecutionContext): Future[T] =
+ transform {
+ t =>
+ if (t.isInstanceOf[Success[T]]) {
+ if (p(t.asInstanceOf[Success[T]].value)) t
+ else Future.filterFailure
+ } else t
+ }
+
+ /** Used by for-comprehensions.
+ * @group Transformations
+ */
+ final def withFilter(p: T => Boolean)(implicit executor: ExecutionContext): Future[T] = filter(p)(executor)
+
+ /** Creates a new future by mapping the value of the current future, if the given partial function is defined at that value.
+ *
+ * If the current future contains a value for which the partial function is defined, the new future will also hold that value.
+ * Otherwise, the resulting future will fail with a `NoSuchElementException`.
+ *
+ * If the current future fails, then the resulting future also fails.
+ *
+ * Example:
+ * {{{
+ * val f = Future { -5 }
+ * val g = f collect {
+ * case x if x < 0 => -x
+ * }
+ * val h = f collect {
+ * case x if x > 0 => x * 2
+ * }
+ * g foreach println // Eventually prints 5
+ * Await.result(h, Duration.Zero) // throw a NoSuchElementException
+ * }}}
+ *
+ * @tparam S the type of the returned `Future`
+ * @param pf the `PartialFunction` to apply to the successful result of this `Future`
+ * @return a `Future` holding the result of application of the `PartialFunction` or a `NoSuchElementException`
+ * @group Transformations
+ */
+ def collect[S](pf: PartialFunction[T, S])(implicit executor: ExecutionContext): Future[S] =
+ transform {
+ t =>
+ if (t.isInstanceOf[Success[T]])
+ Success(pf.applyOrElse(t.asInstanceOf[Success[T]].value, Future.collectFailed))
+ else t.asInstanceOf[Failure[S]]
+ }
+
+ /** Creates a new future that will handle any matching throwable that this
+ * future might contain. If there is no match, or if this future contains
+ * a valid result then the new future will contain the same.
+ *
+ * Example:
+ *
+ * {{{
+ * Future (6 / 0) recover { case e: ArithmeticException => 0 } // result: 0
+ * Future (6 / 0) recover { case e: NotFoundException => 0 } // result: exception
+ * Future (6 / 2) recover { case e: ArithmeticException => 0 } // result: 3
+ * }}}
+ *
+ * @tparam U the type of the returned `Future`
+ * @param pf the `PartialFunction` to apply if this `Future` fails
+ * @return a `Future` with the successful value of this `Future` or the result of the `PartialFunction`
+ * @group Transformations
+ */
+ def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] =
+ transform { _ recover pf }
+
+ /** Creates a new future that will handle any matching throwable that this
+ * future might contain by assigning it a value of another future.
+ *
+ * If there is no match, or if this future contains
+ * a valid result then the new future will contain the same result.
+ *
+ * Example:
+ *
+ * {{{
+ * val f = Future { Int.MaxValue }
+ * Future (6 / 0) recoverWith { case e: ArithmeticException => f } // result: Int.MaxValue
+ * }}}
+ *
+ * @tparam U the type of the returned `Future`
+ * @param pf the `PartialFunction` to apply if this `Future` fails
+ * @return a `Future` with the successful value of this `Future` or the outcome of the `Future` returned by the `PartialFunction`
+ * @group Transformations
+ */
+ def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] =
+ transformWith {
+ t =>
+ if (t.isInstanceOf[Failure[T]]) {
+ val result = pf.applyOrElse(t.asInstanceOf[Failure[T]].exception, Future.recoverWithFailed)
+ if (result ne Future.recoverWithFailedMarker) result
+ else this
+ } else this
+ }
+
+ /** Zips the values of `this` and `that` future, and creates
+ * a new future holding the tuple of their results.
+ *
+ * If either input future fails, the resulting future is failed with the same
+ * throwable, without waiting for the other input future to complete.
+ *
+ * If the application of `f` throws a non-fatal throwable, the resulting future
+ * is failed with that throwable.
+ *
+ * @tparam U the type of the other `Future`
+ * @param that the other `Future`
+ * @return a `Future` with the results of both futures or the failure of the first of them that failed
+ * @group Transformations
+ */
+ def zip[U](that: Future[U]): Future[(T, U)] =
+ zipWith(that)(Future.zipWithTuple2Fun)(parasitic)
+
+ /** Zips the values of `this` and `that` future using a function `f`,
+ * and creates a new future holding the result.
+ *
+ * If either input future fails, the resulting future is failed with the same
+ * throwable, without waiting for the other input future to complete.
+ *
+ * If the application of `f` throws a non-fatal throwable, the resulting future
+ * is failed with that throwable.
+ *
+ * @tparam U the type of the other `Future`
+ * @tparam R the type of the resulting `Future`
+ * @param that the other `Future`
+ * @param f the function to apply to the results of `this` and `that`
+ * @return a `Future` with the result of the application of `f` to the results of `this` and `that`
+ * @group Transformations
+ */
+ def zipWith[U, R](that: Future[U])(f: (T, U) => R)(implicit executor: ExecutionContext): Future[R] = {
+ // This is typically overriden by the implementation in DefaultPromise, which provides
+ // symmetric fail-fast behavior regardless of which future fails first.
+ //
+ // TODO: remove this implementation and make Future#zipWith abstract
+ // when we're next willing to make a binary incompatible change
+ flatMap(r1 => that.map(r2 => f(r1, r2)))(if (executor.isInstanceOf[BatchingExecutor]) executor else parasitic)
+ }
+
+ /** Creates a new future which holds the result of this future if it was completed successfully, or, if not,
+ * the result of the `that` future if `that` is completed successfully.
+ * If both futures are failed, the resulting future holds the throwable object of the first future.
+ *
+ * Using this method will not cause concurrent programs to become nondeterministic.
+ *
+ * Example:
+ * {{{
+ * val f = Future { throw new RuntimeException("failed") }
+ * val g = Future { 5 }
+ * val h = f fallbackTo g
+ * h foreach println // Eventually prints 5
+ * }}}
+ *
+ * @tparam U the type of the other `Future` and the resulting `Future`
+ * @param that the `Future` whose result we want to use if this `Future` fails.
+ * @return a `Future` with the successful result of this or that `Future` or the failure of this `Future` if both fail
+ * @group Transformations
+ */
+ def fallbackTo[U >: T](that: Future[U]): Future[U] =
+ if (this eq that) this
+ else {
+ implicit val ec = parasitic
+ transformWith {
+ t =>
+ if (t.isInstanceOf[Success[T]]) this
+ else that transform { tt => if (tt.isInstanceOf[Success[U]]) tt else t }
+ }
+ }
+
+ /** Creates a new `Future[S]` which is completed with this `Future`'s result if
+ * that conforms to `S`'s erased type or a `ClassCastException` otherwise.
+ *
+ * @tparam S the type of the returned `Future`
+ * @param tag the `ClassTag` which will be used to cast the result of this `Future`
+ * @return a `Future` holding the casted result of this `Future` or a `ClassCastException` otherwise
+ * @group Transformations
+ */
+ def mapTo[S](implicit tag: ClassTag[S]): Future[S] = {
+ implicit val ec = parasitic
+ val boxedClass = {
+ val c = tag.runtimeClass
+ if (c.isPrimitive) Future.toBoxed(c) else c
+ }
+ require(boxedClass ne null)
+ map(s => boxedClass.cast(s).asInstanceOf[S])
+ }
+
+ /** Applies the side-effecting function to the result of this future, and returns
+ * a new future with the result of this future.
+ *
+ * This method allows one to enforce that the callbacks are executed in a
+ * specified order.
+ *
+ * Note that if one of the chained `andThen` callbacks throws
+ * an exception, that exception is not propagated to the subsequent `andThen`
+ * callbacks. Instead, the subsequent `andThen` callbacks are given the original
+ * value of this future.
+ *
+ * The following example prints out `5`:
+ *
+ * {{{
+ * val f = Future { 5 }
+ * f andThen {
+ * case r => throw new RuntimeException("runtime exception")
+ * } andThen {
+ * case Failure(t) => println(t)
+ * case Success(v) => println(v)
+ * }
+ * }}}
+ *
+ * $swallowsExceptions
+ *
+ * @tparam U only used to accept any return type of the given `PartialFunction`
+ * @param pf a `PartialFunction` which will be conditionally applied to the outcome of this `Future`
+ * @return a `Future` which will be completed with the exact same outcome as this `Future` but after the `PartialFunction` has been executed.
+ * @group Callbacks
+ */
+ def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T] =
+ transform {
+ result =>
+ try pf.applyOrElse[Try[T], Any](result, Future.id[Try[T]])
+ catch { case t if NonFatal(t) => executor.reportFailure(t) }
+ // TODO: use `finally`?
+ result
+ }
+}
+
+
+
+/** Future companion object.
+ *
+ * @define nonDeterministic
+ * Note: using this method yields nondeterministic dataflow programs.
+ */
+object Future {
+
+ /**
+ * Utilities, hoisted functions, etc.
+ */
+
+ private[concurrent] final val toBoxed = Map[Class[_], Class[_]](
+ classOf[Boolean] -> classOf[java.lang.Boolean],
+ classOf[Byte] -> classOf[java.lang.Byte],
+ classOf[Char] -> classOf[java.lang.Character],
+ classOf[Short] -> classOf[java.lang.Short],
+ classOf[Int] -> classOf[java.lang.Integer],
+ classOf[Long] -> classOf[java.lang.Long],
+ classOf[Float] -> classOf[java.lang.Float],
+ classOf[Double] -> classOf[java.lang.Double],
+ classOf[Unit] -> classOf[scala.runtime.BoxedUnit]
+ )
+
+ private[this] final val _cachedId: AnyRef => AnyRef = Predef.identity _
+
+ private[concurrent] final def id[T]: T => T = _cachedId.asInstanceOf[T => T]
+
+ private[concurrent] final val collectFailed =
+ (t: Any) => throw new NoSuchElementException("Future.collect partial function is not defined at: " + t) with NoStackTrace
+
+ private[concurrent] final val filterFailure =
+ Failure[Nothing](new NoSuchElementException("Future.filter predicate is not satisfied") with NoStackTrace)
+
+ private[this] final val failedFailure =
+ Failure[Nothing](new NoSuchElementException("Future.failed not completed with a throwable.") with NoStackTrace)
+
+ private[concurrent] final val failedFailureFuture: Future[Nothing] =
+ scala.concurrent.Future.fromTry(failedFailure)
+
+ private[this] final val _failedFun: Try[Any] => Try[Throwable] =
+ v => if (v.isInstanceOf[Failure[Any]]) Success(v.asInstanceOf[Failure[Any]].exception) else failedFailure
+
+ private[concurrent] final def failedFun[T]: Try[T] => Try[Throwable] = _failedFun.asInstanceOf[Try[T] => Try[Throwable]]
+
+ private[concurrent] final val recoverWithFailedMarker: Future[Nothing] =
+ scala.concurrent.Future.failed(new Throwable with NoStackTrace)
+
+ private[concurrent] final val recoverWithFailed = (t: Throwable) => recoverWithFailedMarker
+
+ private[this] final val _zipWithTuple2: (Any, Any) => (Any, Any) = Tuple2.apply _
+ private[concurrent] final def zipWithTuple2Fun[T,U] = _zipWithTuple2.asInstanceOf[(T,U) => (T,U)]
+
+ private[this] final val _addToBuilderFun: (Builder[Any, Nothing], Any) => Builder[Any, Nothing] = (b: Builder[Any, Nothing], e: Any) => b += e
+ private[concurrent] final def addToBuilderFun[A, M] = _addToBuilderFun.asInstanceOf[Function2[Builder[A, M], A, Builder[A, M]]]
+
+ /** A Future which is never completed.
+ */
+ object never extends Future[Nothing] {
+
+ @throws[TimeoutException]
+ @throws[InterruptedException]
+ override final def ready(atMost: Duration)(implicit permit: CanAwait): this.type = {
+ import Duration.{Undefined, Inf, MinusInf}
+ atMost match {
+ case u if u eq Undefined => throw new IllegalArgumentException("cannot wait for Undefined period")
+ case `Inf` =>
+ while(!Thread.interrupted()) {
+ LockSupport.park(this)
+ }
+ throw new InterruptedException
+ case `MinusInf` => // Drop out
+ case f: FiniteDuration if f > Duration.Zero =>
+ var now = System.nanoTime()
+ val deadline = now + f.toNanos
+ while((deadline - now) > 0) {
+ LockSupport.parkNanos(this, deadline - now)
+ if (Thread.interrupted())
+ throw new InterruptedException
+ now = System.nanoTime()
+ }
+ // Done waiting, drop out
+ case _: FiniteDuration => // Drop out if 0 or less
+ case x: Duration.Infinite => throw new MatchError(x)
+ }
+ throw new TimeoutException(s"Future timed out after [$atMost]")
+ }
+
+ @throws[TimeoutException]
+ @throws[InterruptedException]
+ override final def result(atMost: Duration)(implicit permit: CanAwait): Nothing = {
+ ready(atMost)
+ throw new TimeoutException(s"Future timed out after [$atMost]")
+ }
+
+ override final def onComplete[U](f: Try[Nothing] => U)(implicit executor: ExecutionContext): Unit = ()
+ override final def isCompleted: Boolean = false
+ override final def value: Option[Try[Nothing]] = None
+ override final def failed: Future[Throwable] = this
+ override final def foreach[U](f: Nothing => U)(implicit executor: ExecutionContext): Unit = ()
+ override final def transform[S](s: Nothing => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] = this
+ override final def transform[S](f: Try[Nothing] => Try[S])(implicit executor: ExecutionContext): Future[S] = this
+ override final def transformWith[S](f: Try[Nothing] => Future[S])(implicit executor: ExecutionContext): Future[S] = this
+ override final def map[S](f: Nothing => S)(implicit executor: ExecutionContext): Future[S] = this
+ override final def flatMap[S](f: Nothing => Future[S])(implicit executor: ExecutionContext): Future[S] = this
+ override final def flatten[S](implicit ev: Nothing <:< Future[S]): Future[S] = this
+ override final def filter(p: Nothing => Boolean)(implicit executor: ExecutionContext): Future[Nothing] = this
+ override final def collect[S](pf: PartialFunction[Nothing, S])(implicit executor: ExecutionContext): Future[S] = this
+ override final def recover[U >: Nothing](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = this
+ override final def recoverWith[U >: Nothing](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = this
+ override final def zip[U](that: Future[U]): Future[(Nothing, U)] = this
+ override final def zipWith[U, R](that: Future[U])(f: (Nothing, U) => R)(implicit executor: ExecutionContext): Future[R] = this
+ override final def fallbackTo[U >: Nothing](that: Future[U]): Future[U] = this
+ override final def mapTo[S](implicit tag: ClassTag[S]): Future[S] = this
+ override final def andThen[U](pf: PartialFunction[Try[Nothing], U])(implicit executor: ExecutionContext): Future[Nothing] = this
+ override final def toString: String = "Future()"
+ }
+
+ /** A Future which is completed with the Unit value.
+ */
+ final val unit: Future[Unit] = fromTry(Success(()))
+
+ /** Creates an already completed Future with the specified exception.
+ *
+ * @tparam T the type of the value in the future
+ * @param exception the non-null instance of `Throwable`
+ * @return the newly created `Future` instance
+ */
+ final def failed[T](exception: Throwable): Future[T] = Promise.failed(exception).future
+
+ /** Creates an already completed Future with the specified result.
+ *
+ * @tparam T the type of the value in the future
+ * @param result the given successful value
+ * @return the newly created `Future` instance
+ */
+ final def successful[T](result: T): Future[T] = Promise.successful(result).future
+
+ /** Creates an already completed Future with the specified result or exception.
+ *
+ * @tparam T the type of the value in the `Future`
+ * @param result the result of the returned `Future` instance
+ * @return the newly created `Future` instance
+ */
+ final def fromTry[T](result: Try[T]): Future[T] = Promise.fromTry(result).future
+
+ /** Starts an asynchronous computation and returns a `Future` instance with the result of that computation.
+ *
+ * The following expressions are equivalent:
+ *
+ * {{{
+ * val f1 = Future(expr)
+ * val f2 = Future.unit.map(_ => expr)
+ * val f3 = Future.unit.transform(_ => Success(expr))
+ * }}}
+ *
+ * The result becomes available once the asynchronous computation is completed.
+ *
+ * @tparam T the type of the result
+ * @param body the asynchronous computation
+ * @param executor the execution context on which the future is run
+ * @return the `Future` holding the result of the computation
+ */
+ final def apply[T](body: => T)(implicit executor: ExecutionContext): Future[T] =
+ unit.map(_ => body)
+
+ /** Starts an asynchronous computation and returns a `Future` instance with the result of that computation once it completes.
+ *
+ * The following expressions are semantically equivalent:
+ *
+ * {{{
+ * val f1 = Future(expr).flatten
+ * val f2 = Future.delegate(expr)
+ * val f3 = Future.unit.flatMap(_ => expr)
+ * }}}
+ *
+ * The result becomes available once the resulting Future of the asynchronous computation is completed.
+ *
+ * @tparam T the type of the result
+ * @param body the asynchronous computation, returning a Future
+ * @param executor the execution context on which the `body` is evaluated in
+ * @return the `Future` holding the result of the computation
+ */
+ final def delegate[T](body: => Future[T])(implicit executor: ExecutionContext): Future[T] =
+ unit.flatMap(_ => body)
+
+ /** Simple version of `Future.traverse`. Asynchronously and non-blockingly transforms, in essence, a `IterableOnce[Future[A]]`
+ * into a `Future[IterableOnce[A]]`. Useful for reducing many `Future`s into a single `Future`.
+ *
+ * @tparam A the type of the value inside the Futures
+ * @tparam CC the type of the `IterableOnce` of Futures
+ * @tparam To the type of the resulting collection
+ * @param in the `IterableOnce` of Futures which will be sequenced
+ * @return the `Future` of the resulting collection
+ */
+ final def sequence[A, CC[X] <: IterableOnce[X], To](in: CC[Future[A]])(implicit bf: BuildFrom[CC[Future[A]], A, To], executor: ExecutionContext): Future[To] =
+ in.iterator.foldLeft(successful(bf.newBuilder(in))) {
+ (fr, fa) => fr.zipWith(fa)(Future.addToBuilderFun)
+ }.map(_.result())(if (executor.isInstanceOf[BatchingExecutor]) executor else parasitic)
+
+ /** Asynchronously and non-blockingly returns a new `Future` to the result of the first future
+ * in the list that is completed. This means no matter if it is completed as a success or as a failure.
+ *
+ * @tparam T the type of the value in the future
+ * @param futures the `IterableOnce` of Futures in which to find the first completed
+ * @return the `Future` holding the result of the future that is first to be completed
+ */
+ final def firstCompletedOf[T](futures: IterableOnce[Future[T]])(implicit executor: ExecutionContext): Future[T] = {
+ val i = futures.iterator
+ if (!i.hasNext) Future.never
+ else {
+ val p = Promise[T]()
+ val firstCompleteHandler = new AtomicReference[Promise[T]](p) with (Try[T] => Unit) {
+ override final def apply(v1: Try[T]): Unit = {
+ val r = getAndSet(null)
+ if (r ne null)
+ r tryComplete v1 // tryComplete is likely to be cheaper than complete
+ }
+ }
+ while(i.hasNext && firstCompleteHandler.get != null) // exit early if possible
+ i.next().onComplete(firstCompleteHandler)
+ p.future
+ }
+ }
+
+ /** Asynchronously and non-blockingly returns a `Future` that will hold the optional result
+ * of the first `Future` with a result that matches the predicate, failed `Future`s will be ignored.
+ *
+ * @tparam T the type of the value in the future
+ * @param futures the `scala.collection.immutable.Iterable` of Futures to search
+ * @param p the predicate which indicates if it's a match
+ * @return the `Future` holding the optional result of the search
+ */
+ final def find[T](futures: scala.collection.immutable.Iterable[Future[T]])(p: T => Boolean)(implicit executor: ExecutionContext): Future[Option[T]] = {
+ def searchNext(i: Iterator[Future[T]]): Future[Option[T]] =
+ if (!i.hasNext) successful(None)
+ else i.next().transformWith {
+ case Success(r) if p(r) => successful(Some(r))
+ case _ => searchNext(i)
+ }
+
+ searchNext(futures.iterator)
+ }
+
+ /** A non-blocking, asynchronous left fold over the specified futures,
+ * with the start value of the given zero.
+ * The fold is performed asynchronously in left-to-right order as the futures become completed.
+ * The result will be the first failure of any of the futures, or any failure in the actual fold,
+ * or the result of the fold.
+ *
+ * Example:
+ * {{{
+ * val futureSum = Future.foldLeft(futures)(0)(_ + _)
+ * }}}
+ *
+ * @tparam T the type of the value of the input Futures
+ * @tparam R the type of the value of the returned `Future`
+ * @param futures the `scala.collection.immutable.Iterable` of Futures to be folded
+ * @param zero the start value of the fold
+ * @param op the fold operation to be applied to the zero and futures
+ * @return the `Future` holding the result of the fold
+ */
+ final def foldLeft[T, R](futures: scala.collection.immutable.Iterable[Future[T]])(zero: R)(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] =
+ foldNext(futures.iterator, zero, op)
+
+ private[this] final def foldNext[T, R](i: Iterator[Future[T]], prevValue: R, op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] =
+ if (!i.hasNext) successful(prevValue)
+ else i.next().flatMap { value => foldNext(i, op(prevValue, value), op) }
+
+ /** A non-blocking, asynchronous fold over the specified futures, with the start value of the given zero.
+ * The fold is performed on the thread where the last future is completed,
+ * the result will be the first failure of any of the futures, or any failure in the actual fold,
+ * or the result of the fold.
+ *
+ * Example:
+ * {{{
+ * val futureSum = Future.fold(futures)(0)(_ + _)
+ * }}}
+ *
+ * @tparam T the type of the value of the input Futures
+ * @tparam R the type of the value of the returned `Future`
+ * @param futures the `IterableOnce` of Futures to be folded
+ * @param zero the start value of the fold
+ * @param op the fold operation to be applied to the zero and futures
+ * @return the `Future` holding the result of the fold
+ */
+ @deprecated("use Future.foldLeft instead", "2.12.0")
+ // not removed in 2.13, to facilitate 2.11/2.12/2.13 cross-building; remove further down the line (see scala/scala#6319)
+ def fold[T, R](futures: IterableOnce[Future[T]])(zero: R)(@deprecatedName("foldFun") op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] =
+ if (futures.isEmpty) successful(zero)
+ else sequence(futures)(ArrayBuffer, executor).map(_.foldLeft(zero)(op))
+
+ /** Initiates a non-blocking, asynchronous, fold over the supplied futures
+ * where the fold-zero is the result value of the first `Future` in the collection.
+ *
+ * Example:
+ * {{{
+ * val futureSum = Future.reduce(futures)(_ + _)
+ * }}}
+ * @tparam T the type of the value of the input Futures
+ * @tparam R the type of the value of the returned `Future`
+ * @param futures the `IterableOnce` of Futures to be reduced
+ * @param op the reduce operation which is applied to the results of the futures
+ * @return the `Future` holding the result of the reduce
+ */
+ @deprecated("use Future.reduceLeft instead", "2.12.0")
+ // not removed in 2.13, to facilitate 2.11/2.12/2.13 cross-building; remove further down the line (see scala/scala#6319)
+ final def reduce[T, R >: T](futures: IterableOnce[Future[T]])(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] =
+ if (futures.isEmpty) failed(new NoSuchElementException("reduce attempted on empty collection"))
+ else sequence(futures)(ArrayBuffer, executor).map(_ reduceLeft op)
+
+ /** Initiates a non-blocking, asynchronous, left reduction over the supplied futures
+ * where the zero is the result value of the first `Future`.
+ *
+ * Example:
+ * {{{
+ * val futureSum = Future.reduceLeft(futures)(_ + _)
+ * }}}
+ * @tparam T the type of the value of the input Futures
+ * @tparam R the type of the value of the returned `Future`
+ * @param futures the `scala.collection.immutable.Iterable` of Futures to be reduced
+ * @param op the reduce operation which is applied to the results of the futures
+ * @return the `Future` holding the result of the reduce
+ */
+ final def reduceLeft[T, R >: T](futures: scala.collection.immutable.Iterable[Future[T]])(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = {
+ val i = futures.iterator
+ if (!i.hasNext) failed(new NoSuchElementException("reduceLeft attempted on empty collection"))
+ else i.next() flatMap { v => foldNext(i, v, op) }
+ }
+
+ /** Asynchronously and non-blockingly transforms a `IterableOnce[A]` into a `Future[IterableOnce[B]]`
+ * using the provided function `A => Future[B]`.
+ * This is useful for performing a parallel map. For example, to apply a function to all items of a list
+ * in parallel:
+ *
+ * {{{
+ * val myFutureList = Future.traverse(myList)(x => Future(myFunc(x)))
+ * }}}
+ * @tparam A the type of the value inside the Futures in the collection
+ * @tparam B the type of the value of the returned `Future`
+ * @tparam M the type of the collection of Futures
+ * @param in the collection to be mapped over with the provided function to produce a collection of Futures that is then sequenced into a Future collection
+ * @param fn the function to be mapped over the collection to produce a collection of Futures
+ * @return the `Future` of the collection of results
+ */
+ final def traverse[A, B, M[X] <: IterableOnce[X]](in: M[A])(fn: A => Future[B])(implicit bf: BuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] =
+ in.iterator.foldLeft(successful(bf.newBuilder(in))) {
+ (fr, a) => fr.zipWith(fn(a))(Future.addToBuilderFun)
+ }.map(_.result())(if (executor.isInstanceOf[BatchingExecutor]) executor else parasitic)
+}
+
+@deprecated("Superseded by `scala.concurrent.Batchable`", "2.13.0")
+trait OnCompleteRunnable extends Batchable {
+ self: Runnable =>
+}
+
diff --git a/library/src/scala/concurrent/JavaConversions.scala b/library/src/scala/concurrent/JavaConversions.scala
new file mode 100644
index 000000000000..3250e656941a
--- /dev/null
+++ b/library/src/scala/concurrent/JavaConversions.scala
@@ -0,0 +1,38 @@
+/*
+ * 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.concurrent
+
+import java.util.concurrent.{ExecutorService, Executor}
+import scala.language.implicitConversions
+
+/** The `JavaConversions` object provides implicit conversions supporting
+ * interoperability between Scala and Java concurrency classes.
+ */
+@deprecated("Use the factory methods in `ExecutionContext` instead", "2.13.0")
+object JavaConversions {
+
+ /**
+ * Creates a new `ExecutionContext` which uses the provided `ExecutorService`.
+ */
+ @deprecated("Use `ExecutionContext.fromExecutorService` instead", "2.13.0")
+ implicit def asExecutionContext(exec: ExecutorService): ExecutionContextExecutorService =
+ ExecutionContext.fromExecutorService(exec)
+
+ /**
+ * Creates a new `ExecutionContext` which uses the provided `Executor`.
+ */
+ @deprecated("Use `ExecutionContext.fromExecutor` instead", "2.13.0")
+ implicit def asExecutionContext(exec: Executor): ExecutionContextExecutor =
+ ExecutionContext.fromExecutor(exec)
+
+}
diff --git a/library/src/scala/concurrent/Promise.scala b/library/src/scala/concurrent/Promise.scala
new file mode 100644
index 000000000000..cf3f23543c5a
--- /dev/null
+++ b/library/src/scala/concurrent/Promise.scala
@@ -0,0 +1,148 @@
+/*
+ * 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.concurrent
+
+import scala.util.{ Try, Success, Failure }
+
+/** Promise is an object which can be completed with a value or failed
+ * with an exception.
+ *
+ * A promise should always eventually be completed, whether for success or failure,
+ * in order to avoid unintended resource retention for any associated Futures'
+ * callbacks or transformations.
+ *
+ * @define promiseCompletion
+ * If the promise has already been fulfilled, failed or has timed out,
+ * calling this method will throw an IllegalStateException.
+ *
+ * @define allowedThrowables
+ * If the throwable used to fail this promise is an error, a control exception
+ * or an interrupted exception, it will be wrapped as a cause within an
+ * `ExecutionException` which will fail the promise.
+ *
+ * @define nonDeterministic
+ * Note: Using this method may result in non-deterministic concurrent programs.
+ */
+trait Promise[T] {
+ /** Future containing the value of this promise.
+ */
+ def future: Future[T]
+
+ /** Returns whether the promise has already been completed with
+ * a value or an exception.
+ *
+ * $nonDeterministic
+ *
+ * @return `true` if the promise is already completed, `false` otherwise
+ */
+ def isCompleted: Boolean
+
+ /** Completes the promise with either an exception or a value.
+ *
+ * @param result Either the value or the exception to complete the promise with.
+ *
+ * $promiseCompletion
+ */
+ def complete(result: Try[T]): this.type =
+ if (tryComplete(result)) this else throw new IllegalStateException("Promise already completed.")
+
+ /** Tries to complete the promise with either a value or the exception.
+ *
+ * $nonDeterministic
+ *
+ * @return If the promise has already been completed returns `false`, or `true` otherwise.
+ */
+ def tryComplete(result: Try[T]): Boolean
+
+ /** Completes this promise with the specified future, once that future is completed.
+ *
+ * @return This promise
+ */
+ def completeWith(other: Future[T]): this.type = {
+ if (other ne this.future) // this tryCompleteWith this doesn't make much sense
+ other.onComplete(this tryComplete _)(ExecutionContext.parasitic)
+
+ this
+ }
+
+ /** Attempts to complete this promise with the specified future, once that future is completed.
+ *
+ * @return This promise
+ */
+ @deprecated("Since this method is semantically equivalent to `completeWith`, use that instead.", "2.13.0")
+ final def tryCompleteWith(other: Future[T]): this.type = completeWith(other)
+
+ /** Completes the promise with a value.
+ *
+ * @param value The value to complete the promise with.
+ *
+ * $promiseCompletion
+ */
+ def success(value: T): this.type = complete(Success(value))
+
+ /** Tries to complete the promise with a value.
+ *
+ * $nonDeterministic
+ *
+ * @return If the promise has already been completed returns `false`, or `true` otherwise.
+ */
+ def trySuccess(value: T): Boolean = tryComplete(Success(value))
+
+ /** Completes the promise with an exception.
+ *
+ * @param cause The throwable to complete the promise with.
+ *
+ * $allowedThrowables
+ *
+ * $promiseCompletion
+ */
+ def failure(cause: Throwable): this.type = complete(Failure(cause))
+
+ /** Tries to complete the promise with an exception.
+ *
+ * $nonDeterministic
+ *
+ * @return If the promise has already been completed returns `false`, or `true` otherwise.
+ */
+ def tryFailure(cause: Throwable): Boolean = tryComplete(Failure(cause))
+}
+
+object Promise {
+ /** Creates a promise object which can be completed with a value.
+ *
+ * @tparam T the type of the value in the promise
+ * @return the newly created `Promise` instance
+ */
+ final def apply[T](): Promise[T] = new impl.Promise.DefaultPromise[T]()
+
+ /** Creates an already completed Promise with the specified exception.
+ *
+ * @tparam T the type of the value in the promise
+ * @return the newly created `Promise` instance
+ */
+ final def failed[T](exception: Throwable): Promise[T] = fromTry(Failure(exception))
+
+ /** Creates an already completed Promise with the specified result.
+ *
+ * @tparam T the type of the value in the promise
+ * @return the newly created `Promise` instance
+ */
+ final def successful[T](result: T): Promise[T] = fromTry(Success(result))
+
+ /** Creates an already completed Promise with the specified result or exception.
+ *
+ * @tparam T the type of the value in the promise
+ * @return the newly created `Promise` instance
+ */
+ final def fromTry[T](result: Try[T]): Promise[T] = new impl.Promise.DefaultPromise[T](result)
+}
diff --git a/library/src/scala/concurrent/SyncChannel.scala b/library/src/scala/concurrent/SyncChannel.scala
new file mode 100644
index 000000000000..8792524524c3
--- /dev/null
+++ b/library/src/scala/concurrent/SyncChannel.scala
@@ -0,0 +1,77 @@
+/*
+ * 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.concurrent
+
+/** A `SyncChannel` allows one to exchange data synchronously between
+ * a reader and a writer thread. The writer thread is blocked until the
+ * data to be written has been read by a corresponding reader thread.
+ */
+@deprecated("Use `java.util.concurrent.Exchanger` instead.", since = "2.13.0")
+class SyncChannel[A] {
+
+ private final val Signal = ()
+ private type Signal = Unit
+ private[this] var pendingWrites = List[(A, SyncVar[Signal])]()
+ private[this] var pendingReads = List[SyncVar[A]]()
+
+ def write(data: A): Unit = {
+ // create write request
+ val writeReq = new SyncVar[Signal]
+
+ this.synchronized {
+ // check whether there is a reader waiting
+ if (pendingReads.nonEmpty) {
+ val readReq = pendingReads.head
+ pendingReads = pendingReads.tail
+
+ // let reader continue
+ readReq.put(data)
+
+ // resolve write request
+ writeReq.put(Signal)
+ }
+ else {
+ // enqueue write request
+ pendingWrites = pendingWrites ::: List((data, writeReq))
+ }
+ }
+
+ writeReq.get
+ }
+
+ def read: A = {
+ // create read request
+ val readReq = new SyncVar[A]
+
+ this.synchronized {
+ // check whether there is a writer waiting
+ if (pendingWrites.nonEmpty) {
+ // read data
+ val (data, writeReq) = pendingWrites.head
+ pendingWrites = pendingWrites.tail
+
+ // let writer continue
+ writeReq.put(Signal)
+
+ // resolve read request
+ readReq.put(data)
+ }
+ else {
+ // enqueue read request
+ pendingReads = pendingReads ::: List(readReq)
+ }
+ }
+
+ readReq.get
+ }
+}
diff --git a/library/src/scala/concurrent/SyncVar.scala b/library/src/scala/concurrent/SyncVar.scala
new file mode 100644
index 000000000000..66c5fd1bb81d
--- /dev/null
+++ b/library/src/scala/concurrent/SyncVar.scala
@@ -0,0 +1,122 @@
+/*
+ * 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.concurrent
+
+import java.util.concurrent.TimeUnit
+
+/** A class to provide safe concurrent access to a mutable cell.
+ * All methods are synchronized.
+ *
+ * @tparam A type of the contained value
+ */
+@deprecated("Use `java.util.concurrent.LinkedBlockingQueue with capacity 1` instead.", since = "2.13.0")
+class SyncVar[A] {
+ private[this] var isDefined: Boolean = false
+ private[this] var value: A = _
+
+ /**
+ * Wait for this SyncVar to become defined and then get
+ * the stored value without modifying it.
+ *
+ * @return value that is held in this container
+ */
+ def get: A = synchronized {
+ while (!isDefined) wait()
+ value
+ }
+
+ /** Waits `timeout` millis. If `timeout <= 0` just returns 0.
+ * It never returns negative results.
+ */
+ private def waitMeasuringElapsed(timeout: Long): Long = if (timeout <= 0) 0 else {
+ val start = System.nanoTime()
+ wait(timeout)
+ val elapsed = System.nanoTime() - start
+ // nanoTime should be monotonic, but it's not possible to rely on that.
+ // See https://bugs.java.com/view_bug.do?bug_id=6458294
+ if (elapsed < 0) 0 else TimeUnit.NANOSECONDS.toMillis(elapsed)
+ }
+
+ /** Wait at least `timeout` milliseconds (possibly more) for this `SyncVar`
+ * to become defined and then get its value.
+ *
+ * @param timeout time in milliseconds to wait
+ * @return `None` if variable is undefined after `timeout`, `Some(value)` otherwise
+ */
+ def get(timeout: Long): Option[A] = synchronized {
+ /* Defending against the system clock going backward
+ * by counting time elapsed directly. Loop required
+ * to deal with spurious wakeups.
+ */
+ var rest = timeout
+ while (!isDefined && rest > 0) {
+ val elapsed = waitMeasuringElapsed(rest)
+ rest -= elapsed
+ }
+ if (isDefined) Some(value) else None
+ }
+
+ /**
+ * Wait for this SyncVar to become defined and then get
+ * the stored value, unsetting it as a side effect.
+ *
+ * @return value that was held in this container
+ */
+ def take(): A = synchronized {
+ try get
+ finally unsetVal()
+ }
+
+ /** Wait at least `timeout` milliseconds (possibly more) for this `SyncVar`
+ * to become defined and then get the stored value, unsetting it
+ * as a side effect.
+ *
+ * @param timeout the amount of milliseconds to wait
+ * @return the value or a throws an exception if the timeout occurs
+ * @throws NoSuchElementException on timeout
+ */
+ def take(timeout: Long): A = synchronized {
+ try get(timeout).get
+ finally unsetVal()
+ }
+
+ /** Place a value in the SyncVar. If the SyncVar already has a stored value,
+ * wait until another thread takes it. */
+ def put(x: A): Unit = synchronized {
+ while (isDefined) wait()
+ setVal(x)
+ }
+
+ /** Check whether a value is stored in the synchronized variable. */
+ def isSet: Boolean = synchronized {
+ isDefined
+ }
+
+ // `setVal` exists so as to retroactively deprecate `set` without
+ // deprecation warnings where we use `set` internally. The
+ // implementation of `set` was moved to `setVal` to achieve this
+ private def setVal(x: A): Unit = synchronized {
+ isDefined = true
+ value = x
+ notifyAll()
+ }
+
+ // `unsetVal` exists so as to retroactively deprecate `unset` without
+ // deprecation warnings where we use `unset` internally. The
+ // implementation of `unset` was moved to `unsetVal` to achieve this
+ private def unsetVal(): Unit = synchronized {
+ isDefined = false
+ value = null.asInstanceOf[A]
+ notifyAll()
+ }
+}
diff --git a/library/src/scala/concurrent/duration/Deadline.scala b/library/src/scala/concurrent/duration/Deadline.scala
new file mode 100644
index 000000000000..353d0f30fff8
--- /dev/null
+++ b/library/src/scala/concurrent/duration/Deadline.scala
@@ -0,0 +1,85 @@
+/*
+ * 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.concurrent.duration
+
+/**
+ * This class stores a deadline, as obtained via `Deadline.now` or the
+ * duration DSL:
+ *
+ * {{{
+ * import scala.concurrent.duration._
+ * 3.seconds.fromNow
+ * }}}
+ *
+ * Its main purpose is to manage repeated attempts to achieve something (like
+ * awaiting a condition) by offering the methods `hasTimeLeft` and `timeLeft`. All
+ * durations are measured according to `System.nanoTime`; this
+ * does not take into account changes to the system clock (such as leap
+ * seconds).
+ */
+case class Deadline private (time: FiniteDuration) extends Ordered[Deadline] {
+ /**
+ * Return a deadline advanced (i.e., moved into the future) by the given duration.
+ */
+ def +(other: FiniteDuration): Deadline = copy(time = time + other)
+ /**
+ * Return a deadline moved backwards (i.e., towards the past) by the given duration.
+ */
+ def -(other: FiniteDuration): Deadline = copy(time = time - other)
+ /**
+ * Calculate time difference between this and the other deadline, where the result is directed (i.e., may be negative).
+ */
+ def -(other: Deadline): FiniteDuration = time - other.time
+ /**
+ * Calculate time difference between this duration and now; the result is negative if the deadline has passed.
+ *
+ * '''''Note that on some systems this operation is costly because it entails a system call.'''''
+ * Check `System.nanoTime` for your platform.
+ */
+ def timeLeft: FiniteDuration = this - Deadline.now
+ /**
+ * Determine whether the deadline still lies in the future at the point where this method is called.
+ *
+ * '''''Note that on some systems this operation is costly because it entails a system call.'''''
+ * Check `System.nanoTime` for your platform.
+ */
+ def hasTimeLeft(): Boolean = !isOverdue()
+ /**
+ * Determine whether the deadline lies in the past at the point where this method is called.
+ *
+ * '''''Note that on some systems this operation is costly because it entails a system call.'''''
+ * Check `System.nanoTime` for your platform.
+ */
+ def isOverdue(): Boolean = (time.toNanos - System.nanoTime()) < 0
+ /**
+ * The natural ordering for deadline is determined by the natural order of the underlying (finite) duration.
+ */
+ def compare(other: Deadline): Int = time compare other.time
+}
+
+object Deadline {
+ /**
+ * Construct a deadline due exactly at the point where this method is called. Useful for then
+ * advancing it to obtain a future deadline, or for sampling the current time exactly once and
+ * then comparing it to multiple deadlines (using subtraction).
+ */
+ def now: Deadline = Deadline(Duration(System.nanoTime, NANOSECONDS))
+
+ /**
+ * The natural ordering for deadline is determined by the natural order of the underlying (finite) duration.
+ */
+ implicit object DeadlineIsOrdered extends Ordering[Deadline] {
+ def compare(a: Deadline, b: Deadline): Int = a compare b
+ }
+
+}
diff --git a/library/src/scala/concurrent/duration/Duration.scala b/library/src/scala/concurrent/duration/Duration.scala
new file mode 100644
index 000000000000..1312bb12d1d5
--- /dev/null
+++ b/library/src/scala/concurrent/duration/Duration.scala
@@ -0,0 +1,742 @@
+/*
+ * 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.concurrent.duration
+
+import java.lang.{ Double => JDouble }
+import scala.collection.StringParsers
+
+object Duration {
+
+ /**
+ * Construct a Duration from the given length and unit. Observe that nanosecond precision may be lost if
+ *
+ * - the unit is NANOSECONDS
+ * - and the length has an absolute value greater than `2^53`
+ *
+ * Infinite inputs (and NaN) are converted into [[Duration.Inf]], [[Duration.MinusInf]] and [[Duration.Undefined]], respectively.
+ *
+ * @throws IllegalArgumentException if the length was finite but the resulting duration cannot be expressed as a [[FiniteDuration]]
+ */
+ def apply(length: Double, unit: TimeUnit): Duration = fromNanos(unit.toNanos(1) * length)
+
+ /**
+ * Construct a finite duration from the given length and time unit. The unit given is retained
+ * throughout calculations as long as possible, so that it can be retrieved later.
+ */
+ def apply(length: Long, unit: TimeUnit): FiniteDuration = new FiniteDuration(length, unit)
+
+ /**
+ * Construct a finite duration from the given length and time unit, where the latter is
+ * looked up in a list of string representation. Valid choices are:
+ *
+ * `d, day, h, hr, hour, m, min, minute, s, sec, second, ms, milli, millisecond, µs, micro, microsecond, ns, nano, nanosecond`
+ * and their pluralized forms (for every but the first mentioned form of each unit, i.e. no "ds", but "days").
+ */
+ def apply(length: Long, unit: String): FiniteDuration = new FiniteDuration(length, Duration.timeUnit(unit))
+
+ // Double stores 52 bits mantissa, but there is an implied '1' in front, making the limit 2^53
+ // private[this] final val maxPreciseDouble = 9007199254740992d // not used after https://github.com/scala/scala/pull/9233
+
+ /**
+ * Parse String into Duration. Format is `""`, where
+ * whitespace is allowed before, between and after the parts. Infinities are
+ * designated by `"Inf"`, `"PlusInf"`, `"+Inf"`, `"Duration.Inf"` and `"-Inf"`, `"MinusInf"` or `"Duration.MinusInf"`.
+ * Undefined is designated by `"Duration.Undefined"`.
+ *
+ * @throws NumberFormatException if format is not parsable
+ */
+ def apply(s: String): Duration = {
+ val s1: String = s filterNot (_.isWhitespace)
+ s1 match {
+ case "Inf" | "PlusInf" | "+Inf" | "Duration.Inf" => Inf
+ case "MinusInf" | "-Inf" | "Duration.MinusInf" => MinusInf
+ case "Duration.Undefined" => Undefined
+ case _ =>
+ val unitName = s1.reverse.takeWhile(_.isLetter).reverse
+ timeUnit get unitName match {
+ case Some(unit) =>
+ val valueStr = s1 dropRight unitName.length
+ StringParsers.parseLong(valueStr).map(Duration(_, unit))
+ .getOrElse(Duration(JDouble.parseDouble(valueStr), unit))
+ case _ => throw new NumberFormatException("format error " + s)
+ }
+ }
+ }
+
+ // "ms milli millisecond" -> List("ms", "milli", "millis", "millisecond", "milliseconds")
+ private[this] def words(s: String) = (s.trim split "\\s+").toList
+ private[this] def expandLabels(labels: String): List[String] = {
+ val hd :: rest = words(labels): @unchecked
+ hd :: rest.flatMap(s => List(s, s + "s"))
+ }
+ private[this] val timeUnitLabels = List(
+ DAYS -> "d day",
+ HOURS -> "h hr hour",
+ MINUTES -> "m min minute",
+ SECONDS -> "s sec second",
+ MILLISECONDS -> "ms milli millisecond",
+ MICROSECONDS -> "µs micro microsecond",
+ NANOSECONDS -> "ns nano nanosecond"
+ )
+
+ // TimeUnit => standard label
+ protected[duration] val timeUnitName: Map[TimeUnit, String] =
+ timeUnitLabels.toMap.view.mapValues(s => words(s).last).toMap
+
+ // Label => TimeUnit
+ protected[duration] val timeUnit: Map[String, TimeUnit] =
+ timeUnitLabels.flatMap{ case (unit, names) => expandLabels(names) map (_ -> unit) }.toMap
+
+ /**
+ * Extract length and time unit out of a string, where the format must match the description for [[Duration$.apply(s:String)* apply(String)]].
+ * The extractor will not match for malformed strings or non-finite durations.
+ */
+ def unapply(s: String): Option[(Long, TimeUnit)] =
+ ( try Some(apply(s)) catch { case _: RuntimeException => None } ) flatMap unapply
+
+ /**
+ * Extract length and time unit out of a duration, if it is finite.
+ */
+ def unapply(d: Duration): Option[(Long, TimeUnit)] =
+ if (d.isFinite) Some((d.length, d.unit)) else None
+
+ /**
+ * Construct a possibly infinite or undefined Duration from the given number of nanoseconds.
+ *
+ * - `Double.PositiveInfinity` is mapped to [[Duration.Inf]]
+ * - `Double.NegativeInfinity` is mapped to [[Duration.MinusInf]]
+ * - `Double.NaN` is mapped to [[Duration.Undefined]]
+ * - `-0d` is mapped to [[Duration.Zero]] (exactly like `0d`)
+ *
+ * The semantics of the resulting Duration objects matches the semantics of their Double
+ * counterparts with respect to arithmetic operations.
+ *
+ * @throws IllegalArgumentException if the length was finite but the resulting duration cannot be expressed as a [[FiniteDuration]]
+ */
+ def fromNanos(nanos: Double): Duration = {
+ if (nanos.isInfinite)
+ if (nanos > 0) Inf else MinusInf
+ else if (JDouble.isNaN(nanos))
+ Undefined
+ else if (nanos > Long.MaxValue || nanos < Long.MinValue)
+ throw new IllegalArgumentException("trying to construct too large duration with " + nanos + "ns")
+ else
+ fromNanos(nanos.round)
+ }
+
+ private[this] final val ns_per_µs = 1000L
+ private[this] final val ns_per_ms = ns_per_µs * 1000
+ private[this] final val ns_per_s = ns_per_ms * 1000
+ private[this] final val ns_per_min = ns_per_s * 60
+ private[this] final val ns_per_h = ns_per_min * 60
+ private[this] final val ns_per_d = ns_per_h * 24
+
+ /**
+ * Construct a finite duration from the given number of nanoseconds. The
+ * result will have the coarsest possible time unit which can exactly express
+ * this duration.
+ *
+ * @throws IllegalArgumentException for `Long.MinValue` since that would lead to inconsistent behavior afterwards (cannot be negated)
+ */
+ def fromNanos(nanos: Long): FiniteDuration = {
+ if (nanos % ns_per_d == 0) Duration(nanos / ns_per_d , DAYS)
+ else if (nanos % ns_per_h == 0) Duration(nanos / ns_per_h , HOURS)
+ else if (nanos % ns_per_min == 0) Duration(nanos / ns_per_min, MINUTES)
+ else if (nanos % ns_per_s == 0) Duration(nanos / ns_per_s , SECONDS)
+ else if (nanos % ns_per_ms == 0) Duration(nanos / ns_per_ms , MILLISECONDS)
+ else if (nanos % ns_per_µs == 0) Duration(nanos / ns_per_µs , MICROSECONDS)
+ else Duration(nanos, NANOSECONDS)
+ }
+
+ /**
+ * Preconstructed value of `0.days`.
+ */
+ // unit as coarse as possible to keep (_ + Zero) sane unit-wise
+ val Zero: FiniteDuration = new FiniteDuration(0, DAYS)
+
+ /**
+ * The Undefined value corresponds closely to Double.NaN:
+ *
+ * - it is the result of otherwise invalid operations
+ * - it does not equal itself (according to `equals()`)
+ * - it compares greater than any other Duration apart from itself (for which `compare` returns 0)
+ *
+ * The particular comparison semantics mirror those of Double.NaN.
+ *
+ * '''''Use [[eq]] when checking an input of a method against this value.'''''
+ */
+ val Undefined: Infinite = new Infinite {
+ override def toString = "Duration.Undefined"
+ override def equals(other: Any): Boolean = false
+ override def +(other: Duration): Duration = this
+ override def -(other: Duration): Duration = this
+ override def *(factor: Double): Duration = this
+ override def /(factor: Double): Duration = this
+ override def /(other: Duration): Double = Double.NaN
+ def compare(other: Duration): Int = if (other eq this) 0 else 1
+ def unary_- : Duration = this
+ def toUnit(unit: TimeUnit): Double = Double.NaN
+ private def readResolve(): AnyRef = Undefined // Instructs deserialization to use this same instance
+ }
+
+ sealed abstract class Infinite extends Duration {
+ def +(other: Duration): Duration = other match {
+ case x if x eq Undefined => Undefined
+ case x: Infinite if x ne this => Undefined
+ case _ => this
+ }
+ def -(other: Duration): Duration = other match {
+ case x if x eq Undefined => Undefined
+ case x: Infinite if x eq this => Undefined
+ case _ => this
+ }
+
+ def *(factor: Double): Duration =
+ if (factor == 0d || JDouble.isNaN(factor)) Undefined
+ else if (factor < 0d) -this
+ else this
+ def /(divisor: Double): Duration =
+ if (JDouble.isNaN(divisor) || divisor.isInfinite) Undefined
+ else if ((divisor compare 0d) < 0) -this
+ else this
+ def /(divisor: Duration): Double = divisor match {
+ case _: Infinite => Double.NaN
+ case x => Double.PositiveInfinity * (if ((this > Zero) ^ (divisor >= Zero)) -1 else 1)
+ }
+
+ final def isFinite = false
+
+ private[this] def fail(what: String) = throw new IllegalArgumentException(s"$what not allowed on infinite Durations")
+ final def length: Long = fail("length")
+ final def unit: TimeUnit = fail("unit")
+ final def toNanos: Long = fail("toNanos")
+ final def toMicros: Long = fail("toMicros")
+ final def toMillis: Long = fail("toMillis")
+ final def toSeconds: Long = fail("toSeconds")
+ final def toMinutes: Long = fail("toMinutes")
+ final def toHours: Long = fail("toHours")
+ final def toDays: Long = fail("toDays")
+
+ final def toCoarsest: Duration = this
+ }
+
+ /**
+ * Infinite duration: greater than any other (apart from Undefined) and not equal to any other
+ * but itself. This value closely corresponds to Double.PositiveInfinity,
+ * matching its semantics in arithmetic operations.
+ */
+ val Inf: Infinite = new Infinite {
+ override def toString: String = "Duration.Inf"
+ def compare(other: Duration): Int = other match {
+ case x if x eq Undefined => -1 // Undefined != Undefined
+ case x if x eq this => 0 // `case Inf` will include null checks in the byte code
+ case _ => 1
+ }
+ def unary_- : Duration = MinusInf
+ def toUnit(unit: TimeUnit): Double = Double.PositiveInfinity
+ private def readResolve(): AnyRef = Inf // Instructs deserialization to use this same instance
+ }
+
+ /**
+ * Infinite duration: less than any other and not equal to any other
+ * but itself. This value closely corresponds to Double.NegativeInfinity,
+ * matching its semantics in arithmetic operations.
+ */
+ val MinusInf: Infinite = new Infinite {
+ override def toString: String = "Duration.MinusInf"
+ def compare(other: Duration): Int = if (other eq this) 0 else -1
+ def unary_- : Duration = Inf
+ def toUnit(unit: TimeUnit): Double = Double.NegativeInfinity
+ private def readResolve(): AnyRef = MinusInf // Instructs deserialization to use this same instance
+ }
+
+ // Java Factories
+
+ /**
+ * Construct a finite duration from the given length and time unit. The unit given is retained
+ * throughout calculations as long as possible, so that it can be retrieved later.
+ */
+ def create(length: Long, unit: TimeUnit): FiniteDuration = apply(length, unit)
+ /**
+ * Construct a Duration from the given length and unit. Observe that nanosecond precision may be lost if
+ *
+ * - the unit is NANOSECONDS
+ * - and the length has an absolute value greater than `2^53`
+ *
+ * Infinite inputs (and NaN) are converted into [[Duration.Inf]], [[Duration.MinusInf]] and [[Duration.Undefined]], respectively.
+ *
+ * @throws IllegalArgumentException if the length was finite but the resulting duration cannot be expressed as a [[FiniteDuration]]
+ */
+ def create(length: Double, unit: TimeUnit): Duration = apply(length, unit)
+ /**
+ * Construct a finite duration from the given length and time unit, where the latter is
+ * looked up in a list of string representation. Valid choices are:
+ *
+ * `d, day, h, hour, min, minute, s, sec, second, ms, milli, millisecond, µs, micro, microsecond, ns, nano, nanosecond`
+ * and their pluralized forms (for every but the first mentioned form of each unit, i.e. no "ds", but "days").
+ */
+ def create(length: Long, unit: String): FiniteDuration = apply(length, unit)
+ /**
+ * Parse String into Duration. Format is `""`, where
+ * whitespace is allowed before, between and after the parts. Infinities are
+ * designated by `"Inf"`, `"PlusInf"`, `"+Inf"` and `"-Inf"` or `"MinusInf"`.
+ *
+ * @throws NumberFormatException if format is not parsable
+ */
+ def create(s: String): Duration = apply(s)
+
+ /**
+ * The natural ordering of durations matches the natural ordering for Double, including non-finite values.
+ */
+ implicit object DurationIsOrdered extends Ordering[Duration] {
+ def compare(a: Duration, b: Duration): Int = a compare b
+ }
+}
+
+/**
+ *
Utility for working with java.util.concurrent.TimeUnit durations.
+ *
+ * '''''This class is not meant as a general purpose representation of time, it is
+ * optimized for the needs of `scala.concurrent`.'''''
+ *
+ *
Basic Usage
+ *
+ *
+ * Examples:
+ * {{{
+ * import scala.concurrent.duration._
+ *
+ * val duration = Duration(100, MILLISECONDS)
+ * val duration = Duration(100, "millis")
+ *
+ * duration.toNanos
+ * duration < 1.second
+ * duration <= Duration.Inf
+ * }}}
+ *
+ * '''''Invoking inexpressible conversions (like calling `toSeconds` on an infinite duration) will throw an IllegalArgumentException.'''''
+ *
+ *
+ * Implicits are also provided for Int, Long and Double. Example usage:
+ * {{{
+ * import scala.concurrent.duration._
+ *
+ * val duration = 100.millis
+ * }}}
+ *
+ * '''''The DSL provided by the implicit conversions always allows construction of finite durations, even for infinite Double inputs; use Duration.Inf instead.'''''
+ *
+ * Extractors, parsing and arithmetic are also included:
+ * {{{
+ * val d = Duration("1.2 µs")
+ * val Duration(length, unit) = 5 millis
+ * val d2 = d * 2.5
+ * val d3 = d2 + 1.millisecond
+ * }}}
+ *
+ *
Handling of Time Units
+ *
+ * Calculations performed on finite durations always retain the more precise unit of either operand, no matter
+ * whether a coarser unit would be able to exactly express the same duration. This means that Duration can be
+ * used as a lossless container for a (length, unit) pair if it is constructed using the corresponding methods
+ * and no arithmetic is performed on it; adding/subtracting durations should in that case be done with care.
+ *
+ *
Correspondence to Double Semantics
+ *
+ * The semantics of arithmetic operations on Duration are two-fold:
+ *
+ * - exact addition/subtraction with nanosecond resolution for finite durations, independent of the summands' magnitude
+ * - isomorphic to `java.lang.Double` when it comes to infinite or undefined values
+ *
+ * The conversion between Duration and Double is done using [[Duration.toUnit]] (with unit NANOSECONDS)
+ * and [[Duration$.fromNanos(nanos:Double)* Duration.fromNanos(Double)]]
+ *
+ *
Ordering
+ *
+ * The default ordering is consistent with the ordering of Double numbers, which means that Undefined is
+ * considered greater than all other durations, including [[Duration.Inf]].
+ *
+ * @define exc @throws IllegalArgumentException when invoked on a non-finite duration
+ *
+ * @define ovf @throws IllegalArgumentException in case of a finite overflow: the range of a finite duration is `+-(2^63-1)`ns, and no conversion to infinite durations takes place.
+ */
+sealed abstract class Duration extends Serializable with Ordered[Duration] {
+ /**
+ * Obtain the length of this Duration measured in the unit obtained by the `unit` method.
+ *
+ * $exc
+ */
+ def length: Long
+ /**
+ * Obtain the time unit in which the length of this duration is measured.
+ *
+ * $exc
+ */
+ def unit: TimeUnit
+ /**
+ * Return the length of this duration measured in whole nanoseconds, rounding towards zero.
+ *
+ * $exc
+ */
+ def toNanos: Long
+ /**
+ * Return the length of this duration measured in whole microseconds, rounding towards zero.
+ *
+ * $exc
+ */
+ def toMicros: Long
+ /**
+ * Return the length of this duration measured in whole milliseconds, rounding towards zero.
+ *
+ * $exc
+ */
+ def toMillis: Long
+ /**
+ * Return the length of this duration measured in whole seconds, rounding towards zero.
+ *
+ * $exc
+ */
+ def toSeconds: Long
+ /**
+ * Return the length of this duration measured in whole minutes, rounding towards zero.
+ *
+ * $exc
+ */
+ def toMinutes: Long
+ /**
+ * Return the length of this duration measured in whole hours, rounding towards zero.
+ *
+ * $exc
+ */
+ def toHours: Long
+ /**
+ * Return the length of this duration measured in whole days, rounding towards zero.
+ *
+ * $exc
+ */
+ def toDays: Long
+ /**
+ * Return the number of nanoseconds as floating point number, scaled down to the given unit.
+ * The result may not precisely represent this duration due to the Double datatype's inherent
+ * limitations (mantissa size effectively 53 bits). Non-finite durations are represented as
+ * - [[Duration.Undefined]] is mapped to Double.NaN
+ * - [[Duration.Inf]] is mapped to Double.PositiveInfinity
+ * - [[Duration.MinusInf]] is mapped to Double.NegativeInfinity
+ */
+ def toUnit(unit: TimeUnit): Double
+
+ /**
+ * Return the sum of that duration and this. When involving non-finite summands the semantics match those
+ * of Double.
+ *
+ * $ovf
+ */
+ def +(other: Duration): Duration
+ /**
+ * Return the difference of that duration and this. When involving non-finite summands the semantics match those
+ * of Double.
+ *
+ * $ovf
+ */
+ def -(other: Duration): Duration
+ /**
+ * Return this duration multiplied by the scalar factor. When involving non-finite factors the semantics match those
+ * of Double.
+ *
+ * $ovf
+ */
+ def *(factor: Double): Duration
+ /**
+ * Return this duration divided by the scalar factor. When involving non-finite factors the semantics match those
+ * of Double.
+ *
+ * $ovf
+ */
+ def /(divisor: Double): Duration
+ /**
+ * Return the quotient of this and that duration as floating-point number. The semantics are
+ * determined by Double as if calculating the quotient of the nanosecond lengths of both factors.
+ */
+ def /(divisor: Duration): Double
+ /**
+ * Negate this duration. The only two values which are mapped to themselves are [[Duration.Zero]] and [[Duration.Undefined]].
+ */
+ def unary_- : Duration
+ /**
+ * This method returns whether this duration is finite, which is not the same as
+ * `!isInfinite` for Double because this method also returns `false` for [[Duration.Undefined]].
+ */
+ def isFinite: Boolean
+ /**
+ * Return the smaller of this and that duration as determined by the natural ordering.
+ */
+ def min(other: Duration): Duration = if (this < other) this else other
+ /**
+ * Return the larger of this and that duration as determined by the natural ordering.
+ */
+ def max(other: Duration): Duration = if (this > other) this else other
+
+ // Java API
+
+ /**
+ * Return this duration divided by the scalar factor. When involving non-finite factors the semantics match those
+ * of Double.
+ *
+ * $ovf
+ */
+ def div(divisor: Double): Duration = this / divisor
+ /**
+ * Return the quotient of this and that duration as floating-point number. The semantics are
+ * determined by Double as if calculating the quotient of the nanosecond lengths of both factors.
+ */
+ def div(other: Duration): Double = this / other
+ def gt(other: Duration): Boolean = this > other
+ def gteq(other: Duration): Boolean = this >= other
+ def lt(other: Duration): Boolean = this < other
+ def lteq(other: Duration): Boolean = this <= other
+ /**
+ * Return the difference of that duration and this. When involving non-finite summands the semantics match those
+ * of Double.
+ *
+ * $ovf
+ */
+ def minus(other: Duration): Duration = this - other
+ /**
+ * Return this duration multiplied by the scalar factor. When involving non-finite factors the semantics match those
+ * of Double.
+ *
+ * $ovf
+ */
+ def mul(factor: Double): Duration = this * factor
+ /**
+ * Negate this duration. The only two values which are mapped to themselves are [[Duration.Zero]] and [[Duration.Undefined]].
+ */
+ def neg(): Duration = -this
+ /**
+ * Return the sum of that duration and this. When involving non-finite summands the semantics match those
+ * of Double.
+ *
+ * $ovf
+ */
+ def plus(other: Duration): Duration = this + other
+ /**
+ * Return duration which is equal to this duration but with a coarsest Unit, or self in case it is already the coarsest Unit
+ *
+ * Examples:
+ * {{{
+ * Duration(60, MINUTES).toCoarsest // Duration(1, HOURS)
+ * Duration(1000, MILLISECONDS).toCoarsest // Duration(1, SECONDS)
+ * Duration(48, HOURS).toCoarsest // Duration(2, DAYS)
+ * Duration(5, SECONDS).toCoarsest // Duration(5, SECONDS)
+ * }}}
+ */
+ def toCoarsest: Duration
+}
+
+object FiniteDuration {
+
+ implicit object FiniteDurationIsOrdered extends Ordering[FiniteDuration] {
+ def compare(a: FiniteDuration, b: FiniteDuration): Int = a compare b
+ }
+
+ def apply(length: Long, unit: TimeUnit): FiniteDuration = new FiniteDuration(length, unit)
+ def apply(length: Long, unit: String): FiniteDuration = new FiniteDuration(length, Duration.timeUnit(unit))
+
+ // limit on abs. value of durations in their units
+ private final val max_ns = Long.MaxValue
+ private final val max_µs = max_ns / 1000
+ private final val max_ms = max_µs / 1000
+ private final val max_s = max_ms / 1000
+ private final val max_min= max_s / 60
+ private final val max_h = max_min / 60
+ private final val max_d = max_h / 24
+}
+
+/**
+ * This class represents a finite duration. Its addition and subtraction operators are overloaded to retain
+ * this guarantee statically. The range of this class is limited to `+-(2^63-1)`ns, which is roughly 292 years.
+ */
+final class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duration {
+ import FiniteDuration._
+ import Duration._
+
+ private[this] def bounded(max: Long) = -max <= length && length <= max
+
+ require(unit match {
+ /*
+ * enforce the 2^63-1 ns limit, must be pos/neg symmetrical because of unary_-
+ */
+ case NANOSECONDS => bounded(max_ns)
+ case MICROSECONDS => bounded(max_µs)
+ case MILLISECONDS => bounded(max_ms)
+ case SECONDS => bounded(max_s)
+ case MINUTES => bounded(max_min)
+ case HOURS => bounded(max_h)
+ case DAYS => bounded(max_d)
+ case _ =>
+ val v = DAYS.convert(length, unit)
+ -max_d <= v && v <= max_d
+ }, "Duration is limited to +-(2^63-1)ns (ca. 292 years)")
+
+ def toNanos: Long = unit.toNanos(length)
+ def toMicros: Long = unit.toMicros(length)
+ def toMillis: Long = unit.toMillis(length)
+ def toSeconds: Long = unit.toSeconds(length)
+ def toMinutes: Long = unit.toMinutes(length)
+ def toHours: Long = unit.toHours(length)
+ def toDays: Long = unit.toDays(length)
+ def toUnit(u: TimeUnit): Double = toNanos.toDouble / NANOSECONDS.convert(1, u)
+
+ /**
+ * Construct a [[Deadline]] from this duration by adding it to the current instant `Deadline.now`.
+ */
+ def fromNow: Deadline = Deadline.now + this
+
+ private[this] def unitString = timeUnitName(unit) + ( if (length == 1) "" else "s" )
+ override def toString: String = "" + length + " " + unitString
+
+ def compare(other: Duration): Int = other match {
+ case x: FiniteDuration => toNanos compare x.toNanos
+ case _ => -(other compare this)
+ }
+
+ // see https://www.securecoding.cert.org/confluence/display/java/NUM00-J.+Detect+or+prevent+integer+overflow
+ private[this] def safeAdd(a: Long, b: Long): Long = {
+ if ((b > 0) && (a > Long.MaxValue - b) ||
+ (b < 0) && (a < Long.MinValue - b)) throw new IllegalArgumentException("integer overflow")
+ a + b
+ }
+ private[this] def add(otherLength: Long, otherUnit: TimeUnit): FiniteDuration = {
+ val commonUnit = if (otherUnit.convert(1, unit) == 0) unit else otherUnit
+ val totalLength = safeAdd(commonUnit.convert(length, unit), commonUnit.convert(otherLength, otherUnit))
+ new FiniteDuration(totalLength, commonUnit)
+ }
+
+ def +(other: Duration): Duration = other match {
+ case x: FiniteDuration => add(x.length, x.unit)
+ case _ => other
+ }
+ def -(other: Duration): Duration = other match {
+ case x: FiniteDuration => add(-x.length, x.unit)
+ case _ => -other
+ }
+
+ def *(factor: Double): Duration =
+ if (!factor.isInfinite) fromNanos(toNanos * factor)
+ else if (JDouble.isNaN(factor)) Undefined
+ else if ((factor > 0) ^ (this < Zero)) Inf
+ else MinusInf
+
+ def /(divisor: Double): Duration =
+ if (!divisor.isInfinite) fromNanos(toNanos / divisor)
+ else if (JDouble.isNaN(divisor)) Undefined
+ else Zero
+
+ // if this is made a constant, then scalac will elide the conditional and always return +0.0, scala/bug#6331
+ private[this] def minusZero = -0d
+ def /(divisor: Duration): Double =
+ if (divisor.isFinite) toNanos.toDouble / divisor.toNanos
+ else if (divisor eq Undefined) Double.NaN
+ else if ((length < 0) ^ (divisor > Zero)) 0d
+ else minusZero
+
+ // overloaded methods taking FiniteDurations, so that you can calculate while statically staying finite
+ def +(other: FiniteDuration): FiniteDuration = add(other.length, other.unit)
+ def -(other: FiniteDuration): FiniteDuration = add(-other.length, other.unit)
+ def plus(other: FiniteDuration): FiniteDuration = this + other
+ def minus(other: FiniteDuration): FiniteDuration = this - other
+ def min(other: FiniteDuration): FiniteDuration = if (this < other) this else other
+ def max(other: FiniteDuration): FiniteDuration = if (this > other) this else other
+
+ // overloaded methods taking Long so that you can calculate while statically staying finite
+
+ /**
+ * Return the quotient of this duration and the given integer factor.
+ *
+ * @throws java.lang.ArithmeticException if the factor is 0
+ */
+ def /(divisor: Long): FiniteDuration = fromNanos(toNanos / divisor)
+
+ /**
+ * Return the product of this duration and the given integer factor.
+ *
+ * @throws IllegalArgumentException if the result would overflow the range of FiniteDuration
+ */
+ def *(factor: Long): FiniteDuration = new FiniteDuration(safeMul(length, factor), unit)
+
+ /*
+ * This method avoids the use of Long division, which saves 95% of the time spent,
+ * by checking that there are enough leading zeros so that the result has a chance
+ * to fit into a Long again; the remaining edge cases are caught by using the sign
+ * of the product for overflow detection.
+ *
+ * This method is not general purpose because it disallows the (otherwise legal)
+ * case of Long.MinValue * 1, but that is okay for use in FiniteDuration, since
+ * Long.MinValue is not a legal `length` anyway.
+ */
+ private def safeMul(_a: Long, _b: Long): Long = {
+ val a = scala.math.abs(_a)
+ val b = scala.math.abs(_b)
+ import java.lang.Long.{ numberOfLeadingZeros => leading }
+ if (leading(a) + leading(b) < 64) throw new IllegalArgumentException("multiplication overflow")
+ val product = a * b
+ if (product < 0) throw new IllegalArgumentException("multiplication overflow")
+ if (a == _a ^ b == _b) -product else product
+ }
+
+ /**
+ * Return the quotient of this duration and the given integer factor.
+ *
+ * @throws java.lang.ArithmeticException if the factor is 0
+ */
+ def div(divisor: Long): FiniteDuration = this / divisor
+
+ /**
+ * Return the product of this duration and the given integer factor.
+ *
+ * @throws IllegalArgumentException if the result would overflow the range of FiniteDuration
+ */
+ def mul(factor: Long): FiniteDuration = this * factor
+
+ def unary_- : FiniteDuration = Duration(-length, unit)
+
+ final def isFinite = true
+
+ final override def toCoarsest: FiniteDuration = {
+ def loop(length: Long, unit: TimeUnit): FiniteDuration = {
+ def coarserOrThis(coarser: TimeUnit, divider: Int): FiniteDuration =
+ if (length % divider == 0) loop(length / divider, coarser)
+ else if (unit == this.unit) this
+ else FiniteDuration(length, unit)
+
+ unit match {
+ case DAYS => FiniteDuration(length, unit)
+ case HOURS => coarserOrThis(DAYS, 24)
+ case MINUTES => coarserOrThis(HOURS, 60)
+ case SECONDS => coarserOrThis(MINUTES, 60)
+ case MILLISECONDS => coarserOrThis(SECONDS, 1000)
+ case MICROSECONDS => coarserOrThis(MILLISECONDS, 1000)
+ case NANOSECONDS => coarserOrThis(MICROSECONDS, 1000)
+ }
+ }
+
+ if (unit == DAYS || length == 0) this
+ else loop(length, unit)
+ }
+
+ override def equals(other: Any): Boolean = other match {
+ case x: FiniteDuration => toNanos == x.toNanos
+ case _ => super.equals(other)
+ }
+ override def hashCode: Int = toNanos.toInt
+}
diff --git a/library/src/scala/concurrent/duration/DurationConversions.scala b/library/src/scala/concurrent/duration/DurationConversions.scala
new file mode 100644
index 000000000000..30036331be73
--- /dev/null
+++ b/library/src/scala/concurrent/duration/DurationConversions.scala
@@ -0,0 +1,96 @@
+/*
+ * 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.concurrent.duration
+
+import DurationConversions._
+
+// Would be nice to limit the visibility of this trait a little bit,
+// but it crashes scalac to do so.
+trait DurationConversions extends Any {
+ protected def durationIn(unit: TimeUnit): FiniteDuration
+
+ def nanoseconds: FiniteDuration = durationIn(NANOSECONDS)
+ def nanos: FiniteDuration = nanoseconds
+ def nanosecond: FiniteDuration = nanoseconds
+ def nano: FiniteDuration = nanoseconds
+
+ def microseconds: FiniteDuration = durationIn(MICROSECONDS)
+ def micros: FiniteDuration = microseconds
+ def microsecond: FiniteDuration = microseconds
+ def micro: FiniteDuration = microseconds
+
+ def milliseconds: FiniteDuration = durationIn(MILLISECONDS)
+ def millis: FiniteDuration = milliseconds
+ def millisecond: FiniteDuration = milliseconds
+ def milli: FiniteDuration = milliseconds
+
+ def seconds: FiniteDuration = durationIn(SECONDS)
+ def second: FiniteDuration = seconds
+
+ def minutes: FiniteDuration = durationIn(MINUTES)
+ def minute: FiniteDuration = minutes
+
+ def hours: FiniteDuration = durationIn(HOURS)
+ def hour: FiniteDuration = hours
+
+ def days: FiniteDuration = durationIn(DAYS)
+ def day: FiniteDuration = days
+
+ def nanoseconds[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(nanoseconds)
+ def nanos[C](c: C)(implicit ev: Classifier[C]): ev.R = nanoseconds(c)
+ def nanosecond[C](c: C)(implicit ev: Classifier[C]): ev.R = nanoseconds(c)
+ def nano[C](c: C)(implicit ev: Classifier[C]): ev.R = nanoseconds(c)
+
+ def microseconds[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(microseconds)
+ def micros[C](c: C)(implicit ev: Classifier[C]): ev.R = microseconds(c)
+ def microsecond[C](c: C)(implicit ev: Classifier[C]): ev.R = microseconds(c)
+ def micro[C](c: C)(implicit ev: Classifier[C]): ev.R = microseconds(c)
+
+ def milliseconds[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(milliseconds)
+ def millis[C](c: C)(implicit ev: Classifier[C]): ev.R = milliseconds(c)
+ def millisecond[C](c: C)(implicit ev: Classifier[C]): ev.R = milliseconds(c)
+ def milli[C](c: C)(implicit ev: Classifier[C]): ev.R = milliseconds(c)
+
+ def seconds[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(seconds)
+ def second[C](c: C)(implicit ev: Classifier[C]): ev.R = seconds(c)
+
+ def minutes[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(minutes)
+ def minute[C](c: C)(implicit ev: Classifier[C]): ev.R = minutes(c)
+
+ def hours[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(hours)
+ def hour[C](c: C)(implicit ev: Classifier[C]): ev.R = hours(c)
+
+ def days[C](c: C)(implicit ev: Classifier[C]): ev.R = ev.convert(days)
+ def day[C](c: C)(implicit ev: Classifier[C]): ev.R = days(c)
+}
+
+/**
+ * This object just holds some cogs which make the DSL machine work, not for direct consumption.
+ */
+object DurationConversions {
+ trait Classifier[C] {
+ type R
+ def convert(d: FiniteDuration): R
+ }
+
+ implicit object spanConvert extends Classifier[span.type] {
+ type R = FiniteDuration
+ def convert(d: FiniteDuration): FiniteDuration = d
+ }
+
+ implicit object fromNowConvert extends Classifier[fromNow.type] {
+ type R = Deadline
+ def convert(d: FiniteDuration): Deadline = Deadline.now + d
+ }
+
+}
diff --git a/library/src/scala/concurrent/duration/package.scala b/library/src/scala/concurrent/duration/package.scala
new file mode 100644
index 000000000000..f81b8777f6d0
--- /dev/null
+++ b/library/src/scala/concurrent/duration/package.scala
@@ -0,0 +1,87 @@
+/*
+ * 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.concurrent
+
+import scala.language.implicitConversions
+
+package object duration {
+ /**
+ * This object can be used as closing token if you prefer dot-less style but do not want
+ * to enable language.postfixOps:
+ *
+ * {{{
+ * import scala.concurrent.duration._
+ *
+ * val duration = 2 seconds span
+ * }}}
+ */
+ object span
+
+ /**
+ * This object can be used as closing token for declaring a deadline at some future point
+ * in time:
+ *
+ * {{{
+ * import scala.concurrent.duration._
+ *
+ * val deadline = 3 seconds fromNow
+ * }}}
+ */
+ object fromNow
+
+ type TimeUnit = java.util.concurrent.TimeUnit
+ final val DAYS = java.util.concurrent.TimeUnit.DAYS
+ final val HOURS = java.util.concurrent.TimeUnit.HOURS
+ final val MICROSECONDS = java.util.concurrent.TimeUnit.MICROSECONDS
+ final val MILLISECONDS = java.util.concurrent.TimeUnit.MILLISECONDS
+ final val MINUTES = java.util.concurrent.TimeUnit.MINUTES
+ final val NANOSECONDS = java.util.concurrent.TimeUnit.NANOSECONDS
+ final val SECONDS = java.util.concurrent.TimeUnit.SECONDS
+
+ implicit def pairIntToDuration(p: (Int, TimeUnit)): Duration = Duration(p._1.toLong, p._2)
+ implicit def pairLongToDuration(p: (Long, TimeUnit)): FiniteDuration = Duration(p._1, p._2)
+ implicit def durationToPair(d: Duration): (Long, TimeUnit) = (d.length, d.unit)
+
+ implicit final class DurationInt(private val n: Int) extends AnyVal with DurationConversions {
+ override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n.toLong, unit)
+ }
+
+ implicit final class DurationLong(private val n: Long) extends AnyVal with DurationConversions {
+ override protected def durationIn(unit: TimeUnit): FiniteDuration = Duration(n, unit)
+ }
+
+ implicit final class DurationDouble(private val d: Double) extends AnyVal with DurationConversions {
+ override protected def durationIn(unit: TimeUnit): FiniteDuration =
+ Duration(d, unit) match {
+ case f: FiniteDuration => f
+ case _ => throw new IllegalArgumentException("Duration DSL not applicable to " + d)
+ }
+ }
+
+ /*
+ * Avoid reflection based invocation by using non-duck type
+ */
+ implicit final class IntMult(private val i: Int) extends AnyVal {
+ def *(d: Duration): Duration = d * i.toDouble
+ def *(d: FiniteDuration): FiniteDuration = d * i.toLong
+ }
+
+ implicit final class LongMult(private val i: Long) extends AnyVal {
+ def *(d: Duration): Duration = d * i.toDouble
+ def *(d: FiniteDuration): FiniteDuration = d * i.toLong
+ }
+
+ implicit final class DoubleMult(private val f: Double) extends AnyVal {
+ def *(d: Duration): Duration = d * f.toDouble
+ }
+}
diff --git a/library/src/scala/concurrent/impl/ExecutionContextImpl.scala b/library/src/scala/concurrent/impl/ExecutionContextImpl.scala
new file mode 100644
index 000000000000..262a12b1b4b9
--- /dev/null
+++ b/library/src/scala/concurrent/impl/ExecutionContextImpl.scala
@@ -0,0 +1,137 @@
+/*
+ * 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.concurrent.impl
+
+import java.util.concurrent.{ Semaphore, ForkJoinPool, ForkJoinWorkerThread, Callable, Executor, ExecutorService, ThreadFactory, TimeUnit }
+import java.util.Collection
+import scala.concurrent.{ BlockContext, ExecutionContext, CanAwait, ExecutionContextExecutor, ExecutionContextExecutorService }
+
+private[scala] class ExecutionContextImpl private[impl] (final val executor: Executor, final val reporter: Throwable => Unit) extends ExecutionContextExecutor {
+ require(executor ne null, "Executor must not be null")
+ override final def execute(runnable: Runnable): Unit = executor execute runnable
+ override final def reportFailure(t: Throwable): Unit = reporter(t)
+}
+
+private[concurrent] object ExecutionContextImpl {
+
+ final class DefaultThreadFactory(
+ final val daemonic: Boolean,
+ final val maxBlockers: Int,
+ final val prefix: String,
+ final val uncaught: Thread.UncaughtExceptionHandler) extends ThreadFactory with ForkJoinPool.ForkJoinWorkerThreadFactory {
+
+ require(prefix ne null, "DefaultThreadFactory.prefix must be non null")
+ require(maxBlockers >= 0, "DefaultThreadFactory.maxBlockers must be greater-or-equal-to 0")
+
+ private final val blockerPermits = new Semaphore(maxBlockers)
+
+ @annotation.nowarn("cat=deprecation")
+ def wire[T <: Thread](thread: T): T = {
+ thread.setDaemon(daemonic)
+ thread.setUncaughtExceptionHandler(uncaught)
+ thread.setName(prefix + "-" + thread.getId())
+ thread
+ }
+
+ def newThread(runnable: Runnable): Thread = wire(new Thread(runnable))
+
+ def newThread(fjp: ForkJoinPool): ForkJoinWorkerThread =
+ wire(new ForkJoinWorkerThread(fjp) with BlockContext {
+ private[this] final var isBlocked: Boolean = false // This is only ever read & written if this thread is the current thread
+ final override def blockOn[T](thunk: => T)(implicit permission: CanAwait): T =
+ if ((Thread.currentThread eq this) && !isBlocked && blockerPermits.tryAcquire()) {
+ try {
+ val b: ForkJoinPool.ManagedBlocker with (() => T) =
+ new ForkJoinPool.ManagedBlocker with (() => T) {
+ private[this] final var result: T = null.asInstanceOf[T]
+ private[this] final var done: Boolean = false
+ final override def block(): Boolean = {
+ if (!done) {
+ result = thunk // If this throws then it will stop blocking.
+ done = true
+ }
+
+ isReleasable
+ }
+
+ final override def isReleasable = done
+ final override def apply(): T = result
+ }
+ isBlocked = true
+ ForkJoinPool.managedBlock(b)
+ b()
+ } finally {
+ isBlocked = false
+ blockerPermits.release()
+ }
+ } else thunk // Unmanaged blocking
+ })
+ }
+
+ def createDefaultExecutorService(reporter: Throwable => Unit): ExecutionContextExecutorService = {
+ def getInt(name: String, default: String) = (try System.getProperty(name, default) catch {
+ case e: SecurityException => default
+ }) match {
+ case s if s.charAt(0) == 'x' => (Runtime.getRuntime.availableProcessors * s.substring(1).toDouble).ceil.toInt
+ case other => other.toInt
+ }
+
+ val desiredParallelism = // A range between min and max given num
+ scala.math.min(
+ scala.math.max(
+ getInt("scala.concurrent.context.minThreads", "1"),
+ getInt("scala.concurrent.context.numThreads", "x1")),
+ getInt("scala.concurrent.context.maxThreads", "x1")
+ )
+
+ val threadFactory = new DefaultThreadFactory(daemonic = true,
+ maxBlockers = getInt("scala.concurrent.context.maxExtraThreads", "256"),
+ prefix = "scala-execution-context-global",
+ uncaught = (thread: Thread, cause: Throwable) => reporter(cause))
+
+ new ForkJoinPool(desiredParallelism, threadFactory, threadFactory.uncaught, true) with ExecutionContextExecutorService {
+ final override def reportFailure(cause: Throwable): Unit =
+ getUncaughtExceptionHandler() match {
+ case null =>
+ case some => some.uncaughtException(Thread.currentThread, cause)
+ }
+ }
+ }
+
+ def fromExecutor(e: Executor, reporter: Throwable => Unit = ExecutionContext.defaultReporter): ExecutionContextExecutor =
+ e match {
+ case null => createDefaultExecutorService(reporter)
+ case some => new ExecutionContextImpl(some, reporter)
+ }
+
+ def fromExecutorService(es: ExecutorService, reporter: Throwable => Unit = ExecutionContext.defaultReporter):
+ ExecutionContextExecutorService = es match {
+ case null => createDefaultExecutorService(reporter)
+ case some =>
+ new ExecutionContextImpl(some, reporter) with ExecutionContextExecutorService {
+ private[this] final def asExecutorService: ExecutorService = executor.asInstanceOf[ExecutorService]
+ final override def shutdown() = asExecutorService.shutdown()
+ final override def shutdownNow() = asExecutorService.shutdownNow()
+ final override def isShutdown = asExecutorService.isShutdown
+ final override def isTerminated = asExecutorService.isTerminated
+ final override def awaitTermination(l: Long, timeUnit: TimeUnit) = asExecutorService.awaitTermination(l, timeUnit)
+ final override def submit[T](callable: Callable[T]) = asExecutorService.submit(callable)
+ final override def submit[T](runnable: Runnable, t: T) = asExecutorService.submit(runnable, t)
+ final override def submit(runnable: Runnable) = asExecutorService.submit(runnable)
+ final override def invokeAll[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAll(callables)
+ final override def invokeAll[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAll(callables, l, timeUnit)
+ final override def invokeAny[T](callables: Collection[_ <: Callable[T]]) = asExecutorService.invokeAny(callables)
+ final override def invokeAny[T](callables: Collection[_ <: Callable[T]], l: Long, timeUnit: TimeUnit) = asExecutorService.invokeAny(callables, l, timeUnit)
+ }
+ }
+}
diff --git a/library/src/scala/concurrent/impl/FutureConvertersImpl.scala b/library/src/scala/concurrent/impl/FutureConvertersImpl.scala
new file mode 100644
index 000000000000..a9eed4cbb055
--- /dev/null
+++ b/library/src/scala/concurrent/impl/FutureConvertersImpl.scala
@@ -0,0 +1,101 @@
+/*
+ * 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.concurrent.impl
+
+import java.util.concurrent.{CompletableFuture, CompletionStage, TimeUnit}
+import java.util.function.{BiConsumer, BiFunction, Consumer, Function => JFunction}
+
+import scala.concurrent.Future
+import scala.concurrent.impl.Promise.DefaultPromise
+import scala.util.{Failure, Success, Try}
+
+private[scala] object FutureConvertersImpl {
+ final class CF[T](val wrapped: Future[T]) extends CompletableFuture[T] with (Try[T] => Unit) {
+ override def apply(t: Try[T]): Unit = t match {
+ case Success(v) => complete(v)
+ case Failure(e) => completeExceptionally(e)
+ }
+
+ // Ensure that completions of this future cannot hold the Scala Future's completer hostage
+
+ override def thenApply[U](fn: JFunction[_ >: T, _ <: U]): CompletableFuture[U] = thenApplyAsync(fn)
+
+ override def thenAccept(fn: Consumer[_ >: T]): CompletableFuture[Void] = thenAcceptAsync(fn)
+
+ override def thenRun(fn: Runnable): CompletableFuture[Void] = thenRunAsync(fn)
+
+ override def thenCombine[U, V](cs: CompletionStage[_ <: U], fn: BiFunction[_ >: T, _ >: U, _ <: V]): CompletableFuture[V] = thenCombineAsync(cs, fn)
+
+ override def thenAcceptBoth[U](cs: CompletionStage[_ <: U], fn: BiConsumer[_ >: T, _ >: U]): CompletableFuture[Void] = thenAcceptBothAsync(cs, fn)
+
+ override def runAfterBoth(cs: CompletionStage[_], fn: Runnable): CompletableFuture[Void] = runAfterBothAsync(cs, fn)
+
+ override def applyToEither[U](cs: CompletionStage[_ <: T], fn: JFunction[_ >: T, U]): CompletableFuture[U] = applyToEitherAsync(cs, fn)
+
+ override def acceptEither(cs: CompletionStage[_ <: T], fn: Consumer[_ >: T]): CompletableFuture[Void] = acceptEitherAsync(cs, fn)
+
+ override def runAfterEither(cs: CompletionStage[_], fn: Runnable): CompletableFuture[Void] = runAfterEitherAsync(cs, fn)
+
+ override def thenCompose[U](fn: JFunction[_ >: T, _ <: CompletionStage[U]]): CompletableFuture[U] = thenComposeAsync(fn)
+
+ override def whenComplete(fn: BiConsumer[_ >: T, _ >: Throwable]): CompletableFuture[T] = whenCompleteAsync(fn)
+
+ override def handle[U](fn: BiFunction[_ >: T, Throwable, _ <: U]): CompletableFuture[U] = handleAsync(fn)
+
+ override def exceptionally(fn: JFunction[Throwable, _ <: T]): CompletableFuture[T] = {
+ val cf = new CompletableFuture[T]
+ whenCompleteAsync((t, e) => {
+ if (e == null) cf.complete(t)
+ else {
+ val n: AnyRef =
+ try {
+ fn(e).asInstanceOf[AnyRef]
+ } catch {
+ case thr: Throwable =>
+ cf.completeExceptionally(thr)
+ this
+ }
+ if (n ne this) cf.complete(n.asInstanceOf[T])
+ }
+ }
+ )
+ cf
+ }
+
+ /**
+ * @inheritdoc
+ *
+ * WARNING: completing the result of this method will not complete the underlying
+ * Scala Future or Promise (ie, the one that that was passed to `toJava`.)
+ */
+ override def toCompletableFuture: CompletableFuture[T] = this
+
+ override def obtrudeValue(value: T): Unit = throw new UnsupportedOperationException("obtrudeValue may not be used on the result of toJava(scalaFuture)")
+
+ override def obtrudeException(ex: Throwable): Unit = throw new UnsupportedOperationException("obtrudeException may not be used on the result of toJava(scalaFuture)")
+
+ override def get(): T = scala.concurrent.blocking(super.get())
+
+ override def get(timeout: Long, unit: TimeUnit): T = scala.concurrent.blocking(super.get(timeout, unit))
+
+ override def toString(): String = super[CompletableFuture].toString
+ }
+
+ final class P[T](val wrapped: CompletionStage[T]) extends DefaultPromise[T] with BiFunction[T, Throwable, Unit] {
+ override def apply(v: T, e: Throwable): Unit = {
+ if (e == null) success(v)
+ else failure(e)
+ }
+ }
+}
+
diff --git a/library/src/scala/concurrent/impl/Promise.scala b/library/src/scala/concurrent/impl/Promise.scala
new file mode 100644
index 000000000000..bf89e6ef2217
--- /dev/null
+++ b/library/src/scala/concurrent/impl/Promise.scala
@@ -0,0 +1,510 @@
+/*
+ * 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.concurrent.impl
+import scala.concurrent.{Batchable, CanAwait, ExecutionContext, ExecutionException, Future, TimeoutException}
+import scala.concurrent.duration.Duration
+import scala.annotation.{nowarn, switch, tailrec}
+import scala.util.control.{ControlThrowable, NonFatal}
+import scala.util.{Failure, Success, Try}
+import scala.runtime.NonLocalReturnControl
+import java.util.concurrent.locks.AbstractQueuedSynchronizer
+import java.util.concurrent.atomic.AtomicReference
+import java.util.Objects.requireNonNull
+import java.io.{IOException, NotSerializableException, ObjectInputStream, ObjectOutputStream}
+
+/**
+ * Latch used to implement waiting on a DefaultPromise's result.
+ *
+ * Inspired by: http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/locks/AbstractQueuedSynchronizer.java
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * https://creativecommons.org/publicdomain/zero/1.0/
+ */
+private[impl] final class CompletionLatch[T] extends AbstractQueuedSynchronizer with (Try[T] => Unit) {
+ //@volatie not needed since we use acquire/release
+ /*@volatile*/ private[this] var _result: Try[T] = null
+ final def result: Try[T] = _result
+ override protected def tryAcquireShared(ignored: Int): Int = if (getState != 0) 1 else -1
+ override protected def tryReleaseShared(ignore: Int): Boolean = {
+ setState(1)
+ true
+ }
+ override def apply(value: Try[T]): Unit = {
+ _result = value // This line MUST go before releaseShared
+ releaseShared(1)
+ }
+}
+
+private[concurrent] object Promise {
+ /**
+ * Link represents a completion dependency between 2 DefaultPromises.
+ * As the DefaultPromise referred to by a Link can itself be linked to another promise
+ * `relink` traverses such chains and compresses them so that the link always points
+ * to the root of the dependency chain.
+ *
+ * In order to conserve memory, the owner of a Link (a DefaultPromise) is not stored
+ * on the Link, but is instead passed in as a parameter to the operation(s).
+ *
+ * If when compressing a chain of Links it is discovered that the root has been completed,
+ * the `owner`'s value is completed with that value, and the Link chain is discarded.
+ **/
+ private[concurrent] final class Link[T](to: DefaultPromise[T]) extends AtomicReference[DefaultPromise[T]](to) {
+ /**
+ * Compresses this chain and returns the currently known root of this chain of Links.
+ **/
+ final def promise(owner: DefaultPromise[T]): DefaultPromise[T] = {
+ val c = get()
+ compressed(current = c, target = c, owner = owner)
+ }
+
+ /**
+ * The combination of traversing and possibly unlinking of a given `target` DefaultPromise.
+ **/
+ @inline @tailrec private[this] final def compressed(current: DefaultPromise[T], target: DefaultPromise[T], owner: DefaultPromise[T]): DefaultPromise[T] = {
+ val value = target.get()
+ if (value.isInstanceOf[Callbacks[_]]) {
+ if (compareAndSet(current, target)) target // Link
+ else compressed(current = get(), target = target, owner = owner) // Retry
+ } else if (value.isInstanceOf[Link[_]]) compressed(current = current, target = value.asInstanceOf[Link[T]].get(), owner = owner) // Compress
+ else /*if (value.isInstanceOf[Try[T]])*/ {
+ owner.unlink(value.asInstanceOf[Try[T]]) // Discard links
+ owner
+ }
+ }
+ }
+
+ /**
+ * The process of "resolving" a Try is to validate that it only contains
+ * those values which makes sense in the context of Futures.
+ **/
+ // requireNonNull is paramount to guard against null completions
+ private[this] final def resolve[T](value: Try[T]): Try[T] =
+ if (requireNonNull(value).isInstanceOf[Success[T]]) value
+ else {
+ val t = value.asInstanceOf[Failure[T]].exception
+ if (t.isInstanceOf[ControlThrowable] || t.isInstanceOf[InterruptedException] || t.isInstanceOf[Error]) {
+ if (t.isInstanceOf[NonLocalReturnControl[T @unchecked]])
+ Success(t.asInstanceOf[NonLocalReturnControl[T]].value)
+ else
+ Failure(new ExecutionException("Boxed Exception", t))
+ } else value
+ }
+
+ // Left non-final to enable addition of extra fields by Java/Scala converters in scala-java8-compat.
+ class DefaultPromise[T] private[this] (initial: AnyRef) extends AtomicReference[AnyRef](initial) with scala.concurrent.Promise[T] with scala.concurrent.Future[T] with (Try[T] => Unit) {
+ /**
+ * Constructs a new, completed, Promise.
+ */
+ final def this(result: Try[T]) = this(resolve(result): AnyRef)
+
+ /**
+ * Constructs a new, un-completed, Promise.
+ */
+ final def this() = this(Noop: AnyRef)
+
+ /**
+ * WARNING: the `resolved` value needs to have been pre-resolved using `resolve()`
+ * INTERNAL API
+ */
+ override final def apply(resolved: Try[T]): Unit =
+ tryComplete0(get(), resolved)
+
+ /**
+ * Returns the associated `Future` with this `Promise`
+ */
+ override final def future: Future[T] = this
+
+ override final def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S] =
+ dispatchOrAddCallbacks(get(), new Transformation[T, S](Xform_transform, f, executor))
+
+ override final def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S] =
+ dispatchOrAddCallbacks(get(), new Transformation[T, S](Xform_transformWith, f, executor))
+
+ override final def zipWith[U, R](that: Future[U])(f: (T, U) => R)(implicit executor: ExecutionContext): Future[R] = {
+ val state = get()
+ if (state.isInstanceOf[Try[_]]) {
+ if (state.asInstanceOf[Try[T]].isFailure) this.asInstanceOf[Future[R]]
+ else {
+ val l = state.asInstanceOf[Success[T]].get
+ that.map(r => f(l, r))
+ }
+ } else {
+ val buffer = new AtomicReference[Success[Any]]()
+ val zipped = new DefaultPromise[R]()
+
+ val thisF: Try[T] => Unit = {
+ case left: Success[_] =>
+ val right = buffer.getAndSet(left).asInstanceOf[Success[U]]
+ if (right ne null)
+ zipped.tryComplete(try Success(f(left.get, right.get)) catch { case e if NonFatal(e) => Failure(e) })
+ case f => // Can only be Failure
+ zipped.tryComplete(f.asInstanceOf[Failure[R]])
+ }
+
+ val thatF: Try[U] => Unit = {
+ case right: Success[_] =>
+ val left = buffer.getAndSet(right).asInstanceOf[Success[T]]
+ if (left ne null)
+ zipped.tryComplete(try Success(f(left.get, right.get)) catch { case e if NonFatal(e) => Failure(e) })
+ case f => // Can only be Failure
+ zipped.tryComplete(f.asInstanceOf[Failure[R]])
+ }
+ // Cheaper than this.onComplete since we already polled the state
+ this.dispatchOrAddCallbacks(state, new Transformation[T, Unit](Xform_onComplete, thisF, executor))
+ that.onComplete(thatF)
+ zipped.future
+ }
+ }
+
+ override final def foreach[U](f: T => U)(implicit executor: ExecutionContext): Unit = {
+ val state = get()
+ if (!state.isInstanceOf[Failure[_]]) dispatchOrAddCallbacks(state, new Transformation[T, Unit](Xform_foreach, f, executor))
+ }
+
+ override final def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = {
+ val state = get()
+ if (!state.isInstanceOf[Failure[_]]) dispatchOrAddCallbacks(state, new Transformation[T, S](Xform_flatMap, f, executor))
+ else this.asInstanceOf[Future[S]]
+ }
+
+ override final def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = {
+ val state = get()
+ if (!state.isInstanceOf[Failure[_]]) dispatchOrAddCallbacks(state, new Transformation[T, S](Xform_map, f, executor))
+ else this.asInstanceOf[Future[S]]
+ }
+
+ override final def filter(p: T => Boolean)(implicit executor: ExecutionContext): Future[T] = {
+ val state = get()
+ if (!state.isInstanceOf[Failure[_]]) dispatchOrAddCallbacks(state, new Transformation[T, T](Xform_filter, p, executor)) // Short-circuit if we get a Success
+ else this
+ }
+
+ override final def collect[S](pf: PartialFunction[T, S])(implicit executor: ExecutionContext): Future[S] = {
+ val state = get()
+ if (!state.isInstanceOf[Failure[_]]) dispatchOrAddCallbacks(state, new Transformation[T, S](Xform_collect, pf, executor)) // Short-circuit if we get a Success
+ else this.asInstanceOf[Future[S]]
+ }
+
+ override final def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = {
+ val state = get()
+ if (!state.isInstanceOf[Success[_]]) dispatchOrAddCallbacks(state, new Transformation[T, U](Xform_recoverWith, pf, executor)) // Short-circuit if we get a Failure
+ else this.asInstanceOf[Future[U]]
+ }
+
+ override final def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = {
+ val state = get()
+ if (!state.isInstanceOf[Success[_]]) dispatchOrAddCallbacks(state, new Transformation[T, U](Xform_recover, pf, executor)) // Short-circuit if we get a Failure
+ else this.asInstanceOf[Future[U]]
+ }
+
+ override final def mapTo[S](implicit tag: scala.reflect.ClassTag[S]): Future[S] =
+ if (!get().isInstanceOf[Failure[_]]) super[Future].mapTo[S](tag) // Short-circuit if we get a Success
+ else this.asInstanceOf[Future[S]]
+
+
+ override final def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit =
+ dispatchOrAddCallbacks(get(), new Transformation[T, Unit](Xform_onComplete, func, executor))
+
+ override final def failed: Future[Throwable] =
+ if (!get().isInstanceOf[Success[_]]) super.failed
+ else Future.failedFailureFuture // Cached instance in case of already known success
+
+ @tailrec override final def toString: String = {
+ val state = get()
+ if (state.isInstanceOf[Try[_]]) "Future("+state+")"
+ else if (state.isInstanceOf[Link[_]]) state.asInstanceOf[Link[T]].promise(this).toString
+ else /*if (state.isInstanceOf[Callbacks[T]]) */ "Future()"
+ }
+
+ private[this] final def tryAwait0(atMost: Duration): Try[T] =
+ if (atMost ne Duration.Undefined) {
+ val v = value0
+ if (v ne null) v
+ else {
+ val r =
+ if (atMost <= Duration.Zero) null
+ else {
+ val l = new CompletionLatch[T]()
+ onComplete(l)(ExecutionContext.parasitic)
+
+ if (atMost.isFinite)
+ l.tryAcquireSharedNanos(1, atMost.toNanos)
+ else
+ l.acquireSharedInterruptibly(1)
+
+ l.result
+ }
+ if (r ne null) r
+ else throw new TimeoutException("Future timed out after [" + atMost + "]")
+ }
+ } else throw new IllegalArgumentException("Cannot wait for Undefined duration of time")
+
+ @throws(classOf[TimeoutException])
+ @throws(classOf[InterruptedException])
+ final def ready(atMost: Duration)(implicit permit: CanAwait): this.type = {
+ tryAwait0(atMost)
+ this
+ }
+
+ @throws(classOf[Exception])
+ final def result(atMost: Duration)(implicit permit: CanAwait): T =
+ tryAwait0(atMost).get // returns the value, or throws the contained exception
+
+ override final def isCompleted: Boolean = value0 ne null
+
+ override final def value: Option[Try[T]] = Option(value0)
+
+ @tailrec // returns null if not completed
+ private final def value0: Try[T] = {
+ val state = get()
+ if (state.isInstanceOf[Try[_]]) state.asInstanceOf[Try[T]]
+ else if (state.isInstanceOf[Link[_]]) state.asInstanceOf[Link[T]].promise(this).value0
+ else /*if (state.isInstanceOf[Callbacks[T]])*/ null
+ }
+
+ override final def tryComplete(value: Try[T]): Boolean = {
+ val state = get()
+ if (state.isInstanceOf[Try[_]]) false
+ else tryComplete0(state, resolve(value))
+ }
+
+ @tailrec // WARNING: important that the supplied Try really is resolve():d
+ private[Promise] final def tryComplete0(state: AnyRef, resolved: Try[T]): Boolean =
+ if (state.isInstanceOf[Callbacks[_]]) {
+ if (compareAndSet(state, resolved)) {
+ if (state ne Noop) submitWithValue(state.asInstanceOf[Callbacks[T]], resolved)
+ true
+ } else tryComplete0(get(), resolved)
+ } else if (state.isInstanceOf[Link[_]]) {
+ val p = state.asInstanceOf[Link[T]].promise(this) // If this returns owner/this, we are in a completed link
+ (p ne this) && p.tryComplete0(p.get(), resolved) // Use this to get tailcall optimization and avoid re-resolution
+ } else /* if(state.isInstanceOf[Try[T]]) */ false
+
+ override final def completeWith(other: Future[T]): this.type = {
+ if (other ne this) {
+ val state = get()
+ if (!state.isInstanceOf[Try[_]]) {
+ val resolved = if (other.isInstanceOf[DefaultPromise[_]]) other.asInstanceOf[DefaultPromise[T]].value0 else other.value.orNull
+ if (resolved ne null) tryComplete0(state, resolved)
+ else other.onComplete(this)(ExecutionContext.parasitic)
+ }
+ }
+
+ this
+ }
+
+ /** Tries to add the callback, if already completed, it dispatches the callback to be executed.
+ * Used by `onComplete()` to add callbacks to a promise and by `link()` to transfer callbacks
+ * to the root promise when linking two promises together.
+ */
+ @tailrec private final def dispatchOrAddCallbacks[C <: Callbacks[T]](state: AnyRef, callbacks: C): C =
+ if (state.isInstanceOf[Try[_]]) {
+ submitWithValue(callbacks, state.asInstanceOf[Try[T]]) // invariant: callbacks should never be Noop here
+ callbacks
+ } else if (state.isInstanceOf[Callbacks[_]]) {
+ if(compareAndSet(state, if (state ne Noop) concatCallbacks(callbacks, state.asInstanceOf[Callbacks[T]]) else callbacks)) callbacks
+ else dispatchOrAddCallbacks(get(), callbacks)
+ } else /*if (state.isInstanceOf[Link[T]])*/ {
+ val p = state.asInstanceOf[Link[T]].promise(this)
+ p.dispatchOrAddCallbacks(p.get(), callbacks)
+ }
+
+ // IMPORTANT: Noop should never be passed in here, neither as left OR as right
+ @tailrec private[this] final def concatCallbacks(left: Callbacks[T], right: Callbacks[T]): Callbacks[T] =
+ if (left.isInstanceOf[Transformation[T,_]]) new ManyCallbacks[T](left.asInstanceOf[Transformation[T,_]], right)
+ else /*if (left.isInstanceOf[ManyCallbacks[T]) */ { // This should only happen when linking
+ val m = left.asInstanceOf[ManyCallbacks[T]]
+ concatCallbacks(m.rest, new ManyCallbacks(m.first, right))
+ }
+
+ // IMPORTANT: Noop should not be passed in here, `callbacks` cannot be null
+ @tailrec
+ private[this] final def submitWithValue(callbacks: Callbacks[T], resolved: Try[T]): Unit =
+ if(callbacks.isInstanceOf[ManyCallbacks[T]]) {
+ val m: ManyCallbacks[T] = callbacks.asInstanceOf[ManyCallbacks[T]]
+ m.first.submitWithValue(resolved)
+ submitWithValue(m.rest, resolved)
+ } else {
+ callbacks.asInstanceOf[Transformation[T, _]].submitWithValue(resolved)
+ }
+
+ /** Link this promise to the root of another promise.
+ */
+ @tailrec private[concurrent] final def linkRootOf(target: DefaultPromise[T], link: Link[T]): Unit =
+ if (this ne target) {
+ val state = get()
+ if (state.isInstanceOf[Try[_]]) {
+ if(!target.tryComplete0(target.get(), state.asInstanceOf[Try[T]]))
+ throw new IllegalStateException("Cannot link completed promises together")
+ } else if (state.isInstanceOf[Callbacks[_]]) {
+ val l = if (link ne null) link else new Link(target)
+ val p = l.promise(this)
+ if ((this ne p) && compareAndSet(state, l)) {
+ if (state ne Noop) p.dispatchOrAddCallbacks(p.get(), state.asInstanceOf[Callbacks[T]]) // Noop-check is important here
+ } else linkRootOf(p, l)
+ } else /* if (state.isInstanceOf[Link[T]]) */
+ state.asInstanceOf[Link[T]].promise(this).linkRootOf(target, link)
+ }
+
+ /**
+ * Unlinks (removes) the link chain if the root is discovered to be already completed,
+ * and completes the `owner` with that result.
+ **/
+ @tailrec private[concurrent] final def unlink(resolved: Try[T]): Unit = {
+ val state = get()
+ if (state.isInstanceOf[Link[_]]) {
+ val next = if (compareAndSet(state, resolved)) state.asInstanceOf[Link[T]].get() else this
+ next.unlink(resolved)
+ } else tryComplete0(state, resolved)
+ }
+
+ @throws[IOException]
+ private def writeObject(out: ObjectOutputStream): Unit =
+ throw new NotSerializableException("Promises and Futures cannot be serialized")
+
+ @throws[IOException]
+ @throws[ClassNotFoundException]
+ private def readObject(in: ObjectInputStream): Unit =
+ throw new NotSerializableException("Promises and Futures cannot be deserialized")
+ }
+
+ // Constant byte tags for unpacking transformation function inputs or outputs
+ // These need to be Ints to get compiled into constants.
+ final val Xform_noop = 0
+ final val Xform_map = 1
+ final val Xform_flatMap = 2
+ final val Xform_transform = 3
+ final val Xform_transformWith = 4
+ final val Xform_foreach = 5
+ final val Xform_onComplete = 6
+ final val Xform_recover = 7
+ final val Xform_recoverWith = 8
+ final val Xform_filter = 9
+ final val Xform_collect = 10
+
+ /* Marker trait
+ */
+ sealed trait Callbacks[-T]
+
+ final class ManyCallbacks[-T](final val first: Transformation[T,_], final val rest: Callbacks[T]) extends Callbacks[T] {
+ override final def toString: String = "ManyCallbacks"
+ }
+
+ private[this] final val Noop = new Transformation[Nothing, Nothing](Xform_noop, null, ExecutionContext.parasitic)
+
+ /**
+ * A Transformation[F, T] receives an F (it is a Callback[F]) and applies a transformation function to that F,
+ * Producing a value of type T (it is a Promise[T]).
+ * In order to conserve allocations, indirections, and avoid introducing bi/mega-morphicity the transformation
+ * function's type parameters are erased, and the _xform tag will be used to reify them.
+ **/
+ final class Transformation[-F, T] private[this] (
+ private[this] final var _fun: Any => Any,
+ private[this] final var _ec: ExecutionContext,
+ private[this] final var _arg: Try[F],
+ private[this] final val _xform: Int
+ ) extends DefaultPromise[T]() with Callbacks[F] with Runnable with Batchable {
+ final def this(xform: Int, f: _ => _, ec: ExecutionContext) =
+ this(f.asInstanceOf[Any => Any], ec.prepare(): @nowarn("cat=deprecation"), null, xform)
+
+ final def benefitsFromBatching: Boolean = _xform != Xform_onComplete && _xform != Xform_foreach
+
+ // Gets invoked when a value is available, schedules it to be run():ed by the ExecutionContext
+ // submitWithValue *happens-before* run(), through ExecutionContext.execute.
+ // Invariant: _arg is `null`, _ec is non-null. `this` ne Noop.
+ // requireNonNull(resolved) will hold as guarded by `resolve`
+ final def submitWithValue(resolved: Try[F]): this.type = {
+ _arg = resolved
+ val e = _ec
+ try e.execute(this) /* Safe publication of _arg, _fun, _ec */
+ catch {
+ case t: Throwable =>
+ _fun = null // allow to GC
+ _arg = null // see above
+ _ec = null // see above again
+ handleFailure(t, e)
+ }
+
+ this
+ }
+
+ private[this] final def handleFailure(t: Throwable, e: ExecutionContext): Unit = {
+ val wasInterrupted = t.isInstanceOf[InterruptedException]
+ if (wasInterrupted || NonFatal(t)) {
+ val completed = tryComplete0(get(), resolve(Failure(t)))
+ if (completed && wasInterrupted) Thread.currentThread.interrupt()
+
+ // Report or rethrow failures which are unlikely to otherwise be noticed
+ if (_xform == Xform_foreach || _xform == Xform_onComplete || !completed)
+ e.reportFailure(t)
+ } else throw t
+ }
+
+ // Gets invoked by the ExecutionContext, when we have a value to transform.
+ override final def run(): Unit = {
+ val v = _arg
+ val fun = _fun
+ val ec = _ec
+ _fun = null // allow to GC
+ _arg = null // see above
+ _ec = null // see above
+ try {
+ val resolvedResult: Try[_] =
+ (_xform: @switch) match {
+ case Xform_noop =>
+ null
+ case Xform_map =>
+ if (v.isInstanceOf[Success[F]]) Success(fun(v.get)) else v // Faster than `resolve(v map fun)`
+ case Xform_flatMap =>
+ if (v.isInstanceOf[Success[F]]) {
+ val f = fun(v.get)
+ if (f.isInstanceOf[DefaultPromise[_]]) f.asInstanceOf[DefaultPromise[T]].linkRootOf(this, null) else completeWith(f.asInstanceOf[Future[T]])
+ null
+ } else v
+ case Xform_transform =>
+ resolve(fun(v).asInstanceOf[Try[T]])
+ case Xform_transformWith =>
+ val f = fun(v)
+ if (f.isInstanceOf[DefaultPromise[_]]) f.asInstanceOf[DefaultPromise[T]].linkRootOf(this, null) else completeWith(f.asInstanceOf[Future[T]])
+ null
+ case Xform_foreach =>
+ v.foreach(fun)
+ null
+ case Xform_onComplete =>
+ fun(v)
+ null
+ case Xform_recover =>
+ if (v.isInstanceOf[Failure[_]]) resolve(v.recover(fun.asInstanceOf[PartialFunction[Throwable, F]])) else v //recover F=:=T
+ case Xform_recoverWith =>
+ if (v.isInstanceOf[Failure[F]]) {
+ val f = fun.asInstanceOf[PartialFunction[Throwable, Future[T]]].applyOrElse(v.asInstanceOf[Failure[F]].exception, Future.recoverWithFailed)
+ if (f ne Future.recoverWithFailedMarker) {
+ if (f.isInstanceOf[DefaultPromise[T]]) f.asInstanceOf[DefaultPromise[T]].linkRootOf(this, null) else completeWith(f.asInstanceOf[Future[T]])
+ null
+ } else v
+ } else v
+ case Xform_filter =>
+ if (v.isInstanceOf[Failure[F]] || fun.asInstanceOf[F => Boolean](v.get)) v else Future.filterFailure
+ case Xform_collect =>
+ if (v.isInstanceOf[Success[F]]) Success(fun.asInstanceOf[PartialFunction[F, T]].applyOrElse(v.get, Future.collectFailed)) else v
+ case _ =>
+ Failure(new IllegalStateException("BUG: encountered transformation promise with illegal type: " + _xform)) // Safe not to `resolve`
+ }
+ if (resolvedResult ne null)
+ tryComplete0(get(), resolvedResult.asInstanceOf[Try[T]]) // T is erased anyway so we won't have any use for it above
+ } catch {
+ case t: Throwable => handleFailure(t, ec)
+ }
+ }
+ }
+}
diff --git a/library/src/scala/concurrent/package.scala b/library/src/scala/concurrent/package.scala
new file mode 100644
index 000000000000..d648a1c90a15
--- /dev/null
+++ b/library/src/scala/concurrent/package.scala
@@ -0,0 +1,204 @@
+/*
+ * 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
+
+import scala.concurrent.duration.Duration
+import scala.annotation.implicitNotFound
+
+/** This package object contains primitives for concurrent and parallel programming.
+ *
+ * == Guide ==
+ *
+ * A more detailed guide to Futures and Promises, including discussion and examples
+ * can be found at
+ * [[https://docs.scala-lang.org/overviews/core/futures.html]].
+ *
+ * == Common Imports ==
+ *
+ * When working with Futures, you will often find that importing the whole concurrent
+ * package is convenient:
+ *
+ * {{{
+ * import scala.concurrent._
+ * }}}
+ *
+ * When using things like `Future`s, it is often required to have an implicit `ExecutionContext`
+ * in scope. The general advice for these implicits are as follows.
+ *
+ * If the code in question is a class or method definition, and no `ExecutionContext` is available,
+ * request one from the caller by adding an implicit parameter list:
+ *
+ * {{{
+ * def myMethod(myParam: MyType)(implicit ec: ExecutionContext) = …
+ * //Or
+ * class MyClass(myParam: MyType)(implicit ec: ExecutionContext) { … }
+ * }}}
+ *
+ * This allows the caller of the method, or creator of the instance of the class, to decide which
+ * `ExecutionContext` should be used.
+ *
+ * For typical REPL usage and experimentation, importing the global `ExecutionContext` is often desired.
+ *
+ * {{{
+ * import scala.concurrent.ExcutionContext.Implicits.global
+ * }}}
+ *
+ * == Specifying Durations ==
+ *
+ * Operations often require a duration to be specified. A duration DSL is available
+ * to make defining these easier:
+ *
+ * {{{
+ * import scala.concurrent.duration._
+ * val d: Duration = 10.seconds
+ * }}}
+ *
+ * == Using Futures For Non-blocking Computation ==
+ *
+ * Basic use of futures is easy with the factory method on Future, which executes a
+ * provided function asynchronously, handing you back a future result of that function
+ * without blocking the current thread. In order to create the Future you will need
+ * either an implicit or explicit ExecutionContext to be provided:
+ *
+ * {{{
+ * import scala.concurrent._
+ * import ExecutionContext.Implicits.global // implicit execution context
+ *
+ * val firstZebra: Future[Int] = Future {
+ * val words = Files.readAllLines("/etc/dictionaries-common/words").asScala
+ * words.indexOfSlice("zebra")
+ * }
+ * }}}
+ *
+ * == Avoid Blocking ==
+ *
+ * Although blocking is possible in order to await results (with a mandatory timeout duration):
+ *
+ * {{{
+ * import scala.concurrent.duration._
+ * Await.result(firstZebra, 10.seconds)
+ * }}}
+ *
+ * and although this is sometimes necessary to do, in particular for testing purposes, blocking
+ * in general is discouraged when working with Futures and concurrency in order to avoid
+ * potential deadlocks and improve performance. Instead, use callbacks or combinators to
+ * remain in the future domain:
+ *
+ * {{{
+ * val animalRange: Future[Int] = for {
+ * aardvark <- firstAardvark
+ * zebra <- firstZebra
+ * } yield zebra - aardvark
+ *
+ * animalRange.onSuccess {
+ * case x if x > 500000 => println("It's a long way from Aardvark to Zebra")
+ * }
+ * }}}
+ */
+package object concurrent {
+ type ExecutionException = java.util.concurrent.ExecutionException
+ type CancellationException = java.util.concurrent.CancellationException
+ type TimeoutException = java.util.concurrent.TimeoutException
+
+ /** Used to designate a piece of code which potentially blocks, allowing the current [[BlockContext]] to adjust
+ * the runtime's behavior.
+ * Properly marking blocking code may improve performance or avoid deadlocks.
+ *
+ * Blocking on an [[Awaitable]] should be done using [[Await.result]] instead of `blocking`.
+ *
+ * @param body A piece of code which contains potentially blocking or long running calls.
+ * @throws CancellationException if the computation was cancelled
+ * @throws InterruptedException in the case that a wait within the blocking `body` was interrupted
+ */
+ @throws(classOf[Exception])
+ final def blocking[T](body: => T): T = BlockContext.current.blockOn(body)(scala.concurrent.AwaitPermission)
+}
+
+package concurrent {
+ /**
+ * This marker trait is used by [[Await]] to ensure that [[Awaitable.ready]] and [[Awaitable.result]]
+ * are not directly called by user code. An implicit instance of this trait is only available when
+ * user code is currently calling the methods on [[Await]].
+ */
+ @implicitNotFound("Don't call `Awaitable` methods directly, use the `Await` object.")
+ sealed trait CanAwait
+
+ /**
+ * Internal usage only, implementation detail.
+ */
+ private[concurrent] object AwaitPermission extends CanAwait
+
+ /**
+ * `Await` is what is used to ensure proper handling of blocking for `Awaitable` instances.
+ *
+ * While occasionally useful, e.g. for testing, it is recommended that you avoid Await whenever possible—
+ * instead favoring combinators and/or callbacks.
+ * Await's `result` and `ready` methods will block the calling thread's execution until they return,
+ * which will cause performance degradation, and possibly, deadlock issues.
+ */
+ object Await {
+ /**
+ * Await the "completed" state of an `Awaitable`.
+ *
+ * Although this method is blocking, the internal use of [[scala.concurrent.blocking blocking]] ensures that
+ * the underlying [[ExecutionContext]] is given an opportunity to properly manage the blocking.
+ *
+ * WARNING: It is strongly discouraged to supply lengthy timeouts since the progress of the calling thread will be
+ * suspended—blocked—until either the `Awaitable` becomes ready or the timeout expires.
+ *
+ * @param awaitable
+ * the `Awaitable` to be awaited
+ * @param atMost
+ * maximum wait time, which may be negative (no waiting is done),
+ * [[scala.concurrent.duration.Duration.Inf Duration.Inf]] for unbounded waiting, or a finite positive
+ * duration
+ * @return the `awaitable`
+ * @throws InterruptedException if the current thread is interrupted while waiting
+ * @throws TimeoutException if after waiting for the specified time this `Awaitable` is still not ready
+ * @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]]
+ */
+ @throws(classOf[TimeoutException])
+ @throws(classOf[InterruptedException])
+ final def ready[T](awaitable: Awaitable[T], atMost: Duration): awaitable.type = awaitable match {
+ case f: Future[T] if f.isCompleted => awaitable.ready(atMost)(AwaitPermission)
+ case _ => blocking(awaitable.ready(atMost)(AwaitPermission))
+ }
+
+ /**
+ * Await and return the result (of type `T`) of an `Awaitable`.
+ *
+ * Although this method is blocking, the internal use of [[scala.concurrent.blocking blocking]] ensures that
+ * the underlying [[ExecutionContext]] is given an opportunity to properly manage the blocking.
+ *
+ * WARNING: It is strongly discouraged to supply lengthy timeouts since the progress of the calling thread will be
+ * suspended—blocked—until either the `Awaitable` has a result or the timeout expires.
+ *
+ * @param awaitable
+ * the `Awaitable` to be awaited
+ * @param atMost
+ * maximum wait time, which may be negative (no waiting is done),
+ * [[scala.concurrent.duration.Duration.Inf Duration.Inf]] for unbounded waiting, or a finite positive
+ * duration
+ * @return the result value if `awaitable` is completed within the specific maximum wait time
+ * @throws InterruptedException if the current thread is interrupted while waiting
+ * @throws TimeoutException if after waiting for the specified time `awaitable` is still not ready
+ * @throws IllegalArgumentException if `atMost` is [[scala.concurrent.duration.Duration.Undefined Duration.Undefined]]
+ */
+ @throws(classOf[TimeoutException])
+ @throws(classOf[InterruptedException])
+ final def result[T](awaitable: Awaitable[T], atMost: Duration): T = awaitable match {
+ case f: Future[T] if f.isCompleted => f.result(atMost)(AwaitPermission)
+ case _ => blocking(awaitable.result(atMost)(AwaitPermission))
+ }
+ }
+}
diff --git a/library/src/scala/deprecated.scala b/library/src/scala/deprecated.scala
new file mode 100644
index 000000000000..bb1ded88437c
--- /dev/null
+++ b/library/src/scala/deprecated.scala
@@ -0,0 +1,64 @@
+/*
+ * 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
+
+import scala.annotation.meta._
+
+/** An annotation that designates that a definition is deprecated.
+ * A deprecation warning is issued upon usage of the annotated definition.
+ *
+ * Library authors should state the library's deprecation policy in their documentation to give
+ * developers guidance on how long a deprecated definition will be preserved.
+ *
+ * Library authors should prepend the name of their library to the version number to help
+ * developers distinguish deprecations coming from different libraries:
+ *
+ * {{{
+ * @deprecated("this method will be removed", "FooLib 12.0")
+ * def oldMethod(x: Int) = ...
+ * }}}
+ *
+ * The compiler will emit deprecation warnings grouped by library and version:
+ *
+ * {{{
+ * oldMethod(1)
+ * oldMethod(2)
+ * aDeprecatedMethodFromLibraryBar(3, 4)
+ *
+ * // warning: there was one deprecation warning (since BarLib 3.2)
+ * // warning: there were two deprecation warnings (since FooLib 12.0)
+ * // warning: there were three deprecation warnings in total; re-run with -deprecation for details
+ * }}}
+ *
+ * The Scala compiler also warns about using definitions annotated with [[java.lang.Deprecated]]. However it is
+ * recommended to use the Scala `@deprecated` annotation in Scala code because it allows providing a deprecation message.
+ *
+ * '''`@deprecated` in the Scala language and its standard library'''
+ *
+ * A deprecated element of the Scala language or a definition in the Scala standard library will
+ * be preserved at least for the current major version.
+ *
+ * This means that an element deprecated in some 2.13.x release will be preserved in
+ * all 2.13.x releases, but may be removed in the future. (A deprecated element
+ * might be kept longer to ease migration, but developers should not rely on this.)
+ *
+ * @see The official documentation on [[https://www.scala-lang.org/news/2.11.0/#binary-compatibility binary compatibility]].
+ * @param message the message to print during compilation if the definition is accessed
+ * @param since a string identifying the first version in which the definition was deprecated
+ * @see [[scala.deprecatedInheritance]]
+ * @see [[scala.deprecatedOverriding]]
+ * @see [[scala.deprecatedName]]
+ */
+@getter @setter @beanGetter @beanSetter @field
+@deprecatedInheritance("Scheduled for being final in the future", "2.13.0")
+class deprecated(message: String = "", since: String = "") extends scala.annotation.ConstantAnnotation
diff --git a/library/src/scala/deprecatedInheritance.scala b/library/src/scala/deprecatedInheritance.scala
new file mode 100644
index 000000000000..f95b3ef100a0
--- /dev/null
+++ b/library/src/scala/deprecatedInheritance.scala
@@ -0,0 +1,50 @@
+/*
+ * 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
+
+import scala.annotation.meta._
+
+/** An annotation that designates that inheriting from a class is deprecated.
+ *
+ * This is usually done to warn about a non-final class being made final in a future version.
+ * Sub-classing such a class then generates a warning.
+ *
+ * No warnings are generated if the subclass is in the same compilation unit.
+ *
+ * Library authors should state the library's deprecation policy in their documentation to give
+ * developers guidance on when a type annotated with `@deprecatedInheritance` will be `final`ized.
+ *
+ * Library authors should prepend the name of their library to the version number to help
+ * developers distinguish deprecations coming from different libraries:
+ *
+ * {{{
+ * @deprecatedInheritance("this class will be made final", "FooLib 12.0")
+ * class Foo
+ * }}}
+ *
+ * {{{
+ * val foo = new Foo // no deprecation warning
+ * class Bar extends Foo
+ * // warning: inheritance from class Foo is deprecated (since FooLib 12.0): this class will be made final
+ * // class Bar extends Foo
+ * // ^
+ * }}}
+ *
+ * @param message the message to print during compilation if the class was sub-classed
+ * @param since a string identifying the first version in which inheritance was deprecated
+ * @see [[scala.deprecated]]
+ * @see [[scala.deprecatedOverriding]]
+ * @see [[scala.deprecatedName]]
+ */
+@getter @setter @beanGetter @beanSetter
+final class deprecatedInheritance(message: String = "", since: String = "") extends scala.annotation.ConstantAnnotation
diff --git a/library/src/scala/deprecatedName.scala b/library/src/scala/deprecatedName.scala
new file mode 100644
index 000000000000..1a8341b8d498
--- /dev/null
+++ b/library/src/scala/deprecatedName.scala
@@ -0,0 +1,53 @@
+/*
+ * 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
+
+import scala.annotation.meta._
+
+/** An annotation that designates that the name of a parameter is deprecated.
+ *
+ * Using this name in a named argument generates a deprecation warning.
+ *
+ * If the `name` is omitted, then using the canonical name is deprecated.
+ * In that case, lints such as `-Xlint:named-booleans` which encourage
+ * the use of a name will not warn.
+ *
+ * Library authors should state the library's deprecation policy in their documentation to give
+ * developers guidance on how long a deprecated name will be preserved.
+ *
+ * Library authors should prepend the name of their library to the version number to help
+ * developers distinguish deprecations coming from different libraries:
+ *
+ * {{{
+ * def inc(x: Int, @deprecatedName("y", "FooLib 12.0") n: Int): Int = x + n
+ * inc(1, y = 2)
+ * }}}
+ * will produce the following warning:
+ * {{{
+ * warning: the parameter name y is deprecated (since FooLib 12.0): use n instead
+ * inc(1, y = 2)
+ * ^
+ * }}}
+ *
+ * @see [[scala.deprecated]]
+ * @see [[scala.deprecatedInheritance]]
+ * @see [[scala.deprecatedOverriding]]
+ */
+@param
+@deprecatedInheritance("Scheduled for being final in the future", "2.13.0")
+class deprecatedName(name: String = "", since: String = "") extends scala.annotation.StaticAnnotation {
+ // at the time we remove these constructors, we should also change this from a StaticAnnotation to
+ // a ConstantAnnotation; for now, the presence of auxiliary constructors blocks that change
+ @deprecated("The parameter name should be a String, not a symbol.", "2.13.0") def this(name: Symbol, since: String) = this(name.name, since)
+ @deprecated("The parameter name should be a String, not a symbol.", "2.13.0") def this(name: Symbol) = this(name.name, "")
+}
diff --git a/library/src/scala/deprecatedOverriding.scala b/library/src/scala/deprecatedOverriding.scala
new file mode 100644
index 000000000000..0268bee15a10
--- /dev/null
+++ b/library/src/scala/deprecatedOverriding.scala
@@ -0,0 +1,52 @@
+/*
+ * 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
+
+import scala.annotation.meta._
+
+/** An annotation that designates that overriding a member is deprecated.
+ *
+ * Overriding such a member in a sub-class then generates a warning.
+ *
+ * Library authors should state the library's deprecation policy in their documentation to give
+ * developers guidance on when a method annotated with `@deprecatedOverriding` will be `final`ized.
+ *
+ * Library authors should prepend the name of their library to the version number to help
+ * developers distinguish deprecations coming from different libraries:
+ *
+ * {{{
+ * class Foo {
+ * @deprecatedOverriding("this method will be made final", "FooLib 12.0")
+ * def add(x: Int, y: Int) = x + y
+ * }
+ * }}}
+ *
+ * {{{
+ * class Bar extends Foo // no deprecation warning
+ * class Baz extends Foo {
+ * override def add(x: Int, y: Int) = x - y
+ * }
+ * // warning: overriding method add in class Foo is deprecated (since FooLib 12.0): this method will be made final
+ * // override def add(x: Int, y: Int) = x - y
+ * // ^
+ * }}}
+ *
+ * @param message the message to print during compilation if the member was overridden
+ * @param since a string identifying the first version in which overriding was deprecated
+ * @see [[scala.deprecated]]
+ * @see [[scala.deprecatedInheritance]]
+ * @see [[scala.deprecatedName]]
+ */
+@getter @setter @beanGetter @beanSetter
+@deprecatedInheritance("Scheduled for being final in the future", "2.13.0")
+class deprecatedOverriding(message: String = "", since: String = "") extends scala.annotation.ConstantAnnotation
diff --git a/library/src/scala/inline.scala b/library/src/scala/inline.scala
new file mode 100644
index 000000000000..d7d7b55d8d3c
--- /dev/null
+++ b/library/src/scala/inline.scala
@@ -0,0 +1,52 @@
+/*
+ * 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
+
+/**
+ * An annotation for methods that the optimizer should inline.
+ *
+ * Note that by default, the Scala optimizer is disabled and no callsites are inlined. See
+ * `-opt:help` and [[https://docs.scala-lang.org/overviews/compiler-options/optimizer.html the overview document]]
+ * for information on how to enable the optimizer and inliner.
+ *
+ * When inlining is enabled, the inliner will always try to inline methods or callsites annotated
+ * `@inline` (under the condition that inlining from the defining class is allowed).
+ * If inlining is not possible, for example because the method is not
+ * final, an optimizer warning will be issued. See `-Wopt:help` for details.
+ *
+ * Examples:
+ *
+ * {{{
+ * @inline final def f1(x: Int) = x
+ * @noinline final def f2(x: Int) = x
+ * final def f3(x: Int) = x
+ *
+ * def t1 = f1(1) // inlined if possible
+ * def t2 = f2(1) // not inlined
+ * def t3 = f3(1) // may be inlined (the inliner heuristics can select the callsite)
+ * def t4 = f1(1): @noinline // not inlined (override at callsite)
+ * def t5 = f2(1): @inline // inlined if possible (override at callsite)
+ * def t6 = f3(1): @inline // inlined if possible
+ * def t7 = f3(1): @noinline // not inlined
+ * }
+ * }}}
+ *
+ * Note: parentheses are required when annotating a callsite within a larger expression.
+ *
+ * {{{
+ * def t1 = f1(1) + f1(1): @noinline // equivalent to (f1(1) + f1(1)): @noinline
+ * def t2 = f1(1) + (f1(1): @noinline) // the second call to f1 is not inlined
+ * }}}
+ */
+@deprecatedInheritance("Scheduled for being final in the future", "2.13.0")
+class inline extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/io/AnsiColor.scala b/library/src/scala/io/AnsiColor.scala
new file mode 100644
index 000000000000..ca27dac45a6b
--- /dev/null
+++ b/library/src/scala/io/AnsiColor.scala
@@ -0,0 +1,176 @@
+/*
+ * 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 io
+
+/** ANSI escape codes providing control over text formatting and color on supporting text terminals.
+ *
+ * ==ANSI Style and Control Codes==
+ *
+ * This group of escape codes provides control over text styling. For example, to turn on reverse video with bold and
+ * then turn off all styling embed these codes,
+ *
+ * {{{
+ * import io.AnsiColor._
+ *
+ * object ColorDemo extends App {
+ *
+ * println(s"\${REVERSED}\${BOLD}Hello 1979!\${RESET}")
+ * }
+ * }}}
+ *
+ * ==Foreground and Background Colors==
+ *
+ * Embedding ANSI color codes in text output will control the text foreground and background colors.
+ *
+ *
+ *
Foreground
Background
+ *
BLACK
BLACK_B
+ *
RED
RED_B
+ *
GREEN
GREEN_B
+ *
YELLOW
YELLOW_B
+ *
BLUE
BLUE_B
+ *
MAGENTA
MAGENTA_B
+ *
CYAN
CYAN_B
+ *
WHITE
WHITE_B
+ *
+ *
+ * @groupname style-control ANSI Style and Control Codes
+ * @groupprio style-control 101
+ *
+ * @groupname color-black ANSI Black
+ * @groupdesc color-black
+ * @groupprio color-white 180
+ */
+trait AnsiColor {
+ /** Foreground color for ANSI black
+ * @group color-black
+ */
+ final val BLACK = "\u001b[30m"
+ /** Foreground color for ANSI red
+ * @group color-red
+ */
+ final val RED = "\u001b[31m"
+ /** Foreground color for ANSI green
+ * @group color-green
+ */
+ final val GREEN = "\u001b[32m"
+ /** Foreground color for ANSI yellow
+ * @group color-yellow
+ */
+ final val YELLOW = "\u001b[33m"
+ /** Foreground color for ANSI blue
+ * @group color-blue
+ */
+ final val BLUE = "\u001b[34m"
+ /** Foreground color for ANSI magenta
+ * @group color-magenta
+ */
+ final val MAGENTA = "\u001b[35m"
+ /** Foreground color for ANSI cyan
+ * @group color-cyan
+ */
+ final val CYAN = "\u001b[36m"
+ /** Foreground color for ANSI white
+ * @group color-white
+ */
+ final val WHITE = "\u001b[37m"
+
+ /** Background color for ANSI black
+ * @group color-black
+ */
+ final val BLACK_B = "\u001b[40m"
+ /** Background color for ANSI red
+ * @group color-red
+ */
+ final val RED_B = "\u001b[41m"
+ /** Background color for ANSI green
+ * @group color-green
+ */
+ final val GREEN_B = "\u001b[42m"
+ /** Background color for ANSI yellow
+ * @group color-yellow
+ */
+ final val YELLOW_B = "\u001b[43m"
+ /** Background color for ANSI blue
+ * @group color-blue
+ */
+ final val BLUE_B = "\u001b[44m"
+ /** Background color for ANSI magenta
+ * @group color-magenta
+ */
+ final val MAGENTA_B = "\u001b[45m"
+ /** Background color for ANSI cyan
+ * @group color-cyan
+ */
+ final val CYAN_B = "\u001b[46m"
+ /** Background color for ANSI white
+ * @group color-white
+ */
+ final val WHITE_B = "\u001b[47m"
+
+ /** Reset ANSI styles
+ * @group style-control
+ */
+ final val RESET = "\u001b[0m"
+ /** ANSI bold
+ * @group style-control
+ */
+ final val BOLD = "\u001b[1m"
+ /** ANSI underlines
+ * @group style-control
+ */
+ final val UNDERLINED = "\u001b[4m"
+ /** ANSI blink
+ * @group style-control
+ */
+ final val BLINK = "\u001b[5m"
+ /** ANSI reversed
+ * @group style-control
+ */
+ final val REVERSED = "\u001b[7m"
+ /** ANSI invisible
+ * @group style-control
+ */
+ final val INVISIBLE = "\u001b[8m"
+}
+
+object AnsiColor extends AnsiColor { }
diff --git a/library/src/scala/io/BufferedSource.scala b/library/src/scala/io/BufferedSource.scala
new file mode 100644
index 000000000000..2369b528f8f7
--- /dev/null
+++ b/library/src/scala/io/BufferedSource.scala
@@ -0,0 +1,114 @@
+/*
+ * 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.io
+
+import java.io.{ InputStream, BufferedReader, InputStreamReader, PushbackReader }
+import Source.DefaultBufSize
+import scala.collection.{ Iterator, AbstractIterator }
+import scala.collection.mutable.StringBuilder
+
+/** This object provides convenience methods to create an iterable
+ * representation of a source file.
+ */
+class BufferedSource(inputStream: InputStream, bufferSize: Int)(implicit val codec: Codec) extends Source {
+ def this(inputStream: InputStream)(implicit codec: Codec) = this(inputStream, DefaultBufSize)(codec)
+ def reader() = new InputStreamReader(inputStream, codec.decoder)
+ def bufferedReader() = new BufferedReader(reader(), bufferSize)
+
+ // The same reader has to be shared between the iterators produced
+ // by iter and getLines. This is because calling hasNext can cause a
+ // block of data to be read from the stream, which will then be lost
+ // to getLines if it creates a new reader, even though next() was
+ // never called on the original.
+ private[this] var charReaderCreated = false
+ private[this] lazy val charReader = {
+ charReaderCreated = true
+ bufferedReader()
+ }
+
+ override val iter = (
+ Iterator
+ continually (codec wrap charReader.read())
+ takeWhile (_ != -1)
+ map (_.toChar)
+ )
+
+ private def decachedReader: BufferedReader = {
+ // Don't want to lose a buffered char sitting in iter either. Yes,
+ // this is ridiculous, but if I can't get rid of Source, and all the
+ // Iterator bits are designed into Source, and people create Sources
+ // in the repl, and the repl calls toString for the result line, and
+ // that calls hasNext to find out if they're empty, and that leads
+ // to chars being buffered, and no, I don't work here, they left a
+ // door unlocked.
+ // To avoid inflicting this silliness indiscriminately, we can
+ // skip it if the char reader was never created: and almost always
+ // it will not have been created, since getLines will be called
+ // immediately on the source.
+ if (charReaderCreated && iter.hasNext) {
+ val pb = new PushbackReader(charReader)
+ pb unread iter.next().toInt
+ new BufferedReader(pb, bufferSize)
+ }
+ else charReader
+ }
+
+
+ class BufferedLineIterator extends AbstractIterator[String] with Iterator[String] {
+ private[this] val lineReader = decachedReader
+ var nextLine: String = null
+
+ override def hasNext = {
+ if (nextLine == null)
+ nextLine = lineReader.readLine
+
+ nextLine != null
+ }
+ override def next(): String = {
+ val result = {
+ if (nextLine == null) lineReader.readLine
+ else try nextLine finally nextLine = null
+ }
+ if (result == null) Iterator.empty.next()
+ else result
+ }
+ }
+
+ override def getLines(): Iterator[String] = new BufferedLineIterator
+
+ /** Efficiently appends the entire remaining input.
+ *
+ * Note: This function may temporarily load the entire buffer into
+ * memory.
+ */
+ override def addString(sb: StringBuilder, start: String, sep: String, end: String): sb.type =
+ if (sep.isEmpty) {
+ val allReader = decachedReader
+ val buf = new Array[Char](bufferSize)
+ val jsb = sb.underlying
+
+ if (start.length != 0) jsb.append(start)
+ var n = allReader.read(buf)
+ while (n != -1) {
+ jsb.append(buf, 0, n)
+ n = allReader.read(buf)
+ }
+ if (end.length != 0) jsb.append(end)
+ sb
+ // This case is expected to be uncommon, so we're reusing code at
+ // the cost of temporary memory allocations.
+ // mkString will callback into BufferedSource.addString to read
+ // the Buffer into a String, and then we use StringOps.addString
+ // for the interspersing of sep.
+ } else mkString.addString(sb, start, sep, end)
+}
diff --git a/library/src/scala/io/Codec.scala b/library/src/scala/io/Codec.scala
new file mode 100644
index 000000000000..a6eeab50b299
--- /dev/null
+++ b/library/src/scala/io/Codec.scala
@@ -0,0 +1,136 @@
+/*
+ * 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 io
+
+import java.nio.charset.{CharacterCodingException, Charset, CharsetDecoder, CharsetEncoder, CodingErrorAction => Action}
+import java.nio.charset.StandardCharsets.{ISO_8859_1, UTF_8}
+import scala.annotation.migration
+import scala.language.implicitConversions
+
+// Some notes about encodings for use in refining this implementation.
+//
+// Emails: encoding recorded in header, e.g. Content-Type: charset= "iso-8859-1"
+// HTML: optional content-type meta tag.
+//
+// XML: optional encoding parameter.
+//
+//
+// MacRoman vs. UTF-8: see https://groups.google.com/d/msg/jruby-developers/-qtwRhoE1WM/whSPVpTNV28J
+// -Dfile.encoding: see https://bugs.java.com/view_bug.do?bug_id=4375816
+
+/** A class for character encoding/decoding preferences.
+ *
+ */
+class Codec(val charSet: Charset) {
+ type Configure[T] = (T => T, Boolean)
+ type Handler = CharacterCodingException => Int
+
+ // these variables allow configuring the Codec object, and then
+ // all decoders and encoders retrieved from it will use these settings.
+ private[this] var _onMalformedInput: Action = null
+ private[this] var _onUnmappableCharacter: Action = null
+ private[this] var _encodingReplacement: Array[Byte] = null
+ private[this] var _decodingReplacement: String = null
+ private[this] var _onCodingException: Handler = e => throw e
+
+ /** The name of the Codec. */
+ override def toString = name
+
+ // these methods can be chained to configure the variables above
+ def onMalformedInput(newAction: Action): this.type = { _onMalformedInput = newAction ; this }
+ def onUnmappableCharacter(newAction: Action): this.type = { _onUnmappableCharacter = newAction ; this }
+ def decodingReplaceWith(newReplacement: String): this.type = { _decodingReplacement = newReplacement ; this }
+ def encodingReplaceWith(newReplacement: Array[Byte]): this.type = { _encodingReplacement = newReplacement ; this }
+ def onCodingException(handler: Handler): this.type = { _onCodingException = handler ; this }
+
+ def name = charSet.name
+ def encoder: CharsetEncoder = {
+ val enc = charSet.newEncoder()
+ if (_onMalformedInput ne null) enc onMalformedInput _onMalformedInput
+ if (_onUnmappableCharacter ne null) enc onUnmappableCharacter _onUnmappableCharacter
+ if (_encodingReplacement ne null) enc replaceWith _encodingReplacement
+ enc
+ }
+ def decoder: CharsetDecoder = {
+ val dec = charSet.newDecoder()
+ if (_onMalformedInput ne null) dec onMalformedInput _onMalformedInput
+ if (_onUnmappableCharacter ne null) dec onUnmappableCharacter _onUnmappableCharacter
+ if (_decodingReplacement ne null) dec replaceWith _decodingReplacement
+ dec
+ }
+
+ def wrap(body: => Int): Int =
+ try body catch { case e: CharacterCodingException => _onCodingException(e) }
+}
+
+trait LowPriorityCodecImplicits {
+ self: Codec.type =>
+
+ /** The Codec of Last Resort. */
+ implicit lazy val fallbackSystemCodec: Codec = defaultCharsetCodec
+}
+
+object Codec extends LowPriorityCodecImplicits {
+ final val ISO8859: Codec = Codec(ISO_8859_1)
+ final val UTF8: Codec = Codec(UTF_8)
+
+ /** Optimistically these two possible defaults will be the same thing.
+ * In practice this is not necessarily true, and in fact Sun classifies
+ * the fact that you can influence anything at all via -Dfile.encoding
+ * as an accident, with any anomalies considered "not a bug".
+ */
+ def defaultCharsetCodec: Codec = apply(Charset.defaultCharset)
+ def fileEncodingCodec: Codec = apply(scala.util.Properties.encodingString)
+ def default: Codec = defaultCharsetCodec
+
+ def apply(encoding: String): Codec = new Codec(Charset forName encoding)
+ def apply(charSet: Charset): Codec = new Codec(charSet)
+ def apply(decoder: CharsetDecoder): Codec = {
+ val _decoder = decoder
+ new Codec(decoder.charset()) { override def decoder = _decoder }
+ }
+
+ @migration("This method was previously misnamed `toUTF8`. Converts from Array[Byte] to Array[Char].", "2.9.0")
+ def fromUTF8(bytes: Array[Byte]): Array[Char] = fromUTF8(bytes, 0, bytes.length)
+ def fromUTF8(bytes: Array[Byte], offset: Int, len: Int): Array[Char] = {
+ val bbuffer = java.nio.ByteBuffer.wrap(bytes, offset, len)
+ val cbuffer = UTF8.charSet decode bbuffer
+ val chars = new Array[Char](cbuffer.remaining())
+ cbuffer get chars
+
+ chars
+ }
+
+ @migration("This method was previously misnamed `fromUTF8`. Converts from character sequence to Array[Byte].", "2.9.0")
+ def toUTF8(cs: CharSequence): Array[Byte] = {
+ val cbuffer = java.nio.CharBuffer.wrap(cs, 0, cs.length)
+ val bbuffer = UTF8.charSet encode cbuffer
+ val bytes = new Array[Byte](bbuffer.remaining())
+ bbuffer get bytes
+
+ bytes
+ }
+ def toUTF8(chars: Array[Char], offset: Int, len: Int): Array[Byte] = {
+ val cbuffer = java.nio.CharBuffer.wrap(chars, offset, len)
+ val bbuffer = UTF8.charSet encode cbuffer
+ val bytes = new Array[Byte](bbuffer.remaining())
+ bbuffer get bytes
+
+ bytes
+ }
+
+ implicit def string2codec(s: String): Codec = apply(s)
+ implicit def charset2codec(c: Charset): Codec = apply(c)
+ implicit def decoder2codec(cd: CharsetDecoder): Codec = apply(cd)
+}
diff --git a/library/src/scala/io/Position.scala b/library/src/scala/io/Position.scala
new file mode 100644
index 000000000000..5a0a4aecdc31
--- /dev/null
+++ b/library/src/scala/io/Position.scala
@@ -0,0 +1,84 @@
+/*
+ * 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 io
+
+import annotation.nowarn
+
+/** The object Position provides convenience methods to encode
+ * line and column number in one single integer. The encoded line
+ * (column) numbers range from 0 to `LINE_MASK` (`COLUMN_MASK`),
+ * where `0` indicates that the line (column) is undefined and
+ * `1` represents the first line (column).
+ *
+ * Line (Column) numbers greater than `LINE_MASK` (`COLUMN_MASK`) are
+ * replaced by `LINE_MASK` (`COLUMN_MASK`). Furthermore, if the encoded
+ * line number is `LINE_MASK`, the column number is always set to 0.
+ *
+ * The following properties hold:
+ *
+ * the undefined position is 0: `encode(0,0) == 0`
+ * encodings are non-negative : `encode(line,column) >= 0`
+ * position order is preserved:
+ * {{{
+ * (line1 <= line2) || (line1 == line2 && column1 <= column2)
+ * }}}
+ * implies
+ * {{{
+ * encode(line1,column1) <= encode(line2,column2)
+ * }}}
+ */
+@deprecated("this class will be removed", "2.10.0")
+private[scala] abstract class Position {
+ /** Definable behavior for overflow conditions.
+ */
+ def checkInput(line: Int, column: Int): Unit
+
+ /** Number of bits used to encode the line number */
+ final val LINE_BITS = 20
+ /** Number of bits used to encode the column number */
+ final val COLUMN_BITS = 31 - LINE_BITS // no negatives => 31
+ /** Mask to decode the line number */
+ final val LINE_MASK = (1 << LINE_BITS) - 1
+ /** Mask to decode the column number */
+ final val COLUMN_MASK = (1 << COLUMN_BITS) - 1
+
+ /** Encodes a position into a single integer. */
+ final def encode(line: Int, column: Int): Int = {
+ checkInput(line, column)
+
+ if (line >= LINE_MASK)
+ LINE_MASK << COLUMN_BITS
+ else
+ (line << COLUMN_BITS) | scala.math.min(COLUMN_MASK, column)
+ }
+
+ /** Returns the line number of the encoded position. */
+ final def line(pos: Int): Int = (pos >> COLUMN_BITS) & LINE_MASK
+
+ /** Returns the column number of the encoded position. */
+ final def column(pos: Int): Int = pos & COLUMN_MASK
+
+ /** Returns a string representation of the encoded position. */
+ def toString(pos: Int): String = line(pos) + ":" + column(pos)
+}
+
+@nowarn
+private[scala] object Position extends Position {
+ def checkInput(line: Int, column: Int): Unit = {
+ if (line < 0)
+ throw new IllegalArgumentException(s"$line < 0")
+ if (line == 0 && column != 0 || column < 0)
+ throw new IllegalArgumentException(s"$line,$column not allowed")
+ }
+}
diff --git a/library/src/scala/io/Source.scala b/library/src/scala/io/Source.scala
new file mode 100644
index 000000000000..360c9fe0cf6d
--- /dev/null
+++ b/library/src/scala/io/Source.scala
@@ -0,0 +1,381 @@
+/*
+ * 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 io
+
+import scala.collection.{AbstractIterator, BufferedIterator}
+import java.io.{Closeable, FileInputStream, FileNotFoundException, InputStream, PrintStream, File => JFile}
+import java.net.{URI, URL}
+
+import scala.annotation.nowarn
+
+/** This object provides convenience methods to create an iterable
+ * representation of a source file.
+ */
+object Source {
+ val DefaultBufSize = 2048
+
+ /** Creates a `Source` from System.in.
+ */
+ def stdin = fromInputStream(System.in)
+
+ /** Creates a Source from an Iterable.
+ *
+ * @param iterable the Iterable
+ * @return the Source
+ */
+ def fromIterable(iterable: Iterable[Char]): Source = new Source {
+ val iter = iterable.iterator
+ } withReset(() => fromIterable(iterable))
+
+ /** Creates a Source instance from a single character.
+ */
+ def fromChar(c: Char): Source = fromIterable(Array(c))
+
+ /** creates Source from array of characters, with empty description.
+ */
+ def fromChars(chars: Array[Char]): Source = fromIterable(chars)
+
+ /** creates Source from a String, with no description.
+ */
+ def fromString(s: String): Source = fromIterable(s)
+
+ /** creates Source from file with given name, setting its description to
+ * filename.
+ */
+ def fromFile(name: String)(implicit codec: Codec): BufferedSource =
+ fromFile(new JFile(name))(codec)
+
+ /** creates Source from file with given name, using given encoding, setting
+ * its description to filename.
+ */
+ def fromFile(name: String, enc: String): BufferedSource =
+ fromFile(name)(Codec(enc))
+
+ /** creates `source` from file with given file `URI`.
+ */
+ def fromFile(uri: URI)(implicit codec: Codec): BufferedSource =
+ fromFile(new JFile(uri))(codec)
+
+ /** creates Source from file with given file: URI
+ */
+ def fromFile(uri: URI, enc: String): BufferedSource =
+ fromFile(uri)(Codec(enc))
+
+ /** creates Source from file, using default character encoding, setting its
+ * description to filename.
+ */
+ def fromFile(file: JFile)(implicit codec: Codec): BufferedSource =
+ fromFile(file, Source.DefaultBufSize)(codec)
+
+ /** same as fromFile(file, enc, Source.DefaultBufSize)
+ */
+ def fromFile(file: JFile, enc: String): BufferedSource =
+ fromFile(file)(Codec(enc))
+
+ def fromFile(file: JFile, enc: String, bufferSize: Int): BufferedSource =
+ fromFile(file, bufferSize)(Codec(enc))
+
+ /** Creates Source from `file`, using given character encoding, setting
+ * its description to filename. Input is buffered in a buffer of size
+ * `bufferSize`.
+ */
+ def fromFile(file: JFile, bufferSize: Int)(implicit codec: Codec): BufferedSource = {
+ val inputStream = new FileInputStream(file)
+
+ createBufferedSource(
+ inputStream,
+ bufferSize,
+ () => fromFile(file, bufferSize)(codec),
+ () => inputStream.close()
+ )(codec) withDescription s"file:${file.getAbsolutePath}"
+ }
+
+ /** Create a `Source` from array of bytes, decoding
+ * the bytes according to codec.
+ *
+ * @return the created `Source` instance.
+ */
+ def fromBytes(bytes: Array[Byte])(implicit codec: Codec): Source =
+ fromString(new String(bytes, codec.name))
+
+ def fromBytes(bytes: Array[Byte], enc: String): Source =
+ fromBytes(bytes)(Codec(enc))
+
+ /** Create a `Source` from array of bytes, assuming
+ * one byte per character (ISO-8859-1 encoding.)
+ */
+ @deprecated("Use `fromBytes` and specify an encoding", since="2.13.9")
+ def fromRawBytes(bytes: Array[Byte]): Source =
+ fromString(new String(bytes, Codec.ISO8859.charSet))
+
+ /** creates `Source` from file with given file: URI
+ */
+ def fromURI(uri: URI)(implicit codec: Codec): BufferedSource =
+ fromFile(new JFile(uri))(codec)
+
+ /** same as fromURL(new URL(s))(Codec(enc))
+ */
+ def fromURL(s: String, enc: String): BufferedSource =
+ fromURL(s)(Codec(enc))
+
+ /** same as fromURL(new URL(s))
+ */
+ def fromURL(s: String)(implicit codec: Codec): BufferedSource =
+ fromURL(new URI(s).toURL)(codec)
+
+ /** same as fromInputStream(url.openStream())(Codec(enc))
+ */
+ def fromURL(url: URL, enc: String): BufferedSource =
+ fromURL(url)(Codec(enc))
+
+ /** same as fromInputStream(url.openStream())(codec)
+ */
+ def fromURL(url: URL)(implicit codec: Codec): BufferedSource =
+ fromInputStream(url.openStream())(codec)
+
+ /** Reads data from inputStream with a buffered reader, using the encoding
+ * in implicit parameter codec.
+ *
+ * @param inputStream the input stream from which to read
+ * @param bufferSize buffer size (defaults to Source.DefaultBufSize)
+ * @param reset a () => Source which resets the stream (if unset, reset() will throw an Exception)
+ * @param close a () => Unit method which closes the stream (if unset, close() will do nothing)
+ * @param codec (implicit) a scala.io.Codec specifying behavior (defaults to Codec.default)
+ * @return the buffered source
+ */
+ def createBufferedSource(
+ inputStream: InputStream,
+ bufferSize: Int = DefaultBufSize,
+ reset: () => Source = null,
+ close: () => Unit = null
+ )(implicit codec: Codec): BufferedSource = {
+ // workaround for default arguments being unable to refer to other parameters
+ val resetFn = if (reset == null) () => createBufferedSource(inputStream, bufferSize, reset, close)(codec) else reset
+
+ new BufferedSource(inputStream, bufferSize)(codec) withReset resetFn withClose close
+ }
+
+ def fromInputStream(is: InputStream, enc: String): BufferedSource =
+ fromInputStream(is)(Codec(enc))
+
+ def fromInputStream(is: InputStream)(implicit codec: Codec): BufferedSource =
+ createBufferedSource(is, reset = () => fromInputStream(is)(codec), close = () => is.close())(codec)
+
+ /** Reads data from a classpath resource, using either a context classloader (default) or a passed one.
+ *
+ * @param resource name of the resource to load from the classpath
+ * @param classLoader classloader to be used, or context classloader if not specified
+ * @return the buffered source
+ */
+ def fromResource(resource: String, classLoader: ClassLoader = Thread.currentThread().getContextClassLoader())(implicit codec: Codec): BufferedSource =
+ Option(classLoader.getResourceAsStream(resource)) match {
+ case Some(in) => fromInputStream(in)
+ case None => throw new FileNotFoundException(s"resource '$resource' was not found in the classpath from the given classloader.")
+ }
+
+}
+
+/** An iterable representation of source data.
+ * It may be reset with the optional [[reset]] method.
+ *
+ * Subclasses must supply [[scala.io.Source.iter the underlying iterator]].
+ *
+ * Error handling may be customized by overriding the [[scala.io.Source.report report]] method.
+ *
+ * The [[scala.io.Source.ch current input]] and [[scala.io.Source.pos position]],
+ * as well as the [[scala.io.Source.next next character]] methods delegate to
+ * [[scala.io.Source#Positioner the positioner]].
+ *
+ * The default positioner encodes line and column numbers in the position passed to [[report]].
+ * This behavior can be changed by supplying a
+ * [[scala.io.Source.withPositioning(pos:* custom positioner]].
+ *
+ */
+abstract class Source extends Iterator[Char] with Closeable {
+ /** the actual iterator */
+ protected val iter: Iterator[Char]
+
+ // ------ public values
+
+ /** description of this source, default empty */
+ var descr: String = ""
+ var nerrors = 0
+ var nwarnings = 0
+
+ private def lineNum(line: Int): String = (getLines() drop (line - 1) take 1).mkString
+
+ class LineIterator extends AbstractIterator[String] with Iterator[String] {
+ private[this] val sb = new StringBuilder
+
+ lazy val iter: BufferedIterator[Char] = Source.this.iter.buffered
+ def isNewline(ch: Char): Boolean = ch == '\r' || ch == '\n'
+ def getc(): Boolean = iter.hasNext && {
+ val ch = iter.next()
+ if (ch == '\n') false
+ else if (ch == '\r') {
+ if (iter.hasNext && iter.head == '\n')
+ iter.next()
+
+ false
+ }
+ else {
+ sb append ch
+ true
+ }
+ }
+ def hasNext: Boolean = iter.hasNext
+ def next(): String = {
+ sb.clear()
+ while (getc()) { }
+ sb.toString
+ }
+ }
+
+ /** Returns an iterator who returns lines (NOT including newline character(s)).
+ * It will treat any of \r\n, \r, or \n as a line separator (longest match) - if
+ * you need more refined behavior you can subclass Source#LineIterator directly.
+ */
+ def getLines(): Iterator[String] = new LineIterator()
+
+ /** Returns `'''true'''` if this source has more characters.
+ */
+ def hasNext: Boolean = iter.hasNext
+
+ /** Returns next character.
+ */
+ def next(): Char = positioner.next()
+
+ @nowarn("cat=deprecation")
+ class Positioner(encoder: Position) {
+ def this() = this(RelaxedPosition)
+ /** the last character returned by next. */
+ var ch: Char = _
+
+ /** position of last character returned by next */
+ var pos = 0
+
+ /** current line and column */
+ var cline = 1
+ var ccol = 1
+
+ /** default col increment for tabs '\t', set to 4 initially */
+ var tabinc = 4
+
+ def next(): Char = {
+ ch = iter.next()
+ pos = encoder.encode(cline, ccol)
+ ch match {
+ case '\n' =>
+ ccol = 1
+ cline += 1
+ case '\t' =>
+ ccol += tabinc
+ case _ =>
+ ccol += 1
+ }
+ ch
+ }
+ }
+ /** A Position implementation which ignores errors in
+ * the positions.
+ */
+ @nowarn("cat=deprecation")
+ object RelaxedPosition extends Position {
+ def checkInput(line: Int, column: Int): Unit = ()
+ }
+ object RelaxedPositioner extends Positioner(RelaxedPosition) { }
+ object NoPositioner extends Positioner(Position) {
+ override def next(): Char = iter.next()
+ }
+ def ch: Char = positioner.ch
+ def pos: Int = positioner.pos
+
+ /** Reports an error message to the output stream `out`.
+ *
+ * @param pos the source position (line/column)
+ * @param msg the error message to report
+ * @param out PrintStream to use (optional: defaults to `Console.err`)
+ */
+ def reportError(
+ pos: Int,
+ msg: String,
+ out: PrintStream = Console.err): Unit =
+ {
+ nerrors += 1
+ report(pos, msg, out)
+ }
+
+ private def spaces(n: Int) = List.fill(n)(' ').mkString
+ /**
+ * @param pos the source position (line/column)
+ * @param msg the error message to report
+ * @param out PrintStream to use
+ */
+ def report(pos: Int, msg: String, out: PrintStream): Unit = {
+ val line = Position line pos
+ val col = Position column pos
+
+ out println "%s:%d:%d: %s%s%s^".format(descr, line, col, msg, lineNum(line), spaces(col - 1))
+ }
+
+ /**
+ * @param pos the source position (line/column)
+ * @param msg the warning message to report
+ * @param out PrintStream to use (optional: defaults to `Console.out`)
+ */
+ def reportWarning(
+ pos: Int,
+ msg: String,
+ out: PrintStream = Console.out): Unit =
+ {
+ nwarnings += 1
+ report(pos, "warning! " + msg, out)
+ }
+
+ private[this] var resetFunction: () => Source = null
+ private[this] var closeFunction: () => Unit = null
+ private[this] var positioner: Positioner = RelaxedPositioner
+
+ def withReset(f: () => Source): this.type = {
+ resetFunction = f
+ this
+ }
+ def withClose(f: () => Unit): this.type = {
+ closeFunction = f
+ this
+ }
+ def withDescription(text: String): this.type = {
+ descr = text
+ this
+ }
+ /** Change or disable the positioner. */
+ def withPositioning(on: Boolean): this.type = {
+ positioner = if (on) RelaxedPositioner else NoPositioner
+ this
+ }
+ def withPositioning(pos: Positioner): this.type = {
+ positioner = pos
+ this
+ }
+
+ /** The close() method closes the underlying resource. */
+ def close(): Unit = {
+ if (closeFunction != null) closeFunction()
+ }
+
+ /** The reset() method creates a fresh copy of this Source. */
+ def reset(): Source =
+ if (resetFunction != null) resetFunction()
+ else throw new UnsupportedOperationException("Source's reset() method was not set.")
+}
diff --git a/library/src/scala/io/StdIn.scala b/library/src/scala/io/StdIn.scala
new file mode 100644
index 000000000000..a39f99b4d689
--- /dev/null
+++ b/library/src/scala/io/StdIn.scala
@@ -0,0 +1,241 @@
+/*
+ * 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 io
+
+import java.text.MessageFormat
+
+/** private[scala] because this is not functionality we should be providing
+ * in the standard library, at least not in this idiosyncratic form.
+ * Factored into trait because it is better code structure regardless.
+ */
+private[scala] trait StdIn {
+ import scala.Console._
+
+ /** Read a full line from the default input. Returns `null` if the end of the
+ * input stream has been reached.
+ *
+ * @return the string read from the terminal or null if the end of stream was reached.
+ */
+ def readLine(): String = in.readLine()
+
+ /** Print and flush formatted text to the default output, and read a full line from the default input.
+ * Returns `null` if the end of the input stream has been reached.
+ *
+ * @param text the format of the text to print out, as in `printf`.
+ * @param args the parameters used to instantiate the format, as in `printf`.
+ * @return the string read from the default input
+ */
+ def readLine(text: String, args: Any*): String = {
+ printf(text, args: _*)
+ out.flush()
+ readLine()
+ }
+
+ /** Reads a boolean value from an entire line of the default input.
+ * Has a fairly liberal interpretation of the input.
+ *
+ * @return the boolean value read, or false if it couldn't be converted to a boolean
+ * @throws java.io.EOFException if the end of the input stream has been reached.
+ */
+ def readBoolean(): Boolean = {
+ val s = readLine()
+ if (s == null)
+ throw new java.io.EOFException("Console has reached end of input")
+ else
+ s.toLowerCase() match {
+ case "true" => true
+ case "t" => true
+ case "yes" => true
+ case "y" => true
+ case _ => false
+ }
+ }
+
+ /** Reads a byte value from an entire line of the default input.
+ *
+ * @return the Byte that was read
+ * @throws java.io.EOFException if the end of the
+ * input stream has been reached.
+ * @throws java.lang.NumberFormatException if the value couldn't be converted to a Byte
+ */
+ def readByte(): Byte = {
+ val s = readLine()
+ if (s == null)
+ throw new java.io.EOFException("Console has reached end of input")
+ else
+ s.toByte
+ }
+
+ /** Reads a short value from an entire line of the default input.
+ *
+ * @return the short that was read
+ * @throws java.io.EOFException if the end of the
+ * input stream has been reached.
+ * @throws java.lang.NumberFormatException if the value couldn't be converted to a Short
+ */
+ def readShort(): Short = {
+ val s = readLine()
+ if (s == null)
+ throw new java.io.EOFException("Console has reached end of input")
+ else
+ s.toShort
+ }
+
+ /** Reads a char value from an entire line of the default input.
+ *
+ * @return the Char that was read
+ * @throws java.io.EOFException if the end of the
+ * input stream has been reached.
+ * @throws java.lang.StringIndexOutOfBoundsException if the line read from default input was empty
+ */
+ def readChar(): Char = {
+ val s = readLine()
+ if (s == null)
+ throw new java.io.EOFException("Console has reached end of input")
+ else
+ s charAt 0
+ }
+
+ /** Reads an int value from an entire line of the default input.
+ *
+ * @return the Int that was read
+ * @throws java.io.EOFException if the end of the
+ * input stream has been reached.
+ * @throws java.lang.NumberFormatException if the value couldn't be converted to an Int
+ */
+ def readInt(): Int = {
+ val s = readLine()
+ if (s == null)
+ throw new java.io.EOFException("Console has reached end of input")
+ else
+ s.toInt
+ }
+
+ /** Reads an long value from an entire line of the default input.
+ *
+ * @return the Long that was read
+ * @throws java.io.EOFException if the end of the
+ * input stream has been reached.
+ * @throws java.lang.NumberFormatException if the value couldn't be converted to a Long
+ */
+ def readLong(): Long = {
+ val s = readLine()
+ if (s == null)
+ throw new java.io.EOFException("Console has reached end of input")
+ else
+ s.toLong
+ }
+
+ /** Reads a float value from an entire line of the default input.
+ * @return the Float that was read.
+ * @throws java.io.EOFException if the end of the
+ * input stream has been reached.
+ * @throws java.lang.NumberFormatException if the value couldn't be converted to a Float
+ *
+ */
+ def readFloat(): Float = {
+ val s = readLine()
+ if (s == null)
+ throw new java.io.EOFException("Console has reached end of input")
+ else
+ s.toFloat
+ }
+
+ /** Reads a double value from an entire line of the default input.
+ *
+ * @return the Double that was read.
+ * @throws java.io.EOFException if the end of the
+ * input stream has been reached.
+ * @throws java.lang.NumberFormatException if the value couldn't be converted to a Float
+ */
+ def readDouble(): Double = {
+ val s = readLine()
+ if (s == null)
+ throw new java.io.EOFException("Console has reached end of input")
+ else
+ s.toDouble
+ }
+
+ /** Reads in some structured input (from the default input), specified by
+ * a format specifier. See class `java.text.MessageFormat` for details of
+ * the format specification.
+ *
+ * @param format the format of the input.
+ * @return a list of all extracted values.
+ * @throws java.io.EOFException if the end of the input stream has been
+ * reached.
+ */
+ def readf(format: String): List[Any] = {
+ val s = readLine()
+ if (s == null)
+ throw new java.io.EOFException("Console has reached end of input")
+ else
+ textComponents(new MessageFormat(format).parse(s))
+ }
+
+ /** Reads in some structured input (from the default input), specified by
+ * a format specifier, returning only the first value extracted, according
+ * to the format specification.
+ *
+ * @param format format string, as accepted by `readf`.
+ * @return The first value that was extracted from the input
+ */
+ def readf1(format: String): Any = readf(format).head
+
+ /** Reads in some structured input (from the default input), specified
+ * by a format specifier, returning only the first two values extracted,
+ * according to the format specification.
+ *
+ * @param format format string, as accepted by `readf`.
+ * @return A [[scala.Tuple2]] containing the first two values extracted
+ */
+ def readf2(format: String): (Any, Any) = {
+ val res = readf(format)
+ (res.head, res.tail.head)
+ }
+
+ /** Reads in some structured input (from the default input), specified
+ * by a format specifier, returning only the first three values extracted,
+ * according to the format specification.
+ *
+ * @param format format string, as accepted by `readf`.
+ * @return A [[scala.Tuple3]] containing the first three values extracted
+ */
+ def readf3(format: String): (Any, Any, Any) = {
+ val res = readf(format)
+ (res.head, res.tail.head, res.tail.tail.head)
+ }
+
+ private def textComponents(a: Array[AnyRef]): List[Any] = {
+ var i: Int = a.length - 1
+ var res: List[Any] = Nil
+ while (i >= 0) {
+ res = (a(i) match {
+ case x: java.lang.Boolean => x.booleanValue()
+ case x: java.lang.Byte => x.byteValue()
+ case x: java.lang.Short => x.shortValue()
+ case x: java.lang.Character => x.charValue()
+ case x: java.lang.Integer => x.intValue()
+ case x: java.lang.Long => x.longValue()
+ case x: java.lang.Float => x.floatValue()
+ case x: java.lang.Double => x.doubleValue()
+ case x => x
+ }) :: res
+ i -= 1
+ }
+ res
+ }
+}
+
+object StdIn extends StdIn
diff --git a/library/src/scala/jdk/Accumulator.scala b/library/src/scala/jdk/Accumulator.scala
new file mode 100644
index 000000000000..0398a204b9a0
--- /dev/null
+++ b/library/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]
+ }
+ }
+}
diff --git a/library/src/scala/jdk/AnyAccumulator.scala b/library/src/scala/jdk/AnyAccumulator.scala
new file mode 100644
index 000000000000..fa952105fcca
--- /dev/null
+++ b/library/src/scala/jdk/AnyAccumulator.scala
@@ -0,0 +1,380 @@
+/*
+ * 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
+
+import scala.collection.Stepper.EfficientSplit
+import scala.collection.{AnyStepper, Factory, IterableFactoryDefaults, SeqFactory, Stepper, StepperShape, mutable}
+import scala.reflect.ClassTag
+
+/** An Accumulator for arbitrary element types, see [[Accumulator]]. */
+final class AnyAccumulator[A]
+ extends Accumulator[A, AnyAccumulator, AnyAccumulator[A]]
+ with mutable.SeqOps[A, AnyAccumulator, AnyAccumulator[A]]
+ with IterableFactoryDefaults[A, AnyAccumulator]
+ with Serializable {
+ private[jdk] var current: Array[AnyRef] = AnyAccumulator.emptyAnyRefArray
+ private[jdk] var history: Array[Array[AnyRef]] = AnyAccumulator.emptyAnyRefArrayArray
+ private[jdk] var cumul: Array[Long] = AnyAccumulator.emptyLongArray
+
+ private[jdk] def cumulative(i: Int): Long = cumul(i)
+
+ override protected[this] def className: String = "AnyAccumulator"
+
+ def efficientStepper[S <: Stepper[_]](implicit shape: StepperShape[A, S]): S with EfficientSplit =
+ shape.parUnbox(new AnyAccumulatorStepper[A](this.asInstanceOf[AnyAccumulator[A]]))
+
+ private def expand(): Unit = {
+ if (index > 0) {
+ if (hIndex >= history.length) hExpand()
+ history(hIndex) = current
+ cumul(hIndex) = (if (hIndex > 0) cumulative(hIndex-1) else 0) + index
+ hIndex += 1
+ }
+ current = new Array[AnyRef](nextBlockSize)
+ index = 0
+ }
+
+ private def hExpand(): Unit = {
+ if (hIndex == 0) {
+ history = new Array[Array[AnyRef]](4)
+ cumul = new Array[Long](4)
+ }
+ else {
+ history = java.util.Arrays.copyOf(history, history.length << 1)
+ cumul = java.util.Arrays.copyOf(cumul, cumul.length << 1)
+ }
+ }
+
+ /** Appends an element to this `AnyAccumulator`. */
+ def addOne(a: A): this.type = {
+ totalSize += 1
+ if (index >= current.length) expand()
+ current(index) = a.asInstanceOf[AnyRef]
+ index += 1
+ this
+ }
+
+ /** Result collection consisting of all elements appended so far. */
+ override def result(): AnyAccumulator[A] = this
+
+ /** Removes all elements from `that` and appends them to this `AnyAccumulator`. */
+ def drain[A1 <: A](that: AnyAccumulator[A1]): Unit = {
+ var h = 0
+ var prev = 0L
+ var more = true
+ while (more && h < that.hIndex) {
+ val n = (that.cumulative(h) - prev).toInt
+ if (current.length - index >= n) {
+ System.arraycopy(that.history(h), 0, current, index, n)
+ prev = that.cumulative(h)
+ index += n
+ h += 1
+ }
+ else more = false
+ }
+ if (h >= that.hIndex && current.length - index >= 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 - java.lang.Integer.numberOfLeadingZeros(1 + hIndex + slots)))
+ history = java.util.Arrays.copyOf(history, n)
+ cumul = java.util.Arrays.copyOf(cumul, n)
+ }
+ var pv = if (hIndex > 0) cumulative(hIndex-1) else 0L
+ if (index > 0) {
+ pv += index
+ cumul(hIndex) = pv
+ history(hIndex) = if (index < (current.length >>> 3) && current.length > 32) java.util.Arrays.copyOf(current, index) else current
+ hIndex += 1
+ }
+ while (h < that.hIndex) {
+ pv += that.cumulative(h) - prev
+ prev = that.cumulative(h)
+ cumul(hIndex) = pv
+ history(hIndex) = that.history(h)
+ h += 1
+ hIndex += 1
+ }
+ index = that.index
+ current = that.current
+ }
+ totalSize += that.totalSize
+ that.clear()
+ }
+
+ override def clear(): Unit = {
+ super.clear()
+ current = AnyAccumulator.emptyAnyRefArray
+ history = AnyAccumulator.emptyAnyRefArrayArray
+ cumul = AnyAccumulator.emptyLongArray
+ }
+
+ /** Retrieves the `ix`th element. */
+ def apply(ix: Long): A = {
+ if (totalSize - ix <= index || hIndex == 0) current((ix - (totalSize - index)).toInt).asInstanceOf[A]
+ else {
+ val w = seekSlot(ix)
+ history((w >>> 32).toInt)((w & 0xFFFFFFFFL).toInt).asInstanceOf[A]
+ }
+ }
+
+ /** Retrieves the `ix`th element, using an `Int` index. */
+ def apply(i: Int): A = apply(i.toLong)
+
+ def update(idx: Long, elem: A): Unit = {
+ if (totalSize - idx <= index || hIndex == 0) current((idx - (totalSize - index)).toInt) = elem.asInstanceOf[AnyRef]
+ else {
+ val w = seekSlot(idx)
+ history((w >>> 32).toInt)((w & 0xFFFFFFFFL).toInt) = elem.asInstanceOf[AnyRef]
+ }
+ }
+
+ def update(idx: Int, elem: A): Unit = update(idx.toLong, elem)
+
+ /** Returns an `Iterator` over the contents of this `AnyAccumulator`. */
+ def iterator: Iterator[A] = stepper.iterator
+
+ def countLong(p: A => Boolean): Long = {
+ var r = 0L
+ val s = stepper
+ while (s.hasStep)
+ if (p(s.nextStep())) r += 1
+ r
+ }
+
+ /** Copy the elements in this `AnyAccumulator` into an `Array` */
+ override def toArray[B >: A : ClassTag]: Array[B] = {
+ if (totalSize > Int.MaxValue) throw new IllegalArgumentException("Too many elements accumulated for an array: "+totalSize.toString)
+ val a = new Array[B](totalSize.toInt)
+ var j = 0
+ var h = 0
+ var pv = 0L
+ while (h < hIndex) {
+ val x = history(h)
+ val n = cumulative(h) - pv
+ pv = cumulative(h)
+ var i = 0
+ while (i < n) {
+ a(j) = x(i).asInstanceOf[B]
+ i += 1
+ j += 1
+ }
+ h += 1
+ }
+ var i = 0
+ while (i < index) {
+ a(j) = current(i).asInstanceOf[B]
+ i += 1
+ j += 1
+ }
+ a
+ }
+
+ /** Copies the elements in this `AnyAccumulator` to a `List` */
+ override def toList: List[A] = {
+ var ans: List[A] = Nil
+ var i = index - 1
+ while (i >= 0) {
+ ans = current(i).asInstanceOf[A] :: 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).asInstanceOf[A] :: ans
+ i -= 1
+ }
+ h -= 1
+ }
+ ans
+ }
+
+ /**
+ * Copy the elements in this `AnyAccumulator` to a specified collection. Example use:
+ * `acc.to(Vector)`.
+ */
+ override def to[C1](factory: Factory[A, C1]): C1 = {
+ if (totalSize > Int.MaxValue) throw new IllegalArgumentException("Too many elements accumulated for a Scala collection: "+totalSize.toString)
+ factory.fromSpecific(iterator)
+ }
+
+ override def iterableFactory: SeqFactory[AnyAccumulator] = AnyAccumulator
+
+ private def writeReplace(): AnyRef = new AnyAccumulator.SerializationProxy(this)
+}
+
+object AnyAccumulator extends collection.SeqFactory[AnyAccumulator] {
+ private val emptyAnyRefArray = new Array[AnyRef](0)
+ private val emptyAnyRefArrayArray = new Array[Array[AnyRef]](0)
+ private val emptyLongArray = new Array[Long](0)
+
+ import java.util.{function => jf}
+
+ /** A `Supplier` of `AnyAccumulator`s, suitable for use with `java.util.stream.Stream`'s `collect` method. */
+ def supplier[A]: jf.Supplier[AnyAccumulator[A]] = () => new AnyAccumulator[A]
+
+ /** A `BiConsumer` that adds an element to an `AnyAccumulator`, suitable for use with `java.util.stream.Stream`'s `collect` method. */
+ def adder[A]: jf.BiConsumer[AnyAccumulator[A], A] = (ac: AnyAccumulator[A], a: A) => ac addOne a
+
+ /** A `BiConsumer` that adds an `Int` to an `AnyAccumulator`, suitable for use with `java.util.stream.Stream`'s `collect` method. */
+ def unboxedIntAdder: jf.ObjIntConsumer[AnyAccumulator[Int]] = (ac: AnyAccumulator[Int], a: Int) => ac addOne a
+
+ /** A `BiConsumer` that adds a `Long` to an `AnyAccumulator`, suitable for use with `java.util.stream.Stream`'s `collect` method. */
+ def unboxedLongAdder: jf.ObjLongConsumer[AnyAccumulator[Long]] = (ac: AnyAccumulator[Long], a: Long) => ac addOne a
+
+ /** A `BiConsumer` that adds a `Double` to an `AnyAccumulator`, suitable for use with `java.util.stream.Stream`'s `collect` method. */
+ def unboxedDoubleAdder: jf.ObjDoubleConsumer[AnyAccumulator[Double]] = (ac: AnyAccumulator[Double], a: Double) => ac addOne a
+
+ /** A `BiConsumer` that merges `AnyAccumulator`s, suitable for use with `java.util.stream.Stream`'s `collect` method. */
+ def merger[A]: jf.BiConsumer[AnyAccumulator[A], AnyAccumulator[A]] = (a1: AnyAccumulator[A], a2: AnyAccumulator[A]) => a1 drain a2
+
+ def from[A](source: IterableOnce[A]): AnyAccumulator[A] = source match {
+ case acc: AnyAccumulator[A] => acc
+ case _ => new AnyAccumulator[A].addAll(source)
+ }
+
+ def empty[A]: AnyAccumulator[A] = new AnyAccumulator[A]
+
+ def newBuilder[A]: mutable.Builder[A, AnyAccumulator[A]] = new AnyAccumulator[A]
+
+ class SerializationProxy[A](@transient private val acc: AnyAccumulator[A]) extends Serializable {
+ @transient private var result: AnyAccumulator[AnyRef] = _
+
+ private def writeObject(out: ObjectOutputStream): Unit = {
+ out.defaultWriteObject()
+ val size = acc.sizeLong
+ out.writeLong(size)
+ val st = acc.stepper
+ while (st.hasStep)
+ out.writeObject(st.nextStep())
+ }
+
+ private def readObject(in: ObjectInputStream): Unit = {
+ in.defaultReadObject()
+ val res = new AnyAccumulator[AnyRef]()
+ var elems = in.readLong()
+ while (elems > 0) {
+ res += in.readObject()
+ elems -= 1L
+ }
+ result = res
+ }
+
+ private def readResolve(): AnyRef = result
+ }
+}
+
+private[jdk] class AnyAccumulatorStepper[A](private[this] val acc: AnyAccumulator[A]) extends AnyStepper[A] with EfficientSplit {
+ import java.util.Spliterator._
+
+ private var h: Int = 0
+ private var i: Int = 0
+ private var a: Array[AnyRef] = 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): AnyAccumulatorStepper[A] = {
+ val ans = new AnyAccumulatorStepper(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
+
+ def estimateSize: Long = N
+
+ def hasStep: Boolean = N > 0
+
+ def nextStep(): A =
+ if (N <= 0) throw new NoSuchElementException("Next in empty Stepper")
+ else {
+ if (i >= n) loadMore()
+ val ans = a(i).asInstanceOf[A]
+ i += 1
+ N -= 1
+ ans
+ }
+
+ def trySplit(): AnyStepper[A] =
+ 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 >: A]: Spliterator[B] = new AnyStepper.AnyStepperSpliterator[B](this) {
+ // Overridden for efficiency
+ override def tryAdvance(c: Consumer[_ >: B]): Boolean = {
+ if (N <= 0) false
+ else {
+ if (i >= n) loadMore()
+ c.accept(a(i).asInstanceOf[B])
+ i += 1
+ N -= 1
+ true
+ }
+ }
+
+ // Overridden for efficiency
+ override def forEachRemaining(f: java.util.function.Consumer[_ >: B]): Unit = {
+ while (N > 0) {
+ if (i >= n) loadMore()
+ val i0 = i
+ if ((n-i) > N) n = i + N.toInt
+ while (i < n) {
+ f.accept(a(i).asInstanceOf[B])
+ i += 1
+ }
+ N -= (n - i0)
+ }
+ }
+ }
+}
diff --git a/library/src/scala/jdk/CollectionConverters.scala b/library/src/scala/jdk/CollectionConverters.scala
new file mode 100644
index 000000000000..a76dc2d5d010
--- /dev/null
+++ b/library/src/scala/jdk/CollectionConverters.scala
@@ -0,0 +1,95 @@
+/*
+ * 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 scala.collection.convert.{AsJavaExtensions, AsScalaExtensions}
+
+/** This object provides extension methods that convert between Scala and Java collections.
+ *
+ * When writing Java code, use the explicit conversion methods defined in
+ * [[javaapi.CollectionConverters]] instead.
+ *
+ * Note: to create [[java.util.stream.Stream Java Streams]] that operate on Scala collections
+ * (sequentially or in parallel), use [[StreamConverters]].
+ *
+ * {{{
+ * import scala.jdk.CollectionConverters._
+ * val s: java.util.Set[String] = Set("one", "two").asJava
+ * }}}
+ *
+ * The conversions return adapters for the corresponding API, i.e., the collections are wrapped,
+ * not converted. Changes to the original collection are reflected in the view, and vice versa:
+ *
+ * {{{
+ * scala> import scala.jdk.CollectionConverters._
+ *
+ * scala> val s = collection.mutable.Set("one")
+ * s: scala.collection.mutable.Set[String] = HashSet(one)
+ *
+ * scala> val js = s.asJava
+ * js: java.util.Set[String] = [one]
+ *
+ * scala> js.add("two")
+ *
+ * scala> s
+ * res2: scala.collection.mutable.Set[String] = HashSet(two, one)
+ * }}}
+ *
+ * The following conversions are supported via `asScala` and `asJava`:
+ *
+ * {{{
+ * scala.collection.Iterable <=> java.lang.Iterable
+ * scala.collection.Iterator <=> java.util.Iterator
+ * scala.collection.mutable.Buffer <=> java.util.List
+ * scala.collection.mutable.Set <=> java.util.Set
+ * scala.collection.mutable.Map <=> java.util.Map
+ * scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap
+ * }}}
+ *
+ * The following conversions are supported via `asScala` and through
+ * specially-named extension methods to convert to Java collections, as shown:
+ *
+ * {{{
+ * scala.collection.Iterable <=> java.util.Collection (via asJavaCollection)
+ * scala.collection.Iterator <=> java.util.Enumeration (via asJavaEnumeration)
+ * scala.collection.mutable.Map <=> java.util.Dictionary (via asJavaDictionary)
+ * }}}
+ *
+ * In addition, the following one-way conversions are provided via `asJava`:
+ *
+ * {{{
+ * scala.collection.Seq => java.util.List
+ * scala.collection.mutable.Seq => java.util.List
+ * scala.collection.Set => java.util.Set
+ * scala.collection.Map => java.util.Map
+ * }}}
+ *
+ * The following one way conversion is provided via `asScala`:
+ *
+ * {{{
+ * java.util.Properties => scala.collection.mutable.Map
+ * }}}
+ *
+ * In all cases, converting from a source type to a target type and back
+ * again will return the original source object. For example:
+ *
+ * {{{
+ * import scala.jdk.CollectionConverters._
+ *
+ * val source = new scala.collection.mutable.ListBuffer[Int]
+ * val target: java.util.List[Int] = source.asJava
+ * val other: scala.collection.mutable.Buffer[Int] = target.asScala
+ * assert(source eq other)
+ * }}}
+ */
+object CollectionConverters extends AsJavaExtensions with AsScalaExtensions
diff --git a/library/src/scala/jdk/DoubleAccumulator.scala b/library/src/scala/jdk/DoubleAccumulator.scala
new file mode 100644
index 000000000000..9f2d81c3282d
--- /dev/null
+++ b/library/src/scala/jdk/DoubleAccumulator.scala
@@ -0,0 +1,486 @@
+/*
+ * 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.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]` */
+ 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/src/scala/jdk/DurationConverters.scala b/library/src/scala/jdk/DurationConverters.scala
new file mode 100644
index 000000000000..a98cd5b709d6
--- /dev/null
+++ b/library/src/scala/jdk/DurationConverters.scala
@@ -0,0 +1,34 @@
+/*
+ * 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.time.{Duration => JDuration}
+
+import scala.concurrent.duration.FiniteDuration
+
+/** This object provides extension methods that convert between Scala and Java duration types.
+ *
+ * When writing Java code, use the explicit conversion methods defined in
+ * [[javaapi.DurationConverters]] instead.
+ */
+object DurationConverters {
+ implicit class JavaDurationOps(private val duration: JDuration) extends AnyVal {
+ /** Convert a Java duration to a Scala duration, see [[javaapi.DurationConverters.toScala]]. */
+ def toScala: FiniteDuration = javaapi.DurationConverters.toScala(duration)
+ }
+
+ implicit final class ScalaDurationOps(private val duration: FiniteDuration) extends AnyVal {
+ /** Convert a Scala duration to a Java duration, see [[javaapi.DurationConverters.toJava]]. */
+ def toJava: JDuration = javaapi.DurationConverters.toJava(duration)
+ }
+}
diff --git a/library/src/scala/jdk/FunctionConverters.scala b/library/src/scala/jdk/FunctionConverters.scala
new file mode 100644
index 000000000000..3c2d42564df0
--- /dev/null
+++ b/library/src/scala/jdk/FunctionConverters.scala
@@ -0,0 +1,52 @@
+/*
+ * 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
+
+/** This object provides extension methods that convert between Scala and Java function types.
+ *
+ * When writing Java code, use the explicit conversion methods defined in
+ * [[javaapi.FunctionConverters]] instead.
+ *
+ * Using the `.asJava` extension method on a Scala function produces the most specific possible
+ * Java function type:
+ *
+ * {{{
+ * scala> import scala.jdk.FunctionConverters._
+ * scala> val f = (x: Int) => x + 1
+ *
+ * scala> val jf1 = f.asJava
+ * jf1: java.util.function.IntUnaryOperator = ...
+ * }}}
+ *
+ * More generic Java function types can be created using the corresponding `asJavaXYZ` extension
+ * method:
+ *
+ * {{{
+ * scala> val jf2 = f.asJavaFunction
+ * jf2: java.util.function.Function[Int,Int] = ...
+ *
+ * scala> val jf3 = f.asJavaUnaryOperator
+ * jf3: java.util.function.UnaryOperator[Int] = ...
+ * }}}
+ *
+ * Converting a Java function to Scala is done using the `asScala` extension method:
+ *
+ * {{{
+ * scala> List(1,2,3).map(jf2.asScala)
+ * res1: List[Int] = List(2, 3, 4)
+ * }}}
+ */
+object FunctionConverters extends Priority0FunctionExtensions
diff --git a/library/src/scala/jdk/FunctionExtensions.scala b/library/src/scala/jdk/FunctionExtensions.scala
new file mode 100644
index 000000000000..e932609e7af5
--- /dev/null
+++ b/library/src/scala/jdk/FunctionExtensions.scala
@@ -0,0 +1,220 @@
+/*
+ * 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
+
+import language.implicitConversions
+
+trait Priority3FunctionExtensions {
+ import FunctionWrappers._
+
+ @inline implicit def enrichAsJavaBiFunction[T, U, R](sf: scala.Function2[T, U, R]): RichFunction2AsBiFunction[T, U, R] = new RichFunction2AsBiFunction[T, U, R](sf)
+}
+
+
+
+import language.implicitConversions
+
+trait Priority2FunctionExtensions extends Priority3FunctionExtensions {
+ import FunctionWrappers._
+
+ @inline implicit def enrichAsJavaBiConsumer[T, U](sf: scala.Function2[T, U, Unit]): RichFunction2AsBiConsumer[T, U] = new RichFunction2AsBiConsumer[T, U](sf)
+
+ @inline implicit def enrichAsJavaBiPredicate[T, U](sf: scala.Function2[T, U, Boolean]): RichFunction2AsBiPredicate[T, U] = new RichFunction2AsBiPredicate[T, U](sf)
+
+ @inline implicit def enrichAsJavaFunction[T, R](sf: scala.Function1[T, R]): RichFunction1AsFunction[T, R] = new RichFunction1AsFunction[T, R](sf)
+
+ @inline implicit def enrichAsJavaToDoubleBiFunction[T, U](sf: scala.Function2[T, U, Double]): RichFunction2AsToDoubleBiFunction[T, U] = new RichFunction2AsToDoubleBiFunction[T, U](sf)
+
+ @inline implicit def enrichAsJavaToIntBiFunction[T, U](sf: scala.Function2[T, U, Int]): RichFunction2AsToIntBiFunction[T, U] = new RichFunction2AsToIntBiFunction[T, U](sf)
+
+ @inline implicit def enrichAsJavaToLongBiFunction[T, U](sf: scala.Function2[T, U, Long]): RichFunction2AsToLongBiFunction[T, U] = new RichFunction2AsToLongBiFunction[T, U](sf)
+}
+
+
+
+import language.implicitConversions
+
+trait Priority1FunctionExtensions extends Priority2FunctionExtensions {
+ import FunctionWrappers._
+
+ @inline implicit def enrichAsJavaBinaryOperator[T, A1, A2](sf: scala.Function2[T, A1, A2])(implicit evA1: =:=[A1, T], evA2: =:=[A2, T]): RichFunction2AsBinaryOperator[T] = new RichFunction2AsBinaryOperator[T](sf.asInstanceOf[scala.Function2[T, T, T]])
+
+ @inline implicit def enrichAsJavaConsumer[T](sf: scala.Function1[T, Unit]): RichFunction1AsConsumer[T] = new RichFunction1AsConsumer[T](sf)
+
+ @inline implicit def enrichAsJavaDoubleFunction[A0, R](sf: scala.Function1[A0, R])(implicit evA0: =:=[A0, Double]): RichFunction1AsDoubleFunction[R] = new RichFunction1AsDoubleFunction[R](sf.asInstanceOf[scala.Function1[Double, R]])
+
+ @inline implicit def enrichAsJavaIntFunction[A0, R](sf: scala.Function1[A0, R])(implicit evA0: =:=[A0, Int]): RichFunction1AsIntFunction[R] = new RichFunction1AsIntFunction[R](sf.asInstanceOf[scala.Function1[Int, R]])
+
+ @inline implicit def enrichAsJavaLongFunction[A0, R](sf: scala.Function1[A0, R])(implicit evA0: =:=[A0, Long]): RichFunction1AsLongFunction[R] = new RichFunction1AsLongFunction[R](sf.asInstanceOf[scala.Function1[Long, R]])
+
+ @inline implicit def enrichAsJavaObjDoubleConsumer[T, A1](sf: scala.Function2[T, A1, Unit])(implicit evA1: =:=[A1, Double]): RichFunction2AsObjDoubleConsumer[T] = new RichFunction2AsObjDoubleConsumer[T](sf.asInstanceOf[scala.Function2[T, Double, Unit]])
+
+ @inline implicit def enrichAsJavaObjIntConsumer[T, A1](sf: scala.Function2[T, A1, Unit])(implicit evA1: =:=[A1, Int]): RichFunction2AsObjIntConsumer[T] = new RichFunction2AsObjIntConsumer[T](sf.asInstanceOf[scala.Function2[T, Int, Unit]])
+
+ @inline implicit def enrichAsJavaObjLongConsumer[T, A1](sf: scala.Function2[T, A1, Unit])(implicit evA1: =:=[A1, Long]): RichFunction2AsObjLongConsumer[T] = new RichFunction2AsObjLongConsumer[T](sf.asInstanceOf[scala.Function2[T, Long, Unit]])
+
+ @inline implicit def enrichAsJavaPredicate[T](sf: scala.Function1[T, Boolean]): RichFunction1AsPredicate[T] = new RichFunction1AsPredicate[T](sf)
+
+ @inline implicit def enrichAsJavaSupplier[T](sf: scala.Function0[T]): RichFunction0AsSupplier[T] = new RichFunction0AsSupplier[T](sf)
+
+ @inline implicit def enrichAsJavaToDoubleFunction[T](sf: scala.Function1[T, Double]): RichFunction1AsToDoubleFunction[T] = new RichFunction1AsToDoubleFunction[T](sf)
+
+ @inline implicit def enrichAsJavaToIntFunction[T](sf: scala.Function1[T, Int]): RichFunction1AsToIntFunction[T] = new RichFunction1AsToIntFunction[T](sf)
+
+ @inline implicit def enrichAsJavaToLongFunction[T](sf: scala.Function1[T, Long]): RichFunction1AsToLongFunction[T] = new RichFunction1AsToLongFunction[T](sf)
+
+ @inline implicit def enrichAsJavaUnaryOperator[T, A1](sf: scala.Function1[T, A1])(implicit evA1: =:=[A1, T]): RichFunction1AsUnaryOperator[T] = new RichFunction1AsUnaryOperator[T](sf.asInstanceOf[scala.Function1[T, T]])
+}
+
+
+
+import language.implicitConversions
+
+trait Priority0FunctionExtensions extends Priority1FunctionExtensions {
+ import FunctionWrappers._
+
+ @inline implicit def enrichAsJavaBooleanSupplier(sf: scala.Function0[Boolean]): RichFunction0AsBooleanSupplier = new RichFunction0AsBooleanSupplier(sf)
+
+ @inline implicit def enrichAsJavaDoubleBinaryOperator[A0, A1](sf: scala.Function2[A0, A1, Double])(implicit evA0: =:=[A0, Double], evA1: =:=[A1, Double]): RichFunction2AsDoubleBinaryOperator = new RichFunction2AsDoubleBinaryOperator(sf.asInstanceOf[scala.Function2[Double, Double, Double]])
+
+ @inline implicit def enrichAsJavaDoubleConsumer[A0](sf: scala.Function1[A0, Unit])(implicit evA0: =:=[A0, Double]): RichFunction1AsDoubleConsumer = new RichFunction1AsDoubleConsumer(sf.asInstanceOf[scala.Function1[Double, Unit]])
+
+ @inline implicit def enrichAsJavaDoublePredicate[A0](sf: scala.Function1[A0, Boolean])(implicit evA0: =:=[A0, Double]): RichFunction1AsDoublePredicate = new RichFunction1AsDoublePredicate(sf.asInstanceOf[scala.Function1[Double, Boolean]])
+
+ @inline implicit def enrichAsJavaDoubleSupplier(sf: scala.Function0[Double]): RichFunction0AsDoubleSupplier = new RichFunction0AsDoubleSupplier(sf)
+
+ @inline implicit def enrichAsJavaDoubleToIntFunction[A0](sf: scala.Function1[A0, Int])(implicit evA0: =:=[A0, Double]): RichFunction1AsDoubleToIntFunction = new RichFunction1AsDoubleToIntFunction(sf.asInstanceOf[scala.Function1[Double, Int]])
+
+ @inline implicit def enrichAsJavaDoubleToLongFunction[A0](sf: scala.Function1[A0, Long])(implicit evA0: =:=[A0, Double]): RichFunction1AsDoubleToLongFunction = new RichFunction1AsDoubleToLongFunction(sf.asInstanceOf[scala.Function1[Double, Long]])
+
+ @inline implicit def enrichAsJavaDoubleUnaryOperator[A0](sf: scala.Function1[A0, Double])(implicit evA0: =:=[A0, Double]): RichFunction1AsDoubleUnaryOperator = new RichFunction1AsDoubleUnaryOperator(sf.asInstanceOf[scala.Function1[Double, Double]])
+
+ @inline implicit def enrichAsJavaIntBinaryOperator[A0, A1](sf: scala.Function2[A0, A1, Int])(implicit evA0: =:=[A0, Int], evA1: =:=[A1, Int]): RichFunction2AsIntBinaryOperator = new RichFunction2AsIntBinaryOperator(sf.asInstanceOf[scala.Function2[Int, Int, Int]])
+
+ @inline implicit def enrichAsJavaIntConsumer[A0](sf: scala.Function1[A0, Unit])(implicit evA0: =:=[A0, Int]): RichFunction1AsIntConsumer = new RichFunction1AsIntConsumer(sf.asInstanceOf[scala.Function1[Int, Unit]])
+
+ @inline implicit def enrichAsJavaIntPredicate[A0](sf: scala.Function1[A0, Boolean])(implicit evA0: =:=[A0, Int]): RichFunction1AsIntPredicate = new RichFunction1AsIntPredicate(sf.asInstanceOf[scala.Function1[Int, Boolean]])
+
+ @inline implicit def enrichAsJavaIntSupplier(sf: scala.Function0[Int]): RichFunction0AsIntSupplier = new RichFunction0AsIntSupplier(sf)
+
+ @inline implicit def enrichAsJavaIntToDoubleFunction[A0](sf: scala.Function1[A0, Double])(implicit evA0: =:=[A0, Int]): RichFunction1AsIntToDoubleFunction = new RichFunction1AsIntToDoubleFunction(sf.asInstanceOf[scala.Function1[Int, Double]])
+
+ @inline implicit def enrichAsJavaIntToLongFunction[A0](sf: scala.Function1[A0, Long])(implicit evA0: =:=[A0, Int]): RichFunction1AsIntToLongFunction = new RichFunction1AsIntToLongFunction(sf.asInstanceOf[scala.Function1[Int, Long]])
+
+ @inline implicit def enrichAsJavaIntUnaryOperator[A0](sf: scala.Function1[A0, Int])(implicit evA0: =:=[A0, Int]): RichFunction1AsIntUnaryOperator = new RichFunction1AsIntUnaryOperator(sf.asInstanceOf[scala.Function1[Int, Int]])
+
+ @inline implicit def enrichAsJavaLongBinaryOperator[A0, A1](sf: scala.Function2[A0, A1, Long])(implicit evA0: =:=[A0, Long], evA1: =:=[A1, Long]): RichFunction2AsLongBinaryOperator = new RichFunction2AsLongBinaryOperator(sf.asInstanceOf[scala.Function2[Long, Long, Long]])
+
+ @inline implicit def enrichAsJavaLongConsumer[A0](sf: scala.Function1[A0, Unit])(implicit evA0: =:=[A0, Long]): RichFunction1AsLongConsumer = new RichFunction1AsLongConsumer(sf.asInstanceOf[scala.Function1[Long, Unit]])
+
+ @inline implicit def enrichAsJavaLongPredicate[A0](sf: scala.Function1[A0, Boolean])(implicit evA0: =:=[A0, Long]): RichFunction1AsLongPredicate = new RichFunction1AsLongPredicate(sf.asInstanceOf[scala.Function1[Long, Boolean]])
+
+ @inline implicit def enrichAsJavaLongSupplier(sf: scala.Function0[Long]): RichFunction0AsLongSupplier = new RichFunction0AsLongSupplier(sf)
+
+ @inline implicit def enrichAsJavaLongToDoubleFunction[A0](sf: scala.Function1[A0, Double])(implicit evA0: =:=[A0, Long]): RichFunction1AsLongToDoubleFunction = new RichFunction1AsLongToDoubleFunction(sf.asInstanceOf[scala.Function1[Long, Double]])
+
+ @inline implicit def enrichAsJavaLongToIntFunction[A0](sf: scala.Function1[A0, Int])(implicit evA0: =:=[A0, Long]): RichFunction1AsLongToIntFunction = new RichFunction1AsLongToIntFunction(sf.asInstanceOf[scala.Function1[Long, Int]])
+
+ @inline implicit def enrichAsJavaLongUnaryOperator[A0](sf: scala.Function1[A0, Long])(implicit evA0: =:=[A0, Long]): RichFunction1AsLongUnaryOperator = new RichFunction1AsLongUnaryOperator(sf.asInstanceOf[scala.Function1[Long, Long]])
+
+
+
+ @inline implicit def enrichAsScalaFromBiConsumer[T, U](jf: java.util.function.BiConsumer[T, U]): RichBiConsumerAsFunction2[T, U] = new RichBiConsumerAsFunction2[T, U](jf)
+
+ @inline implicit def enrichAsScalaFromBiFunction[T, U, R](jf: java.util.function.BiFunction[T, U, R]): RichBiFunctionAsFunction2[T, U, R] = new RichBiFunctionAsFunction2[T, U, R](jf)
+
+ @inline implicit def enrichAsScalaFromBiPredicate[T, U](jf: java.util.function.BiPredicate[T, U]): RichBiPredicateAsFunction2[T, U] = new RichBiPredicateAsFunction2[T, U](jf)
+
+ @inline implicit def enrichAsScalaFromBinaryOperator[T](jf: java.util.function.BinaryOperator[T]): RichBinaryOperatorAsFunction2[T] = new RichBinaryOperatorAsFunction2[T](jf)
+
+ @inline implicit def enrichAsScalaFromBooleanSupplier(jf: java.util.function.BooleanSupplier): RichBooleanSupplierAsFunction0 = new RichBooleanSupplierAsFunction0(jf)
+
+ @inline implicit def enrichAsScalaFromConsumer[T](jf: java.util.function.Consumer[T]): RichConsumerAsFunction1[T] = new RichConsumerAsFunction1[T](jf)
+
+ @inline implicit def enrichAsScalaFromDoubleBinaryOperator(jf: java.util.function.DoubleBinaryOperator): RichDoubleBinaryOperatorAsFunction2 = new RichDoubleBinaryOperatorAsFunction2(jf)
+
+ @inline implicit def enrichAsScalaFromDoubleConsumer(jf: java.util.function.DoubleConsumer): RichDoubleConsumerAsFunction1 = new RichDoubleConsumerAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromDoubleFunction[R](jf: java.util.function.DoubleFunction[R]): RichDoubleFunctionAsFunction1[R] = new RichDoubleFunctionAsFunction1[R](jf)
+
+ @inline implicit def enrichAsScalaFromDoublePredicate(jf: java.util.function.DoublePredicate): RichDoublePredicateAsFunction1 = new RichDoublePredicateAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromDoubleSupplier(jf: java.util.function.DoubleSupplier): RichDoubleSupplierAsFunction0 = new RichDoubleSupplierAsFunction0(jf)
+
+ @inline implicit def enrichAsScalaFromDoubleToIntFunction(jf: java.util.function.DoubleToIntFunction): RichDoubleToIntFunctionAsFunction1 = new RichDoubleToIntFunctionAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromDoubleToLongFunction(jf: java.util.function.DoubleToLongFunction): RichDoubleToLongFunctionAsFunction1 = new RichDoubleToLongFunctionAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromDoubleUnaryOperator(jf: java.util.function.DoubleUnaryOperator): RichDoubleUnaryOperatorAsFunction1 = new RichDoubleUnaryOperatorAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromFunction[T, R](jf: java.util.function.Function[T, R]): RichFunctionAsFunction1[T, R] = new RichFunctionAsFunction1[T, R](jf)
+
+ @inline implicit def enrichAsScalaFromIntBinaryOperator(jf: java.util.function.IntBinaryOperator): RichIntBinaryOperatorAsFunction2 = new RichIntBinaryOperatorAsFunction2(jf)
+
+ @inline implicit def enrichAsScalaFromIntConsumer(jf: java.util.function.IntConsumer): RichIntConsumerAsFunction1 = new RichIntConsumerAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromIntFunction[R](jf: java.util.function.IntFunction[R]): RichIntFunctionAsFunction1[R] = new RichIntFunctionAsFunction1[R](jf)
+
+ @inline implicit def enrichAsScalaFromIntPredicate(jf: java.util.function.IntPredicate): RichIntPredicateAsFunction1 = new RichIntPredicateAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromIntSupplier(jf: java.util.function.IntSupplier): RichIntSupplierAsFunction0 = new RichIntSupplierAsFunction0(jf)
+
+ @inline implicit def enrichAsScalaFromIntToDoubleFunction(jf: java.util.function.IntToDoubleFunction): RichIntToDoubleFunctionAsFunction1 = new RichIntToDoubleFunctionAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromIntToLongFunction(jf: java.util.function.IntToLongFunction): RichIntToLongFunctionAsFunction1 = new RichIntToLongFunctionAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromIntUnaryOperator(jf: java.util.function.IntUnaryOperator): RichIntUnaryOperatorAsFunction1 = new RichIntUnaryOperatorAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromLongBinaryOperator(jf: java.util.function.LongBinaryOperator): RichLongBinaryOperatorAsFunction2 = new RichLongBinaryOperatorAsFunction2(jf)
+
+ @inline implicit def enrichAsScalaFromLongConsumer(jf: java.util.function.LongConsumer): RichLongConsumerAsFunction1 = new RichLongConsumerAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromLongFunction[R](jf: java.util.function.LongFunction[R]): RichLongFunctionAsFunction1[R] = new RichLongFunctionAsFunction1[R](jf)
+
+ @inline implicit def enrichAsScalaFromLongPredicate(jf: java.util.function.LongPredicate): RichLongPredicateAsFunction1 = new RichLongPredicateAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromLongSupplier(jf: java.util.function.LongSupplier): RichLongSupplierAsFunction0 = new RichLongSupplierAsFunction0(jf)
+
+ @inline implicit def enrichAsScalaFromLongToDoubleFunction(jf: java.util.function.LongToDoubleFunction): RichLongToDoubleFunctionAsFunction1 = new RichLongToDoubleFunctionAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromLongToIntFunction(jf: java.util.function.LongToIntFunction): RichLongToIntFunctionAsFunction1 = new RichLongToIntFunctionAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromLongUnaryOperator(jf: java.util.function.LongUnaryOperator): RichLongUnaryOperatorAsFunction1 = new RichLongUnaryOperatorAsFunction1(jf)
+
+ @inline implicit def enrichAsScalaFromObjDoubleConsumer[T](jf: java.util.function.ObjDoubleConsumer[T]): RichObjDoubleConsumerAsFunction2[T] = new RichObjDoubleConsumerAsFunction2[T](jf)
+
+ @inline implicit def enrichAsScalaFromObjIntConsumer[T](jf: java.util.function.ObjIntConsumer[T]): RichObjIntConsumerAsFunction2[T] = new RichObjIntConsumerAsFunction2[T](jf)
+
+ @inline implicit def enrichAsScalaFromObjLongConsumer[T](jf: java.util.function.ObjLongConsumer[T]): RichObjLongConsumerAsFunction2[T] = new RichObjLongConsumerAsFunction2[T](jf)
+
+ @inline implicit def enrichAsScalaFromPredicate[T](jf: java.util.function.Predicate[T]): RichPredicateAsFunction1[T] = new RichPredicateAsFunction1[T](jf)
+
+ @inline implicit def enrichAsScalaFromSupplier[T](jf: java.util.function.Supplier[T]): RichSupplierAsFunction0[T] = new RichSupplierAsFunction0[T](jf)
+
+ @inline implicit def enrichAsScalaFromToDoubleBiFunction[T, U](jf: java.util.function.ToDoubleBiFunction[T, U]): RichToDoubleBiFunctionAsFunction2[T, U] = new RichToDoubleBiFunctionAsFunction2[T, U](jf)
+
+ @inline implicit def enrichAsScalaFromToDoubleFunction[T](jf: java.util.function.ToDoubleFunction[T]): RichToDoubleFunctionAsFunction1[T] = new RichToDoubleFunctionAsFunction1[T](jf)
+
+ @inline implicit def enrichAsScalaFromToIntBiFunction[T, U](jf: java.util.function.ToIntBiFunction[T, U]): RichToIntBiFunctionAsFunction2[T, U] = new RichToIntBiFunctionAsFunction2[T, U](jf)
+
+ @inline implicit def enrichAsScalaFromToIntFunction[T](jf: java.util.function.ToIntFunction[T]): RichToIntFunctionAsFunction1[T] = new RichToIntFunctionAsFunction1[T](jf)
+
+ @inline implicit def enrichAsScalaFromToLongBiFunction[T, U](jf: java.util.function.ToLongBiFunction[T, U]): RichToLongBiFunctionAsFunction2[T, U] = new RichToLongBiFunctionAsFunction2[T, U](jf)
+
+ @inline implicit def enrichAsScalaFromToLongFunction[T](jf: java.util.function.ToLongFunction[T]): RichToLongFunctionAsFunction1[T] = new RichToLongFunctionAsFunction1[T](jf)
+
+ @inline implicit def enrichAsScalaFromUnaryOperator[T](jf: java.util.function.UnaryOperator[T]): RichUnaryOperatorAsFunction1[T] = new RichUnaryOperatorAsFunction1[T](jf)
+}
diff --git a/library/src/scala/jdk/FunctionWrappers.scala b/library/src/scala/jdk/FunctionWrappers.scala
new file mode 100644
index 000000000000..27153ffed820
--- /dev/null
+++ b/library/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/src/scala/jdk/FutureConverters.scala b/library/src/scala/jdk/FutureConverters.scala
new file mode 100644
index 000000000000..9b9b6ad3c8b6
--- /dev/null
+++ b/library/src/scala/jdk/FutureConverters.scala
@@ -0,0 +1,43 @@
+/*
+ * 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.util.concurrent.CompletionStage
+
+import scala.concurrent.Future
+
+/** This object provides extension methods that convert between Scala [[scala.concurrent.Future]] and Java
+ * [[java.util.concurrent.CompletionStage]]
+ *
+ * When writing Java code, use the explicit conversion methods defined in
+ * [[javaapi.FutureConverters]] instead.
+ *
+ * Note that the bridge is implemented at the read-only side of asynchronous handles, namely
+ * [[scala.concurrent.Future]] (instead of [[scala.concurrent.Promise]]) and [[java.util.concurrent.CompletionStage]] (instead of
+ * [[java.util.concurrent.CompletableFuture]]). This is intentional, as the semantics of bridging
+ * the write-handles would be prone to race conditions; if both ends (`CompletableFuture` and
+ * `Promise`) are completed independently at the same time, they may contain different values
+ * afterwards. For this reason, `toCompletableFuture` is not supported on the created
+ * `CompletionStage`s.
+ */
+object FutureConverters {
+ implicit class FutureOps[T](private val f: Future[T]) extends AnyVal {
+ /** Convert a Scala Future to a Java CompletionStage, see [[javaapi.FutureConverters.asJava]]. */
+ def asJava: CompletionStage[T] = javaapi.FutureConverters.asJava(f)
+ }
+
+ implicit class CompletionStageOps[T](private val cs: CompletionStage[T]) extends AnyVal {
+ /** Convert a Java CompletionStage to a Scala Future, see [[javaapi.FutureConverters.asScala]]. */
+ def asScala: Future[T] = javaapi.FutureConverters.asScala(cs)
+ }
+}
diff --git a/library/src/scala/jdk/IntAccumulator.scala b/library/src/scala/jdk/IntAccumulator.scala
new file mode 100644
index 000000000000..e407f438520a
--- /dev/null
+++ b/library/src/scala/jdk/IntAccumulator.scala
@@ -0,0 +1,491 @@
+/*
+ * 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.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]` */
+ 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/src/scala/jdk/LongAccumulator.scala b/library/src/scala/jdk/LongAccumulator.scala
new file mode 100644
index 000000000000..8c538533a923
--- /dev/null
+++ b/library/src/scala/jdk/LongAccumulator.scala
@@ -0,0 +1,486 @@
+/*
+ * 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.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]` */
+ 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/src/scala/jdk/OptionConverters.scala b/library/src/scala/jdk/OptionConverters.scala
new file mode 100644
index 000000000000..5fbfef206394
--- /dev/null
+++ b/library/src/scala/jdk/OptionConverters.scala
@@ -0,0 +1,111 @@
+/*
+ * 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.util.{Optional, OptionalDouble, OptionalInt, OptionalLong}
+
+/** This object provides extension methods that convert between Scala `Option` and Java `Optional`
+ * types.
+ *
+ * When writing Java code, use the explicit conversion methods defined in
+ * [[javaapi.OptionConverters]] instead.
+ *
+ * Scala `Option` is extended with a `toJava` method that creates a corresponding `Optional`, and
+ * a `toJavaPrimitive` method that creates a specialized variant (e.g., `OptionalInt`) if
+ * applicable.
+ *
+ * Java `Optional` is extended with a `toScala` method and a `toJavaPrimitive` method.
+ *
+ * Finally, specialized `Optional` types are extended with `toScala` and `toJavaGeneric` methods.
+ *
+ * Example usage:
+ *
+ * {{{
+ * import scala.jdk.OptionConverters._
+ * val a = Option("example").toJava // Creates java.util.Optional[String] containing "example"
+ * val b = (None: Option[String]).toJava // Creates an empty java.util.Optional[String]
+ * val c = a.toScala // Back to Option("example")
+ * val d = b.toScala // Back to None typed as Option[String]
+ * val e = Option(2.7).toJava // java.util.Optional[Double] containing boxed 2.7
+ * val f = Option(2.7).toJavaPrimitive // java.util.OptionalDouble containing 2.7 (not boxed)
+ * val g = f.toScala // Back to Option(2.7)
+ * val h = f.toJavaGeneric // Same as e
+ * val i = e.toJavaPrimitive // Same as f
+ * }}}
+ */
+object OptionConverters {
+ /** Provides conversions from Java `Optional` to Scala `Option` and specialized `Optional` types */
+ implicit class RichOptional[A](private val o: java.util.Optional[A]) extends AnyVal {
+ /** Convert a Java `Optional` to a Scala `Option` */
+ def toScala: Option[A] = if (o.isPresent) Some(o.get) else None
+
+ /** Convert a Java `Optional` to a Scala `Option` */
+ @deprecated("Use `toScala` instead", "2.13.0")
+ def asScala: Option[A] = if (o.isPresent) Some(o.get) else None
+
+ /** Convert a generic Java `Optional` to a specialized variant */
+ def toJavaPrimitive[O](implicit shape: OptionShape[A, O]): O = shape.fromJava(o)
+ }
+
+ /** Provides conversions from Scala `Option` to Java `Optional` types */
+ implicit class RichOption[A](private val o: Option[A]) extends AnyVal {
+ /** Convert a Scala `Option` to a generic Java `Optional` */
+ def toJava: Optional[A] = o match { case Some(a) => Optional.ofNullable(a); case _ => Optional.empty[A] }
+
+ /** Convert a Scala `Option` to a generic Java `Optional` */
+ @deprecated("Use `toJava` instead", "2.13.0")
+ def asJava: Optional[A] = o match { case Some(a) => Optional.ofNullable(a); case _ => Optional.empty[A] }
+
+ /** Convert a Scala `Option` to a specialized Java `Optional` */
+ def toJavaPrimitive[O](implicit shape: OptionShape[A, O]): O = shape.fromScala(o)
+ }
+
+ /** Provides conversions from `OptionalDouble` to Scala `Option` and the generic `Optional` */
+ implicit class RichOptionalDouble(private val o: OptionalDouble) extends AnyVal {
+ /** Convert a Java `OptionalDouble` to a Scala `Option` */
+ def toScala: Option[Double] = if (o.isPresent) Some(o.getAsDouble) else None
+
+ /** Convert a Java `OptionalDouble` to a Scala `Option` */
+ @deprecated("Use `toScala` instead", "2.13.0")
+ def asScala: Option[Double] = if (o.isPresent) Some(o.getAsDouble) else None
+
+ /** Convert a Java `OptionalDouble` to a generic Java `Optional` */
+ def toJavaGeneric: Optional[Double] = if (o.isPresent) Optional.of(o.getAsDouble) else Optional.empty[Double]
+ }
+
+ /** Provides conversions from `OptionalInt` to Scala `Option` and the generic `Optional` */
+ implicit class RichOptionalInt(private val o: OptionalInt) extends AnyVal {
+ /** Convert a Java `OptionalInt` to a Scala `Option` */
+ def toScala: Option[Int] = if (o.isPresent) Some(o.getAsInt) else None
+
+ /** Convert a Java `OptionalInt` to a Scala `Option` */
+ @deprecated("Use `toScala` instead", "2.13.0")
+ def asScala: Option[Int] = if (o.isPresent) Some(o.getAsInt) else None
+
+ /** Convert a Java `OptionalInt` to a generic Java `Optional` */
+ def toJavaGeneric: Optional[Int] = if (o.isPresent) Optional.of(o.getAsInt) else Optional.empty[Int]
+ }
+
+ /** Provides conversions from `OptionalLong` to Scala `Option` and the generic `Optional` */
+ implicit class RichOptionalLong(private val o: OptionalLong) extends AnyVal {
+ /** Convert a Java `OptionalLong` to a Scala `Option` */
+ def toScala: Option[Long] = if (o.isPresent) Some(o.getAsLong) else None
+
+ /** Convert a Java `OptionalLong` to a Scala `Option` */
+ @deprecated("Use `toScala` instead", "2.13.0")
+ def asScala: Option[Long] = if (o.isPresent) Some(o.getAsLong) else None
+
+ /** Convert a Java `OptionalLong` to a generic Java `Optional` */
+ def toJavaGeneric: Optional[Long] = if (o.isPresent) Optional.of(o.getAsLong) else Optional.empty[Long]
+ }
+}
diff --git a/library/src/scala/jdk/OptionShape.scala b/library/src/scala/jdk/OptionShape.scala
new file mode 100644
index 000000000000..e56b3296e439
--- /dev/null
+++ b/library/src/scala/jdk/OptionShape.scala
@@ -0,0 +1,67 @@
+/*
+ * 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.util.{Optional, OptionalDouble, OptionalInt, OptionalLong}
+import java.{lang => jl}
+
+import scala.annotation.implicitNotFound
+
+/** A type class implementing conversions from a generic Scala `Option` or Java `Optional` to
+ * a specialized Java variant (for `Double`, `Int` and `Long`).
+ *
+ * @tparam A the primitive type wrapped in an option
+ * @tparam O the specialized Java `Optional` wrapping an element of type `A`
+ */
+@implicitNotFound("No specialized Optional type exists for elements of type ${A}")
+sealed abstract class OptionShape[A, O] {
+ /** Converts from `Optional` to the specialized variant `O` */
+ def fromJava(o: Optional[A]): O
+ /** Converts from `Option` to the specialized variant `O` */
+ def fromScala(o: Option[A]): O
+}
+
+object OptionShape {
+ implicit val doubleOptionShape: OptionShape[Double, OptionalDouble] = new OptionShape[Double, OptionalDouble] {
+ def fromJava(o: Optional[Double]): OptionalDouble =
+ if (o.isPresent) OptionalDouble.of(o.get) else OptionalDouble.empty
+
+ def fromScala(o: Option[Double]): OptionalDouble = o match {
+ case Some(d) => OptionalDouble.of(d)
+ case _ => OptionalDouble.empty
+ }
+ }
+ implicit val jDoubleOptionShape: OptionShape[jl.Double, OptionalDouble] = doubleOptionShape.asInstanceOf[OptionShape[jl.Double, OptionalDouble]]
+
+ implicit val intOptionShape: OptionShape[Int, OptionalInt] = new OptionShape[Int, OptionalInt] {
+ def fromJava(o: Optional[Int]): OptionalInt =
+ if (o.isPresent) OptionalInt.of(o.get) else OptionalInt.empty
+
+ def fromScala(o: Option[Int]): OptionalInt = o match {
+ case Some(d) => OptionalInt.of(d)
+ case _ => OptionalInt.empty
+ }
+ }
+ implicit val jIntegerOptionShape: OptionShape[jl.Integer, OptionalInt] = intOptionShape.asInstanceOf[OptionShape[jl.Integer, OptionalInt]]
+
+ implicit val longOptionShape: OptionShape[Long, OptionalLong] = new OptionShape[Long, OptionalLong] {
+ def fromJava(o: Optional[Long]): OptionalLong =
+ if (o.isPresent) OptionalLong.of(o.get) else OptionalLong.empty
+
+ def fromScala(o: Option[Long]): OptionalLong = o match {
+ case Some(d) => OptionalLong.of(d)
+ case _ => OptionalLong.empty
+ }
+ }
+ implicit val jLongOptionShape: OptionShape[jl.Long, OptionalLong] = longOptionShape.asInstanceOf[OptionShape[jl.Long, OptionalLong]]
+}
diff --git a/library/src/scala/jdk/StreamConverters.scala b/library/src/scala/jdk/StreamConverters.scala
new file mode 100644
index 000000000000..e3338bdba011
--- /dev/null
+++ b/library/src/scala/jdk/StreamConverters.scala
@@ -0,0 +1,92 @@
+/*
+ * 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 scala.collection.convert.StreamExtensions
+
+/** This object provides extension methods to create [[java.util.stream.Stream Java Streams]] that
+ * operate on Scala collections (sequentially or in parallel). For more information on Java
+ * streams, consult the documentation
+ * ([[https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html]]).
+ *
+ * When writing Java code, use the explicit conversion methods defined in
+ * [[javaapi.StreamConverters]] instead.
+ *
+ * The methods `asJavaSeqStream` and `asJavaParStream` convert a collection to a Java Stream:
+ *
+ * {{{
+ * scala> import scala.jdk.StreamConverters._
+ *
+ * scala> val s = (1 to 10).toList.asJavaSeqStream
+ * s: java.util.stream.IntStream = java.util.stream.IntPipeline\$Head@7b1e5e55
+ *
+ * scala> s.map(_ * 2).filter(_ > 5).toScala(List)
+ * res1: List[Int] = List(6, 8, 10, 12, 14, 16, 18, 20)
+ * }}}
+ *
+ * Note: using parallel streams in the Scala REPL causes deadlocks, see
+ * [[https://github.com/scala/bug/issues/9076]]. As a workaround, use `scala -Yrepl-class-based`.
+ *
+ * {{{
+ * scala> def isPrime(n: Int): Boolean = !(2 +: (3 to Math.sqrt(n).toInt by 2) exists (n % _ == 0))
+ * isPrime: (n: Int)Boolean
+ *
+ * scala> (10000 to 1000000).asJavaParStream.filter(isPrime).toScala(Vector)
+ * res6: scala.collection.immutable.Vector[Int] = Vector(10007, 10009, 10037, 10039, ...
+ * }}}
+ *
+ * A Java [[Stream]] provides operations on a sequence of elements. Streams are created from
+ * [[java.util.Spliterator Spliterators]], which are similar to Iterators with the additional
+ * capability to partition off some of their elements. This partitioning, if supported by the
+ * Spliterator, is used for parallelizing Stream operations.
+ *
+ * Scala collections have a method [[scala.collection.IterableOnce.stepper `stepper`]] that
+ * returns a [[scala.collection.Stepper]] for the collection, which in turn can be converted to a
+ * Spliterator for creating a Java Stream.
+ *
+ * The `asJavaSeqStream ` extension method is available on any Scala collection. The
+ * `asJavaParStream` extension method can only be invoked on collections where the return type of
+ * the [[scala.collection.IterableOnce.stepper `stepper`]] method is marked with the
+ * [[scala.collection.Stepper.EfficientSplit]] marker trait. This trait is added to steppers that
+ * support partitioning, and therefore efficient parallel processing.
+ *
+ * The following extension methods are available:
+ *
+ * | Collection Type | Extension Methods |
+ * | --- | --- |
+ * | `IterableOnce` | `asJavaSeqStream` |
+ * | `IndexedSeq`, Arrays, `BitSet`, `Accumulator`, `HashMap`, `HashSet`, `Range`, `TreeMap`, `TreeSet`, `Vector`, Strings | `asJavaParStream` |
+ * | `Map` | `asJavaSeqKeyStream`, `asJavaSeqValueStream` |
+ * | `HashMap`, `TreeMap` | `asJavaParKeyStream`, `asJavaParValueStream` |
+ * | `Stepper` | `asJavaSeqStream` |
+ * | `Stepper with EfficientSplit` | `asJavaParStream` |
+ * | Strings | `asJavaSeqStream`, `asJavaParStream`, `asJavaSeqCharStream`, `asJavaParCharStream`, `asJavaSeqCodePointStream`, `asJavaParCodePointStream` |
+ * | Java streams | `toScala`, `asJavaPrimitiveStream` |
+ *
+ * The `asJavaPrimitiveStream` method converts a `Stream[Int]` to an `IntStream`. It is the dual
+ * of the `boxed` method defined on primitive streams (e.g., `IntStream.boxed` is a
+ * `Stream[Integer]`).
+ *
+ * The `toScala` extension methods on Java streams collects the result of a stream pipeline into a
+ * Scala collection, for example `stream.toScala(List)`, `stream.toScala(Vector)`. Note that
+ * transformation operations on streams are lazy (also called "intermediate"), terminal operations
+ * such as `forEach`, `count` or `toScala` trigger the evaluation.
+ *
+ * Collecting a parallel stream to a collection can be performed in parallel. This is beneficial if
+ * the target collection supports efficient merging of the segments that are built in parallel.
+ * To support this use case, the Scala standard library provides the [[Accumulator]] collection.
+ * This collection supports efficient parallel construction, and it has specialized subtypes for
+ * `Int`, `Long` and `Double` so that primitive Java streams can be collected to a Scala collection
+ * without boxing the elements.
+ */
+object StreamConverters extends StreamExtensions
diff --git a/library/src/scala/jdk/javaapi/CollectionConverters.scala b/library/src/scala/jdk/javaapi/CollectionConverters.scala
new file mode 100644
index 000000000000..80c2d7c0b8a9
--- /dev/null
+++ b/library/src/scala/jdk/javaapi/CollectionConverters.scala
@@ -0,0 +1,77 @@
+/*
+ * 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.javaapi
+
+import scala.collection.convert.{AsJavaConverters, AsScalaConverters}
+
+/** This object contains methods that convert between Scala and Java collections.
+ *
+ * The explicit conversion methods defined here are intended to be used in Java code. For Scala
+ * code, it is recommended to use the extension methods defined in
+ * [[scala.jdk.CollectionConverters]].
+ *
+ * Note: to create [[java.util.stream.Stream Java Streams]] that operate on Scala collections
+ * (sequentially or in parallel), use [[StreamConverters]].
+ *
+ * {{{
+ * // Java Code
+ * import scala.jdk.javaapi.CollectionConverters;
+ * public class A {
+ * public void t(scala.collection.immutable.List l) {
+ * java.util.List jl = CollectionConverters.asJava(l);
+ * }
+ * }
+ * }}}
+ *
+ * The conversions return adapters for the corresponding API, i.e., the collections are wrapped,
+ * not converted. Changes to the original collection are reflected in the view, and vice versa.
+ *
+ * The following conversions are supported via `asScala` and `asJava`:
+ *
+ * {{{
+ * scala.collection.Iterable <=> java.lang.Iterable
+ * scala.collection.Iterator <=> java.util.Iterator
+ * scala.collection.mutable.Buffer <=> java.util.List
+ * scala.collection.mutable.Set <=> java.util.Set
+ * scala.collection.mutable.Map <=> java.util.Map
+ * scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap
+ * }}}
+ *
+ * The following conversions are supported via `asScala` and through
+ * specially-named methods to convert to Java collections, as shown:
+ *
+ * {{{
+ * scala.collection.Iterable <=> java.util.Collection (via asJavaCollection)
+ * scala.collection.Iterator <=> java.util.Enumeration (via asJavaEnumeration)
+ * scala.collection.mutable.Map <=> java.util.Dictionary (via asJavaDictionary)
+ * }}}
+ *
+ * In addition, the following one-way conversions are provided via `asJava`:
+ *
+ * {{{
+ * scala.collection.Seq => java.util.List
+ * scala.collection.mutable.Seq => java.util.List
+ * scala.collection.Set => java.util.Set
+ * scala.collection.Map => java.util.Map
+ * }}}
+ *
+ * The following one way conversion is provided via `asScala`:
+ *
+ * {{{
+ * java.util.Properties => scala.collection.mutable.Map
+ * }}}
+ *
+ * In all cases, converting from a source type to a target type and back
+ * again will return the original source object.
+ */
+object CollectionConverters extends AsJavaConverters with AsScalaConverters
diff --git a/library/src/scala/jdk/javaapi/DurationConverters.scala b/library/src/scala/jdk/javaapi/DurationConverters.scala
new file mode 100644
index 000000000000..00285a11c41a
--- /dev/null
+++ b/library/src/scala/jdk/javaapi/DurationConverters.scala
@@ -0,0 +1,73 @@
+/*
+ * 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.javaapi
+
+import java.time.temporal.ChronoUnit
+import java.time.{Duration => JDuration}
+import java.util.concurrent.TimeUnit
+
+import scala.concurrent.duration.{Duration, FiniteDuration}
+
+/** This object contains methods that convert between Scala and Java duration types.
+ *
+ * The explicit conversion methods defined here are intended to be used in Java code. For Scala
+ * code, it is recommended to use the extension methods defined in [[scala.jdk.DurationConverters]].
+ */
+object DurationConverters {
+ /** Convert a Java duration to a Scala duration. If the nanosecond part of the Java duration is
+ * zero, the returned duration will have a time unit of seconds. If there is a nanoseconds part,
+ * the Scala duration will have a time unit of nanoseconds.
+ *
+ * @throws IllegalArgumentException If the given Java Duration is out of bounds of what can be
+ * expressed by [[scala.concurrent.duration.FiniteDuration]].
+ */
+ def toScala(duration: JDuration): FiniteDuration = {
+ val originalSeconds = duration.getSeconds
+ val originalNanos = duration.getNano
+ if (originalNanos == 0) {
+ if (originalSeconds == 0) Duration.Zero
+ else FiniteDuration(originalSeconds, TimeUnit.SECONDS)
+ } else if (originalSeconds == 0) {
+ FiniteDuration(originalNanos, TimeUnit.NANOSECONDS)
+ } else {
+ try {
+ val secondsAsNanos = Math.multiplyExact(originalSeconds, 1000000000)
+ val totalNanos = secondsAsNanos + originalNanos
+ if ((totalNanos < 0 && secondsAsNanos < 0) || (totalNanos > 0 && secondsAsNanos > 0))
+ FiniteDuration(totalNanos, TimeUnit.NANOSECONDS)
+ else
+ throw new ArithmeticException()
+ } catch {
+ case _: ArithmeticException =>
+ throw new IllegalArgumentException(s"Java duration $duration cannot be expressed as a Scala duration")
+ }
+ }
+ }
+
+ /** Convert a Scala `FiniteDuration` to a Java duration. Note that the Scala duration keeps the
+ * time unit it was created with, while a Java duration always is a pair of seconds and nanos,
+ * so the unit it lost.
+ */
+ def toJava(duration: FiniteDuration): JDuration = {
+ if (duration.length == 0) JDuration.ZERO
+ else duration.unit match {
+ case TimeUnit.NANOSECONDS => JDuration.ofNanos(duration.length)
+ case TimeUnit.MICROSECONDS => JDuration.of(duration.length, ChronoUnit.MICROS)
+ case TimeUnit.MILLISECONDS => JDuration.ofMillis(duration.length)
+ case TimeUnit.SECONDS => JDuration.ofSeconds(duration.length)
+ case TimeUnit.MINUTES => JDuration.ofMinutes(duration.length)
+ case TimeUnit.HOURS => JDuration.ofHours(duration.length)
+ case TimeUnit.DAYS => JDuration.ofDays(duration.length)
+ }
+ }
+}
diff --git a/library/src/scala/jdk/javaapi/FunctionConverters.scala b/library/src/scala/jdk/javaapi/FunctionConverters.scala
new file mode 100644
index 000000000000..22c9769bbf42
--- /dev/null
+++ b/library/src/scala/jdk/javaapi/FunctionConverters.scala
@@ -0,0 +1,956 @@
+/*
+ * 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.javaapi
+
+/** This object contains methods that convert between Scala and Java function types.
+ *
+ * The explicit conversion methods defined here are intended to be used in Java code. For Scala
+ * code, it is recommended to use the extension methods defined in [[scala.jdk.FunctionConverters]].
+ *
+ * For details how the function converters work, see [[scala.jdk.FunctionConverters]].
+ *
+ */
+object FunctionConverters {
+ import scala.jdk.FunctionWrappers._
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromBiConsumer[T, U](jf: java.util.function.BiConsumer[T, U]): scala.Function2[T, U, scala.runtime.BoxedUnit] = jf match {
+ case AsJavaBiConsumer((f @ _)) => f.asInstanceOf[scala.Function2[T, U, scala.runtime.BoxedUnit]]
+ case _ => new FromJavaBiConsumer[T, U](jf).asInstanceOf[scala.Function2[T, U, scala.runtime.BoxedUnit]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaBiConsumer[T, U](sf: scala.Function2[T, U, scala.runtime.BoxedUnit]): java.util.function.BiConsumer[T, U] = ((sf): AnyRef) match {
+ case FromJavaBiConsumer((f @ _)) => f.asInstanceOf[java.util.function.BiConsumer[T, U]]
+ case _ => new AsJavaBiConsumer[T, U](sf.asInstanceOf[scala.Function2[T, U, Unit]])
+ }
+
+
+ @inline def asScalaFromBiFunction[T, U, R](jf: java.util.function.BiFunction[T, U, R]): scala.Function2[T, U, R] = jf match {
+ case AsJavaBiFunction((f @ _)) => f.asInstanceOf[scala.Function2[T, U, R]]
+ case _ => new FromJavaBiFunction[T, U, R](jf).asInstanceOf[scala.Function2[T, U, R]]
+ }
+
+ @inline def asJavaBiFunction[T, U, R](sf: scala.Function2[T, U, R]): java.util.function.BiFunction[T, U, R] = ((sf): AnyRef) match {
+ case FromJavaBiFunction((f @ _)) => f.asInstanceOf[java.util.function.BiFunction[T, U, R]]
+ case _ => new AsJavaBiFunction[T, U, R](sf.asInstanceOf[scala.Function2[T, U, R]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromBiPredicate[T, U](jf: java.util.function.BiPredicate[T, U]): scala.Function2[T, U, java.lang.Boolean] = jf match {
+ case AsJavaBiPredicate((f @ _)) => f.asInstanceOf[scala.Function2[T, U, java.lang.Boolean]]
+ case _ => new FromJavaBiPredicate[T, U](jf).asInstanceOf[scala.Function2[T, U, java.lang.Boolean]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaBiPredicate[T, U](sf: scala.Function2[T, U, java.lang.Boolean]): java.util.function.BiPredicate[T, U] = ((sf): AnyRef) match {
+ case FromJavaBiPredicate((f @ _)) => f.asInstanceOf[java.util.function.BiPredicate[T, U]]
+ case _ => new AsJavaBiPredicate[T, U](sf.asInstanceOf[scala.Function2[T, U, Boolean]])
+ }
+
+
+ @inline def asScalaFromBinaryOperator[T](jf: java.util.function.BinaryOperator[T]): scala.Function2[T, T, T] = jf match {
+ case AsJavaBinaryOperator((f @ _)) => f.asInstanceOf[scala.Function2[T, T, T]]
+ case _ => new FromJavaBinaryOperator[T](jf).asInstanceOf[scala.Function2[T, T, T]]
+ }
+
+ @inline def asJavaBinaryOperator[T](sf: scala.Function2[T, T, T]): java.util.function.BinaryOperator[T] = ((sf): AnyRef) match {
+ case FromJavaBinaryOperator((f @ _)) => f.asInstanceOf[java.util.function.BinaryOperator[T]]
+ case _ => new AsJavaBinaryOperator[T](sf.asInstanceOf[scala.Function2[T, T, T]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromBooleanSupplier(jf: java.util.function.BooleanSupplier): scala.Function0[java.lang.Boolean] = jf match {
+ case AsJavaBooleanSupplier((f @ _)) => f.asInstanceOf[scala.Function0[java.lang.Boolean]]
+ case _ => new FromJavaBooleanSupplier(jf).asInstanceOf[scala.Function0[java.lang.Boolean]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaBooleanSupplier(sf: scala.Function0[java.lang.Boolean]): java.util.function.BooleanSupplier = ((sf): AnyRef) match {
+ case FromJavaBooleanSupplier((f @ _)) => f.asInstanceOf[java.util.function.BooleanSupplier]
+ case _ => new AsJavaBooleanSupplier(sf.asInstanceOf[scala.Function0[Boolean]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromConsumer[T](jf: java.util.function.Consumer[T]): scala.Function1[T, scala.runtime.BoxedUnit] = jf match {
+ case AsJavaConsumer((f @ _)) => f.asInstanceOf[scala.Function1[T, scala.runtime.BoxedUnit]]
+ case _ => new FromJavaConsumer[T](jf).asInstanceOf[scala.Function1[T, scala.runtime.BoxedUnit]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaConsumer[T](sf: scala.Function1[T, scala.runtime.BoxedUnit]): java.util.function.Consumer[T] = ((sf): AnyRef) match {
+ case FromJavaConsumer((f @ _)) => f.asInstanceOf[java.util.function.Consumer[T]]
+ case _ => new AsJavaConsumer[T](sf.asInstanceOf[scala.Function1[T, Unit]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromDoubleBinaryOperator(jf: java.util.function.DoubleBinaryOperator): scala.Function2[java.lang.Double, java.lang.Double, java.lang.Double] = jf match {
+ case AsJavaDoubleBinaryOperator((f @ _)) => f.asInstanceOf[scala.Function2[java.lang.Double, java.lang.Double, java.lang.Double]]
+ case _ => new FromJavaDoubleBinaryOperator(jf).asInstanceOf[scala.Function2[java.lang.Double, java.lang.Double, java.lang.Double]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaDoubleBinaryOperator(sf: scala.Function2[java.lang.Double, java.lang.Double, java.lang.Double]): java.util.function.DoubleBinaryOperator = ((sf): AnyRef) match {
+ case FromJavaDoubleBinaryOperator((f @ _)) => f.asInstanceOf[java.util.function.DoubleBinaryOperator]
+ case _ => new AsJavaDoubleBinaryOperator(sf.asInstanceOf[scala.Function2[Double, Double, Double]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromDoubleConsumer(jf: java.util.function.DoubleConsumer): scala.Function1[java.lang.Double, scala.runtime.BoxedUnit] = jf match {
+ case AsJavaDoubleConsumer((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Double, scala.runtime.BoxedUnit]]
+ case _ => new FromJavaDoubleConsumer(jf).asInstanceOf[scala.Function1[java.lang.Double, scala.runtime.BoxedUnit]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaDoubleConsumer(sf: scala.Function1[java.lang.Double, scala.runtime.BoxedUnit]): java.util.function.DoubleConsumer = ((sf): AnyRef) match {
+ case FromJavaDoubleConsumer((f @ _)) => f.asInstanceOf[java.util.function.DoubleConsumer]
+ case _ => new AsJavaDoubleConsumer(sf.asInstanceOf[scala.Function1[Double, Unit]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromDoubleFunction[R](jf: java.util.function.DoubleFunction[R]): scala.Function1[java.lang.Double, R] = jf match {
+ case AsJavaDoubleFunction((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Double, R]]
+ case _ => new FromJavaDoubleFunction[R](jf).asInstanceOf[scala.Function1[java.lang.Double, R]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaDoubleFunction[R](sf: scala.Function1[java.lang.Double, R]): java.util.function.DoubleFunction[R] = ((sf): AnyRef) match {
+ case FromJavaDoubleFunction((f @ _)) => f.asInstanceOf[java.util.function.DoubleFunction[R]]
+ case _ => new AsJavaDoubleFunction[R](sf.asInstanceOf[scala.Function1[Double, R]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromDoublePredicate(jf: java.util.function.DoublePredicate): scala.Function1[java.lang.Double, java.lang.Boolean] = jf match {
+ case AsJavaDoublePredicate((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Double, java.lang.Boolean]]
+ case _ => new FromJavaDoublePredicate(jf).asInstanceOf[scala.Function1[java.lang.Double, java.lang.Boolean]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaDoublePredicate(sf: scala.Function1[java.lang.Double, java.lang.Boolean]): java.util.function.DoublePredicate = ((sf): AnyRef) match {
+ case FromJavaDoublePredicate((f @ _)) => f.asInstanceOf[java.util.function.DoublePredicate]
+ case _ => new AsJavaDoublePredicate(sf.asInstanceOf[scala.Function1[Double, Boolean]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromDoubleSupplier(jf: java.util.function.DoubleSupplier): scala.Function0[java.lang.Double] = jf match {
+ case AsJavaDoubleSupplier((f @ _)) => f.asInstanceOf[scala.Function0[java.lang.Double]]
+ case _ => new FromJavaDoubleSupplier(jf).asInstanceOf[scala.Function0[java.lang.Double]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaDoubleSupplier(sf: scala.Function0[java.lang.Double]): java.util.function.DoubleSupplier = ((sf): AnyRef) match {
+ case FromJavaDoubleSupplier((f @ _)) => f.asInstanceOf[java.util.function.DoubleSupplier]
+ case _ => new AsJavaDoubleSupplier(sf.asInstanceOf[scala.Function0[Double]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromDoubleToIntFunction(jf: java.util.function.DoubleToIntFunction): scala.Function1[java.lang.Double, java.lang.Integer] = jf match {
+ case AsJavaDoubleToIntFunction((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Double, java.lang.Integer]]
+ case _ => new FromJavaDoubleToIntFunction(jf).asInstanceOf[scala.Function1[java.lang.Double, java.lang.Integer]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaDoubleToIntFunction(sf: scala.Function1[java.lang.Double, java.lang.Integer]): java.util.function.DoubleToIntFunction = ((sf): AnyRef) match {
+ case FromJavaDoubleToIntFunction((f @ _)) => f.asInstanceOf[java.util.function.DoubleToIntFunction]
+ case _ => new AsJavaDoubleToIntFunction(sf.asInstanceOf[scala.Function1[Double, Int]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromDoubleToLongFunction(jf: java.util.function.DoubleToLongFunction): scala.Function1[java.lang.Double, java.lang.Long] = jf match {
+ case AsJavaDoubleToLongFunction((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Double, java.lang.Long]]
+ case _ => new FromJavaDoubleToLongFunction(jf).asInstanceOf[scala.Function1[java.lang.Double, java.lang.Long]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaDoubleToLongFunction(sf: scala.Function1[java.lang.Double, java.lang.Long]): java.util.function.DoubleToLongFunction = ((sf): AnyRef) match {
+ case FromJavaDoubleToLongFunction((f @ _)) => f.asInstanceOf[java.util.function.DoubleToLongFunction]
+ case _ => new AsJavaDoubleToLongFunction(sf.asInstanceOf[scala.Function1[Double, Long]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromDoubleUnaryOperator(jf: java.util.function.DoubleUnaryOperator): scala.Function1[java.lang.Double, java.lang.Double] = jf match {
+ case AsJavaDoubleUnaryOperator((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Double, java.lang.Double]]
+ case _ => new FromJavaDoubleUnaryOperator(jf).asInstanceOf[scala.Function1[java.lang.Double, java.lang.Double]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaDoubleUnaryOperator(sf: scala.Function1[java.lang.Double, java.lang.Double]): java.util.function.DoubleUnaryOperator = ((sf): AnyRef) match {
+ case FromJavaDoubleUnaryOperator((f @ _)) => f.asInstanceOf[java.util.function.DoubleUnaryOperator]
+ case _ => new AsJavaDoubleUnaryOperator(sf.asInstanceOf[scala.Function1[Double, Double]])
+ }
+
+
+ @inline def asScalaFromFunction[T, R](jf: java.util.function.Function[T, R]): scala.Function1[T, R] = jf match {
+ case AsJavaFunction((f @ _)) => f.asInstanceOf[scala.Function1[T, R]]
+ case _ => new FromJavaFunction[T, R](jf).asInstanceOf[scala.Function1[T, R]]
+ }
+
+ @inline def asJavaFunction[T, R](sf: scala.Function1[T, R]): java.util.function.Function[T, R] = ((sf): AnyRef) match {
+ case FromJavaFunction((f @ _)) => f.asInstanceOf[java.util.function.Function[T, R]]
+ case _ => new AsJavaFunction[T, R](sf.asInstanceOf[scala.Function1[T, R]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromIntBinaryOperator(jf: java.util.function.IntBinaryOperator): scala.Function2[java.lang.Integer, java.lang.Integer, java.lang.Integer] = jf match {
+ case AsJavaIntBinaryOperator((f @ _)) => f.asInstanceOf[scala.Function2[java.lang.Integer, java.lang.Integer, java.lang.Integer]]
+ case _ => new FromJavaIntBinaryOperator(jf).asInstanceOf[scala.Function2[java.lang.Integer, java.lang.Integer, java.lang.Integer]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaIntBinaryOperator(sf: scala.Function2[java.lang.Integer, java.lang.Integer, java.lang.Integer]): java.util.function.IntBinaryOperator = ((sf): AnyRef) match {
+ case FromJavaIntBinaryOperator((f @ _)) => f.asInstanceOf[java.util.function.IntBinaryOperator]
+ case _ => new AsJavaIntBinaryOperator(sf.asInstanceOf[scala.Function2[Int, Int, Int]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromIntConsumer(jf: java.util.function.IntConsumer): scala.Function1[java.lang.Integer, scala.runtime.BoxedUnit] = jf match {
+ case AsJavaIntConsumer((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Integer, scala.runtime.BoxedUnit]]
+ case _ => new FromJavaIntConsumer(jf).asInstanceOf[scala.Function1[java.lang.Integer, scala.runtime.BoxedUnit]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaIntConsumer(sf: scala.Function1[java.lang.Integer, scala.runtime.BoxedUnit]): java.util.function.IntConsumer = ((sf): AnyRef) match {
+ case FromJavaIntConsumer((f @ _)) => f.asInstanceOf[java.util.function.IntConsumer]
+ case _ => new AsJavaIntConsumer(sf.asInstanceOf[scala.Function1[Int, Unit]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromIntFunction[R](jf: java.util.function.IntFunction[R]): scala.Function1[java.lang.Integer, R] = jf match {
+ case AsJavaIntFunction((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Integer, R]]
+ case _ => new FromJavaIntFunction[R](jf).asInstanceOf[scala.Function1[java.lang.Integer, R]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaIntFunction[R](sf: scala.Function1[java.lang.Integer, R]): java.util.function.IntFunction[R] = ((sf): AnyRef) match {
+ case FromJavaIntFunction((f @ _)) => f.asInstanceOf[java.util.function.IntFunction[R]]
+ case _ => new AsJavaIntFunction[R](sf.asInstanceOf[scala.Function1[Int, R]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromIntPredicate(jf: java.util.function.IntPredicate): scala.Function1[java.lang.Integer, java.lang.Boolean] = jf match {
+ case AsJavaIntPredicate((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Integer, java.lang.Boolean]]
+ case _ => new FromJavaIntPredicate(jf).asInstanceOf[scala.Function1[java.lang.Integer, java.lang.Boolean]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaIntPredicate(sf: scala.Function1[java.lang.Integer, java.lang.Boolean]): java.util.function.IntPredicate = ((sf): AnyRef) match {
+ case FromJavaIntPredicate((f @ _)) => f.asInstanceOf[java.util.function.IntPredicate]
+ case _ => new AsJavaIntPredicate(sf.asInstanceOf[scala.Function1[Int, Boolean]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromIntSupplier(jf: java.util.function.IntSupplier): scala.Function0[java.lang.Integer] = jf match {
+ case AsJavaIntSupplier((f @ _)) => f.asInstanceOf[scala.Function0[java.lang.Integer]]
+ case _ => new FromJavaIntSupplier(jf).asInstanceOf[scala.Function0[java.lang.Integer]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaIntSupplier(sf: scala.Function0[java.lang.Integer]): java.util.function.IntSupplier = ((sf): AnyRef) match {
+ case FromJavaIntSupplier((f @ _)) => f.asInstanceOf[java.util.function.IntSupplier]
+ case _ => new AsJavaIntSupplier(sf.asInstanceOf[scala.Function0[Int]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromIntToDoubleFunction(jf: java.util.function.IntToDoubleFunction): scala.Function1[java.lang.Integer, java.lang.Double] = jf match {
+ case AsJavaIntToDoubleFunction((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Integer, java.lang.Double]]
+ case _ => new FromJavaIntToDoubleFunction(jf).asInstanceOf[scala.Function1[java.lang.Integer, java.lang.Double]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaIntToDoubleFunction(sf: scala.Function1[java.lang.Integer, java.lang.Double]): java.util.function.IntToDoubleFunction = ((sf): AnyRef) match {
+ case FromJavaIntToDoubleFunction((f @ _)) => f.asInstanceOf[java.util.function.IntToDoubleFunction]
+ case _ => new AsJavaIntToDoubleFunction(sf.asInstanceOf[scala.Function1[Int, Double]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromIntToLongFunction(jf: java.util.function.IntToLongFunction): scala.Function1[java.lang.Integer, java.lang.Long] = jf match {
+ case AsJavaIntToLongFunction((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Integer, java.lang.Long]]
+ case _ => new FromJavaIntToLongFunction(jf).asInstanceOf[scala.Function1[java.lang.Integer, java.lang.Long]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaIntToLongFunction(sf: scala.Function1[java.lang.Integer, java.lang.Long]): java.util.function.IntToLongFunction = ((sf): AnyRef) match {
+ case FromJavaIntToLongFunction((f @ _)) => f.asInstanceOf[java.util.function.IntToLongFunction]
+ case _ => new AsJavaIntToLongFunction(sf.asInstanceOf[scala.Function1[Int, Long]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromIntUnaryOperator(jf: java.util.function.IntUnaryOperator): scala.Function1[java.lang.Integer, java.lang.Integer] = jf match {
+ case AsJavaIntUnaryOperator((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Integer, java.lang.Integer]]
+ case _ => new FromJavaIntUnaryOperator(jf).asInstanceOf[scala.Function1[java.lang.Integer, java.lang.Integer]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaIntUnaryOperator(sf: scala.Function1[java.lang.Integer, java.lang.Integer]): java.util.function.IntUnaryOperator = ((sf): AnyRef) match {
+ case FromJavaIntUnaryOperator((f @ _)) => f.asInstanceOf[java.util.function.IntUnaryOperator]
+ case _ => new AsJavaIntUnaryOperator(sf.asInstanceOf[scala.Function1[Int, Int]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromLongBinaryOperator(jf: java.util.function.LongBinaryOperator): scala.Function2[java.lang.Long, java.lang.Long, java.lang.Long] = jf match {
+ case AsJavaLongBinaryOperator((f @ _)) => f.asInstanceOf[scala.Function2[java.lang.Long, java.lang.Long, java.lang.Long]]
+ case _ => new FromJavaLongBinaryOperator(jf).asInstanceOf[scala.Function2[java.lang.Long, java.lang.Long, java.lang.Long]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaLongBinaryOperator(sf: scala.Function2[java.lang.Long, java.lang.Long, java.lang.Long]): java.util.function.LongBinaryOperator = ((sf): AnyRef) match {
+ case FromJavaLongBinaryOperator((f @ _)) => f.asInstanceOf[java.util.function.LongBinaryOperator]
+ case _ => new AsJavaLongBinaryOperator(sf.asInstanceOf[scala.Function2[Long, Long, Long]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromLongConsumer(jf: java.util.function.LongConsumer): scala.Function1[java.lang.Long, scala.runtime.BoxedUnit] = jf match {
+ case AsJavaLongConsumer((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Long, scala.runtime.BoxedUnit]]
+ case _ => new FromJavaLongConsumer(jf).asInstanceOf[scala.Function1[java.lang.Long, scala.runtime.BoxedUnit]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaLongConsumer(sf: scala.Function1[java.lang.Long, scala.runtime.BoxedUnit]): java.util.function.LongConsumer = ((sf): AnyRef) match {
+ case FromJavaLongConsumer((f @ _)) => f.asInstanceOf[java.util.function.LongConsumer]
+ case _ => new AsJavaLongConsumer(sf.asInstanceOf[scala.Function1[Long, Unit]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromLongFunction[R](jf: java.util.function.LongFunction[R]): scala.Function1[java.lang.Long, R] = jf match {
+ case AsJavaLongFunction((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Long, R]]
+ case _ => new FromJavaLongFunction[R](jf).asInstanceOf[scala.Function1[java.lang.Long, R]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaLongFunction[R](sf: scala.Function1[java.lang.Long, R]): java.util.function.LongFunction[R] = ((sf): AnyRef) match {
+ case FromJavaLongFunction((f @ _)) => f.asInstanceOf[java.util.function.LongFunction[R]]
+ case _ => new AsJavaLongFunction[R](sf.asInstanceOf[scala.Function1[Long, R]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromLongPredicate(jf: java.util.function.LongPredicate): scala.Function1[java.lang.Long, java.lang.Boolean] = jf match {
+ case AsJavaLongPredicate((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Long, java.lang.Boolean]]
+ case _ => new FromJavaLongPredicate(jf).asInstanceOf[scala.Function1[java.lang.Long, java.lang.Boolean]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaLongPredicate(sf: scala.Function1[java.lang.Long, java.lang.Boolean]): java.util.function.LongPredicate = ((sf): AnyRef) match {
+ case FromJavaLongPredicate((f @ _)) => f.asInstanceOf[java.util.function.LongPredicate]
+ case _ => new AsJavaLongPredicate(sf.asInstanceOf[scala.Function1[Long, Boolean]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromLongSupplier(jf: java.util.function.LongSupplier): scala.Function0[java.lang.Long] = jf match {
+ case AsJavaLongSupplier((f @ _)) => f.asInstanceOf[scala.Function0[java.lang.Long]]
+ case _ => new FromJavaLongSupplier(jf).asInstanceOf[scala.Function0[java.lang.Long]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaLongSupplier(sf: scala.Function0[java.lang.Long]): java.util.function.LongSupplier = ((sf): AnyRef) match {
+ case FromJavaLongSupplier((f @ _)) => f.asInstanceOf[java.util.function.LongSupplier]
+ case _ => new AsJavaLongSupplier(sf.asInstanceOf[scala.Function0[Long]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromLongToDoubleFunction(jf: java.util.function.LongToDoubleFunction): scala.Function1[java.lang.Long, java.lang.Double] = jf match {
+ case AsJavaLongToDoubleFunction((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Long, java.lang.Double]]
+ case _ => new FromJavaLongToDoubleFunction(jf).asInstanceOf[scala.Function1[java.lang.Long, java.lang.Double]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaLongToDoubleFunction(sf: scala.Function1[java.lang.Long, java.lang.Double]): java.util.function.LongToDoubleFunction = ((sf): AnyRef) match {
+ case FromJavaLongToDoubleFunction((f @ _)) => f.asInstanceOf[java.util.function.LongToDoubleFunction]
+ case _ => new AsJavaLongToDoubleFunction(sf.asInstanceOf[scala.Function1[Long, Double]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromLongToIntFunction(jf: java.util.function.LongToIntFunction): scala.Function1[java.lang.Long, java.lang.Integer] = jf match {
+ case AsJavaLongToIntFunction((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Long, java.lang.Integer]]
+ case _ => new FromJavaLongToIntFunction(jf).asInstanceOf[scala.Function1[java.lang.Long, java.lang.Integer]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaLongToIntFunction(sf: scala.Function1[java.lang.Long, java.lang.Integer]): java.util.function.LongToIntFunction = ((sf): AnyRef) match {
+ case FromJavaLongToIntFunction((f @ _)) => f.asInstanceOf[java.util.function.LongToIntFunction]
+ case _ => new AsJavaLongToIntFunction(sf.asInstanceOf[scala.Function1[Long, Int]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromLongUnaryOperator(jf: java.util.function.LongUnaryOperator): scala.Function1[java.lang.Long, java.lang.Long] = jf match {
+ case AsJavaLongUnaryOperator((f @ _)) => f.asInstanceOf[scala.Function1[java.lang.Long, java.lang.Long]]
+ case _ => new FromJavaLongUnaryOperator(jf).asInstanceOf[scala.Function1[java.lang.Long, java.lang.Long]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaLongUnaryOperator(sf: scala.Function1[java.lang.Long, java.lang.Long]): java.util.function.LongUnaryOperator = ((sf): AnyRef) match {
+ case FromJavaLongUnaryOperator((f @ _)) => f.asInstanceOf[java.util.function.LongUnaryOperator]
+ case _ => new AsJavaLongUnaryOperator(sf.asInstanceOf[scala.Function1[Long, Long]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromObjDoubleConsumer[T](jf: java.util.function.ObjDoubleConsumer[T]): scala.Function2[T, java.lang.Double, scala.runtime.BoxedUnit] = jf match {
+ case AsJavaObjDoubleConsumer((f @ _)) => f.asInstanceOf[scala.Function2[T, java.lang.Double, scala.runtime.BoxedUnit]]
+ case _ => new FromJavaObjDoubleConsumer[T](jf).asInstanceOf[scala.Function2[T, java.lang.Double, scala.runtime.BoxedUnit]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaObjDoubleConsumer[T](sf: scala.Function2[T, java.lang.Double, scala.runtime.BoxedUnit]): java.util.function.ObjDoubleConsumer[T] = ((sf): AnyRef) match {
+ case FromJavaObjDoubleConsumer((f @ _)) => f.asInstanceOf[java.util.function.ObjDoubleConsumer[T]]
+ case _ => new AsJavaObjDoubleConsumer[T](sf.asInstanceOf[scala.Function2[T, Double, Unit]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromObjIntConsumer[T](jf: java.util.function.ObjIntConsumer[T]): scala.Function2[T, java.lang.Integer, scala.runtime.BoxedUnit] = jf match {
+ case AsJavaObjIntConsumer((f @ _)) => f.asInstanceOf[scala.Function2[T, java.lang.Integer, scala.runtime.BoxedUnit]]
+ case _ => new FromJavaObjIntConsumer[T](jf).asInstanceOf[scala.Function2[T, java.lang.Integer, scala.runtime.BoxedUnit]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaObjIntConsumer[T](sf: scala.Function2[T, java.lang.Integer, scala.runtime.BoxedUnit]): java.util.function.ObjIntConsumer[T] = ((sf): AnyRef) match {
+ case FromJavaObjIntConsumer((f @ _)) => f.asInstanceOf[java.util.function.ObjIntConsumer[T]]
+ case _ => new AsJavaObjIntConsumer[T](sf.asInstanceOf[scala.Function2[T, Int, Unit]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromObjLongConsumer[T](jf: java.util.function.ObjLongConsumer[T]): scala.Function2[T, java.lang.Long, scala.runtime.BoxedUnit] = jf match {
+ case AsJavaObjLongConsumer((f @ _)) => f.asInstanceOf[scala.Function2[T, java.lang.Long, scala.runtime.BoxedUnit]]
+ case _ => new FromJavaObjLongConsumer[T](jf).asInstanceOf[scala.Function2[T, java.lang.Long, scala.runtime.BoxedUnit]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaObjLongConsumer[T](sf: scala.Function2[T, java.lang.Long, scala.runtime.BoxedUnit]): java.util.function.ObjLongConsumer[T] = ((sf): AnyRef) match {
+ case FromJavaObjLongConsumer((f @ _)) => f.asInstanceOf[java.util.function.ObjLongConsumer[T]]
+ case _ => new AsJavaObjLongConsumer[T](sf.asInstanceOf[scala.Function2[T, Long, Unit]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromPredicate[T](jf: java.util.function.Predicate[T]): scala.Function1[T, java.lang.Boolean] = jf match {
+ case AsJavaPredicate((f @ _)) => f.asInstanceOf[scala.Function1[T, java.lang.Boolean]]
+ case _ => new FromJavaPredicate[T](jf).asInstanceOf[scala.Function1[T, java.lang.Boolean]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaPredicate[T](sf: scala.Function1[T, java.lang.Boolean]): java.util.function.Predicate[T] = ((sf): AnyRef) match {
+ case FromJavaPredicate((f @ _)) => f.asInstanceOf[java.util.function.Predicate[T]]
+ case _ => new AsJavaPredicate[T](sf.asInstanceOf[scala.Function1[T, Boolean]])
+ }
+
+
+ @inline def asScalaFromSupplier[T](jf: java.util.function.Supplier[T]): scala.Function0[T] = jf match {
+ case AsJavaSupplier((f @ _)) => f.asInstanceOf[scala.Function0[T]]
+ case _ => new FromJavaSupplier[T](jf).asInstanceOf[scala.Function0[T]]
+ }
+
+ @inline def asJavaSupplier[T](sf: scala.Function0[T]): java.util.function.Supplier[T] = ((sf): AnyRef) match {
+ case FromJavaSupplier((f @ _)) => f.asInstanceOf[java.util.function.Supplier[T]]
+ case _ => new AsJavaSupplier[T](sf.asInstanceOf[scala.Function0[T]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromToDoubleBiFunction[T, U](jf: java.util.function.ToDoubleBiFunction[T, U]): scala.Function2[T, U, java.lang.Double] = jf match {
+ case AsJavaToDoubleBiFunction((f @ _)) => f.asInstanceOf[scala.Function2[T, U, java.lang.Double]]
+ case _ => new FromJavaToDoubleBiFunction[T, U](jf).asInstanceOf[scala.Function2[T, U, java.lang.Double]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaToDoubleBiFunction[T, U](sf: scala.Function2[T, U, java.lang.Double]): java.util.function.ToDoubleBiFunction[T, U] = ((sf): AnyRef) match {
+ case FromJavaToDoubleBiFunction((f @ _)) => f.asInstanceOf[java.util.function.ToDoubleBiFunction[T, U]]
+ case _ => new AsJavaToDoubleBiFunction[T, U](sf.asInstanceOf[scala.Function2[T, U, Double]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromToDoubleFunction[T](jf: java.util.function.ToDoubleFunction[T]): scala.Function1[T, java.lang.Double] = jf match {
+ case AsJavaToDoubleFunction((f @ _)) => f.asInstanceOf[scala.Function1[T, java.lang.Double]]
+ case _ => new FromJavaToDoubleFunction[T](jf).asInstanceOf[scala.Function1[T, java.lang.Double]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaToDoubleFunction[T](sf: scala.Function1[T, java.lang.Double]): java.util.function.ToDoubleFunction[T] = ((sf): AnyRef) match {
+ case FromJavaToDoubleFunction((f @ _)) => f.asInstanceOf[java.util.function.ToDoubleFunction[T]]
+ case _ => new AsJavaToDoubleFunction[T](sf.asInstanceOf[scala.Function1[T, Double]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromToIntBiFunction[T, U](jf: java.util.function.ToIntBiFunction[T, U]): scala.Function2[T, U, java.lang.Integer] = jf match {
+ case AsJavaToIntBiFunction((f @ _)) => f.asInstanceOf[scala.Function2[T, U, java.lang.Integer]]
+ case _ => new FromJavaToIntBiFunction[T, U](jf).asInstanceOf[scala.Function2[T, U, java.lang.Integer]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaToIntBiFunction[T, U](sf: scala.Function2[T, U, java.lang.Integer]): java.util.function.ToIntBiFunction[T, U] = ((sf): AnyRef) match {
+ case FromJavaToIntBiFunction((f @ _)) => f.asInstanceOf[java.util.function.ToIntBiFunction[T, U]]
+ case _ => new AsJavaToIntBiFunction[T, U](sf.asInstanceOf[scala.Function2[T, U, Int]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromToIntFunction[T](jf: java.util.function.ToIntFunction[T]): scala.Function1[T, java.lang.Integer] = jf match {
+ case AsJavaToIntFunction((f @ _)) => f.asInstanceOf[scala.Function1[T, java.lang.Integer]]
+ case _ => new FromJavaToIntFunction[T](jf).asInstanceOf[scala.Function1[T, java.lang.Integer]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaToIntFunction[T](sf: scala.Function1[T, java.lang.Integer]): java.util.function.ToIntFunction[T] = ((sf): AnyRef) match {
+ case FromJavaToIntFunction((f @ _)) => f.asInstanceOf[java.util.function.ToIntFunction[T]]
+ case _ => new AsJavaToIntFunction[T](sf.asInstanceOf[scala.Function1[T, Int]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromToLongBiFunction[T, U](jf: java.util.function.ToLongBiFunction[T, U]): scala.Function2[T, U, java.lang.Long] = jf match {
+ case AsJavaToLongBiFunction((f @ _)) => f.asInstanceOf[scala.Function2[T, U, java.lang.Long]]
+ case _ => new FromJavaToLongBiFunction[T, U](jf).asInstanceOf[scala.Function2[T, U, java.lang.Long]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaToLongBiFunction[T, U](sf: scala.Function2[T, U, java.lang.Long]): java.util.function.ToLongBiFunction[T, U] = ((sf): AnyRef) match {
+ case FromJavaToLongBiFunction((f @ _)) => f.asInstanceOf[java.util.function.ToLongBiFunction[T, U]]
+ case _ => new AsJavaToLongBiFunction[T, U](sf.asInstanceOf[scala.Function2[T, U, Long]])
+ }
+
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asScalaFromToLongFunction[T](jf: java.util.function.ToLongFunction[T]): scala.Function1[T, java.lang.Long] = jf match {
+ case AsJavaToLongFunction((f @ _)) => f.asInstanceOf[scala.Function1[T, java.lang.Long]]
+ case _ => new FromJavaToLongFunction[T](jf).asInstanceOf[scala.Function1[T, java.lang.Long]]
+ }
+
+ /** Note: this method uses the boxed type `java.lang.X` (or `BoxedUnit`) instead of the
+ * primitive type `scala.X` to improve compatibility when using it in Java code (the
+ * Scala compiler emits `C[Int]` as `C[Object]` in bytecode due to
+ * [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In Scala code, add
+ * `import scala.jdk.FunctionConverters._` and use the extension methods instead.
+ */
+ @inline def asJavaToLongFunction[T](sf: scala.Function1[T, java.lang.Long]): java.util.function.ToLongFunction[T] = ((sf): AnyRef) match {
+ case FromJavaToLongFunction((f @ _)) => f.asInstanceOf[java.util.function.ToLongFunction[T]]
+ case _ => new AsJavaToLongFunction[T](sf.asInstanceOf[scala.Function1[T, Long]])
+ }
+
+
+ @inline def asScalaFromUnaryOperator[T](jf: java.util.function.UnaryOperator[T]): scala.Function1[T, T] = jf match {
+ case AsJavaUnaryOperator((f @ _)) => f.asInstanceOf[scala.Function1[T, T]]
+ case _ => new FromJavaUnaryOperator[T](jf).asInstanceOf[scala.Function1[T, T]]
+ }
+
+ @inline def asJavaUnaryOperator[T](sf: scala.Function1[T, T]): java.util.function.UnaryOperator[T] = ((sf): AnyRef) match {
+ case FromJavaUnaryOperator((f @ _)) => f.asInstanceOf[java.util.function.UnaryOperator[T]]
+ case _ => new AsJavaUnaryOperator[T](sf.asInstanceOf[scala.Function1[T, T]])
+ }
+}
diff --git a/library/src/scala/jdk/javaapi/FutureConverters.scala b/library/src/scala/jdk/javaapi/FutureConverters.scala
new file mode 100644
index 000000000000..d28a8da8a92e
--- /dev/null
+++ b/library/src/scala/jdk/javaapi/FutureConverters.scala
@@ -0,0 +1,89 @@
+/*
+ * 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.javaapi
+
+import java.util.concurrent.{CompletableFuture, CompletionStage}
+import scala.concurrent.impl.FutureConvertersImpl.{CF, P}
+import scala.concurrent.{ExecutionContext, Future}
+import scala.util.Success
+
+/** This object contains methods that convert between Scala [[scala.concurrent.Future]] and Java [[java.util.concurrent.CompletionStage]].
+ *
+ * The explicit conversion methods defined here are intended to be used in Java code. For Scala
+ * code, it is recommended to use the extension methods defined in [[scala.jdk.FutureConverters]].
+ *
+ * Note that the bridge is implemented at the read-only side of asynchronous handles, namely
+ * [[scala.concurrent.Future]] (instead of [[scala.concurrent.Promise]]) and [[java.util.concurrent.CompletionStage]] (instead of
+ * [[java.util.concurrent.CompletableFuture]]). This is intentional, as the semantics of bridging
+ * the write-handles would be prone to race conditions; if both ends (`CompletableFuture` and
+ * `Promise`) are completed independently at the same time, they may contain different values
+ * afterwards. For this reason, `toCompletableFuture` is not supported on the created
+ * `CompletionStage`s.
+ */
+object FutureConverters {
+ /** Returns a [[java.util.concurrent.CompletionStage]] that will be completed with the same value or exception as the
+ * given Scala [[scala.concurrent.Future]] when that completes. Since the Future is a read-only representation,
+ * this CompletionStage does not support the `toCompletableFuture` method.
+ *
+ * The semantics of Scala Future demand that all callbacks are invoked asynchronously by default,
+ * therefore the returned CompletionStage routes all calls to synchronous transformations to
+ * their asynchronous counterparts, i.e., `thenRun` will internally call `thenRunAsync`.
+ *
+ * @param f The Scala Future which may eventually supply the completion for the returned
+ * CompletionStage
+ * @return a CompletionStage that runs all callbacks asynchronously and does not support the
+ * CompletableFuture interface
+ */
+ def asJava[T](f: Future[T]): CompletionStage[T] = {
+ f match {
+ case p: P[T] => p.wrapped
+ // in theory not safe (could be `class C extends Future[A] with CompletionStage[B]`):
+ case c: CompletionStage[T @unchecked] => c
+ case _ =>
+ val cf = new CF[T](f)
+ f.onComplete(cf)(ExecutionContext.parasitic)
+ cf
+ }
+ }
+
+ /** Returns a Scala [[scala.concurrent.Future]] that will be completed with the same value or exception as the
+ * given [[java.util.concurrent.CompletionStage]] when that completes. Transformations of the returned Future are
+ * executed asynchronously as specified by the ExecutionContext that is given to the combinator
+ * methods.
+ *
+ * @param cs The CompletionStage which may eventually supply the completion for the returned
+ * Scala Future
+ * @return a Scala Future that represents the CompletionStage's completion
+ */
+ def asScala[T](cs: CompletionStage[T]): Future[T] = {
+ cs match {
+ case cf: CF[T] => cf.wrapped
+ // in theory not safe (could be `class C extends Future[A] with CompletionStage[B]`):
+ case f: Future[T @unchecked] => f
+ case _ =>
+ val p = new P[T](cs)
+ val completedCF = cs match {
+ case cf0: CompletableFuture[T @unchecked] =>
+ // drop `MinimalStage` (scala/bug#12918)
+ val cf = cf0.toCompletableFuture
+ if (cf.isDone && !cf.isCompletedExceptionally) cf else null
+ case _ => null
+ }
+ if (completedCF != null)
+ p.tryComplete(Success(completedCF.join()))
+ else
+ cs.handle(p)
+ p.future
+ }
+ }
+}
diff --git a/library/src/scala/jdk/javaapi/OptionConverters.scala b/library/src/scala/jdk/javaapi/OptionConverters.scala
new file mode 100644
index 000000000000..27ae7b4e6060
--- /dev/null
+++ b/library/src/scala/jdk/javaapi/OptionConverters.scala
@@ -0,0 +1,84 @@
+/*
+ * 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.javaapi
+
+import java.util.{Optional, OptionalDouble, OptionalInt, OptionalLong}
+import java.{lang => jl}
+
+/** This object contains methods that convert between Scala `Option` and Java `Optional` types.
+ *
+ * The explicit conversion methods defined here are intended to be used in Java code. For Scala
+ * code, it is recommended to use the extension methods defined in [[scala.jdk.OptionConverters]].
+ *
+ * @define primitiveNote Note: this method uses the boxed type `java.lang.X` instead of the
+ * primitive type `scala.X` to improve compatibility when using it in
+ * Java code (the Scala compiler emits `C[Int]` as `C[Object]` in bytecode
+ * due to [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In
+ * Scala code, add `import scala.jdk.OptionConverters._` and use the
+ * extension methods instead.
+ */
+object OptionConverters {
+ /** Convert a Scala `Option` to a Java `Optional` */
+ def toJava[A](o: Option[A]): Optional[A] = o match {
+ case Some(a) => Optional.ofNullable(a)
+ case _ => Optional.empty[A]
+ }
+
+ /** Convert a Scala `Option[java.lang.Double]` to a Java `OptionalDouble`
+ *
+ * $primitiveNote
+ */
+ def toJavaOptionalDouble(o: Option[jl.Double]): OptionalDouble = o match {
+ case Some(a) => OptionalDouble.of(a)
+ case _ => OptionalDouble.empty
+ }
+
+ /** Convert a Scala `Option[java.lang.Integer]` to a Java `OptionalInt`
+ *
+ * $primitiveNote
+ */
+ def toJavaOptionalInt(o: Option[jl.Integer]): OptionalInt = o match {
+ case Some(a) => OptionalInt.of(a)
+ case _ => OptionalInt.empty
+ }
+
+ /** Convert a Scala `Option[java.lang.Long]` to a Java `OptionalLong`
+ *
+ * $primitiveNote
+ */
+ def toJavaOptionalLong(o: Option[jl.Long]): OptionalLong = o match {
+ case Some(a) => OptionalLong.of(a)
+ case _ => OptionalLong.empty
+ }
+
+ /** Convert a Java `Optional` to a Scala `Option` */
+ def toScala[A](o: Optional[A]): Option[A] = if (o.isPresent) Some(o.get) else None
+
+ /** Convert a Java `OptionalDouble` to a Scala `Option[java.lang.Double]`
+ *
+ * $primitiveNote
+ */
+ def toScala(o: OptionalDouble): Option[jl.Double] = if (o.isPresent) Some(o.getAsDouble) else None
+
+ /** Convert a Java `OptionalInt` to a Scala `Option[java.lang.Integer]`
+ *
+ * $primitiveNote
+ */
+ def toScala(o: OptionalInt): Option[jl.Integer] = if (o.isPresent) Some(o.getAsInt) else None
+
+ /** Convert a Java `OptionalLong` to a Scala `Option[java.lang.Long]`
+ *
+ * $primitiveNote
+ */
+ def toScala(o: OptionalLong): Option[jl.Long] = if (o.isPresent) Some(o.getAsLong) else None
+}
diff --git a/library/src/scala/jdk/javaapi/StreamConverters.scala b/library/src/scala/jdk/javaapi/StreamConverters.scala
new file mode 100644
index 000000000000..d5adeb84ab71
--- /dev/null
+++ b/library/src/scala/jdk/javaapi/StreamConverters.scala
@@ -0,0 +1,356 @@
+/*
+ * 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.javaapi
+
+import java.util.stream.{DoubleStream, IntStream, LongStream, Stream, StreamSupport}
+import java.{lang => jl}
+
+/** This object contains methods to create Java Streams that operate on Scala collections
+ * (sequentially or in parallel). For more information on Java streams, consult the documentation
+ * ([[https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html]]).
+ *
+ * The explicit conversion methods defined here are intended to be used in Java code. For Scala
+ * code, it is recommended to use the extension methods defined in [[scala.jdk.StreamConverters]].
+ *
+ * Note: to convert between Scala collections and classic Java collections, use
+ * [[CollectionConverters]].
+ *
+ * For details how the stream converters work, see [[scala.jdk.StreamConverters]].
+ *
+ * @define parNote Note: parallel processing is only efficient for collections that have a
+ * [[scala.collection.Stepper]] implementation which supports efficient splitting. For collections
+ * where this is the case, the [[scala.collection.IterableOnce.stepper `stepper`]]
+ * method has a return type marked `with EfficientSplit`.
+ *
+ * @define primitiveNote Note: this method uses the boxed type `java.lang.X` instead of the
+ * primitive type `scala.X` to improve compatibility when using it in
+ * Java code (the Scala compiler emits `C[Int]` as `C[Object]` in bytecode
+ * due to [[https://github.com/scala/bug/issues/4214 scala/bug#4214]]). In
+ * Scala code, add `import scala.jdk.StreamConverters._` and use the
+ * extension methods instead.
+ */
+object StreamConverters {
+ /////////////////////////////////////
+ // sequential streams for collections
+ /////////////////////////////////////
+
+ /** Create a sequential [[java.util.stream.Stream Java Stream]] for a Scala collection. */
+ def asJavaSeqStream[A](cc: IterableOnce[A]): Stream[A] = StreamSupport.stream(cc.stepper.spliterator, false)
+
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for a Scala collection.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqIntStream (cc: IterableOnce[jl.Integer]): IntStream = StreamSupport.intStream(cc.stepper.spliterator, false)
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for a Scala collection.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqIntStreamFromByte (cc: IterableOnce[jl.Byte]): IntStream = StreamSupport.intStream(cc.stepper.spliterator, false)
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for a Scala collection.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqIntStreamFromShort(cc: IterableOnce[jl.Short]): IntStream = StreamSupport.intStream(cc.stepper.spliterator, false)
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for a Scala collection.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqIntStreamFromChar (cc: IterableOnce[jl.Character]): IntStream = StreamSupport.intStream(cc.stepper.spliterator, false)
+
+ /** Create a sequential [[java.util.stream.DoubleStream Java DoubleStream]] for a Scala collection.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqDoubleStream (cc: IterableOnce[jl.Double]): DoubleStream = StreamSupport.doubleStream(cc.stepper.spliterator, false)
+ /** Create a sequential [[java.util.stream.DoubleStream Java DoubleStream]] for a Scala collection.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqDoubleStreamFromFloat(cc: IterableOnce[jl.Float]): DoubleStream = StreamSupport.doubleStream(cc.stepper.spliterator, false)
+
+ /** Create a sequential [[java.util.stream.LongStream Java LongStream]] for a Scala collection.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqLongStream(cc: IterableOnce[jl.Long]): LongStream = StreamSupport.longStream(cc.stepper.spliterator, false)
+
+ // Map Key Streams
+
+ /** Create a sequential [[java.util.stream.Stream Java Stream]] for the keys of a Scala Map. */
+ def asJavaSeqKeyStream[K, V](m: collection.Map[K, V]): Stream[K] = StreamSupport.stream(m.keyStepper.spliterator, false)
+
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for the keys of a Scala Map.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqKeyIntStream [V](m: collection.Map[jl.Integer, V]): IntStream = StreamSupport.intStream(m.keyStepper.spliterator, false)
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for the keys of a Scala Map.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqKeyIntStreamFromByte [V](m: collection.Map[jl.Byte, V]): IntStream = StreamSupport.intStream(m.keyStepper.spliterator, false)
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for the keys of a Scala Map.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqKeyIntStreamFromShort[V](m: collection.Map[jl.Short, V]): IntStream = StreamSupport.intStream(m.keyStepper.spliterator, false)
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for the keys of a Scala Map.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqKeyIntStreamFromChar [V](m: collection.Map[jl.Character, V]): IntStream = StreamSupport.intStream(m.keyStepper.spliterator, false)
+
+ /** Create a sequential [[java.util.stream.DoubleStream Java DoubleStream]] for the keys of a Scala Map.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqKeyDoubleStream [V](m: collection.Map[jl.Double, V]): DoubleStream = StreamSupport.doubleStream(m.keyStepper.spliterator, false)
+ /** Create a sequential [[java.util.stream.DoubleStream Java DoubleStream]] for the keys of a Scala Map.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqKeyDoubleStreamFromFloat[V](m: collection.Map[jl.Float, V]): DoubleStream = StreamSupport.doubleStream(m.keyStepper.spliterator, false)
+
+ /** Create a sequential [[java.util.stream.LongStream Java LongStream]] for the keys of a Scala Map.
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqKeyLongStream[V](m: collection.Map[jl.Long, V]): LongStream = StreamSupport.longStream(m.keyStepper.spliterator, false)
+
+ // Map Value Streams
+
+ /** Create a sequential [[java.util.stream.Stream Java Stream]] for the values of a Scala Map. */
+ def asJavaSeqValueStream[K, V](m: collection.Map[K, V]): Stream[V] = StreamSupport.stream(m.valueStepper.spliterator, false)
+
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for the values of a
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqValueIntStream [K](m: collection.Map[K, jl.Integer]): IntStream = StreamSupport.intStream(m.valueStepper.spliterator, false)
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for the values of a
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqValueIntStreamFromByte [K](m: collection.Map[K, jl.Byte]): IntStream = StreamSupport.intStream(m.valueStepper.spliterator, false)
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for the values of a
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqValueIntStreamFromShort[K](m: collection.Map[K, jl.Short]): IntStream = StreamSupport.intStream(m.valueStepper.spliterator, false)
+ /** Create a sequential [[java.util.stream.IntStream Java IntStream]] for the values of a
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqValueIntStreamFromChar [K](m: collection.Map[K, jl.Character]): IntStream = StreamSupport.intStream(m.valueStepper.spliterator, false)
+
+ /** Create a sequential [[java.util.stream.DoubleStream Java DoubleStream]] for the values of a
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqValueDoubleStream [K](m: collection.Map[K, jl.Double]): DoubleStream = StreamSupport.doubleStream(m.valueStepper.spliterator, false)
+ /** Create a sequential [[java.util.stream.DoubleStream Java DoubleStream]] for the values of a
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqValueDoubleStreamFromFloat[K](m: collection.Map[K, jl.Float]): DoubleStream = StreamSupport.doubleStream(m.valueStepper.spliterator, false)
+
+ /** Create a sequential [[java.util.stream.LongStream Java LongStream]] for the values of a
+ *
+ * $primitiveNote
+ */
+ def asJavaSeqValueLongStream[K](m: collection.Map[K, jl.Long]): LongStream = StreamSupport.longStream(m.valueStepper.spliterator, false)
+
+ ///////////////////////////////////
+ // parallel streams for collections
+ ///////////////////////////////////
+
+ /** Create a parallel [[java.util.stream.Stream Java Stream]] for a Scala collection.
+ *
+ * $parNote
+ */
+ def asJavaParStream[A](cc: IterableOnce[A]): Stream[A] = StreamSupport.stream(cc.stepper.spliterator, true)
+
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for a Scala collection.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParIntStream (cc: IterableOnce[jl.Integer]): IntStream = StreamSupport.intStream(cc.stepper.spliterator, true)
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for a Scala collection.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParIntStreamFromByte (cc: IterableOnce[jl.Byte]): IntStream = StreamSupport.intStream(cc.stepper.spliterator, true)
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for a Scala collection.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParIntStreamFromShort(cc: IterableOnce[jl.Short]): IntStream = StreamSupport.intStream(cc.stepper.spliterator, true)
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for a Scala collection.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParIntStreamFromChar (cc: IterableOnce[jl.Character]): IntStream = StreamSupport.intStream(cc.stepper.spliterator, true)
+
+ /** Create a parallel [[java.util.stream.DoubleStream Java DoubleStream]] for a Scala collection.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParDoubleStream (cc: IterableOnce[jl.Double]): DoubleStream = StreamSupport.doubleStream(cc.stepper.spliterator, true)
+ /** Create a parallel [[java.util.stream.DoubleStream Java DoubleStream]] for a Scala collection.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParDoubleStreamFromFloat(cc: IterableOnce[jl.Float]): DoubleStream = StreamSupport.doubleStream(cc.stepper.spliterator, true)
+
+ /** Create a parallel [[java.util.stream.LongStream Java LongStream]] for a Scala collection.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParLongStream(cc: IterableOnce[jl.Long]): LongStream = StreamSupport.longStream(cc.stepper.spliterator, true)
+
+
+ // Map Key Streams
+
+ /** Create a parallel [[java.util.stream.Stream Java Stream]] for the keys of a Scala Map.
+ *
+ * $parNote
+ */
+ def asJavaParKeyStream[K, V](m: collection.Map[K, V]): Stream[K] = StreamSupport.stream(m.keyStepper.spliterator, true)
+
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for the keys of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParKeyIntStream [V](m: collection.Map[jl.Integer, V]): IntStream = StreamSupport.intStream(m.keyStepper.spliterator, true)
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for the keys of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParKeyIntStreamFromByte [V](m: collection.Map[jl.Byte, V]): IntStream = StreamSupport.intStream(m.keyStepper.spliterator, true)
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for the keys of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParKeyIntStreamFromShort[V](m: collection.Map[jl.Short, V]): IntStream = StreamSupport.intStream(m.keyStepper.spliterator, true)
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for the keys of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParKeyIntStreamFromChar [V](m: collection.Map[jl.Character, V]): IntStream = StreamSupport.intStream(m.keyStepper.spliterator, true)
+
+ /** Create a parallel [[java.util.stream.DoubleStream Java DoubleStream]] for the keys of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParKeyDoubleStream [V](m: collection.Map[jl.Double, V]): DoubleStream = StreamSupport.doubleStream(m.keyStepper.spliterator, true)
+ /** Create a parallel [[java.util.stream.DoubleStream Java DoubleStream]] for the keys of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParKeyDoubleStreamFromFloat[V](m: collection.Map[jl.Float, V]): DoubleStream = StreamSupport.doubleStream(m.keyStepper.spliterator, true)
+
+ /** Create a parallel [[java.util.stream.LongStream Java LongStream]] for the keys of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParKeyLongStream[V](m: collection.Map[jl.Long, V]): LongStream = StreamSupport.longStream(m.keyStepper.spliterator, true)
+
+ // Map Value Streams
+
+ /** Create a parallel [[java.util.stream.Stream Java Stream]] for the values of a Scala Map.
+ *
+ * $parNote
+ */
+ def asJavaParValueStream[K, V](m: collection.Map[K, V]): Stream[V] = StreamSupport.stream(m.valueStepper.spliterator, true)
+
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for the values of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParValueIntStream [K](m: collection.Map[K, jl.Integer]): IntStream = StreamSupport.intStream(m.valueStepper.spliterator, true)
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for the values of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParValueIntStreamFromByte [K](m: collection.Map[K, jl.Byte]): IntStream = StreamSupport.intStream(m.valueStepper.spliterator, true)
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for the values of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParValueIntStreamFromShort[K](m: collection.Map[K, jl.Short]): IntStream = StreamSupport.intStream(m.valueStepper.spliterator, true)
+ /** Create a parallel [[java.util.stream.IntStream Java IntStream]] for the values of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParValueIntStreamFromChar [K](m: collection.Map[K, jl.Character]): IntStream = StreamSupport.intStream(m.valueStepper.spliterator, true)
+
+ /** Create a parallel [[java.util.stream.DoubleStream Java DoubleStream]] for the values of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParValueDoubleStream [K](m: collection.Map[K, jl.Double]): DoubleStream = StreamSupport.doubleStream(m.valueStepper.spliterator, true)
+ /** Create a parallel [[java.util.stream.DoubleStream Java DoubleStream]] for the values of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParValueDoubleStreamFromFloat[K](m: collection.Map[K, jl.Float]): DoubleStream = StreamSupport.doubleStream(m.valueStepper.spliterator, true)
+
+ /** Create a parallel [[java.util.stream.LongStream Java LongStream]] for the values of a Scala Map.
+ *
+ * $parNote
+ *
+ * $primitiveNote
+ */
+ def asJavaParValueLongStream[K](m: collection.Map[K, jl.Long]): LongStream = StreamSupport.longStream(m.valueStepper.spliterator, true)
+}
diff --git a/library/src/scala/jdk/package.scala b/library/src/scala/jdk/package.scala
new file mode 100644
index 000000000000..386a6886cefd
--- /dev/null
+++ b/library/src/scala/jdk/package.scala
@@ -0,0 +1,46 @@
+/*
+ * 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
+
+/** The jdk package contains utilities to interact with JDK classes.
+ *
+ * This packages offers a number of converters, that are able to wrap or copy
+ * types from the scala library to equivalent types in the JDK class library
+ * and vice versa:
+ *
+ * - [[CollectionConverters]], converting collections like [[scala.collection.Seq]],
+ * [[scala.collection.Map]], [[scala.collection.Set]],
+ * [[scala.collection.mutable.Buffer]], [[scala.collection.Iterator]]
+ * and [[scala.collection.Iterable]] to their JDK counterparts
+ * - [[OptionConverters]], converting between [[Option]] and
+ * [[java.util.Optional]] and primitive variations
+ * - [[StreamConverters]], to create JDK Streams from scala collections
+ * - [[DurationConverters]], for conversions between scala
+ * [[scala.concurrent.duration.FiniteDuration]] and [[java.time.Duration]]
+ * - [[FunctionConverters]], from scala Functions to java
+ * [[java.util.function.Function]], [[java.util.function.UnaryOperator]],
+ * [[java.util.function.Consumer]] and [[java.util.function.Predicate]], as
+ * well as primitive variations and Bi-variations.
+ *
+ * By convention, converters that wrap an object to provide a different
+ * interface to the same underlying data structure use .asScala and .asJava
+ * extension methods, whereas converters that copy the underlying data structure
+ * use .toScala and .toJava.
+ *
+ * In the [[javaapi]] package, the same converters can be found with a
+ * java-friendly interface that don't rely on implicit enrichments.
+ *
+ * Additionally, this package offers [[Accumulator]]s, capable of efficiently
+ * traversing JDK Streams.
+ **/
+package object jdk
diff --git a/library/src/scala/language.scala b/library/src/scala/language.scala
new file mode 100644
index 000000000000..72f523fa08b4
--- /dev/null
+++ b/library/src/scala/language.scala
@@ -0,0 +1,531 @@
+/*
+ * 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
+
+import scala.annotation.compileTimeOnly
+
+/**
+ * The `scala.language` object controls the language features available to the programmer, as proposed in the
+ * [[https://docs.google.com/document/d/1nlkvpoIRkx7at1qJEZafJwthZ3GeIklTFhqmXMvTX9Q/edit '''SIP-18 document''']].
+ *
+ * Each of these features has to be explicitly imported into the current scope to become available:
+ * {{{
+ * import language.postfixOps // or language._
+ * List(1, 2, 3) reverse
+ * }}}
+ *
+ * The language features are:
+ * - [[dynamics `dynamics`]] enables defining calls rewriting using the [[scala.Dynamic `Dynamic`]] trait
+ * - [[existentials `existentials`]] enables writing existential types
+ * - [[higherKinds `higherKinds`]] enables writing higher-kinded types
+ * - [[implicitConversions `implicitConversions`]] enables defining implicit methods and members
+ * - [[postfixOps `postfixOps`]] enables postfix operators (not recommended)
+ * - [[reflectiveCalls `reflectiveCalls`]] enables using structural types
+ * - [[experimental `experimental`]] contains newer features that have not yet been tested in production
+ *
+ * @groupname production Language Features
+ * @groupname experimental Experimental Language Features
+ * @groupprio experimental 10
+ */
+object language {
+
+ import languageFeature._
+
+ /** Only where this feature is enabled, can direct or indirect subclasses of trait scala.Dynamic
+ * be defined. If `dynamics` is not enabled, a definition of a class, trait,
+ * or object that has `Dynamic` as a base trait is rejected by the compiler.
+ *
+ * Selections of dynamic members of existing subclasses of trait `Dynamic` are unaffected;
+ * they can be used anywhere.
+ *
+ * '''Why introduce the feature?''' To enable flexible DSLs and convenient interfacing
+ * with dynamic languages.
+ *
+ * '''Why control it?''' Dynamic member selection can undermine static checkability
+ * of programs. Furthermore, dynamic member selection often relies on reflection,
+ * which is not available on all platforms.
+ *
+ * @group production
+ */
+ implicit lazy val dynamics: dynamics = languageFeature.dynamics
+
+ /** Only where this feature is enabled, is postfix operator notation `(expr op)` permitted.
+ * If `postfixOps` is not enabled, an expression using postfix notation is rejected by the compiler.
+ *
+ * '''Why keep the feature?''' Postfix notation is preserved for backward
+ * compatibility only. Historically, several DSLs written in Scala need the notation.
+ *
+ * '''Why control it?''' Postfix operators interact poorly with semicolon inference.
+ * Most programmers avoid them for this reason alone. Postfix syntax is
+ * associated with an abuse of infix notation, `a op1 b op2 c op3`,
+ * that can be harder to read than ordinary method invocation with judicious
+ * use of parentheses. It is recommended not to enable this feature except for
+ * legacy code.
+ *
+ * @group production
+ */
+ implicit lazy val postfixOps: postfixOps = languageFeature.postfixOps
+
+ /** Where this feature is enabled, accesses to members of structural types that need
+ * reflection are supported. If `reflectiveCalls` is not enabled, an expression
+ * requiring reflection will trigger a warning from the compiler.
+ *
+ * A structural type is a type of the form
+ * `Parents { Decls }` where `Decls` contains declarations of new members that do
+ * not override any member in `Parents`. To access one of these members, a
+ * reflective call is needed.
+ *
+ * '''Why keep the feature?''' Structural types provide great flexibility because
+ * they avoid the need to define inheritance hierarchies a priori. Besides,
+ * their definition falls out quite naturally from Scala’s concept of type refinement.
+ *
+ * '''Why control it?''' Reflection is not available on all platforms. Popular tools
+ * such as ProGuard have problems dealing with it. Even where reflection is available,
+ * reflective dispatch can lead to surprising performance degradations.
+ *
+ * @group production
+ */
+ implicit lazy val reflectiveCalls: reflectiveCalls = languageFeature.reflectiveCalls
+
+ /** Where this feature is enabled, definitions of implicit conversion methods are allowed.
+ * If `implicitConversions` is not enabled, the definition of an implicit
+ * conversion method will trigger a warning from the compiler.
+ *
+ * An implicit conversion is an implicit value of unary function type `A => B`,
+ * or an implicit method that has in its first parameter section a single,
+ * non-implicit parameter. Examples:
+ *
+ * {{{
+ * implicit def intToString(i: Int): String = s"\$i"
+ * implicit val conv: Int => String = i => s"\$i"
+ * implicit val numerals: List[String] = List("zero", "one", "two", "three")
+ * implicit val strlen: String => Int = _.length
+ * implicit def listToInt[T](xs: List[T])(implicit f: T => Int): Int = xs.map(f).sum
+ * }}}
+ *
+ * This language feature warns only for implicit conversions introduced by methods.
+ *
+ * Other values, including functions or data types which extend `Function1`,
+ * such as `Map`, `Set`, and `List`, do not warn.
+ *
+ * Implicit class definitions, which introduce a conversion to the wrapping class,
+ * also do not warn.
+ *
+ * '''Why keep the feature?''' Implicit conversions are central to many aspects
+ * of Scala’s core libraries.
+ *
+ * '''Why control it?''' Implicit conversions are known to cause many pitfalls
+ * if over-used. And there is a tendency to over-use them because they look
+ * very powerful and their effects seem to be easy to understand. Also, in
+ * most situations using implicit parameters leads to a better design than
+ * implicit conversions.
+ *
+ * @group production
+ */
+ implicit lazy val implicitConversions: implicitConversions = languageFeature.implicitConversions
+
+ /** Where this feature is enabled, higher-kinded types can be written.
+ * If `higherKinds` is not enabled, a higher-kinded type such as `F[A]`
+ * will trigger a warning from the compiler.
+ *
+ * '''Why keep the feature?''' Higher-kinded types enable the definition of very general
+ * abstractions such as functor, monad, or arrow. A significant set of advanced
+ * libraries relies on them. Higher-kinded types are also at the core of the
+ * scala-virtualized effort to produce high-performance parallel DSLs through staging.
+ *
+ * '''Why control it?''' Higher kinded types in Scala lead to a Turing-complete
+ * type system, where compiler termination is no longer guaranteed. They tend
+ * to be useful mostly for type-level computation and for highly generic design
+ * patterns. The level of abstraction implied by these design patterns is often
+ * a barrier to understanding for newcomers to a Scala codebase. Some syntactic
+ * aspects of higher-kinded types are hard to understand for the uninitiated and
+ * type inference is less effective for them than for normal types. Because we are
+ * not completely happy with them yet, it is possible that some aspects of
+ * higher-kinded types will change in future versions of Scala. So an explicit
+ * enabling also serves as a warning that code involving higher-kinded types
+ * might have to be slightly revised in the future.
+ *
+ * @group production
+ */
+ @deprecated("higherKinds no longer needs to be imported explicitly", "2.13.1")
+ implicit lazy val higherKinds: higherKinds = languageFeature.higherKinds
+
+ /** Where this feature is enabled, existential types that cannot be expressed as wildcard
+ * types can be written and are allowed in inferred types of values or return
+ * types of methods. If `existentials` is not enabled, those cases will trigger
+ * a warning from the compiler.
+ *
+ * Existential types with wildcard type syntax such as `List[_]`,
+ * or `Map[String, _]` are not affected.
+ *
+ * '''Why keep the feature?''' Existential types are needed to make sense of Java’s wildcard
+ * types and raw types and the erased types of run-time values.
+ *
+ * '''Why control it?''' Having complex existential types in a code base usually makes
+ * application code very brittle, with a tendency to produce type errors with
+ * obscure error messages. Therefore, going overboard with existential types
+ * is generally perceived not to be a good idea. Also, complicated existential types
+ * might be no longer supported in a future simplification of the language.
+ *
+ * @group production
+ */
+ implicit lazy val existentials: existentials = languageFeature.existentials
+
+ /** The experimental object contains features that are known to have unstable API or
+ * behavior that may change in future releases.
+ *
+ * Experimental features '''may undergo API changes''' in future releases, so production
+ * code should not rely on them.
+ *
+ * Programmers are encouraged to try out experimental features and
+ * [[https://github.com/scala/bug/issues report any bugs or API inconsistencies]]
+ * they encounter so they can be improved in future releases.
+ *
+ * @group experimental
+ */
+ object experimental {
+
+ import languageFeature.experimental._
+
+ /** Only where this feature is enabled, are macro definitions allowed.
+ * If `macros` is not enabled, macro definitions are rejected by the compiler.
+ *
+ * Macro implementations and macro applications are not governed by this
+ * language feature; they can be used anywhere.
+ *
+ * '''Why introduce the feature?''' Macros promise to make the language more regular,
+ * replacing ad-hoc language constructs with a general powerful abstraction
+ * capability that can express them. Macros are also a more disciplined and
+ * powerful replacement for compiler plugins.
+ *
+ * '''Why control it?''' For their very power, macros can lead to code that is hard
+ * to debug and understand.
+ */
+ implicit lazy val macros: macros = languageFeature.experimental.macros
+
+ /* Experimental support for richer dependent types (disabled for now)
+ * One can still run the compiler with support for parsing singleton applications
+ * using command line option `-language:experimental.dependent`.
+ * But one cannot use a feature import for this as long as this entry is commented out.
+ */
+ //object dependent
+
+ /** Experimental support for named type arguments.
+ *
+ * @see [[https://dotty.epfl.ch/docs/reference/other-new-features/named-typeargs]]
+ */
+ @compileTimeOnly("`namedTypeArguments` can only be used at compile time in import statements")
+ object namedTypeArguments
+
+ /** Experimental support for generic number literals.
+ *
+ * @see [[https://dotty.epfl.ch/docs/reference/changed-features/numeric-literals]]
+ */
+ @compileTimeOnly("`genericNumberLiterals` can only be used at compile time in import statements")
+ object genericNumberLiterals
+
+ /** Experimental support for `erased` modifier
+ *
+ * @see [[https://dotty.epfl.ch/docs/reference/experimental/erased-defs]]
+ */
+ @compileTimeOnly("`erasedDefinitions` can only be used at compile time in import statements")
+ object erasedDefinitions
+
+ /** Experimental support for using indentation for arguments
+ */
+ @compileTimeOnly("`fewerBraces` can only be used at compile time in import statements")
+ @deprecated("`fewerBraces` is now standard, no language import is needed", since = "3.3")
+ object fewerBraces
+
+ /** Experimental support for typechecked exception capabilities
+ *
+ * @see [[https://dotty.epfl.ch/docs/reference/experimental/canthrow]]
+ */
+ @compileTimeOnly("`saferExceptions` can only be used at compile time in import statements")
+ object saferExceptions
+
+ /** Adds support for clause interleaving:
+ * Methods can now have as many type clauses as they like, this allows to have type bounds depend on terms: `def f(x: Int)[A <: x.type]: A`
+ *
+ * @see [[https://github.com/scala/improvement-proposals/blob/main/content/clause-interleaving.md]]
+ */
+ @compileTimeOnly("`clauseInterleaving` can only be used at compile time in import statements")
+ @deprecated("`clauseInterleaving` is now standard, no language import is needed", since = "3.6")
+ object clauseInterleaving
+
+ /** Experimental support for pure function type syntax
+ *
+ * @see [[https://dotty.epfl.ch/docs/reference/experimental/purefuns]]
+ */
+ @compileTimeOnly("`pureFunctions` can only be used at compile time in import statements")
+ object pureFunctions
+
+ /** Experimental support for capture checking; implies support for pureFunctions
+ *
+ * @see [[https://dotty.epfl.ch/docs/reference/experimental/cc]]
+ */
+ @compileTimeOnly("`captureChecking` can only be used at compile time in import statements")
+ object captureChecking
+
+ /** Experimental support for automatic conversions of arguments, without requiring
+ * a language import `import scala.language.implicitConversions`.
+ *
+ * @see [[https://dotty.epfl.ch/docs/reference/experimental/into-modifier]]
+ */
+ @compileTimeOnly("`into` can only be used at compile time in import statements")
+ object into
+
+ /** Experimental support for named tuples.
+ *
+ * @see [[https://dotty.epfl.ch/docs/reference/experimental/named-tuples]]
+ */
+ @compileTimeOnly("`namedTuples` can only be used at compile time in import statements")
+ object namedTuples
+
+ /** Experimental support for new features for better modularity, including
+ * - better tracking of dependencies through classes
+ * - better usability of context bounds
+ * - better syntax and conventions for type classes
+ * - ability to merge exported types in intersections
+ *
+ * @see [[https://dotty.epfl.ch/docs/reference/experimental/modularity]]
+ * @see [[https://dotty.epfl.ch/docs/reference/experimental/typeclasses]]
+ */
+ @compileTimeOnly("`modularity` can only be used at compile time in import statements")
+ object modularity
+
+ /** Was needed to add support for relaxed imports of extension methods.
+ * The language import is no longer needed as this is now a standard feature since SIP was accepted.
+ * @see [[http://dotty.epfl.ch/docs/reference/contextual/extension-methods]]
+ */
+ @compileTimeOnly("`relaxedExtensionImports` can only be used at compile time in import statements")
+ @deprecated("The experimental.relaxedExtensionImports language import is no longer needed since the feature is now standard", since = "3.4")
+ object relaxedExtensionImports
+
+ /** Enhance match type extractors to follow aliases and singletons.
+ *
+ * @see [[https://github.com/scala/improvement-proposals/pull/84]]
+ */
+ @compileTimeOnly("`betterMatchTypeExtractors` can only be used at compile time in import statements")
+ @deprecated("The experimental.betterMatchTypeExtractors language import is no longer needed since the feature is now standard. It now has no effect, including when setting an older source version.", since = "3.6")
+ object betterMatchTypeExtractors
+
+ /** Experimental support for quote pattern matching with polymorphic functions
+ *
+ * @see [[https://dotty.epfl.ch/docs/reference/experimental/quoted-patterns-with-polymorphic-functions]]
+ */
+ @compileTimeOnly("`quotedPatternsWithPolymorphicFunctions` can only be used at compile time in import statements")
+ object quotedPatternsWithPolymorphicFunctions
+
+ /** Experimental support for improvements in `for` comprehensions
+ *
+ * @see [[https://github.com/scala/improvement-proposals/pull/79]]
+ */
+ @compileTimeOnly("`betterFors` can only be used at compile time in import statements")
+ object betterFors
+
+ }
+
+ /** The deprecated object contains features that are no longer officially suypported in Scala.
+ * Features in this object are slated for removal. New code should not use them and
+ * old code should migrate away from them.
+ */
+ @compileTimeOnly("`deprecated` can only be used at compile time in import statements")
+ object deprecated:
+
+ /** Symbol literals have been deprecated since 2.13. Since Scala 3.0 they
+ * are no longer an official part of Scala. For compatibility with legacy software,
+ * symbol literals are still supported with a language import, but new software
+ * should not use them.
+ */
+ @compileTimeOnly("`symbolLiterals` can only be used at compile time in import statements")
+ object symbolLiterals
+
+ end deprecated
+
+ /** Where imported, auto-tupling is disabled.
+ *
+ * '''Why control the feature?''' Auto-tupling can lead to confusing and
+ * brittle code in presence of overloads. In particular, surprising overloads
+ * can be selected, and adding new overloads can change which overload is selected
+ * in suprising ways.
+ *
+ * '''Why allow it?''' Not allowing auto-tupling is difficult to reconcile with
+ * operators accepting tuples.
+ */
+ @compileTimeOnly("`noAutoTupling` can only be used at compile time in import statements")
+ object noAutoTupling
+
+ /** Where imported, loose equality using eqAny is disabled.
+ *
+ * '''Why allow and control the feature?''' For compatibility and migration reasons,
+ * strict equality is opt-in. See linked documentation for more information.
+ *
+ * @see [[https://dotty.epfl.ch/docs/reference/contextual/multiversal-equality]]
+ */
+ @compileTimeOnly("`strictEquality` can only be used at compile time in import statements")
+ object strictEquality
+
+ /** Where imported, ad hoc extensions of non-open classes in other
+ * compilation units are allowed.
+ *
+ * '''Why control the feature?''' Ad-hoc extensions should usually be avoided
+ * since they typically cannot rely on an "internal" contract between a class
+ * and its extensions. Only open classes need to specify such a contract.
+ * Ad-hoc extensions might break for future versions of the extended class,
+ * since the extended class is free to change its implementation without
+ * being constrained by an internal contract.
+ *
+ * '''Why allow it?''' An ad-hoc extension can sometimes be necessary,
+ * for instance when mocking a class in a testing framework, or to work
+ * around a bug or missing feature in the original class. Nevertheless,
+ * such extensions should be limited in scope and clearly documented.
+ * That's why the language import is required for them.
+ */
+ @compileTimeOnly("`adhocExtensions` can only be used at compile time in import statements")
+ object adhocExtensions
+
+ /** Unsafe Nulls fot Explicit Nulls
+ * Inside the "unsafe" scope, `Null` is considered as a subtype of all reference types.
+ *
+ * @see [[http://dotty.epfl.ch/docs/reference/other-new-features/explicit-nulls.html]]
+ */
+ @compileTimeOnly("`unsafeNulls` can only be used at compile time in import statements")
+ object unsafeNulls
+
+ @compileTimeOnly("`future` can only be used at compile time in import statements")
+ object future
+
+ @compileTimeOnly("`future-migration` can only be used at compile time in import statements")
+ object `future-migration`
+
+ /** Set source version to 3.0-migration.
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.0-migration` can only be used at compile time in import statements")
+ object `3.0-migration`
+
+ /** Set source version to 3.0.
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.0` can only be used at compile time in import statements")
+ object `3.0`
+
+ /** Set source version to 3.1-migration.
+ *
+ * This is a no-op, and should not be used. A syntax error will be reported upon import.
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.1-migration` can only be used at compile time in import statements")
+ @deprecated("`3.1-migration` is not valid, use `3.1` instead", since = "3.2")
+ object `3.1-migration`
+
+ /** Set source version to 3.1
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.1` can only be used at compile time in import statements")
+ object `3.1`
+
+ /** Set source version to 3.2-migration.
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.2-migration` can only be used at compile time in import statements")
+ object `3.2-migration`
+
+ /** Set source version to 3.2
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.2` can only be used at compile time in import statements")
+ object `3.2`
+
+ /** Set source version to 3.3-migration.
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.3-migration` can only be used at compile time in import statements")
+ object `3.3-migration`
+
+ /** Set source version to 3.3
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.3` can only be used at compile time in import statements")
+ object `3.3`
+
+ /** Set source version to 3.4-migration.
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.4-migration` can only be used at compile time in import statements")
+ object `3.4-migration`
+
+ /** Set source version to 3.4
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.4` can only be used at compile time in import statements")
+ object `3.4`
+
+ /** Set source version to 3.5-migration.
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.5-migration` can only be used at compile time in import statements")
+ object `3.5-migration`
+
+ /** Set source version to 3.5
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.5` can only be used at compile time in import statements")
+ object `3.5`
+
+ /** Set source version to 3.6-migration.
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.6-migration` can only be used at compile time in import statements")
+ object `3.6-migration`
+
+ /** Set source version to 3.6
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.6` can only be used at compile time in import statements")
+ object `3.6`
+
+ /** Set source version to 3.7-migration.
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.7-migration` can only be used at compile time in import statements")
+ object `3.7-migration`
+
+ /** Set source version to 3.7
+ *
+ * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]]
+ */
+ @compileTimeOnly("`3.7` can only be used at compile time in import statements")
+ object `3.7`
+
+
+ // !!! Keep in sync with dotty.tools.dotc.config.SourceVersion !!!
+ // Also add tests in `tests/pos/source-import-3-x.scala` and `tests/pos/source-import-3-x-migration.scala`
+
+}
diff --git a/library/src/scala/languageFeature.scala b/library/src/scala/languageFeature.scala
new file mode 100644
index 000000000000..236774c990ba
--- /dev/null
+++ b/library/src/scala/languageFeature.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.
+ */
+
+package scala
+
+import scala.annotation.meta
+
+object languageFeature {
+
+ @meta.languageFeature("extension of type scala.Dynamic", enableRequired = true)
+ sealed trait dynamics
+ object dynamics extends dynamics
+
+ @meta.languageFeature("postfix operator #", enableRequired = true)
+ sealed trait postfixOps
+ object postfixOps extends postfixOps
+
+ @meta.languageFeature("reflective access of structural type member #", enableRequired = false)
+ sealed trait reflectiveCalls
+ object reflectiveCalls extends reflectiveCalls
+
+ @meta.languageFeature("implicit conversion #", enableRequired = false)
+ sealed trait implicitConversions
+ object implicitConversions extends implicitConversions
+
+ @deprecated("scala.language.higherKinds no longer needs to be imported explicitly", "2.13.1")
+ @meta.languageFeature("higher-kinded type", enableRequired = false)
+ sealed trait higherKinds
+ @deprecated("scala.language.higherKinds no longer needs to be imported explicitly", "2.13.1")
+ object higherKinds extends higherKinds
+
+ @meta.languageFeature("#, which cannot be expressed by wildcards,", enableRequired = false)
+ sealed trait existentials
+ object existentials extends existentials
+
+ object experimental {
+ @meta.languageFeature("macro definition", enableRequired = true)
+ sealed trait macros
+ object macros extends macros
+ }
+}
+
diff --git a/library/src/scala/math/BigDecimal.scala b/library/src/scala/math/BigDecimal.scala
new file mode 100644
index 000000000000..e70cdbab41e4
--- /dev/null
+++ b/library/src/scala/math/BigDecimal.scala
@@ -0,0 +1,721 @@
+/*
+ * 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 math
+
+import scala.language.implicitConversions
+
+import java.math.{
+ BigDecimal => BigDec,
+ MathContext,
+ RoundingMode => JRM,
+}
+import scala.collection.immutable.NumericRange
+
+object BigDecimal {
+ private final val maximumHashScale = 4934 // Quit maintaining hash identity with BigInt beyond this scale
+ private final val hashCodeNotComputed = 0x5D50690F // Magic value (happens to be "BigDecimal" old MurmurHash3 value)
+ private final val deci2binary = 3.3219280948873626 // Ratio of log(10) to log(2)
+ private[this] val minCached = -512
+ private[this] val maxCached = 512
+ val defaultMathContext = MathContext.DECIMAL128
+
+ /** Cache only for defaultMathContext using BigDecimals in a small range. */
+ private[this] lazy val cache = new Array[BigDecimal](maxCached - minCached + 1)
+
+ object RoundingMode extends Enumeration {
+ // Annoying boilerplate to ensure consistency with java.math.RoundingMode
+ type RoundingMode = Value
+ val UP = Value(JRM.UP.ordinal)
+ val DOWN = Value(JRM.DOWN.ordinal)
+ val CEILING = Value(JRM.CEILING.ordinal)
+ val FLOOR = Value(JRM.FLOOR.ordinal)
+ val HALF_UP = Value(JRM.HALF_UP.ordinal)
+ val HALF_DOWN = Value(JRM.HALF_DOWN.ordinal)
+ val HALF_EVEN = Value(JRM.HALF_EVEN.ordinal)
+ val UNNECESSARY = Value(JRM.UNNECESSARY.ordinal)
+ }
+
+ /** Constructs a `BigDecimal` using the decimal text representation of `Double` value `d`, rounding if necessary. */
+ def decimal(d: Double, mc: MathContext): BigDecimal =
+ new BigDecimal(new BigDec(java.lang.Double.toString(d), mc), mc)
+
+ /** Constructs a `BigDecimal` using the decimal text representation of `Double` value `d`. */
+ def decimal(d: Double): BigDecimal = decimal(d, defaultMathContext)
+
+ /** Constructs a `BigDecimal` using the decimal text representation of `Float` value `f`, rounding if necessary.
+ * Note that `BigDecimal.decimal(0.1f) != 0.1f` since equality agrees with the `Double` representation, and
+ * `0.1 != 0.1f`.
+ */
+ def decimal(f: Float, mc: MathContext): BigDecimal =
+ new BigDecimal(new BigDec(java.lang.Float.toString(f), mc), mc)
+
+ /** Constructs a `BigDecimal` using the decimal text representation of `Float` value `f`.
+ * Note that `BigDecimal.decimal(0.1f) != 0.1f` since equality agrees with the `Double` representation, and
+ * `0.1 != 0.1f`.
+ */
+ def decimal(f: Float): BigDecimal = decimal(f, defaultMathContext)
+
+ // This exists solely to avoid conversion from Int/Long to Float, screwing everything up.
+ /** Constructs a `BigDecimal` from a `Long`, rounding if necessary. This is identical to `BigDecimal(l, mc)`. */
+ def decimal(l: Long, mc: MathContext): BigDecimal = apply(l, mc)
+
+ // This exists solely to avoid conversion from Int/Long to Float, screwing everything up.
+ /** Constructs a `BigDecimal` from a `Long`. This is identical to `BigDecimal(l)`. */
+ def decimal(l: Long): BigDecimal = apply(l)
+
+ /** Constructs a `BigDecimal` using a `java.math.BigDecimal`, rounding if necessary. */
+ def decimal(bd: BigDec, mc: MathContext): BigDecimal = new BigDecimal(bd.round(mc), mc)
+
+ /** Constructs a `BigDecimal` by expanding the binary fraction
+ * contained by `Double` value `d` into a decimal representation,
+ * rounding if necessary. When a `Float` is converted to a
+ * `Double`, the binary fraction is preserved, so this method
+ * also works for converted `Float`s.
+ */
+ def binary(d: Double, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(d, mc), mc)
+
+ /** Constructs a `BigDecimal` by expanding the binary fraction
+ * contained by `Double` value `d` into a decimal representation.
+ * Note: this also works correctly on converted `Float`s.
+ */
+ def binary(d: Double): BigDecimal = binary(d, defaultMathContext)
+
+ /** Constructs a `BigDecimal` from a `java.math.BigDecimal`. The
+ * precision is the default for `BigDecimal` or enough to represent
+ * the `java.math.BigDecimal` exactly, whichever is greater.
+ */
+ def exact(repr: BigDec): BigDecimal = {
+ val mc =
+ if (repr.precision <= defaultMathContext.getPrecision) defaultMathContext
+ else new MathContext(repr.precision, java.math.RoundingMode.HALF_EVEN)
+ new BigDecimal(repr, mc)
+ }
+
+ /** Constructs a `BigDecimal` by fully expanding the binary fraction
+ * contained by `Double` value `d`, adjusting the precision as
+ * necessary. Note: this works correctly on converted `Float`s also.
+ */
+ def exact(d: Double): BigDecimal = exact(new BigDec(d))
+
+ /** Constructs a `BigDecimal` that exactly represents a `BigInt`.
+ */
+ def exact(bi: BigInt): BigDecimal = exact(new BigDec(bi.bigInteger))
+
+ /** Constructs a `BigDecimal` that exactly represents a `Long`. Note that
+ * all creation methods for `BigDecimal` that do not take a `MathContext`
+ * represent a `Long`; this is equivalent to `apply`, `valueOf`, etc..
+ */
+ def exact(l: Long): BigDecimal = apply(l)
+
+ /** Constructs a `BigDecimal` that exactly represents the number
+ * specified in a `String`.
+ */
+ def exact(s: String): BigDecimal = exact(new BigDec(s))
+
+ /** Constructs a `BigDecimal` that exactly represents the number
+ * specified in base 10 in a character array.
+ */
+ def exact(cs: Array[Char]): BigDecimal = exact(new BigDec(cs))
+
+
+ /** Constructs a `BigDecimal` using the java BigDecimal static
+ * valueOf constructor. Equivalent to `BigDecimal.decimal`.
+ *
+ * @param d the specified double value
+ * @return the constructed `BigDecimal`
+ */
+ def valueOf(d: Double): BigDecimal = apply(BigDec valueOf d)
+
+ /** Constructs a `BigDecimal` using the java BigDecimal static
+ * valueOf constructor.
+ *
+ * @param x the specified `Long` value
+ * @return the constructed `BigDecimal`
+ */
+ def valueOf(x: Long): BigDecimal = apply(x)
+
+ /** Constructs a `BigDecimal` whose value is equal to that of the
+ * specified `Integer` value.
+ *
+ * @param i the specified integer value
+ * @return the constructed `BigDecimal`
+ */
+ def apply(i: Int): BigDecimal = apply(i, defaultMathContext)
+
+ /** Constructs a `BigDecimal` whose value is equal to that of the
+ * specified `Integer` value, rounding if necessary.
+ *
+ * @param i the specified integer value
+ * @param mc the precision and rounding mode for creation of this value and future operations on it
+ * @return the constructed `BigDecimal`
+ */
+ def apply(i: Int, mc: MathContext): BigDecimal =
+ if (mc == defaultMathContext && minCached <= i && i <= maxCached) {
+ val offset = i - minCached
+ var n = cache(offset)
+ if (n eq null) { n = new BigDecimal(BigDec.valueOf(i.toLong), mc); cache(offset) = n }
+ n
+ }
+ else apply(i.toLong, mc)
+
+ /** Constructs a `BigDecimal` whose value is equal to that of the
+ * specified long value.
+ *
+ * @param l the specified long value
+ * @return the constructed `BigDecimal`
+ */
+ def apply(l: Long): BigDecimal =
+ if (minCached <= l && l <= maxCached) apply(l.toInt)
+ else new BigDecimal(BigDec.valueOf(l), defaultMathContext)
+
+ /** Constructs a `BigDecimal` whose value is equal to that of the
+ * specified long value, but rounded if necessary.
+ *
+ * @param l the specified long value
+ * @param mc the precision and rounding mode for creation of this value and future operations on it
+ * @return the constructed `BigDecimal`
+ */
+ def apply(l: Long, mc: MathContext): BigDecimal =
+ new BigDecimal(new BigDec(l, mc), mc)
+
+ /** Constructs a `BigDecimal` whose unscaled value is equal to that
+ * of the specified long value.
+ *
+ * @param unscaledVal the value
+ * @param scale the scale
+ * @return the constructed `BigDecimal`
+ */
+ def apply(unscaledVal: Long, scale: Int): BigDecimal =
+ apply(BigInt(unscaledVal), scale)
+
+ /** Constructs a `BigDecimal` whose unscaled value is equal to that
+ * of the specified long value, but rounded if necessary.
+ *
+ * @param unscaledVal the value
+ * @param scale the scale
+ * @param mc the precision and rounding mode for creation of this value and future operations on it
+ * @return the constructed `BigDecimal`
+ */
+ def apply(unscaledVal: Long, scale: Int, mc: MathContext): BigDecimal =
+ apply(BigInt(unscaledVal), scale, mc)
+
+ /** Constructs a `BigDecimal` whose value is equal to that of the
+ * specified double value. Equivalent to `BigDecimal.decimal`.
+ *
+ * @param d the specified `Double` value
+ * @return the constructed `BigDecimal`
+ */
+ def apply(d: Double): BigDecimal = decimal(d, defaultMathContext)
+
+ // note we don't use the static valueOf because it doesn't let us supply
+ // a MathContext, but we should be duplicating its logic, modulo caching.
+ /** Constructs a `BigDecimal` whose value is equal to that of the
+ * specified double value, but rounded if necessary. Equivalent to
+ * `BigDecimal.decimal`.
+ *
+ * @param d the specified `Double` value
+ * @param mc the precision and rounding mode for creation of this value and future operations on it
+ * @return the constructed `BigDecimal`
+ */
+ def apply(d: Double, mc: MathContext): BigDecimal = decimal(d, mc)
+
+ /** Translates a character array representation of a `BigDecimal`
+ * into a `BigDecimal`.
+ */
+ def apply(x: Array[Char]): BigDecimal = exact(x)
+
+ /** Translates a character array representation of a `BigDecimal`
+ * into a `BigDecimal`, rounding if necessary.
+ */
+ def apply(x: Array[Char], mc: MathContext): BigDecimal =
+ new BigDecimal(new BigDec(x, mc), mc)
+
+ /** Translates the decimal String representation of a `BigDecimal`
+ * into a `BigDecimal`.
+ */
+ def apply(x: String): BigDecimal = exact(x)
+
+ /** Translates the decimal String representation of a `BigDecimal`
+ * into a `BigDecimal`, rounding if necessary.
+ */
+ def apply(x: String, mc: MathContext): BigDecimal =
+ new BigDecimal(new BigDec(x, mc), mc)
+
+ /** Constructs a `BigDecimal` whose value is equal to that of the
+ * specified `BigInt` value.
+ *
+ * @param x the specified `BigInt` value
+ * @return the constructed `BigDecimal`
+ */
+ def apply(x: BigInt): BigDecimal = exact(x)
+
+ /** Constructs a `BigDecimal` whose value is equal to that of the
+ * specified `BigInt` value, rounding if necessary.
+ *
+ * @param x the specified `BigInt` value
+ * @param mc the precision and rounding mode for creation of this value and future operations on it
+ * @return the constructed `BigDecimal`
+ */
+ def apply(x: BigInt, mc: MathContext): BigDecimal =
+ new BigDecimal(new BigDec(x.bigInteger, mc), mc)
+
+ /** Constructs a `BigDecimal` whose unscaled value is equal to that
+ * of the specified `BigInt` value.
+ *
+ * @param unscaledVal the specified `BigInt` value
+ * @param scale the scale
+ * @return the constructed `BigDecimal`
+ */
+ def apply(unscaledVal: BigInt, scale: Int): BigDecimal =
+ exact(new BigDec(unscaledVal.bigInteger, scale))
+
+ /** Constructs a `BigDecimal` whose unscaled value is equal to that
+ * of the specified `BigInt` value.
+ *
+ * @param unscaledVal the specified `BigInt` value
+ * @param scale the scale
+ * @param mc the precision and rounding mode for creation of this value and future operations on it
+ * @return the constructed `BigDecimal`
+ */
+ def apply(unscaledVal: BigInt, scale: Int, mc: MathContext): BigDecimal =
+ new BigDecimal(new BigDec(unscaledVal.bigInteger, scale, mc), mc)
+
+ /** Constructs a `BigDecimal` from a `java.math.BigDecimal`. */
+ def apply(bd: BigDec): BigDecimal = new BigDecimal(bd, defaultMathContext)
+
+ /** Implicit conversion from `Int` to `BigDecimal`. */
+ implicit def int2bigDecimal(i: Int): BigDecimal = apply(i)
+
+ /** Implicit conversion from `Long` to `BigDecimal`. */
+ implicit def long2bigDecimal(l: Long): BigDecimal = apply(l)
+
+ /** Implicit conversion from `Double` to `BigDecimal`. */
+ implicit def double2bigDecimal(d: Double): BigDecimal = decimal(d)
+
+ /** Implicit conversion from `java.math.BigDecimal` to `scala.BigDecimal`. */
+ implicit def javaBigDecimal2bigDecimal(x: BigDec): BigDecimal = if (x == null) null else apply(x)
+}
+
+/**
+ * `BigDecimal` represents decimal floating-point numbers of arbitrary precision.
+ * By default, the precision approximately matches that of IEEE 128-bit floating
+ * point numbers (34 decimal digits, `HALF_EVEN` rounding mode). Within the range
+ * of IEEE binary128 numbers, `BigDecimal` will agree with `BigInt` for both
+ * equality and hash codes (and will agree with primitive types as well). Beyond
+ * that range--numbers with more than 4934 digits when written out in full--the
+ * `hashCode` of `BigInt` and `BigDecimal` is allowed to diverge due to difficulty
+ * in efficiently computing both the decimal representation in `BigDecimal` and the
+ * binary representation in `BigInt`.
+ *
+ * When creating a `BigDecimal` from a `Double` or `Float`, care must be taken as
+ * the binary fraction representation of `Double` and `Float` does not easily
+ * convert into a decimal representation. Three explicit schemes are available
+ * for conversion. `BigDecimal.decimal` will convert the floating-point number
+ * to a decimal text representation, and build a `BigDecimal` based on that.
+ * `BigDecimal.binary` will expand the binary fraction to the requested or default
+ * precision. `BigDecimal.exact` will expand the binary fraction to the
+ * full number of digits, thus producing the exact decimal value corresponding to
+ * the binary fraction of that floating-point number. `BigDecimal` equality
+ * matches the decimal expansion of `Double`: `BigDecimal.decimal(0.1) == 0.1`.
+ * Note that since `0.1f != 0.1`, the same is not true for `Float`. Instead,
+ * `0.1f == BigDecimal.decimal((0.1f).toDouble)`.
+ *
+ * To test whether a `BigDecimal` number can be converted to a `Double` or
+ * `Float` and then back without loss of information by using one of these
+ * methods, test with `isDecimalDouble`, `isBinaryDouble`, or `isExactDouble`
+ * or the corresponding `Float` versions. Note that `BigInt`'s `isValidDouble`
+ * will agree with `isExactDouble`, not the `isDecimalDouble` used by default.
+ *
+ * `BigDecimal` uses the decimal representation of binary floating-point numbers
+ * to determine equality and hash codes. This yields different answers than
+ * conversion between `Long` and `Double` values, where the exact form is used.
+ * As always, since floating-point is a lossy representation, it is advisable to
+ * take care when assuming identity will be maintained across multiple conversions.
+ *
+ * `BigDecimal` maintains a `MathContext` that determines the rounding that
+ * is applied to certain calculations. In most cases, the value of the
+ * `BigDecimal` is also rounded to the precision specified by the `MathContext`.
+ * To create a `BigDecimal` with a different precision than its `MathContext`,
+ * use `new BigDecimal(new java.math.BigDecimal(...), mc)`. Rounding will
+ * be applied on those mathematical operations that can dramatically change the
+ * number of digits in a full representation, namely multiplication, division,
+ * and powers. The left-hand argument's `MathContext` always determines the
+ * degree of rounding, if any, and is the one propagated through arithmetic
+ * operations that do not apply rounding themselves.
+ */
+final class BigDecimal(val bigDecimal: BigDec, val mc: MathContext)
+extends ScalaNumber with ScalaNumericConversions with Serializable with Ordered[BigDecimal] {
+ def this(bigDecimal: BigDec) = this(bigDecimal, BigDecimal.defaultMathContext)
+ import BigDecimal.RoundingMode._
+ import BigDecimal.{decimal, binary, exact}
+
+ if (bigDecimal eq null) throw new IllegalArgumentException("null value for BigDecimal")
+ if (mc eq null) throw new IllegalArgumentException("null MathContext for BigDecimal")
+
+ // There was an implicit to cut down on the wrapper noise for BigDec -> BigDecimal.
+ // However, this may mask introduction of surprising behavior (e.g. lack of rounding
+ // where one might expect it). Wrappers should be applied explicitly with an
+ // eye to correctness.
+
+ // Sane hash code computation (which is surprisingly hard).
+ // Note--not lazy val because we can't afford the extra space.
+ private final var computedHashCode: Int = BigDecimal.hashCodeNotComputed
+ private final def computeHashCode(): Unit = {
+ computedHashCode =
+ if (isWhole && (precision - scale) < BigDecimal.maximumHashScale) toBigInt.hashCode
+ else if (isDecimalDouble) doubleValue.##
+ else {
+ val temp = bigDecimal.stripTrailingZeros
+ scala.util.hashing.MurmurHash3.mixLast( temp.scaleByPowerOfTen(temp.scale).toBigInteger.hashCode, temp.scale )
+ }
+ }
+
+ /** Returns the hash code for this BigDecimal.
+ * Note that this does not merely use the underlying java object's
+ * `hashCode` because we compare `BigDecimal`s with `compareTo`
+ * which deems 2 == 2.00, whereas in java these are unequal
+ * with unequal `hashCode`s. These hash codes agree with `BigInt`
+ * for whole numbers up ~4934 digits (the range of IEEE 128 bit floating
+ * point). Beyond this, hash codes will disagree; this prevents the
+ * explicit representation of the `BigInt` form for `BigDecimal` values
+ * with large exponents.
+ */
+ override def hashCode(): Int = {
+ if (computedHashCode == BigDecimal.hashCodeNotComputed) computeHashCode()
+ computedHashCode
+ }
+
+ /** Compares this BigDecimal with the specified value for equality. Where `Float` and `Double`
+ * disagree, `BigDecimal` will agree with the `Double` value
+ */
+ override def equals (that: Any): Boolean = that match {
+ case that: BigDecimal => this equals that
+ case that: BigInt =>
+ that.bitLength > (precision-scale-2)*BigDecimal.deci2binary &&
+ this.toBigIntExact.exists(that equals _)
+ case that: Double =>
+ !that.isInfinity && {
+ val d = toDouble
+ !d.isInfinity && d == that && equals(decimal(d))
+ }
+ case that: Float =>
+ !that.isInfinity && {
+ val f = toFloat
+ !f.isInfinity && f == that && equals(decimal(f.toDouble))
+ }
+ case _ => isValidLong && unifiedPrimitiveEquals(that)
+ }
+ override def isValidByte = noArithmeticException(toByteExact)
+ override def isValidShort = noArithmeticException(toShortExact)
+ override def isValidChar = isValidInt && toIntExact >= Char.MinValue && toIntExact <= Char.MaxValue
+ override def isValidInt = noArithmeticException(toIntExact)
+ def isValidLong = noArithmeticException(toLongExact)
+
+ /** Tests whether this `BigDecimal` holds the decimal representation of a `Double`. */
+ def isDecimalDouble = {
+ val d = toDouble
+ !d.isInfinity && equals(decimal(d))
+ }
+
+ /** Tests whether this `BigDecimal` holds the decimal representation of a `Float`. */
+ def isDecimalFloat = {
+ val f = toFloat
+ !f.isInfinity && equals(decimal(f))
+ }
+
+ /** Tests whether this `BigDecimal` holds, to within precision, the binary representation of a `Double`. */
+ def isBinaryDouble = {
+ val d = toDouble
+ !d.isInfinity && equals(binary(d,mc))
+ }
+
+ /** Tests whether this `BigDecimal` holds, to within precision, the binary representation of a `Float`. */
+ def isBinaryFloat = {
+ val f = toFloat
+ !f.isInfinity && equals(binary(f,mc))
+ }
+
+ /** Tests whether this `BigDecimal` holds the exact expansion of a `Double`'s binary fractional form into base 10. */
+ def isExactDouble = {
+ val d = toDouble
+ !d.isInfinity && equals(exact(d))
+ }
+
+ /** Tests whether this `BigDecimal` holds the exact expansion of a `Float`'s binary fractional form into base 10. */
+ def isExactFloat = {
+ val f = toFloat
+ !f.isInfinity && equals(exact(f.toDouble))
+ }
+
+
+ private def noArithmeticException(body: => Unit): Boolean = {
+ try { body ; true }
+ catch { case _: ArithmeticException => false }
+ }
+
+ def isWhole = scale <= 0 || bigDecimal.stripTrailingZeros.scale <= 0
+
+ def underlying: java.math.BigDecimal = bigDecimal
+
+
+ /** Compares this BigDecimal with the specified BigDecimal for equality.
+ */
+ def equals (that: BigDecimal): Boolean = compare(that) == 0
+
+ /** Compares this BigDecimal with the specified BigDecimal
+ */
+ def compare (that: BigDecimal): Int = this.bigDecimal compareTo that.bigDecimal
+
+ /** Addition of BigDecimals
+ */
+ def + (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal.add(that.bigDecimal, mc), mc)
+
+ /** Subtraction of BigDecimals
+ */
+ def - (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal.subtract(that.bigDecimal, mc), mc)
+
+ /** Multiplication of BigDecimals
+ */
+ def * (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal.multiply(that.bigDecimal, mc), mc)
+
+ /** Division of BigDecimals
+ */
+ def / (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal.divide(that.bigDecimal, mc), mc)
+
+ /** Division and Remainder - returns tuple containing the result of
+ * divideToIntegralValue and the remainder. The computation is exact: no rounding is applied.
+ */
+ def /% (that: BigDecimal): (BigDecimal, BigDecimal) = {
+ val qr = this.bigDecimal.divideAndRemainder(that.bigDecimal, mc)
+ (new BigDecimal(qr(0), mc), new BigDecimal(qr(1), mc))
+ }
+
+ /** Divide to Integral value.
+ */
+ def quot (that: BigDecimal): BigDecimal =
+ new BigDecimal(this.bigDecimal.divideToIntegralValue(that.bigDecimal, mc), mc)
+
+ /** Returns the minimum of this and that, or this if the two are equal
+ */
+ def min (that: BigDecimal): BigDecimal = (this compare that) match {
+ case x if x <= 0 => this
+ case _ => that
+ }
+
+ /** Returns the maximum of this and that, or this if the two are equal
+ */
+ def max (that: BigDecimal): BigDecimal = (this compare that) match {
+ case x if x >= 0 => this
+ case _ => that
+ }
+
+ /** Remainder after dividing this by that.
+ */
+ def remainder (that: BigDecimal): BigDecimal = new BigDecimal(this.bigDecimal.remainder(that.bigDecimal, mc), mc)
+
+ /** Remainder after dividing this by that.
+ */
+ def % (that: BigDecimal): BigDecimal = this.remainder(that)
+
+ /** Returns a BigDecimal whose value is this ** n.
+ */
+ def pow (n: Int): BigDecimal = new BigDecimal(this.bigDecimal.pow(n, mc), mc)
+
+ /** Returns a BigDecimal whose value is the negation of this BigDecimal
+ */
+ def unary_- : BigDecimal = new BigDecimal(this.bigDecimal.negate(mc), mc)
+
+ /** Returns the absolute value of this BigDecimal
+ */
+ def abs: BigDecimal = if (signum < 0) unary_- else this
+
+ /** Returns the sign of this BigDecimal;
+ * -1 if it is less than 0,
+ * +1 if it is greater than 0,
+ * 0 if it is equal to 0.
+ */
+ def signum: Int = this.bigDecimal.signum()
+
+ /** Returns the sign of this BigDecimal;
+ * -1 if it is less than 0,
+ * +1 if it is greater than 0,
+ * 0 if it is equal to 0.
+ */
+ def sign: BigDecimal = signum
+
+ /** Returns the precision of this `BigDecimal`.
+ */
+ def precision: Int = this.bigDecimal.precision
+
+ /** Returns a BigDecimal rounded according to the supplied MathContext settings, but
+ * preserving its own MathContext for future operations.
+ */
+ def round(mc: MathContext): BigDecimal = {
+ val r = this.bigDecimal round mc
+ if (r eq bigDecimal) this else new BigDecimal(r, this.mc)
+ }
+
+ /** Returns a `BigDecimal` rounded according to its own `MathContext` */
+ def rounded: BigDecimal = {
+ val r = bigDecimal round mc
+ if (r eq bigDecimal) this else new BigDecimal(r, mc)
+ }
+
+ /** Returns the scale of this `BigDecimal`.
+ */
+ def scale: Int = this.bigDecimal.scale
+
+ /** Returns the size of an ulp, a unit in the last place, of this BigDecimal.
+ */
+ def ulp: BigDecimal = new BigDecimal(this.bigDecimal.ulp, mc)
+
+ /** Returns a new BigDecimal based on the supplied MathContext, rounded as needed.
+ */
+ def apply(mc: MathContext): BigDecimal = new BigDecimal(this.bigDecimal round mc, mc)
+
+ /** Returns a `BigDecimal` whose scale is the specified value, and whose value is
+ * numerically equal to this BigDecimal's.
+ */
+ def setScale(scale: Int): BigDecimal =
+ if (this.scale == scale) this
+ else new BigDecimal(this.bigDecimal.setScale(scale), mc)
+
+ def setScale(scale: Int, mode: RoundingMode): BigDecimal =
+ if (this.scale == scale) this
+ else new BigDecimal(this.bigDecimal.setScale(scale, JRM.valueOf(mode.id)), mc)
+
+ /** Converts this BigDecimal to a Byte.
+ * If the BigDecimal is too big to fit in a Byte, only the low-order 8 bits are returned.
+ * Note that this conversion can lose information about the overall magnitude of the
+ * BigDecimal value as well as return a result with the opposite sign.
+ */
+ override def byteValue = intValue.toByte
+
+ /** Converts this BigDecimal to a Short.
+ * If the BigDecimal is too big to fit in a Short, only the low-order 16 bits are returned.
+ * Note that this conversion can lose information about the overall magnitude of the
+ * BigDecimal value as well as return a result with the opposite sign.
+ */
+ override def shortValue = intValue.toShort
+
+ /** Converts this BigDecimal to a Char.
+ * If the BigDecimal is too big to fit in a Char, only the low-order 16 bits are returned.
+ * Note that this conversion can lose information about the overall magnitude of the
+ * BigDecimal value and that it always returns a positive result.
+ */
+ def charValue = intValue.toChar
+
+ /** Converts this BigDecimal to an Int.
+ * If the BigDecimal is too big to fit in an Int, only the low-order 32 bits
+ * are returned. Note that this conversion can lose information about the
+ * overall magnitude of the BigDecimal value as well as return a result with
+ * the opposite sign.
+ */
+ def intValue = this.bigDecimal.intValue
+
+ /** Converts this BigDecimal to a Long.
+ * If the BigDecimal is too big to fit in a Long, only the low-order 64 bits
+ * are returned. Note that this conversion can lose information about the
+ * overall magnitude of the BigDecimal value as well as return a result with
+ * the opposite sign.
+ */
+ def longValue = this.bigDecimal.longValue
+
+ /** Converts this BigDecimal to a Float.
+ * if this BigDecimal has too great a magnitude to represent as a float,
+ * it will be converted to `Float.NEGATIVE_INFINITY` or
+ * `Float.POSITIVE_INFINITY` as appropriate.
+ */
+ def floatValue = this.bigDecimal.floatValue
+
+ /** Converts this BigDecimal to a Double.
+ * if this BigDecimal has too great a magnitude to represent as a double,
+ * it will be converted to `Double.NEGATIVE_INFINITY` or
+ * `Double.POSITIVE_INFINITY` as appropriate.
+ */
+ def doubleValue = this.bigDecimal.doubleValue
+
+ /** Converts this `BigDecimal` to a [[scala.Byte]], checking for lost information.
+ * If this `BigDecimal` has a nonzero fractional part, or is out of the possible
+ * range for a [[scala.Byte]] result, then a `java.lang.ArithmeticException` is
+ * thrown.
+ */
+ def toByteExact = bigDecimal.byteValueExact
+
+ /** Converts this `BigDecimal` to a [[scala.Short]], checking for lost information.
+ * If this `BigDecimal` has a nonzero fractional part, or is out of the possible
+ * range for a [[scala.Short]] result, then a `java.lang.ArithmeticException` is
+ * thrown.
+ */
+ def toShortExact = bigDecimal.shortValueExact
+
+ /** Converts this `BigDecimal` to a [[scala.Int]], checking for lost information.
+ * If this `BigDecimal` has a nonzero fractional part, or is out of the possible
+ * range for an [[scala.Int]] result, then a `java.lang.ArithmeticException` is
+ * thrown.
+ */
+ def toIntExact = bigDecimal.intValueExact
+
+ /** Converts this `BigDecimal` to a [[scala.Long]], checking for lost information.
+ * If this `BigDecimal` has a nonzero fractional part, or is out of the possible
+ * range for a [[scala.Long]] result, then a `java.lang.ArithmeticException` is
+ * thrown.
+ */
+ def toLongExact = bigDecimal.longValueExact
+
+ /** Creates a partially constructed NumericRange[BigDecimal] in range
+ * `[start;end)`, where start is the target BigDecimal. The step
+ * must be supplied via the "by" method of the returned object in order
+ * to receive the fully constructed range. For example:
+ * {{{
+ * val partial = BigDecimal(1.0) to 2.0 // not usable yet
+ * val range = partial by 0.01 // now a NumericRange
+ * val range2 = BigDecimal(0) to 1.0 by 0.01 // all at once of course is fine too
+ * }}}
+ *
+ * @param end the end value of the range (exclusive)
+ * @return the partially constructed NumericRange
+ */
+ def until(end: BigDecimal): Range.Partial[BigDecimal, NumericRange.Exclusive[BigDecimal]] =
+ new Range.Partial(until(end, _))
+
+ /** Same as the one-argument `until`, but creates the range immediately. */
+ def until(end: BigDecimal, step: BigDecimal): NumericRange.Exclusive[BigDecimal] = Range.BigDecimal(this, end, step)
+
+ /** Like `until`, but inclusive of the end value. */
+ def to(end: BigDecimal): Range.Partial[BigDecimal, NumericRange.Inclusive[BigDecimal]] =
+ new Range.Partial(to(end, _))
+
+ /** Like `until`, but inclusive of the end value. */
+ def to(end: BigDecimal, step: BigDecimal) = Range.BigDecimal.inclusive(this, end, step)
+
+ /** Converts this `BigDecimal` to a scala.BigInt.
+ */
+ def toBigInt: BigInt = new BigInt(this.bigDecimal.toBigInteger)
+
+ /** Converts this `BigDecimal` to a scala.BigInt if it
+ * can be done losslessly, returning Some(BigInt) or None.
+ */
+ def toBigIntExact: Option[BigInt] =
+ if (isWhole) {
+ try Some(new BigInt(this.bigDecimal.toBigIntegerExact))
+ catch { case _: ArithmeticException => None }
+ }
+ else None
+
+ /** Returns the decimal String representation of this BigDecimal.
+ */
+ override def toString: String = this.bigDecimal.toString
+
+}
diff --git a/library/src/scala/math/BigInt.scala b/library/src/scala/math/BigInt.scala
new file mode 100644
index 000000000000..9a17ee02a51a
--- /dev/null
+++ b/library/src/scala/math/BigInt.scala
@@ -0,0 +1,638 @@
+/*
+ * 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 math
+
+import java.math.BigInteger
+
+import scala.annotation.nowarn
+import scala.language.implicitConversions
+import scala.collection.immutable.NumericRange
+
+object BigInt {
+
+ private val longMinValueBigInteger = BigInteger.valueOf(Long.MinValue)
+ private val longMinValue = new BigInt(longMinValueBigInteger, Long.MinValue)
+
+ private[this] val minCached = -1024
+ private[this] val maxCached = 1024
+ private[this] val cache = new Array[BigInt](maxCached - minCached + 1)
+
+ private[this] def getCached(i: Int): BigInt = {
+ val offset = i - minCached
+ var n = cache(offset)
+ if (n eq null) {
+ n = new BigInt(null, i.toLong)
+ cache(offset) = n
+ }
+ n
+ }
+
+ private val minusOne = BigInteger.valueOf(-1)
+
+ /** Constructs a `BigInt` whose value is equal to that of the
+ * specified integer value.
+ *
+ * @param i the specified integer value
+ * @return the constructed `BigInt`
+ */
+ def apply(i: Int): BigInt =
+ if (minCached <= i && i <= maxCached) getCached(i) else apply(i: Long)
+
+ /** Constructs a `BigInt` whose value is equal to that of the
+ * specified long value.
+ *
+ * @param l the specified long value
+ * @return the constructed `BigInt`
+ */
+ def apply(l: Long): BigInt =
+ if (minCached <= l && l <= maxCached) getCached(l.toInt)
+ else if (l == Long.MinValue) longMinValue
+ else new BigInt(null, l)
+
+ /** Translates a byte array containing the two's-complement binary
+ * representation of a BigInt into a BigInt.
+ */
+ def apply(x: Array[Byte]): BigInt =
+ apply(new BigInteger(x))
+
+ /** Translates the sign-magnitude representation of a BigInt into a BigInt.
+ *
+ * @param signum signum of the number (-1 for negative, 0 for zero, 1
+ * for positive).
+ * @param magnitude big-endian binary representation of the magnitude of
+ * the number.
+ */
+ def apply(signum: Int, magnitude: Array[Byte]): BigInt =
+ apply(new BigInteger(signum, magnitude))
+
+ /** Constructs a randomly generated positive BigInt that is probably prime,
+ * with the specified bitLength.
+ */
+ def apply(bitlength: Int, certainty: Int, rnd: scala.util.Random): BigInt =
+ apply(new BigInteger(bitlength, certainty, rnd.self))
+
+ /** Constructs a randomly generated BigInt, uniformly distributed over the
+ * range `0` to `(2 ^ numBits - 1)`, inclusive.
+ */
+ def apply(numbits: Int, rnd: scala.util.Random): BigInt =
+ apply(new BigInteger(numbits, rnd.self))
+
+ /** Translates the decimal String representation of a BigInt into a BigInt.
+ */
+ def apply(x: String): BigInt =
+ apply(new BigInteger(x))
+
+ /** Translates the string representation of a `BigInt` in the
+ * specified `radix` into a BigInt.
+ */
+ def apply(x: String, radix: Int): BigInt =
+ apply(new BigInteger(x, radix))
+
+ /** Translates a `java.math.BigInteger` into a BigInt.
+ */
+ def apply(x: BigInteger): BigInt = {
+ if (x.bitLength <= 63) {
+ val l = x.longValue
+ if (minCached <= l && l <= maxCached) getCached(l.toInt) else new BigInt(x, l)
+ } else new BigInt(x, Long.MinValue)
+ }
+
+ /** Returns a positive BigInt that is probably prime, with the specified bitLength.
+ */
+ def probablePrime(bitLength: Int, rnd: scala.util.Random): BigInt =
+ apply(BigInteger.probablePrime(bitLength, rnd.self))
+
+ /** Implicit conversion from `Int` to `BigInt`.
+ */
+ implicit def int2bigInt(i: Int): BigInt = apply(i)
+
+ /** Implicit conversion from `Long` to `BigInt`.
+ */
+ implicit def long2bigInt(l: Long): BigInt = apply(l)
+
+ /** Implicit conversion from `java.math.BigInteger` to `scala.BigInt`.
+ */
+ implicit def javaBigInteger2bigInt(x: BigInteger): BigInt = if (x eq null) null else apply(x)
+
+ // this method is adapted from Google Guava's version at
+ // https://github.com/google/guava/blob/master/guava/src/com/google/common/math/LongMath.java
+ // that code carries the following notice:
+ // * Copyright (C) 2011 The Guava Authors
+ // *
+ // * Licensed under the Apache License, Version 2.0 (the "License")
+ /**
+ * Returns the greatest common divisor of a and b. Returns 0 if a == 0 && b == 0.
+ */
+ private def longGcd(a: Long, b: Long): Long = {
+ // both a and b must be >= 0
+ if (a == 0) { // 0 % b == 0, so b divides a, but the converse doesn't hold.
+ // BigInteger.gcd is consistent with this decision.
+ return b
+ }
+ else if (b == 0) return a // similar logic
+ /*
+ * Uses the binary GCD algorithm; see http://en.wikipedia.org/wiki/Binary_GCD_algorithm. This is
+ * >60% faster than the Euclidean algorithm in benchmarks.
+ */
+ val aTwos = java.lang.Long.numberOfTrailingZeros(a)
+ var a1 = a >> aTwos // divide out all 2s
+
+ val bTwos = java.lang.Long.numberOfTrailingZeros(b)
+ var b1 = b >> bTwos
+ while (a1 != b1) { // both a, b are odd
+ // The key to the binary GCD algorithm is as follows:
+ // Both a1 and b1 are odd. Assume a1 > b1; then gcd(a1 - b1, b1) = gcd(a1, b1).
+ // But in gcd(a1 - b1, b1), a1 - b1 is even and b1 is odd, so we can divide out powers of two.
+ // We bend over backwards to avoid branching, adapting a technique from
+ // http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax
+ val delta = a1 - b1 // can't overflow, since a1 and b1 are nonnegative
+ val minDeltaOrZero = delta & (delta >> (java.lang.Long.SIZE - 1))
+ // equivalent to Math.min(delta, 0)
+ a1 = delta - minDeltaOrZero - minDeltaOrZero // sets a to Math.abs(a - b)
+
+ // a is now nonnegative and even
+ b1 += minDeltaOrZero // sets b to min(old a, b)
+
+ a1 >>= java.lang.Long.numberOfTrailingZeros(a1) // divide out all 2s, since 2 doesn't divide b
+
+ }
+ a1 << scala.math.min(aTwos, bTwos)
+ }
+
+}
+
+/** A type with efficient encoding of arbitrary integers.
+ *
+ * It wraps `java.math.BigInteger`, with optimization for small values that can be encoded in a `Long`.
+ */
+final class BigInt private (private var _bigInteger: BigInteger, private val _long: Long)
+ extends ScalaNumber
+ with ScalaNumericConversions
+ with Serializable
+ with Ordered[BigInt]
+{
+ // The class has a special encoding for integer that fit in a Long *and* are not equal to Long.MinValue.
+ //
+ // The Long value Long.MinValue is a tag specifying that the integer is encoded in the BigInteger field.
+ //
+ // There are three possible states for the class fields (_bigInteger, _long)
+ // 1. (null, l) where l != Long.MinValue, encodes the integer "l"
+ // 2. (b, l) where l != Long.MinValue; then b is a BigInteger with value l, encodes "l" == "b"
+ // 3a. (b, Long.MinValue) where b == Long.MinValue, encodes Long.MinValue
+ // 3b. (b, Long.MinValue) where b does not fit in a Long, encodes "b"
+ //
+ // There is only one possible transition 1. -> 2., when the method .bigInteger is called, then the field
+ // _bigInteger caches the result.
+ //
+ // The case 3a. is the only one where the BigInteger could actually fit in a Long, but as its value is used as a
+ // tag, we'll take the slow path instead.
+ //
+ // Additionally, we know that if this.isValidLong is true, then _long is the encoded value.
+
+ /** Public constructor present for compatibility. Use the BigInt.apply companion object method instead. */
+ def this(bigInteger: BigInteger) = this(
+ bigInteger, // even if it is a short BigInteger, we cache the instance
+ if (bigInteger.bitLength <= 63)
+ bigInteger.longValue // if _bigInteger is actually equal to Long.MinValue, no big deal, its value acts as a tag
+ else Long.MinValue
+ )
+
+ /** Returns whether the integer is encoded in the Long. Returns true for all values fitting in a Long except
+ * Long.MinValue. */
+ private def longEncoding: Boolean = _long != Long.MinValue
+
+ def bigInteger: BigInteger = {
+ val read = _bigInteger
+ if (read ne null) read else {
+ val write = BigInteger.valueOf(_long)
+ _bigInteger = write // reference assignment is atomic; this is multi-thread safe (if possibly wasteful)
+ write
+ }
+ }
+
+ /** Returns the hash code for this BigInt. */
+ override def hashCode(): Int =
+ if (isValidLong) unifiedPrimitiveHashcode
+ else bigInteger.##
+
+ /** Compares this BigInt with the specified value for equality. */
+ @nowarn("cat=other-non-cooperative-equals")
+ override def equals(that: Any): Boolean = that match {
+ case that: BigInt => this equals that
+ case that: BigDecimal => that equals this
+ case that: Double => isValidDouble && toDouble == that
+ case that: Float => isValidFloat && toFloat == that
+ case x => isValidLong && unifiedPrimitiveEquals(x)
+ }
+
+ override def isValidByte: Boolean = _long >= Byte.MinValue && _long <= Byte.MaxValue /* && longEncoding */
+ override def isValidShort: Boolean = _long >= Short.MinValue && _long <= Short.MaxValue /* && longEncoding */
+ override def isValidChar: Boolean = _long >= Char.MinValue && _long <= Char.MaxValue /* && longEncoding */
+ override def isValidInt: Boolean = _long >= Int.MinValue && _long <= Int.MaxValue /* && longEncoding */
+ def isValidLong: Boolean = longEncoding || _bigInteger == BigInt.longMinValueBigInteger // rhs of || tests == Long.MinValue
+
+ /** Returns `true` iff this can be represented exactly by [[scala.Float]]; otherwise returns `false`.
+ */
+ def isValidFloat: Boolean = {
+ val bitLen = bitLength
+ (bitLen <= 24 ||
+ {
+ val lowest = lowestSetBit
+ bitLen <= java.lang.Float.MAX_EXPONENT + 1 && // exclude this < -2^128 && this >= 2^128
+ lowest >= bitLen - 24 &&
+ lowest < java.lang.Float.MAX_EXPONENT + 1 // exclude this == -2^128
+ }
+ ) && !bitLengthOverflow
+ }
+ /** Returns `true` iff this can be represented exactly by [[scala.Double]]; otherwise returns `false`.
+ */
+ def isValidDouble: Boolean = {
+ val bitLen = bitLength
+ (bitLen <= 53 ||
+ {
+ val lowest = lowestSetBit
+ bitLen <= java.lang.Double.MAX_EXPONENT + 1 && // exclude this < -2^1024 && this >= 2^1024
+ lowest >= bitLen - 53 &&
+ lowest < java.lang.Double.MAX_EXPONENT + 1 // exclude this == -2^1024
+ }
+ ) && !bitLengthOverflow
+ }
+ /** Some implementations of java.math.BigInteger allow huge values with bit length greater than Int.MaxValue.
+ * The BigInteger.bitLength method returns truncated bit length in this case.
+ * This method tests if result of bitLength is valid.
+ * This method will become unnecessary if BigInt constructors reject huge BigIntegers.
+ */
+ private def bitLengthOverflow = {
+ val shifted = bigInteger.shiftRight(Int.MaxValue)
+ (shifted.signum != 0) && !(shifted equals BigInt.minusOne)
+ }
+
+ @deprecated("isWhole on an integer type is always true", "2.12.15")
+ def isWhole: Boolean = true
+ def underlying: BigInteger = bigInteger
+
+ /** Compares this BigInt with the specified BigInt for equality.
+ */
+ def equals(that: BigInt): Boolean =
+ if (this.longEncoding)
+ that.longEncoding && (this._long == that._long)
+ else
+ !that.longEncoding && (this._bigInteger == that._bigInteger)
+
+ /** Compares this BigInt with the specified BigInt
+ */
+ def compare(that: BigInt): Int =
+ if (this.longEncoding) {
+ if (that.longEncoding) java.lang.Long.compare(this._long, that._long) else -that._bigInteger.signum()
+ } else {
+ if (that.longEncoding) _bigInteger.signum() else this._bigInteger.compareTo(that._bigInteger)
+ }
+
+ /** Addition of BigInts
+ */
+ def +(that: BigInt): BigInt = {
+ if (this.longEncoding && that.longEncoding) { // fast path
+ val x = this._long
+ val y = that._long
+ val z = x + y
+ if ((~(x ^ y) & (x ^ z)) >= 0L) return BigInt(z)
+ }
+ BigInt(this.bigInteger.add(that.bigInteger))
+ }
+
+ /** Subtraction of BigInts
+ */
+ def -(that: BigInt): BigInt = {
+ if (this.longEncoding && that.longEncoding) { // fast path
+ val x = this._long
+ val y = that._long
+ val z = x - y
+ if (((x ^ y) & (x ^ z)) >= 0L) return BigInt(z)
+ }
+ BigInt(this.bigInteger.subtract(that.bigInteger))
+ }
+
+ /** Multiplication of BigInts
+ */
+ def *(that: BigInt): BigInt = {
+ if (this.longEncoding && that.longEncoding) { // fast path
+ val x = this._long
+ val y = that._long
+ val z = x * y
+ // original code checks the y != Long.MinValue, but when longEncoding is true, that is never the case
+ // if (x == 0 || (y == z / x && !(x == -1 && y == Long.MinValue))) return BigInt(z)
+ if (x == 0 || y == z / x) return BigInt(z)
+ }
+ BigInt(this.bigInteger.multiply(that.bigInteger))
+ }
+
+ /** Division of BigInts
+ */
+ def /(that: BigInt): BigInt =
+ // in the fast path, note that the original code avoided storing -Long.MinValue in a long:
+ // if (this._long != Long.MinValue || that._long != -1) return BigInt(this._long / that._long)
+ // but we know this._long cannot be Long.MinValue, because Long.MinValue is the tag for bigger integers
+ if (this.longEncoding && that.longEncoding) BigInt(this._long / that._long)
+ else BigInt(this.bigInteger.divide(that.bigInteger))
+
+ /** Remainder of BigInts
+ */
+ def %(that: BigInt): BigInt =
+ // see / for the original logic regarding Long.MinValue
+ if (this.longEncoding && that.longEncoding) BigInt(this._long % that._long)
+ else BigInt(this.bigInteger.remainder(that.bigInteger))
+
+ /** Returns a pair of two BigInts containing (this / that) and (this % that).
+ */
+ def /%(that: BigInt): (BigInt, BigInt) =
+ if (this.longEncoding && that.longEncoding) {
+ val x = this._long
+ val y = that._long
+ // original line: if (x != Long.MinValue || y != -1) return (BigInt(x / y), BigInt(x % y))
+ (BigInt(x / y), BigInt(x % y))
+ } else {
+ val dr = this.bigInteger.divideAndRemainder(that.bigInteger)
+ (BigInt(dr(0)), BigInt(dr(1)))
+ }
+
+ /** Leftshift of BigInt
+ */
+ def <<(n: Int): BigInt =
+ if (longEncoding && n <= 0) (this >> (-n)) else BigInt(this.bigInteger.shiftLeft(n))
+
+ /** (Signed) rightshift of BigInt
+ */
+ def >>(n: Int): BigInt =
+ if (longEncoding && n >= 0) {
+ if (n < 64) BigInt(_long >> n)
+ else if (_long < 0) BigInt(-1)
+ else BigInt(0) // for _long >= 0
+ } else BigInt(this.bigInteger.shiftRight(n))
+
+ /** Bitwise and of BigInts
+ */
+ def &(that: BigInt): BigInt =
+ if (this.longEncoding && that.longEncoding)
+ BigInt(this._long & that._long)
+ else BigInt(this.bigInteger.and(that.bigInteger))
+
+ /** Bitwise or of BigInts
+ */
+ def |(that: BigInt): BigInt =
+ if (this.longEncoding && that.longEncoding)
+ BigInt(this._long | that._long)
+ else BigInt(this.bigInteger.or(that.bigInteger))
+
+ /** Bitwise exclusive-or of BigInts
+ */
+ def ^(that: BigInt): BigInt =
+ if (this.longEncoding && that.longEncoding)
+ BigInt(this._long ^ that._long)
+ else BigInt(this.bigInteger.xor(that.bigInteger))
+
+ /** Bitwise and-not of BigInts. Returns a BigInt whose value is (this & ~that).
+ */
+ def &~(that: BigInt): BigInt =
+ if (this.longEncoding && that.longEncoding)
+ BigInt(this._long & ~that._long)
+ else BigInt(this.bigInteger.andNot(that.bigInteger))
+
+ /** Returns the greatest common divisor of abs(this) and abs(that)
+ */
+ def gcd(that: BigInt): BigInt =
+ if (this.longEncoding) {
+ if (this._long == 0) return that.abs
+ // if (this._long == Long.MinValue) return (-this) gcd that
+ // this != 0 && this != Long.MinValue
+ if (that.longEncoding) {
+ if (that._long == 0) return this.abs
+ // if (that._long == Long.MinValue) return this gcd (-that)
+ BigInt(BigInt.longGcd(this._long.abs, that._long.abs))
+ } else that gcd this // force the BigInteger on the left
+ } else {
+ // this is not a valid long
+ if (that.longEncoding) {
+ if (that._long == 0) return this.abs
+ // if (that._long == Long.MinValue) return this gcd (-that)
+ val red = (this._bigInteger mod BigInteger.valueOf(that._long.abs)).longValue()
+ if (red == 0) return that.abs
+ BigInt(BigInt.longGcd(that._long.abs, red))
+ } else BigInt(this.bigInteger.gcd(that.bigInteger))
+ }
+
+
+ /** Returns a BigInt whose value is (this mod that).
+ * This method differs from `%` in that it always returns a non-negative BigInt.
+ * @param that A positive number
+ */
+ def mod(that: BigInt): BigInt =
+ if (this.longEncoding && that.longEncoding && that._long > 0) {
+ val res = this._long % that._long
+ if (res >= 0) BigInt(res) else BigInt(res + that._long)
+ } else BigInt(this.bigInteger.mod(that.bigInteger))
+
+ /** Returns the minimum of this and that
+ */
+ def min(that: BigInt): BigInt =
+ if (this <= that) this else that
+
+ /** Returns the maximum of this and that
+ */
+ def max(that: BigInt): BigInt =
+ if (this >= that) this else that
+
+ /** Returns a BigInt whose value is (this raised to the power of exp).
+ */
+ def pow(exp: Int): BigInt = BigInt(this.bigInteger.pow(exp))
+
+ /** Returns a BigInt whose value is
+ * (this raised to the power of exp modulo m).
+ */
+ def modPow(exp: BigInt, m: BigInt): BigInt = BigInt(this.bigInteger.modPow(exp.bigInteger, m.bigInteger))
+
+ /** Returns a BigInt whose value is (the inverse of this modulo m).
+ */
+ def modInverse(m: BigInt): BigInt = BigInt(this.bigInteger.modInverse(m.bigInteger))
+
+ /** Returns a BigInt whose value is the negation of this BigInt
+ */
+ def unary_- : BigInt = if (longEncoding) BigInt(-_long) else BigInt(this.bigInteger.negate())
+
+ /** Returns the absolute value of this BigInt
+ */
+ def abs: BigInt = if (signum < 0) -this else this
+
+ /** Returns the sign of this BigInt;
+ * -1 if it is less than 0,
+ * +1 if it is greater than 0,
+ * 0 if it is equal to 0.
+ */
+ def signum: Int = if (longEncoding) java.lang.Long.signum(_long) else _bigInteger.signum()
+
+ /** Returns the sign of this BigInt;
+ * -1 if it is less than 0,
+ * +1 if it is greater than 0,
+ * 0 if it is equal to 0.
+ */
+ def sign: BigInt = BigInt(signum)
+
+ /** Returns the bitwise complement of this BigInt
+ */
+ def unary_~ : BigInt =
+ // it is equal to -(this + 1)
+ if (longEncoding && _long != Long.MaxValue) BigInt(-(_long + 1)) else BigInt(this.bigInteger.not())
+
+ /** Returns true if and only if the designated bit is set.
+ */
+ def testBit(n: Int): Boolean =
+ if (longEncoding && n >= 0) {
+ if (n <= 63)
+ (_long & (1L << n)) != 0
+ else
+ _long < 0 // give the sign bit
+ } else this.bigInteger.testBit(n)
+
+ /** Returns a BigInt whose value is equivalent to this BigInt with the designated bit set.
+ */
+ def setBit(n: Int): BigInt = // note that we do not operate on the Long sign bit #63
+ if (longEncoding && n <= 62 && n >= 0) BigInt(_long | (1L << n)) else BigInt(this.bigInteger.setBit(n))
+
+ /** Returns a BigInt whose value is equivalent to this BigInt with the designated bit cleared.
+ */
+ def clearBit(n: Int): BigInt = // note that we do not operate on the Long sign bit #63
+ if (longEncoding && n <= 62 && n >= 0) BigInt(_long & ~(1L << n)) else BigInt(this.bigInteger.clearBit(n))
+
+ /** Returns a BigInt whose value is equivalent to this BigInt with the designated bit flipped.
+ */
+ def flipBit(n: Int): BigInt = // note that we do not operate on the Long sign bit #63
+ if (longEncoding && n <= 62 && n >= 0) BigInt(_long ^ (1L << n)) else BigInt(this.bigInteger.flipBit(n))
+
+ /** Returns the index of the rightmost (lowest-order) one bit in this BigInt
+ * (the number of zero bits to the right of the rightmost one bit).
+ */
+ def lowestSetBit: Int =
+ if (longEncoding) {
+ if (_long == 0) -1 else java.lang.Long.numberOfTrailingZeros(_long)
+ } else this.bigInteger.getLowestSetBit()
+
+ /** Returns the number of bits in the minimal two's-complement representation of this BigInt,
+ * excluding a sign bit.
+ */
+ def bitLength: Int =
+ // bitLength is defined as ceil(log2(this < 0 ? -this : this + 1)))
+ // where ceil(log2(x)) = 64 - numberOfLeadingZeros(x - 1)
+ if (longEncoding) {
+ if (_long < 0) 64 - java.lang.Long.numberOfLeadingZeros(-(_long + 1)) // takes care of Long.MinValue
+ else 64 - java.lang.Long.numberOfLeadingZeros(_long)
+ } else _bigInteger.bitLength()
+
+ /** Returns the number of bits in the two's complement representation of this BigInt
+ * that differ from its sign bit.
+ */
+ def bitCount: Int =
+ if (longEncoding) {
+ if (_long < 0) java.lang.Long.bitCount(-(_long + 1)) else java.lang.Long.bitCount(_long)
+ } else this.bigInteger.bitCount()
+
+ /** Returns true if this BigInt is probably prime, false if it's definitely composite.
+ * @param certainty a measure of the uncertainty that the caller is willing to tolerate:
+ * if the call returns true the probability that this BigInt is prime
+ * exceeds (1 - 1/2 ^ certainty).
+ * The execution time of this method is proportional to the value of
+ * this parameter.
+ */
+ def isProbablePrime(certainty: Int): Boolean = this.bigInteger.isProbablePrime(certainty)
+
+ /** Converts this BigInt to a byte.
+ * If the BigInt is too big to fit in a byte, only the low-order 8 bits are returned.
+ * Note that this conversion can lose information about the overall magnitude of the
+ * BigInt value as well as return a result with the opposite sign.
+ */
+ override def byteValue: Byte = intValue.toByte
+
+ /** Converts this BigInt to a short.
+ * If the BigInt is too big to fit in a short, only the low-order 16 bits are returned.
+ * Note that this conversion can lose information about the overall magnitude of the
+ * BigInt value as well as return a result with the opposite sign.
+ */
+ override def shortValue: Short = intValue.toShort
+
+ /** Converts this BigInt to a char.
+ * If the BigInt is too big to fit in a char, only the low-order 16 bits are returned.
+ * Note that this conversion can lose information about the overall magnitude of the
+ * BigInt value and that it always returns a positive result.
+ */
+ def charValue: Char = intValue.toChar
+
+ /** Converts this BigInt to an int.
+ * If the BigInt is too big to fit in an int, only the low-order 32 bits
+ * are returned. Note that this conversion can lose information about the
+ * overall magnitude of the BigInt value as well as return a result with
+ * the opposite sign.
+ */
+ def intValue: Int = if (longEncoding) _long.toInt else this.bigInteger.intValue
+
+ /** Converts this BigInt to a long.
+ * If the BigInt is too big to fit in a long, only the low-order 64 bits
+ * are returned. Note that this conversion can lose information about the
+ * overall magnitude of the BigInt value as well as return a result with
+ * the opposite sign.
+ */
+ def longValue: Long = if (longEncoding) _long else _bigInteger.longValue
+
+ /** Converts this `BigInt` to a `float`.
+ * If this `BigInt` has too great a magnitude to represent as a float,
+ * it will be converted to `Float.NEGATIVE_INFINITY` or
+ * `Float.POSITIVE_INFINITY` as appropriate.
+ */
+ def floatValue: Float = this.bigInteger.floatValue
+
+ /** Converts this `BigInt` to a `double`.
+ * if this `BigInt` has too great a magnitude to represent as a double,
+ * it will be converted to `Double.NEGATIVE_INFINITY` or
+ * `Double.POSITIVE_INFINITY` as appropriate.
+ */
+ def doubleValue: Double =
+ if (isValidLong && (-(1L << 53) <= _long && _long <= (1L << 53))) _long.toDouble
+ else this.bigInteger.doubleValue
+
+ /** Create a `NumericRange[BigInt]` in range `[start;end)`
+ * with the specified step, where start is the target BigInt.
+ *
+ * @param end the end value of the range (exclusive)
+ * @param step the distance between elements (defaults to 1)
+ * @return the range
+ */
+ def until(end: BigInt, step: BigInt = BigInt(1)): NumericRange.Exclusive[BigInt] = Range.BigInt(this, end, step)
+
+ /** Like until, but inclusive of the end value.
+ */
+ def to(end: BigInt, step: BigInt = BigInt(1)): NumericRange.Inclusive[BigInt] = Range.BigInt.inclusive(this, end, step)
+
+ /** Returns the decimal String representation of this BigInt.
+ */
+ override def toString(): String = if (longEncoding) _long.toString() else _bigInteger.toString()
+
+ /** Returns the String representation in the specified radix of this BigInt.
+ */
+ def toString(radix: Int): String = this.bigInteger.toString(radix)
+
+ /** Returns a byte array containing the two's-complement representation of
+ * this BigInt. The byte array will be in big-endian byte-order: the most
+ * significant byte is in the zeroth element. The array will contain the
+ * minimum number of bytes required to represent this BigInt, including at
+ * least one sign bit.
+ */
+ def toByteArray: Array[Byte] = this.bigInteger.toByteArray()
+}
diff --git a/library/src/scala/math/Equiv.scala b/library/src/scala/math/Equiv.scala
new file mode 100644
index 000000000000..b5d01b362901
--- /dev/null
+++ b/library/src/scala/math/Equiv.scala
@@ -0,0 +1,507 @@
+/*
+ * 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 math
+
+import java.util.Comparator
+import scala.annotation.migration
+
+/** A trait for representing equivalence relations. It is important to
+ * distinguish between a type that can be compared for equality or
+ * equivalence and a representation of equivalence on some type. This
+ * trait is for representing the latter.
+ *
+ * An [[https://en.wikipedia.org/wiki/Equivalence_relation equivalence relation]]
+ * is a binary relation on a type. This relation is exposed as
+ * the `equiv` method of the `Equiv` trait. The relation must be:
+ *
+ * 1. reflexive: `equiv(x, x) == true` for any x of type `T`.
+ * 1. symmetric: `equiv(x, y) == equiv(y, x)` for any `x` and `y` of type `T`.
+ * 1. transitive: if `equiv(x, y) == true` and `equiv(y, z) == true`, then
+ * `equiv(x, z) == true` for any `x`, `y`, and `z` of type `T`.
+ */
+
+trait Equiv[T] extends Any with Serializable {
+ /** Returns `true` iff `x` is equivalent to `y`.
+ */
+ def equiv(x: T, y: T): Boolean
+}
+
+trait LowPriorityEquiv {
+ self: Equiv.type =>
+
+ /**
+ * @deprecated This implicit universal `Equiv` instance allows accidentally
+ * comparing instances of types for which equality isn't well-defined or implemented.
+ * (For example, it does not make sense to compare two `Function1` instances.)
+ *
+ * Use `Equiv.universal` explicitly instead. If you really want an implicit universal `Equiv` instance
+ * despite the potential problems, consider `implicit def universalEquiv[T]: Equiv[T] = universal[T]`.
+ */
+ @deprecated("Use explicit Equiv.universal instead. See Scaladoc entry for more information: " +
+ "https://www.scala-lang.org/api/current/scala/math/Equiv$.html#universalEquiv[T]:scala.math.Equiv[T]",
+ since = "2.13.0")
+ implicit def universalEquiv[T]: Equiv[T] = universal[T]
+}
+
+object Equiv extends LowPriorityEquiv {
+ def reference[T <: AnyRef]: Equiv[T] = { _ eq _ }
+ def universal[T]: Equiv[T] = { _ == _ }
+ def fromComparator[T](cmp: Comparator[T]): Equiv[T] = {
+ (x, y) => cmp.compare(x, y) == 0
+ }
+ def fromFunction[T](cmp: (T, T) => Boolean): Equiv[T] = {
+ (x, y) => cmp(x, y)
+ }
+ def by[T, S: Equiv](f: T => S): Equiv[T] =
+ ((x, y) => implicitly[Equiv[S]].equiv(f(x), f(y)))
+
+ @inline def apply[T: Equiv]: Equiv[T] = implicitly[Equiv[T]]
+
+ /* copied from Ordering */
+
+ private final val optionSeed = 43
+ private final val iterableSeed = 47
+
+ private final class IterableEquiv[CC[X] <: Iterable[X], T](private val eqv: Equiv[T]) extends Equiv[CC[T]] {
+ def equiv(x: CC[T], y: CC[T]): Boolean = {
+ val xe = x.iterator
+ val ye = y.iterator
+
+ while (xe.hasNext && ye.hasNext) {
+ if (!eqv.equiv(xe.next(), ye.next())) return false
+ }
+
+ xe.hasNext == ye.hasNext
+ }
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: IterableEquiv[_, _] => this.eqv == that.eqv
+ case _ => false
+ }
+ override def hashCode(): Int = eqv.hashCode() * iterableSeed
+ }
+
+ trait ExtraImplicits {
+ /** Not in the standard scope due to the potential for divergence:
+ * For instance `implicitly[Equiv[Any]]` diverges in its presence.
+ */
+ implicit def seqEquiv[CC[X] <: scala.collection.Seq[X], T](implicit eqv: Equiv[T]): Equiv[CC[T]] =
+ new IterableEquiv[CC, T](eqv)
+
+ implicit def sortedSetEquiv[CC[X] <: scala.collection.SortedSet[X], T](implicit eqv: Equiv[T]): Equiv[CC[T]] =
+ new IterableEquiv[CC, T](eqv)
+ }
+
+ /** An object containing implicits which are not in the default scope. */
+ object Implicits extends ExtraImplicits { }
+
+ implicit object Unit extends Equiv[Unit] {
+ def equiv(x: Unit, y: Unit): Boolean = true
+ }
+
+ implicit object Boolean extends Equiv[Boolean] {
+ def equiv(x: Boolean, y: Boolean): Boolean = x == y
+ }
+
+ implicit object Byte extends Equiv[Byte] {
+ def equiv(x: Byte, y: Byte): Boolean = x == y
+ }
+
+ implicit object Char extends Equiv[Char] {
+ def equiv(x: Char, y: Char): Boolean = x == y
+ }
+
+ implicit object Short extends Equiv[Short] {
+ def equiv(x: Short, y: Short): Boolean = x == y
+ }
+
+ implicit object Int extends Equiv[Int] {
+ def equiv(x: Int, y: Int): Boolean = x == y
+ }
+
+ implicit object Long extends Equiv[Long] {
+ def equiv(x: Long, y: Long): Boolean = x == y
+ }
+
+ /** `Equiv`s for `Float`s.
+ *
+ * @define floatEquiv Because the behaviour of `Float`s specified by IEEE is
+ * not consistent with behaviors required of an equivalence
+ * relation for `NaN` (it is not reflexive), there are two
+ * equivalences defined for `Float`: `StrictEquiv`, which
+ * is reflexive, and `IeeeEquiv`, which is consistent
+ * with IEEE spec and floating point operations defined in
+ * [[scala.math]].
+ */
+ object Float {
+ /** An equivalence for `Float`s which is reflexive (treats all `NaN`s
+ * as equivalent), and treats `-0.0` and `0.0` as not equivalent; it
+ * behaves the same as [[java.lang.Float.compare]].
+ *
+ * $floatEquiv
+ *
+ * This equivalence may be preferable for collections.
+ *
+ * @see [[IeeeEquiv]]
+ */
+ trait StrictEquiv extends Equiv[Float] {
+ def equiv(x: Float, y: Float): Boolean = java.lang.Float.compare(x, y) == 0
+ }
+ implicit object StrictEquiv extends StrictEquiv
+
+ /** An equivalence for `Float`s which is consistent with IEEE specifications.
+ *
+ * $floatEquiv
+ *
+ * This equivalence may be preferable for numeric contexts.
+ *
+ * @see [[StrictEquiv]]
+ */
+ trait IeeeEquiv extends Equiv[Float] {
+ override def equiv(x: Float, y: Float): Boolean = x == y
+ }
+ implicit object IeeeEquiv extends IeeeEquiv
+ }
+
+ @migration(
+ " The default implicit equivalence for floats no longer conforms to\n" +
+ " to IEEE 754's behavior for -0.0F and NaN.\n" +
+ " Import `Equiv.Float.IeeeEquiv` to recover the previous behavior.\n" +
+ " See also https://www.scala-lang.org/api/current/scala/math/Equiv$$Float$.html.", "2.13.2")
+ implicit object DeprecatedFloatEquiv extends Float.StrictEquiv
+
+ /** `Equiv`s for `Double`s.
+ *
+ * @define doubleEquiv Because the behaviour of `Double`s specified by IEEE is
+ * not consistent with behaviors required of an equivalence
+ * relation for `NaN` (it is not reflexive), there are two
+ * equivalences defined for `Double`: `StrictEquiv`, which
+ * is reflexive, and `IeeeEquiv`, which is consistent
+ * with IEEE spec and floating point operations defined in
+ * [[scala.math]].
+ */
+ object Double {
+ /** An equivalence for `Double`s which is reflexive (treats all `NaN`s
+ * as equivalent), and treats `-0.0` and `0.0` as not equivalent; it
+ * behaves the same as [[java.lang.Double.compare]].
+ *
+ * $doubleEquiv
+ *
+ * This equivalence may be preferable for collections.
+ *
+ * @see [[IeeeEquiv]]
+ */
+ trait StrictEquiv extends Equiv[Double] {
+ def equiv(x: Double, y: Double): Boolean = java.lang.Double.compare(x, y) == 0
+ }
+ implicit object StrictEquiv extends StrictEquiv
+
+ /** An equivalence for `Double`s which is consistent with IEEE specifications.
+ *
+ * $doubleEquiv
+ *
+ * This equivalence may be preferable for numeric contexts.
+ *
+ * @see [[StrictEquiv]]
+ */
+ trait IeeeEquiv extends Equiv[Double] {
+ def equiv(x: Double, y: Double): Boolean = x == y
+ }
+ implicit object IeeeEquiv extends IeeeEquiv
+ }
+ @migration(
+ " The default implicit equivalence for doubles no longer conforms to\n" +
+ " to IEEE 754's behavior for -0.0D and NaN.\n" +
+ " Import `Equiv.Double.IeeeEquiv` to recover the previous behavior.\n" +
+ " See also https://www.scala-lang.org/api/current/scala/math/Equiv$$Double$.html.", "2.13.2")
+ implicit object DeprecatedDoubleEquiv extends Double.StrictEquiv
+
+ implicit object BigInt extends Equiv[BigInt] {
+ def equiv(x: BigInt, y: BigInt): Boolean = x == y
+ }
+
+ implicit object BigDecimal extends Equiv[BigDecimal] {
+ def equiv(x: BigDecimal, y: BigDecimal): Boolean = x == y
+ }
+
+ implicit object String extends Equiv[String] {
+ def equiv(x: String, y: String): Boolean = x == y
+ }
+
+ implicit object Symbol extends Equiv[Symbol] {
+ def equiv(x: Symbol, y: Symbol): Boolean = x == y
+ }
+
+ implicit def Option[T](implicit eqv: Equiv[T]): Equiv[Option[T]] =
+ new OptionEquiv[T](eqv)
+
+ private[this] final class OptionEquiv[T](private val eqv: Equiv[T]) extends Equiv[Option[T]] {
+ def equiv(x: Option[T], y: Option[T]): Boolean = (x, y) match {
+ case (None, None) => true
+ case (Some(x), Some(y)) => eqv.equiv(x, y)
+ case _ => false
+ }
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: OptionEquiv[_] => this.eqv == that.eqv
+ case _ => false
+ }
+ override def hashCode(): Int = eqv.hashCode() * optionSeed
+ }
+
+ implicit def Tuple2[T1, T2](implicit eqv1: Equiv[T1], eqv2: Equiv[T2]): Equiv[(T1, T2)] =
+ new Tuple2Equiv(eqv1, eqv2)
+
+ private[this] final class Tuple2Equiv[T1, T2](private val eqv1: Equiv[T1],
+ private val eqv2: Equiv[T2]) extends Equiv[(T1, T2)] {
+ def equiv(x: (T1, T2), y: (T1, T2)): Boolean =
+ eqv1.equiv(x._1, y._1) &&
+ eqv2.equiv(x._2, y._2)
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple2Equiv[_, _] =>
+ this.eqv1 == that.eqv1 &&
+ this.eqv2 == that.eqv2
+ case _ => false
+ }
+ override def hashCode(): Int = (eqv1, eqv2).hashCode()
+ }
+
+ implicit def Tuple3[T1, T2, T3](implicit eqv1: Equiv[T1], eqv2: Equiv[T2], eqv3: Equiv[T3]) : Equiv[(T1, T2, T3)] =
+ new Tuple3Equiv(eqv1, eqv2, eqv3)
+
+ private[this] final class Tuple3Equiv[T1, T2, T3](private val eqv1: Equiv[T1],
+ private val eqv2: Equiv[T2],
+ private val eqv3: Equiv[T3]) extends Equiv[(T1, T2, T3)] {
+ def equiv(x: (T1, T2, T3), y: (T1, T2, T3)): Boolean =
+ eqv1.equiv(x._1, y._1) &&
+ eqv2.equiv(x._2, y._2) &&
+ eqv3.equiv(x._3, y._3)
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple3Equiv[_, _, _] =>
+ this.eqv1 == that.eqv1 &&
+ this.eqv2 == that.eqv2 &&
+ this.eqv3 == that.eqv3
+ case _ => false
+ }
+ override def hashCode(): Int = (eqv1, eqv2, eqv3).hashCode()
+ }
+
+ implicit def Tuple4[T1, T2, T3, T4](implicit eqv1: Equiv[T1], eqv2: Equiv[T2], eqv3: Equiv[T3], eqv4: Equiv[T4]) : Equiv[(T1, T2, T3, T4)] =
+ new Tuple4Equiv(eqv1, eqv2, eqv3, eqv4)
+
+ private[this] final class Tuple4Equiv[T1, T2, T3, T4](private val eqv1: Equiv[T1],
+ private val eqv2: Equiv[T2],
+ private val eqv3: Equiv[T3],
+ private val eqv4: Equiv[T4])
+ extends Equiv[(T1, T2, T3, T4)] {
+ def equiv(x: (T1, T2, T3, T4), y: (T1, T2, T3, T4)): Boolean =
+ eqv1.equiv(x._1, y._1) &&
+ eqv2.equiv(x._2, y._2) &&
+ eqv3.equiv(x._3, y._3) &&
+ eqv4.equiv(x._4, y._4)
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple4Equiv[_, _, _, _] =>
+ this.eqv1 == that.eqv1 &&
+ this.eqv2 == that.eqv2 &&
+ this.eqv3 == that.eqv3 &&
+ this.eqv4 == that.eqv4
+ case _ => false
+ }
+ override def hashCode(): Int = (eqv1, eqv2, eqv3, eqv4).hashCode()
+ }
+
+ implicit def Tuple5[T1, T2, T3, T4, T5](implicit eqv1: Equiv[T1], eqv2: Equiv[T2], eqv3: Equiv[T3], eqv4: Equiv[T4], eqv5: Equiv[T5]): Equiv[(T1, T2, T3, T4, T5)] =
+ new Tuple5Equiv(eqv1, eqv2, eqv3, eqv4, eqv5)
+
+ private[this] final class Tuple5Equiv[T1, T2, T3, T4, T5](private val eqv1: Equiv[T1],
+ private val eqv2: Equiv[T2],
+ private val eqv3: Equiv[T3],
+ private val eqv4: Equiv[T4],
+ private val eqv5: Equiv[T5])
+ extends Equiv[(T1, T2, T3, T4, T5)] {
+ def equiv(x: (T1, T2, T3, T4, T5), y: (T1, T2, T3, T4, T5)): Boolean =
+ eqv1.equiv(x._1, y._1) &&
+ eqv2.equiv(x._2, y._2) &&
+ eqv3.equiv(x._3, y._3) &&
+ eqv4.equiv(x._4, y._4) &&
+ eqv5.equiv(x._5, y._5)
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple5Equiv[_, _, _, _, _] =>
+ this.eqv1 == that.eqv1 &&
+ this.eqv2 == that.eqv2 &&
+ this.eqv3 == that.eqv3 &&
+ this.eqv4 == that.eqv4 &&
+ this.eqv5 == that.eqv5
+ case _ => false
+ }
+ override def hashCode(): Int = (eqv1, eqv2, eqv3, eqv4, eqv5).hashCode()
+ }
+
+ implicit def Tuple6[T1, T2, T3, T4, T5, T6](implicit eqv1: Equiv[T1], eqv2: Equiv[T2], eqv3: Equiv[T3], eqv4: Equiv[T4], eqv5: Equiv[T5], eqv6: Equiv[T6]): Equiv[(T1, T2, T3, T4, T5, T6)] =
+ new Tuple6Equiv(eqv1, eqv2, eqv3, eqv4, eqv5, eqv6)
+
+ private[this] final class Tuple6Equiv[T1, T2, T3, T4, T5, T6](private val eqv1: Equiv[T1],
+ private val eqv2: Equiv[T2],
+ private val eqv3: Equiv[T3],
+ private val eqv4: Equiv[T4],
+ private val eqv5: Equiv[T5],
+ private val eqv6: Equiv[T6])
+ extends Equiv[(T1, T2, T3, T4, T5, T6)] {
+ def equiv(x: (T1, T2, T3, T4, T5, T6), y: (T1, T2, T3, T4, T5, T6)): Boolean =
+ eqv1.equiv(x._1, y._1) &&
+ eqv2.equiv(x._2, y._2) &&
+ eqv3.equiv(x._3, y._3) &&
+ eqv4.equiv(x._4, y._4) &&
+ eqv5.equiv(x._5, y._5) &&
+ eqv6.equiv(x._6, y._6)
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple6Equiv[_, _, _, _, _, _] =>
+ this.eqv1 == that.eqv1 &&
+ this.eqv2 == that.eqv2 &&
+ this.eqv3 == that.eqv3 &&
+ this.eqv4 == that.eqv4 &&
+ this.eqv5 == that.eqv5 &&
+ this.eqv6 == that.eqv6
+ case _ => false
+ }
+ override def hashCode(): Int = (eqv1, eqv2, eqv3, eqv4, eqv5, eqv6).hashCode()
+ }
+
+ implicit def Tuple7[T1, T2, T3, T4, T5, T6, T7](implicit eqv1: Equiv[T1], eqv2: Equiv[T2], eqv3: Equiv[T3], eqv4: Equiv[T4], eqv5: Equiv[T5], eqv6: Equiv[T6], eqv7: Equiv[T7]): Equiv[(T1, T2, T3, T4, T5, T6, T7)] =
+ new Tuple7Equiv(eqv1, eqv2, eqv3, eqv4, eqv5, eqv6, eqv7)
+
+ private[this] final class Tuple7Equiv[T1, T2, T3, T4, T5, T6, T7](private val eqv1: Equiv[T1],
+ private val eqv2: Equiv[T2],
+ private val eqv3: Equiv[T3],
+ private val eqv4: Equiv[T4],
+ private val eqv5: Equiv[T5],
+ private val eqv6: Equiv[T6],
+ private val eqv7: Equiv[T7])
+ extends Equiv[(T1, T2, T3, T4, T5, T6, T7)] {
+ def equiv(x: (T1, T2, T3, T4, T5, T6, T7), y: (T1, T2, T3, T4, T5, T6, T7)): Boolean =
+ eqv1.equiv(x._1, y._1) &&
+ eqv2.equiv(x._2, y._2) &&
+ eqv3.equiv(x._3, y._3) &&
+ eqv4.equiv(x._4, y._4) &&
+ eqv5.equiv(x._5, y._5) &&
+ eqv6.equiv(x._6, y._6) &&
+ eqv7.equiv(x._7, y._7)
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple7Equiv[_, _, _, _, _, _, _] =>
+ this.eqv1 == that.eqv1 &&
+ this.eqv2 == that.eqv2 &&
+ this.eqv3 == that.eqv3 &&
+ this.eqv4 == that.eqv4 &&
+ this.eqv5 == that.eqv5 &&
+ this.eqv6 == that.eqv6 &&
+ this.eqv7 == that.eqv7
+ case _ => false
+ }
+ override def hashCode(): Int = (eqv1, eqv2, eqv3, eqv4, eqv5, eqv6, eqv7).hashCode()
+ }
+
+ implicit def Tuple8[T1, T2, T3, T4, T5, T6, T7, T8](implicit eqv1: Equiv[T1], eqv2: Equiv[T2], eqv3: Equiv[T3], eqv4: Equiv[T4], eqv5: Equiv[T5], eqv6: Equiv[T6], eqv7: Equiv[T7], eqv8: Equiv[T8]): Equiv[(T1, T2, T3, T4, T5, T6, T7, T8)] =
+ new Tuple8Equiv(eqv1, eqv2, eqv3, eqv4, eqv5, eqv6, eqv7, eqv8)
+
+ private[this] final class Tuple8Equiv[T1, T2, T3, T4, T5, T6, T7, T8](private val eqv1: Equiv[T1],
+ private val eqv2: Equiv[T2],
+ private val eqv3: Equiv[T3],
+ private val eqv4: Equiv[T4],
+ private val eqv5: Equiv[T5],
+ private val eqv6: Equiv[T6],
+ private val eqv7: Equiv[T7],
+ private val eqv8: Equiv[T8])
+ extends Equiv[(T1, T2, T3, T4, T5, T6, T7, T8)] {
+ def equiv(x: (T1, T2, T3, T4, T5, T6, T7, T8), y: (T1, T2, T3, T4, T5, T6, T7, T8)): Boolean =
+ eqv1.equiv(x._1, y._1) &&
+ eqv2.equiv(x._2, y._2) &&
+ eqv3.equiv(x._3, y._3) &&
+ eqv4.equiv(x._4, y._4) &&
+ eqv5.equiv(x._5, y._5) &&
+ eqv6.equiv(x._6, y._6) &&
+ eqv7.equiv(x._7, y._7) &&
+ eqv8.equiv(x._8, y._8)
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple8Equiv[_, _, _, _, _, _, _, _] =>
+ this.eqv1 == that.eqv1 &&
+ this.eqv2 == that.eqv2 &&
+ this.eqv3 == that.eqv3 &&
+ this.eqv4 == that.eqv4 &&
+ this.eqv5 == that.eqv5 &&
+ this.eqv6 == that.eqv6 &&
+ this.eqv7 == that.eqv7 &&
+ this.eqv8 == that.eqv8
+ case _ => false
+ }
+ override def hashCode(): Int = (eqv1, eqv2, eqv3, eqv4, eqv5, eqv6, eqv7, eqv8).hashCode()
+ }
+
+ implicit def Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9](implicit eqv1: Equiv[T1], eqv2: Equiv[T2], eqv3: Equiv[T3], eqv4: Equiv[T4], eqv5: Equiv[T5], eqv6: Equiv[T6], eqv7: Equiv[T7], eqv8 : Equiv[T8], eqv9: Equiv[T9]): Equiv[(T1, T2, T3, T4, T5, T6, T7, T8, T9)] =
+ new Tuple9Equiv(eqv1, eqv2, eqv3, eqv4, eqv5, eqv6, eqv7, eqv8, eqv9)
+
+ private[this] final class Tuple9Equiv[T1, T2, T3, T4, T5, T6, T7, T8, T9](private val eqv1: Equiv[T1],
+ private val eqv2: Equiv[T2],
+ private val eqv3: Equiv[T3],
+ private val eqv4: Equiv[T4],
+ private val eqv5: Equiv[T5],
+ private val eqv6: Equiv[T6],
+ private val eqv7: Equiv[T7],
+ private val eqv8: Equiv[T8],
+ private val eqv9: Equiv[T9])
+ extends Equiv[(T1, T2, T3, T4, T5, T6, T7, T8, T9)] {
+ def equiv(x: (T1, T2, T3, T4, T5, T6, T7, T8, T9), y: (T1, T2, T3, T4, T5, T6, T7, T8, T9)): Boolean =
+ eqv1.equiv(x._1, y._1) &&
+ eqv2.equiv(x._2, y._2) &&
+ eqv3.equiv(x._3, y._3) &&
+ eqv4.equiv(x._4, y._4) &&
+ eqv5.equiv(x._5, y._5) &&
+ eqv6.equiv(x._6, y._6) &&
+ eqv7.equiv(x._7, y._7) &&
+ eqv8.equiv(x._8, y._8) &&
+ eqv9.equiv(x._9, y._9)
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple9Equiv[_, _, _, _, _, _, _, _, _] =>
+ this.eqv1 == that.eqv1 &&
+ this.eqv2 == that.eqv2 &&
+ this.eqv3 == that.eqv3 &&
+ this.eqv4 == that.eqv4 &&
+ this.eqv5 == that.eqv5 &&
+ this.eqv6 == that.eqv6 &&
+ this.eqv7 == that.eqv7 &&
+ this.eqv8 == that.eqv8 &&
+ this.eqv9 == that.eqv9
+ case _ => false
+ }
+ override def hashCode(): Int = (eqv1, eqv2, eqv3, eqv4, eqv5, eqv6, eqv7, eqv8, eqv9).hashCode()
+ }
+
+}
diff --git a/library/src/scala/math/Fractional.scala b/library/src/scala/math/Fractional.scala
new file mode 100644
index 000000000000..2066cc65d8ac
--- /dev/null
+++ b/library/src/scala/math/Fractional.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.
+ */
+
+package scala
+package math
+
+import scala.language.implicitConversions
+
+trait Fractional[T] extends Numeric[T] {
+ def div(x: T, y: T): T
+
+ class FractionalOps(lhs: T) extends NumericOps(lhs) {
+ def /(rhs: T) = div(lhs, rhs)
+ }
+ override implicit def mkNumericOps(lhs: T): FractionalOps =
+ new FractionalOps(lhs)
+}
+
+object Fractional {
+ @inline def apply[T](implicit frac: Fractional[T]): Fractional[T] = frac
+
+ trait ExtraImplicits {
+ implicit def infixFractionalOps[T](x: T)(implicit num: Fractional[T]): Fractional[T]#FractionalOps = new num.FractionalOps(x)
+ }
+ object Implicits extends ExtraImplicits
+}
diff --git a/library/src/scala/math/Integral.scala b/library/src/scala/math/Integral.scala
new file mode 100644
index 000000000000..d5dd189d64fe
--- /dev/null
+++ b/library/src/scala/math/Integral.scala
@@ -0,0 +1,41 @@
+/*
+ * 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 math
+
+import scala.language.implicitConversions
+
+trait Integral[T] extends Numeric[T] {
+ def quot(x: T, y: T): T
+ def rem(x: T, y: T): T
+
+ class IntegralOps(lhs: T) extends NumericOps(lhs) {
+ def /(rhs: T) = quot(lhs, rhs)
+ def %(rhs: T) = rem(lhs, rhs)
+ def /%(rhs: T) = (quot(lhs, rhs), rem(lhs, rhs))
+ }
+ override implicit def mkNumericOps(lhs: T): IntegralOps = new IntegralOps(lhs)
+}
+
+object Integral {
+ @inline def apply[T](implicit int: Integral[T]): Integral[T] = int
+
+ trait ExtraImplicits {
+ /** The regrettable design of Numeric/Integral/Fractional has them all
+ * bumping into one another when searching for this implicit, so they
+ * are exiled into their own companions.
+ */
+ implicit def infixIntegralOps[T](x: T)(implicit num: Integral[T]): Integral[T]#IntegralOps = new num.IntegralOps(x)
+ }
+ object Implicits extends ExtraImplicits
+}
diff --git a/library/src/scala/math/Numeric.scala b/library/src/scala/math/Numeric.scala
new file mode 100644
index 000000000000..84028f13f833
--- /dev/null
+++ b/library/src/scala/math/Numeric.scala
@@ -0,0 +1,261 @@
+/*
+ * 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 math
+
+import scala.collection.StringParsers
+import scala.language.implicitConversions
+import scala.util.Try
+
+object Numeric {
+ @inline def apply[T](implicit num: Numeric[T]): Numeric[T] = num
+
+ trait ExtraImplicits {
+ /** These implicits create conversions from a value for which an implicit Numeric
+ * exists to the inner class which creates infix operations. Once imported, you
+ * can write methods as follows:
+ * {{{
+ * def plus[T: Numeric](x: T, y: T) = x + y
+ * }}}
+ */
+ implicit def infixNumericOps[T](x: T)(implicit num: Numeric[T]): Numeric[T]#NumericOps = new num.NumericOps(x)
+ }
+ object Implicits extends ExtraImplicits { }
+
+ trait BigIntIsIntegral extends Integral[BigInt] {
+ def plus(x: BigInt, y: BigInt): BigInt = x + y
+ def minus(x: BigInt, y: BigInt): BigInt = x - y
+ def times(x: BigInt, y: BigInt): BigInt = x * y
+ def quot(x: BigInt, y: BigInt): BigInt = x / y
+ def rem(x: BigInt, y: BigInt): BigInt = x % y
+ def negate(x: BigInt): BigInt = -x
+ def fromInt(x: Int): BigInt = BigInt(x)
+ def parseString(str: String): Option[BigInt] = Try(BigInt(str)).toOption
+ def toInt(x: BigInt): Int = x.intValue
+ def toLong(x: BigInt): Long = x.longValue
+ def toFloat(x: BigInt): Float = x.floatValue
+ def toDouble(x: BigInt): Double = x.doubleValue
+ }
+ implicit object BigIntIsIntegral extends BigIntIsIntegral with Ordering.BigIntOrdering
+
+ trait IntIsIntegral extends Integral[Int] {
+ def plus(x: Int, y: Int): Int = x + y
+ def minus(x: Int, y: Int): Int = x - y
+ def times(x: Int, y: Int): Int = x * y
+ def quot(x: Int, y: Int): Int = x / y
+ def rem(x: Int, y: Int): Int = x % y
+ def negate(x: Int): Int = -x
+ def fromInt(x: Int): Int = x
+ def parseString(str: String): Option[Int] = StringParsers.parseInt(str)
+ def toInt(x: Int): Int = x
+ def toLong(x: Int): Long = x.toLong
+ def toFloat(x: Int): Float = x.toFloat
+ def toDouble(x: Int): Double = x.toDouble
+ override def signum(x: Int): Int = math.signum(x)
+ override def sign(x: Int): Int = math.signum(x)
+ }
+ implicit object IntIsIntegral extends IntIsIntegral with Ordering.IntOrdering
+
+ trait ShortIsIntegral extends Integral[Short] {
+ def plus(x: Short, y: Short): Short = (x + y).toShort
+ def minus(x: Short, y: Short): Short = (x - y).toShort
+ def times(x: Short, y: Short): Short = (x * y).toShort
+ def quot(x: Short, y: Short): Short = (x / y).toShort
+ def rem(x: Short, y: Short): Short = (x % y).toShort
+ def negate(x: Short): Short = (-x).toShort
+ def fromInt(x: Int): Short = x.toShort
+ def parseString(str: String): Option[Short] = StringParsers.parseShort(str)
+ def toInt(x: Short): Int = x.toInt
+ def toLong(x: Short): Long = x.toLong
+ def toFloat(x: Short): Float = x.toFloat
+ def toDouble(x: Short): Double = x.toDouble
+ override def signum(x: Short): Int = math.signum(x.toInt)
+ override def sign(x: Short): Short = math.signum(x.toInt).toShort
+ }
+ implicit object ShortIsIntegral extends ShortIsIntegral with Ordering.ShortOrdering
+
+ trait ByteIsIntegral extends Integral[Byte] {
+ def plus(x: Byte, y: Byte): Byte = (x + y).toByte
+ def minus(x: Byte, y: Byte): Byte = (x - y).toByte
+ def times(x: Byte, y: Byte): Byte = (x * y).toByte
+ def quot(x: Byte, y: Byte): Byte = (x / y).toByte
+ def rem(x: Byte, y: Byte): Byte = (x % y).toByte
+ def negate(x: Byte): Byte = (-x).toByte
+ def fromInt(x: Int): Byte = x.toByte
+ def parseString(str: String): Option[Byte] = StringParsers.parseByte(str)
+ def toInt(x: Byte): Int = x.toInt
+ def toLong(x: Byte): Long = x.toLong
+ def toFloat(x: Byte): Float = x.toFloat
+ def toDouble(x: Byte): Double = x.toDouble
+ override def signum(x: Byte): Int = math.signum(x.toInt)
+ override def sign(x: Byte): Byte = math.signum(x.toInt).toByte
+ }
+ implicit object ByteIsIntegral extends ByteIsIntegral with Ordering.ByteOrdering
+
+ trait CharIsIntegral extends Integral[Char] {
+ def plus(x: Char, y: Char): Char = (x + y).toChar
+ def minus(x: Char, y: Char): Char = (x - y).toChar
+ def times(x: Char, y: Char): Char = (x * y).toChar
+ def quot(x: Char, y: Char): Char = (x / y).toChar
+ def rem(x: Char, y: Char): Char = (x % y).toChar
+ def negate(x: Char): Char = (-x).toChar
+ def fromInt(x: Int): Char = x.toChar
+ def parseString(str: String): Option[Char] = Try(str.toInt.toChar).toOption
+ def toInt(x: Char): Int = x.toInt
+ def toLong(x: Char): Long = x.toLong
+ def toFloat(x: Char): Float = x.toFloat
+ def toDouble(x: Char): Double = x.toDouble
+ override def signum(x: Char): Int = math.signum(x.toInt)
+ override def sign(x: Char): Char = math.signum(x.toInt).toChar
+ }
+ implicit object CharIsIntegral extends CharIsIntegral with Ordering.CharOrdering
+
+ trait LongIsIntegral extends Integral[Long] {
+ def plus(x: Long, y: Long): Long = x + y
+ def minus(x: Long, y: Long): Long = x - y
+ def times(x: Long, y: Long): Long = x * y
+ def quot(x: Long, y: Long): Long = x / y
+ def rem(x: Long, y: Long): Long = x % y
+ def negate(x: Long): Long = -x
+ def fromInt(x: Int): Long = x.toLong
+ def parseString(str: String): Option[Long] = StringParsers.parseLong(str)
+ def toInt(x: Long): Int = x.toInt
+ def toLong(x: Long): Long = x
+ def toFloat(x: Long): Float = x.toFloat
+ def toDouble(x: Long): Double = x.toDouble
+ override def signum(x: Long): Int = math.signum(x).toInt
+ override def sign(x: Long): Long = math.signum(x)
+ }
+ implicit object LongIsIntegral extends LongIsIntegral with Ordering.LongOrdering
+
+ trait FloatIsFractional extends Fractional[Float] {
+ def plus(x: Float, y: Float): Float = x + y
+ def minus(x: Float, y: Float): Float = x - y
+ def times(x: Float, y: Float): Float = x * y
+ def negate(x: Float): Float = -x
+ def fromInt(x: Int): Float = x.toFloat
+ def parseString(str: String): Option[Float] = StringParsers.parseFloat(str)
+ def toInt(x: Float): Int = x.toInt
+ def toLong(x: Float): Long = x.toLong
+ def toFloat(x: Float): Float = x
+ def toDouble(x: Float): Double = x.toDouble
+ def div(x: Float, y: Float): Float = x / y
+ // logic in Numeric base trait mishandles abs(-0.0f)
+ override def abs(x: Float): Float = math.abs(x)
+ // logic in Numeric base trait mishandles sign(-0.0f) and sign(Float.NaN)
+ override def sign(x: Float): Float = math.signum(x)
+ }
+ implicit object FloatIsFractional extends FloatIsFractional with Ordering.Float.IeeeOrdering
+
+ trait DoubleIsFractional extends Fractional[Double] {
+ def plus(x: Double, y: Double): Double = x + y
+ def minus(x: Double, y: Double): Double = x - y
+ def times(x: Double, y: Double): Double = x * y
+ def negate(x: Double): Double = -x
+ def fromInt(x: Int): Double = x.toDouble
+ def parseString(str: String): Option[Double] = StringParsers.parseDouble(str)
+ def toInt(x: Double): Int = x.toInt
+ def toLong(x: Double): Long = x.toLong
+ def toFloat(x: Double): Float = x.toFloat
+ def toDouble(x: Double): Double = x
+ def div(x: Double, y: Double): Double = x / y
+ // logic in Numeric base trait mishandles abs(-0.0)
+ override def abs(x: Double): Double = math.abs(x)
+ // logic in Numeric base trait mishandles sign(-0.0) and sign(Double.NaN)
+ override def sign(x: Double): Double = math.signum(x)
+ }
+ implicit object DoubleIsFractional extends DoubleIsFractional with Ordering.Double.IeeeOrdering
+
+ trait BigDecimalIsConflicted extends Numeric[BigDecimal] {
+ // works around pollution of math context by ignoring identity element
+ def plus(x: BigDecimal, y: BigDecimal): BigDecimal = {
+ import BigDecimalIsConflicted._0
+ if (x eq _0) y else x + y
+ }
+ def minus(x: BigDecimal, y: BigDecimal): BigDecimal = {
+ import BigDecimalIsConflicted._0
+ if (x eq _0) -y else x - y
+ }
+ // works around pollution of math context by ignoring identity element
+ def times(x: BigDecimal, y: BigDecimal): BigDecimal = {
+ import BigDecimalIsConflicted._1
+ if (x eq _1) y else x * y
+ }
+ def negate(x: BigDecimal): BigDecimal = -x
+ def fromInt(x: Int): BigDecimal = BigDecimal(x)
+ def parseString(str: String): Option[BigDecimal] = Try(BigDecimal(str)).toOption
+ def toInt(x: BigDecimal): Int = x.intValue
+ def toLong(x: BigDecimal): Long = x.longValue
+ def toFloat(x: BigDecimal): Float = x.floatValue
+ def toDouble(x: BigDecimal): Double = x.doubleValue
+ }
+ private object BigDecimalIsConflicted {
+ private val _0 = BigDecimal(0) // cached zero is ordinarily cached for default math context
+ private val _1 = BigDecimal(1) // cached one is ordinarily cached for default math context
+ }
+
+ trait BigDecimalIsFractional extends BigDecimalIsConflicted with Fractional[BigDecimal] {
+ def div(x: BigDecimal, y: BigDecimal): BigDecimal = x / y
+ }
+ trait BigDecimalAsIfIntegral extends BigDecimalIsConflicted with Integral[BigDecimal] {
+ def quot(x: BigDecimal, y: BigDecimal): BigDecimal = x quot y
+ def rem(x: BigDecimal, y: BigDecimal): BigDecimal = x remainder y
+ }
+
+ // For BigDecimal we offer an implicit Fractional object, but also one
+ // which acts like an Integral type, which is useful in NumericRange.
+ implicit object BigDecimalIsFractional extends BigDecimalIsFractional with Ordering.BigDecimalOrdering
+ object BigDecimalAsIfIntegral extends BigDecimalAsIfIntegral with Ordering.BigDecimalOrdering
+}
+
+trait Numeric[T] extends Ordering[T] {
+ def plus(x: T, y: T): T
+ def minus(x: T, y: T): T
+ def times(x: T, y: T): T
+ def negate(x: T): T
+ def fromInt(x: Int): T
+ def parseString(str: String): Option[T]
+ def toInt(x: T): Int
+ def toLong(x: T): Long
+ def toFloat(x: T): Float
+ def toDouble(x: T): Double
+
+ def zero = fromInt(0)
+ def one = fromInt(1)
+
+ def abs(x: T): T = if (lt(x, zero)) negate(x) else x
+
+ @deprecated("use `sign` method instead", since = "2.13.0") def signum(x: T): Int =
+ if (lt(x, zero)) -1
+ else if (gt(x, zero)) 1
+ else 0
+ def sign(x: T): T =
+ if (lt(x, zero)) negate(one)
+ else if (gt(x, zero)) one
+ else zero
+
+ class NumericOps(lhs: T) {
+ def +(rhs: T) = plus(lhs, rhs)
+ def -(rhs: T) = minus(lhs, rhs)
+ def *(rhs: T) = times(lhs, rhs)
+ def unary_- = negate(lhs)
+ def abs: T = Numeric.this.abs(lhs)
+ @deprecated("use `sign` method instead", since = "2.13.0") def signum: Int = Numeric.this.signum(lhs)
+ def sign: T = Numeric.this.sign(lhs)
+ def toInt: Int = Numeric.this.toInt(lhs)
+ def toLong: Long = Numeric.this.toLong(lhs)
+ def toFloat: Float = Numeric.this.toFloat(lhs)
+ def toDouble: Double = Numeric.this.toDouble(lhs)
+ }
+ implicit def mkNumericOps(lhs: T): NumericOps = new NumericOps(lhs)
+}
diff --git a/library/src/scala/math/Ordered.scala b/library/src/scala/math/Ordered.scala
new file mode 100644
index 000000000000..fe3ed90453e0
--- /dev/null
+++ b/library/src/scala/math/Ordered.scala
@@ -0,0 +1,101 @@
+/*
+ * 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 math
+
+import scala.language.implicitConversions
+
+/** A trait for data that have a single, natural ordering. See
+ * [[scala.math.Ordering]] before using this trait for
+ * more information about whether to use [[scala.math.Ordering]] instead.
+ *
+ * Classes that implement this trait can be sorted with
+ * [[scala.util.Sorting]] and can be compared with standard comparison operators
+ * (e.g. > and <).
+ *
+ * Ordered should be used for data with a single, natural ordering (like
+ * integers) while Ordering allows for multiple ordering implementations.
+ * An Ordering instance will be implicitly created if necessary.
+ *
+ * [[scala.math.Ordering]] is an alternative to this trait that allows multiple orderings to be
+ * defined for the same type.
+ *
+ * [[scala.math.PartiallyOrdered]] is an alternative to this trait for partially ordered data.
+ *
+ * For example, create a simple class that implements `Ordered` and then sort it with [[scala.util.Sorting]]:
+ * {{{
+ * case class OrderedClass(n:Int) extends Ordered[OrderedClass] {
+ * def compare(that: OrderedClass) = this.n - that.n
+ * }
+ *
+ * val x = Array(OrderedClass(1), OrderedClass(5), OrderedClass(3))
+ * scala.util.Sorting.quickSort(x)
+ * x
+ * }}}
+ *
+ * It is important that the `equals` method for an instance of `Ordered[A]` be consistent with the
+ * compare method. However, due to limitations inherent in the type erasure semantics, there is no
+ * reasonable way to provide a default implementation of equality for instances of `Ordered[A]`.
+ * Therefore, if you need to be able to use equality on an instance of `Ordered[A]` you must
+ * provide it yourself either when inheriting or instantiating.
+ *
+ * It is important that the `hashCode` method for an instance of `Ordered[A]` be consistent with
+ * the `compare` method. However, it is not possible to provide a sensible default implementation.
+ * Therefore, if you need to be able compute the hash of an instance of `Ordered[A]` you must
+ * provide it yourself either when inheriting or instantiating.
+ *
+ * @see [[scala.math.Ordering]], [[scala.math.PartiallyOrdered]]
+ */
+trait Ordered[A] extends Any with java.lang.Comparable[A] {
+
+ /** Result of comparing `this` with operand `that`.
+ *
+ * Implement this method to determine how instances of A will be sorted.
+ *
+ * Returns `x` where:
+ *
+ * - `x < 0` when `this < that`
+ *
+ * - `x == 0` when `this == that`
+ *
+ * - `x > 0` when `this > that`
+ *
+ */
+ def compare(that: A): Int
+
+ /** Returns true if `this` is less than `that`
+ */
+ def < (that: A): Boolean = (this compare that) < 0
+
+ /** Returns true if `this` is greater than `that`.
+ */
+ def > (that: A): Boolean = (this compare that) > 0
+
+ /** Returns true if `this` is less than or equal to `that`.
+ */
+ def <= (that: A): Boolean = (this compare that) <= 0
+
+ /** Returns true if `this` is greater than or equal to `that`.
+ */
+ def >= (that: A): Boolean = (this compare that) >= 0
+
+ /** Result of comparing `this` with operand `that`.
+ */
+ def compareTo(that: A): Int = compare(that)
+}
+
+object Ordered {
+ /** Lens from `Ordering[T]` to `Ordered[T]` */
+ implicit def orderingToOrdered[T](x: T)(implicit ord: Ordering[T]): Ordered[T] =
+ new Ordered[T] { def compare(that: T): Int = ord.compare(x, that) }
+}
diff --git a/library/src/scala/math/Ordering.scala b/library/src/scala/math/Ordering.scala
new file mode 100644
index 000000000000..5a34f1fe91a9
--- /dev/null
+++ b/library/src/scala/math/Ordering.scala
@@ -0,0 +1,928 @@
+/*
+ * 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 math
+
+import java.util.Comparator
+
+import scala.language.implicitConversions
+import scala.annotation.migration
+
+/** Ordering is a trait whose instances each represent a strategy for sorting
+ * instances of a type.
+ *
+ * Ordering's companion object defines many implicit objects to deal with
+ * subtypes of [[AnyVal]] (e.g. `Int`, `Double`), `String`, and others.
+ *
+ * To sort instances by one or more member variables, you can take advantage
+ * of these built-in orderings using [[Ordering.by]] and [[Ordering.on]]:
+ *
+ * {{{
+ * import scala.util.Sorting
+ * val pairs = Array(("a", 5, 2), ("c", 3, 1), ("b", 1, 3))
+ *
+ * // sort by 2nd element
+ * Sorting.quickSort(pairs)(Ordering.by[(String, Int, Int), Int](_._2))
+ *
+ * // sort by the 3rd element, then 1st
+ * Sorting.quickSort(pairs)(Ordering[(Int, String)].on(x => (x._3, x._1)))
+ * }}}
+ *
+ * An `Ordering[T]` is implemented by specifying the [[compare]] method,
+ * `compare(a: T, b: T): Int`, which decides how to order two instances
+ * `a` and `b`. Instances of `Ordering[T]` can be used by things like
+ * `scala.util.Sorting` to sort collections like `Array[T]`.
+ *
+ * For example:
+ *
+ * {{{
+ * import scala.util.Sorting
+ *
+ * case class Person(name:String, age:Int)
+ * val people = Array(Person("bob", 30), Person("ann", 32), Person("carl", 19))
+ *
+ * // sort by age
+ * object AgeOrdering extends Ordering[Person] {
+ * def compare(a:Person, b:Person) = a.age.compare(b.age)
+ * }
+ * Sorting.quickSort(people)(AgeOrdering)
+ * }}}
+ *
+ * This trait and [[scala.math.Ordered]] both provide this same functionality, but
+ * in different ways. A type `T` can be given a single way to order itself by
+ * extending `Ordered`. Using `Ordering`, this same type may be sorted in many
+ * other ways. `Ordered` and `Ordering` both provide implicits allowing them to be
+ * used interchangeably.
+ *
+ * You can `import scala.math.Ordering.Implicits._` to gain access to other
+ * implicit orderings.
+ *
+ * @see [[scala.math.Ordered]], [[scala.util.Sorting]], [[scala.math.Ordering.Implicits]]
+ */
+trait Ordering[T] extends Comparator[T] with PartialOrdering[T] with Serializable {
+ outer =>
+
+ /** Returns whether a comparison between `x` and `y` is defined, and if so
+ * the result of `compare(x, y)`.
+ */
+ def tryCompare(x: T, y: T): Some[Int] = Some(compare(x, y))
+
+ /** Returns an integer whose sign communicates how x compares to y.
+ *
+ * The result sign has the following meaning:
+ *
+ * - negative if x < y
+ * - positive if x > y
+ * - zero otherwise (if x == y)
+ */
+ def compare(x: T, y: T): Int
+
+ /** Return true if `x` <= `y` in the ordering. */
+ override def lteq(x: T, y: T): Boolean = compare(x, y) <= 0
+
+ /** Return true if `x` >= `y` in the ordering. */
+ override def gteq(x: T, y: T): Boolean = compare(x, y) >= 0
+
+ /** Return true if `x` < `y` in the ordering. */
+ override def lt(x: T, y: T): Boolean = compare(x, y) < 0
+
+ /** Return true if `x` > `y` in the ordering. */
+ override def gt(x: T, y: T): Boolean = compare(x, y) > 0
+
+ /** Return true if `x` == `y` in the ordering. */
+ override def equiv(x: T, y: T): Boolean = compare(x, y) == 0
+
+ /** Return `x` if `x` >= `y`, otherwise `y`. */
+ def max[U <: T](x: U, y: U): U = if (gteq(x, y)) x else y
+
+ /** Return `x` if `x` <= `y`, otherwise `y`. */
+ def min[U <: T](x: U, y: U): U = if (lteq(x, y)) x else y
+
+ /** Return the opposite ordering of this one.
+ *
+ * Implementations overriding this method MUST override [[isReverseOf]]
+ * as well if they change the behavior at all (for example, caching does
+ * not require overriding it).
+ */
+ override def reverse: Ordering[T] = new Ordering.Reverse[T](this)
+
+ /** Returns whether or not the other ordering is the opposite
+ * ordering of this one.
+ *
+ * Equivalent to `other == this.reverse`.
+ *
+ * Implementations should only override this method if they are overriding
+ * [[reverse]] as well.
+ */
+ def isReverseOf(other: Ordering[_]): Boolean = other match {
+ case that: Ordering.Reverse[_] => that.outer == this
+ case _ => false
+ }
+
+ /** Given f, a function from U into T, creates an Ordering[U] whose compare
+ * function is equivalent to:
+ *
+ * {{{
+ * def compare(x:U, y:U) = Ordering[T].compare(f(x), f(y))
+ * }}}
+ */
+ def on[U](f: U => T): Ordering[U] = new Ordering[U] {
+ def compare(x: U, y: U) = outer.compare(f(x), f(y))
+ }
+
+ /** Creates an Ordering[T] whose compare function returns the
+ * result of this Ordering's compare function, if it is non-zero,
+ * or else the result of `other`s compare function.
+ *
+ * @example
+ * {{{
+ * case class Pair(a: Int, b: Int)
+ *
+ * val pairOrdering = Ordering.by[Pair, Int](_.a)
+ * .orElse(Ordering.by[Pair, Int](_.b))
+ * }}}
+ *
+ * @param other an Ordering to use if this Ordering returns zero
+ */
+ def orElse(other: Ordering[T]): Ordering[T] = (x, y) => {
+ val res1 = outer.compare(x, y)
+ if (res1 != 0) res1 else other.compare(x, y)
+ }
+
+ /** Given f, a function from T into S, creates an Ordering[T] whose compare
+ * function returns the result of this Ordering's compare function,
+ * if it is non-zero, or else a result equivalent to:
+ *
+ * {{{
+ * Ordering[S].compare(f(x), f(y))
+ * }}}
+ *
+ * This function is equivalent to passing the result of `Ordering.by(f)`
+ * to `orElse`.
+ *
+ * @example
+ * {{{
+ * case class Pair(a: Int, b: Int)
+ *
+ * val pairOrdering = Ordering.by[Pair, Int](_.a)
+ * .orElseBy[Int](_.b)
+ * }}}
+ */
+ def orElseBy[S](f: T => S)(implicit ord: Ordering[S]): Ordering[T] = (x, y) => {
+ val res1 = outer.compare(x, y)
+ if (res1 != 0) res1 else ord.compare(f(x), f(y))
+ }
+
+ /** This inner class defines comparison operators available for `T`.
+ *
+ * It can't extend `AnyVal` because it is not a top-level class
+ * or a member of a statically accessible object.
+ */
+ class OrderingOps(lhs: T) {
+ def <(rhs: T): Boolean = lt(lhs, rhs)
+ def <=(rhs: T): Boolean = lteq(lhs, rhs)
+ def >(rhs: T): Boolean = gt(lhs, rhs)
+ def >=(rhs: T): Boolean = gteq(lhs, rhs)
+ def equiv(rhs: T): Boolean = Ordering.this.equiv(lhs, rhs)
+ def max(rhs: T): T = Ordering.this.max(lhs, rhs)
+ def min(rhs: T): T = Ordering.this.min(lhs, rhs)
+ }
+
+ /** This implicit method augments `T` with the comparison operators defined
+ * in `scala.math.Ordering.Ops`.
+ */
+ implicit def mkOrderingOps(lhs: T): OrderingOps = new OrderingOps(lhs)
+}
+
+trait LowPriorityOrderingImplicits {
+
+ type AsComparable[A] = A => Comparable[_ >: A]
+
+ /** This would conflict with all the nice implicit Orderings
+ * available, but thanks to the magic of prioritized implicits
+ * via subclassing we can make `Ordered[A] => Ordering[A]` only
+ * turn up if nothing else works. Since `Ordered[A]` extends
+ * `Comparable[A]` anyway, we can throw in some Java interop too.
+ */
+ implicit def ordered[A](implicit asComparable: AsComparable[A]): Ordering[A] = new Ordering[A] {
+ def compare(x: A, y: A): Int = asComparable(x).compareTo(y)
+ }
+
+ implicit def comparatorToOrdering[A](implicit cmp: Comparator[A]): Ordering[A] = new Ordering[A] {
+ def compare(x: A, y: A) = cmp.compare(x, y)
+ }
+}
+
+/** This is the companion object for the [[scala.math.Ordering]] trait.
+ *
+ * It contains many implicit orderings as well as well as methods to construct
+ * new orderings.
+ */
+object Ordering extends LowPriorityOrderingImplicits {
+ private final val reverseSeed = 41
+ private final val optionSeed = 43
+ private final val iterableSeed = 47
+
+ @inline def apply[T](implicit ord: Ordering[T]) = ord
+
+ /** An ordering which caches the value of its reverse. */
+ sealed trait CachedReverse[T] extends Ordering[T] {
+ private[this] val _reverse = super.reverse
+ override final def reverse: Ordering[T] = _reverse
+ override final def isReverseOf(other: Ordering[_]): Boolean = other eq _reverse
+ }
+
+ /** A reverse ordering */
+ private final class Reverse[T](private[Ordering] val outer: Ordering[T]) extends Ordering[T] {
+ override def reverse: Ordering[T] = outer
+ override def isReverseOf(other: Ordering[_]): Boolean = other == outer
+
+ def compare(x: T, y: T): Int = outer.compare(y, x)
+ override def lteq(x: T, y: T): Boolean = outer.lteq(y, x)
+ override def gteq(x: T, y: T): Boolean = outer.gteq(y, x)
+ override def lt(x: T, y: T): Boolean = outer.lt(y, x)
+ override def gt(x: T, y: T): Boolean = outer.gt(y, x)
+ override def equiv(x: T, y: T): Boolean = outer.equiv(y, x)
+ override def max[U <: T](x: U, y: U): U = outer.min(x, y)
+ override def min[U <: T](x: U, y: U): U = outer.max(x, y)
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Reverse[_] => this.outer == that.outer
+ case _ => false
+ }
+ override def hashCode(): Int = outer.hashCode() * reverseSeed
+ }
+
+ @SerialVersionUID(-2996748994664583574L)
+ private final class IterableOrdering[CC[X] <: Iterable[X], T](private val ord: Ordering[T]) extends Ordering[CC[T]] {
+ def compare(x: CC[T], y: CC[T]): Int = {
+ val xe = x.iterator
+ val ye = y.iterator
+
+ while (xe.hasNext && ye.hasNext) {
+ val res = ord.compare(xe.next(), ye.next())
+ if (res != 0) return res
+ }
+
+ Boolean.compare(xe.hasNext, ye.hasNext)
+ }
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: IterableOrdering[_, _] => this.ord == that.ord
+ case _ => false
+ }
+ override def hashCode(): Int = ord.hashCode() * iterableSeed
+ }
+
+ trait ExtraImplicits {
+ /** Not in the standard scope due to the potential for divergence:
+ * For instance `implicitly[Ordering[Any]]` diverges in its presence.
+ */
+ implicit def seqOrdering[CC[X] <: scala.collection.Seq[X], T](implicit ord: Ordering[T]): Ordering[CC[T]] =
+ new IterableOrdering[CC, T](ord)
+
+ implicit def sortedSetOrdering[CC[X] <: scala.collection.SortedSet[X], T](implicit ord: Ordering[T]): Ordering[CC[T]] =
+ new IterableOrdering[CC, T](ord)
+
+ /** This implicit creates a conversion from any value for which an
+ * implicit `Ordering` exists to the class which creates infix operations.
+ * With it imported, you can write methods as follows:
+ *
+ * {{{
+ * def lessThan[T: Ordering](x: T, y: T) = x < y
+ * }}}
+ */
+ implicit def infixOrderingOps[T](x: T)(implicit ord: Ordering[T]): Ordering[T]#OrderingOps = new ord.OrderingOps(x)
+ }
+
+ /** An object containing implicits which are not in the default scope. */
+ object Implicits extends ExtraImplicits { }
+
+ /** Construct an Ordering[T] given a function `lt`. */
+ def fromLessThan[T](cmp: (T, T) => Boolean): Ordering[T] = new Ordering[T] {
+ def compare(x: T, y: T) = if (cmp(x, y)) -1 else if (cmp(y, x)) 1 else 0
+ // overrides to avoid multiple comparisons
+ override def lt(x: T, y: T): Boolean = cmp(x, y)
+ override def gt(x: T, y: T): Boolean = cmp(y, x)
+ override def gteq(x: T, y: T): Boolean = !cmp(x, y)
+ override def lteq(x: T, y: T): Boolean = !cmp(y, x)
+ }
+
+ /** Given f, a function from T into S, creates an Ordering[T] whose compare
+ * function is equivalent to:
+ *
+ * {{{
+ * def compare(x:T, y:T) = Ordering[S].compare(f(x), f(y))
+ * }}}
+ *
+ * This function is an analogue to Ordering.on where the Ordering[S]
+ * parameter is passed implicitly.
+ */
+ def by[T, S](f: T => S)(implicit ord: Ordering[S]): Ordering[T] = new Ordering[T] {
+ def compare(x: T, y: T) = ord.compare(f(x), f(y))
+ override def lt(x: T, y: T): Boolean = ord.lt(f(x), f(y))
+ override def gt(x: T, y: T): Boolean = ord.gt(f(x), f(y))
+ override def gteq(x: T, y: T): Boolean = ord.gteq(f(x), f(y))
+ override def lteq(x: T, y: T): Boolean = ord.lteq(f(x), f(y))
+ }
+
+ trait UnitOrdering extends Ordering[Unit] {
+ def compare(x: Unit, y: Unit) = 0
+ }
+ @SerialVersionUID(4089257611611206746L)
+ implicit object Unit extends UnitOrdering
+
+ trait BooleanOrdering extends Ordering[Boolean] {
+ def compare(x: Boolean, y: Boolean): Int = java.lang.Boolean.compare(x, y)
+ }
+ @SerialVersionUID(-94703182178890445L)
+ implicit object Boolean extends BooleanOrdering
+
+ trait ByteOrdering extends Ordering[Byte] {
+ def compare(x: Byte, y: Byte): Int = java.lang.Byte.compare(x, y)
+ }
+ @SerialVersionUID(-2268545360148786406L)
+ implicit object Byte extends ByteOrdering
+
+ trait CharOrdering extends Ordering[Char] {
+ def compare(x: Char, y: Char): Int = java.lang.Character.compare(x, y)
+ }
+ @SerialVersionUID(2588141633104296698L)
+ implicit object Char extends CharOrdering
+
+ trait ShortOrdering extends Ordering[Short] {
+ def compare(x: Short, y: Short): Int = java.lang.Short.compare(x, y)
+ }
+ @SerialVersionUID(4919657051864630912L)
+ implicit object Short extends ShortOrdering
+
+ trait IntOrdering extends Ordering[Int] {
+ def compare(x: Int, y: Int): Int = java.lang.Integer.compare(x, y)
+ }
+ @SerialVersionUID(-8412871093094815037L)
+ implicit object Int extends IntOrdering with CachedReverse[Int]
+
+ trait LongOrdering extends Ordering[Long] {
+ def compare(x: Long, y: Long): Int = java.lang.Long.compare(x, y)
+ }
+ @SerialVersionUID(-5231423581640563981L)
+ implicit object Long extends LongOrdering
+
+ /** `Ordering`s for `Float`s.
+ *
+ * The default extends `Ordering.Float.TotalOrdering`.
+ *
+ * `Ordering.Float.TotalOrdering` uses the `java.lang.Float.compare` semantics for all operations.
+ * Scala also provides the `Ordering.Float.IeeeOrdering` semantics. Which uses the IEEE 754 semantics
+ * for float ordering.
+ *
+ * Historically: `IeeeOrdering` was used in Scala from 2.10.x through 2.12.x. This changed in 2.13.0
+ * to `TotalOrdering`.
+ *
+ * Prior to Scala 2.10.0, the `Ordering` instance used semantics
+ * consistent with `java.lang.Float.compare`.
+ *
+ * Scala 2.10.0 changed the implementation of `lt`, `equiv`, `min`, etc., to be
+ * IEEE 754 compliant, while keeping the `compare` method NOT compliant,
+ * creating an internally inconsistent instance. IEEE 754 specifies that
+ * `0.0F == -0.0F`. In addition, it requires all comparisons with `Float.NaN` return
+ * `false` thus `0.0F < Float.NaN`, `0.0F > Float.NaN`, and
+ * `Float.NaN == Float.NaN` all yield `false`, analogous `None` in `flatMap`.
+ *
+ *
+ * {{{
+ * List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).sorted // List(-Infinity, 0.0, 1.0, NaN)
+ * List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).min // -Infinity
+ * implicitly[Ordering[Float]].lt(0.0F, 0.0F / 0.0F) // true
+ * {
+ * import Ordering.Float.IeeeOrdering
+ * List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).sorted // List(-Infinity, 0.0, 1.0, NaN)
+ * List(0.0F, 1.0F, 0.0F / 0.0F, -1.0F / 0.0F).min // NaN
+ * implicitly[Ordering[Float]].lt(0.0F, 0.0F / 0.0F) // false
+ * }
+ * }}}
+ *
+ * @define floatOrdering Because the behavior of `Float`s specified by IEEE is
+ * not consistent with a total ordering when dealing with
+ * `NaN`, there are two orderings defined for `Float`:
+ * `TotalOrdering`, which is consistent with a total
+ * ordering, and `IeeeOrdering`, which is consistent
+ * as much as possible with IEEE spec and floating point
+ * operations defined in [[scala.math]].
+ */
+ object Float {
+ /** An ordering for `Float`s which is a fully consistent total ordering,
+ * and treats `NaN` as larger than all other `Float` values; it behaves
+ * the same as [[java.lang.Float.compare]].
+ *
+ * $floatOrdering
+ *
+ * This ordering may be preferable for sorting collections.
+ *
+ * @see [[IeeeOrdering]]
+ */
+ trait TotalOrdering extends Ordering[Float] {
+ def compare(x: Float, y: Float) = java.lang.Float.compare(x, y)
+ }
+ @SerialVersionUID(2951539161283192433L)
+ implicit object TotalOrdering extends TotalOrdering
+
+ /** An ordering for `Float`s which is consistent with IEEE specifications
+ * whenever possible.
+ *
+ * - `lt`, `lteq`, `equiv`, `gteq` and `gt` are consistent with primitive
+ * comparison operations for `Float`s, and return `false` when called with
+ * `NaN`.
+ * - `min` and `max` are consistent with `math.min` and `math.max`, and
+ * return `NaN` when called with `NaN` as either argument.
+ * - `compare` behaves the same as [[java.lang.Float.compare]].
+ *
+ * $floatOrdering
+ *
+ * This ordering may be preferable for numeric contexts.
+ *
+ * @see [[TotalOrdering]]
+ */
+ trait IeeeOrdering extends Ordering[Float] {
+ def compare(x: Float, y: Float) = java.lang.Float.compare(x, y)
+
+ override def lteq(x: Float, y: Float): Boolean = x <= y
+ override def gteq(x: Float, y: Float): Boolean = x >= y
+ override def lt(x: Float, y: Float): Boolean = x < y
+ override def gt(x: Float, y: Float): Boolean = x > y
+ override def equiv(x: Float, y: Float): Boolean = x == y
+ override def max[U <: Float](x: U, y: U): U = math.max(x, y).asInstanceOf[U]
+ override def min[U <: Float](x: U, y: U): U = math.min(x, y).asInstanceOf[U]
+ }
+ @SerialVersionUID(2142189527751553605L)
+ implicit object IeeeOrdering extends IeeeOrdering
+ }
+ @migration(
+ " The default implicit ordering for floats now maintains consistency\n" +
+ " between its `compare` method and its `lt`, `min`, `equiv`, etc., methods,\n" +
+ " which means nonconforming to IEEE 754's behavior for -0.0F and NaN.\n" +
+ " The sort order of floats remains the same, however, with NaN at the end.\n" +
+ " Import Ordering.Float.IeeeOrdering to recover the previous behavior.\n" +
+ " See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Float$.html.", "2.13.0")
+ @SerialVersionUID(-8500693657289762132L)
+ implicit object DeprecatedFloatOrdering extends Float.TotalOrdering
+
+ /** `Ordering`s for `Double`s.
+ *
+ * The behavior of the comparison operations provided by the default (implicit)
+ * ordering on `Double` changed in 2.10.0 and 2.13.0.
+ * Prior to Scala 2.10.0, the `Ordering` instance used semantics
+ * consistent with `java.lang.Double.compare`.
+ *
+ * Scala 2.10.0 changed the implementation of `lt`, `equiv`, `min`, etc., to be
+ * IEEE 754 compliant, while keeping the `compare` method NOT compliant,
+ * creating an internally inconsistent instance. IEEE 754 specifies that
+ * `0.0 == -0.0`. In addition, it requires all comparisons with `Double.NaN` return
+ * `false` thus `0.0 < Double.NaN`, `0.0 > Double.NaN`, and
+ * `Double.NaN == Double.NaN` all yield `false`, analogous `None` in `flatMap`.
+ *
+ * Recognizing the limitation of the IEEE 754 semantics in terms of ordering,
+ * Scala 2.13.0 created two instances: `Ordering.Double.IeeeOrdering`, which retains
+ * the IEEE 754 semantics from Scala 2.12.x, and `Ordering.Double.TotalOrdering`,
+ * which brings back the `java.lang.Double.compare` semantics for all operations.
+ * The default extends `TotalOrdering`.
+ *
+ * {{{
+ * List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).sorted // List(-Infinity, 0.0, 1.0, NaN)
+ * List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).min // -Infinity
+ * implicitly[Ordering[Double]].lt(0.0, 0.0 / 0.0) // true
+ * {
+ * import Ordering.Double.IeeeOrdering
+ * List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).sorted // List(-Infinity, 0.0, 1.0, NaN)
+ * List(0.0, 1.0, 0.0 / 0.0, -1.0 / 0.0).min // NaN
+ * implicitly[Ordering[Double]].lt(0.0, 0.0 / 0.0) // false
+ * }
+ * }}}
+ *
+ * @define doubleOrdering Because the behavior of `Double`s specified by IEEE is
+ * not consistent with a total ordering when dealing with
+ * `NaN`, there are two orderings defined for `Double`:
+ * `TotalOrdering`, which is consistent with a total
+ * ordering, and `IeeeOrdering`, which is consistent
+ * as much as possible with IEEE spec and floating point
+ * operations defined in [[scala.math]].
+ */
+ object Double {
+ /** An ordering for `Double`s which is a fully consistent total ordering,
+ * and treats `NaN` as larger than all other `Double` values; it behaves
+ * the same as [[java.lang.Double.compare]].
+ *
+ * $doubleOrdering
+ *
+ * This ordering may be preferable for sorting collections.
+ *
+ * @see [[IeeeOrdering]]
+ */
+ trait TotalOrdering extends Ordering[Double] {
+ def compare(x: Double, y: Double) = java.lang.Double.compare(x, y)
+ }
+ @SerialVersionUID(-831119229746134011L)
+ implicit object TotalOrdering extends TotalOrdering
+
+ /** An ordering for `Double`s which is consistent with IEEE specifications
+ * whenever possible.
+ *
+ * - `lt`, `lteq`, `equiv`, `gteq` and `gt` are consistent with primitive
+ * comparison operations for `Double`s, and return `false` when called with
+ * `NaN`.
+ * - `min` and `max` are consistent with `math.min` and `math.max`, and
+ * return `NaN` when called with `NaN` as either argument.
+ * - `compare` behaves the same as [[java.lang.Double.compare]].
+ *
+ * $doubleOrdering
+ *
+ * This ordering may be preferable for numeric contexts.
+ *
+ * @see [[TotalOrdering]]
+ */
+ trait IeeeOrdering extends Ordering[Double] {
+ def compare(x: Double, y: Double) = java.lang.Double.compare(x, y)
+
+ override def lteq(x: Double, y: Double): Boolean = x <= y
+ override def gteq(x: Double, y: Double): Boolean = x >= y
+ override def lt(x: Double, y: Double): Boolean = x < y
+ override def gt(x: Double, y: Double): Boolean = x > y
+ override def equiv(x: Double, y: Double): Boolean = x == y
+ override def max[U <: Double](x: U, y: U): U = math.max(x, y).asInstanceOf[U]
+ override def min[U <: Double](x: U, y: U): U = math.min(x, y).asInstanceOf[U]
+ }
+ @SerialVersionUID(5722631152457877238L)
+ implicit object IeeeOrdering extends IeeeOrdering
+ }
+ @migration(
+ " The default implicit ordering for doubles now maintains consistency\n" +
+ " between its `compare` method and its `lt`, `min`, `equiv`, etc., methods,\n" +
+ " which means nonconforming to IEEE 754's behavior for -0.0 and NaN.\n" +
+ " The sort order of doubles remains the same, however, with NaN at the end.\n" +
+ " Import Ordering.Double.IeeeOrdering to recover the previous behavior.\n" +
+ " See also https://www.scala-lang.org/api/current/scala/math/Ordering$$Double$.html.", "2.13.0")
+ @SerialVersionUID(-7340686892557971538L)
+ implicit object DeprecatedDoubleOrdering extends Double.TotalOrdering
+
+ trait BigIntOrdering extends Ordering[BigInt] {
+ def compare(x: BigInt, y: BigInt) = x.compare(y)
+ }
+ @SerialVersionUID(-3075297647817530785L)
+ implicit object BigInt extends BigIntOrdering
+
+ trait BigDecimalOrdering extends Ordering[BigDecimal] {
+ def compare(x: BigDecimal, y: BigDecimal) = x.compare(y)
+ }
+ @SerialVersionUID(-833457937756812905L)
+ implicit object BigDecimal extends BigDecimalOrdering
+
+ trait StringOrdering extends Ordering[String] {
+ def compare(x: String, y: String) = x.compareTo(y)
+ }
+ @SerialVersionUID(1302240016074071079L)
+ implicit object String extends StringOrdering
+
+ trait SymbolOrdering extends Ordering[Symbol] {
+ def compare(x: Symbol, y: Symbol): Int = x.name.compareTo(y.name)
+ }
+ @SerialVersionUID(1996702162912307637L)
+ implicit object Symbol extends SymbolOrdering
+
+ trait OptionOrdering[T] extends Ordering[Option[T]] {
+ def optionOrdering: Ordering[T]
+ def compare(x: Option[T], y: Option[T]) = (x, y) match {
+ case (None, None) => 0
+ case (None, _) => -1
+ case (_, None) => 1
+ case (Some(x), Some(y)) => optionOrdering.compare(x, y)
+ }
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: OptionOrdering[_] => this.optionOrdering == that.optionOrdering
+ case _ => false
+ }
+ override def hashCode(): Int = optionOrdering.hashCode() * optionSeed
+ }
+ implicit def Option[T](implicit ord: Ordering[T]): Ordering[Option[T]] = {
+ @SerialVersionUID(6958068162830323876L)
+ class O extends OptionOrdering[T] { val optionOrdering = ord }
+ new O()
+ }
+
+ /** @deprecated Iterables are not guaranteed to have a consistent order, so the `Ordering`
+ * returned by this method may not be stable or meaningful. If you are using a type
+ * with a consistent order (such as `Seq`), use its `Ordering` (found in the
+ * [[Implicits]] object) instead.
+ */
+ @deprecated("Iterables are not guaranteed to have a consistent order; if using a type with a " +
+ "consistent order (e.g. Seq), use its Ordering (found in the Ordering.Implicits object)", since = "2.13.0")
+ implicit def Iterable[T](implicit ord: Ordering[T]): Ordering[Iterable[T]] =
+ new IterableOrdering[Iterable, T](ord)
+
+ implicit def Tuple2[T1, T2](implicit ord1: Ordering[T1], ord2: Ordering[T2]): Ordering[(T1, T2)] =
+ new Tuple2Ordering(ord1, ord2)
+
+ @SerialVersionUID(4945084135299531202L)
+ private[this] final class Tuple2Ordering[T1, T2](private val ord1: Ordering[T1],
+ private val ord2: Ordering[T2]) extends Ordering[(T1, T2)] {
+ def compare(x: (T1, T2), y: (T1, T2)): Int = {
+ val compare1 = ord1.compare(x._1, y._1)
+ if (compare1 != 0) return compare1
+ ord2.compare(x._2, y._2)
+ }
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple2Ordering[_, _] =>
+ this.ord1 == that.ord1 &&
+ this.ord2 == that.ord2
+ case _ => false
+ }
+ override def hashCode(): Int = (ord1, ord2).hashCode()
+ }
+
+ implicit def Tuple3[T1, T2, T3](implicit ord1: Ordering[T1], ord2: Ordering[T2], ord3: Ordering[T3]) : Ordering[(T1, T2, T3)] =
+ new Tuple3Ordering(ord1, ord2, ord3)
+
+ @SerialVersionUID(-5367223704121832335L)
+ private[this] final class Tuple3Ordering[T1, T2, T3](private val ord1: Ordering[T1],
+ private val ord2: Ordering[T2],
+ private val ord3: Ordering[T3]) extends Ordering[(T1, T2, T3)] {
+ def compare(x: (T1, T2, T3), y: (T1, T2, T3)): Int = {
+ val compare1 = ord1.compare(x._1, y._1)
+ if (compare1 != 0) return compare1
+ val compare2 = ord2.compare(x._2, y._2)
+ if (compare2 != 0) return compare2
+ ord3.compare(x._3, y._3)
+ }
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple3Ordering[_, _, _] =>
+ this.ord1 == that.ord1 &&
+ this.ord2 == that.ord2 &&
+ this.ord3 == that.ord3
+ case _ => false
+ }
+ override def hashCode(): Int = (ord1, ord2, ord3).hashCode()
+ }
+
+ implicit def Tuple4[T1, T2, T3, T4](implicit ord1: Ordering[T1], ord2: Ordering[T2], ord3: Ordering[T3], ord4: Ordering[T4]) : Ordering[(T1, T2, T3, T4)] =
+ new Tuple4Ordering(ord1, ord2, ord3, ord4)
+
+ @SerialVersionUID(-6055313861145218178L)
+ private[this] final class Tuple4Ordering[T1, T2, T3, T4](private val ord1: Ordering[T1],
+ private val ord2: Ordering[T2],
+ private val ord3: Ordering[T3],
+ private val ord4: Ordering[T4])
+ extends Ordering[(T1, T2, T3, T4)] {
+ def compare(x: (T1, T2, T3, T4), y: (T1, T2, T3, T4)): Int = {
+ val compare1 = ord1.compare(x._1, y._1)
+ if (compare1 != 0) return compare1
+ val compare2 = ord2.compare(x._2, y._2)
+ if (compare2 != 0) return compare2
+ val compare3 = ord3.compare(x._3, y._3)
+ if (compare3 != 0) return compare3
+ ord4.compare(x._4, y._4)
+ }
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple4Ordering[_, _, _, _] =>
+ this.ord1 == that.ord1 &&
+ this.ord2 == that.ord2 &&
+ this.ord3 == that.ord3 &&
+ this.ord4 == that.ord4
+ case _ => false
+ }
+ override def hashCode(): Int = (ord1, ord2, ord3, ord4).hashCode()
+ }
+
+ implicit def Tuple5[T1, T2, T3, T4, T5](implicit ord1: Ordering[T1], ord2: Ordering[T2], ord3: Ordering[T3], ord4: Ordering[T4], ord5: Ordering[T5]): Ordering[(T1, T2, T3, T4, T5)] =
+ new Tuple5Ordering(ord1, ord2, ord3, ord4, ord5)
+
+ @SerialVersionUID(-5517329921227646061L)
+ private[this] final class Tuple5Ordering[T1, T2, T3, T4, T5](private val ord1: Ordering[T1],
+ private val ord2: Ordering[T2],
+ private val ord3: Ordering[T3],
+ private val ord4: Ordering[T4],
+ private val ord5: Ordering[T5])
+ extends Ordering[(T1, T2, T3, T4, T5)] {
+ def compare(x: (T1, T2, T3, T4, T5), y: (T1, T2, T3, T4, T5)): Int = {
+ val compare1 = ord1.compare(x._1, y._1)
+ if (compare1 != 0) return compare1
+ val compare2 = ord2.compare(x._2, y._2)
+ if (compare2 != 0) return compare2
+ val compare3 = ord3.compare(x._3, y._3)
+ if (compare3 != 0) return compare3
+ val compare4 = ord4.compare(x._4, y._4)
+ if (compare4 != 0) return compare4
+ ord5.compare(x._5, y._5)
+ }
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple5Ordering[_, _, _, _, _] =>
+ this.ord1 == that.ord1 &&
+ this.ord2 == that.ord2 &&
+ this.ord3 == that.ord3 &&
+ this.ord4 == that.ord4 &&
+ this.ord5 == that.ord5
+ case _ => false
+ }
+ override def hashCode(): Int = (ord1, ord2, ord3, ord4, ord5).hashCode()
+ }
+
+ @SerialVersionUID(3045467524192969060L)
+ implicit def Tuple6[T1, T2, T3, T4, T5, T6](implicit ord1: Ordering[T1], ord2: Ordering[T2], ord3: Ordering[T3], ord4: Ordering[T4], ord5: Ordering[T5], ord6: Ordering[T6]): Ordering[(T1, T2, T3, T4, T5, T6)] =
+ new Tuple6Ordering(ord1, ord2, ord3, ord4, ord5, ord6)
+
+ private[this] final class Tuple6Ordering[T1, T2, T3, T4, T5, T6](private val ord1: Ordering[T1],
+ private val ord2: Ordering[T2],
+ private val ord3: Ordering[T3],
+ private val ord4: Ordering[T4],
+ private val ord5: Ordering[T5],
+ private val ord6: Ordering[T6])
+ extends Ordering[(T1, T2, T3, T4, T5, T6)] {
+ def compare(x: (T1, T2, T3, T4, T5, T6), y: (T1, T2, T3, T4, T5, T6)): Int = {
+ val compare1 = ord1.compare(x._1, y._1)
+ if (compare1 != 0) return compare1
+ val compare2 = ord2.compare(x._2, y._2)
+ if (compare2 != 0) return compare2
+ val compare3 = ord3.compare(x._3, y._3)
+ if (compare3 != 0) return compare3
+ val compare4 = ord4.compare(x._4, y._4)
+ if (compare4 != 0) return compare4
+ val compare5 = ord5.compare(x._5, y._5)
+ if (compare5 != 0) return compare5
+ ord6.compare(x._6, y._6)
+ }
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple6Ordering[_, _, _, _, _, _] =>
+ this.ord1 == that.ord1 &&
+ this.ord2 == that.ord2 &&
+ this.ord3 == that.ord3 &&
+ this.ord4 == that.ord4 &&
+ this.ord5 == that.ord5 &&
+ this.ord6 == that.ord6
+ case _ => false
+ }
+ override def hashCode(): Int = (ord1, ord2, ord3, ord4, ord5, ord6).hashCode()
+ }
+
+ implicit def Tuple7[T1, T2, T3, T4, T5, T6, T7](implicit ord1: Ordering[T1], ord2: Ordering[T2], ord3: Ordering[T3], ord4: Ordering[T4], ord5: Ordering[T5], ord6: Ordering[T6], ord7: Ordering[T7]): Ordering[(T1, T2, T3, T4, T5, T6, T7)] =
+ new Tuple7Ordering(ord1, ord2, ord3, ord4, ord5, ord6, ord7)
+
+ @SerialVersionUID(1253188205893682451L)
+ private[this] final class Tuple7Ordering[T1, T2, T3, T4, T5, T6, T7](private val ord1: Ordering[T1],
+ private val ord2: Ordering[T2],
+ private val ord3: Ordering[T3],
+ private val ord4: Ordering[T4],
+ private val ord5: Ordering[T5],
+ private val ord6: Ordering[T6],
+ private val ord7: Ordering[T7])
+ extends Ordering[(T1, T2, T3, T4, T5, T6, T7)] {
+ def compare(x: (T1, T2, T3, T4, T5, T6, T7), y: (T1, T2, T3, T4, T5, T6, T7)): Int = {
+ val compare1 = ord1.compare(x._1, y._1)
+ if (compare1 != 0) return compare1
+ val compare2 = ord2.compare(x._2, y._2)
+ if (compare2 != 0) return compare2
+ val compare3 = ord3.compare(x._3, y._3)
+ if (compare3 != 0) return compare3
+ val compare4 = ord4.compare(x._4, y._4)
+ if (compare4 != 0) return compare4
+ val compare5 = ord5.compare(x._5, y._5)
+ if (compare5 != 0) return compare5
+ val compare6 = ord6.compare(x._6, y._6)
+ if (compare6 != 0) return compare6
+ ord7.compare(x._7, y._7)
+ }
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple7Ordering[_, _, _, _, _, _, _] =>
+ this.ord1 == that.ord1 &&
+ this.ord2 == that.ord2 &&
+ this.ord3 == that.ord3 &&
+ this.ord4 == that.ord4 &&
+ this.ord5 == that.ord5 &&
+ this.ord6 == that.ord6 &&
+ this.ord7 == that.ord7
+ case _ => false
+ }
+ override def hashCode(): Int = (ord1, ord2, ord3, ord4, ord5, ord6, ord7).hashCode()
+ }
+
+ @SerialVersionUID(4003095353309354068L)
+ implicit def Tuple8[T1, T2, T3, T4, T5, T6, T7, T8](implicit ord1: Ordering[T1], ord2: Ordering[T2], ord3: Ordering[T3], ord4: Ordering[T4], ord5: Ordering[T5], ord6: Ordering[T6], ord7: Ordering[T7], ord8: Ordering[T8]): Ordering[(T1, T2, T3, T4, T5, T6, T7, T8)] =
+ new Tuple8Ordering(ord1, ord2, ord3, ord4, ord5, ord6, ord7, ord8)
+
+ private[this] final class Tuple8Ordering[T1, T2, T3, T4, T5, T6, T7, T8](private val ord1: Ordering[T1],
+ private val ord2: Ordering[T2],
+ private val ord3: Ordering[T3],
+ private val ord4: Ordering[T4],
+ private val ord5: Ordering[T5],
+ private val ord6: Ordering[T6],
+ private val ord7: Ordering[T7],
+ private val ord8: Ordering[T8])
+ extends Ordering[(T1, T2, T3, T4, T5, T6, T7, T8)] {
+ def compare(x: (T1, T2, T3, T4, T5, T6, T7, T8), y: (T1, T2, T3, T4, T5, T6, T7, T8)): Int = {
+ val compare1 = ord1.compare(x._1, y._1)
+ if (compare1 != 0) return compare1
+ val compare2 = ord2.compare(x._2, y._2)
+ if (compare2 != 0) return compare2
+ val compare3 = ord3.compare(x._3, y._3)
+ if (compare3 != 0) return compare3
+ val compare4 = ord4.compare(x._4, y._4)
+ if (compare4 != 0) return compare4
+ val compare5 = ord5.compare(x._5, y._5)
+ if (compare5 != 0) return compare5
+ val compare6 = ord6.compare(x._6, y._6)
+ if (compare6 != 0) return compare6
+ val compare7 = ord7.compare(x._7, y._7)
+ if (compare7 != 0) return compare7
+ ord8.compare(x._8, y._8)
+ }
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple8Ordering[_, _, _, _, _, _, _, _] =>
+ this.ord1 == that.ord1 &&
+ this.ord2 == that.ord2 &&
+ this.ord3 == that.ord3 &&
+ this.ord4 == that.ord4 &&
+ this.ord5 == that.ord5 &&
+ this.ord6 == that.ord6 &&
+ this.ord7 == that.ord7 &&
+ this.ord8 == that.ord8
+ case _ => false
+ }
+ override def hashCode(): Int = (ord1, ord2, ord3, ord4, ord5, ord6, ord7, ord8).hashCode()
+ }
+
+ @SerialVersionUID(8185342054829975001L)
+ implicit def Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9](implicit ord1: Ordering[T1], ord2: Ordering[T2], ord3: Ordering[T3], ord4: Ordering[T4], ord5: Ordering[T5], ord6: Ordering[T6], ord7: Ordering[T7], ord8 : Ordering[T8], ord9: Ordering[T9]): Ordering[(T1, T2, T3, T4, T5, T6, T7, T8, T9)] =
+ new Tuple9Ordering(ord1, ord2, ord3, ord4, ord5, ord6, ord7, ord8, ord9)
+
+ private[this] final class Tuple9Ordering[T1, T2, T3, T4, T5, T6, T7, T8, T9](private val ord1: Ordering[T1],
+ private val ord2: Ordering[T2],
+ private val ord3: Ordering[T3],
+ private val ord4: Ordering[T4],
+ private val ord5: Ordering[T5],
+ private val ord6: Ordering[T6],
+ private val ord7: Ordering[T7],
+ private val ord8: Ordering[T8],
+ private val ord9: Ordering[T9])
+ extends Ordering[(T1, T2, T3, T4, T5, T6, T7, T8, T9)] {
+ def compare(x: (T1, T2, T3, T4, T5, T6, T7, T8, T9), y: (T1, T2, T3, T4, T5, T6, T7, T8, T9)): Int = {
+ val compare1 = ord1.compare(x._1, y._1)
+ if (compare1 != 0) return compare1
+ val compare2 = ord2.compare(x._2, y._2)
+ if (compare2 != 0) return compare2
+ val compare3 = ord3.compare(x._3, y._3)
+ if (compare3 != 0) return compare3
+ val compare4 = ord4.compare(x._4, y._4)
+ if (compare4 != 0) return compare4
+ val compare5 = ord5.compare(x._5, y._5)
+ if (compare5 != 0) return compare5
+ val compare6 = ord6.compare(x._6, y._6)
+ if (compare6 != 0) return compare6
+ val compare7 = ord7.compare(x._7, y._7)
+ if (compare7 != 0) return compare7
+ val compare8 = ord8.compare(x._8, y._8)
+ if (compare8 != 0) return compare8
+ ord9.compare(x._9, y._9)
+ }
+
+ override def equals(obj: scala.Any): Boolean = obj match {
+ case that: AnyRef if this eq that => true
+ case that: Tuple9Ordering[_, _, _, _, _, _, _, _, _] =>
+ this.ord1 == that.ord1 &&
+ this.ord2 == that.ord2 &&
+ this.ord3 == that.ord3 &&
+ this.ord4 == that.ord4 &&
+ this.ord5 == that.ord5 &&
+ this.ord6 == that.ord6 &&
+ this.ord7 == that.ord7 &&
+ this.ord8 == that.ord8 &&
+ this.ord9 == that.ord9
+ case _ => false
+ }
+ override def hashCode(): Int = (ord1, ord2, ord3, ord4, ord5, ord6, ord7, ord8, ord9).hashCode()
+ }
+}
diff --git a/library/src/scala/math/PartialOrdering.scala b/library/src/scala/math/PartialOrdering.scala
new file mode 100644
index 000000000000..e8ea9d355344
--- /dev/null
+++ b/library/src/scala/math/PartialOrdering.scala
@@ -0,0 +1,88 @@
+/*
+ * 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 math
+
+/** A trait for representing partial orderings. It is important to
+ * distinguish between a type that has a partial order and a representation
+ * of partial ordering on some type. This trait is for representing the
+ * latter.
+ *
+ * A [[https://en.wikipedia.org/wiki/Partially_ordered_set partial ordering]] is a
+ * binary relation on a type `T`, exposed as the `lteq` method of this trait.
+ * This relation must be:
+ *
+ * - reflexive: `lteq(x, x) == '''true'''`, for any `x` of type `T`.
+ * - anti-symmetric: if `lteq(x, y) == '''true'''` and
+ * `lteq(y, x) == '''true'''`
+ * then `equiv(x, y) == '''true'''`, for any `x` and `y` of type `T`.
+ * - transitive: if `lteq(x, y) == '''true'''` and
+ * `lteq(y, z) == '''true'''` then `lteq(x, z) == '''true'''`,
+ * for any `x`, `y`, and `z` of type `T`.
+ *
+ * Additionally, a partial ordering induces an
+ * [[https://en.wikipedia.org/wiki/Equivalence_relation equivalence relation]]
+ * on a type `T`: `x` and `y` of type `T` are equivalent if and only if
+ * `lteq(x, y) && lteq(y, x) == '''true'''`. This equivalence relation is
+ * exposed as the `equiv` method, inherited from the
+ * [[scala.math.Equiv Equiv]] trait.
+ */
+
+trait PartialOrdering[T] extends Equiv[T] {
+ outer =>
+
+ /** Result of comparing `x` with operand `y`.
+ * Returns `None` if operands are not comparable.
+ * If operands are comparable, returns `Some(r)` where
+ * - `r < 0` iff `x < y`
+ * - `r == 0` iff `x == y`
+ * - `r > 0` iff `x > y`
+ */
+ def tryCompare(x: T, y: T): Option[Int]
+
+ /** Returns `'''true'''` iff `x` comes before `y` in the ordering.
+ */
+ def lteq(x: T, y: T): Boolean
+
+ /** Returns `'''true'''` iff `y` comes before `x` in the ordering.
+ */
+ def gteq(x: T, y: T): Boolean = lteq(y, x)
+
+ /** Returns `'''true'''` iff `x` comes before `y` in the ordering
+ * and is not the same as `y`.
+ */
+ def lt(x: T, y: T): Boolean = lteq(x, y) && !equiv(x, y)
+
+ /** Returns `'''true'''` iff `y` comes before `x` in the ordering
+ * and is not the same as `x`.
+ */
+ def gt(x: T, y: T): Boolean = gteq(x, y) && !equiv(x, y)
+
+ /** Returns `'''true'''` iff `x` is equivalent to `y` in the ordering.
+ */
+ def equiv(x: T, y: T): Boolean = lteq(x,y) && lteq(y,x)
+
+ def reverse : PartialOrdering[T] = new PartialOrdering[T] {
+ override def reverse = outer
+ def tryCompare(x: T, y: T) = outer.tryCompare(y, x)
+ def lteq(x: T, y: T) = outer.lteq(y, x)
+ override def gteq(x: T, y: T) = outer.gteq(y, x)
+ override def lt(x: T, y: T) = outer.lt(y, x)
+ override def gt(x: T, y: T) = outer.gt(y, x)
+ override def equiv(x: T, y: T) = outer.equiv(y, x)
+ }
+}
+
+object PartialOrdering {
+ @inline def apply[T](implicit ev: PartialOrdering[T]): PartialOrdering[T] = ev
+}
diff --git a/library/src/scala/math/PartiallyOrdered.scala b/library/src/scala/math/PartiallyOrdered.scala
new file mode 100644
index 000000000000..b955879ae0f1
--- /dev/null
+++ b/library/src/scala/math/PartiallyOrdered.scala
@@ -0,0 +1,54 @@
+/*
+ * 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 math
+
+/** A class for partially ordered data.
+ */
+trait PartiallyOrdered[+A] extends Any {
+
+ type AsPartiallyOrdered[B] = B => PartiallyOrdered[B]
+
+ /** Result of comparing `'''this'''` with operand `that`.
+ * Returns `None` if operands are not comparable.
+ * If operands are comparable, returns `Some(x)` where
+ * - `x < 0` iff `'''this''' < that`
+ * - `x == 0` iff `'''this''' == that`
+ * - `x > 0` iff `'''this''' > that`
+ */
+ def tryCompareTo [B >: A: AsPartiallyOrdered](that: B): Option[Int]
+
+ def < [B >: A: AsPartiallyOrdered](that: B): Boolean =
+ (this tryCompareTo that) match {
+ case Some(x) if x < 0 => true
+ case _ => false
+ }
+
+ def > [B >: A: AsPartiallyOrdered](that: B): Boolean =
+ (this tryCompareTo that) match {
+ case Some(x) if x > 0 => true
+ case _ => false
+ }
+
+ def <= [B >: A: AsPartiallyOrdered](that: B): Boolean =
+ (this tryCompareTo that) match {
+ case Some(x) if x <= 0 => true
+ case _ => false
+ }
+
+ def >= [B >: A: AsPartiallyOrdered](that: B): Boolean =
+ (this tryCompareTo that) match {
+ case Some(x) if x >= 0 => true
+ case _ => false
+ }
+}
diff --git a/library/src/scala/math/ScalaNumber.java b/library/src/scala/math/ScalaNumber.java
new file mode 100644
index 000000000000..5ed76ec3fb22
--- /dev/null
+++ b/library/src/scala/math/ScalaNumber.java
@@ -0,0 +1,20 @@
+/*
+ * 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.math;
+
+/** A marker class for Number types introduced by Scala
+ */
+public abstract class ScalaNumber extends java.lang.Number {
+ protected abstract boolean isWhole();
+ public abstract Object underlying();
+}
diff --git a/library/src/scala/math/ScalaNumericConversions.scala b/library/src/scala/math/ScalaNumericConversions.scala
new file mode 100644
index 000000000000..a3fa90c98c9d
--- /dev/null
+++ b/library/src/scala/math/ScalaNumericConversions.scala
@@ -0,0 +1,122 @@
+/*
+ * 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 math
+
+/** A slightly more specific conversion trait for classes which
+ * extend ScalaNumber (which excludes value classes.)
+ */
+trait ScalaNumericConversions extends ScalaNumber with ScalaNumericAnyConversions {
+ def underlying: Object
+}
+
+/** Conversions which present a consistent conversion interface
+ * across all the numeric types, suitable for use in value classes.
+ */
+trait ScalaNumericAnyConversions extends Any {
+ /** @return `'''true'''` if this number has no decimal component, `'''false'''` otherwise. */
+ def isWhole: Boolean
+
+ def byteValue: Byte
+ def shortValue: Short
+ def intValue: Int
+ def longValue: Long
+ def floatValue: Float
+ def doubleValue: Double
+
+ /** Returns the value of this as a [[scala.Char]]. This may involve
+ * rounding or truncation.
+ */
+ def toChar = intValue.toChar
+
+ /** Returns the value of this as a [[scala.Byte]]. This may involve
+ * rounding or truncation.
+ */
+ def toByte = byteValue
+
+ /** Returns the value of this as a [[scala.Short]]. This may involve
+ * rounding or truncation.
+ */
+ def toShort = shortValue
+
+ /** Returns the value of this as an [[scala.Int]]. This may involve
+ * rounding or truncation.
+ */
+ def toInt = intValue
+
+ /** Returns the value of this as a [[scala.Long]]. This may involve
+ * rounding or truncation.
+ */
+ def toLong = longValue
+
+ /** Returns the value of this as a [[scala.Float]]. This may involve
+ * rounding or truncation.
+ */
+ def toFloat = floatValue
+
+ /** Returns the value of this as a [[scala.Double]]. This may involve
+ * rounding or truncation.
+ */
+ def toDouble = doubleValue
+
+ /** Returns `true` iff this has a zero fractional part, and is within the
+ * range of [[scala.Byte]] MinValue and MaxValue; otherwise returns `false`.
+ */
+ def isValidByte = isWhole && (toInt == toByte)
+
+ /** Returns `true` iff this has a zero fractional part, and is within the
+ * range of [[scala.Short]] MinValue and MaxValue; otherwise returns `false`.
+ */
+ def isValidShort = isWhole && (toInt == toShort)
+
+ /** Returns `true` iff this has a zero fractional part, and is within the
+ * range of [[scala.Int]] MinValue and MaxValue; otherwise returns `false`.
+ */
+ def isValidInt = isWhole && (toLong == toInt)
+
+ /** Returns `true` iff this has a zero fractional part, and is within the
+ * range of [[scala.Char]] MinValue and MaxValue; otherwise returns `false`.
+ */
+ def isValidChar = isWhole && (toInt >= Char.MinValue && toInt <= Char.MaxValue)
+
+ protected def unifiedPrimitiveHashcode = {
+ val lv = toLong
+ if (lv >= Int.MinValue && lv <= Int.MaxValue) lv.toInt
+ else lv.##
+ }
+
+ /** Should only be called after all known non-primitive
+ * types have been excluded. This method won't dispatch
+ * anywhere else after checking against the primitives
+ * to avoid infinite recursion between equals and this on
+ * unknown "Number" variants.
+ *
+ * Additionally, this should only be called if the numeric
+ * type is happy to be converted to Long, Float, and Double.
+ * If for instance a BigInt much larger than the Long range is
+ * sent here, it will claim equality with whatever Long is left
+ * in its lower 64 bits. Or a BigDecimal with more precision
+ * than Double can hold: same thing. There's no way given the
+ * interface available here to prevent this error.
+ */
+ protected def unifiedPrimitiveEquals(x: Any) = x match {
+ case x: Char => isValidChar && (toInt == x.toInt)
+ case x: Byte => isValidByte && (toByte == x)
+ case x: Short => isValidShort && (toShort == x)
+ case x: Int => isValidInt && (toInt == x)
+ case x: Long => toLong == x
+ case x: Float => toFloat == x
+ case x: Double => toDouble == x
+ case _ => false
+ }
+}
diff --git a/library/src/scala/math/package.scala b/library/src/scala/math/package.scala
new file mode 100644
index 000000000000..dbfde894aa0c
--- /dev/null
+++ b/library/src/scala/math/package.scala
@@ -0,0 +1,438 @@
+/*
+ * 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
+
+/** The package object `scala.math` contains methods for performing basic
+ * numeric operations such as elementary exponential, logarithmic, root and
+ * trigonometric functions.
+ *
+ * All methods forward to [[java.lang.Math]] unless otherwise noted.
+ *
+ * @see [[java.lang.Math]]
+ *
+ * @groupname math-const Mathematical Constants
+ * @groupprio math-const 10
+ *
+ * @groupname minmax Minimum and Maximum
+ * @groupdesc minmax Find the min or max of two numbers. Note: [[scala.collection.IterableOnceOps]] has
+ * min and max methods which determine the min or max of a collection.
+ * @groupprio minmax 20
+ *
+ * @groupname rounding Rounding
+ * @groupprio rounding 30
+ *
+ * @groupname scaling Scaling
+ * @groupdesc scaling Scaling with rounding guarantees
+ * @groupprio scaling 40
+ *
+ * @groupname explog Exponential and Logarithmic
+ * @groupprio explog 50
+ *
+ * @groupname trig Trigonometric
+ * @groupdesc trig Arguments in radians
+ * @groupprio trig 60
+ *
+ * @groupname angle-conversion Angular Measurement Conversion
+ * @groupprio angle-conversion 70
+ *
+ * @groupname hyperbolic Hyperbolic
+ * @groupprio hyperbolic 80
+ *
+ * @groupname abs Absolute Values
+ * @groupdesc abs Determine the magnitude of a value by discarding the sign. Results are >= 0.
+ * @groupprio abs 90
+ *
+ * @groupname signs Signs
+ * @groupdesc signs For `signum` extract the sign of a value. Results are -1, 0 or 1.
+ * Note the `signum` methods are not pure forwarders to the Java versions.
+ * In particular, the return type of `java.lang.Long.signum` is `Int`,
+ * but here it is widened to `Long` so that each overloaded variant
+ * will return the same numeric type it is passed.
+ * @groupprio signs 100
+ *
+ * @groupname root-extraction Root Extraction
+ * @groupprio root-extraction 110
+ *
+ * @groupname polar-coords Polar Coordinates
+ * @groupprio polar-coords 120
+ *
+ * @groupname ulp Unit of Least Precision
+ * @groupprio ulp 130
+ *
+ * @groupname randomisation Pseudo Random Number Generation
+ * @groupprio randomisation 140
+ *
+ * @groupname exact Exact Arithmetic
+ * @groupdesc exact Integral addition, multiplication, stepping and conversion throwing ArithmeticException instead of underflowing or overflowing
+ * @groupprio exact 150
+ *
+ * @groupname modquo Modulus and Quotient
+ * @groupdesc modquo Calculate quotient values by rounding to negative infinity
+ * @groupprio modquo 160
+ *
+ * @groupname adjacent-float Adjacent Floats
+ * @groupprio adjacent-float 170
+ */
+package object math {
+ /** The `Double` value that is closer than any other to `e`, the base of
+ * the natural logarithms.
+ * @group math-const
+ */
+ @inline final val E = java.lang.Math.E
+
+ /** The `Double` value that is closer than any other to `pi`, the ratio of
+ * the circumference of a circle to its diameter.
+ * @group math-const
+ */
+ @inline final val Pi = java.lang.Math.PI
+
+ /** Returns a `Double` value with a positive sign, greater than or equal
+ * to `0.0` and less than `1.0`.
+ *
+ * @group randomisation
+ */
+ def random(): Double = java.lang.Math.random()
+
+ /** @group trig */
+ def sin(x: Double): Double = java.lang.Math.sin(x)
+ /** @group trig */
+ def cos(x: Double): Double = java.lang.Math.cos(x)
+ /** @group trig */
+ def tan(x: Double): Double = java.lang.Math.tan(x)
+ /** @group trig */
+ def asin(x: Double): Double = java.lang.Math.asin(x)
+ /** @group trig */
+ def acos(x: Double): Double = java.lang.Math.acos(x)
+ /** @group trig */
+ def atan(x: Double): Double = java.lang.Math.atan(x)
+
+ /** Converts an angle measured in degrees to an approximately equivalent
+ * angle measured in radians.
+ *
+ * @param x an angle, in degrees
+ * @return the measurement of the angle `x` in radians.
+ * @group angle-conversion
+ */
+ def toRadians(x: Double): Double = java.lang.Math.toRadians(x)
+
+ /** Converts an angle measured in radians to an approximately equivalent
+ * angle measured in degrees.
+ *
+ * @param x angle, in radians
+ * @return the measurement of the angle `x` in degrees.
+ * @group angle-conversion
+ */
+ def toDegrees(x: Double): Double = java.lang.Math.toDegrees(x)
+
+ /** Converts rectangular coordinates `(x, y)` to polar `(r, theta)`.
+ *
+ * @param x the ordinate coordinate
+ * @param y the abscissa coordinate
+ * @return the ''theta'' component of the point `(r, theta)` in polar
+ * coordinates that corresponds to the point `(x, y)` in
+ * Cartesian coordinates.
+ * @group polar-coords
+ */
+ def atan2(y: Double, x: Double): Double = java.lang.Math.atan2(y, x)
+
+ /** Returns the square root of the sum of the squares of both given `Double`
+ * values without intermediate underflow or overflow.
+ *
+ * The ''r'' component of the point `(r, theta)` in polar
+ * coordinates that corresponds to the point `(x, y)` in
+ * Cartesian coordinates.
+ * @group polar-coords
+ */
+ def hypot(x: Double, y: Double): Double = java.lang.Math.hypot(x, y)
+
+ // -----------------------------------------------------------------------
+ // rounding functions
+ // -----------------------------------------------------------------------
+
+ /** @group rounding */
+ def ceil(x: Double): Double = java.lang.Math.ceil(x)
+ /** @group rounding */
+ def floor(x: Double): Double = java.lang.Math.floor(x)
+
+ /** Returns the `Double` value that is closest in value to the
+ * argument and is equal to a mathematical integer.
+ *
+ * @param x a `Double` value
+ * @return the closest floating-point value to a that is equal to a
+ * mathematical integer.
+ * @group rounding
+ */
+ def rint(x: Double): Double = java.lang.Math.rint(x)
+
+ /** There is no reason to round a `Long`, but this method prevents unintended conversion to `Float` followed by rounding to `Int`.
+ *
+ * @note Does not forward to [[java.lang.Math]]
+ * @group rounding
+ */
+ @deprecated("This is an integer type; there is no reason to round it. Perhaps you meant to call this with a floating-point value?", "2.11.0")
+ def round(x: Long): Long = x
+
+ /** Returns the closest `Int` to the argument.
+ *
+ * @param x a floating-point value to be rounded to a `Int`.
+ * @return the value of the argument rounded to the nearest `Int` value.
+ * @group rounding
+ */
+ def round(x: Float): Int = java.lang.Math.round(x)
+
+ /** Returns the closest `Long` to the argument.
+ *
+ * @param x a floating-point value to be rounded to a `Long`.
+ * @return the value of the argument rounded to the nearest`long` value.
+ * @group rounding
+ */
+ def round(x: Double): Long = java.lang.Math.round(x)
+
+ /** @group abs */
+ def abs(x: Int): Int = java.lang.Math.abs(x)
+ /** @group abs */
+ def abs(x: Long): Long = java.lang.Math.abs(x)
+ /** @group abs */
+ def abs(x: Float): Float = java.lang.Math.abs(x)
+ /** @group abs */
+ def abs(x: Double): Double = java.lang.Math.abs(x)
+
+ /** @group minmax */
+ def max(x: Int, y: Int): Int = java.lang.Math.max(x, y)
+ /** @group minmax */
+ def max(x: Long, y: Long): Long = java.lang.Math.max(x, y)
+ /** @group minmax */
+ def max(x: Float, y: Float): Float = java.lang.Math.max(x, y)
+ /** @group minmax */
+ def max(x: Double, y: Double): Double = java.lang.Math.max(x, y)
+
+ /** @group minmax */
+ def min(x: Int, y: Int): Int = java.lang.Math.min(x, y)
+ /** @group minmax */
+ def min(x: Long, y: Long): Long = java.lang.Math.min(x, y)
+ /** @group minmax */
+ def min(x: Float, y: Float): Float = java.lang.Math.min(x, y)
+ /** @group minmax */
+ def min(x: Double, y: Double): Double = java.lang.Math.min(x, y)
+
+ /** @group signs
+ * @note Forwards to [[java.lang.Integer]]
+ */
+ def signum(x: Int): Int = java.lang.Integer.signum(x)
+ /** @group signs
+ * @note Forwards to [[java.lang.Long]]
+ */
+ def signum(x: Long): Long = java.lang.Long.signum(x)
+ /** @group signs */
+ def signum(x: Float): Float = java.lang.Math.signum(x)
+ /** @group signs */
+ def signum(x: Double): Double = java.lang.Math.signum(x)
+
+ /** @group modquo */
+ def floorDiv(x: Int, y: Int): Int = java.lang.Math.floorDiv(x, y)
+
+ /** @group modquo */
+ def floorDiv(x: Long, y: Long): Long = java.lang.Math.floorDiv(x, y)
+
+ /** @group modquo */
+ def floorMod(x: Int, y: Int): Int = java.lang.Math.floorMod(x, y)
+
+ /** @group modquo */
+ def floorMod(x: Long, y: Long): Long = java.lang.Math.floorMod(x, y)
+
+ /** @group signs */
+ def copySign(magnitude: Double, sign: Double): Double = java.lang.Math.copySign(magnitude, sign)
+
+ /** @group signs */
+ def copySign(magnitude: Float, sign: Float): Float = java.lang.Math.copySign(magnitude, sign)
+
+ /** @group adjacent-float */
+ def nextAfter(start: Double, direction: Double): Double = java.lang.Math.nextAfter(start, direction)
+
+ /** @group adjacent-float */
+ def nextAfter(start: Float, direction: Double): Float = java.lang.Math.nextAfter(start, direction)
+
+ /** @group adjacent-float */
+ def nextUp(d: Double): Double = java.lang.Math.nextUp(d)
+
+ /** @group adjacent-float */
+ def nextUp(f: Float): Float = java.lang.Math.nextUp(f)
+
+ /** @group adjacent-float */
+ def nextDown(d: Double): Double = java.lang.Math.nextDown(d)
+
+ /** @group adjacent-float */
+ def nextDown(f: Float): Float = java.lang.Math.nextDown(f)
+
+ /** @group scaling */
+ def scalb(d: Double, scaleFactor: Int): Double = java.lang.Math.scalb(d, scaleFactor)
+
+ /** @group scaling */
+ def scalb(f: Float, scaleFactor: Int): Float = java.lang.Math.scalb(f, scaleFactor)
+
+ // -----------------------------------------------------------------------
+ // root functions
+ // -----------------------------------------------------------------------
+
+ /** Returns the square root of a `Double` value.
+ *
+ * @param x the number to take the square root of
+ * @return the value √x
+ * @group root-extraction
+ */
+ def sqrt(x: Double): Double = java.lang.Math.sqrt(x)
+
+ /** Returns the cube root of the given `Double` value.
+ *
+ * @param x the number to take the cube root of
+ * @return the value ∛x
+ * @group root-extraction
+ */
+ def cbrt(x: Double): Double = java.lang.Math.cbrt(x)
+
+ // -----------------------------------------------------------------------
+ // exponential functions
+ // -----------------------------------------------------------------------
+
+ /** Returns the value of the first argument raised to the power of the
+ * second argument.
+ *
+ * @param x the base.
+ * @param y the exponent.
+ * @return the value `x^y^`.
+ * @group explog
+ */
+ def pow(x: Double, y: Double): Double = java.lang.Math.pow(x, y)
+
+ /** Returns Euler's number `e` raised to the power of a `Double` value.
+ *
+ * @param x the exponent to raise `e` to.
+ * @return the value `e^a^`, where `e` is the base of the natural
+ * logarithms.
+ * @group explog
+ */
+ def exp(x: Double): Double = java.lang.Math.exp(x)
+
+ /** Returns `exp(x) - 1`.
+ * @group explog
+ */
+ def expm1(x: Double): Double = java.lang.Math.expm1(x)
+
+ /** @group explog */
+ def getExponent(f: Float): Int = java.lang.Math.getExponent(f)
+
+ /** @group explog */
+ def getExponent(d: Double): Int = java.lang.Math.getExponent(d)
+
+ // -----------------------------------------------------------------------
+ // logarithmic functions
+ // -----------------------------------------------------------------------
+
+ /** Returns the natural logarithm of a `Double` value.
+ *
+ * @param x the number to take the natural logarithm of
+ * @return the value `logₑ(x)` where `e` is Eulers number
+ * @group explog
+ */
+ def log(x: Double): Double = java.lang.Math.log(x)
+
+ /** Returns the natural logarithm of the sum of the given `Double` value and 1.
+ * @group explog
+ */
+ def log1p(x: Double): Double = java.lang.Math.log1p(x)
+
+ /** Returns the base 10 logarithm of the given `Double` value.
+ * @group explog
+ */
+ def log10(x: Double): Double = java.lang.Math.log10(x)
+
+ // -----------------------------------------------------------------------
+ // trigonometric functions
+ // -----------------------------------------------------------------------
+
+ /** Returns the hyperbolic sine of the given `Double` value.
+ * @group hyperbolic
+ */
+ def sinh(x: Double): Double = java.lang.Math.sinh(x)
+
+ /** Returns the hyperbolic cosine of the given `Double` value.
+ * @group hyperbolic
+ */
+ def cosh(x: Double): Double = java.lang.Math.cosh(x)
+
+ /** Returns the hyperbolic tangent of the given `Double` value.
+ * @group hyperbolic
+ */
+ def tanh(x: Double):Double = java.lang.Math.tanh(x)
+
+ // -----------------------------------------------------------------------
+ // miscellaneous functions
+ // -----------------------------------------------------------------------
+
+ /** Returns the size of an ulp of the given `Double` value.
+ * @group ulp
+ */
+ def ulp(x: Double): Double = java.lang.Math.ulp(x)
+
+ /** Returns the size of an ulp of the given `Float` value.
+ * @group ulp
+ */
+ def ulp(x: Float): Float = java.lang.Math.ulp(x)
+
+ /** @group exact */
+ def IEEEremainder(x: Double, y: Double): Double = java.lang.Math.IEEEremainder(x, y)
+
+ // -----------------------------------------------------------------------
+ // exact functions
+ // -----------------------------------------------------------------------
+
+ /** @group exact */
+ def addExact(x: Int, y: Int): Int = java.lang.Math.addExact(x, y)
+
+ /** @group exact */
+ def addExact(x: Long, y: Long): Long = java.lang.Math.addExact(x, y)
+
+ /** @group exact */
+ def subtractExact(x: Int, y: Int): Int = java.lang.Math.subtractExact(x, y)
+
+ /** @group exact */
+ def subtractExact(x: Long, y: Long): Long = java.lang.Math.subtractExact(x, y)
+
+ /** @group exact */
+ def multiplyExact(x: Int, y: Int): Int = java.lang.Math.multiplyExact(x, y)
+
+ /** @group exact */
+ def multiplyExact(x: Long, y: Long): Long = java.lang.Math.multiplyExact(x, y)
+
+ /** @group exact */
+ def incrementExact(x: Int): Int = java.lang.Math.incrementExact(x)
+
+ /** @group exact */
+ def incrementExact(x: Long) = java.lang.Math.incrementExact(x)
+
+ /** @group exact */
+ def decrementExact(x: Int) = java.lang.Math.decrementExact(x)
+
+ /** @group exact */
+ def decrementExact(x: Long) = java.lang.Math.decrementExact(x)
+
+ /** @group exact */
+ def negateExact(x: Int) = java.lang.Math.negateExact(x)
+
+ /** @group exact */
+ def negateExact(x: Long) = java.lang.Math.negateExact(x)
+
+ /** @group exact */
+ def toIntExact(x: Long): Int = java.lang.Math.toIntExact(x)
+
+}
diff --git a/library/src/scala/native.scala b/library/src/scala/native.scala
new file mode 100644
index 000000000000..6a453d1809d1
--- /dev/null
+++ b/library/src/scala/native.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.
+ */
+
+package scala
+
+/** Marker for native methods.
+ *
+ * {{{
+ * @native def f(x: Int, y: List[Long]): String = ...
+ * }}}
+ *
+ * A `@native` method is compiled to the platform's native method,
+ * while discarding the method's body (if any). The body will be type checked if present.
+ *
+ * A method marked @native must be a member of a class, not a trait (since 2.12).
+ */
+@deprecatedInheritance("Scheduled for being final in the future", "2.13.0")
+class native extends scala.annotation.StaticAnnotation {}
diff --git a/library/src/scala/noinline.scala b/library/src/scala/noinline.scala
new file mode 100644
index 000000000000..eede8d5051f2
--- /dev/null
+++ b/library/src/scala/noinline.scala
@@ -0,0 +1,48 @@
+/*
+ * 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
+
+/**
+ * An annotation for methods that the optimizer should not inline.
+ *
+ * Note that by default, the Scala optimizer is disabled and no callsites are inlined. See
+ * `-opt:help` for information how to enable the optimizer and inliner.
+ *
+ * When inlining is enabled, the inliner will never inline methods or callsites annotated
+ * `@noinline`.
+ *
+ * Examples:
+ *
+ * {{{
+ * @inline final def f1(x: Int) = x
+ * @noinline final def f2(x: Int) = x
+ * final def f3(x: Int) = x
+ *
+ * def t1 = f1(1) // inlined if possible
+ * def t2 = f2(1) // not inlined
+ * def t3 = f3(1) // may be inlined (the inliner heuristics can select the callsite)
+ * def t4 = f1(1): @noinline // not inlined (override at callsite)
+ * def t5 = f2(1): @inline // inlined if possible (override at callsite)
+ * def t6 = f3(1): @inline // inlined if possible
+ * def t7 = f3(1): @noinline // not inlined
+ * }
+ * }}}
+ *
+ * Note: parentheses are required when annotating a callsite within a larger expression.
+ *
+ * {{{
+ * def t1 = f1(1) + f1(1): @noinline // equivalent to (f1(1) + f1(1)): @noinline
+ * def t2 = f1(1) + (f1(1): @noinline) // the second call to f1 is not inlined
+ * }}}
+ */
+final class noinline extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/package.scala b/library/src/scala/package.scala
new file mode 100644
index 000000000000..f84dcfd85a73
--- /dev/null
+++ b/library/src/scala/package.scala
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ */
+
+import scala.annotation.migration
+
+/**
+ * Core Scala types. They are always available without an explicit import.
+ * @contentDiagram hideNodes "scala.Serializable"
+ */
+package object scala {
+ type Cloneable = java.lang.Cloneable
+ type Serializable = java.io.Serializable
+
+ type Throwable = java.lang.Throwable
+ type Exception = java.lang.Exception
+ type Error = java.lang.Error
+
+ type RuntimeException = java.lang.RuntimeException
+ type NullPointerException = java.lang.NullPointerException
+ type ClassCastException = java.lang.ClassCastException
+ type IndexOutOfBoundsException = java.lang.IndexOutOfBoundsException
+ type ArrayIndexOutOfBoundsException = java.lang.ArrayIndexOutOfBoundsException
+ type StringIndexOutOfBoundsException = java.lang.StringIndexOutOfBoundsException
+ type UnsupportedOperationException = java.lang.UnsupportedOperationException
+ type IllegalArgumentException = java.lang.IllegalArgumentException
+ type NoSuchElementException = java.util.NoSuchElementException
+ type NumberFormatException = java.lang.NumberFormatException
+ type AbstractMethodError = java.lang.AbstractMethodError
+ type InterruptedException = java.lang.InterruptedException
+
+ // A dummy used by the specialization annotation.
+ val AnyRef = new Specializable {
+ override def toString = "object AnyRef"
+ }
+
+ @deprecated("Use IterableOnce instead of TraversableOnce", "2.13.0")
+ type TraversableOnce[+A] = scala.collection.IterableOnce[A]
+
+ type IterableOnce[+A] = scala.collection.IterableOnce[A]
+
+ @deprecated("Use Iterable instead of Traversable", "2.13.0")
+ type Traversable[+A] = scala.collection.Iterable[A]
+ @deprecated("Use Iterable instead of Traversable", "2.13.0")
+ val Traversable = scala.collection.Iterable
+
+ type Iterable[+A] = scala.collection.Iterable[A]
+ val Iterable = scala.collection.Iterable
+
+ @migration("scala.Seq is now scala.collection.immutable.Seq instead of scala.collection.Seq", "2.13.0")
+ type Seq[+A] = scala.collection.immutable.Seq[A]
+ val Seq = scala.collection.immutable.Seq
+
+ @migration("scala.IndexedSeq is now scala.collection.immutable.IndexedSeq instead of scala.collection.IndexedSeq", "2.13.0")
+ type IndexedSeq[+A] = scala.collection.immutable.IndexedSeq[A]
+ val IndexedSeq = scala.collection.immutable.IndexedSeq
+
+ type Iterator[+A] = scala.collection.Iterator[A]
+ val Iterator = scala.collection.Iterator
+
+ @deprecated("Use scala.collection.BufferedIterator instead of scala.BufferedIterator", "2.13.0")
+ type BufferedIterator[+A] = scala.collection.BufferedIterator[A]
+
+ type List[+A] = scala.collection.immutable.List[A]
+ val List = scala.collection.immutable.List
+
+ val Nil = scala.collection.immutable.Nil
+
+ type ::[+A] = scala.collection.immutable.::[A]
+ val :: = scala.collection.immutable.::
+
+ val +: = scala.collection.+:
+ val :+ = scala.collection.:+
+
+ @deprecated("Use LazyList instead of Stream", "2.13.0")
+ type Stream[+A] = scala.collection.immutable.Stream[A]
+ @deprecated("Use LazyList instead of Stream", "2.13.0")
+ val Stream = scala.collection.immutable.Stream
+
+ type LazyList[+A] = scala.collection.immutable.LazyList[A]
+ val LazyList = scala.collection.immutable.LazyList
+ // This should be an alias to LazyList.#:: but we need to support Stream, too
+ //val #:: = scala.collection.immutable.LazyList.#::
+ object #:: {
+ def unapply[A](s: LazyList[A]): Option[(A, LazyList[A])] =
+ if (s.nonEmpty) Some((s.head, s.tail)) else None
+ @deprecated("Prefer LazyList instead", since = "2.13.0")
+ def unapply[A](s: Stream[A]): Option[(A, Stream[A])] =
+ if (s.nonEmpty) Some((s.head, s.tail)) else None
+ }
+
+ type Vector[+A] = scala.collection.immutable.Vector[A]
+ val Vector = scala.collection.immutable.Vector
+
+ type StringBuilder = scala.collection.mutable.StringBuilder
+ val StringBuilder = scala.collection.mutable.StringBuilder
+
+ type Range = scala.collection.immutable.Range
+ val Range = scala.collection.immutable.Range
+
+ // Numeric types which were moved into scala.math.*
+
+ type BigDecimal = scala.math.BigDecimal
+ val BigDecimal = scala.math.BigDecimal
+
+ type BigInt = scala.math.BigInt
+ val BigInt = scala.math.BigInt
+
+ type Equiv[T] = scala.math.Equiv[T]
+ val Equiv = scala.math.Equiv
+
+ type Fractional[T] = scala.math.Fractional[T]
+ val Fractional = scala.math.Fractional
+
+ type Integral[T] = scala.math.Integral[T]
+ val Integral = scala.math.Integral
+
+ type Numeric[T] = scala.math.Numeric[T]
+ val Numeric = scala.math.Numeric
+
+ type Ordered[T] = scala.math.Ordered[T]
+ val Ordered = scala.math.Ordered
+
+ type Ordering[T] = scala.math.Ordering[T]
+ val Ordering = scala.math.Ordering
+
+ type PartialOrdering[T] = scala.math.PartialOrdering[T]
+ type PartiallyOrdered[T] = scala.math.PartiallyOrdered[T]
+
+ type Either[+A, +B] = scala.util.Either[A, B]
+ val Either = scala.util.Either
+
+ type Left[+A, +B] = scala.util.Left[A, B]
+ val Left = scala.util.Left
+
+ type Right[+A, +B] = scala.util.Right[A, B]
+ val Right = scala.util.Right
+
+}
diff --git a/library/src/scala/ref/PhantomReference.scala b/library/src/scala/ref/PhantomReference.scala
new file mode 100644
index 000000000000..0790f539d03d
--- /dev/null
+++ b/library/src/scala/ref/PhantomReference.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.ref
+
+class PhantomReference[+T <: AnyRef](value: T, queue: ReferenceQueue[T]) extends ReferenceWrapper[T] {
+ val underlying: java.lang.ref.PhantomReference[_ <: T] =
+ new PhantomReferenceWithWrapper[T](value, queue, this)
+}
+
+private class PhantomReferenceWithWrapper[T <: AnyRef](value: T, queue: ReferenceQueue[T], val wrapper: PhantomReference[T])
+ extends java.lang.ref.PhantomReference[T](value, queue.underlying.asInstanceOf[java.lang.ref.ReferenceQueue[T]]) with ReferenceWithWrapper[T]
diff --git a/library/src/scala/ref/Reference.scala b/library/src/scala/ref/Reference.scala
new file mode 100644
index 000000000000..02e673fa4184
--- /dev/null
+++ b/library/src/scala/ref/Reference.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.
+ */
+
+package scala.ref
+
+/**
+ * @see `java.lang.ref.Reference`
+ */
+trait Reference[+T <: AnyRef] extends Function0[T] {
+ /** return the underlying value */
+ def apply(): T
+ /** return `Some` underlying if it hasn't been collected, otherwise `None` */
+ def get: Option[T]
+ override def toString: String = get.map(_.toString).getOrElse("")
+ def clear(): Unit
+ def enqueue(): Boolean
+ def isEnqueued: Boolean
+}
diff --git a/library/src/scala/ref/ReferenceQueue.scala b/library/src/scala/ref/ReferenceQueue.scala
new file mode 100644
index 000000000000..70743708c732
--- /dev/null
+++ b/library/src/scala/ref/ReferenceQueue.scala
@@ -0,0 +1,30 @@
+/*
+ * 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.ref
+
+class ReferenceQueue[+T <: AnyRef] {
+
+ private[ref] val underlying: java.lang.ref.ReferenceQueue[_ <: T] = new java.lang.ref.ReferenceQueue[T]
+ override def toString: String = underlying.toString
+
+ protected def Wrapper(jref: java.lang.ref.Reference[_]): Option[Reference[T]] =
+ jref match {
+ case null => None
+ case ref => Some(ref.asInstanceOf[ReferenceWithWrapper[T]].wrapper)
+ }
+
+ def poll: Option[Reference[T]] = Wrapper(underlying.poll)
+ def remove: Option[Reference[T]] = Wrapper(underlying.remove)
+ def remove(timeout: Long): Option[Reference[T]] = Wrapper(underlying.remove(timeout))
+
+}
diff --git a/library/src/scala/ref/ReferenceWrapper.scala b/library/src/scala/ref/ReferenceWrapper.scala
new file mode 100644
index 000000000000..4e681ed18570
--- /dev/null
+++ b/library/src/scala/ref/ReferenceWrapper.scala
@@ -0,0 +1,34 @@
+/*
+ * 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.ref
+
+import scala.annotation.nowarn
+
+@nowarn("cat=deprecation")
+trait ReferenceWrapper[+T <: AnyRef] extends Reference[T] with Proxy {
+ val underlying: java.lang.ref.Reference[_ <: T]
+ override def get = Option(underlying.get)
+ def apply() = {
+ val ret = underlying.get
+ if (ret eq null) throw new NoSuchElementException
+ ret
+ }
+ def clear(): Unit = underlying.clear()
+ def enqueue(): Boolean = underlying.enqueue()
+ def isEnqueued: Boolean = underlying.isEnqueued
+ def self: java.lang.ref.Reference[_ <: T] = underlying
+}
+
+private trait ReferenceWithWrapper[T <: AnyRef] {
+ val wrapper: ReferenceWrapper[T]
+}
diff --git a/library/src/scala/ref/SoftReference.scala b/library/src/scala/ref/SoftReference.scala
new file mode 100644
index 000000000000..859eef5e7fef
--- /dev/null
+++ b/library/src/scala/ref/SoftReference.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.
+ */
+
+package scala.ref
+
+class SoftReference[+T <: AnyRef](value : T, queue : ReferenceQueue[T]) extends ReferenceWrapper[T] {
+ def this(value : T) = this(value, null)
+
+ val underlying: java.lang.ref.SoftReference[_ <: T] =
+ new SoftReferenceWithWrapper[T](value, queue, this)
+}
+
+/**
+ * A companion object that implements an extractor for `SoftReference` values
+ */
+object SoftReference {
+
+ /** Creates a `SoftReference` pointing to `value` */
+ def apply[T <: AnyRef](value: T): SoftReference[T] = new SoftReference(value)
+
+ /** Optionally returns the referenced value, or `None` if that value no longer exists */
+ def unapply[T <: AnyRef](sr: SoftReference[T]): Option[T] = Option(sr.underlying.get)
+}
+
+private class SoftReferenceWithWrapper[T <: AnyRef](value: T, queue: ReferenceQueue[T], val wrapper: SoftReference[T])
+ extends java.lang.ref.SoftReference[T](value, if (queue == null) null else queue.underlying.asInstanceOf[java.lang.ref.ReferenceQueue[T]]) with ReferenceWithWrapper[T]
diff --git a/library/src/scala/ref/WeakReference.scala b/library/src/scala/ref/WeakReference.scala
new file mode 100644
index 000000000000..5ca06063590b
--- /dev/null
+++ b/library/src/scala/ref/WeakReference.scala
@@ -0,0 +1,37 @@
+/*
+ * 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.ref
+
+/**
+ * A wrapper class for java.lang.ref.WeakReference
+ * The new functionality is (1) results are Option values, instead of using null.
+ * (2) There is an extractor that maps the weak reference itself into an option.
+ */
+class WeakReference[+T <: AnyRef](value: T, queue: ReferenceQueue[T]) extends ReferenceWrapper[T] {
+ def this(value: T) = this(value, null)
+ val underlying: java.lang.ref.WeakReference[_ <: T] =
+ new WeakReferenceWithWrapper[T](value, queue, this)
+}
+
+/** An extractor for weak reference values */
+object WeakReference {
+
+ /** Creates a weak reference pointing to `value` */
+ def apply[T <: AnyRef](value: T): WeakReference[T] = new WeakReference(value)
+
+ /** Optionally returns the referenced value, or `None` if that value no longer exists */
+ def unapply[T <: AnyRef](wr: WeakReference[T]): Option[T] = Option(wr.underlying.get)
+}
+
+private class WeakReferenceWithWrapper[T <: AnyRef](value: T, queue: ReferenceQueue[T], val wrapper: WeakReference[T])
+ extends java.lang.ref.WeakReference[T](value, if (queue == null) null else queue.underlying.asInstanceOf[java.lang.ref.ReferenceQueue[T]]) with ReferenceWithWrapper[T]
diff --git a/library/src/scala/reflect/ClassManifestDeprecatedApis.scala b/library/src/scala/reflect/ClassManifestDeprecatedApis.scala
new file mode 100644
index 000000000000..cc8d0a457c2a
--- /dev/null
+++ b/library/src/scala/reflect/ClassManifestDeprecatedApis.scala
@@ -0,0 +1,248 @@
+/*
+ * 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 reflect
+
+import scala.collection.mutable.{ArrayBuilder, ArraySeq}
+import java.lang.{Class => jClass}
+
+import scala.annotation.{nowarn, tailrec}
+
+@deprecated("use scala.reflect.ClassTag instead", "2.10.0")
+trait ClassManifestDeprecatedApis[T] extends OptManifest[T] {
+ self: ClassManifest[T] =>
+
+ // Still in use in target test.junit.comp.
+ @deprecated("use runtimeClass instead", "2.10.0")
+ def erasure: jClass[_] = runtimeClass
+
+ private def subtype(sub: jClass[_], sup: jClass[_]): Boolean = {
+ @tailrec
+ def loop(left: Set[jClass[_]], seen: Set[jClass[_]]): Boolean = {
+ left.nonEmpty && {
+ val next = left.head
+ val supers = next.getInterfaces.toSet ++ Option(next.getSuperclass)
+ supers(sup) || {
+ val xs = left ++ supers filterNot seen
+ loop(xs - next, seen + next)
+ }
+ }
+ }
+ loop(Set(sub), Set())
+ }
+
+ private def subargs(args1: List[OptManifest[_]], args2: List[OptManifest[_]]) = (args1 corresponds args2) {
+ // !!! [Martin] this is wrong, need to take variance into account
+ case (x: ClassManifest[_], y: ClassManifest[_]) => x <:< y
+ case (x, y) => (x eq NoManifest) && (y eq NoManifest)
+ }
+
+ /** Tests whether the type represented by this manifest is a subtype
+ * of the type represented by `that` manifest, subject to the limitations
+ * described in the header.
+ */
+ @deprecated("use scala.reflect.runtime.universe.TypeTag for subtype checking instead", "2.10.0")
+ def <:<(that: ClassManifest[_]): Boolean = {
+ // All types which could conform to these types will override <:<.
+ def cannotMatch = {
+ import Manifest._
+ that.isInstanceOf[AnyValManifest[_]] || (that eq AnyVal) || (that eq Nothing) || (that eq Null)
+ }
+
+ // This is wrong, and I don't know how it can be made right
+ // without more development of Manifests, due to arity-defying
+ // relationships like:
+ //
+ // List[String] <: AnyRef
+ // Map[Int, Int] <: Iterable[(Int, Int)]
+ //
+ // Given the manifest for Map[K, V] how do I determine that a
+ // supertype has single type argument (K, V) ? I don't see how we
+ // can say whether X <:< Y when type arguments are involved except
+ // when the erasure is the same, even before considering variance.
+ !cannotMatch && {
+ // this part is wrong for not considering variance
+ if (this.runtimeClass == that.runtimeClass)
+ subargs(this.typeArguments, that.typeArguments)
+ // this part is wrong for punting unless the rhs has no type
+ // arguments, but it's better than a blindfolded pinata swing.
+ else
+ that.typeArguments.isEmpty && subtype(this.runtimeClass, that.runtimeClass)
+ }
+ }
+
+ /** Tests whether the type represented by this manifest is a supertype
+ * of the type represented by `that` manifest, subject to the limitations
+ * described in the header.
+ */
+ @deprecated("use scala.reflect.runtime.universe.TypeTag for subtype checking instead", "2.10.0")
+ def >:>(that: ClassManifest[_]): Boolean =
+ that <:< this
+
+ override def canEqual(other: Any) = other match {
+ case _: ClassManifest[_] => true
+ case _ => false
+ }
+
+ protected def arrayClass[A](tp: jClass[_]): jClass[Array[A]] =
+ java.lang.reflect.Array.newInstance(tp, 0).getClass.asInstanceOf[jClass[Array[A]]]
+
+ @deprecated("use wrap instead", "2.10.0")
+ def arrayManifest: ClassManifest[Array[T]] =
+ ClassManifest.classType[Array[T]](arrayClass[T](runtimeClass), this)
+
+ @deprecated("use wrap.newArray instead", "2.10.0")
+ def newArray2(len: Int): Array[Array[T]] =
+ java.lang.reflect.Array.newInstance(arrayClass[T](runtimeClass), len)
+ .asInstanceOf[Array[Array[T]]]
+
+ @deprecated("use wrap.wrap.newArray instead", "2.10.0")
+ def newArray3(len: Int): Array[Array[Array[T]]] =
+ java.lang.reflect.Array.newInstance(arrayClass[Array[T]](arrayClass[T](runtimeClass)), len)
+ .asInstanceOf[Array[Array[Array[T]]]]
+
+ @deprecated("use wrap.wrap.wrap.newArray instead", "2.10.0")
+ def newArray4(len: Int): Array[Array[Array[Array[T]]]] =
+ java.lang.reflect.Array.newInstance(arrayClass[Array[Array[T]]](arrayClass[Array[T]](arrayClass[T](runtimeClass))), len)
+ .asInstanceOf[Array[Array[Array[Array[T]]]]]
+
+ @deprecated("use wrap.wrap.wrap.wrap.newArray instead", "2.10.0")
+ def newArray5(len: Int): Array[Array[Array[Array[Array[T]]]]] =
+ java.lang.reflect.Array.newInstance(arrayClass[Array[Array[Array[T]]]](arrayClass[Array[Array[T]]](arrayClass[Array[T]](arrayClass[T](runtimeClass)))), len)
+ .asInstanceOf[Array[Array[Array[Array[Array[T]]]]]]
+
+ @deprecated("create WrappedArray directly instead", "2.10.0")
+ def newWrappedArray(len: Int): ArraySeq[T] =
+ // it's safe to assume T <: AnyRef here because the method is overridden for all value type manifests
+ new ArraySeq.ofRef[T with AnyRef](newArray(len).asInstanceOf[Array[T with AnyRef]]).asInstanceOf[ArraySeq[T]]
+
+ @deprecated("use ArrayBuilder.make(this) instead", "2.10.0")
+ def newArrayBuilder(): ArrayBuilder[T] =
+ // it's safe to assume T <: AnyRef here because the method is overridden for all value type manifests
+ new ArrayBuilder.ofRef[T with AnyRef]()(this.asInstanceOf[ClassManifest[T with AnyRef]]).asInstanceOf[ArrayBuilder[T]]
+
+ @deprecated("use scala.reflect.runtime.universe.TypeTag to capture type structure instead", "2.10.0")
+ def typeArguments: List[OptManifest[_]] = List()
+
+ protected def argString =
+ if (typeArguments.nonEmpty) typeArguments.mkString("[", ", ", "]")
+ else if (runtimeClass.isArray) "["+ClassManifest.fromClass(runtimeClass.getComponentType)+"]"
+ else ""
+}
+
+/** `ClassManifestFactory` defines factory methods for manifests.
+ * It is intended for use by the compiler and should not be used in client code.
+ *
+ * Unlike `ClassManifest`, this factory isn't annotated with a deprecation warning.
+ * This is done to prevent avalanches of deprecation warnings in the code that calls methods with manifests.
+ *
+ * In a perfect world, we would just remove the @deprecated annotation from `ClassManifest` the object
+ * and then delete it in 2.11. After all, that object is explicitly marked as internal, so no one should use it.
+ * However a lot of existing libraries disregarded the Scaladoc that comes with `ClassManifest`,
+ * so we need to somehow nudge them into migrating prior to removing stuff out of the blue.
+ * Hence we've introduced this design decision as the lesser of two evils.
+ */
+@nowarn("""cat=deprecation&origin=scala\.reflect\.ClassManifest.*""")
+object ClassManifestFactory {
+ val Byte = ManifestFactory.Byte
+ val Short = ManifestFactory.Short
+ val Char = ManifestFactory.Char
+ val Int = ManifestFactory.Int
+ val Long = ManifestFactory.Long
+ val Float = ManifestFactory.Float
+ val Double = ManifestFactory.Double
+ val Boolean = ManifestFactory.Boolean
+ val Unit = ManifestFactory.Unit
+ val Any = ManifestFactory.Any
+ val Object = ManifestFactory.Object
+ val AnyVal = ManifestFactory.AnyVal
+ val Nothing = ManifestFactory.Nothing
+ val Null = ManifestFactory.Null
+
+ def fromClass[T](clazz: jClass[T]): ClassManifest[T] = clazz match {
+ case java.lang.Byte.TYPE => Byte.asInstanceOf[ClassManifest[T]]
+ case java.lang.Short.TYPE => Short.asInstanceOf[ClassManifest[T]]
+ case java.lang.Character.TYPE => Char.asInstanceOf[ClassManifest[T]]
+ case java.lang.Integer.TYPE => Int.asInstanceOf[ClassManifest[T]]
+ case java.lang.Long.TYPE => Long.asInstanceOf[ClassManifest[T]]
+ case java.lang.Float.TYPE => Float.asInstanceOf[ClassManifest[T]]
+ case java.lang.Double.TYPE => Double.asInstanceOf[ClassManifest[T]]
+ case java.lang.Boolean.TYPE => Boolean.asInstanceOf[ClassManifest[T]]
+ case java.lang.Void.TYPE => Unit.asInstanceOf[ClassManifest[T]]
+ case _ => classType[T with AnyRef](clazz).asInstanceOf[ClassManifest[T]]
+ }
+
+ def singleType[T <: AnyRef](value: AnyRef): Manifest[T] = Manifest.singleType(value)
+
+ /** ClassManifest for the class type `clazz`, where `clazz` is
+ * a top-level or static class.
+ * @note This no-prefix, no-arguments case is separate because we
+ * it's called from ScalaRunTime.boxArray itself. If we
+ * pass varargs as arrays into this, we get an infinitely recursive call
+ * to boxArray. (Besides, having a separate case is more efficient)
+ */
+ def classType[T](clazz: jClass[_]): ClassManifest[T] =
+ new ClassTypeManifest[T](None, clazz, Nil)
+
+ /** ClassManifest for the class type `clazz[args]`, where `clazz` is
+ * a top-level or static class and `args` are its type arguments */
+ def classType[T](clazz: jClass[_], arg1: OptManifest[_], args: OptManifest[_]*): ClassManifest[T] =
+ new ClassTypeManifest[T](None, clazz, arg1 :: args.toList)
+
+ /** ClassManifest for the class type `clazz[args]`, where `clazz` is
+ * a class with non-package prefix type `prefix` and type arguments `args`.
+ */
+ def classType[T](prefix: OptManifest[_], clazz: jClass[_], args: OptManifest[_]*): ClassManifest[T] =
+ new ClassTypeManifest[T](Some(prefix), clazz, args.toList)
+
+ def arrayType[T](arg: OptManifest[_]): ClassManifest[Array[T]] = (arg: @unchecked) match {
+ case NoManifest => Object.asInstanceOf[ClassManifest[Array[T]]]
+ case m: ClassManifest[_] => m.asInstanceOf[ClassManifest[T]].arrayManifest
+ }
+
+ @SerialVersionUID(1L)
+ private class AbstractTypeClassManifest[T](prefix: OptManifest[_], name: String, clazz: jClass[_], args: OptManifest[_]*) extends ClassManifest[T] {
+ override def runtimeClass = clazz
+ override val typeArguments = args.toList
+ override def toString = prefix.toString+"#"+name+argString
+ }
+
+ /** ClassManifest for the abstract type `prefix # name`. `upperBound` is not
+ * strictly necessary as it could be obtained by reflection. It was
+ * added so that erasure can be calculated without reflection. */
+ def abstractType[T](prefix: OptManifest[_], name: String, clazz: jClass[_], args: OptManifest[_]*): ClassManifest[T] =
+ new AbstractTypeClassManifest(prefix, name, clazz)
+
+ /** ClassManifest for the abstract type `prefix # name`. `upperBound` is not
+ * strictly necessary as it could be obtained by reflection. It was
+ * added so that erasure can be calculated without reflection.
+ * todo: remove after next bootstrap
+ */
+ def abstractType[T](prefix: OptManifest[_], name: String, upperbound: ClassManifest[_], args: OptManifest[_]*): ClassManifest[T] =
+ new AbstractTypeClassManifest(prefix, name, upperbound.runtimeClass)
+}
+
+/** Manifest for the class type `clazz[args]`, where `clazz` is
+ * a top-level or static class */
+@nowarn("""cat=deprecation&origin=scala\.reflect\.ClassManifest""")
+@SerialVersionUID(1L)
+private class ClassTypeManifest[T](
+ prefix: Option[OptManifest[_]],
+ val runtimeClass: jClass[_],
+ override val typeArguments: List[OptManifest[_]]) extends ClassManifest[T]
+{
+ override def toString =
+ (if (prefix.isEmpty) "" else prefix.get.toString+"#") +
+ (if (runtimeClass.isArray) "Array" else runtimeClass.getName) +
+ argString
+}
diff --git a/library/src/scala/reflect/ClassTag.scala b/library/src/scala/reflect/ClassTag.scala
new file mode 100644
index 000000000000..5ebd3f1506e1
--- /dev/null
+++ b/library/src/scala/reflect/ClassTag.scala
@@ -0,0 +1,168 @@
+/*
+ * 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 reflect
+
+import java.lang.{Class => jClass}
+import java.lang.ref.{WeakReference => jWeakReference}
+import scala.annotation.{implicitNotFound, nowarn}
+import scala.runtime.ClassValueCompat
+
+/**
+ *
+ * A `ClassTag[T]` stores the erased class of a given type `T`, accessible via the `runtimeClass`
+ * field. This is particularly useful for instantiating `Array`s whose element types are unknown
+ * at compile time.
+ *
+ * `ClassTag`s are a weaker special case of [[scala.reflect.api.TypeTags.TypeTag]]s, in that they
+ * wrap only the runtime class of a given type, whereas a `TypeTag` contains all static type
+ * information. That is, `ClassTag`s are constructed from knowing only the top-level class of a
+ * type, without necessarily knowing all of its argument types. This runtime information is enough
+ * for runtime `Array` creation.
+ *
+ * For example:
+ * {{{
+ * scala> def mkArray[T : ClassTag](elems: T*) = Array[T](elems: _*)
+ * mkArray: [T](elems: T*)(implicit evidence\$1: scala.reflect.ClassTag[T])Array[T]
+ *
+ * scala> mkArray(42, 13)
+ * res0: Array[Int] = Array(42, 13)
+ *
+ * scala> mkArray("Japan","Brazil","Germany")
+ * res1: Array[String] = Array(Japan, Brazil, Germany)
+ * }}}
+ *
+ * See [[scala.reflect.api.TypeTags]] for more examples, or the
+ * [[https://docs.scala-lang.org/overviews/reflection/typetags-manifests.html Reflection Guide: TypeTags]]
+ * for more details.
+ *
+ */
+@nowarn("""cat=deprecation&origin=scala\.reflect\.ClassManifestDeprecatedApis""")
+@implicitNotFound(msg = "No ClassTag available for ${T}")
+trait ClassTag[T] extends ClassManifestDeprecatedApis[T] with Equals with Serializable {
+ // please, don't add any APIs here, like it was with `newWrappedArray` and `newArrayBuilder`
+ // class tags, and all tags in general, should be as minimalistic as possible
+
+ /** A class representing the type `U` to which `T` would be erased.
+ * Note that there is no subtyping relationship between `T` and `U`.
+ */
+ def runtimeClass: jClass[_]
+
+ /** Produces a `ClassTag` that knows how to instantiate an `Array[Array[T]]` */
+ def wrap: ClassTag[Array[T]] = ClassTag[Array[T]](arrayClass(runtimeClass))
+
+ /** Produces a new array with element type `T` and length `len` */
+ def newArray(len: Int): Array[T] =
+ java.lang.reflect.Array.newInstance(runtimeClass, len).asInstanceOf[Array[T]]
+
+ /** A ClassTag[T] can serve as an extractor that matches only objects of type T.
+ *
+ * The compiler tries to turn unchecked type tests in pattern matches into checked ones
+ * by wrapping a `(_: T)` type pattern as `ct(_: T)`, where `ct` is the `ClassTag[T]` instance.
+ * Type tests necessary before calling other extractors are treated similarly.
+ * `SomeExtractor(...)` is turned into `ct(SomeExtractor(...))` if `T` in `SomeExtractor.unapply(x: T)`
+ * is uncheckable, but we have an instance of `ClassTag[T]`.
+ */
+ def unapply(x: Any): Option[T] =
+ if (runtimeClass.isInstance(x)) Some(x.asInstanceOf[T])
+ else None
+
+ // case class accessories
+ override def canEqual(x: Any) = x.isInstanceOf[ClassTag[_]]
+ override def equals(x: Any) = x.isInstanceOf[ClassTag[_]] && this.runtimeClass == x.asInstanceOf[ClassTag[_]].runtimeClass
+ override def hashCode = runtimeClass.##
+ override def toString = {
+ def prettyprint(clazz: jClass[_]): String =
+ if (clazz.isArray) s"Array[${prettyprint(clazz.getComponentType)}]" else
+ clazz.getName
+ prettyprint(runtimeClass)
+ }
+}
+
+/**
+ * Class tags corresponding to primitive types and constructor/extractor for ClassTags.
+ */
+object ClassTag {
+ private[this] val ObjectTYPE = classOf[java.lang.Object]
+ private[this] val NothingTYPE = classOf[scala.runtime.Nothing$]
+ private[this] val NullTYPE = classOf[scala.runtime.Null$]
+
+ import ManifestFactory._
+
+ val Byte : ByteManifest = Manifest.Byte
+ val Short : ShortManifest = Manifest.Short
+ val Char : CharManifest = Manifest.Char
+ val Int : IntManifest = Manifest.Int
+ val Long : LongManifest = Manifest.Long
+ val Float : FloatManifest = Manifest.Float
+ val Double : DoubleManifest = Manifest.Double
+ val Boolean : BooleanManifest = Manifest.Boolean
+ val Unit : UnitManifest = Manifest.Unit
+ val Any : ClassTag[scala.Any] = Manifest.Any
+ val Object : ClassTag[java.lang.Object] = Manifest.Object
+ val AnyVal : ClassTag[scala.AnyVal] = Manifest.AnyVal
+ val AnyRef : ClassTag[scala.AnyRef] = Manifest.AnyRef
+ val Nothing : ClassTag[scala.Nothing] = Manifest.Nothing
+ val Null : ClassTag[scala.Null] = Manifest.Null
+
+ private val cacheDisabled = java.lang.Boolean.getBoolean("scala.reflect.classtag.cache.disable")
+ private[this] object cache extends ClassValueCompat[jWeakReference[ClassTag[_]]] {
+ override def computeValue(runtimeClass: jClass[_]): jWeakReference[ClassTag[_]] =
+ new jWeakReference(computeTag(runtimeClass))
+
+ def computeTag(runtimeClass: jClass[_]): ClassTag[_] =
+ runtimeClass match {
+ case x if x.isPrimitive => primitiveClassTag(runtimeClass)
+ case ObjectTYPE => ClassTag.Object
+ case NothingTYPE => ClassTag.Nothing
+ case NullTYPE => ClassTag.Null
+ case _ => new GenericClassTag[AnyRef](runtimeClass)
+ }
+
+ private def primitiveClassTag[T](runtimeClass: Class[_]): ClassTag[_] =
+ (runtimeClass: @unchecked) match {
+ case java.lang.Byte.TYPE => ClassTag.Byte
+ case java.lang.Short.TYPE => ClassTag.Short
+ case java.lang.Character.TYPE => ClassTag.Char
+ case java.lang.Integer.TYPE => ClassTag.Int
+ case java.lang.Long.TYPE => ClassTag.Long
+ case java.lang.Float.TYPE => ClassTag.Float
+ case java.lang.Double.TYPE => ClassTag.Double
+ case java.lang.Boolean.TYPE => ClassTag.Boolean
+ case java.lang.Void.TYPE => ClassTag.Unit
+ }
+ }
+
+ @SerialVersionUID(1L)
+ private class GenericClassTag[T](val runtimeClass: jClass[_]) extends ClassTag[T] {
+ override def newArray(len: Int): Array[T] = {
+ java.lang.reflect.Array.newInstance(runtimeClass, len).asInstanceOf[Array[T]]
+ }
+ }
+
+ def apply[T](runtimeClass1: jClass[_]): ClassTag[T] = {
+ if (cacheDisabled) {
+ cache.computeTag(runtimeClass1).asInstanceOf[ClassTag[T]]
+ } else {
+ val ref = cache.get(runtimeClass1).asInstanceOf[jWeakReference[ClassTag[T]]]
+ var tag = ref.get
+ if (tag == null) {
+ cache.remove(runtimeClass1)
+ tag = cache.computeTag(runtimeClass1).asInstanceOf[ClassTag[T]]
+ }
+ tag
+ }
+ }
+
+ def unapply[T](ctag: ClassTag[T]): Option[Class[_]] = Some(ctag.runtimeClass)
+}
diff --git a/library/src/scala/reflect/Manifest.scala b/library/src/scala/reflect/Manifest.scala
new file mode 100644
index 000000000000..9f382fdd800e
--- /dev/null
+++ b/library/src/scala/reflect/Manifest.scala
@@ -0,0 +1,461 @@
+/*
+ * 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 reflect
+
+import scala.annotation.{implicitNotFound, nowarn}
+import scala.collection.mutable.{ArrayBuilder, ArraySeq}
+
+/** A `Manifest[T]` is an opaque descriptor for type T. Its supported use
+ * is to give access to the erasure of the type as a `Class` instance, as
+ * is necessary for the creation of native `Arrays` if the class is not
+ * known at compile time.
+ *
+ * The type-relation operators `<:<` and `=:=` should be considered
+ * approximations only, as there are numerous aspects of type conformance
+ * which are not yet adequately represented in manifests.
+ *
+ * Example usages:
+ * {{{
+ * def arr[T] = new Array[T](0) // does not compile
+ * def arr[T](implicit m: Manifest[T]) = new Array[T](0) // compiles
+ * def arr[T: Manifest] = new Array[T](0) // shorthand for the preceding
+ *
+ * // Methods manifest and optManifest are in [[scala.Predef]].
+ * def isApproxSubType[T: Manifest, U: Manifest] = manifest[T] <:< manifest[U]
+ * isApproxSubType[List[String], List[AnyRef]] // true
+ * isApproxSubType[List[String], List[Int]] // false
+ *
+ * def methods[T: Manifest] = manifest[T].runtimeClass.getMethods
+ * def retType[T: Manifest](name: String) =
+ * methods[T] find (_.getName == name) map (_.getGenericReturnType)
+ *
+ * retType[Map[_, _]]("values") // Some(scala.collection.Iterable)
+ * }}}
+ */
+@nowarn("""cat=deprecation&origin=scala\.reflect\.ClassManifest(DeprecatedApis.*)?""")
+@implicitNotFound(msg = "No Manifest available for ${T}.")
+// TODO undeprecated until Scala reflection becomes non-experimental
+// @deprecated("use scala.reflect.ClassTag (to capture erasures) or scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0")
+trait Manifest[T] extends ClassManifest[T] with Equals {
+ override def typeArguments: List[Manifest[_]] = Nil
+
+ override def arrayManifest: Manifest[Array[T]] =
+ Manifest.classType[Array[T]](arrayClass[T](runtimeClass), this)
+
+ override def canEqual(that: Any): Boolean = that match {
+ case _: Manifest[_] => true
+ case _ => false
+ }
+ /** Note: testing for erasure here is important, as it is many times
+ * faster than <:< and rules out most comparisons.
+ */
+ override def equals(that: Any): Boolean = that match {
+ case m: Manifest[_] => (m canEqual this) && (this.runtimeClass == m.runtimeClass) && (this <:< m) && (m <:< this)
+ case _ => false
+ }
+ override def hashCode = this.runtimeClass.##
+}
+
+/** The object `Manifest` defines factory methods for manifests.
+ * It is intended for use by the compiler and should not be used in client code.
+ */
+// TODO undeprecated until Scala reflection becomes non-experimental
+// @deprecated("use scala.reflect.ClassTag (to capture erasures), scala.reflect.runtime.universe.TypeTag (to capture types) or both instead", "2.10.0")
+object Manifest {
+ /* Forward all the public members of ManifestFactory, since this object used
+ * to be a `private val Manifest = ManifestFactory` in the package object. It
+ * was moved here because it needs to be in the same file as `trait Manifest`
+ * defined above.
+ */
+
+ def valueManifests: List[AnyValManifest[_]] =
+ ManifestFactory.valueManifests
+
+ val Byte: ManifestFactory.ByteManifest = ManifestFactory.Byte
+ val Short: ManifestFactory.ShortManifest = ManifestFactory.Short
+ val Char: ManifestFactory.CharManifest = ManifestFactory.Char
+ val Int: ManifestFactory.IntManifest = ManifestFactory.Int
+ val Long: ManifestFactory.LongManifest = ManifestFactory.Long
+ val Float: ManifestFactory.FloatManifest = ManifestFactory.Float
+ val Double: ManifestFactory.DoubleManifest = ManifestFactory.Double
+ val Boolean: ManifestFactory.BooleanManifest = ManifestFactory.Boolean
+ val Unit: ManifestFactory.UnitManifest = ManifestFactory.Unit
+
+ val Any: Manifest[scala.Any] = ManifestFactory.Any
+ val Object: Manifest[java.lang.Object] = ManifestFactory.Object
+ val AnyRef: Manifest[scala.AnyRef] = ManifestFactory.AnyRef
+ val AnyVal: Manifest[scala.AnyVal] = ManifestFactory.AnyVal
+ val Null: Manifest[scala.Null] = ManifestFactory.Null
+ val Nothing: Manifest[scala.Nothing] = ManifestFactory.Nothing
+
+ /** Manifest for the singleton type `value.type`. */
+ def singleType[T <: AnyRef](value: AnyRef): Manifest[T] =
+ ManifestFactory.singleType[T](value)
+
+ /** Manifest for the class type `clazz[args]`, where `clazz` is
+ * a top-level or static class.
+ * @note This no-prefix, no-arguments case is separate because we
+ * it's called from ScalaRunTime.boxArray itself. If we
+ * pass varargs as arrays into this, we get an infinitely recursive call
+ * to boxArray. (Besides, having a separate case is more efficient)
+ */
+ def classType[T](clazz: Predef.Class[_]): Manifest[T] =
+ ManifestFactory.classType[T](clazz)
+
+ /** Manifest for the class type `clazz`, where `clazz` is
+ * a top-level or static class and args are its type arguments. */
+ def classType[T](clazz: Predef.Class[T], arg1: Manifest[_], args: Manifest[_]*): Manifest[T] =
+ ManifestFactory.classType[T](clazz, arg1, args: _*)
+
+ /** Manifest for the class type `clazz[args]`, where `clazz` is
+ * a class with non-package prefix type `prefix` and type arguments `args`.
+ */
+ def classType[T](prefix: Manifest[_], clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] =
+ ManifestFactory.classType[T](prefix, clazz, args: _*)
+
+ def arrayType[T](arg: Manifest[_]): Manifest[Array[T]] =
+ ManifestFactory.arrayType[T](arg)
+
+ /** Manifest for the abstract type `prefix # name`. `upperBound` is not
+ * strictly necessary as it could be obtained by reflection. It was
+ * added so that erasure can be calculated without reflection. */
+ def abstractType[T](prefix: Manifest[_], name: String, upperBound: Predef.Class[_], args: Manifest[_]*): Manifest[T] =
+ ManifestFactory.abstractType[T](prefix, name, upperBound, args: _*)
+
+ /** Manifest for the unknown type `_ >: L <: U` in an existential. */
+ def wildcardType[T](lowerBound: Manifest[_], upperBound: Manifest[_]): Manifest[T] =
+ ManifestFactory.wildcardType[T](lowerBound, upperBound)
+
+ /** Manifest for the intersection type `parents_0 with ... with parents_n`. */
+ def intersectionType[T](parents: Manifest[_]*): Manifest[T] =
+ ManifestFactory.intersectionType[T](parents: _*)
+
+}
+
+// TODO undeprecated until Scala reflection becomes non-experimental
+// @deprecated("use type tags and manually check the corresponding class or type instead", "2.10.0")
+@nowarn("""cat=deprecation&origin=scala\.reflect\.ClassManifest(DeprecatedApis.*)?""")
+@SerialVersionUID(1L)
+abstract class AnyValManifest[T <: AnyVal](override val toString: String) extends Manifest[T] with Equals {
+ override def <:<(that: ClassManifest[_]): Boolean =
+ (that eq this) || (that eq Manifest.Any) || (that eq Manifest.AnyVal)
+ override def canEqual(other: Any) = other match {
+ case _: AnyValManifest[_] => true
+ case _ => false
+ }
+ override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef]
+ @transient
+ override val hashCode = System.identityHashCode(this)
+}
+
+/** `ManifestFactory` defines factory methods for manifests.
+ * It is intended for use by the compiler and should not be used in client code.
+ *
+ * Unlike `Manifest`, this factory isn't annotated with a deprecation warning.
+ * This is done to prevent avalanches of deprecation warnings in the code that calls methods with manifests.
+ * Why so complicated? Read up the comments for `ClassManifestFactory`.
+ */
+@nowarn("""cat=deprecation&origin=scala\.reflect\.ClassManifest(DeprecatedApis.*)?""")
+object ManifestFactory {
+ def valueManifests: List[AnyValManifest[_]] =
+ List(Byte, Short, Char, Int, Long, Float, Double, Boolean, Unit)
+
+ @SerialVersionUID(1L)
+ final private[reflect] class ByteManifest extends AnyValManifest[scala.Byte]("Byte") {
+ def runtimeClass: Class[java.lang.Byte] = java.lang.Byte.TYPE
+ @inline override def newArray(len: Int): Array[Byte] = new Array[Byte](len)
+ override def newWrappedArray(len: Int): ArraySeq[Byte] = new ArraySeq.ofByte(new Array[Byte](len))
+ override def newArrayBuilder(): ArrayBuilder[Byte] = new ArrayBuilder.ofByte()
+ override def unapply(x: Any): Option[Byte] = {
+ x match {
+ case d: Byte => Some(d)
+ case _ => None
+ }
+ }
+ private def readResolve(): Any = Manifest.Byte
+ }
+ val Byte: ByteManifest = new ByteManifest
+
+ @SerialVersionUID(1L)
+ final private[reflect] class ShortManifest extends AnyValManifest[scala.Short]("Short") {
+ def runtimeClass: Class[java.lang.Short] = java.lang.Short.TYPE
+ @inline override def newArray(len: Int): Array[Short] = new Array[Short](len)
+ override def newWrappedArray(len: Int): ArraySeq[Short] = new ArraySeq.ofShort(new Array[Short](len))
+ override def newArrayBuilder(): ArrayBuilder[Short] = new ArrayBuilder.ofShort()
+ override def unapply(x: Any): Option[Short] = {
+ x match {
+ case d: Short => Some(d)
+ case _ => None
+ }
+ }
+ private def readResolve(): Any = Manifest.Short
+ }
+ val Short: ShortManifest = new ShortManifest
+
+ @SerialVersionUID(1L)
+ final private[reflect] class CharManifest extends AnyValManifest[scala.Char]("Char") {
+ def runtimeClass: Class[java.lang.Character] = java.lang.Character.TYPE
+ @inline override def newArray(len: Int): Array[Char] = new Array[Char](len)
+ override def newWrappedArray(len: Int): ArraySeq[Char] = new ArraySeq.ofChar(new Array[Char](len))
+ override def newArrayBuilder(): ArrayBuilder[Char] = new ArrayBuilder.ofChar()
+ override def unapply(x: Any): Option[Char] = {
+ x match {
+ case d: Char => Some(d)
+ case _ => None
+ }
+ }
+ private def readResolve(): Any = Manifest.Char
+ }
+ val Char: CharManifest = new CharManifest
+
+ @SerialVersionUID(1L)
+ final private[reflect] class IntManifest extends AnyValManifest[scala.Int]("Int") {
+ def runtimeClass: Class[java.lang.Integer] = java.lang.Integer.TYPE
+ @inline override def newArray(len: Int): Array[Int] = new Array[Int](len)
+ override def newWrappedArray(len: Int): ArraySeq[Int] = new ArraySeq.ofInt(new Array[Int](len))
+ override def newArrayBuilder(): ArrayBuilder[Int] = new ArrayBuilder.ofInt()
+ override def unapply(x: Any): Option[Int] = {
+ x match {
+ case d: Int => Some(d)
+ case _ => None
+ }
+ }
+ private def readResolve(): Any = Manifest.Int
+ }
+ val Int: IntManifest = new IntManifest
+
+ @SerialVersionUID(1L)
+ final private[reflect] class LongManifest extends AnyValManifest[scala.Long]("Long") {
+ def runtimeClass: Class[java.lang.Long] = java.lang.Long.TYPE
+ @inline override def newArray(len: Int): Array[Long] = new Array[Long](len)
+ override def newWrappedArray(len: Int): ArraySeq[Long] = new ArraySeq.ofLong(new Array[Long](len))
+ override def newArrayBuilder(): ArrayBuilder[Long] = new ArrayBuilder.ofLong()
+ override def unapply(x: Any): Option[Long] = {
+ x match {
+ case d: Long => Some(d)
+ case _ => None
+ }
+ }
+ private def readResolve(): Any = Manifest.Long
+ }
+ val Long: LongManifest = new LongManifest
+
+ @SerialVersionUID(1L)
+ final private[reflect] class FloatManifest extends AnyValManifest[scala.Float]("Float") {
+ def runtimeClass: Class[java.lang.Float] = java.lang.Float.TYPE
+ @inline override def newArray(len: Int): Array[Float] = new Array[Float](len)
+ override def newWrappedArray(len: Int): ArraySeq[Float] = new ArraySeq.ofFloat(new Array[Float](len))
+ override def newArrayBuilder(): ArrayBuilder[Float] = new ArrayBuilder.ofFloat()
+ override def unapply(x: Any): Option[Float] = {
+ x match {
+ case d: Float => Some(d)
+ case _ => None
+ }
+ }
+ private def readResolve(): Any = Manifest.Float
+ }
+ val Float: FloatManifest = new FloatManifest
+
+ @SerialVersionUID(1L)
+ final private[reflect] class DoubleManifest extends AnyValManifest[scala.Double]("Double") {
+ def runtimeClass: Class[java.lang.Double] = java.lang.Double.TYPE
+ @inline override def newArray(len: Int): Array[Double] = new Array[Double](len)
+ override def newWrappedArray(len: Int): ArraySeq[Double] = new ArraySeq.ofDouble(new Array[Double](len))
+ override def newArrayBuilder(): ArrayBuilder[Double] = new ArrayBuilder.ofDouble()
+
+ override def unapply(x: Any): Option[Double] = {
+ x match {
+ case d: Double => Some(d)
+ case _ => None
+ }
+ }
+ private def readResolve(): Any = Manifest.Double
+ }
+ val Double: DoubleManifest = new DoubleManifest
+
+ @SerialVersionUID(1L)
+ final private[reflect] class BooleanManifest extends AnyValManifest[scala.Boolean]("Boolean") {
+ def runtimeClass: Class[java.lang.Boolean] = java.lang.Boolean.TYPE
+ @inline override def newArray(len: Int): Array[Boolean] = new Array[Boolean](len)
+ override def newWrappedArray(len: Int): ArraySeq[Boolean] = new ArraySeq.ofBoolean(new Array[Boolean](len))
+ override def newArrayBuilder(): ArrayBuilder[Boolean] = new ArrayBuilder.ofBoolean()
+ override def unapply(x: Any): Option[Boolean] = {
+ x match {
+ case d: Boolean => Some(d)
+ case _ => None
+ }
+ }
+ private def readResolve(): Any = Manifest.Boolean
+ }
+ val Boolean: BooleanManifest = new BooleanManifest
+
+ @SerialVersionUID(1L)
+ final private[reflect] class UnitManifest extends AnyValManifest[scala.Unit]("Unit") {
+ def runtimeClass: Class[java.lang.Void] = java.lang.Void.TYPE
+ @inline override def newArray(len: Int): Array[Unit] = new Array[Unit](len)
+ override def newWrappedArray(len: Int): ArraySeq[Unit] = new ArraySeq.ofUnit(new Array[Unit](len))
+ override def newArrayBuilder(): ArrayBuilder[Unit] = new ArrayBuilder.ofUnit()
+ override protected def arrayClass[T](tp: Class[_]): Class[Array[T]] =
+ if (tp eq runtimeClass) classOf[Array[scala.runtime.BoxedUnit]].asInstanceOf[Class[Array[T]]]
+ else super.arrayClass(tp)
+ override def unapply(x: Any): Option[Unit] = {
+ x match {
+ case d: Unit => Some(d)
+ case _ => None
+ }
+ }
+ private def readResolve(): Any = Manifest.Unit
+ }
+ val Unit: UnitManifest = new UnitManifest
+
+ private[this] val ObjectTYPE = classOf[java.lang.Object]
+ private[this] val NothingTYPE = classOf[scala.runtime.Nothing$]
+ private[this] val NullTYPE = classOf[scala.runtime.Null$]
+
+ @SerialVersionUID(1L)
+ final private class AnyManifest extends PhantomManifest[scala.Any](ObjectTYPE, "Any") {
+ override def newArray(len: Int) = new Array[scala.Any](len)
+ override def <:<(that: ClassManifest[_]): Boolean = (that eq this)
+ private def readResolve(): Any = Manifest.Any
+ }
+ val Any: Manifest[scala.Any] = new AnyManifest
+
+ @SerialVersionUID(1L)
+ final private class ObjectManifest extends PhantomManifest[java.lang.Object](ObjectTYPE, "Object") {
+ override def newArray(len: Int) = new Array[java.lang.Object](len)
+ override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any)
+ private def readResolve(): Any = Manifest.Object
+ }
+ val Object: Manifest[java.lang.Object] = new ObjectManifest
+
+ val AnyRef: Manifest[scala.AnyRef] = Object.asInstanceOf[Manifest[scala.AnyRef]]
+
+ @SerialVersionUID(1L)
+ final private class AnyValPhantomManifest extends PhantomManifest[scala.AnyVal](ObjectTYPE, "AnyVal") {
+ override def newArray(len: Int) = new Array[scala.AnyVal](len)
+ override def <:<(that: ClassManifest[_]): Boolean = (that eq this) || (that eq Any)
+ private def readResolve(): Any = Manifest.AnyVal
+ }
+ val AnyVal: Manifest[scala.AnyVal] = new AnyValPhantomManifest
+
+ @SerialVersionUID(1L)
+ final private class NullManifest extends PhantomManifest[scala.Null](NullTYPE, "Null") {
+ override def newArray(len: Int) = new Array[scala.Null](len)
+ override def <:<(that: ClassManifest[_]): Boolean =
+ (that ne null) && (that ne Nothing) && !(that <:< AnyVal)
+ private def readResolve(): Any = Manifest.Null
+ }
+ val Null: Manifest[scala.Null] = new NullManifest
+
+ @SerialVersionUID(1L)
+ final private class NothingManifest extends PhantomManifest[scala.Nothing](NothingTYPE, "Nothing") {
+ override def newArray(len: Int) = new Array[scala.Nothing](len)
+ override def <:<(that: ClassManifest[_]): Boolean = (that ne null)
+ private def readResolve(): Any = Manifest.Nothing
+ }
+ val Nothing: Manifest[scala.Nothing] = new NothingManifest
+
+ @SerialVersionUID(1L)
+ final private class SingletonTypeManifest[T <: AnyRef](value: AnyRef) extends Manifest[T] {
+ lazy val runtimeClass: Class[_ <: AnyRef] = value.getClass
+ override lazy val toString = value.toString + ".type"
+ }
+
+ /** Manifest for the singleton type `value.type`. */
+ def singleType[T <: AnyRef](value: AnyRef): Manifest[T] =
+ new SingletonTypeManifest[T](value)
+
+ /** Manifest for the class type `clazz[args]`, where `clazz` is
+ * a top-level or static class.
+ * @note This no-prefix, no-arguments case is separate because we
+ * it's called from ScalaRunTime.boxArray itself. If we
+ * pass varargs as arrays into this, we get an infinitely recursive call
+ * to boxArray. (Besides, having a separate case is more efficient)
+ */
+ def classType[T](clazz: Predef.Class[_]): Manifest[T] =
+ new ClassTypeManifest[T](None, clazz, Nil)
+
+ /** Manifest for the class type `clazz`, where `clazz` is
+ * a top-level or static class and args are its type arguments. */
+ def classType[T](clazz: Predef.Class[T], arg1: Manifest[_], args: Manifest[_]*): Manifest[T] =
+ new ClassTypeManifest[T](None, clazz, arg1 :: args.toList)
+
+ /** Manifest for the class type `clazz[args]`, where `clazz` is
+ * a class with non-package prefix type `prefix` and type arguments `args`.
+ */
+ def classType[T](prefix: Manifest[_], clazz: Predef.Class[_], args: Manifest[_]*): Manifest[T] =
+ new ClassTypeManifest[T](Some(prefix), clazz, args.toList)
+
+ @SerialVersionUID(1L)
+ private abstract class PhantomManifest[T](_runtimeClass: Predef.Class[_],
+ override val toString: String) extends ClassTypeManifest[T](None, _runtimeClass, Nil) {
+ override def equals(that: Any): Boolean = this eq that.asInstanceOf[AnyRef]
+ @transient
+ override val hashCode = System.identityHashCode(this)
+ }
+
+ /** Manifest for the class type `clazz[args]`, where `clazz` is
+ * a top-level or static class. */
+ @SerialVersionUID(1L)
+ private class ClassTypeManifest[T](prefix: Option[Manifest[_]],
+ val runtimeClass: Predef.Class[_],
+ override val typeArguments: List[Manifest[_]]) extends Manifest[T] {
+ override def toString =
+ (if (prefix.isEmpty) "" else prefix.get.toString+"#") +
+ (if (runtimeClass.isArray) "Array" else runtimeClass.getName) +
+ argString
+ }
+
+ def arrayType[T](arg: Manifest[_]): Manifest[Array[T]] =
+ arg.asInstanceOf[Manifest[T]].arrayManifest
+
+ @SerialVersionUID(1L)
+ private class AbstractTypeManifest[T](prefix: Manifest[_], name: String, upperBound: Predef.Class[_], args: scala.collection.Seq[Manifest[_]]) extends Manifest[T] {
+ def runtimeClass = upperBound
+ override val typeArguments = args.toList
+ override def toString = prefix.toString+"#"+name+argString
+ }
+
+ /** Manifest for the abstract type `prefix # name`. `upperBound` is not
+ * strictly necessary as it could be obtained by reflection. It was
+ * added so that erasure can be calculated without reflection. */
+ def abstractType[T](prefix: Manifest[_], name: String, upperBound: Predef.Class[_], args: Manifest[_]*): Manifest[T] =
+ new AbstractTypeManifest[T](prefix, name, upperBound, args)
+
+ @SerialVersionUID(1L)
+ private class WildcardManifest[T](lowerBound: Manifest[_], upperBound: Manifest[_]) extends Manifest[T] {
+ def runtimeClass = upperBound.runtimeClass
+ override def toString =
+ "_" +
+ (if (lowerBound eq Nothing) "" else " >: "+lowerBound) +
+ (if (upperBound eq Nothing) "" else " <: "+upperBound)
+ }
+
+ /** Manifest for the unknown type `_ >: L <: U` in an existential.
+ */
+ def wildcardType[T](lowerBound: Manifest[_], upperBound: Manifest[_]): Manifest[T] =
+ new WildcardManifest[T](lowerBound, upperBound)
+
+ @SerialVersionUID(1L)
+ private class IntersectionTypeManifest[T](parents: Array[Manifest[_]]) extends Manifest[T] {
+ // We use an `Array` instead of a `Seq` for `parents` to avoid cyclic dependencies during deserialization
+ // which can cause serialization proxies to leak and cause a ClassCastException.
+ def runtimeClass = parents(0).runtimeClass
+ override def toString = parents.mkString(" with ")
+ }
+
+ /** Manifest for the intersection type `parents_0 with ... with parents_n`. */
+ def intersectionType[T](parents: Manifest[_]*): Manifest[T] =
+ new IntersectionTypeManifest[T](parents.toArray)
+}
diff --git a/library/src/scala/reflect/NameTransformer.scala b/library/src/scala/reflect/NameTransformer.scala
new file mode 100644
index 000000000000..4980ed5bd6b4
--- /dev/null
+++ b/library/src/scala/reflect/NameTransformer.scala
@@ -0,0 +1,167 @@
+/*
+ * 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 reflect
+
+/** Provides functions to encode and decode Scala symbolic names.
+ * Also provides some constants.
+ */
+object NameTransformer {
+ // TODO: reduce duplication with and in StdNames
+ // I made these constants because we cannot change them without bumping our major version anyway.
+ final val NAME_JOIN_STRING = "$"
+ final val MODULE_SUFFIX_STRING = "$"
+ final val MODULE_INSTANCE_NAME = "MODULE$"
+ final val LOCAL_SUFFIX_STRING = " "
+ final val LAZY_LOCAL_SUFFIX_STRING = "$lzy"
+ final val MODULE_VAR_SUFFIX_STRING = "$module"
+ final val SETTER_SUFFIX_STRING = "_$eq"
+ final val TRAIT_SETTER_SEPARATOR_STRING = "$_setter_$"
+
+ private[this] val nops = 128
+ private[this] val ncodes = 26 * 26
+
+ private class OpCodes(val op: Char, val code: String, val next: OpCodes)
+
+ private[this] val op2code = new Array[String](nops)
+ private[this] val code2op = new Array[OpCodes](ncodes)
+ private def enterOp(op: Char, code: String) = {
+ op2code(op.toInt) = code
+ val c = (code.charAt(1) - 'a') * 26 + code.charAt(2) - 'a'
+ code2op(c.toInt) = new OpCodes(op, code, code2op(c))
+ }
+
+ /* Note: decoding assumes opcodes are only ever lowercase. */
+ enterOp('~', "$tilde")
+ enterOp('=', "$eq")
+ enterOp('<', "$less")
+ enterOp('>', "$greater")
+ enterOp('!', "$bang")
+ enterOp('#', "$hash")
+ enterOp('%', "$percent")
+ enterOp('^', "$up")
+ enterOp('&', "$amp")
+ enterOp('|', "$bar")
+ enterOp('*', "$times")
+ enterOp('/', "$div")
+ enterOp('+', "$plus")
+ enterOp('-', "$minus")
+ enterOp(':', "$colon")
+ enterOp('\\', "$bslash")
+ enterOp('?', "$qmark")
+ enterOp('@', "$at")
+
+ /** Replace operator symbols by corresponding `\$opname`.
+ *
+ * @param name the string to encode
+ * @return the string with all recognized opchars replaced with their encoding
+ */
+ def encode(name: String): String = {
+ var buf: StringBuilder = null
+ val len = name.length()
+ var i = 0
+ while (i < len) {
+ val c = name charAt i
+ if (c < nops && (op2code(c.toInt) ne null)) {
+ if (buf eq null) {
+ buf = new StringBuilder()
+ buf.append(name.substring(0, i))
+ }
+ buf.append(op2code(c.toInt))
+ /* Handle glyphs that are not valid Java/JVM identifiers */
+ }
+ else if (!Character.isJavaIdentifierPart(c)) {
+ if (buf eq null) {
+ buf = new StringBuilder()
+ buf.append(name.substring(0, i))
+ }
+ buf.append("$u%04X".format(c.toInt))
+ }
+ else if (buf ne null) {
+ buf.append(c)
+ }
+ i += 1
+ }
+ if (buf eq null) name else buf.toString()
+ }
+
+ /** Replace `\$opname` by corresponding operator symbol.
+ *
+ * @param name0 the string to decode
+ * @return the string with all recognized operator symbol encodings replaced with their name
+ */
+ def decode(name0: String): String = {
+ //System.out.println("decode: " + name);//DEBUG
+ val name = if (name0.endsWith("")) name0.stripSuffix("") + "this"
+ else name0
+ var buf: StringBuilder = null
+ val len = name.length()
+ var i = 0
+ while (i < len) {
+ var ops: OpCodes = null
+ var unicode = false
+ val c = name charAt i
+ if (c == '$' && i + 2 < len) {
+ val ch1 = name.charAt(i+1)
+ if ('a' <= ch1 && ch1 <= 'z') {
+ val ch2 = name.charAt(i+2)
+ if ('a' <= ch2 && ch2 <= 'z') {
+ ops = code2op((ch1 - 'a') * 26 + ch2 - 'a')
+ while ((ops ne null) && !name.startsWith(ops.code, i)) ops = ops.next
+ if (ops ne null) {
+ if (buf eq null) {
+ buf = new StringBuilder()
+ buf.append(name.substring(0, i))
+ }
+ buf.append(ops.op)
+ i += ops.code.length()
+ }
+ /* Handle the decoding of Unicode glyphs that are
+ * not valid Java/JVM identifiers */
+ } else if ((len - i) >= 6 && // Check that there are enough characters left
+ ch1 == 'u' &&
+ ((Character.isDigit(ch2)) ||
+ ('A' <= ch2 && ch2 <= 'F'))) {
+ /* Skip past "$u", next four should be hexadecimal */
+ val hex = name.substring(i+2, i+6)
+ try {
+ val str = Integer.parseInt(hex, 16).toChar
+ if (buf eq null) {
+ buf = new StringBuilder()
+ buf.append(name.substring(0, i))
+ }
+ buf.append(str)
+ /* 2 for "$u", 4 for hexadecimal number */
+ i += 6
+ unicode = true
+ } catch {
+ case _:NumberFormatException =>
+ /* `hex` did not decode to a hexadecimal number, so
+ * do nothing. */
+ }
+ }
+ }
+ }
+ /* If we didn't see an opcode or encoded Unicode glyph, and the
+ buffer is non-empty, write the current character and advance
+ one */
+ if ((ops eq null) && !unicode) {
+ if (buf ne null)
+ buf.append(c)
+ i += 1
+ }
+ }
+ //System.out.println("= " + (if (buf == null) name else buf.toString()));//DEBUG
+ if (buf eq null) name else buf.toString()
+ }
+}
diff --git a/library/src/scala/reflect/NoManifest.scala b/library/src/scala/reflect/NoManifest.scala
new file mode 100644
index 000000000000..819ffede46d3
--- /dev/null
+++ b/library/src/scala/reflect/NoManifest.scala
@@ -0,0 +1,22 @@
+/*
+ * 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 reflect
+
+/** One of the branches of an [[scala.reflect.OptManifest]].
+ */
+// TODO undeprecated until Scala reflection becomes non-experimental
+// @deprecated("This notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0")
+object NoManifest extends OptManifest[Nothing] with Serializable {
+ override def toString = ">"
+}
diff --git a/library/src/scala/reflect/OptManifest.scala b/library/src/scala/reflect/OptManifest.scala
new file mode 100644
index 000000000000..f3b3c3117236
--- /dev/null
+++ b/library/src/scala/reflect/OptManifest.scala
@@ -0,0 +1,22 @@
+/*
+ * 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 reflect
+
+/** A `OptManifest[T]` is an optional [[scala.reflect.Manifest]].
+ *
+ * It is either a `Manifest` or the value `NoManifest`.
+ */
+// TODO undeprecated until Scala reflection becomes non-experimental
+// @deprecated("This notion doesn't have a corresponding concept in 2.10, because scala.reflect.runtime.universe.TypeTag can capture arbitrary types. Use type tags instead of manifests, and there will be no need in opt manifests.", "2.10.0")
+trait OptManifest[+T] extends Serializable
diff --git a/library/src/scala/reflect/ScalaLongSignature.java b/library/src/scala/reflect/ScalaLongSignature.java
new file mode 100644
index 000000000000..29a77dc2f352
--- /dev/null
+++ b/library/src/scala/reflect/ScalaLongSignature.java
@@ -0,0 +1,24 @@
+/*
+ * 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.reflect;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface ScalaLongSignature {
+ String[] bytes();
+}
diff --git a/library/src/scala/reflect/ScalaSignature.java b/library/src/scala/reflect/ScalaSignature.java
new file mode 100644
index 000000000000..dbd5a46bfd10
--- /dev/null
+++ b/library/src/scala/reflect/ScalaSignature.java
@@ -0,0 +1,24 @@
+/*
+ * 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.reflect;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface ScalaSignature {
+ String bytes();
+}
diff --git a/library/src/scala/reflect/macros/internal/macroImpl.scala b/library/src/scala/reflect/macros/internal/macroImpl.scala
new file mode 100644
index 000000000000..c26426a079f2
--- /dev/null
+++ b/library/src/scala/reflect/macros/internal/macroImpl.scala
@@ -0,0 +1,30 @@
+/*
+ * 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.reflect.macros
+package internal
+
+/** Links macro definitions with their implementation.
+ * This is necessary to preserve macro def -> macro impl links between compilation runs.
+ *
+ * More precisely, after typechecking right-hand side of a macro def
+ * `typedMacroBody` slaps `macroImpl` annotation onto the macro def
+ * with the result of typechecking as a sole parameter.
+ *
+ * As an unfortunate consequence, this annotation must be defined in scala-library.jar,
+ * because anyone (even those programmers who compile their programs with only scala-library on classpath)
+ * must be able to define macros.
+ *
+ * To lessen the weirdness we define this annotation as `private[scala]`.
+ * It will not prevent pickling, but it will prevent application developers (and scaladocs) from seeing the annotation.
+ */
+private[scala] final class macroImpl(val referenceToMacroImpl: Any) extends scala.annotation.StaticAnnotation
diff --git a/library/src/scala/reflect/package.scala b/library/src/scala/reflect/package.scala
new file mode 100644
index 000000000000..caf79866c71e
--- /dev/null
+++ b/library/src/scala/reflect/package.scala
@@ -0,0 +1,76 @@
+/*
+ * 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
+
+import java.lang.reflect.{AccessibleObject => jAccessibleObject}
+import scala.annotation.nowarn
+
+package object reflect {
+
+ // in the new scheme of things ClassManifests are aliased to ClassTags
+ // this is done because we want `toArray` in collections work with ClassTags
+ // but changing it to use the ClassTag context bound without aliasing ClassManifest
+ // will break everyone who subclasses and overrides `toArray`
+ // luckily for us, aliasing doesn't hamper backward compatibility, so it's ideal in this situation
+ // I wish we could do the same for Manifests and TypeTags though
+
+ // note, by the way, that we don't touch ClassManifest the object
+ // because its Byte, Short and so on factory fields are incompatible with ClassTag's
+
+ /** A `ClassManifest[T]` is an opaque descriptor for type `T`.
+ * It is used by the compiler to preserve information necessary
+ * for instantiating `Arrays` in those cases where the element type
+ * is unknown at compile time.
+ *
+ * The type-relation operators make an effort to present a more accurate
+ * picture than can be realized with erased types, but they should not be
+ * relied upon to give correct answers. In particular they are likely to
+ * be wrong when variance is involved or when a subtype has a different
+ * number of type arguments than a supertype.
+ */
+ @deprecated("use scala.reflect.ClassTag instead", "2.10.0")
+ @annotation.implicitNotFound(msg = "No ClassManifest available for ${T}.")
+ type ClassManifest[T] = scala.reflect.ClassTag[T]
+
+ /** The object `ClassManifest` defines factory methods for manifests.
+ * It is intended for use by the compiler and should not be used in client code.
+ */
+ @deprecated("use scala.reflect.ClassTag instead", "2.10.0")
+ val ClassManifest = ClassManifestFactory
+
+ def classTag[T](implicit ctag: ClassTag[T]) = ctag
+
+ /** Make a java reflection object accessible, if it is not already
+ * and it is possible to do so. If a SecurityException is thrown in the
+ * attempt, it is caught and discarded.
+ */
+ def ensureAccessible[T <: jAccessibleObject](m: T): T = {
+ // This calls `setAccessible` unnecessarily, because `isAccessible` is only `true` if `setAccessible(true)`
+ // was called before, not if the reflected object is inherently accessible.
+ // TODO: replace by `canAccess` once we're on JDK 9+
+ if (!m.isAccessible: @nowarn("cat=deprecation")) {
+ try m setAccessible true
+ catch { case _: SecurityException => } // does nothing
+ }
+ m
+ }
+
+ // anchor for the class tag materialization macro emitted during tag materialization in Implicits.scala
+ // implementation is hardwired into `scala.reflect.reify.Taggers`
+ // using the mechanism implemented in `scala.tools.reflect.FastTrack`
+ // todo. once we have implicit macros for tag generation, we can remove this anchor
+ private[scala] def materializeClassTag[T](): ClassTag[T] = macro ???
+}
+
+/** An exception that indicates an error during Scala reflection */
+case class ScalaReflectionException(msg: String) extends Exception(msg)
diff --git a/library/src/scala/runtime/AbstractFunction0.scala b/library/src/scala/runtime/AbstractFunction0.scala
new file mode 100644
index 000000000000..c322efcd6281
--- /dev/null
+++ b/library/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/src/scala/runtime/AbstractFunction1.scala b/library/src/scala/runtime/AbstractFunction1.scala
new file mode 100644
index 000000000000..49977d8a1393
--- /dev/null
+++ b/library/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] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction10.scala b/library/src/scala/runtime/AbstractFunction10.scala
new file mode 100644
index 000000000000..121c3cc0d53b
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction10.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 AbstractFunction10[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, +R] extends Function10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction11.scala b/library/src/scala/runtime/AbstractFunction11.scala
new file mode 100644
index 000000000000..c4321c10f142
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction11.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 AbstractFunction11[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, +R] extends Function11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction12.scala b/library/src/scala/runtime/AbstractFunction12.scala
new file mode 100644
index 000000000000..3f6d666f9c42
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction12.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 AbstractFunction12[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, +R] extends Function12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction13.scala b/library/src/scala/runtime/AbstractFunction13.scala
new file mode 100644
index 000000000000..264de0f87296
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction13.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 AbstractFunction13[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, +R] extends Function13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction14.scala b/library/src/scala/runtime/AbstractFunction14.scala
new file mode 100644
index 000000000000..1e92d1e04bae
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction14.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 AbstractFunction14[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, +R] extends Function14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction15.scala b/library/src/scala/runtime/AbstractFunction15.scala
new file mode 100644
index 000000000000..ed9b6b187e39
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction15.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 AbstractFunction15[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, +R] extends Function15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction16.scala b/library/src/scala/runtime/AbstractFunction16.scala
new file mode 100644
index 000000000000..839efed863b6
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction16.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 AbstractFunction16[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, +R] extends Function16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction17.scala b/library/src/scala/runtime/AbstractFunction17.scala
new file mode 100644
index 000000000000..ee91b466ea5b
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction17.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 AbstractFunction17[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, +R] extends Function17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction18.scala b/library/src/scala/runtime/AbstractFunction18.scala
new file mode 100644
index 000000000000..83aaf6b10c44
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction18.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 AbstractFunction18[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, +R] extends Function18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction19.scala b/library/src/scala/runtime/AbstractFunction19.scala
new file mode 100644
index 000000000000..93741656a585
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction19.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 AbstractFunction19[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, +R] extends Function19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction2.scala b/library/src/scala/runtime/AbstractFunction2.scala
new file mode 100644
index 000000000000..7c8d1628e545
--- /dev/null
+++ b/library/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/src/scala/runtime/AbstractFunction20.scala b/library/src/scala/runtime/AbstractFunction20.scala
new file mode 100644
index 000000000000..b2858b27c125
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction20.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 AbstractFunction20[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, +R] extends Function20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction21.scala b/library/src/scala/runtime/AbstractFunction21.scala
new file mode 100644
index 000000000000..e36e6b043959
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction21.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 AbstractFunction21[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, -T21, +R] extends Function21[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction22.scala b/library/src/scala/runtime/AbstractFunction22.scala
new file mode 100644
index 000000000000..f9cf63a9542d
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction22.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 AbstractFunction22[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, -T10, -T11, -T12, -T13, -T14, -T15, -T16, -T17, -T18, -T19, -T20, -T21, -T22, +R] extends Function22[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction3.scala b/library/src/scala/runtime/AbstractFunction3.scala
new file mode 100644
index 000000000000..fbeb3e7b1cf8
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction3.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 AbstractFunction3[-T1, -T2, -T3, +R] extends Function3[T1, T2, T3, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction4.scala b/library/src/scala/runtime/AbstractFunction4.scala
new file mode 100644
index 000000000000..9a91280eea52
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction4.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 AbstractFunction4[-T1, -T2, -T3, -T4, +R] extends Function4[T1, T2, T3, T4, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction5.scala b/library/src/scala/runtime/AbstractFunction5.scala
new file mode 100644
index 000000000000..a7880cdb0a14
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction5.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 AbstractFunction5[-T1, -T2, -T3, -T4, -T5, +R] extends Function5[T1, T2, T3, T4, T5, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction6.scala b/library/src/scala/runtime/AbstractFunction6.scala
new file mode 100644
index 000000000000..0a8c4eeacc70
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction6.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 AbstractFunction6[-T1, -T2, -T3, -T4, -T5, -T6, +R] extends Function6[T1, T2, T3, T4, T5, T6, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction7.scala b/library/src/scala/runtime/AbstractFunction7.scala
new file mode 100644
index 000000000000..d0f18b0dcbd4
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction7.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 AbstractFunction7[-T1, -T2, -T3, -T4, -T5, -T6, -T7, +R] extends Function7[T1, T2, T3, T4, T5, T6, T7, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction8.scala b/library/src/scala/runtime/AbstractFunction8.scala
new file mode 100644
index 000000000000..4f1a528a4ed9
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction8.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 AbstractFunction8[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, +R] extends Function8[T1, T2, T3, T4, T5, T6, T7, T8, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractFunction9.scala b/library/src/scala/runtime/AbstractFunction9.scala
new file mode 100644
index 000000000000..f4ebb395bd5a
--- /dev/null
+++ b/library/src/scala/runtime/AbstractFunction9.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 AbstractFunction9[-T1, -T2, -T3, -T4, -T5, -T6, -T7, -T8, -T9, +R] extends Function9[T1, T2, T3, T4, T5, T6, T7, T8, T9, R] {
+
+}
diff --git a/library/src/scala/runtime/AbstractPartialFunction.scala b/library/src/scala/runtime/AbstractPartialFunction.scala
new file mode 100644
index 000000000000..f4e8ae1b7818
--- /dev/null
+++ b/library/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/src/scala/runtime/ArrayCharSequence.scala b/library/src/scala/runtime/ArrayCharSequence.scala
new file mode 100644
index 000000000000..971b0ac24c0d
--- /dev/null
+++ b/library/src/scala/runtime/ArrayCharSequence.scala
@@ -0,0 +1,47 @@
+/*
+ * 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
+
+// Still need this one since the implicit class ArrayCharSequence only converts
+// a single argument.
+final class ArrayCharSequence(val xs: Array[Char], start: Int, end: Int) extends CharSequence {
+ // yikes
+ // java.lang.VerifyError: (class: scala/runtime/ArrayCharSequence, method: signature: ([C)V)
+ // Constructor must call super() or this()
+ //
+ // def this(xs: Array[Char]) = this(xs, 0, xs.length)
+
+ def length: Int = math.max(0, end - start)
+ def charAt(index: Int): Char = {
+ if (0 <= index && index < length)
+ xs(start + index)
+ else throw new ArrayIndexOutOfBoundsException(s"$index is out of bounds (min 0, max ${xs.length - 1})")
+ }
+ def subSequence(start0: Int, end0: Int): CharSequence = {
+ if (start0 < 0) throw new ArrayIndexOutOfBoundsException(s"$start0 is out of bounds (min 0, max ${length -1})")
+ else if (end0 > length) throw new ArrayIndexOutOfBoundsException(s"$end0 is out of bounds (min 0, max ${xs.length -1})")
+ else if (end0 <= start0) new ArrayCharSequence(xs, 0, 0)
+ else {
+ val newlen = end0 - start0
+ val start1 = start + start0
+ new ArrayCharSequence(xs, start1, start1 + newlen)
+ }
+ }
+ override def toString = {
+ val start = math.max(this.start, 0)
+ val end = math.min(xs.length, start + length)
+
+ if (start >= end) "" else new String(xs, start, end - start)
+ }
+}
diff --git a/library/src/scala/runtime/BooleanRef.java b/library/src/scala/runtime/BooleanRef.java
new file mode 100644
index 000000000000..2c43fd719366
--- /dev/null
+++ b/library/src/scala/runtime/BooleanRef.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+public final class BooleanRef implements java.io.Serializable {
+ private static final long serialVersionUID = -5730524563015615974L;
+
+ public boolean elem;
+ public BooleanRef(boolean elem) { this.elem = elem; }
+ public String toString() { return String.valueOf(elem); }
+
+ public static BooleanRef create(boolean e) { return new BooleanRef(e); }
+ public static BooleanRef zero() { return new BooleanRef(false); }
+}
diff --git a/library/src/scala/runtime/BoxedUnit.java b/library/src/scala/runtime/BoxedUnit.java
new file mode 100644
index 000000000000..aaa986f87f1a
--- /dev/null
+++ b/library/src/scala/runtime/BoxedUnit.java
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+
+public final class BoxedUnit implements java.io.Serializable {
+ private static final long serialVersionUID = 8405543498931817370L;
+
+ public final static BoxedUnit UNIT = new BoxedUnit();
+
+ public final static Class TYPE = java.lang.Void.TYPE;
+
+ private Object readResolve() { return UNIT; }
+
+ private BoxedUnit() { }
+
+ public boolean equals(java.lang.Object other) {
+ return this == other;
+ }
+
+ public int hashCode() {
+ return 0;
+ }
+
+ public String toString() {
+ return "()";
+ }
+}
diff --git a/library/src/scala/runtime/BoxesRunTime.java b/library/src/scala/runtime/BoxesRunTime.java
new file mode 100644
index 000000000000..3ddc2516fbb9
--- /dev/null
+++ b/library/src/scala/runtime/BoxesRunTime.java
@@ -0,0 +1,760 @@
+/*
+ * 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.math.ScalaNumber;
+
+/** An object (static class) that defines methods used for creating,
+ * reverting, and calculating with, boxed values. There are four classes
+ * of methods in this object:
+ * - Convenience boxing methods which call the static valueOf method
+ * on the boxed class, thus utilizing the JVM boxing cache.
+ * - Convenience unboxing methods returning default value on null.
+ * - The generalised comparison method to be used when an object may
+ * be a boxed value.
+ * - Standard value operators for boxed number and quasi-number values.
+ */
+public final class BoxesRunTime
+{
+ private static final int CHAR = 0, /* BYTE = 1, SHORT = 2, */ INT = 3, LONG = 4, FLOAT = 5, DOUBLE = 6, OTHER = 7;
+
+ /** We don't need to return BYTE and SHORT, as everything which might
+ * care widens to INT.
+ */
+ private static int typeCode(Object a) {
+ if (a instanceof java.lang.Integer) return INT;
+ if (a instanceof java.lang.Double) return DOUBLE;
+ if (a instanceof java.lang.Long) return LONG;
+ if (a instanceof java.lang.Character) return CHAR;
+ if (a instanceof java.lang.Float) return FLOAT;
+ if ((a instanceof java.lang.Byte) || (a instanceof java.lang.Short)) return INT;
+ return OTHER;
+ }
+
+/* BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING ... BOXING */
+
+ public static java.lang.Boolean boxToBoolean(boolean b) {
+ return java.lang.Boolean.valueOf(b);
+ }
+
+ public static java.lang.Character boxToCharacter(char c) {
+ return java.lang.Character.valueOf(c);
+ }
+
+ public static java.lang.Byte boxToByte(byte b) {
+ return java.lang.Byte.valueOf(b);
+ }
+
+ public static java.lang.Short boxToShort(short s) {
+ return java.lang.Short.valueOf(s);
+ }
+
+ public static java.lang.Integer boxToInteger(int i) {
+ return java.lang.Integer.valueOf(i);
+ }
+
+ public static java.lang.Long boxToLong(long l) {
+ return java.lang.Long.valueOf(l);
+ }
+
+ public static java.lang.Float boxToFloat(float f) {
+ return java.lang.Float.valueOf(f);
+ }
+
+ public static java.lang.Double boxToDouble(double d) {
+ // System.out.println("box " + d);
+ // (new Throwable()).printStackTrace();
+ return java.lang.Double.valueOf(d);
+ }
+
+/* UNBOXING ... UNBOXING ... UNBOXING ... UNBOXING ... UNBOXING ... UNBOXING ... UNBOXING */
+
+ public static boolean unboxToBoolean(Object b) {
+ return b == null ? false : ((java.lang.Boolean)b).booleanValue();
+ }
+
+ public static char unboxToChar(Object c) {
+ return c == null ? 0 : ((java.lang.Character)c).charValue();
+ }
+
+ public static byte unboxToByte(Object b) {
+ return b == null ? 0 : ((java.lang.Byte)b).byteValue();
+ }
+
+ public static short unboxToShort(Object s) {
+ return s == null ? 0 : ((java.lang.Short)s).shortValue();
+ }
+
+ public static int unboxToInt(Object i) {
+ return i == null ? 0 : ((java.lang.Integer)i).intValue();
+ }
+
+ public static long unboxToLong(Object l) {
+ return l == null ? 0 : ((java.lang.Long)l).longValue();
+ }
+
+ public static float unboxToFloat(Object f) {
+ return f == null ? 0.0f : ((java.lang.Float)f).floatValue();
+ }
+
+ public static double unboxToDouble(Object d) {
+ // System.out.println("unbox " + d);
+ return d == null ? 0.0d : ((java.lang.Double)d).doubleValue();
+ }
+
+ /* COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON ... COMPARISON */
+
+ public static boolean equals(Object x, Object y) {
+ if (x == y) return true;
+ return equals2(x, y);
+ }
+
+ /** Since all applicable logic has to be present in the equals method of a ScalaNumber
+ * in any case, we dispatch to it as soon as we spot one on either side.
+ */
+ public static boolean equals2(Object x, Object y) {
+ if (x instanceof java.lang.Number)
+ return equalsNumObject((java.lang.Number)x, y);
+ if (x instanceof java.lang.Character)
+ return equalsCharObject((java.lang.Character)x, y);
+ if (x == null)
+ return y == null;
+
+ return x.equals(y);
+ }
+
+ public static boolean equalsNumObject(java.lang.Number xn, Object y) {
+ if (y instanceof java.lang.Number)
+ return equalsNumNum(xn, (java.lang.Number)y);
+ if (y instanceof java.lang.Character)
+ return equalsNumChar(xn, (java.lang.Character)y);
+ if (xn == null)
+ return y == null;
+
+ return xn.equals(y);
+ }
+
+ public static boolean equalsNumNum(java.lang.Number xn, java.lang.Number yn) {
+ int xcode = typeCode(xn);
+ int ycode = typeCode(yn);
+ switch (ycode > xcode ? ycode : xcode) {
+ case INT:
+ return xn.intValue() == yn.intValue();
+ case LONG:
+ return xn.longValue() == yn.longValue();
+ case FLOAT:
+ return xn.floatValue() == yn.floatValue();
+ case DOUBLE:
+ return xn.doubleValue() == yn.doubleValue();
+ default:
+ if ((yn instanceof ScalaNumber) && !(xn instanceof ScalaNumber))
+ return yn.equals(xn);
+ }
+ if (xn == null)
+ return yn == null;
+
+ return xn.equals(yn);
+ }
+
+ public static boolean equalsCharObject(java.lang.Character xc, Object y) {
+ if (y instanceof java.lang.Character)
+ return xc.charValue() == ((java.lang.Character)y).charValue();
+ if (y instanceof java.lang.Number)
+ return equalsNumChar((java.lang.Number)y, xc);
+ if (xc == null)
+ return y == null;
+
+ return xc.equals(y);
+ }
+
+ public static boolean equalsNumChar(java.lang.Number xn, java.lang.Character yc) {
+ if (yc == null)
+ return xn == null;
+
+ char ch = yc.charValue();
+ switch (typeCode(xn)) {
+ case INT:
+ return xn.intValue() == ch;
+ case LONG:
+ return xn.longValue() == ch;
+ case FLOAT:
+ return xn.floatValue() == ch;
+ case DOUBLE:
+ return xn.doubleValue() == ch;
+ default:
+ return xn.equals(yc);
+ }
+ }
+
+ private static int unboxCharOrInt(Object arg1, int code) {
+ if (code == CHAR)
+ return ((java.lang.Character) arg1).charValue();
+ else
+ return ((java.lang.Number) arg1).intValue();
+ }
+ private static long unboxCharOrLong(Object arg1, int code) {
+ if (code == CHAR)
+ return ((java.lang.Character) arg1).charValue();
+ else
+ return ((java.lang.Number) arg1).longValue();
+ }
+ private static float unboxCharOrFloat(Object arg1, int code) {
+ if (code == CHAR)
+ return ((java.lang.Character) arg1).charValue();
+ else
+ return ((java.lang.Number) arg1).floatValue();
+ }
+ private static double unboxCharOrDouble(Object arg1, int code) {
+ if (code == CHAR)
+ return ((java.lang.Character) arg1).charValue();
+ else
+ return ((java.lang.Number) arg1).doubleValue();
+ }
+
+/* OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS ... OPERATORS */
+
+ /** arg1 + arg2 */
+ public static Object add(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ return boxToInteger(unboxCharOrInt(arg1, code1) + unboxCharOrInt(arg2, code2));
+ }
+ if (maxcode <= LONG) {
+ return boxToLong(unboxCharOrLong(arg1, code1) + unboxCharOrLong(arg2, code2));
+ }
+ if (maxcode <= FLOAT) {
+ return boxToFloat(unboxCharOrFloat(arg1, code1) + unboxCharOrFloat(arg2, code2));
+ }
+ if (maxcode <= DOUBLE) {
+ return boxToDouble(unboxCharOrDouble(arg1, code1) + unboxCharOrDouble(arg2, code2));
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 - arg2 */
+ public static Object subtract(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ return boxToInteger(unboxCharOrInt(arg1, code1) - unboxCharOrInt(arg2, code2));
+ }
+ if (maxcode <= LONG) {
+ return boxToLong(unboxCharOrLong(arg1, code1) - unboxCharOrLong(arg2, code2));
+ }
+ if (maxcode <= FLOAT) {
+ return boxToFloat(unboxCharOrFloat(arg1, code1) - unboxCharOrFloat(arg2, code2));
+ }
+ if (maxcode <= DOUBLE) {
+ return boxToDouble(unboxCharOrDouble(arg1, code1) - unboxCharOrDouble(arg2, code2));
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 * arg2 */
+ public static Object multiply(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ return boxToInteger(unboxCharOrInt(arg1, code1) * unboxCharOrInt(arg2, code2));
+ }
+ if (maxcode <= LONG) {
+ return boxToLong(unboxCharOrLong(arg1, code1) * unboxCharOrLong(arg2, code2));
+ }
+ if (maxcode <= FLOAT) {
+ return boxToFloat(unboxCharOrFloat(arg1, code1) * unboxCharOrFloat(arg2, code2));
+ }
+ if (maxcode <= DOUBLE) {
+ return boxToDouble(unboxCharOrDouble(arg1, code1) * unboxCharOrDouble(arg2, code2));
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 / arg2 */
+ public static Object divide(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+
+ if (maxcode <= INT)
+ return boxToInteger(unboxCharOrInt(arg1, code1) / unboxCharOrInt(arg2, code2));
+ if (maxcode <= LONG)
+ return boxToLong(unboxCharOrLong(arg1, code1) / unboxCharOrLong(arg2, code2));
+ if (maxcode <= FLOAT)
+ return boxToFloat(unboxCharOrFloat(arg1, code1) / unboxCharOrFloat(arg2, code2));
+ if (maxcode <= DOUBLE)
+ return boxToDouble(unboxCharOrDouble(arg1, code1) / unboxCharOrDouble(arg2, code2));
+
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 % arg2 */
+ public static Object takeModulo(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+
+ if (maxcode <= INT)
+ return boxToInteger(unboxCharOrInt(arg1, code1) % unboxCharOrInt(arg2, code2));
+ if (maxcode <= LONG)
+ return boxToLong(unboxCharOrLong(arg1, code1) % unboxCharOrLong(arg2, code2));
+ if (maxcode <= FLOAT)
+ return boxToFloat(unboxCharOrFloat(arg1, code1) % unboxCharOrFloat(arg2, code2));
+ if (maxcode <= DOUBLE)
+ return boxToDouble(unboxCharOrDouble(arg1, code1) % unboxCharOrDouble(arg2, code2));
+
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 >> arg2 */
+ public static Object shiftSignedRight(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ if (code1 <= INT) {
+ int val1 = unboxCharOrInt(arg1, code1);
+ if (code2 <= INT) {
+ int val2 = unboxCharOrInt(arg2, code2);
+ return boxToInteger(val1 >> val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = unboxCharOrLong(arg2, code2);
+ return boxToInteger(val1 >> val2);
+ }
+ }
+ if (code1 <= LONG) {
+ long val1 = unboxCharOrLong(arg1, code1);
+ if (code2 <= INT) {
+ int val2 = unboxCharOrInt(arg2, code2);
+ return boxToLong(val1 >> val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = unboxCharOrLong(arg2, code2);
+ return boxToLong(val1 >> val2);
+ }
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 << arg2 */
+ public static Object shiftSignedLeft(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ if (code1 <= INT) {
+ int val1 = unboxCharOrInt(arg1, code1);
+ if (code2 <= INT) {
+ int val2 = unboxCharOrInt(arg2, code2);
+ return boxToInteger(val1 << val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = unboxCharOrLong(arg2, code2);
+ return boxToInteger(val1 << val2);
+ }
+ }
+ if (code1 <= LONG) {
+ long val1 = unboxCharOrLong(arg1, code1);
+ if (code2 <= INT) {
+ int val2 = unboxCharOrInt(arg2, code2);
+ return boxToLong(val1 << val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = unboxCharOrLong(arg2, code2);
+ return boxToLong(val1 << val2);
+ }
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 >>> arg2 */
+ public static Object shiftLogicalRight(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ if (code1 <= INT) {
+ int val1 = unboxCharOrInt(arg1, code1);
+ if (code2 <= INT) {
+ int val2 = unboxCharOrInt(arg2, code2);
+ return boxToInteger(val1 >>> val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = unboxCharOrLong(arg2, code2);
+ return boxToInteger(val1 >>> val2);
+ }
+ }
+ if (code1 <= LONG) {
+ long val1 = unboxCharOrLong(arg1, code1);
+ if (code2 <= INT) {
+ int val2 = unboxCharOrInt(arg2, code2);
+ return boxToLong(val1 >>> val2);
+ }
+ if (code2 <= LONG) {
+ long val2 = unboxCharOrLong(arg2, code2);
+ return boxToLong(val1 >>> val2);
+ }
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** -arg */
+ public static Object negate(Object arg) throws NoSuchMethodException {
+ int code = typeCode(arg);
+ if (code <= INT) {
+ int val = unboxCharOrInt(arg, code);
+ return boxToInteger(-val);
+ }
+ if (code <= LONG) {
+ long val = unboxCharOrLong(arg, code);
+ return boxToLong(-val);
+ }
+ if (code <= FLOAT) {
+ float val = unboxCharOrFloat(arg, code);
+ return boxToFloat(-val);
+ }
+ if (code <= DOUBLE) {
+ double val = unboxCharOrDouble(arg, code);
+ return boxToDouble(-val);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** +arg */
+ public static Object positive(Object arg) throws NoSuchMethodException {
+ int code = typeCode(arg);
+ if (code <= INT) {
+ return boxToInteger(+unboxCharOrInt(arg, code));
+ }
+ if (code <= LONG) {
+ return boxToLong(+unboxCharOrLong(arg, code));
+ }
+ if (code <= FLOAT) {
+ return boxToFloat(+unboxCharOrFloat(arg, code));
+ }
+ if (code <= DOUBLE) {
+ return boxToDouble(+unboxCharOrDouble(arg, code));
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 & arg2 */
+ public static Object takeAnd(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) || (arg2 instanceof Boolean)) {
+ if ((arg1 instanceof Boolean) && (arg2 instanceof Boolean))
+ return boxToBoolean(((java.lang.Boolean) arg1).booleanValue() & ((java.lang.Boolean) arg2).booleanValue());
+ else
+ throw new NoSuchMethodException();
+ }
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+
+ if (maxcode <= INT)
+ return boxToInteger(unboxCharOrInt(arg1, code1) & unboxCharOrInt(arg2, code2));
+ if (maxcode <= LONG)
+ return boxToLong(unboxCharOrLong(arg1, code1) & unboxCharOrLong(arg2, code2));
+
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 | arg2 */
+ public static Object takeOr(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) || (arg2 instanceof Boolean)) {
+ if ((arg1 instanceof Boolean) && (arg2 instanceof Boolean))
+ return boxToBoolean(((java.lang.Boolean) arg1).booleanValue() | ((java.lang.Boolean) arg2).booleanValue());
+ else
+ throw new NoSuchMethodException();
+ }
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+
+ if (maxcode <= INT)
+ return boxToInteger(unboxCharOrInt(arg1, code1) | unboxCharOrInt(arg2, code2));
+ if (maxcode <= LONG)
+ return boxToLong(unboxCharOrLong(arg1, code1) | unboxCharOrLong(arg2, code2));
+
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 ^ arg2 */
+ public static Object takeXor(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) || (arg2 instanceof Boolean)) {
+ if ((arg1 instanceof Boolean) && (arg2 instanceof Boolean))
+ return boxToBoolean(((java.lang.Boolean) arg1).booleanValue() ^ ((java.lang.Boolean) arg2).booleanValue());
+ else
+ throw new NoSuchMethodException();
+ }
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+
+ if (maxcode <= INT)
+ return boxToInteger(unboxCharOrInt(arg1, code1) ^ unboxCharOrInt(arg2, code2));
+ if (maxcode <= LONG)
+ return boxToLong(unboxCharOrLong(arg1, code1) ^ unboxCharOrLong(arg2, code2));
+
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 && arg2 */
+ public static Object takeConditionalAnd(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) && (arg2 instanceof Boolean)) {
+ return boxToBoolean(((java.lang.Boolean) arg1).booleanValue() && ((java.lang.Boolean) arg2).booleanValue());
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** arg1 || arg2 */
+ public static Object takeConditionalOr(Object arg1, Object arg2) throws NoSuchMethodException {
+ if ((arg1 instanceof Boolean) && (arg2 instanceof Boolean)) {
+ return boxToBoolean(((java.lang.Boolean) arg1).booleanValue() || ((java.lang.Boolean) arg2).booleanValue());
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** ~arg */
+ public static Object complement(Object arg) throws NoSuchMethodException {
+ int code = typeCode(arg);
+ if (code <= INT) {
+ return boxToInteger(~unboxCharOrInt(arg, code));
+ }
+ if (code <= LONG) {
+ return boxToLong(~unboxCharOrLong(arg, code));
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** !arg */
+ public static Object takeNot(Object arg) throws NoSuchMethodException {
+ if (arg instanceof Boolean) {
+ return boxToBoolean(!((java.lang.Boolean) arg).booleanValue());
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public static Object testEqual(Object arg1, Object arg2) throws NoSuchMethodException {
+ return boxToBoolean(arg1 == arg2);
+ }
+
+ public static Object testNotEqual(Object arg1, Object arg2) throws NoSuchMethodException {
+ return boxToBoolean(arg1 != arg2);
+ }
+
+ public static Object testLessThan(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = unboxCharOrInt(arg1, code1);
+ int val2 = unboxCharOrInt(arg2, code2);
+ return boxToBoolean(val1 < val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = unboxCharOrLong(arg1, code1);
+ long val2 = unboxCharOrLong(arg2, code2);
+ return boxToBoolean(val1 < val2);
+ }
+ if (maxcode <= FLOAT) {
+ float val1 = unboxCharOrFloat(arg1, code1);
+ float val2 = unboxCharOrFloat(arg2, code2);
+ return boxToBoolean(val1 < val2);
+ }
+ if (maxcode <= DOUBLE) {
+ double val1 = unboxCharOrDouble(arg1, code1);
+ double val2 = unboxCharOrDouble(arg2, code2);
+ return boxToBoolean(val1 < val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public static Object testLessOrEqualThan(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = unboxCharOrInt(arg1, code1);
+ int val2 = unboxCharOrInt(arg2, code2);
+ return boxToBoolean(val1 <= val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = unboxCharOrLong(arg1, code1);
+ long val2 = unboxCharOrLong(arg2, code2);
+ return boxToBoolean(val1 <= val2);
+ }
+ if (maxcode <= FLOAT) {
+ float val1 = unboxCharOrFloat(arg1, code1);
+ float val2 = unboxCharOrFloat(arg2, code2);
+ return boxToBoolean(val1 <= val2);
+ }
+ if (maxcode <= DOUBLE) {
+ double val1 = unboxCharOrDouble(arg1, code1);
+ double val2 = unboxCharOrDouble(arg2, code2);
+ return boxToBoolean(val1 <= val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public static Object testGreaterOrEqualThan(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = unboxCharOrInt(arg1, code1);
+ int val2 = unboxCharOrInt(arg2, code2);
+ return boxToBoolean(val1 >= val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = unboxCharOrLong(arg1, code1);
+ long val2 = unboxCharOrLong(arg2, code2);
+ return boxToBoolean(val1 >= val2);
+ }
+ if (maxcode <= FLOAT) {
+ float val1 = unboxCharOrFloat(arg1, code1);
+ float val2 = unboxCharOrFloat(arg2, code2);
+ return boxToBoolean(val1 >= val2);
+ }
+ if (maxcode <= DOUBLE) {
+ double val1 = unboxCharOrDouble(arg1, code1);
+ double val2 = unboxCharOrDouble(arg2, code2);
+ return boxToBoolean(val1 >= val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public static Object testGreaterThan(Object arg1, Object arg2) throws NoSuchMethodException {
+ int code1 = typeCode(arg1);
+ int code2 = typeCode(arg2);
+ int maxcode = (code1 < code2) ? code2 : code1;
+ if (maxcode <= INT) {
+ int val1 = unboxCharOrInt(arg1, code1);
+ int val2 = unboxCharOrInt(arg2, code2);
+ return boxToBoolean(val1 > val2);
+ }
+ if (maxcode <= LONG) {
+ long val1 = unboxCharOrLong(arg1, code1);
+ long val2 = unboxCharOrLong(arg2, code2);
+ return boxToBoolean(val1 > val2);
+ }
+ if (maxcode <= FLOAT) {
+ float val1 = unboxCharOrFloat(arg1, code1);
+ float val2 = unboxCharOrFloat(arg2, code2);
+ return boxToBoolean(val1 > val2);
+ }
+ if (maxcode <= DOUBLE) {
+ double val1 = unboxCharOrDouble(arg1, code1);
+ double val2 = unboxCharOrDouble(arg2, code2);
+ return boxToBoolean(val1 > val2);
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public static boolean isBoxedNumberOrBoolean(Object arg) {
+ return (arg instanceof java.lang.Boolean) || isBoxedNumber(arg);
+ }
+ public static boolean isBoxedNumber(Object arg) {
+ return (
+ (arg instanceof java.lang.Integer)
+ || (arg instanceof java.lang.Long)
+ || (arg instanceof java.lang.Double)
+ || (arg instanceof java.lang.Float)
+ || (arg instanceof java.lang.Short)
+ || (arg instanceof java.lang.Character)
+ || (arg instanceof java.lang.Byte)
+ );
+ }
+
+ /** arg.toChar */
+ public static java.lang.Character toCharacter(Object arg) throws NoSuchMethodException {
+ if (arg instanceof java.lang.Integer) return boxToCharacter((char)unboxToInt(arg));
+ if (arg instanceof java.lang.Short) return boxToCharacter((char)unboxToShort(arg));
+ if (arg instanceof java.lang.Character) return (java.lang.Character)arg;
+ if (arg instanceof java.lang.Long) return boxToCharacter((char)unboxToLong(arg));
+ if (arg instanceof java.lang.Byte) return boxToCharacter((char)unboxToByte(arg));
+ if (arg instanceof java.lang.Float) return boxToCharacter((char)unboxToFloat(arg));
+ if (arg instanceof java.lang.Double) return boxToCharacter((char)unboxToDouble(arg));
+ throw new NoSuchMethodException();
+ }
+
+ /** arg.toByte */
+ public static java.lang.Byte toByte(Object arg) throws NoSuchMethodException {
+ if (arg instanceof java.lang.Integer) return boxToByte((byte)unboxToInt(arg));
+ if (arg instanceof java.lang.Character) return boxToByte((byte)unboxToChar(arg));
+ if (arg instanceof java.lang.Byte) return (java.lang.Byte)arg;
+ if (arg instanceof java.lang.Long) return boxToByte((byte)unboxToLong(arg));
+ if (arg instanceof java.lang.Short) return boxToByte((byte)unboxToShort(arg));
+ if (arg instanceof java.lang.Float) return boxToByte((byte)unboxToFloat(arg));
+ if (arg instanceof java.lang.Double) return boxToByte((byte)unboxToDouble(arg));
+ throw new NoSuchMethodException();
+ }
+
+ /** arg.toShort */
+ public static java.lang.Short toShort(Object arg) throws NoSuchMethodException {
+ if (arg instanceof java.lang.Integer) return boxToShort((short)unboxToInt(arg));
+ if (arg instanceof java.lang.Long) return boxToShort((short)unboxToLong(arg));
+ if (arg instanceof java.lang.Character) return boxToShort((short)unboxToChar(arg));
+ if (arg instanceof java.lang.Byte) return boxToShort((short)unboxToByte(arg));
+ if (arg instanceof java.lang.Short) return (java.lang.Short)arg;
+ if (arg instanceof java.lang.Float) return boxToShort((short)unboxToFloat(arg));
+ if (arg instanceof java.lang.Double) return boxToShort((short)unboxToDouble(arg));
+ throw new NoSuchMethodException();
+ }
+
+ /** arg.toInt */
+ public static java.lang.Integer toInteger(Object arg) throws NoSuchMethodException {
+ if (arg instanceof java.lang.Integer) return (java.lang.Integer)arg;
+ if (arg instanceof java.lang.Long) return boxToInteger((int)unboxToLong(arg));
+ if (arg instanceof java.lang.Double) return boxToInteger((int)unboxToDouble(arg));
+ if (arg instanceof java.lang.Float) return boxToInteger((int)unboxToFloat(arg));
+ if (arg instanceof java.lang.Character) return boxToInteger((int)unboxToChar(arg));
+ if (arg instanceof java.lang.Byte) return boxToInteger((int)unboxToByte(arg));
+ if (arg instanceof java.lang.Short) return boxToInteger((int)unboxToShort(arg));
+ throw new NoSuchMethodException();
+ }
+
+ /** arg.toLong */
+ public static java.lang.Long toLong(Object arg) throws NoSuchMethodException {
+ if (arg instanceof java.lang.Integer) return boxToLong((long)unboxToInt(arg));
+ if (arg instanceof java.lang.Double) return boxToLong((long)unboxToDouble(arg));
+ if (arg instanceof java.lang.Float) return boxToLong((long)unboxToFloat(arg));
+ if (arg instanceof java.lang.Long) return (java.lang.Long)arg;
+ if (arg instanceof java.lang.Character) return boxToLong((long)unboxToChar(arg));
+ if (arg instanceof java.lang.Byte) return boxToLong((long)unboxToByte(arg));
+ if (arg instanceof java.lang.Short) return boxToLong((long)unboxToShort(arg));
+ throw new NoSuchMethodException();
+ }
+
+ /** arg.toFloat */
+ public static java.lang.Float toFloat(Object arg) throws NoSuchMethodException {
+ if (arg instanceof java.lang.Integer) return boxToFloat((float)unboxToInt(arg));
+ if (arg instanceof java.lang.Long) return boxToFloat((float)unboxToLong(arg));
+ if (arg instanceof java.lang.Float) return (java.lang.Float)arg;
+ if (arg instanceof java.lang.Double) return boxToFloat((float)unboxToDouble(arg));
+ if (arg instanceof java.lang.Character) return boxToFloat((float)unboxToChar(arg));
+ if (arg instanceof java.lang.Byte) return boxToFloat((float)unboxToByte(arg));
+ if (arg instanceof java.lang.Short) return boxToFloat((float)unboxToShort(arg));
+ throw new NoSuchMethodException();
+ }
+
+ /** arg.toDouble */
+ public static java.lang.Double toDouble(Object arg) throws NoSuchMethodException {
+ if (arg instanceof java.lang.Integer) return boxToDouble((double)unboxToInt(arg));
+ if (arg instanceof java.lang.Float) return boxToDouble((double)unboxToFloat(arg));
+ if (arg instanceof java.lang.Double) return (java.lang.Double)arg;
+ if (arg instanceof java.lang.Long) return boxToDouble((double)unboxToLong(arg));
+ if (arg instanceof java.lang.Character) return boxToDouble((double)unboxToChar(arg));
+ if (arg instanceof java.lang.Byte) return boxToDouble((double)unboxToByte(arg));
+ if (arg instanceof java.lang.Short) return boxToDouble((double)unboxToShort(arg));
+ throw new NoSuchMethodException();
+ }
+
+}
diff --git a/library/src/scala/runtime/ByteRef.java b/library/src/scala/runtime/ByteRef.java
new file mode 100644
index 000000000000..4630440fd7a7
--- /dev/null
+++ b/library/src/scala/runtime/ByteRef.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+public final class ByteRef implements java.io.Serializable {
+ private static final long serialVersionUID = -100666928446877072L;
+
+ public byte elem;
+ public ByteRef(byte elem) { this.elem = elem; }
+ public String toString() { return java.lang.Byte.toString(elem); }
+
+ public static ByteRef create(byte e) { return new ByteRef(e); }
+ public static ByteRef zero() { return new ByteRef((byte)0); }
+}
diff --git a/library/src/scala/runtime/CharRef.java b/library/src/scala/runtime/CharRef.java
new file mode 100644
index 000000000000..05e8fa55c982
--- /dev/null
+++ b/library/src/scala/runtime/CharRef.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+public final class CharRef implements java.io.Serializable {
+ private static final long serialVersionUID = 6537214938268005702L;
+
+ public char elem;
+ public CharRef(char elem) { this.elem = elem; }
+ public String toString() { return java.lang.Character.toString(elem); }
+
+ public static CharRef create(char e) { return new CharRef(e); }
+ public static CharRef zero() { return new CharRef((char)0); }
+}
diff --git a/library/src/scala/runtime/ClassValueCompat.scala b/library/src/scala/runtime/ClassValueCompat.scala
new file mode 100644
index 000000000000..09a619f7a5f5
--- /dev/null
+++ b/library/src/scala/runtime/ClassValueCompat.scala
@@ -0,0 +1,53 @@
+/*
+ * 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.runtime.ClassValueCompat._
+
+private[scala] abstract class ClassValueCompat[T] extends ClassValueInterface[T] { self =>
+ private val instance: ClassValueInterface[T] =
+ if (classValueAvailable) new JavaClassValue()
+ else new FallbackClassValue()
+
+ private class JavaClassValue extends ClassValue[T] with ClassValueInterface[T] {
+ override def computeValue(cls: Class[_]): T = self.computeValue(cls)
+ }
+
+ private class FallbackClassValue extends ClassValueInterface[T] {
+ override def get(cls: Class[_]): T = self.computeValue(cls)
+
+ override def remove(cls: Class[_]): Unit = {}
+ }
+
+ def get(cls: Class[_]): T = instance.get(cls)
+
+ def remove(cls: Class[_]): Unit = instance.remove(cls)
+
+ protected def computeValue(cls: Class[_]): T
+}
+
+private[scala] object ClassValueCompat {
+ trait ClassValueInterface[T] {
+ def get(cls: Class[_]): T
+
+ def remove(cls: Class[_]): Unit
+ }
+
+ private val classValueAvailable: Boolean = try {
+ Class.forName("java.lang.ClassValue", false, classOf[Object].getClassLoader)
+ true
+ } catch {
+ case _: ClassNotFoundException => false
+ }
+}
diff --git a/library/src/scala/runtime/DoubleRef.java b/library/src/scala/runtime/DoubleRef.java
new file mode 100644
index 000000000000..52b40cde396e
--- /dev/null
+++ b/library/src/scala/runtime/DoubleRef.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+public final class DoubleRef implements java.io.Serializable {
+ private static final long serialVersionUID = 8304402127373655534L;
+
+ public double elem;
+ public DoubleRef(double elem) { this.elem = elem; }
+ public String toString() { return java.lang.Double.toString(elem); }
+
+ public static DoubleRef create(double e) { return new DoubleRef(e); }
+ public static DoubleRef zero() { return new DoubleRef(0); }
+}
diff --git a/library/src/scala/runtime/FloatRef.java b/library/src/scala/runtime/FloatRef.java
new file mode 100644
index 000000000000..d28d62a0ccc2
--- /dev/null
+++ b/library/src/scala/runtime/FloatRef.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+public final class FloatRef implements java.io.Serializable {
+ private static final long serialVersionUID = -5793980990371366933L;
+
+ public float elem;
+ public FloatRef(float elem) { this.elem = elem; }
+ public String toString() { return java.lang.Float.toString(elem); }
+
+ public static FloatRef create(float e) { return new FloatRef(e); }
+ public static FloatRef zero() { return new FloatRef(0); }
+}
diff --git a/library/src/scala/runtime/IntRef.java b/library/src/scala/runtime/IntRef.java
new file mode 100644
index 000000000000..d456c3a750b3
--- /dev/null
+++ b/library/src/scala/runtime/IntRef.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+public final class IntRef implements java.io.Serializable {
+ private static final long serialVersionUID = 1488197132022872888L;
+
+ public int elem;
+ public IntRef(int elem) { this.elem = elem; }
+ public String toString() { return java.lang.Integer.toString(elem); }
+
+ public static IntRef create(int e) { return new IntRef(e); }
+ public static IntRef zero() { return new IntRef(0); }
+}
diff --git a/library/src/scala/runtime/LambdaDeserialize.scala b/library/src/scala/runtime/LambdaDeserialize.scala
new file mode 100644
index 000000000000..b4270d63e643
--- /dev/null
+++ b/library/src/scala/runtime/LambdaDeserialize.scala
@@ -0,0 +1,44 @@
+/*
+ * 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 java.lang.invoke._
+import java.util
+
+import scala.annotation.varargs
+import scala.collection.immutable
+
+final class LambdaDeserialize private (lookup: MethodHandles.Lookup, targetMethods: Array[MethodHandle]) {
+ private val targetMethodMap: util.HashMap[String, MethodHandle] = new util.HashMap[String, MethodHandle](targetMethods.length)
+
+ for (targetMethod <- targetMethods) {
+ val info = lookup.revealDirect(targetMethod)
+ val key = LambdaDeserialize.nameAndDescriptorKey(info.getName, info.getMethodType.toMethodDescriptorString)
+ targetMethodMap.put(key, targetMethod)
+ }
+
+ private val cache = new util.HashMap[String, MethodHandle]
+
+ def deserializeLambda(serialized: SerializedLambda): AnyRef = LambdaDeserializer.deserializeLambda(lookup, cache, targetMethodMap, serialized)
+}
+
+object LambdaDeserialize {
+ @varargs @throws[Throwable]
+ def bootstrap(lookup: MethodHandles.Lookup, invokedName: String, invokedType: MethodType, targetMethods: MethodHandle*): CallSite = {
+ val targetMethodsArray = targetMethods.asInstanceOf[immutable.ArraySeq[_]].unsafeArray.asInstanceOf[Array[MethodHandle]]
+ val exact = MethodHandleConstants.LAMBDA_DESERIALIZE_DESERIALIZE_LAMBDA.bindTo(new LambdaDeserialize(lookup, targetMethodsArray)).asType(invokedType)
+ new ConstantCallSite(exact)
+ }
+
+ def nameAndDescriptorKey(name: String, descriptor: String): String = name + descriptor
+}
diff --git a/library/src/scala/runtime/LambdaDeserializer.scala b/library/src/scala/runtime/LambdaDeserializer.scala
new file mode 100644
index 000000000000..76fc5d778bec
--- /dev/null
+++ b/library/src/scala/runtime/LambdaDeserializer.scala
@@ -0,0 +1,129 @@
+/*
+ * 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 java.lang.invoke._
+
+/**
+ * This class is only intended to be called by synthetic `$deserializeLambda$` method that the Scala 2.12
+ * compiler will add to classes hosting lambdas.
+ *
+ * It is not intended to be consumed directly.
+ */
+object LambdaDeserializer {
+ /**
+ * Deserialize a lambda by calling `LambdaMetafactory.altMetafactory` to spin up a lambda class
+ * and instantiating this class with the captured arguments.
+ *
+ * A cache may be provided to ensure that subsequent deserialization of the same lambda expression
+ * is cheap, it amounts to a reflective call to the constructor of the previously created class.
+ * However, deserialization of the same lambda expression is not guaranteed to use the same class,
+ * concurrent deserialization of the same lambda expression may spin up more than one class.
+ *
+ * Assumptions:
+ * - No additional marker interfaces are required beyond `java.io.Serializable`. These are
+ * not stored in `SerializedLambda`, so we can't reconstitute them.
+ * - No additional bridge methods are passed to `altMetafactory`. Again, these are not stored.
+ *
+ * @param lookup The factory for method handles. Must have access to the implementation method, the
+ * functional interface class, and `java.io.Serializable`.
+ * @param cache A cache used to avoid spinning up a class for each deserialization of a given lambda. May be `null`
+ * @param serialized The lambda to deserialize. Note that this is typically created by the `readResolve`
+ * member of the anonymous class created by `LambdaMetaFactory`.
+ * @return An instance of the functional interface
+ */
+ def deserializeLambda(lookup: MethodHandles.Lookup, cache: java.util.Map[String, MethodHandle],
+ targetMethodMap: java.util.Map[String, MethodHandle], serialized: SerializedLambda): AnyRef = {
+ val result = deserializeLambdaOrNull(lookup, cache, targetMethodMap, serialized)
+ if (result == null) throw new IllegalArgumentException("Illegal lambda deserialization")
+ else result
+ }
+
+ def deserializeLambdaOrNull(lookup: MethodHandles.Lookup, cache: java.util.Map[String, MethodHandle],
+ targetMethodMap: java.util.Map[String, MethodHandle], serialized: SerializedLambda): AnyRef = {
+ assert(targetMethodMap != null)
+ def slashDot(name: String) = name.replaceAll("/", ".")
+ val loader = lookup.lookupClass().getClassLoader
+ val implClass = loader.loadClass(slashDot(serialized.getImplClass))
+ val key = LambdaDeserialize.nameAndDescriptorKey(serialized.getImplMethodName, serialized.getImplMethodSignature)
+
+ def makeCallSite: CallSite = {
+ import serialized._
+ def parseDescriptor(s: String) =
+ MethodType.fromMethodDescriptorString(s, loader)
+
+ val funcInterfaceSignature = parseDescriptor(getFunctionalInterfaceMethodSignature)
+ val instantiated = parseDescriptor(getInstantiatedMethodType)
+ val functionalInterfaceClass = loader.loadClass(slashDot(getFunctionalInterfaceClass))
+
+ val implMethodSig = parseDescriptor(getImplMethodSignature)
+ // Construct the invoked type from the impl method type. This is the type of a factory
+ // that will be generated by the meta-factory. It is a method type, with param types
+ // coming form the types of the captures, and return type being the functional interface.
+ val invokedType: MethodType = {
+ // 1. Add receiver for non-static impl methods
+ val withReceiver = getImplMethodKind match {
+ case MethodHandleInfo.REF_invokeStatic | MethodHandleInfo.REF_newInvokeSpecial =>
+ implMethodSig
+ case _ =>
+ implMethodSig.insertParameterTypes(0, implClass)
+ }
+ // 2. Remove lambda parameters, leaving only captures. Note: the receiver may be a lambda parameter,
+ // such as in `Function