diff --git a/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala b/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala index a9fe59c56463..01efe1559de3 100644 --- a/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/BootstrappedOnlyCompilationTests.scala @@ -128,7 +128,7 @@ class BootstrappedOnlyCompilationTests { val basicTests = List( compileFilesInDir("tests/run-with-compiler", withCompilerOptions), compileFilesInDir("tests/run-staging", withStagingOptions), - compileFilesInDir("tests/run-custom-args/tasty-inspector", withTastyInspectorOptions) + compileFilesInDir("tests/run-tasty-inspector", withTastyInspectorOptions) ) val tests = if scala.util.Properties.isWin then basicTests diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index 5051e8244f23..e0ed71914ca4 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -50,7 +50,6 @@ class CompilationTests { compileFilesInDir("tests/pos-custom-args/no-experimental", defaultOptions.and("-Yno-experimental")), compileFilesInDir("tests/pos-custom-args/strict", defaultOptions.and("-source", "future", "-deprecation", "-Xfatal-warnings")), compileDir("tests/pos-special/java-param-names", defaultOptions.withJavacOnlyOptions("-parameters")), - compileDir("tests/pos-special/stdlib", defaultOptions), compileFile( // succeeds despite -Xfatal-warnings because of -nowarn "tests/neg-custom-args/fatal-warnings/xfatalWarnings.scala", diff --git a/tests/neg/i9685bis.check b/tests/neg/i9685bis.check deleted file mode 100644 index 1cc81df9987c..000000000000 --- a/tests/neg/i9685bis.check +++ /dev/null @@ -1,9 +0,0 @@ --- [E008] Not Found Error: tests/neg/i9685bis.scala:25:4 --------------------------------------------------------------- -25 | 1.asdf // error - | ^^^^^^ - | value asdf is not a member of Int, but could be made available as an extension method. - | - | The following import might make progress towards fixing the problem: - | - | import foo.Baz.toBaz - | diff --git a/tests/neg/i9685bis.scala b/tests/neg/i9685bis.scala deleted file mode 100644 index 7f95e4fe3ff7..000000000000 --- a/tests/neg/i9685bis.scala +++ /dev/null @@ -1,25 +0,0 @@ -// scalac: -source future - -package foo - -import scala.language.implicitConversions - -class Foo - -object Foo: - - inline implicit def toFoo(x: Int): Foo = Foo() - -class Bar - -object Bar: - inline given Conversion[Int, Bar] with - def apply(x: Int): Bar = Bar() - -class Baz - -object Baz: - transparent inline implicit def toBaz(x: Int): Baz = Baz() - -object Usage: - 1.asdf // error diff --git a/tests/pos-special/stdlib/Test1.scala b/tests/pos-special/stdlib/Test1.scala deleted file mode 100644 index e5ae39027f94..000000000000 --- a/tests/pos-special/stdlib/Test1.scala +++ /dev/null @@ -1,34 +0,0 @@ -import language.experimental.captureChecking -import collection.{View, Seq} -import collection.mutable.{ArrayBuffer, ListBuffer} - -import java.io.* - -object Test0: - - def usingLogFile[sealed T](op: FileOutputStream^ => T): T = - val logFile = FileOutputStream("log") - val result = op(logFile) - logFile.close() - result - - def test(xs: List[Int]) = - usingLogFile: f => - xs.map: x => - f.write(x) - x * x - -object Test1: - def test(it: Iterator[Int]^, v: View[Int]^) = - val isEven: Int => Boolean = _ % 2 == 0 - val it2 = it.filter(isEven) - val _: Iterator[Int]^{it, isEven} = it2 - val it2c: Iterator[Int]^{it2} = it2 - val v2 = v.filter(isEven) - val _: View[Int]^{v, isEven} = v2 - val v2c: View[Int]^{v2} = v2 - val v3 = v.drop(2) - val _: View[Int]^{v} = v3 - val v3c: View[Int]^{v3} = v3 - val (xs6, xs7) = v.partition(isEven) - val (xs6a, xs7a) = v.partition(_ % 2 == 0) diff --git a/tests/pos-special/stdlib/Test2.scala b/tests/pos-special/stdlib/Test2.scala deleted file mode 100644 index cab9440c17db..000000000000 --- a/tests/pos-special/stdlib/Test2.scala +++ /dev/null @@ -1,232 +0,0 @@ -import scala.reflect.ClassTag -import language.experimental.captureChecking -import collection.{View, Seq} -import collection.mutable.{ArrayBuffer, ListBuffer} - -object Test { - - def seqOps(xs: Seq[Int]) = { // try with Seq[Int]^{cap} - val strPlusInt: (String, Int) => String = _ + _ - val intPlusStr: (Int, String) => String = _ + _ - val isEven: Int => Boolean = _ % 2 == 0 - val isNonNeg: Int => Boolean = _ > 0 - val flips: Int => List[Int] = x => x :: -x :: Nil - val x1 = xs.foldLeft("")(strPlusInt) - val y1: String = x1 - val x2 = xs.foldRight("")(intPlusStr) - val y2: String = x2 - val x3 = xs.indexWhere(isEven) - val y3: Int = x3 - val x4 = xs.head - val y4: Int = x4 - val x5 = xs.to(List) - val y5: List[Int] = x5 - val (xs6, xs7) = xs.partition(isEven) - val ys6: Seq[Int] = xs6 - val ys7: Seq[Int] = xs7 - val xs8 = xs.drop(2) - val ys8: Seq[Int] = xs8 - val xs9 = xs.map(isNonNeg) - val ys9: Seq[Boolean] = xs9 - val xs10 = xs.flatMap(flips) - val ys10: Seq[Int] = xs10 - val xs11 = xs ++ xs - val ys11: Seq[Int] = xs11 - val xs12 = xs ++ Nil - val ys12: Seq[Int] = xs12 - val xs13 = Nil ++ xs - val ys13: Seq[Int] = xs13 - val xs14 = xs ++ ("a" :: Nil) - val ys14: Seq[Any] = xs14 - val xs15 = xs.zip(xs9) - val ys15: Seq[(Int, Boolean)] = xs15 - val xs16 = xs.reverse - val ys16: Seq[Int] = xs16 - println("-------") - println(x1) - println(x2) - println(x3) - println(x4) - println(x5) - println(xs6) - println(xs7) - println(xs8) - println(xs9) - println(xs10) - println(xs11) - println(xs12) - println(xs13) - println(xs14) - println(xs15) - println(xs16) - } - - def iterOps(xs: => Iterator[Int]^) = - val strPlusInt: (String, Int) => String = _ + _ - val intPlusStr: (Int, String) => String = _ + _ - val isEven: Int => Boolean = _ % 2 == 0 - val isNonNeg: Int => Boolean = _ > 0 - val flips: Int => List[Int] = x => x :: -x :: Nil - val x1 = xs.foldLeft("")(strPlusInt) - val y1: String = x1 - val x2 = xs.foldRight("")(intPlusStr) - val y2: String = x2 - val x4 = xs.next() - val y4: Int = x4 - val x5 = xs.to(List) - val y5: List[Int] = x5 - val (xs6, xs7) = xs.partition(isEven) - val ys6: Iterator[Int]^{xs6, isEven} = xs6 - val ys7: Iterator[Int]^{xs7, isEven} = xs7 - val (xs6a, xs7a) = xs.partition(_ % 2 == 0) - val ys6a: Iterator[Int]^{xs6} = xs6 - val ys7a: Iterator[Int]^{xs7} = xs7 - val xs8 = xs.drop(2) - val ys8: Iterator[Int]^{xs8} = xs8 - val xs9 = xs.map(isNonNeg) - val ys9: Iterator[Boolean]^{xs9} = xs9 - val xs10 = xs.flatMap(flips) - val ys10: Iterator[Int]^{xs10} = xs10 - val xs11 = xs ++ xs - val ys11: Iterator[Int]^{xs11} = xs11 - val xs12 = xs ++ Nil - val ys12: Iterator[Int]^{xs12} = xs12 - val xs13 = Nil ++ xs - val ys13: List[Int] = xs13 - val xs14 = xs ++ ("a" :: Nil) - val ys14: Iterator[Any]^{xs14} = xs14 - val xs15 = xs.zip(xs9) - val ys15: Iterator[(Int, Boolean)]^{xs15} = xs15 - println("-------") - println(x1) - println(x2) - println(x4) - println(x5) - println(xs6.to(List)) - println(xs7.to(List)) - println(xs8.to(List)) - println(xs9.to(List)) - println(xs10.to(List)) - println(xs11.to(List)) - println(xs12.to(List)) - println(xs13.to(List)) - println(xs14.to(List)) - println(xs15.to(List)) - - def viewOps(xs: View[Int]^) = { - val strPlusInt: (String, Int) => String = _ + _ - val intPlusStr: (Int, String) => String = _ + _ - val isEven: Int => Boolean = _ % 2 == 0 - val isNonNeg: Int => Boolean = _ > 0 - val flips: Int => List[Int] = x => x :: -x :: Nil - val x1 = xs.foldLeft("")(strPlusInt) - val y1: String = x1 - val x2 = xs.foldRight("")(intPlusStr) - val y2: String = x2 - //val x3 = xs.indexWhere(_ % 2 == 0) // indexWhere does not exist on View - //val y3: Int = x3 - val x4 = xs.head - val y4: Int = x4 - val x5 = xs.to(List) - val y5: List[Int] = x5 - val (xs6, xs7) = xs.partition(isEven) - val ys6: View[Int]^{xs6, isEven} = xs6 - val ys7: View[Int]^{xs7, isEven} = xs7 - val (xs6a, xs7a) = xs.partition(_ % 2 == 0) - val ys6a: View[Int]^{xs6} = xs6 - val ys7a: View[Int]^{xs7} = xs7 - val xs8 = xs.drop(2) - val ys8: View[Int]^{xs8} = xs8 - val xs9 = xs.map(isNonNeg) - val ys9: View[Boolean]^{xs9} = xs9 - val xs10 = xs.flatMap(flips) - val ys10: View[Int]^{xs10} = xs10 - val xs11 = xs ++ xs - val ys11: View[Int]^{xs11} = xs11 - val xs12 = xs ++ Nil - val ys12: View[Int]^{xs12} = xs12 - val xs13 = Nil ++ xs - val ys13: List[Int] = xs13 - val xs14 = xs ++ ("a" :: Nil) - val ys14: View[Any]^{xs14} = xs14 - val xs15 = xs.zip(xs9) - val ys15: View[(Int, Boolean)]^{xs15} = xs15 - println("-------") - println(x1) - println(x2) - println(x4) - println(x5) - println(xs6.to(List)) - println(xs7.to(List)) - println(xs8.to(List)) - println(xs9.to(List)) - println(xs10.to(List)) - println(xs11.to(List)) - println(xs12.to(List)) - println(xs13.to(List)) - println(xs14.to(List)) - println(xs15.to(List)) - } - - def stringOps(xs: String) = { - val x1 = xs.foldLeft("")(_ + _) - val y1: String = x1 - val x2 = xs.foldRight("")(_ + _) - val y2: String = x2 - val x3 = xs.indexWhere(_ % 2 == 0) - val y3: Int = x3 - val x4 = xs.head - val y4: Int = x4 - val x5 = xs.to(List) - val y5: List[Char] = x5 - val (xs6, xs7) = xs.partition(_ % 2 == 0) - val ys6: String = xs6 - val ys7: String = xs7 - val xs8 = xs.drop(2) - val ys8: String = xs8 - val xs9 = xs.map(_ + 1) - val ys9: Seq[Int] = xs9 - val xs9a = xs.map(_.toUpper) - val ys9a: String = xs9a - val xs10 = xs.flatMap((x: Char) => s"$x,$x") - val ys10: String = xs10 - val xs11 = xs ++ xs - val ys11: String = xs11 - val ops = collection.StringOps(xs) // !!! otherwise we can a "cannot establish reference" - val xs13 = Nil ++ ops.iterator - val ys13: List[Char] = xs13 - val xs14 = xs ++ ("xyz" :: Nil) - val ys14: Seq[Any] = xs14 - val xs15 = xs.zip(xs9) - val ys15: Seq[(Char, Int)] = xs15 - println("-------") - println(x1) - println(x2) - println(x3) - println(x4) - println(x5) - println(xs6) - println(xs7) - println(xs8) - println(xs9) - println(xs9a) - println(xs10) - println(xs11) - println(xs13) - println(xs14) - println(xs15) - } - - def main(args: Array[String]) = { - val ints = List(1, 2, 3) - val intsBuf = ints.to(ArrayBuffer) - val intsListBuf = ints.to(ListBuffer) - val intsView = ints.view - seqOps(ints) - seqOps(intsBuf) - seqOps(intsListBuf) - viewOps(intsView) - iterOps(ints.iterator) - stringOps("abc") - } -} diff --git a/tests/pos-special/stdlib/collection/IndexedSeq.scala b/tests/pos-special/stdlib/collection/IndexedSeq.scala deleted file mode 100644 index c48dc4932e62..000000000000 --- a/tests/pos-special/stdlib/collection/IndexedSeq.scala +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala -package collection - -import scala.annotation.{nowarn, tailrec} -import scala.collection.Searching.{Found, InsertionPoint, SearchResult} -import scala.collection.Stepper.EfficientSplit -import scala.math.Ordering -import language.experimental.captureChecking - -/** 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 AnyRef 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 = apply(0) - - override def headOption: Option[A] = if (isEmpty) None else Some(head) - - override def last: A = apply(length - 1) - - // 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/tests/pos-special/stdlib/collection/Iterable.scala b/tests/pos-special/stdlib/collection/Iterable.scala deleted file mode 100644 index 85c0debc6685..000000000000 --- a/tests/pos-special/stdlib/collection/Iterable.scala +++ /dev/null @@ -1,1052 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala -package collection - -import scala.annotation.nowarn -import scala.annotation.unchecked.uncheckedVariance -import scala.collection.mutable.Builder -import scala.collection.View.{LeftPartitionMapped, RightPartitionMapped} -import language.experimental.captureChecking - -/** 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] { - this: Iterable[A]^ => - - // 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] { - this: IterableOps[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]^{this} - - /** 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]^{this} = toIterable - - override def isTraversableAgain: Boolean = true - - /** - * @return This collection as a `C`. - */ - protected def coll: C^{this} - - @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^{this} = 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^{coll} - - /** 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]^{this} = 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^{this} = 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]^{this} = 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^{this, pred} = fromSpecific(new View.Filter(this, pred, isFlipped = false)) - - def filterNot(pred: A => Boolean): C^{this, pred} = 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]^{this, p} = new IterableOps.WithFilter(this, p) - - /** A pair of, first, all elements that satisfy predicate `p` and, second, - * all elements that do not. Interesting because it splits a collection in two. - * - * 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^{this, p}, C^{this, p}) = { - val first = new View.Filter(this, p, false) - val second = new View.Filter(this, p, true) - (fromSpecific(first), fromSpecific(second)) - } - - override def splitAt(n: Int): (C^{this}, C^{this}) = (take(n), drop(n)) - - def take(n: Int): C^{this} = 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^{this} = 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^{this, p} = fromSpecific(new View.TakeWhile(this, p)) - - def span(p: A => Boolean): (C^{this, p}, C^{this, p}) = (takeWhile(p), dropWhile(p)) - - def drop(n: Int): C^{this} = 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^{this} = fromSpecific(new View.DropRight(this, n)) - - def dropWhile(p: A => Boolean): C^{this, p} = 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^{this}]^{this} = - 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^{this}]^{this} = 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^{this}]^{this} = - iterator.sliding(size, step).map(fromSpecific) - - /** The rest of the collection without its first element. */ - def tail: C^{this} = { - if (isEmpty) throw new UnsupportedOperationException - drop(1) - } - - /** The initial part of the collection without its last element. - * $willForceEvaluation - */ - def init: C^{this} = { - if (isEmpty) throw new UnsupportedOperationException - dropRight(1) - } - - def slice(from: Int, until: Int): C^{this} = - 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]^{this, op} = scanLeft(z)(op) - - def scanLeft[B](z: B)(op: (B, A) => B): CC[B]^{this, op} = 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]^{this, op} = { - 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]^{this, f} = iterableFactory.from(new View.Map(this, f)) - - def flatMap[B](f: A => IterableOnce[B]^): CC[B]^{this, f} = iterableFactory.from(new View.FlatMap(this, f)) - - def flatten[B](implicit asIterable: A -> IterableOnce[B]): CC[B]^{this} = flatMap(asIterable) - - def collect[B](pf: PartialFunction[A, B]^): CC[B]^{this, pf} = - 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]^{this, f}, CC[A2]^{this, f}) = { - val left: View[A1]^{f, this} = new LeftPartitionMapped(this, f) - val right: View[A2]^{f, this} = 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]^{this, suffix} = 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]^{this, suffix} = 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)]^{this, that} = 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)]^{this} = 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 collection of type `That` 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)]^{this, that} = 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]^{this}, CC[A2]^{this}) = { - val first: View[A1]^{this} = new View.Map[A, A1](this, asPair(_)._1) - val second: View[A2]^{this} = 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]^{this}, CC[A2]^{this}, CC[A3]^{this}) = { - val first: View[A1]^{this} = new View.Map[A, A1](this, asTriple(_)._1) - val second: View[A2]^{this} = new View.Map[A, A2](this, asTriple(_)._2) - val third: View[A3]^{this} = 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^{this}]^{this} = 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^{this}]^{this} = iterateUntilEmpty(_.init) - - override def tapEach[U](f: A => U): C^{this, f} = fromSpecific(new View.Map(this, { (a: A) => f(a); a })) - - // A helper for tails and inits. - private[this] def iterateUntilEmpty(f: Iterable[A]^{this} => Iterable[A]^{this}): Iterator[C^{this}]^{this, f} = { - // 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((itble: Iterable[A]^) => itble.iterator.nonEmpty) - // CC TODO type annotation for itble needed. - // The previous code `.takeWhile(_.iterator.nonEmpty)` does not work. - (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]^{this, that} = 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 { - this: SizeCompareOps^{it} => - /** 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]^{this} = - new View.Filter(self, p, isFlipped = false) - - def map[B](f: A => B): CC[B]^{this} = - self.iterableFactory.from(new View.Map(filtered, f)) - - def flatMap[B](f: A => IterableOnce[B]): CC[B]^{this} = - 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]^{this, q} = - 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) - override def last = a - override def lastOption = Some(a) - override def view = 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.empty - override def init = 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]^{coll} = 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]^{coll} = 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]^{coll} = sortedIterableFactory.from(coll)(ordering) - override protected def newSpecificBuilder: mutable.Builder[A @uncheckedVariance, CC[A @uncheckedVariance]] = sortedIterableFactory.newBuilder[A](ordering) - override def empty: CC[A @uncheckedVariance] = sortedIterableFactory.empty(ordering) - - override def withFilter(p: A => Boolean): SortedSetOps.WithFilter[A, WithFilterCC, CC]^{p} = - 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]] { - this: MapFactoryDefaults[K, V, CC, WithFilterCC] => - override protected def fromSpecific(coll: IterableOnce[(K, V @uncheckedVariance)]^): CC[K, V @uncheckedVariance]^{coll} = 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]^{p} = - 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(ordering) - override protected def fromSpecific(coll: IterableOnce[(K, V @uncheckedVariance)]^): CC[K, V @uncheckedVariance]^{coll} = sortedMapFactory.from(coll)(ordering) - override protected def newSpecificBuilder: mutable.Builder[(K, V @uncheckedVariance), CC[K, V @uncheckedVariance]] = sortedMapFactory.newBuilder[K, V](ordering) - - override def withFilter(p: ((K, V)) => Boolean): collection.SortedMapOps.WithFilter[K, V, WithFilterCC, UnsortedCC, CC]^{p} = - new collection.SortedMapOps.WithFilter[K, V, WithFilterCC, UnsortedCC, CC](this, p) -} diff --git a/tests/pos-special/stdlib/collection/IterableOnce.scala b/tests/pos-special/stdlib/collection/IterableOnce.scala deleted file mode 100644 index f75eab54a89b..000000000000 --- a/tests/pos-special/stdlib/collection/IterableOnce.scala +++ /dev/null @@ -1,1364 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala -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.AbstractFunction2 -import language.experimental.captureChecking - -/** - * 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 { - this: IterableOnce[A]^ => - - /** Iterator can be used only once */ - def iterator: Iterator[A]^{this} - - /** 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[_]^{this}](implicit shape: StepperShape[A, S]): S = { - import convert.impl._ - val s: Any = 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] - } - - /** @return 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]^{f} = 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]^{f} = 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]^{f} = 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]^{f} = 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) - } - - @inline private[collection] def checkArraySizeWithinVMLimit(size: Int): Unit = { - import scala.runtime.PStatics.VM_MaxArraySize - if (size > VM_MaxArraySize) { - throw new Exception(s"Size of array-backed collection exceeds VM array size limit of ${VM_MaxArraySize}") - } - } -} - -/** 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 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 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 in which operations are performed on elements is unspecified - * and may be nondeterministic. - * @define coll collection - * - */ -trait IterableOnceOps[+A, +CC[_], +C] extends Any { this: IterableOnce[A]^ => - /////////////////////////////////////////////////////////////// Abstract methods that must be implemented - - import IterableOnceOps.Maximized - - /** 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]^{this, op} - - /** 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^{this, p} - - /** 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(p: A => Boolean): C^{this, p} - - /** 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^{this} - - /** 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^{this, p} - - /** Selects all elements except 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^{this} - - /** Drops longest prefix of elements that satisfy a 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^{this, p} - - /** 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^{this} - - /** 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]^{this, f} - - /** 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]^{this, f} - - /** 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]^{this} - - /** 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]^{this, pf} - - /** 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)]^{this} - - /** 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^{this, p}, C^{this, p}) - - /** 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^{this}, C^{this}) = { - 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^{this, f} - - /////////////////////////////////////////////////////////////// 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 - - /** 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 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 a binary operator to a start value and all elements of this $coll, - * going left to right. - * - * $willNotTerminateInf - * $orderDependentFold - * - * @param z the start value. - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive elements of this $coll, - * going left to right with the start value `z` on the left: - * `op(...op(z, x,,1,,), x,,2,,, ..., x,,n,,)` where `x,,1,,, ..., x,,n,,` - * are the elements of this $coll. - * 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 a binary operator to all elements of this $coll and a start value, - * going right to left. - * - * $willNotTerminateInf - * $orderDependentFold - * @param z the start value. - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive elements of this $coll, - * going right to left with the start value `z` on the right: - * `op(x,,1,,, op(x,,2,,, ... op(x,,n,,, z)...))` where `x,,1,,, ..., x,,n,,` - * are the elements of this $coll. - * 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) - - /** Folds the elements of this $coll using the specified associative binary operator. - * The default implementation in `IterableOnce` is equivalent to `foldLeft` but may be - * overridden for more efficient traversal orders. - * - * $undefinedorder - * $willNotTerminateInf - * - * @tparam A1 a type parameter for the binary operator, a supertype of `A`. - * @param z a neutral element for the fold operation; may be added to the result - * an arbitrary number of times, and must not change the result (e.g., `Nil` for list concatenation, - * 0 for addition, or 1 for multiplication). - * @param op a binary operator that must be associative. - * @return the result of applying the fold operator `op` between all the elements and `z`, or `z` if this $coll is empty. - */ - def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op) - - /** Reduces the elements of this $coll using the specified associative binary operator. - * - * $undefinedorder - * - * @tparam B A type parameter for the binary operator, a supertype of `A`. - * @param op A binary operator that must be associative. - * @return The result of applying reduce operator `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) - - /** Reduces the elements of this $coll, if any, using the specified - * associative binary operator. - * - * $undefinedorder - * - * @tparam B A type parameter for the binary operator, a supertype of `A`. - * @param op A binary operator that must be associative. - * @return An option value containing result of applying reduce operator `op` between all - * the elements if the collection is nonempty, and `None` otherwise. - */ - def reduceOption[B >: A](op: (B, B) => B): Option[B] = reduceLeftOption(op) - - /** Applies a binary operator to all elements of this $coll, - * going left to right. - * $willNotTerminateInf - * $orderDependentFold - * - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive elements of this $coll, - * going left to right: - * `op( op( ... op(x,,1,,, x,,2,,) ..., x,,n-1,,), x,,n,,)` where `x,,1,,, ..., x,,n,,` - * are the elements of this $coll. - * @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 a binary operator to all elements of this $coll, going right to left. - * $willNotTerminateInf - * $orderDependentFold - * - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive elements of this $coll, - * going right to left: - * `op(x,,1,,, op(x,,2,,, ..., op(x,,n-1,,, x,,n,,)...))` where `x,,1,,, ..., x,,n,,` - * are the elements of this $coll. - * @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 - } - - /** Optionally applies a binary operator to all elements of this $coll, going left to right. - * $willNotTerminateInf - * $orderDependentFold - * - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return an option value containing the result of `reduceLeft(op)` if this $coll is nonempty, - * `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 - } - - /** Optionally applies a binary operator to all elements of this $coll, going - * right to left. - * $willNotTerminateInf - * $orderDependentFold - * - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return an option value containing the result of `reduceRight(op)` if this $coll is nonempty, - * `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 - - /** Copy 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) - - /** Copy 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 - } - - /** 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 scala.runtime.AbstractFunction1[A, Any] { - def apply(a: A) = 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 - } - - @deprecated("`aggregate` is not relevant for sequential collections. Use `foldLeft(z)(seqop)` instead.", "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`, convert this collection 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]^{this} = iterator - - def toList: immutable.List[A] = immutable.List.from(this) - - def toVector: immutable.Vector[A] = immutable.Vector.from(this) - - def toMap[K, V](implicit ev: A <:< (K, V)): immutable.Map[K, V] = - immutable.Map.from(this.asInstanceOf[IterableOnce[(K, V)]]) - - def toSet[B >: A]: immutable.Set[B] = immutable.Set.from(this) - - /** @return This collection as a `Seq[A]`. This is equivalent to `to(Seq)` but might be faster. - */ - def toSeq: immutable.Seq[A] = immutable.Seq.from(this) - - 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) - - @`inline` final def toBuffer[B >: A]: mutable.Buffer[B] = mutable.Buffer.from(this) - - /** Convert collection to array. - * - * Implementation note: DO NOT call [[Array.from]] from this method. - */ - def toArray[B >: A: ClassTag]: Array[B] = - if (knownSize >= 0) { - val destination = new Array[B](knownSize) - copyToArray(destination, 0) - 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 - } -} - -object IterableOnceOps: - - // Moved out of trait IterableOnceOps to here, since universal traits cannot - // have nested classes in Scala 3 - 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 - } - } -end IterableOnceOps \ No newline at end of file diff --git a/tests/pos-special/stdlib/collection/Iterator.scala b/tests/pos-special/stdlib/collection/Iterator.scala deleted file mode 100644 index 4903a1dae0a6..000000000000 --- a/tests/pos-special/stdlib/collection/Iterator.scala +++ /dev/null @@ -1,1308 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala.collection - -import scala.collection.mutable.{ArrayBuffer, ArrayBuilder, Builder, ImmutableBuilder} -import scala.annotation.tailrec -import scala.annotation.unchecked.uncheckedVariance -import scala.runtime.Statics -import language.experimental.captureChecking -import caps.unsafe.unsafeAssumePure - - -/** 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: Iterator[A]^ => - - /** 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: Iterator[A]^{this} = 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]^{this} = 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]^{this} = 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]^{this, p}, Iterator[A]^{this, p}) = { - 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]^{this} = - 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]^{this} = - new GroupedIterator[B](self, size, step) - - def scanLeft[B](z: B)(op: (B, A) => B): Iterator[B]^{this, op} = 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]^{self, op} = - 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]^{this} = 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]^{this, p} = filterImpl(p, isFlipped = false) - - def filterNot(p: A => Boolean): Iterator[A]^{this, p} = filterImpl(p, isFlipped = true) - - private[collection] def filterImpl(p: A => Boolean, isFlipped: Boolean): Iterator[A]^{this, p} = 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]^{this, p} = filter(p) - - def collect[B](pf: PartialFunction[A, B]^): Iterator[B]^{this, pf} = 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]^{this} = 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]^{this} = 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]^{this, f} = 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]^{this, f} = new AbstractIterator[B] { - private[this] var cur: Iterator[B]^{f} = Iterator.empty - /** Trillium logic boolean: -1 = unknown, 0 = false, 1 = true */ - private[this] var _hasNext: Int = -1 - - private[this] def nextCur(): Unit = { - cur = null - 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]^{this} = - flatMap[B](ev) - - def concat[B >: A](xs: => IterableOnce[B]^): Iterator[B]^{this, xs} = new Iterator.ConcatIterator[B](self).concat(xs) - - @`inline` final def ++ [B >: A](xs: => IterableOnce[B]^): Iterator[B]^{this, xs} = concat(xs) - - def take(n: Int): Iterator[A]^{this} = sliceIterator(0, n max 0) - - def takeWhile(p: A => Boolean): Iterator[A]^{self, p} = new AbstractIterator[A] { - private[this] var hd: A = _ - private[this] var hdDefined: Boolean = false - private[this] var tail: Iterator[A]^{self} = 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]^{this} = sliceIterator(n, -1) - - def dropWhile(p: A => Boolean): Iterator[A]^{this, p} = 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]^{this, p}, Iterator[A]^{this, p}) = { - /* - * 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]^{this} = sliceIterator(from, until max 0) - - /** Creates an optionally bounded slice, unbounded if `until` is negative. */ - protected def sliceIterator(from: Int, until: Int): Iterator[A]^{this} = { - 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)]^{this, that} = 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)]^{this, that} = 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)]^{this} = 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]^{this}, Iterator[A]^{this}) = { - 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]^{this, patchElems} = - 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]^{this, f} = 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) = 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} = 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]^{elem} = 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]^{f} = 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]^{f} = 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]^{f} = 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]^{elem} = 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](val from: Iterator[A]^) extends AbstractIterator[A] { - private var current: Iterator[A] = from.unsafeAssumePure - // This should be Iteratpr[A]^, but fails since mutable variables can't capture cap. - // To do better we'd need to track nesting levels for universal capabiltities. - 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]^{this, that} = { - 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]^{this} = head.iterator // CC todo: can't use {head} as capture set, gives "cannot establish a reference" - } - - /** 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]^{underlying} = { - 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 - if (rest == 0) empty - else { - dropping += lo - 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]: - this: Iterator[A]^ => diff --git a/tests/pos-special/stdlib/collection/LinearSeq.scala b/tests/pos-special/stdlib/collection/LinearSeq.scala deleted file mode 100644 index 393f5fda4187..000000000000 --- a/tests/pos-special/stdlib/collection/LinearSeq.scala +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala -package collection - -import scala.annotation.{nowarn, tailrec} -import language.experimental.captureChecking - -/** 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 AnyRef 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 AnyRef 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/tests/pos-special/stdlib/collection/Map.scala b/tests/pos-special/stdlib/collection/Map.scala deleted file mode 100644 index ef4f915ea573..000000000000 --- a/tests/pos-special/stdlib/collection/Map.scala +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala -package collection - -import scala.annotation.nowarn -import scala.collection.generic.DefaultSerializable -import scala.collection.mutable.StringBuilder -import scala.util.hashing.MurmurHash3 -import language.experimental.captureChecking - -/** 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)) - - /** Collects all keys of this map in a set. - * @return a set containing all keys of 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 - } - - /** Collects all keys of this map in an iterable collection. - * - * @return the keys of this map as an iterable. - */ - 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 - } - - /** Creates an iterator for all keys. - * - * @return an iterator over all keys. - */ - 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 might be overridden in subclasses. - * - * @param key the given key value for which a binding is missing. - * @throws NoSuchElementException - */ - @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} = 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]^{p, q} = - 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/tests/pos-special/stdlib/collection/Seq.scala b/tests/pos-special/stdlib/collection/Seq.scala deleted file mode 100644 index 14a276cfa579..000000000000 --- a/tests/pos-special/stdlib/collection/Seq.scala +++ /dev/null @@ -1,1201 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala.collection - -import scala.collection.immutable.Range -import scala.util.hashing.MurmurHash3 -import Searching.{Found, InsertionPoint, SearchResult} -import scala.annotation.nowarn -import language.experimental.captureChecking -import caps.unsafe.unsafeAssumePure - -/** 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 { - this: Seq[A] => - - 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 AnyRef - // CC TODO: Our treechecker disallows classes in universal traits, but the typer accepts - // them. Since SeqOps contains nested classes, I changed it to be no longer a universal trait. - // Alternatively we could - // - Change TreeChecker to accept this - // - Move nested classes out of the trait - with IterableOps[A, CC, C] { self => - - override def view: SeqView[A] = new SeqView.Id[A](this) - - /** Get 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).unsafeAssumePure - - /** 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 new $coll with elements in reversed order. - * - * $willNotTerminateInf - * $willForceEvaluation - * - * @return A new $coll with all elements of this $coll in reversed order. - */ - def reverse: C = fromSpecific(reversed) - - /** An iterator yielding elements in reversed 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 reversed 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 s1 = self.toGenericSeq map (e => (e, m.getOrElseUpdate(e, m.size))) - //val s2: Seq[(A, Int)] = s1 sortBy (_._2) - //val (es, is) = s2.unzip(using Predef.$conforms[(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) - copyToArray(arr) - 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 - - /** Are the elements of this collection 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 more values are replaced than actually exist, the 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 - } - - /** Search 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) - - /** Search 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/tests/pos-special/stdlib/collection/StrictOptimizedIterableOps.scala b/tests/pos-special/stdlib/collection/StrictOptimizedIterableOps.scala deleted file mode 100644 index 5b504a2469b5..000000000000 --- a/tests/pos-special/stdlib/collection/StrictOptimizedIterableOps.scala +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala -package collection - -import scala.annotation.nowarn -import scala.annotation.unchecked.uncheckedVariance -import scala.runtime.Statics -import language.experimental.captureChecking - -/** - * 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] { - this: StrictOptimizedIterableOps[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/tests/pos-special/stdlib/collection/StrictOptimizedSeqOps.scala b/tests/pos-special/stdlib/collection/StrictOptimizedSeqOps.scala deleted file mode 100644 index 50ddbca30f9e..000000000000 --- a/tests/pos-special/stdlib/collection/StrictOptimizedSeqOps.scala +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala.collection -import language.experimental.captureChecking - -/** - * Trait that overrides operations on sequences in order - * to take advantage of strict builders. - */ -trait StrictOptimizedSeqOps [+A, +CC[_], +C] - extends AnyRef - 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] - if (knownSize >= 0) { - b.sizeHint(size + 1) - } - b += elem - b ++= this - b.result() - } - - override def appended[B >: A](elem: B): CC[B] = { - val b = iterableFactory.newBuilder[B] - if (knownSize >= 0) { - b.sizeHint(size + 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/tests/pos-special/stdlib/collection/StringOps.scala b/tests/pos-special/stdlib/collection/StringOps.scala deleted file mode 100644 index f570531def98..000000000000 --- a/tests/pos-special/stdlib/collection/StringOps.scala +++ /dev/null @@ -1,1649 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala -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 -import language.experimental.captureChecking - -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^{p, q} = 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. - * - * @param args the arguments used to instantiating the pattern. - * @throws java.lang.IllegalArgumentException - */ - 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.lang.IllegalArgumentException - */ - 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 a binary operator to a start value and all chars of this string, - * going left to right. - * - * @param z the start value. - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive chars of this string, - * going left to right with the start value `z` on the left: - * {{{ - * op(...op(z, x_1), x_2, ..., x_n) - * }}} - * where `x,,1,,, ..., x,,n,,` are the chars of this string. - * 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 a binary operator to all chars of this string and a start value, - * going right to left. - * - * @param z the start value. - * @param op the binary operator. - * @tparam B the result type of the binary operator. - * @return the result of inserting `op` between consecutive chars of this string, - * going right to left with the start value `z` on the right: - * {{{ - * op(x_1, op(x_2, ... op(x_n, z)...)) - * }}} - * where `x,,1,,, ..., x,,n,,` are the chars of this string. - * 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 - } - - /** Folds the chars of this string using the specified associative binary operator. - * - * @tparam A1 a type parameter for the binary operator, a supertype of Char. - * @param z a neutral element for the fold operation; may be added to the result - * an arbitrary number of times, and must not change the result (e.g., `Nil` for list concatenation, - * 0 for addition, or 1 for multiplication). - * @param op a binary operator that must be associative. - * @return the result of applying the fold operator `op` between all the chars and `z`, or `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^{p} = new StringOps.WithFilter(p, s) - - /** The rest of the string without its first char. - * @note $unicodeunaware - */ - def tail: String = slice(1, s.length) - - /** The initial part of the string without its last char. - * @note $unicodeunaware - */ - def init: String = 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]^{f} = - 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]^{that} = 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/tests/pos-special/stdlib/collection/View.scala b/tests/pos-special/stdlib/collection/View.scala deleted file mode 100644 index 8e2ee3ad9e32..000000000000 --- a/tests/pos-special/stdlib/collection/View.scala +++ /dev/null @@ -1,542 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala.collection - -import scala.annotation.{nowarn, tailrec} -import scala.collection.mutable.{ArrayBuffer, Builder} -import scala.collection.immutable.LazyList -import language.experimental.captureChecking - -/** 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 { - this: View[A]^ => - - override def view: View[A]^{this} = 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]^{it} = new AbstractView[A] { - def iterator: Iterator[A]^{it} = 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} = 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], Pure { - 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[A]^{elem} = 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]^{f} = 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]^{f} = 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]^{f} = 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: Iterator[A]^{underlying, p} = 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, p} = - 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} = 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: Iterator[A1]^{underlying, f} = 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: Iterator[A2]^{this} = 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: Iterator[A]^{underlying} = 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: Iterator[A]^{underlying} = 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: Iterator[A]^{underlying, p} = 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: Iterator[A]^{underlying} = 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: Iterator[A]^{underlying} = 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, p} = 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, op} = 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: Iterator[B]^{underlying, f} = 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: Iterator[B]^{underlying, f} = 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: Iterator[B]^{underlying, pf} = 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: Iterator[A]^{prefix, suffix} = 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: Iterator[(A, B)]^{underlying, other} = 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: Iterator[(A, B)]^{underlying, other} = 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]^{underlying} = - val ct = new Concat(underlying, new View.Single(elem)) - ct.iterator // CC TODO breakout into `ct` needed, otherwise "cannot establish a reference" error - 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]^{underlying} = - val ct = new Concat(new View.Single(elem), underlying) - ct.iterator // CC TODO breakout into `ct` needed, otherwise "cannot establish a reference" error - 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]^{underlying} = 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} = other match { - case other: Iterable[A] => other - case other => LazyList.from(other) - } - - def iterator: Iterator[A]^{underlying, other} = 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} = 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} = 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]^{it} = { - 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](underlying: Iterator[A]^, maxlen: Int) extends AbstractIterator[A] { - private[this] var current: Iterator[A]^{underlying} = underlying - 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(current.hasNext) { - val n = current.next().asInstanceOf[AnyRef] - if(pos >= buf.length) buf.addOne(n) - else buf(pos) = n - pos += 1 - if(pos == maxlen) pos = 0 - len += 1 - } - current = 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]^{this} = { - 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]^{it} = { - 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](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/tests/pos-special/stdlib/collection/immutable/Iterable.scala b/tests/pos-special/stdlib/collection/immutable/Iterable.scala deleted file mode 100644 index 44f13d0f2895..000000000000 --- a/tests/pos-special/stdlib/collection/immutable/Iterable.scala +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala.collection.immutable - -import scala.collection.{IterableFactory, IterableFactoryDefaults} -import language.experimental.captureChecking - -/** 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] { - this: Iterable[A]^ => - - 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/tests/pos-special/stdlib/collection/immutable/List.scala b/tests/pos-special/stdlib/collection/immutable/List.scala deleted file mode 100644 index 6245c5001776..000000000000 --- a/tests/pos-special/stdlib/collection/immutable/List.scala +++ /dev/null @@ -1,693 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala -package collection -package immutable - -import scala.annotation.unchecked.uncheckedVariance -import scala.annotation.tailrec -import mutable.{Builder, ListBuffer} -import scala.collection.generic.DefaultSerializable -import scala.runtime.Statics.releaseFence -import language.experimental.captureChecking - -/** 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 - } - - /** - * @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 new IndexOutOfBoundsException(s"$index is out of bounds (min 0, 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/tests/pos-special/stdlib/collection/immutable/Seq.scala b/tests/pos-special/stdlib/collection/immutable/Seq.scala deleted file mode 100644 index 5184cadaccae..000000000000 --- a/tests/pos-special/stdlib/collection/immutable/Seq.scala +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala -package collection -package immutable - -import language.experimental.captureChecking - -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 AnyRef 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 AnyRef 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/tests/pos-special/stdlib/collection/mutable/Buffer.scala b/tests/pos-special/stdlib/collection/mutable/Buffer.scala deleted file mode 100644 index 0a70c75bac0c..000000000000 --- a/tests/pos-special/stdlib/collection/mutable/Buffer.scala +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala.collection -package mutable - -import scala.annotation.nowarn -import language.experimental.captureChecking - - -/** 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. - */ - @`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 xs the iterable object containing the elements to append. - */ - @`inline` final def appendAll(xs: IterableOnce[A]^): this.type = addAll(xs) - - - /** Alias for `prepend` */ - @`inline` final def +=: (elem: A): this.type = prepend(elem) - - 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) - - 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 } - - def dropInPlace(n: Int): this.type = { remove(0, normalized(n)); this } - def dropRightInPlace(n: Int): this.type = { - val norm = normalized(n) - remove(length - norm, norm) - this - } - def takeInPlace(n: Int): this.type = { - val norm = normalized(n) - remove(norm, length - norm) - this - } - def takeRightInPlace(n: Int): this.type = { remove(0, length - normalized(n)); this } - 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) - - def dropWhileInPlace(p: A => Boolean): this.type = { - val idx = indexWhere(!p(_)) - if (idx < 0) { clear(); this } else dropInPlace(idx) - } - def takeWhileInPlace(p: A => Boolean): this.type = { - val idx = indexWhere(!p(_)) - if (idx < 0) this else takeInPlace(idx) - } - 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 - - 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 - } - - 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/tests/pos-special/stdlib/collection/mutable/Builder.scala b/tests/pos-special/stdlib/collection/mutable/Builder.scala deleted file mode 100644 index dd57cb75da91..000000000000 --- a/tests/pos-special/stdlib/collection/mutable/Builder.scala +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala.collection.mutable - -import language.experimental.captureChecking - - -/** 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: Builder[A, To]^ => - - /** 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 - * when the next `result` is called. 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. - */ - def sizeHint(size: Int): Unit = () - - /** Gives a hint that one expects the `result` of this builder - * to have the same size as the given collection, plus some delta. This will - * provide a hint only if the collection has a known size - * 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 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. - */ - final def sizeHint(coll: scala.collection.IterableOnce[_]^, delta: Int = 0): Unit = { - val s = coll.knownSize - if (s != -1) sizeHint(s + 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 my mapping the result using `f`. */ - def mapResult[NewTo](f: To => NewTo): Builder[A, NewTo]^{this, f} = 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/tests/pos-special/stdlib/collection/mutable/Growable.scala b/tests/pos-special/stdlib/collection/mutable/Growable.scala deleted file mode 100644 index 3b5eabac37bf..000000000000 --- a/tests/pos-special/stdlib/collection/mutable/Growable.scala +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala -package collection -package mutable - -import language.experimental.captureChecking - -/** 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 xs the IterableOnce producing the elements to $add. - * @return the $coll itself. - */ - def addAll(xs: IterableOnce[A]^): this.type = { - if (xs.asInstanceOf[AnyRef] eq this) addAll(Buffer.from(xs)) // avoid mutating under our own iterator - else { - val it = xs.iterator - while (it.hasNext) { - addOne(it.next()) - } - } - this - } - - /** Alias for `addAll` */ - @`inline` final def ++= (xs: IterableOnce[A]^): this.type = addAll(xs) - - /** @return The number of elements in the collection under construction, if it can be cheaply computed, - * -1 otherwise. 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/tests/pos-special/stdlib/collection/mutable/Iterable.scala b/tests/pos-special/stdlib/collection/mutable/Iterable.scala deleted file mode 100644 index bf286157b376..000000000000 --- a/tests/pos-special/stdlib/collection/mutable/Iterable.scala +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala.collection.mutable - -import scala.collection.{IterableFactory, IterableFactoryDefaults} -import language.experimental.captureChecking - -trait Iterable[A] - extends collection.Iterable[A] - with collection.IterableOps[A, Iterable, Iterable[A]] - with IterableFactoryDefaults[A, Iterable] { - this: Iterable[A]^ => - - 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]: - this: AbstractIterable[A]^ => diff --git a/tests/pos-special/stdlib/collection/mutable/ListBuffer.scala b/tests/pos-special/stdlib/collection/mutable/ListBuffer.scala deleted file mode 100644 index 570c815644ee..000000000000 --- a/tests/pos-special/stdlib/collection/mutable/ListBuffer.scala +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala.collection -package mutable - -import scala.annotation.{nowarn, tailrec} -import scala.collection.immutable.{::, List, Nil} -import java.lang.{IllegalArgumentException, IndexOutOfBoundsException} - -import scala.collection.generic.DefaultSerializable -import scala.runtime.Statics.releaseFence -import language.experimental.captureChecking - -/** 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 - 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 new IndexOutOfBoundsException(s"$idx is out of bounds (min 0, 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 new IndexOutOfBoundsException(s"$idx is out of bounds (min 0, 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 - len += fresh.length - } - } - - def insertAll(idx: Int, elems: IterableOnce[A]^): Unit = { - if (idx < 0 || idx > len) throw new IndexOutOfBoundsException(s"$idx is out of bounds (min 0, 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 new IndexOutOfBoundsException(s"$idx is out of bounds (min 0, 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 - } - - 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 - } - - 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 - } - - 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/tests/pos-special/stdlib/collection/mutable/MutationTracker.scala b/tests/pos-special/stdlib/collection/mutable/MutationTracker.scala deleted file mode 100644 index 3e9b16540031..000000000000 --- a/tests/pos-special/stdlib/collection/mutable/MutationTracker.scala +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala -package collection -package mutable - -import java.util.ConcurrentModificationException -import language.experimental.captureChecking - -/** - * 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/tests/pos-special/stdlib/collection/mutable/Seq.scala b/tests/pos-special/stdlib/collection/mutable/Seq.scala deleted file mode 100644 index 443eec379c1b..000000000000 --- a/tests/pos-special/stdlib/collection/mutable/Seq.scala +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala.collection.mutable - -import scala.collection.{IterableFactoryDefaults, SeqFactory} -import language.experimental.captureChecking - -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/tests/pos-special/stdlib/collection/mutable/Shrinkable.scala b/tests/pos-special/stdlib/collection/mutable/Shrinkable.scala deleted file mode 100644 index de2a24ecf01f..000000000000 --- a/tests/pos-special/stdlib/collection/mutable/Shrinkable.scala +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala -package collection.mutable - -import scala.annotation.tailrec -import language.experimental.captureChecking - -/** 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/tests/pos-special/stdlib/collection/mutable/StringBuilder.scala b/tests/pos-special/stdlib/collection/mutable/StringBuilder.scala deleted file mode 100644 index c7859214821d..000000000000 --- a/tests/pos-special/stdlib/collection/mutable/StringBuilder.scala +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala.collection.mutable - -import scala.collection.{IterableFactoryDefaults, IterableOnce} -import scala.collection.immutable.WrappedString -import language.experimental.captureChecking - -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/tests/pos-special/stdlib/runtime/PStatics.scala b/tests/pos-special/stdlib/runtime/PStatics.scala deleted file mode 100644 index 788a56962855..000000000000 --- a/tests/pos-special/stdlib/runtime/PStatics.scala +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Scala (https://www.scala-lang.org) - * - * Copyright EPFL and Lightbend, Inc. - * - * Licensed under Apache License 2.0 - * (http://www.apache.org/licenses/LICENSE-2.0). - * - * See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - */ - -package scala.runtime - -// things that should be in `Statics`, but can't be yet for bincompat reasons -// TODO 3.T: move to `Statics` -private[scala] object PStatics { - final val VM_MaxArraySize = 2147483645 // == `Int.MaxValue - 2`, hotspot limit -} diff --git a/tests/run-custom-args/tasty-inspector/i10359.scala b/tests/run-tasty-inspector/i10359.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/i10359.scala rename to tests/run-tasty-inspector/i10359.scala diff --git a/tests/run-custom-args/tasty-inspector/i13352.scala b/tests/run-tasty-inspector/i13352.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/i13352.scala rename to tests/run-tasty-inspector/i13352.scala diff --git a/tests/run-custom-args/tasty-inspector/i14027.scala b/tests/run-tasty-inspector/i14027.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/i14027.scala rename to tests/run-tasty-inspector/i14027.scala diff --git a/tests/run-custom-args/tasty-inspector/i14785.scala b/tests/run-tasty-inspector/i14785.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/i14785.scala rename to tests/run-tasty-inspector/i14785.scala diff --git a/tests/run-custom-args/tasty-inspector/i14788.scala b/tests/run-tasty-inspector/i14788.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/i14788.scala rename to tests/run-tasty-inspector/i14788.scala diff --git a/tests/run-custom-args/tasty-inspector/i14789.scala b/tests/run-tasty-inspector/i14789.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/i14789.scala rename to tests/run-tasty-inspector/i14789.scala diff --git a/tests/run-custom-args/tasty-inspector/i8163.scala b/tests/run-tasty-inspector/i8163.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/i8163.scala rename to tests/run-tasty-inspector/i8163.scala diff --git a/tests/run-custom-args/tasty-inspector/i8364.scala b/tests/run-tasty-inspector/i8364.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/i8364.scala rename to tests/run-tasty-inspector/i8364.scala diff --git a/tests/run-custom-args/tasty-inspector/i8389.scala b/tests/run-tasty-inspector/i8389.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/i8389.scala rename to tests/run-tasty-inspector/i8389.scala diff --git a/tests/run-custom-args/tasty-inspector/i8460.scala b/tests/run-tasty-inspector/i8460.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/i8460.scala rename to tests/run-tasty-inspector/i8460.scala diff --git a/tests/run-custom-args/tasty-inspector/i9970.scala b/tests/run-tasty-inspector/i9970.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/i9970.scala rename to tests/run-tasty-inspector/i9970.scala diff --git a/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala similarity index 85% rename from tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala rename to tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala index 5ccdb753e9b3..e63393d49e67 100644 --- a/tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala +++ b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala @@ -49,10 +49,9 @@ val experimentalDefinitionInLibrary = Set( //// New feature: capture checking "scala.annotation.capability", - "scala.annotation.internal.WithPureFuns", - "scala.annotation.internal.requiresCapability", "scala.annotation.retains", "scala.annotation.retainsByName", + "scala.Pure", "scala.caps", "scala.caps$", @@ -62,7 +61,15 @@ val experimentalDefinitionInLibrary = Set( //// New feature: Macro annotations "scala.annotation.MacroAnnotation", + //// New feature: -Ysafe-init-global + "scala.annotation.init", + "scala.annotation.init$", + "scala.annotation.init$.widen", + "scala.annotation.init$.region", + //// New APIs: Quotes + // Should be stabilized in 3.4.0 + "scala.quoted.Quotes.reflectModule.defnModule.FunctionClass", "scala.quoted.Quotes.reflectModule.FlagsModule.AbsOverride", // Can be stabilized in 3.4.0 (unsure) or later "scala.quoted.Quotes.reflectModule.CompilationInfoModule.XmacroSettings", @@ -76,21 +83,23 @@ val experimentalDefinitionInLibrary = Set( "scala.quoted.Quotes.reflectModule.SymbolModule.newModule", "scala.quoted.Quotes.reflectModule.SymbolModule.freshName", "scala.quoted.Quotes.reflectModule.SymbolMethods.info", - // Quotes for functions with erased parameters. - "scala.quoted.Quotes.reflectModule.MethodTypeMethods.erasedParams", - "scala.quoted.Quotes.reflectModule.MethodTypeMethods.hasErasedParams", - "scala.quoted.Quotes.reflectModule.TermParamClauseMethods.erasedArgs", - "scala.quoted.Quotes.reflectModule.TermParamClauseMethods.hasErasedArgs", - "scala.quoted.Quotes.reflectModule.defnModule.ErasedFunctionClass", // New feature: functions with erased parameters. // Need erasedDefinitions enabled. - "scala.runtime.ErasedFunction", + "scala.runtime.ErasedFunction", // will be removed (now using PolyFunction) "scala.quoted.Quotes.reflectModule.MethodTypeMethods.erasedParams", "scala.quoted.Quotes.reflectModule.MethodTypeMethods.hasErasedParams", "scala.quoted.Quotes.reflectModule.TermParamClauseMethods.erasedArgs", "scala.quoted.Quotes.reflectModule.TermParamClauseMethods.hasErasedArgs", - "scala.quoted.Quotes.reflectModule.defnModule.ErasedFunctionClass" + "scala.quoted.Quotes.reflectModule.defnModule.PolyFunctionClass", + + // New feature: reverse method on Tuple + "scala.Tuple.reverse", + "scala.Tuple$.Helpers", + "scala.Tuple$.Helpers$", + "scala.Tuple$.Helpers$.ReverseImpl", + "scala.Tuple$.Reverse", + "scala.runtime.Tuples$.reverse" ) @@ -117,9 +126,9 @@ val experimentalDefinitionInLibrary = Set( |Found @experimental definition in library not listed: |${missingFromList.toSeq.sorted.mkString("\n")} | - |If added new experimental definitions to the library, add them to the list in tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala + |If added new experimental definitions to the library, add them to the list in tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala | - |Test only: sbt "scala3-bootstrapped/testCompilation tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala" + |Test only: sbt "scala3-bootstrapped/testCompilation tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala" |""".stripMargin ) assert(missingInLibrary.isEmpty, @@ -128,9 +137,9 @@ val experimentalDefinitionInLibrary = Set( |Listed @experimental definition was not found in the library |${missingInLibrary.toSeq.sorted.mkString("\n")} | - |If experimental definition was removed or stabilized, remove from the list in tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala + |If experimental definition was removed or stabilized, remove from the list in tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala | - |Test only: sbt "scala3-bootstrapped/testCompilation tests/run-custom-args/tasty-inspector/stdlibExperimentalDefinitions.scala" + |Test only: sbt "scala3-bootstrapped/testCompilation tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala" |""".stripMargin ) } diff --git a/tests/run-custom-args/tasty-inspector/tasty-documentation-inspector/Foo.scala b/tests/run-tasty-inspector/tasty-documentation-inspector/Foo.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/tasty-documentation-inspector/Foo.scala rename to tests/run-tasty-inspector/tasty-documentation-inspector/Foo.scala diff --git a/tests/run-custom-args/tasty-inspector/tasty-documentation-inspector/Test.scala b/tests/run-tasty-inspector/tasty-documentation-inspector/Test.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/tasty-documentation-inspector/Test.scala rename to tests/run-tasty-inspector/tasty-documentation-inspector/Test.scala diff --git a/tests/run-custom-args/tasty-inspector/tasty-inspector/Foo.scala b/tests/run-tasty-inspector/tasty-inspector/Foo.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/tasty-inspector/Foo.scala rename to tests/run-tasty-inspector/tasty-inspector/Foo.scala diff --git a/tests/run-custom-args/tasty-inspector/tasty-inspector/Test.scala b/tests/run-tasty-inspector/tasty-inspector/Test.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/tasty-inspector/Test.scala rename to tests/run-tasty-inspector/tasty-inspector/Test.scala diff --git a/tests/run-custom-args/tasty-inspector/tastyPaths.check b/tests/run-tasty-inspector/tastyPaths.check similarity index 70% rename from tests/run-custom-args/tasty-inspector/tastyPaths.check rename to tests/run-tasty-inspector/tastyPaths.check index 4aab4bcb2590..f9d3486040b8 100644 --- a/tests/run-custom-args/tasty-inspector/tastyPaths.check +++ b/tests/run-tasty-inspector/tastyPaths.check @@ -1,2 +1,2 @@ -List(/tastyPaths/I8163.class) +List(/tastyPaths/I8163.tasty) `reflect.SourceFile.current` cannot be called within the TASTy ispector diff --git a/tests/run-custom-args/tasty-inspector/tastyPaths.scala b/tests/run-tasty-inspector/tastyPaths.scala similarity index 100% rename from tests/run-custom-args/tasty-inspector/tastyPaths.scala rename to tests/run-tasty-inspector/tastyPaths.scala