Skip to content

Commit 5e6e284

Browse files
authored
Merge pull request scala#7519 from MrRexZ/ticket/9954-indexedseq-optimizations
Implemented IndexedSeqView's Iterator and ReverseIterator `slice` operation
2 parents 4dfe532 + e7eca32 commit 5e6e284

File tree

2 files changed

+81
-4
lines changed

2 files changed

+81
-4
lines changed

src/library/scala/collection/IndexedSeqView.scala

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,34 +42,66 @@ object IndexedSeqView {
4242
@SerialVersionUID(3L)
4343
private final class IndexedSeqViewIterator[A](self: IndexedSeqView[A]) extends AbstractIterator[A] with Serializable {
4444
private[this] var current = 0
45+
private[this] var remainder = self.size
4546
override def knownSize: Int = self.size - current
46-
def hasNext = current < self.size
47+
def hasNext = remainder > 0
4748
def next(): A =
4849
if (hasNext) {
4950
val r = self.apply(current)
5051
current += 1
52+
remainder -= 1
5153
r
5254
} else Iterator.empty.next()
5355

5456
override def drop(n: Int): Iterator[A] = {
55-
if (n > 0) current = Math.min(self.size, current + n)
57+
if (n > 0) {
58+
current += n
59+
remainder = Math.max(0, remainder - n)
60+
}
61+
this
62+
}
63+
64+
override protected def sliceIterator(from: Int, until: Int): Iterator[A] = {
65+
66+
def formatRange(value : Int) : Int = if (value < 0) 0 else if (value > remainder) remainder else value
67+
68+
val formatFrom = formatRange(from)
69+
val formatUntil = formatRange(until)
70+
remainder = Math.max(0, formatUntil - formatFrom)
71+
current = current + formatFrom
5672
this
5773
}
5874
}
5975
@SerialVersionUID(3L)
6076
private final class IndexedSeqViewReverseIterator[A](self: IndexedSeqView[A]) extends AbstractIterator[A] with Serializable {
6177
private[this] var pos = self.size - 1
62-
def hasNext: Boolean = pos >= 0
78+
private[this] var remainder = self.size
79+
def hasNext: Boolean = remainder > 0
6380
def next(): A =
6481
if (pos < 0) throw new NoSuchElementException
6582
else {
6683
val r = self(pos)
6784
pos -= 1
85+
remainder -= 1
6886
r
6987
}
7088

7189
override def drop(n: Int): Iterator[A] = {
72-
if (n > 0) pos = Math.max( -1, pos - n)
90+
if (n > 0) {
91+
pos -= n
92+
remainder = Math.max(0, remainder - n)
93+
}
94+
this
95+
}
96+
97+
98+
override def sliceIterator(from: Int, until: Int): Iterator[A] = {
99+
val startCutoff = pos
100+
val untilCutoff = startCutoff - remainder + 1
101+
val nextStartCutoff = if (from < 0) startCutoff else if (startCutoff - from < 0) 0 else startCutoff - from
102+
val nextUntilCutoff = if (until < 0) startCutoff else if (startCutoff - until < untilCutoff) untilCutoff else startCutoff - until + 1
103+
remainder = Math.max(0, nextStartCutoff - nextUntilCutoff + 1)
104+
pos = nextStartCutoff
73105
this
74106
}
75107
}

test/junit/scala/collection/immutable/IndexedSeqTest.scala

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ package scala.collection.immutable
33
import org.junit._
44
import Assert._
55

6+
import scala.collection.Seq.empty
7+
import scala.language.postfixOps
8+
import scala.tools.testing.AssertUtil._
69
import scala.util.AllocationTest
710

811
class IndexedSeqTest extends AllocationTest {
@@ -93,6 +96,48 @@ class IndexedSeqTest extends AllocationTest {
9396
assertNotEquals(Range(0,1), new MyRange(0, 1))
9497
assertEquals(new MyRange(0, 1), new MyRange(0, 1))
9598
}
99+
100+
@Test def testforwardSliceEquals(): Unit = {
101+
102+
def generateTestIter = (0 to 10).view iterator
103+
104+
105+
assertSameElements(empty toList, generateTestIter slice (3, -1))
106+
assertSameElements(empty toList, generateTestIter slice (0, 0))
107+
assertSameElements(empty, generateTestIter slice (3, 3))
108+
assertSameElements(List(0) , generateTestIter slice (0, 1))
109+
assertSameElements(0 to 1 , generateTestIter slice (0, 2))
110+
assertSameElements(3 to 6 toList, generateTestIter slice(3,7))
111+
assertSameElements(0 to 2 toList, generateTestIter slice (-1, 3))
112+
assertSameElements(0 to 10 toList, generateTestIter slice (0, 11))
113+
assertSameElements(6 to 12 by 2 toList, generateTestIter slice (3, 7) map (2 * _))
114+
assertSameElements(6 to 12 by 2 toList, generateTestIter map (2 * _) slice (3, 7))
115+
assertSameElements(4 to 6 toList, generateTestIter slice (3, 7) drop 1)
116+
assertSameElements(4 to 7 toList, generateTestIter drop 1 slice (3, 7))
117+
assertSameElements(4 to 5 toList, generateTestIter slice (3, 7) slice (1, 3))
118+
assertSameElements(4 to 6 toList, generateTestIter slice (3, 7) slice (1, 10))
119+
}
120+
121+
@Test def testbackwardSliceEquals(): Unit = {
122+
123+
def generateTestIter = (0 to 10).view reverseIterator
124+
125+
assertSameElements(empty toList, generateTestIter slice (3, -1))
126+
assertSameElements(empty toList, generateTestIter slice (3, 2))
127+
assertSameElements(empty, generateTestIter slice (0, 0))
128+
assertSameElements(empty, generateTestIter slice (3, 3))
129+
assertSameElements(List(10) , generateTestIter slice (0, 1))
130+
assertSameElements(10 to 9 by -1 , generateTestIter slice (0, 2))
131+
assertSameElements(7 to 4 by -1 toList, generateTestIter slice(3,7))
132+
assertSameElements(10 to 8 by -1 toList, generateTestIter slice (-1, 3))
133+
assertSameElements(14 to 8 by -2 toList, generateTestIter slice (3, 7) map (2 * _))
134+
assertSameElements(14 to 8 by -2 toList, generateTestIter map (2 * _) slice (3, 7))
135+
assertSameElements(6 to 4 by -1 toList, generateTestIter slice (3, 7) drop 1)
136+
assertSameElements(6 to 3 by -1 toList, generateTestIter drop 1 slice (3, 7))
137+
assertSameElements(6 to 5 by -1 toList, generateTestIter slice (3, 7) slice (1, 3))
138+
assertSameElements(6 to 4 by -1 toList, generateTestIter slice (3, 7) slice (1, 10))
139+
}
140+
96141
}
97142
final class MyRange(val start: Int, val end: Int) extends IndexedSeq[Int] {
98143
def apply(idx: Int) = start + idx

0 commit comments

Comments
 (0)