|
| 1 | +/* |
| 2 | + * Scala (https://www.scala-lang.org) |
| 3 | + * |
| 4 | + * Copyright EPFL and Lightbend, Inc. |
| 5 | + * |
| 6 | + * Licensed under Apache License 2.0 |
| 7 | + * (http://www.apache.org/licenses/LICENSE-2.0). |
| 8 | + * |
| 9 | + * See the NOTICE file distributed with this work for |
| 10 | + * additional information regarding copyright ownership. |
| 11 | + */ |
| 12 | + |
| 13 | +package scala |
| 14 | +package collection |
| 15 | + |
| 16 | +import scala.annotation.nowarn |
| 17 | +import language.experimental.captureChecking |
| 18 | +import caps.unsafe.unsafeAssumePure |
| 19 | + |
| 20 | +/** !!! Scala 2 difference: Need intermediate trait SeqViewOps to collect the |
| 21 | + * necessary functionality over which SeqViews are defined, and at the same |
| 22 | + * time allowing impure operations. Scala 2 uses SeqOps here, but SeqOps is |
| 23 | + * pure, whereas SeqViews are Iterables which can be impure (for instance, |
| 24 | + * mapping a SeqView with an impure function gives an impure view). |
| 25 | + */ |
| 26 | +trait SeqViewOps[+A, +CC[_], +C] extends Any with IterableOps[A, CC, C] { |
| 27 | + self: SeqViewOps[A, CC, C]^ => |
| 28 | + |
| 29 | + def length: Int |
| 30 | + def apply(x: Int): A |
| 31 | + def appended[B >: A](elem: B): CC[B]^{this} |
| 32 | + def prepended[B >: A](elem: B): CC[B]^{this} |
| 33 | + def reverse: C^{this} |
| 34 | + def sorted[B >: A](implicit ord: Ordering[B]): C^{this} |
| 35 | + |
| 36 | + def reverseIterator: Iterator[A]^{this} = reversed.iterator |
| 37 | +} |
| 38 | + |
| 39 | +trait SeqView[+A] extends SeqViewOps[A, View, View[A]] with View[A] { |
| 40 | + self: SeqView[A]^ => |
| 41 | + |
| 42 | + override def view: SeqView[A]^{this} = this |
| 43 | + |
| 44 | + override def map[B](f: A => B): SeqView[B]^{this, f} = new SeqView.Map(this, f) |
| 45 | + override def appended[B >: A](elem: B): SeqView[B]^{this} = new SeqView.Appended(this, elem) |
| 46 | + override def prepended[B >: A](elem: B): SeqView[B]^{this} = new SeqView.Prepended(elem, this) |
| 47 | + override def reverse: SeqView[A]^{this} = new SeqView.Reverse(this) |
| 48 | + override def take(n: Int): SeqView[A]^{this} = new SeqView.Take(this, n) |
| 49 | + override def drop(n: Int): SeqView[A]^{this} = new SeqView.Drop(this, n) |
| 50 | + override def takeRight(n: Int): SeqView[A]^{this} = new SeqView.TakeRight(this, n) |
| 51 | + override def dropRight(n: Int): SeqView[A]^{this} = new SeqView.DropRight(this, n) |
| 52 | + override def tapEach[U](f: A => U): SeqView[A]^{this, f} = new SeqView.Map(this, { (a: A) => f(a); a }) |
| 53 | + |
| 54 | + def concat[B >: A](suffix: SeqView.SomeSeqOps[B]): SeqView[B]^{this} = new SeqView.Concat(this, suffix) |
| 55 | + def appendedAll[B >: A](suffix: SeqView.SomeSeqOps[B]): SeqView[B]^{this} = new SeqView.Concat(this, suffix) |
| 56 | + def prependedAll[B >: A](prefix: SeqView.SomeSeqOps[B]): SeqView[B]^{this} = new SeqView.Concat(prefix, this) |
| 57 | + |
| 58 | + override def sorted[B >: A](implicit ord: Ordering[B]): SeqView[A]^{this} = new SeqView.Sorted(this, ord) |
| 59 | + |
| 60 | + @nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""") |
| 61 | + override protected[this] def stringPrefix: String = "SeqView" |
| 62 | +} |
| 63 | + |
| 64 | +object SeqView { |
| 65 | + |
| 66 | + /** A `SeqOps` whose collection type and collection type constructor are unknown */ |
| 67 | + private type SomeSeqOps[+A] = SeqViewOps[A, AnyConstr, _] |
| 68 | + |
| 69 | + /** A view that doesn’t apply any transformation to an underlying sequence */ |
| 70 | + @SerialVersionUID(3L) |
| 71 | + class Id[+A](underlying: SomeSeqOps[A]^) extends AbstractSeqView[A] { |
| 72 | + def apply(idx: Int): A = underlying.apply(idx) |
| 73 | + def length: Int = underlying.length |
| 74 | + def iterator: Iterator[A]^{this} = underlying.iterator |
| 75 | + override def knownSize: Int = underlying.knownSize |
| 76 | + override def isEmpty: Boolean = underlying.isEmpty |
| 77 | + } |
| 78 | + |
| 79 | + @SerialVersionUID(3L) |
| 80 | + class Map[+A, +B](underlying: SomeSeqOps[A]^, f: A => B) extends View.Map[A, B](underlying, f) with SeqView[B] { |
| 81 | + def apply(idx: Int): B = f(underlying(idx)) |
| 82 | + def length: Int = underlying.length |
| 83 | + } |
| 84 | + |
| 85 | + @SerialVersionUID(3L) |
| 86 | + class Appended[+A](underlying: SomeSeqOps[A]^, elem: A) extends View.Appended(underlying, elem) with SeqView[A] { |
| 87 | + def apply(idx: Int): A = if (idx == underlying.length) elem else underlying(idx) |
| 88 | + def length: Int = underlying.length + 1 |
| 89 | + } |
| 90 | + |
| 91 | + @SerialVersionUID(3L) |
| 92 | + class Prepended[+A](elem: A, underlying: SomeSeqOps[A]^) extends View.Prepended(elem, underlying) with SeqView[A] { |
| 93 | + def apply(idx: Int): A = if (idx == 0) elem else underlying(idx - 1) |
| 94 | + def length: Int = underlying.length + 1 |
| 95 | + } |
| 96 | + |
| 97 | + @SerialVersionUID(3L) |
| 98 | + class Concat[A](prefix: SomeSeqOps[A]^, suffix: SomeSeqOps[A]^) extends View.Concat[A](prefix, suffix) with SeqView[A] { |
| 99 | + def apply(idx: Int): A = { |
| 100 | + val l = prefix.length |
| 101 | + if (idx < l) prefix(idx) else suffix(idx - l) |
| 102 | + } |
| 103 | + def length: Int = prefix.length + suffix.length |
| 104 | + } |
| 105 | + |
| 106 | + @SerialVersionUID(3L) |
| 107 | + class Reverse[A](underlying: SomeSeqOps[A]^) extends AbstractSeqView[A] { |
| 108 | + def apply(i: Int) = underlying.apply(size - 1 - i) |
| 109 | + def length = underlying.size |
| 110 | + def iterator: Iterator[A]^{this} = underlying.reverseIterator |
| 111 | + override def knownSize: Int = underlying.knownSize |
| 112 | + override def isEmpty: Boolean = underlying.isEmpty |
| 113 | + } |
| 114 | + |
| 115 | + @SerialVersionUID(3L) |
| 116 | + class Take[+A](underlying: SomeSeqOps[A]^, n: Int) extends View.Take(underlying, n) with SeqView[A] { |
| 117 | + def apply(idx: Int): A = if (idx < n) { |
| 118 | + underlying(idx) |
| 119 | + } else { |
| 120 | + throw new IndexOutOfBoundsException(s"$idx is out of bounds (min 0, max ${if (underlying.knownSize >= 0) knownSize - 1 else "unknown"})") |
| 121 | + } |
| 122 | + def length: Int = underlying.length min normN |
| 123 | + } |
| 124 | + |
| 125 | + @SerialVersionUID(3L) |
| 126 | + class TakeRight[+A](underlying: SomeSeqOps[A]^, n: Int) extends View.TakeRight(underlying, n) with SeqView[A] { |
| 127 | + private[this] val delta = (underlying.size - (n max 0)) max 0 |
| 128 | + def length = underlying.size - delta |
| 129 | + @throws[IndexOutOfBoundsException] |
| 130 | + def apply(i: Int) = underlying.apply(i + delta) |
| 131 | + } |
| 132 | + |
| 133 | + @SerialVersionUID(3L) |
| 134 | + class Drop[A](underlying: SomeSeqOps[A]^, n: Int) extends View.Drop[A](underlying, n) with SeqView[A] { |
| 135 | + def length = (underlying.size - normN) max 0 |
| 136 | + @throws[IndexOutOfBoundsException] |
| 137 | + def apply(i: Int) = underlying.apply(i + normN) |
| 138 | + override def drop(n: Int): SeqView[A]^{this} = new Drop(underlying, this.n + n) |
| 139 | + } |
| 140 | + |
| 141 | + @SerialVersionUID(3L) |
| 142 | + class DropRight[A](underlying: SomeSeqOps[A]^, n: Int) extends View.DropRight[A](underlying, n) with SeqView[A] { |
| 143 | + private[this] val len = (underlying.size - (n max 0)) max 0 |
| 144 | + def length = len |
| 145 | + @throws[IndexOutOfBoundsException] |
| 146 | + def apply(i: Int) = underlying.apply(i) |
| 147 | + } |
| 148 | + |
| 149 | + @SerialVersionUID(3L) |
| 150 | + class Sorted[A, B >: A] private (private[this] var underlying: SomeSeqOps[A]^, |
| 151 | + private[this] val len: Int, |
| 152 | + ord: Ordering[B]) |
| 153 | + extends SeqView[A] { |
| 154 | + outer: Sorted[A, B]^ => |
| 155 | + |
| 156 | + // force evaluation immediately by calling `length` so infinite collections |
| 157 | + // hang on `sorted`/`sortWith`/`sortBy` rather than on arbitrary method calls |
| 158 | + def this(underlying: SomeSeqOps[A]^, ord: Ordering[B]) = this(underlying, underlying.length, ord) |
| 159 | + |
| 160 | + @SerialVersionUID(3L) |
| 161 | + private[this] class ReverseSorted extends SeqView[A] { |
| 162 | + private[this] lazy val _reversed = new SeqView.Reverse(_sorted) |
| 163 | + |
| 164 | + def apply(i: Int): A = _reversed.apply(i) |
| 165 | + def length: Int = len |
| 166 | + def iterator: Iterator[A]^{this} = Iterator.empty ++ _reversed.iterator // very lazy |
| 167 | + override def knownSize: Int = len |
| 168 | + override def isEmpty: Boolean = len == 0 |
| 169 | + override def to[C1](factory: Factory[A, C1]): C1 = _reversed.to(factory) |
| 170 | + override def reverse: SeqView[A]^{outer} = outer |
| 171 | + override protected def reversed: Iterable[A] = outer.unsafeAssumePure |
| 172 | + |
| 173 | + override def sorted[B1 >: A](implicit ord1: Ordering[B1]): SeqView[A]^{this} = |
| 174 | + if (ord1 == Sorted.this.ord) outer.unsafeAssumePure |
| 175 | + else if (ord1.isReverseOf(Sorted.this.ord)) this |
| 176 | + else new Sorted(elems, len, ord1) |
| 177 | + } |
| 178 | + |
| 179 | + @volatile private[this] var evaluated = false |
| 180 | + |
| 181 | + private[this] lazy val _sorted: Seq[A] = { |
| 182 | + val res = { |
| 183 | + val len = this.len |
| 184 | + if (len == 0) Nil |
| 185 | + else if (len == 1) List(underlying.head) |
| 186 | + else { |
| 187 | + val arr = new Array[Any](len) // Array[Any] =:= Array[AnyRef] |
| 188 | + underlying.copyToArray(arr) |
| 189 | + java.util.Arrays.sort(arr.asInstanceOf[Array[AnyRef]], ord.asInstanceOf[Ordering[AnyRef]]) |
| 190 | + // casting the Array[AnyRef] to Array[A] and creating an ArraySeq from it |
| 191 | + // is safe because: |
| 192 | + // - the ArraySeq is immutable, and items that are not of type A |
| 193 | + // cannot be added to it |
| 194 | + // - we know it only contains items of type A (and if this collection |
| 195 | + // contains items of another type, we'd get a CCE anyway) |
| 196 | + // - the cast doesn't actually do anything in the runtime because the |
| 197 | + // type of A is not known and Array[_] is Array[AnyRef] |
| 198 | + immutable.ArraySeq.unsafeWrapArray(arr.asInstanceOf[Array[A]]) |
| 199 | + } |
| 200 | + } |
| 201 | + evaluated = true |
| 202 | + underlying = null |
| 203 | + res |
| 204 | + } |
| 205 | + |
| 206 | + private[this] def elems: SomeSeqOps[A]^{this} = { |
| 207 | + val orig = underlying |
| 208 | + if (evaluated) _sorted else orig |
| 209 | + } |
| 210 | + |
| 211 | + def apply(i: Int): A = _sorted.apply(i) |
| 212 | + def length: Int = len |
| 213 | + def iterator: Iterator[A]^{this} = Iterator.empty ++ _sorted.iterator // very lazy |
| 214 | + override def knownSize: Int = len |
| 215 | + override def isEmpty: Boolean = len == 0 |
| 216 | + override def to[C1](factory: Factory[A, C1]): C1 = _sorted.to(factory) |
| 217 | + override def reverse: SeqView[A] = new ReverseSorted |
| 218 | + // we know `_sorted` is either tiny or has efficient random access, |
| 219 | + // so this is acceptable for `reversed` |
| 220 | + override protected def reversed: Iterable[A] = new ReverseSorted |
| 221 | + |
| 222 | + override def sorted[B1 >: A](implicit ord1: Ordering[B1]): SeqView[A]^{this} = |
| 223 | + if (ord1 == this.ord) this |
| 224 | + else if (ord1.isReverseOf(this.ord)) reverse |
| 225 | + else new Sorted(elems, len, ord1) |
| 226 | + } |
| 227 | +} |
| 228 | + |
| 229 | +/** Explicit instantiation of the `SeqView` trait to reduce class file size in subclasses. */ |
| 230 | +@SerialVersionUID(3L) |
| 231 | +abstract class AbstractSeqView[+A] extends AbstractView[A] with SeqView[A] |
0 commit comments