Skip to content

Commit 7baf7c8

Browse files
committed
Merge pull request scala#5033 from szeiger/issue/9623-2.12
Replace JoinIterator & improve ConcatIterator
2 parents ad35e02 + f701990 commit 7baf7c8

File tree

1 file changed

+46
-44
lines changed

1 file changed

+46
-44
lines changed

src/library/scala/collection/Iterator.scala

Lines changed: 46 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ package collection
1111

1212
import mutable.ArrayBuffer
1313
import scala.annotation.{tailrec, migration}
14+
import scala.annotation.unchecked.{uncheckedVariance => uV}
1415
import immutable.Stream
1516

1617
/** The `Iterator` object provides various functions for creating specialized iterators.
@@ -160,78 +161,79 @@ object Iterator {
160161
def next = elem
161162
}
162163

163-
/** Avoid stack overflows when applying ++ to lots of iterators by
164-
* flattening the unevaluated iterators out into a vector of closures.
164+
/** Creates an iterator to which other iterators can be appended efficiently.
165+
* Nested ConcatIterators are merged to avoid blowing the stack.
165166
*/
166-
private[scala] final class ConcatIterator[+A](private[this] var current: Iterator[A], initial: Vector[() => Iterator[A]]) extends Iterator[A] {
167-
@deprecated def this(initial: Vector[() => Iterator[A]]) = this(Iterator.empty, initial) // for binary compatibility
168-
private[this] var queue: Vector[() => Iterator[A]] = initial
169-
private[this] var currentHasNextChecked = false
167+
private final class ConcatIterator[+A](private var current: Iterator[A @uV]) extends Iterator[A] {
168+
private var tail: ConcatIteratorCell[A @uV] = null
169+
private var last: ConcatIteratorCell[A @uV] = null
170+
private var currentHasNextChecked = false
171+
170172
// Advance current to the next non-empty iterator
171173
// current is set to null when all iterators are exhausted
172174
@tailrec
173175
private[this] def advance(): Boolean = {
174-
if (queue.isEmpty) {
176+
if (tail eq null) {
175177
current = null
178+
last = null
176179
false
177180
}
178181
else {
179-
current = queue.head()
180-
queue = queue.tail
181-
if (current.hasNext) {
182+
current = tail.headIterator
183+
tail = tail.tail
184+
merge()
185+
if (currentHasNextChecked) true
186+
else if (current.hasNext) {
182187
currentHasNextChecked = true
183188
true
184189
} else advance()
185190
}
186191
}
192+
193+
// If the current iterator is a ConcatIterator, merge it into this one
194+
@tailrec
195+
private[this] def merge(): Unit =
196+
if (current.isInstanceOf[ConcatIterator[_]]) {
197+
val c = current.asInstanceOf[ConcatIterator[A]]
198+
current = c.current
199+
currentHasNextChecked = c.currentHasNextChecked
200+
if (c.tail ne null) {
201+
c.last.tail = tail
202+
tail = c.tail
203+
}
204+
merge()
205+
}
206+
187207
def hasNext =
188208
if (currentHasNextChecked) true
189209
else if (current eq null) false
190210
else if (current.hasNext) {
191211
currentHasNextChecked = true
192212
true
193213
} else advance()
214+
194215
def next() =
195216
if (hasNext) {
196217
currentHasNextChecked = false
197218
current.next()
198219
} else Iterator.empty.next()
199220

200-
override def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] =
201-
new ConcatIterator(current, queue :+ (() => that.toIterator))
202-
}
203-
204-
private[scala] final class JoinIterator[+A](lhs: Iterator[A], that: => GenTraversableOnce[A]) extends Iterator[A] {
205-
private[this] var state = 0 // 0: lhs not checked, 1: lhs has next, 2: switched to rhs
206-
private[this] lazy val rhs: Iterator[A] = that.toIterator
207-
def hasNext = state match {
208-
case 0 =>
209-
if (lhs.hasNext) {
210-
state = 1
211-
true
212-
} else {
213-
state = 2
214-
rhs.hasNext
215-
}
216-
case 1 => true
217-
case _ => rhs.hasNext
218-
}
219-
def next() = state match {
220-
case 0 =>
221-
if (lhs.hasNext) lhs.next()
222-
else {
223-
state = 2
224-
rhs.next()
225-
}
226-
case 1 =>
227-
state = 0
228-
lhs.next()
229-
case _ =>
230-
rhs.next()
221+
override def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = {
222+
val c = new ConcatIteratorCell[B](that, null).asInstanceOf[ConcatIteratorCell[A]]
223+
if(tail eq null) {
224+
tail = c
225+
last = c
226+
} else {
227+
last.tail = c
228+
last = c
229+
}
230+
if(current eq null) current = Iterator.empty
231+
this
231232
}
233+
}
232234

233-
override def ++[B >: A](that: => GenTraversableOnce[B]) =
234-
new ConcatIterator(this, Vector(() => that.toIterator))
235+
private[this] final class ConcatIteratorCell[A](head: => GenTraversableOnce[A], var tail: ConcatIteratorCell[A]) {
236+
def headIterator: Iterator[A] = head.toIterator
235237
}
236238

237239
/** Creates a delegating iterator capped by a limit count. Negative limit means unbounded.
@@ -456,7 +458,7 @@ trait Iterator[+A] extends TraversableOnce[A] {
456458
* @usecase def ++(that: => Iterator[A]): Iterator[A]
457459
* @inheritdoc
458460
*/
459-
def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = new Iterator.JoinIterator(self, that)
461+
def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = new Iterator.ConcatIterator(self) ++ that
460462

461463
/** Creates a new iterator by applying a function to all values produced by this iterator
462464
* and concatenating the results.

0 commit comments

Comments
 (0)