Skip to content
This repository was archived by the owner on Sep 1, 2020. It is now read-only.

Commit 3ae3e9f

Browse files
committed
Merge pull request scala#4530 from som-snytt/issue/9332
SI-9332 Iterator.span exhausts leading iterator
2 parents b0a511f + 5ebb7bb commit 3ae3e9f

File tree

2 files changed

+22
-20
lines changed

2 files changed

+22
-20
lines changed

src/library/scala/collection/Iterator.scala

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -580,29 +580,21 @@ trait Iterator[+A] extends TraversableOnce[A] {
580580
def span(p: A => Boolean): (Iterator[A], Iterator[A]) = {
581581
val self = buffered
582582

583-
/*
584-
* Giving a name to following iterator (as opposed to trailing) because
585-
* anonymous class is represented as a structural type that trailing
586-
* iterator is referring (the finish() method) and thus triggering
587-
* handling of structural calls. It's not what's intended here.
588-
*/
583+
// Must be a named class to avoid structural call to finish from trailing iterator
589584
class Leading extends AbstractIterator[A] {
590-
val lookahead = new mutable.Queue[A]
591-
def advance() = {
592-
self.hasNext && p(self.head) && {
593-
lookahead += self.next
594-
true
595-
}
585+
private val drained = new mutable.Queue[A]
586+
private var finished = false
587+
def finish(): Unit = {
588+
require(!finished)
589+
finished = true
590+
while (selfish) drained += self.next
596591
}
597-
def finish() = {
598-
while (advance()) ()
599-
}
600-
def hasNext = lookahead.nonEmpty || advance()
592+
private def selfish = self.hasNext && p(self.head)
593+
def hasNext = if (finished) drained.nonEmpty else selfish
601594
def next() = {
602-
if (lookahead.isEmpty)
603-
advance()
604-
605-
lookahead.dequeue()
595+
if (finished) drained.dequeue()
596+
else if (selfish) self.next()
597+
else empty.next()
606598
}
607599
}
608600
val leading = new Leading

test/junit/scala/collection/IteratorTest.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,14 @@ class IteratorTest {
154154
results += (Stream from 1).toIterator.drop(10).toStream.drop(10).toIterator.next()
155155
assertSameElements(List(1,1,21), results)
156156
}
157+
// SI-9332
158+
@Test def spanExhaustsLeadingIterator(): Unit = {
159+
def it = Iterator.iterate(0)(_ + 1).take(6)
160+
val (x, y) = it.span(_ != 1)
161+
val z = x.toList
162+
assertEquals(1, z.size)
163+
assertFalse(x.hasNext)
164+
assertEquals(1, y.next)
165+
assertFalse(x.hasNext) // was true, after advancing underlying iterator
166+
}
157167
}

0 commit comments

Comments
 (0)