diff --git a/collections-contrib/src/main/scala/strawman/collection/MultiDict.scala b/collections-contrib/src/main/scala/strawman/collection/MultiDict.scala index 6c7d6c9725..f8df99e45e 100644 --- a/collections-contrib/src/main/scala/strawman/collection/MultiDict.scala +++ b/collections-contrib/src/main/scala/strawman/collection/MultiDict.scala @@ -101,7 +101,7 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]] * @tparam W new type of values */ def map[L, W](f: ((K, V)) => (L, W)): CC[L, W] = - multiMapFromIterable(View.Map(toIterable, f)) + multiMapFromIterable(new View.Map(toIterable, f)) /** * @return a multidict that contains all the entries of `this` multidict, @@ -112,7 +112,7 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]] * @tparam W new type of values */ def flatMap[L, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = - multiMapFromIterable(View.FlatMap(toIterable, f)) + multiMapFromIterable(new View.FlatMap(toIterable, f)) /** * @return a multidict that contains all the entries of `this` multidict @@ -125,19 +125,19 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]] */ def collect[L, W](pf: PartialFunction[(K, V), (L, W)]): CC[L, W] = flatMap(kv => - if (pf.isDefinedAt(kv)) View.Single(pf(kv)) + if (pf.isDefinedAt(kv)) new View.Single(pf(kv)) else View.Empty ) /** Concatenate the entries given in `that` iterable to `this` multidict */ def concat(that: Iterable[(K, V)]): C = - fromSpecificIterable(View.Concat(toIterable, that)) + fromSpecificIterable(new View.Concat(toIterable, that)) override def withFilter(p: ((K, V)) => Boolean): MultiMapWithFilter = new MultiMapWithFilter(p) class MultiMapWithFilter(p: ((K, V)) => Boolean) extends WithFilter(p) { - def map[L, W](f: ((K, V)) => (L, W)): CC[L, W] = multiMapFromIterable(View.Map(filtered, f)) - def flatMap[L, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = multiMapFromIterable(View.FlatMap(filtered, f)) + def map[L, W](f: ((K, V)) => (L, W)): CC[L, W] = multiMapFromIterable(new View.Map(filtered, f)) + def flatMap[L, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = multiMapFromIterable(new View.FlatMap(filtered, f)) override def withFilter(q: ((K, V)) => Boolean): MultiMapWithFilter = new MultiMapWithFilter(kv => p(kv) && q(kv)) } @@ -157,7 +157,7 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]] * @tparam W the type of values of the returned multidict */ def mapSets[L, W](f: ((K, Set[V])) => (L, Set[W])): CC[L, W] = - fromSets(View.Map(sets, f)) + fromSets(new View.Map(sets, f)) /** * @return a multidict that contains all the entries of `this` multidict, @@ -170,7 +170,7 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]] */ def collectSets[L, W](pf: PartialFunction[(K, Set[V]), (L, Set[W])]): CC[L, W] = flatMapSets(kvs => - if (pf.isDefinedAt(kvs)) View.Single(pf(kvs)) + if (pf.isDefinedAt(kvs)) new View.Single(pf(kvs)) else View.Empty ) @@ -183,7 +183,7 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]] * @tparam W the type of values of the returned multidict */ def flatMapSets[L, W](f: ((K, Set[V])) => IterableOnce[(L, Set[W])]): CC[L, W] = - fromSets(View.FlatMap(sets, f)) + fromSets(new View.FlatMap(sets, f)) /** * @return a new multidict concatenating the values of this multidict @@ -192,14 +192,14 @@ trait MultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, V]] * @param that the collection of values to add to this multidict */ def concatSets(that: Iterable[(K, Set[V])]): C = - fromSpecificSets(View.Concat(sets, that)) + fromSpecificSets(new View.Concat(sets, that)) /** * @return a multidict that contains all the entries of this multidict * that satisfy the predicate `p` */ def filterSets(p: ((K, Set[V])) => Boolean): C = - fromSpecificSets(View.Filter(sets, p, isFlipped = false)) + fromSpecificSets(new View.Filter(sets, p, isFlipped = false)) } diff --git a/collections-contrib/src/main/scala/strawman/collection/MultiSet.scala b/collections-contrib/src/main/scala/strawman/collection/MultiSet.scala index 71f1690765..b2f266122b 100644 --- a/collections-contrib/src/main/scala/strawman/collection/MultiSet.scala +++ b/collections-contrib/src/main/scala/strawman/collection/MultiSet.scala @@ -35,11 +35,11 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] extends IterableOps[A, CC, C] { protected[this] def fromSpecificOccurrences(it: Iterable[(A, Int)]): C = - fromSpecificIterable(it.view.flatMap { case (e, n) => View.Fill(n)(e) }) + fromSpecificIterable(it.view.flatMap { case (e, n) => new View.Fill(n)(e) }) protected[this] def fromOccurrences[E](it: Iterable[(E, Int)]): CC[E] = // Note new MultiSet(it.to(Map)) would be more efficient but would also loose duplicates - fromIterable(it.view.flatMap { case (e, n) => View.Fill(n)(e) }) + fromIterable(it.view.flatMap { case (e, n) => new View.Fill(n)(e) }) /** * @return All the elements contained in this multiset and their number of occurrences @@ -47,7 +47,7 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] def occurrences: Map[A, Int] def iterator(): Iterator[A] = - occurrences.iterator().flatMap { case (elem, n) => View.Fill(n)(elem) } + occurrences.iterator().flatMap { case (elem, n) => new View.Fill(n)(elem) } /** * @return The number of occurrences of `elem` in this multiset @@ -68,7 +68,7 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * @param that the collection of elements to add to this multiset */ def concat(that: Iterable[A]): C = - fromSpecificIterable(View.Concat(toIterable, that)) + fromSpecificIterable(new View.Concat(toIterable, that)) /** * @return a new multiset summing the occurrences of this multiset @@ -77,7 +77,7 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * @param that the collection of occurrences to add to this multiset */ def concatOccurrences(that: Iterable[(A, Int)]): C = - fromSpecificOccurrences(View.Concat(occurrences, that)) + fromSpecificOccurrences(new View.Concat(occurrences, that)) /** * @return a new multiset resulting from applying the given function `f` @@ -87,11 +87,11 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * @tparam B the element type of the returned collection */ def mapOccurrences[B](f: ((A, Int)) => (B, Int)): CC[B] = - fromOccurrences(View.Map(occurrences, f)) + fromOccurrences(new View.Map(occurrences, f)) def collectOccurrences[B](pf: PartialFunction[(A, Int), (B, Int)]): CC[B] = flatMapOccurrences(kvs => - if (pf.isDefinedAt(kvs)) View.Single(pf(kvs)) + if (pf.isDefinedAt(kvs)) new View.Single(pf(kvs)) else View.Empty ) @@ -103,14 +103,14 @@ trait MultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * @tparam B the element type of the returned collection */ def flatMapOccurrences[B](f: ((A, Int)) => IterableOnce[(B, Int)]): CC[B] = - fromOccurrences(View.FlatMap(occurrences, f)) + fromOccurrences(new View.FlatMap(occurrences, f)) /** * @return a new multiset containing only the occurrences of elements * of this multiset that satisfy the given predicate `p` */ def filterOccurrences(p: ((A, Int)) => Boolean): C = - fromSpecificOccurrences(View.Filter(occurrences, p, isFlipped = false)) + fromSpecificOccurrences(new View.Filter(occurrences, p, isFlipped = false)) // TODO Add more multiset operations like union and intersection diff --git a/collections-contrib/src/main/scala/strawman/collection/SortedMultiDict.scala b/collections-contrib/src/main/scala/strawman/collection/SortedMultiDict.scala index f2f7d70f68..b4f294cdf6 100644 --- a/collections-contrib/src/main/scala/strawman/collection/SortedMultiDict.scala +++ b/collections-contrib/src/main/scala/strawman/collection/SortedMultiDict.scala @@ -54,8 +54,8 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, override def withFilter(p: ((K, V)) => Boolean): SortedMultiMapWithFilter = new SortedMultiMapWithFilter(p) class SortedMultiMapWithFilter(p: ((K, V)) => Boolean) extends MultiMapWithFilter(p) { - def map[L : Ordering, W](f: ((K, V)) => (L, W)): CC[L, W] = sortedFromIterable(View.Map(filtered, f)) - def flatMap[L : Ordering, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = sortedFromIterable(View.FlatMap(filtered, f)) + def map[L : Ordering, W](f: ((K, V)) => (L, W)): CC[L, W] = sortedFromIterable(new View.Map(filtered, f)) + def flatMap[L : Ordering, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = sortedFromIterable(new View.FlatMap(filtered, f)) override def withFilter(q: ((K, V)) => Boolean): SortedMultiMapWithFilter = new SortedMultiMapWithFilter(kv => p(kv) && q(kv)) } @@ -67,7 +67,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, * @tparam L new type of keys * @tparam W new type of values */ - def map[L : Ordering, W](f: ((K, V)) => (L, W)): CC[L, W] = sortedFromIterable(View.Map(toIterable, f)) + def map[L : Ordering, W](f: ((K, V)) => (L, W)): CC[L, W] = sortedFromIterable(new View.Map(toIterable, f)) /** * Builds a new sorted multidict by applying a function to all groups of elements @@ -78,7 +78,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, * `f` to each pair of element and its number of occurrences of this * sorted multiset and collecting the results. */ - def mapSets[L : Ordering, W](f: ((K, Set[V])) => (L, Set[W])): CC[L, W] = sortedFromSets(View.Map(sets, f)) + def mapSets[L : Ordering, W](f: ((K, Set[V])) => (L, Set[W])): CC[L, W] = sortedFromSets(new View.Map(sets, f)) /** * @return a sorted multidict that contains all the entries of `this` sorted multidict, @@ -88,7 +88,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, * @tparam L new type of keys * @tparam W new type of values */ - def flatMap[L : Ordering, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = sortedFromIterable(View.FlatMap(toIterable, f)) + def flatMap[L : Ordering, W](f: ((K, V)) => IterableOnce[(L, W)]): CC[L, W] = sortedFromIterable(new View.FlatMap(toIterable, f)) /** * @return a new sorted multidict resulting from applying the given function `f` @@ -98,7 +98,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, * @tparam L the new type of keys * @tparam W the type of values of the returned sorted multidict */ - def flatMapSets[L : Ordering, W](f: ((K, Set[V])) => IterableOnce[(L, Set[W])]): CC[L, W] = sortedFromSets(View.FlatMap(sets, f)) + def flatMapSets[L : Ordering, W](f: ((K, Set[V])) => IterableOnce[(L, Set[W])]): CC[L, W] = sortedFromSets(new View.FlatMap(sets, f)) /** * @return a sorted multidict that contains all the entries of `this` sorted multidict @@ -110,7 +110,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, * @tparam W new type of values */ def collect[L : Ordering, W](pf: PartialFunction[(K, V), (L, W)]): CC[L, W] = flatMap(kv => - if (pf.isDefinedAt(kv)) View.Single(pf(kv)) + if (pf.isDefinedAt(kv)) new View.Single(pf(kv)) else View.Empty ) @@ -124,7 +124,7 @@ trait SortedMultiDictOps[K, V, +CC[X, Y] <: MultiDict[X, Y], +C <: MultiDict[K, * @tparam W the new type of values */ def collectSets[L : Ordering, W](pf: PartialFunction[(K, Set[V]), (L, Set[W])]): CC[L, W] = flatMapSets(kv => - if (pf.isDefinedAt(kv)) View.Single(pf(kv)) + if (pf.isDefinedAt(kv)) new View.Single(pf(kv)) else View.Empty ) diff --git a/collections-contrib/src/main/scala/strawman/collection/SortedMultiSet.scala b/collections-contrib/src/main/scala/strawman/collection/SortedMultiSet.scala index 8764fb2dab..07a8b103c3 100644 --- a/collections-contrib/src/main/scala/strawman/collection/SortedMultiSet.scala +++ b/collections-contrib/src/main/scala/strawman/collection/SortedMultiSet.scala @@ -30,7 +30,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] protected[this] def sortedFromIterable[B : Ordering](it: Iterable[B]): SortedIterableCC[B] protected[this] def sortedFromOccurrences[B : Ordering](it: Iterable[(B, Int)]): CC[B] = - sortedFromIterable(it.view.flatMap { case (b, n) => View.Fill(n)(b) }) + sortedFromIterable(it.view.flatMap { case (b, n) => new View.Fill(n)(b) }) /** `this` sorted multiset upcasted to an unsorted multiset */ def unsorted: MultiSet[A] @@ -46,7 +46,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * @param start The lower-bound (inclusive) of the iterator */ def iteratorFrom(start: A): Iterator[A] = - occurrences.iteratorFrom(start).flatMap { case (elem, n) => View.Fill(n)(elem) } + occurrences.iteratorFrom(start).flatMap { case (elem, n) => new View.Fill(n)(elem) } def firstKey: A = occurrences.firstKey def lastKey: A = occurrences.lastKey @@ -70,9 +70,9 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] */ class SortedWithFilter(p: A => Boolean) extends WithFilter(p) { - def map[B : Ordering](f: A => B): CC[B] = sortedIterableFactory.from(View.Map(filtered, f)) + def map[B : Ordering](f: A => B): CC[B] = sortedIterableFactory.from(new View.Map(filtered, f)) - def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = sortedIterableFactory.from(View.FlatMap(filtered, f)) + def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = sortedIterableFactory.from(new View.FlatMap(filtered, f)) override def withFilter(q: A => Boolean): SortedWithFilter = new SortedWithFilter(a => p(a) && q(a)) @@ -85,7 +85,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * @return a new collection resulting from applying the given function * `f` to each element of this sorted multiset and collecting the results. */ - def map[B : Ordering](f: A => B): CC[B] = sortedFromIterable(View.Map(toIterable, f)) + def map[B : Ordering](f: A => B): CC[B] = sortedFromIterable(new View.Map(toIterable, f)) /** * Builds a new sorted multiset by applying a function to all pairs of element and its @@ -98,7 +98,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * sorted multiset and collecting the results. */ def mapOccurrences[B : Ordering](f: ((A, Int)) => (B, Int)): CC[B] = - sortedFromOccurrences(View.Map(occurrences, f)) + sortedFromOccurrences(new View.Map(occurrences, f)) /** * Builds a new collection by applying a function to all elements of this sorted @@ -109,7 +109,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * @return a new collection resulting from applying the given function `f` to * each element of this sorted multiset and concatenating the results. */ - def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = sortedFromIterable(View.FlatMap(toIterable, f)) + def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = sortedFromIterable(new View.FlatMap(toIterable, f)) /** * Builds a new collection by applying a function to all pairs of element and @@ -123,7 +123,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * multiset and concatenating the results. */ def flatMapOccurrences[B : Ordering](f: ((A, Int)) => IterableOnce[(B, Int)]): CC[B] = - sortedFromOccurrences(View.FlatMap(occurrences, f)) + sortedFromOccurrences(new View.FlatMap(occurrences, f)) /** * Returns a sorted multiset formed from this sorted multiset and another iterable @@ -136,7 +136,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * is the minimum of the lengths of `this` and `that` */ def zip[B](that: Iterable[B])(implicit ev: Ordering[B]): CC[(A @uncheckedVariance, B)] = // sound bcs of VarianceNote - sortedFromIterable(View.Zip(toIterable, that)) + sortedFromIterable(new View.Zip(toIterable, that)) /** * @return a new collection resulting from applying the given partial @@ -146,7 +146,7 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * @tparam B the element type of the returned collection */ def collect[B : Ordering](pf: PartialFunction[A, B]): CC[B] = flatMap(a => - if (pf.isDefinedAt(a)) View.Single(pf(a)) + if (pf.isDefinedAt(a)) new View.Single(pf(a)) else View.Empty ) @@ -158,14 +158,14 @@ trait SortedMultiSetOps[A, +CC[X] <: MultiSet[X], +C <: MultiSet[A]] * @tparam B the element type of the returned collection */ def collectOccurrences[B : Ordering](pf: PartialFunction[(A, Int), (B, Int)]): CC[B] = flatMapOccurrences(a => - if (pf.isDefinedAt(a)) View.Single(pf(a)) + if (pf.isDefinedAt(a)) new View.Single(pf(a)) else View.Empty ) // --- Override return type of methods that returned an unsorted MultiSet override def zipWithIndex: CC[(A, Int)] = - sortedFromIterable(View.ZipWithIndex(toIterable)) + sortedFromIterable(new View.ZipWithIndex(toIterable)) } diff --git a/collections-contrib/src/main/scala/strawman/collection/decorators/SeqDecorator.scala b/collections-contrib/src/main/scala/strawman/collection/decorators/SeqDecorator.scala index de51d69682..87480e10d5 100644 --- a/collections-contrib/src/main/scala/strawman/collection/decorators/SeqDecorator.scala +++ b/collections-contrib/src/main/scala/strawman/collection/decorators/SeqDecorator.scala @@ -24,7 +24,7 @@ class SeqDecorator[A, CC[X] <: SeqOps[X, CC, _]](`this`: CC[A]) { * }}} */ def intersperse[B >: A](sep: B): CC[B] = - `this`.iterableFactory.from(View.Intersperse(`this`.toIterable, sep)) + `this`.iterableFactory.from(new View.Intersperse(`this`.toIterable, sep)) /** Adds the element `sep` between each element of the sequence, * prepending `start` and appending `end`. @@ -42,6 +42,6 @@ class SeqDecorator[A, CC[X] <: SeqOps[X, CC, _]](`this`: CC[A]) { * }}} */ def intersperse[B >: A, C](start: B, sep: B, end: B): CC[B] = - `this`.iterableFactory.from(View.IntersperseSurround(`this`.toIterable, start, sep, end)) + `this`.iterableFactory.from(new View.IntersperseSurround(`this`.toIterable, start, sep, end)) } diff --git a/collections-contrib/src/main/scala/strawman/collection/decorators/views.scala b/collections-contrib/src/main/scala/strawman/collection/decorators/views.scala index 49828f2a7b..467739f992 100644 --- a/collections-contrib/src/main/scala/strawman/collection/decorators/views.scala +++ b/collections-contrib/src/main/scala/strawman/collection/decorators/views.scala @@ -4,13 +4,13 @@ package decorators /** Views used by decorators */ object View { - case class Intersperse[A](underlying: Iterable[A], sep: A) extends View[A] { + class Intersperse[A](underlying: Iterable[A], sep: A) extends View[A] { def iterator(): Iterator[A] = underlying.iterator().intersperse(sep) override def knownSize: Int = if (underlying.knownSize > 0) (2 * underlying.knownSize - 1) else underlying.knownSize } - case class IntersperseSurround[A](underlying: Iterable[A], start: A, sep: A, end: A) extends View[A] { + class IntersperseSurround[A](underlying: Iterable[A], start: A, sep: A, end: A) extends View[A] { def iterator(): Iterator[A] = underlying.iterator().intersperse(start, sep, end) override def knownSize: Int = diff --git a/collections/src/main/scala/strawman/collection/ArrayOps.scala b/collections/src/main/scala/strawman/collection/ArrayOps.scala index e397f8a5f5..63f366ad41 100644 --- a/collections/src/main/scala/strawman/collection/ArrayOps.scala +++ b/collections/src/main/scala/strawman/collection/ArrayOps.scala @@ -12,14 +12,14 @@ object ArrayOps { protected def p: A => Boolean protected def ao: ArrayOps[A] protected def filtered = View.Filter(ao.toIterable, p, isFlipped = false) - def map[B](f: A => B): immutable.IndexedSeq[B] = ao.iterableFactory.from(View.Map(filtered, f)) - def flatMap[B](f: A => IterableOnce[B]): immutable.IndexedSeq[B] = ao.iterableFactory.from(View.FlatMap(filtered, f)) + def map[B](f: A => B): immutable.IndexedSeq[B] = ao.iterableFactory.from(new View.Map(filtered, f)) + def flatMap[B](f: A => IterableOnce[B]): immutable.IndexedSeq[B] = ao.iterableFactory.from(new View.FlatMap(filtered, f)) } class WithFilter[A](protected val p: A => Boolean, protected val ao: ArrayOps[A]) extends collection.WithFilter[A, immutable.IndexedSeq] with LowPriorityWithFilterOps[A] { def foreach[U](f: A => U): Unit = filtered.foreach(f) - def map[B: ClassTag](f: A => B): Array[B] = ao.fromTaggedIterable(View.Map(filtered, f)) - def flatMap[B: ClassTag](f: A => IterableOnce[B]): Array[B] = ao.fromTaggedIterable(View.FlatMap(filtered, f)) + def map[B: ClassTag](f: A => B): Array[B] = ao.fromTaggedIterable(new View.Map(filtered, f)) + def flatMap[B: ClassTag](f: A => IterableOnce[B]): Array[B] = ao.fromTaggedIterable(new View.FlatMap(filtered, f)) def withFilter(q: A => Boolean): WithFilter[A] = new WithFilter[A](a => p(a) && q(a), ao) } } @@ -27,7 +27,7 @@ object ArrayOps { class ArrayOps[A](val xs: Array[A]) extends AnyVal with IterableOnce[A] with IndexedSeqOps[A, immutable.IndexedSeq, Array[A]] - with StrictOptimizedSeqOps[A, Seq, Array[A]] { + with StrictOptimizedSeqOps[A, immutable.IndexedSeq, Array[A]] { protected def fromTaggedIterable[B: ClassTag](coll: Iterable[B]): Array[B] = coll.toArray[B] @@ -51,7 +51,7 @@ class ArrayOps[A](val xs: Array[A]) extends AnyVal override def className = "Array" - def map[B: ClassTag](f: A => B): Array[B] = fromTaggedIterable(View.Map(toIterable, f)) + def map[B: ClassTag](f: A => B): Array[B] = fromTaggedIterable(new View.Map(this, f)) def mapInPlace(f: A => A): Array[A] = { var i = 0 @@ -62,10 +62,10 @@ class ArrayOps[A](val xs: Array[A]) extends AnyVal xs } - def flatMap[B: ClassTag](f: A => IterableOnce[B]): Array[B] = fromTaggedIterable(View.FlatMap(toIterable, f)) + def flatMap[B: ClassTag](f: A => IterableOnce[B]): Array[B] = fromTaggedIterable(new View.FlatMap(toIterable, f)) def flatMap[BS, B](f: A => BS)(implicit asIterable: BS => Iterable[B], m: ClassTag[B]): Array[B] = - fromTaggedIterable(View.FlatMap(toIterable, (x: A) => asIterable(f(x)))) + fromTaggedIterable(new View.FlatMap(this, (x: A) => asIterable(f(x)))) def flatten[B](implicit asIterable: A => strawman.collection.Iterable[B], m: ClassTag[B]): Array[B] = { val b = WrappedArray.newBuilder[B]().mapResult(_.toArray) @@ -81,22 +81,22 @@ class ArrayOps[A](val xs: Array[A]) extends AnyVal @`inline` final def ++[B >: A : ClassTag](xs: Iterable[B]): Array[B] = appendedAll(xs) - def zip[B: ClassTag](that: Iterable[B]): Array[(A, B)] = fromTaggedIterable(View.Zip(toIterable, that)) + def zip[B: ClassTag](that: Iterable[B]): Array[(A, B)] = fromTaggedIterable(new View.Zip(this, that)) - def zipWithIndex(implicit ct: ClassTag[(A, Int)]): Array[(A, Int)] = fromTaggedIterable(View.ZipWithIndex(toIterable)) + def zipWithIndex(implicit ct: ClassTag[(A, Int)]): Array[(A, Int)] = fromTaggedIterable(new View.ZipWithIndex(this)) - def appended[B >: A : ClassTag](x: B): Array[B] = fromTaggedIterable(View.Append(toIterable, x)) + def appended[B >: A : ClassTag](x: B): Array[B] = fromTaggedIterable(new View.Appended(this, x)) @`inline` final def :+ [B >: A : ClassTag](x: B): Array[B] = appended(x) - def prepended[B >: A : ClassTag](x: B): Array[B] = fromTaggedIterable(View.Prepend(x, toIterable)) + def prepended[B >: A : ClassTag](x: B): Array[B] = fromTaggedIterable(new View.Prepended(x, this)) @`inline` final def +: [B >: A : ClassTag](x: B): Array[B] = prepended(x) - def prependedAll[B >: A : ClassTag](prefix: Iterable[B]): Array[B] = fromTaggedIterable(View.Concat(prefix, toIterable)) + def prependedAll[B >: A : ClassTag](prefix: Iterable[B]): Array[B] = fromTaggedIterable(new View.Concat(prefix, this)) @`inline` final def ++: [B >: A : ClassTag](prefix: Iterable[B]): Array[B] = prependedAll(prefix) - def appendedAll[B >: A : ClassTag](suffix: Iterable[B]): Array[B] = fromTaggedIterable(View.Concat(toIterable, suffix)) + def appendedAll[B >: A : ClassTag](suffix: Iterable[B]): Array[B] = fromTaggedIterable(new View.Concat(this, suffix)) @`inline` final def :++ [B >: A : ClassTag](suffix: Iterable[B]): Array[B] = appendedAll(suffix) @`inline` final def concat[B >: A : ClassTag](suffix: Iterable[B]): Array[B] = appendedAll(suffix) def patch[B >: A : ClassTag](from: Int, other: Iterable[B], replaced: Int): Array[B] = - fromTaggedIterable(new View.Patched(toIterable, from, other, replaced)) //TODO optimize + fromTaggedIterable(new View.Patched(this, from, other, replaced)) //TODO optimize /** Converts an array of pairs into an array of first elements and an array of second elements. * diff --git a/collections/src/main/scala/strawman/collection/BitSet.scala b/collections/src/main/scala/strawman/collection/BitSet.scala index a2a614498e..77157445bd 100644 --- a/collections/src/main/scala/strawman/collection/BitSet.scala +++ b/collections/src/main/scala/strawman/collection/BitSet.scala @@ -162,9 +162,9 @@ trait BitSetOps[+C <: BitSet with BitSetOps[C]] * @return a new bitset resulting from applying the given function ''f'' to * each element of this bitset and collecting the results */ - def map(f: Int => Int): C = fromSpecificIterable(View.Map(toIterable, f)) + def map(f: Int => Int): C = fromSpecificIterable(new View.Map(toIterable, f)) - def flatMap(f: Int => IterableOnce[Int]): C = fromSpecificIterable(View.FlatMap(toIterable, f)) + def flatMap(f: Int => IterableOnce[Int]): C = fromSpecificIterable(new View.FlatMap(toIterable, f)) } diff --git a/collections/src/main/scala/strawman/collection/Factory.scala b/collections/src/main/scala/strawman/collection/Factory.scala index f31c79a073..e1e4f8e298 100644 --- a/collections/src/main/scala/strawman/collection/Factory.scala +++ b/collections/src/main/scala/strawman/collection/Factory.scala @@ -92,7 +92,7 @@ trait IterableFactory[+CC[_]] { * @param elems the elements of the created $coll * @return a new $coll with elements `elems` */ - def apply[A](elems: A*): CC[A] = from(View.Elems(elems: _*)) + def apply[A](elems: A*): CC[A] = from(new View.Elems(elems: _*)) /** Produces a $coll containing repeated applications of a function to a start value. * @@ -130,7 +130,7 @@ trait IterableFactory[+CC[_]] { * @param elem the element computation * @return A $coll that contains the results of `n` evaluations of `elem`. */ - def fill[A](n: Int)(elem: => A): CC[A] = from(View.Fill(n)(elem)) + def fill[A](n: Int)(elem: => A): CC[A] = from(new View.Fill(n)(elem)) /** Produces a two-dimensional $coll containing the results of some element computation a number of times. * @param n1 the number of elements in the 1st dimension @@ -312,8 +312,8 @@ trait StrictOptimizedSeqFactory[+CC[_]] extends SeqFactory[CC] { */ trait SpecificIterableFactory[-A, +C] extends Factory[A, C] { def empty: C - def apply(xs: A*): C = fromSpecific(View.Elems(xs: _*)) - def fill(n: Int)(elem: => A): C = fromSpecific(View.Fill(n)(elem)) + def apply(xs: A*): C = fromSpecific(new View.Elems(xs: _*)) + def fill(n: Int)(elem: => A): C = fromSpecific(new View.Fill(n)(elem)) def newBuilder(): Builder[A, C] } @@ -387,14 +387,14 @@ trait EvidenceIterableFactory[+CC[_], Ev[_]] { def empty[A : Ev]: CC[A] - def apply[A : Ev](xs: A*): CC[A] = from(View.Elems(xs: _*)) + def apply[A : Ev](xs: A*): CC[A] = from(new View.Elems(xs: _*)) /** Produces a $coll containing the results of some element computation a number of times. * @param n the number of elements contained in the $coll. * @param elem the element computation * @return A $coll that contains the results of `n` evaluations of `elem`. */ - def fill[A : Ev](n: Int)(elem: => A): CC[A] = from(View.Fill(n)(elem)) + def fill[A : Ev](n: Int)(elem: => A): CC[A] = from(new View.Fill(n)(elem)) /** Produces a $coll containing values of a given function over a range of integer values starting from 0. * @param n The number of elements in the $coll diff --git a/collections/src/main/scala/strawman/collection/IndexedSeq.scala b/collections/src/main/scala/strawman/collection/IndexedSeq.scala index 075d09e4c1..1abd6b9fee 100644 --- a/collections/src/main/scala/strawman/collection/IndexedSeq.scala +++ b/collections/src/main/scala/strawman/collection/IndexedSeq.scala @@ -13,7 +13,7 @@ trait IndexedSeq[+A] extends Seq[A] with IndexedSeqOps[A, IndexedSeq, IndexedSeq object IndexedSeq extends SeqFactory.Delegate[IndexedSeq](immutable.IndexedSeq) /** Base trait for indexed Seq operations */ -trait IndexedSeqOps[+A, +CC[X] <: IndexedSeq[X], +C] extends Any with SeqOps[A, CC, C] { self => +trait IndexedSeqOps[+A, +CC[_], +C] extends Any with SeqOps[A, CC, C] { self => def iterator(): Iterator[A] = view.iterator() @@ -27,19 +27,26 @@ trait IndexedSeqOps[+A, +CC[X] <: IndexedSeq[X], +C] extends Any with SeqOps[A, } else Iterator.empty.next() } - override def view: IndexedView[A] = new IndexedView[A] { - def length: Int = self.length - def apply(i: Int): A = self(i) - } + override def view: IndexedView[A] = new IndexedView.Id[A](this) + + override protected[this] def reversed: Iterable[A] = new IndexedView.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 IndexedView.Prepended(elem, this)) + + override def take(n: Int): C = fromSpecificIterable(new IndexedView.Take(this, n)) + + override def takeRight(n: Int): C = fromSpecificIterable(new IndexedView.TakeRight(this, n)) + + override def drop(n: Int): C = fromSpecificIterable(new IndexedView.Drop(this, n)) + + override def dropRight(n: Int): C = fromSpecificIterable(new IndexedView.DropRight(this, n)) - override protected[this] def reversed: Iterable[A] = view.reverse + override def map[B](f: A => B): CC[B] = iterableFactory.from(new IndexedView.Map(this, f)) - /** A collection containing the last `n` elements of this collection. */ - override def takeRight(n: Int): C = fromSpecificIterable(view.takeRight(n)) + override def reverse: C = fromSpecificIterable(new IndexedView.Reverse(this)) - /** The rest of the collection without its `n` last elements. For - * linear, immutable collections this should avoid making a copy. */ - override def dropRight(n: Int): C = fromSpecificIterable(view.dropRight(n)) + override def slice(from: Int, until: Int): C = fromSpecificIterable(new IndexedView.Slice(this, from, until)) override def lengthCompare(len: Int): Int = length - len diff --git a/collections/src/main/scala/strawman/collection/IndexedView.scala b/collections/src/main/scala/strawman/collection/IndexedView.scala new file mode 100644 index 0000000000..8436c5cb13 --- /dev/null +++ b/collections/src/main/scala/strawman/collection/IndexedView.scala @@ -0,0 +1,84 @@ +package strawman +package collection + +import scala.{Any, Boolean, Equals, IllegalArgumentException, Int, NoSuchElementException, Nothing, annotation, IndexOutOfBoundsException, throws, AnyRef, Array, deprecated, `inline`} +import scala.Predef.{<:<, intWrapper} + +/** View defined in terms of indexing a range */ +trait IndexedView[+A] extends IndexedSeqOps[A, View, View[A]] with SeqView[A] { self => + + override def view: IndexedView[A] = this + + override def iterator(): Iterator[A] = new AbstractIterator[A] { + private var current = 0 + override def knownSize: Int = self.size - current + def hasNext = current < self.size + def next(): A = { + val r = self.apply(current) + current += 1 + r + } + } + + override def prepended[B >: A](elem: B): IndexedView[B] = new IndexedView.Prepended(elem, this) + override def take(n: Int): IndexedView[A] = new IndexedView.Take(this, n) + override def takeRight(n: Int): IndexedView[A] = new IndexedView.TakeRight(this, n) + override def drop(n: Int): IndexedView[A] = new IndexedView.Drop(this, n) + override def dropRight(n: Int): IndexedView[A] = new IndexedView.DropRight(this, n) + override def map[B](f: A => B): IndexedView[B] = new IndexedView.Map(this, f) + override def reverse: IndexedView[A] = new IndexedView.Reverse(this) + override def slice(from: Int, until: Int): IndexedView[A] = new IndexedView.Slice(this, from, until) +} + +object IndexedView { + + /** An `IndexedSeqOps` whose collection type and collection type constructor are unknown */ + type SomeIndexedSeqOps[A] = IndexedSeqOps[A, AnyConstr, _] + + class Id[+A](underlying: SomeIndexedSeqOps[A]) + extends SeqView.Id(underlying) with IndexedView[A] + + class Prepended[+A](elem: A, underlying: SomeIndexedSeqOps[A]) + extends SeqView.Prepended(elem, underlying) with IndexedView[A] + + class Take[A](underlying: SomeIndexedSeqOps[A], n: Int) + extends SeqView.Take(underlying, n) with IndexedView[A] + + class TakeRight[A](underlying: SomeIndexedSeqOps[A], n: Int) extends IndexedView[A] { + private[this] val delta = (underlying.size - (n max 0)) max 0 + def length = underlying.size - delta + @throws[IndexOutOfBoundsException] + def apply(i: Int) = underlying.apply(i + delta) + } + + class Drop[A](underlying: SomeIndexedSeqOps[A], n: Int) extends View.Drop[A](underlying, n) with IndexedView[A] { + def length = (underlying.size - normN) max 0 + @throws[IndexOutOfBoundsException] + def apply(i: Int) = underlying.apply(i + normN) + } + + class DropRight[A](underlying: SomeIndexedSeqOps[A], n: Int) extends IndexedView[A] { + private[this] val len = (underlying.size - (n max 0)) max 0 + def length = len + @throws[IndexOutOfBoundsException] + def apply(i: Int) = underlying.apply(i) + } + + class Map[A, B](underlying: SomeIndexedSeqOps[A], f: A => B) + extends SeqView.Map(underlying, f) with IndexedView[B] + + class Reverse[A](underlying: SomeIndexedSeqOps[A]) extends IndexedView[A] { + def length = underlying.size + @throws[IndexOutOfBoundsException] + def apply(i: Int) = underlying.apply(size - 1 - i) + } + + class Slice[A](underlying: SomeIndexedSeqOps[A], from: Int, until: Int) extends IndexedView[A] { + protected val lo = from max 0 + protected val hi = until min underlying.length + protected val len = (hi - lo) max 0 + @throws[IndexOutOfBoundsException] + def apply(i: Int): A = underlying(lo + i) + def length: Int = len + } +} diff --git a/collections/src/main/scala/strawman/collection/Iterable.scala b/collections/src/main/scala/strawman/collection/Iterable.scala index 5dd321582e..3975b80209 100644 --- a/collections/src/main/scala/strawman/collection/Iterable.scala +++ b/collections/src/main/scala/strawman/collection/Iterable.scala @@ -90,7 +90,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { protected[this] def fromSpecificIterable(coll: Iterable[A]): C /** Similar to `fromSpecificIterable`, but for a (possibly) different type of element. - * Note that the return type is know `CC[E]`. + * Note that the return type is now `CC[E]`. */ @`inline` final protected[this] def fromIterable[E](it: Iterable[E]): CC[E] = iterableFactory.from(it) @@ -374,6 +374,9 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { 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) @@ -714,7 +717,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * @return a new $coll consisting of all elements of this $coll that satisfy the given * predicate `pred`. Their order may not be preserved. */ - def filter(pred: A => Boolean): C = fromSpecificIterable(View.Filter(toIterable, pred, isFlipped = false)) + def filter(pred: A => Boolean): C = fromSpecificIterable(new View.Filter(this, pred, isFlipped = false)) /** Selects all elements of this $coll which do not satisfy a predicate. * @@ -722,7 +725,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * @return a new $coll consisting of all elements of this $coll that do not satisfy the given * predicate `pred`. Their order may not be preserved. */ - def filterNot(pred: A => Boolean): C = fromSpecificIterable(View.Filter(toIterable, pred, isFlipped = true)) + def filterNot(pred: A => Boolean): C = fromSpecificIterable(new View.Filter(this, pred, isFlipped = true)) /** Creates a non-strict filter of this $coll. * @@ -747,11 +750,11 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { */ class WithFilter(p: A => Boolean) extends collection.WithFilter[A, CC] { - protected[this] def filtered = View.Filter(toIterable, p, isFlipped = false) + protected[this] def filtered = new View.Filter(IterableOps.this, p, isFlipped = false) - def map[B](f: A => B): CC[B] = iterableFactory.from(View.Map(filtered, f)) + def map[B](f: A => B): CC[B] = iterableFactory.from(new View.Map(filtered, f)) - def flatMap[B](f: A => IterableOnce[B]): CC[B] = iterableFactory.from(View.FlatMap(filtered, f)) + def flatMap[B](f: A => IterableOnce[B]): CC[B] = iterableFactory.from(new View.FlatMap(filtered, f)) def foreach[U](f: A => U): Unit = filtered.foreach(f) @@ -767,7 +770,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * which requires only a single traversal. */ def partition(p: A => Boolean): (C, C) = { - val pn = View.Partition(toIterable, p) + val pn = new View.Partition(this, p) (fromSpecificIterable(pn.first), fromSpecificIterable(pn.second)) } @@ -783,7 +786,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { def splitAt(n: Int): (C, C) = (take(n), drop(n)) /** A collection containing the first `n` elements of this collection. */ - def take(n: Int): C = fromSpecificIterable(View.Take(toIterable, n)) + def take(n: Int): C = fromSpecificIterable(new View.Take(this, n)) /** A collection containing the last `n` elements of this collection. */ def takeRight(n: Int): C = { @@ -805,7 +808,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * @return the longest prefix of this $coll whose elements all satisfy * the predicate `p`. */ - def takeWhile(p: A => Boolean): C = fromSpecificIterable(View.TakeWhile(toIterable, p)) + def takeWhile(p: A => Boolean): C = fromSpecificIterable(new View.TakeWhile(this, p)) /** Splits this $coll into a prefix/suffix pair according to a predicate. * @@ -823,7 +826,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { /** The rest of the collection without its `n` first elements. For * linear, immutable collections this should avoid making a copy. */ - def drop(n: Int): C = fromSpecificIterable(View.Drop(toIterable, n)) + def drop(n: Int): C = fromSpecificIterable(new View.Drop(this, n)) /** The rest of the collection without its `n` last elements. For * linear, immutable collections this should avoid making a copy. @@ -846,7 +849,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * @return the longest suffix of this $coll whose first element * does not satisfy the predicate `p`. */ - def dropWhile(p: A => Boolean): C = fromSpecificIterable(View.DropWhile(toIterable, p)) + def dropWhile(p: A => Boolean): C = fromSpecificIterable(new View.DropWhile(this, p)) /** Partitions elements in fixed size ${coll}s. * @see [[scala.collection.Iterator]], method `grouped` @@ -910,7 +913,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * of this $coll. */ def slice(from: Int, until: Int): C = - fromSpecificIterable(View.Drop(View.Take(toIterable, until), from)) + fromSpecificIterable(new View.Drop(new View.Take(this, until), from)) /** Partitions this $coll into a map of ${coll}s according to some discriminator function. * @@ -1025,7 +1028,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * @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] = fromIterable(View.ScanLeft(toIterable, z, op)) + def scanLeft[B](z: B)(op: (B, A) => B): CC[B] = fromIterable(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. @@ -1059,7 +1062,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * @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] = fromIterable(View.Map(toIterable, f)) + def map[B](f: A => B): CC[B] = fromIterable(new View.Map(this, f)) /** Builds a new collection by applying a function to all elements of this $coll * and using the elements of the resulting collections. @@ -1092,7 +1095,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * @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] = fromIterable(View.FlatMap(toIterable, f)) + def flatMap[B](f: A => IterableOnce[B]): CC[B] = fromIterable(new View.FlatMap(this, f)) /** Converts this $coll of traversable collections into * a $coll formed by the elements of these traversable @@ -1122,7 +1125,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * */ def flatten[B](implicit asIterable: A => IterableOnce[B]): CC[B] = - fromIterable(View.FlatMap(toIterable, asIterable)) + fromIterable(new View.FlatMap(this, asIterable)) /** Builds a new collection by applying a partial function to all elements of this $coll * on which the function is defined. @@ -1135,7 +1138,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { */ def collect[B](pf: PartialFunction[A, B]): CC[B] = flatMap { a => - if (pf.isDefinedAt(a)) View.Single(pf(a)) + if (pf.isDefinedAt(a)) new View.Single(pf(a)) else View.Empty } @@ -1162,7 +1165,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * @return a new $coll which contains all elements * of this $coll followed by all elements of `suffix`. */ - def concat[B >: A](suffix: Iterable[B]): CC[B] = fromIterable(View.Concat(toIterable, suffix)) + def concat[B >: A](suffix: Iterable[B]): CC[B] = fromIterable(new View.Concat(this, suffix)) /** Alias for `concat` */ @`inline` final def ++ [B >: A](suffix: Iterable[B]): CC[B] = concat(suffix) @@ -1176,7 +1179,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * @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: Iterable[B]): CC[(A @uncheckedVariance, B)] = fromIterable(View.Zip(toIterable, that)) + def zip[B](that: Iterable[B]): CC[(A @uncheckedVariance, B)] = fromIterable(new View.Zip(this, that)) // sound bcs of VarianceNote /** Zips this $coll with its indices. @@ -1186,7 +1189,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * @example * `List("a", "b", "c").zipWithIndex == List(("a", 0), ("b", 1), ("c", 2))` */ - def zipWithIndex: CC[(A @uncheckedVariance, Int)] = fromIterable(View.ZipWithIndex(toIterable)) + def zipWithIndex: CC[(A @uncheckedVariance, Int)] = fromIterable(new View.ZipWithIndex(this)) /** Returns a $coll formed from this $coll and another iterable collection * by combining corresponding elements in pairs. @@ -1202,7 +1205,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * 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)] = fromIterable(View.ZipAll(toIterable, that, thisElem, thatElem)) + def zipAll[A1 >: A, B](that: Iterable[B], thisElem: A1, thatElem: B): CC[(A1, B)] = fromIterable(new View.ZipAll(this, that, thisElem, thatElem)) /** Converts this $coll of pairs into two collections of the first and second * half of each pair. @@ -1224,7 +1227,7 @@ trait IterableOps[+A, +CC[_], +C] extends Any with IterableOnce[A] { * half of each element pair of this $coll. */ def unzip[A1, A2](implicit asPair: A => (A1, A2)): (CC[A1], CC[A2]) = { - val unzipped = View.Unzip(toIterable) + val unzipped = new View.Unzip(this) (fromIterable(unzipped.first), fromIterable(unzipped.second)) } diff --git a/collections/src/main/scala/strawman/collection/Map.scala b/collections/src/main/scala/strawman/collection/Map.scala index 3450eb5658..54e3bd53a4 100644 --- a/collections/src/main/scala/strawman/collection/Map.scala +++ b/collections/src/main/scala/strawman/collection/Map.scala @@ -54,10 +54,13 @@ trait Map[K, +V] * @define coll map * @define Coll `Map` */ -trait MapOps[K, +V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C] +// 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] - with Equals { + with PartialFunction[K, V] { + + override def view: MapView[K, V] = new MapView.Id(this) protected[this] type MapCC[K, V] = CC[K, V] @@ -165,14 +168,14 @@ trait MapOps[K, +V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C] * @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. */ - def filterKeys(p: K => Boolean): View[(K, V)] = View.FilterKeys(toIterable, p) + 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. */ - def mapValues[W](f: V => W): View[(K, W)] = View.MapValues(toIterable, f) + 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 @@ -216,9 +219,9 @@ trait MapOps[K, +V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C] */ class MapWithFilter(p: ((K, V)) => Boolean) extends WithFilter(p) { - def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = mapFactory.from(View.Map(filtered, f)) + def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = mapFactory.from(new View.Map(filtered, f)) - def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] = mapFactory.from(View.FlatMap(filtered, f)) + def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] = mapFactory.from(new View.FlatMap(filtered, f)) override def withFilter(q: ((K, V)) => Boolean): MapWithFilter = new MapWithFilter(kv => p(kv) && q(kv)) @@ -230,7 +233,7 @@ trait MapOps[K, +V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C] * @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(View.Map(toIterable, f)) + def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = mapFactory.from(new View.Map(toIterable, f)) /** Builds a new collection by applying a partial function to all elements of this $coll * on which the function is defined. @@ -244,7 +247,7 @@ trait MapOps[K, +V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C] */ def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)]): CC[K2, V2] = flatMap { a => - if (pf.isDefinedAt(a)) View.Single(pf(a)) + if (pf.isDefinedAt(a)) new View.Single(pf(a)) else View.Empty } @@ -255,7 +258,7 @@ trait MapOps[K, +V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C] * @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(View.FlatMap(toIterable, f)) + def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] = mapFactory.from(new View.FlatMap(toIterable, 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 @@ -265,7 +268,7 @@ trait MapOps[K, +V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C] * @return a new $coll which contains all elements * of this $coll followed by all elements of `suffix`. */ - def concat[V2 >: V](suffix: collection.Iterable[(K, V2)]): CC[K, V2] = mapFactory.from(View.Concat(toIterable, suffix)) + def concat[V2 >: V](suffix: collection.Iterable[(K, V2)]): CC[K, V2] = mapFactory.from(new View.Concat(toIterable, suffix)) /** Alias for `concat` */ /*@`inline` final*/ def ++ [V2 >: V](xs: collection.Iterable[(K, V2)]): CC[K, V2] = concat(xs) @@ -276,7 +279,7 @@ trait MapOps[K, +V, +CC[X, Y] <: MapOps[X, Y, CC, _], +C] iterator().map { case (k, v) => s"$k -> $v" }.mkString(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(View.Append(toIterable, kv)) + def + [V1 >: V](kv: (K, V1)): CC[K, V1] = mapFactory.from(new View.Appended(toIterable, kv)) } /** diff --git a/collections/src/main/scala/strawman/collection/MapView.scala b/collections/src/main/scala/strawman/collection/MapView.scala new file mode 100644 index 0000000000..f27e94f58f --- /dev/null +++ b/collections/src/main/scala/strawman/collection/MapView.scala @@ -0,0 +1,48 @@ +package strawman.collection + +import scala.{Boolean, Int, Option, None} + +import strawman.collection.mutable.Builder + +trait MapView[K, +V] + extends MapOps[K, V, ({ type l[X, Y] = View[(X, Y)] })#l, View[(K, V)]] + with View[(K, V)] { + + override def view: MapView[K, V] = this + + def mapFactory: MapFactory[({ type l[X, Y] = View[(X, Y)] })#l] = + new MapFactory[({ type l[X, Y] = View[(X, Y)] })#l] { + def newBuilder[X, Y](): Builder[(X, Y), View[(X, Y)]] = View.newBuilder[(X, Y)]() + def empty[X, Y]: View[(X, Y)] = View.empty + def from[X, Y](it: IterableOnce[(X, Y)]): View[(X, Y)] = View.from(it) + } + + def empty: View[(K, V)] = View.Empty + +} + +object MapView { + + /** An `IterableOps` whose collection type and collection type constructor are unknown */ + type SomeIterableConstr[X, Y] = IterableOps[_, AnyConstr, _] + /** A `MapOps` whose collection type and collection type constructor are (mostly) unknown */ + type SomeMapOps[K, +V] = MapOps[K, V, SomeIterableConstr, _] + + class Id[K, +V](underlying: SomeMapOps[K, V]) extends MapView[K, V] { + def get(key: K): Option[V] = underlying.get(key) + def iterator(): Iterator[(K, V)] = underlying.iterator() + override def knownSize: Int = underlying.knownSize + } + + class MapValues[K, +V, +W](underlying: SomeMapOps[K, V], f: V => W) extends MapView[K, W] { + def iterator(): Iterator[(K, W)] = underlying.iterator().map(kv => (kv._1, f(kv._2))) + def get(key: K): Option[W] = underlying.get(key).map(f) + override def knownSize: Int = underlying.knownSize + } + + class FilterKeys[K, +V](underlying: SomeMapOps[K, V], p: K => Boolean) extends MapView[K, V] { + def iterator(): Iterator[(K, V)] = underlying.iterator().filter { case (k, _) => p(k) } + def get(key: K): Option[V] = if (p(key)) underlying.get(key) else None + } + +} \ No newline at end of file diff --git a/collections/src/main/scala/strawman/collection/Seq.scala b/collections/src/main/scala/strawman/collection/Seq.scala index f6c2348e76..0a69039295 100644 --- a/collections/src/main/scala/strawman/collection/Seq.scala +++ b/collections/src/main/scala/strawman/collection/Seq.scala @@ -84,6 +84,8 @@ object Seq extends SeqFactory.Delegate[Seq](immutable.Seq) trait SeqOps[+A, +CC[_], +C] extends Any with IterableOps[A, CC, C] { + 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] @@ -119,7 +121,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * @return a new $coll consisting of `value` followed * by all elements of this $coll. */ - def prepended[B >: A](elem: B): CC[B] = fromIterable(View.Prepend(elem, toIterable)) + def prepended[B >: A](elem: B): CC[B] = fromIterable(new View.Prepended(elem, this)) /** Alias for `prepended`. * @@ -149,7 +151,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * @return a new $coll consisting of * all elements of this $coll followed by `value`. */ - def appended[B >: A](elem: B): CC[B] = fromIterable(View.Append(toIterable, elem)) + def appended[B >: A](elem: B): CC[B] = fromIterable(new View.Appended(this, elem)) /** Alias for `appended` * @@ -170,7 +172,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * @return a new $coll which contains all elements of `prefix` followed * by all the elements of this $coll. */ - def prependedAll[B >: A](prefix: Iterable[B]): CC[B] = fromIterable(View.Concat(prefix, toIterable)) + def prependedAll[B >: A](prefix: Iterable[B]): CC[B] = fromIterable(new View.Concat(prefix, this)) /** Alias for `prependedAll` */ @`inline` final def ++: [B >: A](prefix: Iterable[B]): CC[B] = prependedAll(prefix) @@ -208,7 +210,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * @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 = fromSpecificIterable(View.DistinctBy(toIterable, f)) + def distinctBy[B](f: A => B): C = fromSpecificIterable(new View.DistinctBy(this, f)) /** Returns new $coll with elements in reversed order. * @@ -282,7 +284,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * 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] = fromIterable(View.PadTo(toIterable, len, elem)) + def padTo[B >: A](len: Int, elem: B): CC[B] = fromIterable(new View.PadTo(this, len, elem)) /** Computes length of longest segment whose elements all satisfy some predicate. * @@ -423,7 +425,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any 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] = fromIterable(View.Map(View.fromIteratorProvider(() => reverseIterator()), f)) + def reverseMap[B](f: A => B): CC[B] = fromIterable(new View.Map(View.fromIteratorProvider(() => reverseIterator()), f)) /** Iterates over distinct permutations. * @@ -764,7 +766,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any * by all the elements of `other`. */ def patch[B >: A](from: Int, other: IterableOnce[B], replaced: Int): CC[B] = - fromIterable(new View.Patched(toIterable, from, other, replaced)) + fromIterable(new View.Patched(this, from, other, replaced)) private[this] def occCounts[B](sq: Seq[B]): mutable.Map[B, Int] = { val occ = mutable.Map.empty[B, Int].withDefaultValue(0) diff --git a/collections/src/main/scala/strawman/collection/SeqView.scala b/collections/src/main/scala/strawman/collection/SeqView.scala new file mode 100644 index 0000000000..de103cc5e6 --- /dev/null +++ b/collections/src/main/scala/strawman/collection/SeqView.scala @@ -0,0 +1,47 @@ +package strawman +package collection + +import scala.{Int, IndexOutOfBoundsException} +import scala.Predef.intWrapper + +trait SeqView[+A] extends SeqOps[A, View, View[A]] with View[A] { + + override def view: SeqView[A] = this + + override def map[B](f: A => B): SeqView[B] = new SeqView.Map(this, f) + + override def prepended[B >: A](elem: B): SeqView[B] = new SeqView.Prepended(elem, this) + + override def take(n: Int): SeqView[A] = new SeqView.Take(this, n) + +} + +object SeqView { + + /** A `SeqOps` whose collection type and collection type constructor are unknown */ + type SomeSeqOps[+A] = SeqOps[A, AnyConstr, _] + + /** A view that doesn’t apply any transformation to an underlying sequence */ + class Id[+A](underlying: SeqOps[A, AnyConstr, _]) extends SeqView[A] { + def apply(idx: Int): A = underlying.apply(idx) + def length: Int = underlying.length + def iterator(): Iterator[A] = underlying.iterator() + override def knownSize: Int = underlying.knownSize + } + + class Map[+A, +B](underlying: SomeSeqOps[A], f: A => B) extends View.Map[A, B](underlying, f) with SeqView[B] { + def apply(idx: Int): B = f(underlying(idx)) + def length: Int = underlying.length + } + + class Prepended[+A](elem: A, underlying: SomeSeqOps[A]) extends View.Prepended(elem, underlying) with SeqView[A] { + def apply(idx: Int): A = if (idx == 0) elem else underlying(idx - 1) + def length: Int = underlying.length + 1 + } + + class Take[+A](underlying: SomeSeqOps[A], n: Int) extends View.Take(underlying, n) with SeqView[A] { + def apply(idx: Int): A = if (idx < n) underlying(idx) else throw new IndexOutOfBoundsException(idx.toString) + def length: Int = underlying.length min normN + } + +} \ No newline at end of file diff --git a/collections/src/main/scala/strawman/collection/Set.scala b/collections/src/main/scala/strawman/collection/Set.scala index 75a9225a84..50ca081e00 100644 --- a/collections/src/main/scala/strawman/collection/Set.scala +++ b/collections/src/main/scala/strawman/collection/Set.scala @@ -168,10 +168,10 @@ trait SetOps[A, +CC[_], +C <: SetOps[A, CC, C]] * @param that the collection containing the elements to add. * @return a new $coll with the given elements added, omitting duplicates. */ - def concat(that: collection.Iterable[A]): C = fromSpecificIterable(View.Concat(toIterable, that)) + def concat(that: collection.Iterable[A]): C = fromSpecificIterable(new View.Concat(toIterable, that)) @deprecated("Consider requiring an immutable Set or fall back to Set.union ", "2.13.0") - @`inline` final def + [B >: A](elem: B): CC[B] = iterableFactory.from(View.Append(toIterable, elem)) + @`inline` final def + [B >: A](elem: B): CC[B] = iterableFactory.from(new View.Appended(toIterable, elem)) //TODO We should be able to use `fromIterable` here but Dotty complains about a variance problem with no apparent workaround /** Alias for `concat` */ diff --git a/collections/src/main/scala/strawman/collection/SortedMap.scala b/collections/src/main/scala/strawman/collection/SortedMap.scala index 7976099543..cb75db2dc9 100644 --- a/collections/src/main/scala/strawman/collection/SortedMap.scala +++ b/collections/src/main/scala/strawman/collection/SortedMap.scala @@ -126,10 +126,10 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], class SortedMapWithFilter(p: ((K, V)) => Boolean) extends MapWithFilter(p) { def map[K2 : Ordering, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] = - sortedMapFactory.from(View.Map(filtered, f)) + sortedMapFactory.from(new View.Map(filtered, f)) def flatMap[K2 : Ordering, V2](f: ((K, V)) => IterableOnce[(K2, V2)]): CC[K2, V2] = - sortedMapFactory.from(View.FlatMap(filtered, f)) + sortedMapFactory.from(new View.FlatMap(filtered, f)) override def withFilter(q: ((K, V)) => Boolean): SortedMapWithFilter = new SortedMapWithFilter(kv => p(kv) && q(kv)) @@ -143,7 +143,7 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], * `f` to each element of this $coll and collecting the results. */ def map[K2, V2](f: ((K, V)) => (K2, V2))(implicit ordering: Ordering[K2]): CC[K2, V2] = - sortedMapFactory.from(View.Map[(K, V), (K2, V2)](toIterable, f)) + sortedMapFactory.from(new View.Map[(K, V), (K2, V2)](toIterable, f)) /** Builds a new sorted map by applying a function to all elements of this $coll * and using the elements of the resulting collections. @@ -153,7 +153,7 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], * `f` to each element of this $coll and concatenating the results. */ def flatMap[K2, V2](f: ((K, V)) => IterableOnce[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] = - sortedMapFactory.from(View.FlatMap(toIterable, f)) + sortedMapFactory.from(new View.FlatMap(toIterable, f)) /** Builds a new sorted map by applying a partial function to all elements of this $coll * on which the function is defined. @@ -165,7 +165,7 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], */ def collect[K2, V2](pf: PartialFunction[(K, V), (K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] = flatMap { (kv: (K, V)) => - if (pf.isDefinedAt(kv)) View.Single(pf(kv)) + if (pf.isDefinedAt(kv)) new View.Single(pf(kv)) else View.Empty } @@ -179,13 +179,13 @@ trait SortedMapOps[K, +V, +CC[X, Y] <: Map[X, Y] with SortedMapOps[X, Y, CC, _], * @return a new collection of type `CC[K2, V2]` which contains all elements * of this $coll followed by all elements of `xs`. */ - def concat[K2 >: K, V2 >: V](xs: Iterable[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] = sortedMapFactory.from(View.Concat(toIterable, xs)) + def concat[K2 >: K, V2 >: V](xs: Iterable[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] = sortedMapFactory.from(new View.Concat(toIterable, xs)) /** Alias for `concat` */ @`inline` final def ++ [K2 >: K, V2 >: V](xs: Iterable[(K2, V2)])(implicit ordering: Ordering[K2]): CC[K2, V2] = concat(xs) // We override these methods to fix their return type (which would be `Map` otherwise) - override def concat[V2 >: V](xs: collection.Iterable[(K, V2)]): CC[K, V2] = sortedMapFactory.from(View.Concat(toIterable, xs)) + override def concat[V2 >: V](xs: collection.Iterable[(K, V2)]): CC[K, V2] = sortedMapFactory.from(new View.Concat(toIterable, xs)) override def ++ [V2 >: V](xs: collection.Iterable[(K, V2)]): CC[K, V2] = concat(xs) // TODO Also override mapValues diff --git a/collections/src/main/scala/strawman/collection/SortedSet.scala b/collections/src/main/scala/strawman/collection/SortedSet.scala index 62132999df..e1b8ab28fb 100644 --- a/collections/src/main/scala/strawman/collection/SortedSet.scala +++ b/collections/src/main/scala/strawman/collection/SortedSet.scala @@ -74,9 +74,9 @@ trait SortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]] */ class SortedWithFilter(p: A => Boolean) extends WithFilter(p) { - def map[B : Ordering](f: A => B): CC[B] = sortedIterableFactory.from(View.Map(filtered, f)) + def map[B : Ordering](f: A => B): CC[B] = sortedIterableFactory.from(new View.Map(filtered, f)) - def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = sortedIterableFactory.from(View.FlatMap(filtered, f)) + def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = sortedIterableFactory.from(new View.FlatMap(filtered, f)) override def withFilter(q: A => Boolean): SortedWithFilter = new SortedWithFilter(a => p(a) && q(a)) @@ -89,7 +89,7 @@ trait SortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]] * @return a new $coll resulting from applying the given function * `f` to each element of this $coll and collecting the results. */ - def map[B : Ordering](f: A => B): CC[B] = sortedFromIterable(View.Map(toIterable, f)) + def map[B : Ordering](f: A => B): CC[B] = sortedFromIterable(new View.Map(toIterable, f)) /** Builds a new sorted collection by applying a function to all elements of this $coll * and using the elements of the resulting collections. @@ -99,7 +99,7 @@ trait SortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]] * @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 : Ordering](f: A => IterableOnce[B]): CC[B] = sortedFromIterable(View.FlatMap(toIterable, f)) + def flatMap[B : Ordering](f: A => IterableOnce[B]): CC[B] = sortedFromIterable(new View.FlatMap(toIterable, f)) /** Returns a $coll formed from this $coll and another iterable collection * by combining corresponding elements in pairs. @@ -111,7 +111,7 @@ trait SortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]] * The length of the returned collection is the minimum of the lengths of this $coll and `that`. */ def zip[B](that: Iterable[B])(implicit ev: Ordering[(A @uncheckedVariance, B)]): CC[(A @uncheckedVariance, B)] = // sound bcs of VarianceNote - sortedFromIterable(View.Zip(toIterable, that)) + sortedFromIterable(new View.Zip(toIterable, that)) /** Builds a new sorted collection by applying a partial function to all elements of this $coll * on which the function is defined. @@ -123,7 +123,7 @@ trait SortedSetOps[A, +CC[X] <: SortedSet[X], +C <: SortedSetOps[A, CC, C]] * The order of the elements is preserved. */ def collect[B: Ordering](pf: scala.PartialFunction[A, B]): CC[B] = flatMap(a => - if (pf.isDefinedAt(a)) View.Single(pf(a)) + if (pf.isDefinedAt(a)) new View.Single(pf(a)) else View.Empty ) } diff --git a/collections/src/main/scala/strawman/collection/StringOps.scala b/collections/src/main/scala/strawman/collection/StringOps.scala index cc05672df3..dc24bf0820 100644 --- a/collections/src/main/scala/strawman/collection/StringOps.scala +++ b/collections/src/main/scala/strawman/collection/StringOps.scala @@ -153,7 +153,7 @@ final class StringOps(val s: String) * by `other`. */ def patch(from: Int, other: String, replaced: Int): String = - fromSpecificIterable(new View.Patched(toIterable, from, other, replaced)) //TODO optimize + fromSpecificIterable(new View.Patched(this, from, other, replaced)) //TODO optimize /** A copy of this string with one single replaced element. * @param index the position of the replacement @@ -162,7 +162,7 @@ final class StringOps(val s: String) * @throws IndexOutOfBoundsException if `index` does not satisfy `0 <= index < length`. */ def updated(index: Int, elem: Char): String = - fromSpecificIterable(View.Updated(toIterable, index, elem)) // TODO optimize + fromSpecificIterable(new View.Updated(this, index, elem)) // TODO optimize override def toString = s diff --git a/collections/src/main/scala/strawman/collection/View.scala b/collections/src/main/scala/strawman/collection/View.scala index 5447845940..36d8ba783f 100644 --- a/collections/src/main/scala/strawman/collection/View.scala +++ b/collections/src/main/scala/strawman/collection/View.scala @@ -13,7 +13,8 @@ import scala.Predef.{<:<, intWrapper} * @define Coll `View` */ trait View[+A] extends Iterable[A] with IterableOps[A, View, View[A]] { - override def view = this + + override def view: View[A] = this override def iterableFactory = View @@ -62,7 +63,7 @@ object View extends IterableFactory[View] { def newBuilder[A](): Builder[A, View[A]] = ArrayBuffer.newBuilder[A]().mapResult(from) - override def apply[A](xs: A*): View[A] = Elems(xs: _*) + override def apply[A](xs: A*): View[A] = new Elems(xs: _*) /** The empty view */ case object Empty extends View[Nothing] { @@ -71,7 +72,7 @@ object View extends IterableFactory[View] { } /** A view with exactly one element */ - case class Single[A](a: A) extends View[A] { + class Single[A](a: A) extends View[A] { def iterator(): Iterator[A] = new Iterator[A] { private var notConsumed: Boolean = true @@ -86,19 +87,19 @@ object View extends IterableFactory[View] { } /** A view with given elements */ - case class Elems[A](xs: A*) extends View[A] { + class Elems[A](xs: A*) extends View[A] { def iterator() = Iterator(xs: _*) - override def knownSize = xs.length // should be: xs.knownSize, but A*'s are not sequences in this strawman. + override def knownSize = xs.toStrawman.knownSize } /** A view containing the results of some element computation a number of times. */ - case class Fill[A](n: Int)(elem: => A) extends View[A] { + class Fill[A](n: Int)(elem: => A) extends View[A] { def iterator() = Iterator.fill(n)(elem) override def knownSize: Int = 0 max n } /** A view containing values of a given function over a range of integer values starting from 0. */ - case class Tabulate[A](n: Int)(f: Int => A) extends View[A] { + class Tabulate[A](n: Int)(f: Int => A) extends View[A] { def iterator(): Iterator[A] = Iterator.tabulate(n)(f) override def knownSize: Int = 0 max n } @@ -108,9 +109,12 @@ object View extends IterableFactory[View] { def iterator(): Iterator[A] = Iterator.iterate(start)(f).take(len) override def knownSize: Int = 0 max len } + + /** An `IterableOps` whose collection type and collection type constructor are unknown */ + type SomeIterableOps[A] = IterableOps[A, AnyConstr, _] /** A view that filters an underlying collection. */ - class Filter[A](val underlying: Iterable[A], val p: A => Boolean, val isFlipped: Boolean) extends View[A] { + class Filter[A](val underlying: SomeIterableOps[A], val p: A => Boolean, val isFlipped: Boolean) extends View[A] { def iterator() = underlying.iterator().filterImpl(p, isFlipped) } @@ -122,84 +126,75 @@ object View extends IterableFactory[View] { } } - case class FilterKeys[K, V](underlying: Iterable[(K, V)], p: K => Boolean) extends View[(K, V)] { - def iterator(): Iterator[(K, V)] = underlying.iterator().filter(kv => p(kv._1)) - } - /** A view that removes the duplicated elements as determined by the transformation function `f` */ - case class DistinctBy[A, B](underlying: Iterable[A], f: A => B) extends View[A] { + class DistinctBy[A, B](underlying: SomeIterableOps[A], f: A => B) extends View[A] { def iterator(): Iterator[A] = underlying.iterator().distinctBy(f) } /** A view that partitions an underlying collection into two views */ - case class Partition[A](underlying: Iterable[A], p: A => Boolean) { + class Partition[A](val underlying: SomeIterableOps[A], val p: A => Boolean) { /** The view consisting of all elements of the underlying collection * that satisfy `p`. */ - val first = Partitioned(this, true) + val first = new Partitioned(this, true) /** The view consisting of all elements of the underlying collection * that do not satisfy `p`. */ - val second = Partitioned(this, false) + val second = new Partitioned(this, false) } /** A view representing one half of a partition. */ - case class Partitioned[A](partition: Partition[A], cond: Boolean) extends View[A] { + class Partitioned[A](partition: Partition[A], cond: Boolean) extends View[A] { def iterator() = partition.underlying.iterator().filter(x => partition.p(x) == cond) } /** A view that drops leading elements of the underlying collection. */ - case class Drop[A](underlying: Iterable[A], n: Int) extends View[A] { + class Drop[A](underlying: SomeIterableOps[A], n: Int) extends View[A] { def iterator() = underlying.iterator().drop(n) protected val normN = n max 0 override def knownSize = if (underlying.knownSize >= 0) (underlying.knownSize - normN) max 0 else -1 } - case class DropWhile[A](underlying: Iterable[A], p: A => Boolean) extends View[A] { + class DropWhile[A](underlying: SomeIterableOps[A], p: A => Boolean) extends View[A] { def iterator() = underlying.iterator().dropWhile(p) } /** A view that takes leading elements of the underlying collection. */ - case class Take[A](underlying: Iterable[A], n: Int) extends View[A] { + class Take[+A](underlying: SomeIterableOps[A], n: Int) extends View[A] { def iterator() = underlying.iterator().take(n) protected val normN = n max 0 override def knownSize = if (underlying.knownSize >= 0) underlying.knownSize min normN else -1 } - case class TakeWhile[A](underlying: Iterable[A], p: A => Boolean) extends View[A] { + class TakeWhile[A](underlying: SomeIterableOps[A], p: A => Boolean) extends View[A] { def iterator(): Iterator[A] = underlying.iterator().takeWhile(p) } - case class ScanLeft[A, B](underlying: Iterable[A], z: B, op: (B, A) => B) extends View[B] { + class ScanLeft[+A, +B](underlying: SomeIterableOps[A], z: B, op: (B, A) => B) extends View[B] { def iterator(): Iterator[B] = underlying.iterator().scanLeft(z)(op) override def knownSize: Int = if (underlying.knownSize >= 0) underlying.knownSize + 1 else -1 } /** A view that maps elements of the underlying collection. */ - case class Map[A, B](underlying: Iterable[A], f: A => B) extends View[B] { + class Map[+A, +B](underlying: SomeIterableOps[A], f: A => B) extends View[B] { def iterator() = underlying.iterator().map(f) override def knownSize = underlying.knownSize } - case class MapValues[K, V, W](underlying: Iterable[(K, V)], f: V => W) extends View[(K, W)] { - def iterator(): Iterator[(K, W)] = underlying.iterator().map(kv => (kv._1, f(kv._2))) - override def knownSize: Int = underlying.knownSize - } - /** A view that flatmaps elements of the underlying collection. */ - case class FlatMap[A, B](underlying: Iterable[A], f: A => IterableOnce[B]) extends View[B] { + class FlatMap[A, B](underlying: SomeIterableOps[A], f: A => IterableOnce[B]) extends View[B] { def iterator() = underlying.iterator().flatMap(f) } /** A view that concatenates elements of the prefix collection or iterator with the elements * of the suffix collection or iterator. */ - case class Concat[A](prefix: Iterable[A], suffix: Iterable[A]) extends View[A] { + class Concat[A](prefix: SomeIterableOps[A], suffix: SomeIterableOps[A]) extends View[A] { def iterator() = prefix.iterator() ++ suffix.iterator() override def knownSize = if (prefix.knownSize >= 0 && suffix.knownSize >= 0) prefix.knownSize + suffix.knownSize @@ -209,7 +204,7 @@ object View extends IterableFactory[View] { /** A view that zips elements of the underlying collection with the elements * of another collection. */ - case class Zip[A, B](underlying: Iterable[A], other: Iterable[B]) extends View[(A, B)] { + class Zip[A, B](underlying: SomeIterableOps[A], other: Iterable[B]) extends View[(A, B)] { def iterator() = underlying.iterator().zip(other) override def knownSize = underlying.knownSize min other.knownSize } @@ -218,7 +213,7 @@ object View extends IterableFactory[View] { * 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. */ - case class ZipAll[A, B](underlying: Iterable[A], other: Iterable[B], thisElem: A, thatElem: B) extends View[(A, B)] { + class ZipAll[A, B](underlying: SomeIterableOps[A], other: Iterable[B], thisElem: A, thatElem: B) extends View[(A, B)] { def iterator() = underlying.iterator().zipAll(other, thisElem, thatElem) override def knownSize = { val s1 = underlying.knownSize @@ -230,18 +225,18 @@ object View extends IterableFactory[View] { } /** A view that appends an element to its elements */ - case class Append[A](underlying: Iterable[A], elem: A) extends View[A] { - def iterator(): Iterator[A] = Concat(underlying, View.Single(elem)).iterator() + class Appended[A](underlying: SomeIterableOps[A], elem: A) extends View[A] { + def iterator(): Iterator[A] = new Concat(underlying, new View.Single(elem)).iterator() override def knownSize: Int = if (underlying.knownSize >= 0) underlying.knownSize + 1 else -1 } /** A view that prepends an element to its elements */ - case class Prepend[A](elem: A, underlying: Iterable[A]) extends View[A] { - def iterator(): Iterator[A] = Concat(View.Single(elem), underlying).iterator() + class Prepended[+A](elem: A, underlying: SomeIterableOps[A]) extends View[A] { + def iterator(): Iterator[A] = new Concat(new View.Single(elem), underlying).iterator() override def knownSize: Int = if (underlying.knownSize >= 0) underlying.knownSize + 1 else -1 } - case class Updated[A](underlying: Iterable[A], index: Int, elem: A) extends View[A] { + class Updated[A](underlying: SomeIterableOps[A], index: Int, elem: A) extends View[A] { def iterator(): Iterator[A] = new Iterator[A] { private val it = underlying.iterator() private var i = 0 @@ -255,16 +250,16 @@ object View extends IterableFactory[View] { override def knownSize: Int = underlying.knownSize } - private[collection] class Patched[A](underlying: Iterable[A], from: Int, other: IterableOnce[A], replaced: Int) extends View[A] { + private[collection] class Patched[A](underlying: SomeIterableOps[A], from: Int, other: IterableOnce[A], replaced: Int) extends View[A] { def iterator(): Iterator[A] = underlying.iterator().patch(from, other.iterator(), replaced) } - case class ZipWithIndex[A](underlying: Iterable[A]) extends View[(A, Int)] { + class ZipWithIndex[A](underlying: SomeIterableOps[A]) extends View[(A, Int)] { def iterator(): Iterator[(A, Int)] = underlying.iterator().zipWithIndex override def knownSize: Int = underlying.knownSize } - case class Unzip[A, A1, A2](underlying: Iterable[A])(implicit asPair: A => (A1, A2)) { + class Unzip[A, A1, A2](underlying: SomeIterableOps[A])(implicit asPair: A => (A1, A2)) { val first: View[A1] = new View[A1] { def iterator(): Iterator[A1] = underlying.iterator().map(xs => asPair(xs)._1) @@ -277,7 +272,7 @@ object View extends IterableFactory[View] { } } - case class PadTo[A](underlying: Iterable[A], len: Int, elem: A) extends View[A] { + class PadTo[A](underlying: SomeIterableOps[A], len: Int, elem: A) extends View[A] { def iterator(): Iterator[A] = new Iterator[A] { private var i = 0 private val it = underlying.iterator() @@ -294,70 +289,3 @@ object View extends IterableFactory[View] { override def knownSize: Int = if (underlying.knownSize >= 0) underlying.knownSize max len else -1 } } - -/** View defined in terms of indexing a range */ -trait IndexedView[+A] extends View[A] with SeqOps[A, View, View[A]] { self => - - def iterator(): Iterator[A] = new AbstractIterator[A] { - private var current = 0 - override def knownSize: Int = self.length - current - def hasNext = current < self.length - def next(): A = { - val r = self.apply(current) - current += 1 - r - } - } - - final override def knownSize: Int = length - - override def take(n: Int): IndexedView[A] = new IndexedView.Take(this, n) - override def takeRight(n: Int): IndexedView[A] = new IndexedView.TakeRight(this, n) - override def drop(n: Int): IndexedView[A] = new IndexedView.Drop(this, n) - override def dropRight(n: Int): IndexedView[A] = new IndexedView.DropRight(this, n) - override def map[B](f: A => B): IndexedView[B] = new IndexedView.Map(this, f) - override def reverse: IndexedView[A] = IndexedView.Reverse(this) -} - -object IndexedView { - - class Take[A](underlying: IndexedView[A], n: Int) extends IndexedView[A] { - private[this] val normN = n max 0 - def length = underlying.length min normN - @throws[IndexOutOfBoundsException] - def apply(i: Int) = underlying.apply(i) - } - - class TakeRight[A](underlying: IndexedView[A], n: Int) extends IndexedView[A] { - private[this] val delta = (underlying.length - (n max 0)) max 0 - def length = underlying.length - delta - @throws[IndexOutOfBoundsException] - def apply(i: Int) = underlying.apply(i + delta) - } - - class Drop[A](underlying: IndexedView[A], n: Int) extends IndexedView[A] { - protected val normN = n max 0 - def length = (underlying.length - normN) max 0 - @throws[IndexOutOfBoundsException] - def apply(i: Int) = underlying.apply(i + normN) - } - - class DropRight[A](underlying: IndexedView[A], n: Int) extends IndexedView[A] { - private[this] val len = (underlying.length - (n max 0)) max 0 - def length = len - @throws[IndexOutOfBoundsException] - def apply(i: Int) = underlying.apply(i) - } - - class Map[A, B](underlying: IndexedView[A], f: A => B) extends IndexedView[B] { - def length = underlying.length - @throws[IndexOutOfBoundsException] - def apply(n: Int) = f(underlying.apply(n)) - } - - case class Reverse[A](underlying: IndexedView[A]) extends IndexedView[A] { - def length = underlying.length - @throws[IndexOutOfBoundsException] - def apply(i: Int) = underlying.apply(length - 1 - i) - } -} diff --git a/collections/src/main/scala/strawman/collection/concurrent/TrieMap.scala b/collections/src/main/scala/strawman/collection/concurrent/TrieMap.scala index 0c88cc8ee9..fa3cc7ca6a 100644 --- a/collections/src/main/scala/strawman/collection/concurrent/TrieMap.scala +++ b/collections/src/main/scala/strawman/collection/concurrent/TrieMap.scala @@ -955,11 +955,11 @@ final class TrieMap[K, V] private (r: AnyRef, rtupd: AtomicReferenceFieldUpdater if (nonReadOnly) readOnlySnapshot().keySet else super.keySet } - override def filterKeys(p: K => Boolean): collection.View[(K, V)] = { + override def filterKeys(p: K => Boolean): collection.MapView[K, V] = { if (nonReadOnly) readOnlySnapshot().filterKeys(p) else super.filterKeys(p) } - override def mapValues[W](f: V => W): collection.View[(K, W)] = { + override def mapValues[W](f: V => W): collection.MapView[K, W] = { if (nonReadOnly) readOnlySnapshot().mapValues(f) else super.mapValues(f) } diff --git a/collections/src/main/scala/strawman/collection/immutable/ImmutableArray.scala b/collections/src/main/scala/strawman/collection/immutable/ImmutableArray.scala index 4a77958642..79d1e7a9cb 100644 --- a/collections/src/main/scala/strawman/collection/immutable/ImmutableArray.scala +++ b/collections/src/main/scala/strawman/collection/immutable/ImmutableArray.scala @@ -74,7 +74,7 @@ sealed abstract class ImmutableArray[+A] Array.copy(bs.unsafeArray, 0, dest, length, bs.length) ImmutableArray.unsafeWrapArray(dest) case _ => - fromIterable(View.Concat(toIterable, xs)) + fromIterable(new View.Concat(toIterable, xs)) } override def prependedAll[B >: A](xs: collection.Iterable[B]): ImmutableArray[B] = @@ -85,7 +85,7 @@ sealed abstract class ImmutableArray[+A] Array.copy(unsafeArray, 0, dest, bs.length, length) ImmutableArray.unsafeWrapArray(dest) case _ => - fromIterable(View.Concat(xs, toIterable)) + fromIterable(new View.Concat(xs, toIterable)) } override def zip[B](that: collection.Iterable[B]): ImmutableArray[(A, B)] = @@ -95,7 +95,7 @@ sealed abstract class ImmutableArray[+A] (apply(i), bs(i)) } case _ => - fromIterable(View.Zip(toIterable, that)) + fromIterable(new View.Zip(toIterable, that)) } override def take(n: Int): ImmutableArray[A] = iterableFactory.tabulate(n)(apply) diff --git a/collections/src/main/scala/strawman/collection/immutable/IntMap.scala b/collections/src/main/scala/strawman/collection/immutable/IntMap.scala index c435a0fb88..56fad414cf 100644 --- a/collections/src/main/scala/strawman/collection/immutable/IntMap.scala +++ b/collections/src/main/scala/strawman/collection/immutable/IntMap.scala @@ -303,9 +303,9 @@ sealed abstract class IntMap[+T] extends Map[Int, T] case IntMap.Nil => IntMap.Tip(key, value) } - def map[V2](f: ((Int, T)) => (Int, V2)): IntMap[V2] = intMapFromIterable(View.Map(toIterable, f)) + def map[V2](f: ((Int, T)) => (Int, V2)): IntMap[V2] = intMapFromIterable(new View.Map(toIterable, f)) - def flatMap[V2](f: ((Int, T)) => IterableOnce[(Int, V2)]): IntMap[V2] = intMapFromIterable(View.FlatMap(toIterable, f)) + def flatMap[V2](f: ((Int, T)) => IterableOnce[(Int, V2)]): IntMap[V2] = intMapFromIterable(new View.FlatMap(toIterable, f)) override def concat [V1 >: T](that: collection.Iterable[(Int, V1)]): IntMap[V1] = super.concat(that).asInstanceOf[IntMap[V1]] // Already has corect type but not declared as such diff --git a/collections/src/main/scala/strawman/collection/immutable/LongMap.scala b/collections/src/main/scala/strawman/collection/immutable/LongMap.scala index ee9862ca88..74e1d0d41c 100644 --- a/collections/src/main/scala/strawman/collection/immutable/LongMap.scala +++ b/collections/src/main/scala/strawman/collection/immutable/LongMap.scala @@ -450,9 +450,9 @@ sealed abstract class LongMap[+T] extends Map[Long, T] case LongMap.Nil => throw new IllegalStateException("Empty set") } - def map[V2](f: ((Long, T)) => (Long, V2)): LongMap[V2] = LongMap.from(View.Map(coll, f)) + def map[V2](f: ((Long, T)) => (Long, V2)): LongMap[V2] = LongMap.from(new View.Map(coll, f)) - def flatMap[V2](f: ((Long, T)) => IterableOnce[(Long, V2)]): LongMap[V2] = LongMap.from(View.FlatMap(coll, f)) + def flatMap[V2](f: ((Long, T)) => IterableOnce[(Long, V2)]): LongMap[V2] = LongMap.from(new View.FlatMap(coll, f)) override def concat [V1 >: T](that: strawman.collection.Iterable[(Long, V1)]): LongMap[V1] = super.concat(that).asInstanceOf[LongMap[V1]] // Already has corect type but not declared as such diff --git a/collections/src/main/scala/strawman/collection/immutable/Map.scala b/collections/src/main/scala/strawman/collection/immutable/Map.scala index e903613e06..658c419749 100644 --- a/collections/src/main/scala/strawman/collection/immutable/Map.scala +++ b/collections/src/main/scala/strawman/collection/immutable/Map.scala @@ -173,6 +173,7 @@ object Map extends MapFactory[Map] { @SerialVersionUID(3L) private object EmptyMap extends Map[Any, Nothing] with Serializable { override def size: Int = 0 + override def knownSize: Int = 0 override def apply(key: Any) = throw new NoSuchElementException("key not found: " + key) override def contains(key: Any) = false def get(key: Any): Option[Nothing] = None @@ -183,7 +184,8 @@ object Map extends MapFactory[Map] { @SerialVersionUID(3L) final class Map1[K, +V](key1: K, value1: V) extends Map[K, V] with Serializable { - override def size = 1 + override def size: Int = 1 + override def knownSize: Int = 1 override def apply(key: K) = if (key == key1) value1 else throw new NoSuchElementException("key not found: " + key) override def contains(key: K) = key == key1 def get(key: K): Option[V] = @@ -201,7 +203,8 @@ object Map extends MapFactory[Map] { @SerialVersionUID(3L) final class Map2[K, +V](key1: K, value1: V, key2: K, value2: V) extends Map[K, V] with Serializable { - override def size = 2 + override def size: Int = 2 + override def knownSize: Int = 2 override def apply(key: K) = if (key == key1) value1 else if (key == key2) value2 @@ -227,7 +230,8 @@ object Map extends MapFactory[Map] { @SerialVersionUID(3L) class Map3[K, +V](key1: K, value1: V, key2: K, value2: V, key3: K, value3: V) extends Map[K, V] with Serializable { - override def size = 3 + override def size: Int = 3 + override def knownSize: Int = 3 override def apply(key: K) = if (key == key1) value1 else if (key == key2) value2 @@ -257,7 +261,8 @@ object Map extends MapFactory[Map] { @SerialVersionUID(3L) final class Map4[K, +V](key1: K, value1: V, key2: K, value2: V, key3: K, value3: V, key4: K, value4: V) extends Map[K, V] with Serializable { - override def size = 4 + override def size: Int = 4 + override def knownSize: Int = 4 override def apply(key: K) = if (key == key1) value1 else if (key == key2) value2 diff --git a/collections/src/main/scala/strawman/collection/immutable/Seq.scala b/collections/src/main/scala/strawman/collection/immutable/Seq.scala index 0657ac795a..d8a385f404 100644 --- a/collections/src/main/scala/strawman/collection/immutable/Seq.scala +++ b/collections/src/main/scala/strawman/collection/immutable/Seq.scala @@ -26,7 +26,7 @@ trait SeqOps[+A, +CC[_], +C] extends Any with collection.SeqOps[A, CC, C] { * @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`. */ - def updated[B >: A](index: Int, elem: B): CC[B] = fromIterable(View.Updated(toIterable, index, elem)) + def updated[B >: A](index: Int, elem: B): CC[B] = fromIterable(new View.Updated(this, index, elem)) } /** @@ -49,7 +49,17 @@ trait IndexedSeq[+A] extends Seq[A] object IndexedSeq extends SeqFactory.Delegate[IndexedSeq](Vector) /** Base trait for immutable indexed Seq operations */ -trait IndexedSeqOps[+A, +CC[X] <: IndexedSeq[X], +C] extends SeqOps[A, CC, C] with collection.IndexedSeqOps[A, CC, C] +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] diff --git a/collections/src/main/scala/strawman/collection/immutable/Vector.scala b/collections/src/main/scala/strawman/collection/immutable/Vector.scala index 605faa1057..339d4a57ae 100644 --- a/collections/src/main/scala/strawman/collection/immutable/Vector.scala +++ b/collections/src/main/scala/strawman/collection/immutable/Vector.scala @@ -167,11 +167,6 @@ final class Vector[+A] private[immutable] (private[collection] val startIndex: I dropRight(1) } - override def slice(from: Int, until: Int): Vector[A] = - take(until).drop(from) - - override def splitAt(n: Int): (Vector[A], Vector[A]) = (take(n), drop(n)) - // appendAll (suboptimal but avoids worst performance gotchas) override def appendedAll[B >: A](suffix: collection.Iterable[B]): Vector[B] = { import Vector.{Log2ConcatFaster, TinyAppendFaster} diff --git a/collections/src/main/scala/strawman/collection/mutable/AnyRefMap.scala b/collections/src/main/scala/strawman/collection/mutable/AnyRefMap.scala index e385b3a330..7633fec8da 100644 --- a/collections/src/main/scala/strawman/collection/mutable/AnyRefMap.scala +++ b/collections/src/main/scala/strawman/collection/mutable/AnyRefMap.scala @@ -425,9 +425,9 @@ class AnyRefMap[K <: AnyRef, V] private[collection] (defaultEntry: K => V, initi // The `K with AnyRef` parameter type is necessary to distinguish these methods from the base methods they overload (not override) // TODO: Remove the unnecessary implicit in Scala 2.13; Dotty requires it for disambiguation def map[K2 <: AnyRef, V2](f: ((K with AnyRef, V)) => (K2, V2))(implicit ev: K2 <:< AnyRef): AnyRefMap[K2, V2] = - AnyRefMap.from(View.Map(toIterable, f)) + AnyRefMap.from(new View.Map(toIterable, f)) def flatMap[K2 <: AnyRef, V2](f: ((K with AnyRef, V)) => IterableOnce[(K2, V2)])(implicit ev: K2 <:< AnyRef): AnyRefMap[K2, V2] = - AnyRefMap.from(View.FlatMap(toIterable, f)) + AnyRefMap.from(new View.FlatMap(toIterable, f)) } object AnyRefMap { diff --git a/collections/src/main/scala/strawman/collection/mutable/IndexedSeq.scala b/collections/src/main/scala/strawman/collection/mutable/IndexedSeq.scala index 08b2e87784..c360dfa6db 100644 --- a/collections/src/main/scala/strawman/collection/mutable/IndexedSeq.scala +++ b/collections/src/main/scala/strawman/collection/mutable/IndexedSeq.scala @@ -1,6 +1,8 @@ package strawman.collection package mutable +import scala.AnyRef + trait IndexedSeq[T] extends Seq[T] with strawman.collection.IndexedSeq[T] with IndexedSeqOps[T, IndexedSeq, IndexedSeq[T]] { @@ -10,6 +12,6 @@ trait IndexedSeq[T] extends Seq[T] object IndexedSeq extends SeqFactory.Delegate[IndexedSeq](ArrayBuffer) -trait IndexedSeqOps[A, +CC[X] <: IndexedSeq[X], +C <: IndexedSeq[A]] +trait IndexedSeqOps[A, +CC[_], +C <: AnyRef] extends strawman.collection.IndexedSeqOps[A, CC, C] with SeqOps[A, CC, C] diff --git a/collections/src/main/scala/strawman/collection/mutable/LongMap.scala b/collections/src/main/scala/strawman/collection/mutable/LongMap.scala index 6f359696ce..79b8bc72cb 100644 --- a/collections/src/main/scala/strawman/collection/mutable/LongMap.scala +++ b/collections/src/main/scala/strawman/collection/mutable/LongMap.scala @@ -517,9 +517,9 @@ final class LongMap[V] private[collection] (defaultEntry: Long => V, initialBuff this } - def map[V2](f: ((Long, V)) => (Long, V2)): LongMap[V2] = LongMap.from(View.Map(coll, f)) + def map[V2](f: ((Long, V)) => (Long, V2)): LongMap[V2] = LongMap.from(new View.Map(coll, f)) - def flatMap[V2](f: ((Long, V)) => IterableOnce[(Long, V2)]): LongMap[V2] = LongMap.from(View.FlatMap(coll, f)) + def flatMap[V2](f: ((Long, V)) => IterableOnce[(Long, V2)]): LongMap[V2] = LongMap.from(new View.FlatMap(coll, f)) } object LongMap { diff --git a/collections/src/main/scala/strawman/collection/mutable/Seq.scala b/collections/src/main/scala/strawman/collection/mutable/Seq.scala index 419aaeb077..371860ae64 100644 --- a/collections/src/main/scala/strawman/collection/mutable/Seq.scala +++ b/collections/src/main/scala/strawman/collection/mutable/Seq.scala @@ -1,6 +1,6 @@ package strawman.collection.mutable -import scala.{Array, Boolean, IllegalArgumentException, IndexOutOfBoundsException, Int, Long, Unit, throws} +import scala.{AnyRef, Array, Boolean, IllegalArgumentException, IndexOutOfBoundsException, Int, Long, Unit, throws} import strawman.collection import strawman.collection.{IterableOnce, SeqFactory, toNewSeq, toOldSeq} @@ -25,14 +25,14 @@ object Seq extends SeqFactory.Delegate[Seq](ArrayBuffer) * @define coll mutable sequence * @define Coll `mutable.Seq` */ -trait SeqOps[A, +CC[X] <: Seq[X], +C <: Seq[A]] +trait SeqOps[A, +CC[_], +C <: AnyRef] extends IterableOps[A, CC, C] with collection.SeqOps[A, CC, C] with Cloneable[C] { override def clone(): C = { val b = newSpecificBuilder() - b ++= coll + b ++= toIterable b.result() } diff --git a/documentation/DESIGN.md b/documentation/DESIGN.md index 93d665bf76..7ec444249e 100644 --- a/documentation/DESIGN.md +++ b/documentation/DESIGN.md @@ -218,8 +218,8 @@ As an example, here is how the default implementation of `map` and `take` are defined: ~~~ scala -def take(n: Int): C = fromSpecificIterable(View.Take(toIterable, n)) -def map[B](f: A => B): CC[B] = fromIterable(View.Map(toIterable, f)) +def take(n: Int): C = fromSpecificIterable(new View.Take(toIterable, n)) +def map[B](f: A => B): CC[B] = fromIterable(new View.Map(toIterable, f)) ~~~ `View.Map` creates a `View` that applies the function `f` to the elements diff --git a/test/junit/src/test/scala/strawman/collection/FactoriesTest.scala b/test/junit/src/test/scala/strawman/collection/FactoriesTest.scala index 6432efea1f..0de3f5b8c3 100644 --- a/test/junit/src/test/scala/strawman/collection/FactoriesTest.scala +++ b/test/junit/src/test/scala/strawman/collection/FactoriesTest.scala @@ -29,7 +29,7 @@ class FactoriesTest { } def apply(factory: IterableFactory[Iterable]): Unit = { - assertTrue(factory(1, 2, 3).iterator().sameElements(View.Elems(1, 2, 3))) + assertTrue(factory(1, 2, 3).iterator().sameElements(new View.Elems(1, 2, 3))) } def iterate(factory: IterableFactory[Iterable]): Unit = { diff --git a/test/junit/src/test/scala/strawman/collection/ViewTest.scala b/test/junit/src/test/scala/strawman/collection/ViewTest.scala index 61fce4e47a..5ae4a9c6f0 100644 --- a/test/junit/src/test/scala/strawman/collection/ViewTest.scala +++ b/test/junit/src/test/scala/strawman/collection/ViewTest.scala @@ -1,5 +1,7 @@ package strawman.collection +import strawman.collection.immutable.List + import org.junit.Assert._ import org.junit.Test import org.junit.runner.RunWith @@ -19,4 +21,34 @@ class ViewTest { assertEquals(iter, iter.view drop Int.MinValue to Iterable) assertEquals(iter, iter.view dropRight Int.MinValue to Iterable) } + + @Test + def seqView(): Unit = { + val xs = List(1, 2, 3).view + assertEquals(List(3, 2, 1), xs.reverse.to(List)) + assertEquals(2, xs(1)) +// assertEquals(xs, xs.reverse.reverse.to(List)) doesn’t compile + } + + @Test + def mapView(): Unit = { + val xs = immutable.Map(1 -> "a", 2 -> "b") + assertEquals("a", xs.view(1)) + val ys = xs.mapValues(s => s.toUpperCase) + assertTrue(ys.contains(1)) + assertEquals("B", ys(2)) + } + + @Test + def viewsViewIsNoOp(): Unit = { + def check[A](it: Iterable[A]): Unit = { + val view = it.view + assertTrue(view eq view.view) + } + check(immutable.Set(1, 2, 3)) // View + check(List(1, 2, 3)) // SeqView + check(immutable.Vector(1, 2, 3)) // IndexedView + check(immutable.Map(1 -> "a", 2 -> "b")) // MapView + } + }