Skip to content

Commit bd4db97

Browse files
committed
Add IndexedSeqView to lib
1 parent 35f2246 commit bd4db97

File tree

2 files changed

+191
-2
lines changed

2 files changed

+191
-2
lines changed

tests/pos-special/stdlib/collection/IndexedSeq.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import scala.collection.Searching.{Found, InsertionPoint, SearchResult}
1818
import scala.collection.Stepper.EfficientSplit
1919
import scala.math.Ordering
2020
import language.experimental.captureChecking
21+
import caps.unsafe.unsafeAssumePure
22+
2123

2224
/** Base trait for indexed sequences that have efficient `apply` and `length` */
2325
trait IndexedSeq[+A] extends Seq[A]
@@ -33,7 +35,7 @@ trait IndexedSeq[+A] extends Seq[A]
3335
object IndexedSeq extends SeqFactory.Delegate[IndexedSeq](immutable.IndexedSeq)
3436

3537
/** Base trait for indexed Seq operations */
36-
trait IndexedSeqOps[+A, +CC[_], +C] extends Any with SeqOps[A, CC, C] { self =>
38+
trait IndexedSeqOps[+A, +CC[_], +C] extends Any with IndexedSeqViewOps[A, CC, C] with SeqOps[A, CC, C] { self =>
3739

3840
def iterator: Iterator[A] = view.iterator
3941

@@ -86,7 +88,7 @@ trait IndexedSeqOps[+A, +CC[_], +C] extends Any with SeqOps[A, CC, C] { self =>
8688

8789
override def dropRight(n: Int): C = fromSpecific(new IndexedSeqView.DropRight(this, n))
8890

89-
override def map[B](f: A => B): CC[B] = iterableFactory.from(new IndexedSeqView.Map(this, f))
91+
override def map[B](f: A => B): CC[B] = iterableFactory.from(new IndexedSeqView.Map(this, f)).unsafeAssumePure
9092

9193
override def reverse: C = fromSpecific(new IndexedSeqView.Reverse(this))
9294

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
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+
19+
trait IndexedSeqViewOps[+A, +CC[_], +C] extends Any with SeqViewOps[A, CC, C] {
20+
self: IndexedSeqViewOps[A, CC, C]^ =>
21+
}
22+
23+
/** View defined in terms of indexing a range */
24+
trait IndexedSeqView[+A] extends IndexedSeqViewOps[A, View, View[A]] with SeqView[A] {
25+
self: IndexedSeqView[A]^ =>
26+
27+
override def view: IndexedSeqView[A]^{this} = this
28+
29+
@deprecated("Use .view.slice(from, until) instead of .view(from, until)", "2.13.0")
30+
override def view(from: Int, until: Int): IndexedSeqView[A]^{this} = view.slice(from, until)
31+
32+
override def iterator: Iterator[A]^{this} = new IndexedSeqView.IndexedSeqViewIterator(this)
33+
override def reverseIterator: Iterator[A]^{this} = new IndexedSeqView.IndexedSeqViewReverseIterator(this)
34+
35+
override def appended[B >: A](elem: B): IndexedSeqView[B]^{this} = new IndexedSeqView.Appended(this, elem)
36+
override def prepended[B >: A](elem: B): IndexedSeqView[B]^{this} = new IndexedSeqView.Prepended(elem, this)
37+
override def take(n: Int): IndexedSeqView[A]^{this} = new IndexedSeqView.Take(this, n)
38+
override def takeRight(n: Int): IndexedSeqView[A]^{this} = new IndexedSeqView.TakeRight(this, n)
39+
override def drop(n: Int): IndexedSeqView[A]^{this} = new IndexedSeqView.Drop(this, n)
40+
override def dropRight(n: Int): IndexedSeqView[A]^{this} = new IndexedSeqView.DropRight(this, n)
41+
override def map[B](f: A => B): IndexedSeqView[B]^{this, f} = new IndexedSeqView.Map(this, f)
42+
override def reverse: IndexedSeqView[A]^{this} = new IndexedSeqView.Reverse(this)
43+
override def slice(from: Int, until: Int): IndexedSeqView[A]^{this} = new IndexedSeqView.Slice(this, from, until)
44+
override def tapEach[U](f: A => U): IndexedSeqView[A]^{this, f} = new IndexedSeqView.Map(this, { (a: A) => f(a); a})
45+
46+
def concat[B >: A](suffix: IndexedSeqView.SomeIndexedSeqViewOps[B]): IndexedSeqView[B]^{this} = new IndexedSeqView.Concat(this, suffix)
47+
def appendedAll[B >: A](suffix: IndexedSeqView.SomeIndexedSeqViewOps[B]): IndexedSeqView[B]^{this} = new IndexedSeqView.Concat(this, suffix)
48+
def prependedAll[B >: A](prefix: IndexedSeqView.SomeIndexedSeqViewOps[B]): IndexedSeqView[B]^{this} = new IndexedSeqView.Concat(prefix, this)
49+
50+
@nowarn("""cat=deprecation&origin=scala\.collection\.Iterable\.stringPrefix""")
51+
override protected[this] def stringPrefix: String = "IndexedSeqView"
52+
}
53+
54+
object IndexedSeqView {
55+
56+
@SerialVersionUID(3L)
57+
private[collection] class IndexedSeqViewIterator[A](self: IndexedSeqView[A]^) extends AbstractIterator[A] with Serializable {
58+
this: IndexedSeqViewIterator[A]^ =>
59+
private[this] var current = 0
60+
private[this] var remainder = self.length
61+
override def knownSize: Int = remainder
62+
@inline private[this] def _hasNext: Boolean = remainder > 0
63+
def hasNext: Boolean = _hasNext
64+
def next(): A =
65+
if (_hasNext) {
66+
val r = self(current)
67+
current += 1
68+
remainder -= 1
69+
r
70+
} else Iterator.empty.next()
71+
72+
override def drop(n: Int): Iterator[A]^{this} = {
73+
if (n > 0) {
74+
current += n
75+
remainder = Math.max(0, remainder - n)
76+
}
77+
this
78+
}
79+
80+
override protected def sliceIterator(from: Int, until: Int): Iterator[A]^{this} = {
81+
82+
def formatRange(value : Int) : Int = if (value < 0) 0 else if (value > remainder) remainder else value
83+
84+
val formatFrom = formatRange(from)
85+
val formatUntil = formatRange(until)
86+
remainder = Math.max(0, formatUntil - formatFrom)
87+
current = current + formatFrom
88+
this
89+
}
90+
}
91+
@SerialVersionUID(3L)
92+
private[collection] class IndexedSeqViewReverseIterator[A](self: IndexedSeqView[A]^) extends AbstractIterator[A] with Serializable {
93+
this: IndexedSeqViewReverseIterator[A]^ =>
94+
private[this] var remainder = self.length
95+
private[this] var pos = remainder - 1
96+
@inline private[this] def _hasNext: Boolean = remainder > 0
97+
def hasNext: Boolean = _hasNext
98+
def next(): A =
99+
if (_hasNext) {
100+
val r = self(pos)
101+
pos -= 1
102+
remainder -= 1
103+
r
104+
} else Iterator.empty.next()
105+
106+
// from < 0 means don't move pos, until < 0 means don't limit remainder
107+
//
108+
override protected def sliceIterator(from: Int, until: Int): Iterator[A]^{this} = {
109+
if (_hasNext) {
110+
if (remainder <= from) remainder = 0 // exhausted by big skip
111+
else if (from <= 0) { // no skip, pos is same
112+
if (until >= 0 && until < remainder) remainder = until // ...limited by until
113+
}
114+
else {
115+
pos -= from // skip ahead
116+
if (until >= 0 && until < remainder) { // ...limited by until
117+
if (until <= from) remainder = 0 // ...exhausted if limit is smaller than skip
118+
else remainder = until - from // ...limited by until, less the skip
119+
}
120+
else remainder -= from // ...otherwise just less the skip
121+
}
122+
}
123+
this
124+
}
125+
}
126+
127+
/** An `IndexedSeqViewOps` whose collection type and collection type constructor are unknown */
128+
type SomeIndexedSeqViewOps[A] = IndexedSeqViewOps[A, AnyConstr, _]
129+
130+
@SerialVersionUID(3L)
131+
class Id[+A](underlying: SomeIndexedSeqViewOps[A]^)
132+
extends SeqView.Id(underlying) with IndexedSeqView[A]
133+
134+
@SerialVersionUID(3L)
135+
class Appended[+A](underlying: SomeIndexedSeqViewOps[A]^, elem: A)
136+
extends SeqView.Appended(underlying, elem) with IndexedSeqView[A]
137+
138+
@SerialVersionUID(3L)
139+
class Prepended[+A](elem: A, underlying: SomeIndexedSeqViewOps[A]^)
140+
extends SeqView.Prepended(elem, underlying) with IndexedSeqView[A]
141+
142+
@SerialVersionUID(3L)
143+
class Concat[A](prefix: SomeIndexedSeqViewOps[A]^, suffix: SomeIndexedSeqViewOps[A]^)
144+
extends SeqView.Concat[A](prefix, suffix) with IndexedSeqView[A]
145+
146+
@SerialVersionUID(3L)
147+
class Take[A](underlying: SomeIndexedSeqViewOps[A]^, n: Int)
148+
extends SeqView.Take(underlying, n) with IndexedSeqView[A]
149+
150+
@SerialVersionUID(3L)
151+
class TakeRight[A](underlying: SomeIndexedSeqViewOps[A]^, n: Int)
152+
extends SeqView.TakeRight(underlying, n) with IndexedSeqView[A]
153+
154+
@SerialVersionUID(3L)
155+
class Drop[A](underlying: SomeIndexedSeqViewOps[A]^, n: Int)
156+
extends SeqView.Drop[A](underlying, n) with IndexedSeqView[A]
157+
158+
@SerialVersionUID(3L)
159+
class DropRight[A](underlying: SomeIndexedSeqViewOps[A]^, n: Int)
160+
extends SeqView.DropRight[A](underlying, n) with IndexedSeqView[A]
161+
162+
@SerialVersionUID(3L)
163+
class Map[A, B](underlying: SomeIndexedSeqViewOps[A]^, f: A => B)
164+
extends SeqView.Map(underlying, f) with IndexedSeqView[B]
165+
166+
@SerialVersionUID(3L)
167+
class Reverse[A](underlying: SomeIndexedSeqViewOps[A]^) extends SeqView.Reverse[A](underlying) with IndexedSeqView[A] {
168+
override def reverse: IndexedSeqView[A] = underlying match {
169+
case x: IndexedSeqView[A] => x
170+
case _ => super.reverse
171+
}
172+
}
173+
174+
@SerialVersionUID(3L)
175+
class Slice[A](underlying: SomeIndexedSeqViewOps[A]^, from: Int, until: Int) extends AbstractIndexedSeqView[A] {
176+
protected val lo = from max 0
177+
protected val hi = (until max 0) min underlying.length
178+
protected val len = (hi - lo) max 0
179+
@throws[IndexOutOfBoundsException]
180+
def apply(i: Int): A = underlying(lo + i)
181+
def length: Int = len
182+
}
183+
}
184+
185+
/** Explicit instantiation of the `IndexedSeqView` trait to reduce class file size in subclasses. */
186+
@SerialVersionUID(3L)
187+
abstract class AbstractIndexedSeqView[+A] extends AbstractSeqView[A] with IndexedSeqView[A]

0 commit comments

Comments
 (0)