summaryrefslogtreecommitdiff
path: root/src/library/scala/collection/Iterator.scala
diff options
context:
space:
mode:
authorStefan Zeiger <szeiger@novocode.com>2016-01-29 17:28:16 +0100
committerStefan Zeiger <szeiger@novocode.com>2016-02-01 14:41:17 +0100
commitecee7b75328ae1f856b5fa832ebad7fc9e42f64a (patch)
treed49c0a1e1d2f1b546d374e8888b431f0e069bf86 /src/library/scala/collection/Iterator.scala
parentea154faf467ae27c221ba0dcd7235e1e55673c51 (diff)
downloadscala-ecee7b75328ae1f856b5fa832ebad7fc9e42f64a.tar.gz
scala-ecee7b75328ae1f856b5fa832ebad7fc9e42f64a.tar.bz2
scala-ecee7b75328ae1f856b5fa832ebad7fc9e42f64a.zip
SI-9623 Avoid unnecessary hasNext calls in JoinIterator & ConcatIterator
These iterator implementations are used to concatenate two (JoinIterator) or more (ConcatIterator) other iterators with `++`. They used to perform many unnecessary calls to the child iterators’ `hasNext` methods. This improved state machine-based implementation reduces that number to the bare minimum, i.e. iterating over concatenated iterators with `foreach` calls the children's `hasNext` methods a total of (number of children) + (number of elements) times, the same as when iterating over all children separately.
Diffstat (limited to 'src/library/scala/collection/Iterator.scala')
-rw-r--r--src/library/scala/collection/Iterator.scala51
1 files changed, 45 insertions, 6 deletions
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index ed536f10a8..8d88b1c6b1 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -10,7 +10,7 @@ package scala
package collection
import mutable.ArrayBuffer
-import scala.annotation.migration
+import scala.annotation.{tailrec, migration}
import immutable.Stream
import scala.collection.generic.CanBuildFrom
import scala.annotation.unchecked.{ uncheckedVariance => uV }
@@ -168,8 +168,10 @@ object Iterator {
private[scala] final class ConcatIterator[+A](private[this] var current: Iterator[A], initial: Vector[() => Iterator[A]]) extends Iterator[A] {
@deprecated def this(initial: Vector[() => Iterator[A]]) = this(Iterator.empty, initial) // for binary compatibility
private[this] var queue: Vector[() => Iterator[A]] = initial
+ private[this] var currentHasNextChecked = false
// Advance current to the next non-empty iterator
// current is set to null when all iterators are exhausted
+ @tailrec
private[this] def advance(): Boolean = {
if (queue.isEmpty) {
current = null
@@ -178,20 +180,57 @@ object Iterator {
else {
current = queue.head()
queue = queue.tail
- current.hasNext || advance()
+ if (current.hasNext) {
+ currentHasNextChecked = true
+ true
+ } else advance()
}
}
- def hasNext = (current ne null) && (current.hasNext || advance())
- def next() = if (hasNext) current.next else Iterator.empty.next
+ def hasNext =
+ if (currentHasNextChecked) true
+ else if (current eq null) false
+ else if (current.hasNext) {
+ currentHasNextChecked = true
+ true
+ } else advance()
+ def next() =
+ if (hasNext) {
+ currentHasNextChecked = false
+ current.next()
+ } else Iterator.empty.next()
override def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] =
new ConcatIterator(current, queue :+ (() => that.toIterator))
}
private[scala] final class JoinIterator[+A](lhs: Iterator[A], that: => GenTraversableOnce[A]) extends Iterator[A] {
+ private[this] var state = 0 // 0: lhs not checked, 1: lhs has next, 2: switched to rhs
private[this] lazy val rhs: Iterator[A] = that.toIterator
- def hasNext = lhs.hasNext || rhs.hasNext
- def next = if (lhs.hasNext) lhs.next else rhs.next
+ def hasNext = state match {
+ case 0 =>
+ if (lhs.hasNext) {
+ state = 1
+ true
+ } else {
+ state = 2
+ rhs.hasNext
+ }
+ case 1 => true
+ case _ => rhs.hasNext
+ }
+ def next() = state match {
+ case 0 =>
+ if (lhs.hasNext) lhs.next()
+ else {
+ state = 2
+ rhs.next()
+ }
+ case 1 =>
+ state = 0
+ lhs.next()
+ case _ =>
+ rhs.next()
+ }
override def ++[B >: A](that: => GenTraversableOnce[B]) =
new ConcatIterator(this, Vector(() => that.toIterator))