summaryrefslogtreecommitdiff
path: root/src/library/scala/collection/Iterator.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/library/scala/collection/Iterator.scala')
-rw-r--r--src/library/scala/collection/Iterator.scala77
1 files changed, 47 insertions, 30 deletions
diff --git a/src/library/scala/collection/Iterator.scala b/src/library/scala/collection/Iterator.scala
index 2bb5bd1df9..72a23a0dd0 100644
--- a/src/library/scala/collection/Iterator.scala
+++ b/src/library/scala/collection/Iterator.scala
@@ -161,6 +161,41 @@ object Iterator {
def hasNext = true
def next = elem
}
+
+ /** Avoid stack overflows when applying ++ to lots of iterators by
+ * flattening the unevaluated iterators out into a vector of closures.
+ */
+ private[scala] final class ConcatIterator[+A](initial: Vector[() => Iterator[A]]) extends Iterator[A] {
+ // current set to null when all iterators are exhausted
+ private[this] var current: Iterator[A] = Iterator.empty
+ private[this] var queue: Vector[() => Iterator[A]] = initial
+ // Advance current to the next non-empty iterator
+ private[this] def advance(): Boolean = {
+ if (queue.isEmpty) {
+ current = null
+ false
+ }
+ else {
+ current = queue.head()
+ queue = queue.tail
+ current.hasNext || advance()
+ }
+ }
+ def hasNext = (current ne null) && (current.hasNext || advance())
+ def next() = if (hasNext) current.next else Iterator.empty.next
+
+ override def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] =
+ new ConcatIterator(queue :+ (() => that.toIterator))
+ }
+
+ private[scala] final class JoinIterator[+A](lhs: Iterator[A], that: => GenTraversableOnce[A]) extends Iterator[A] {
+ 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
+
+ override def ++[B >: A](that: => GenTraversableOnce[B]) =
+ new ConcatIterator(Vector(() => this, () => that.toIterator))
+ }
}
import Iterator.empty
@@ -338,24 +373,7 @@ trait Iterator[+A] extends TraversableOnce[A] {
* @usecase def ++(that: => Iterator[A]): Iterator[A]
* @inheritdoc
*/
- def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = new AbstractIterator[B] {
- // optimize a little bit to prevent n log n behavior.
- private var cur : Iterator[B] = self
- private var selfExhausted : Boolean = false
- // since that is by-name, make sure it's only referenced once -
- // if "val it = that" is inside the block, then hasNext on an empty
- // iterator will continually reevaluate it. (ticket #3269)
- lazy val it = that.toIterator
- // the eq check is to avoid an infinite loop on "x ++ x"
- def hasNext = cur.hasNext || (!selfExhausted && {
- it.hasNext && {
- cur = it
- selfExhausted = true
- true
- }
- })
- def next() = { hasNext; cur.next() }
- }
+ def ++[B >: A](that: => GenTraversableOnce[B]): Iterator[B] = new Iterator.JoinIterator(self, that)
/** Creates a new iterator by applying a function to all values produced by this iterator
* and concatenating the results.
@@ -368,7 +386,7 @@ trait Iterator[+A] extends TraversableOnce[A] {
def flatMap[B](f: A => GenTraversableOnce[B]): Iterator[B] = new AbstractIterator[B] {
private var cur: Iterator[B] = empty
def hasNext: Boolean =
- cur.hasNext || self.hasNext && { cur = f(self.next).toIterator; hasNext }
+ cur.hasNext || self.hasNext && { cur = f(self.next()).toIterator; hasNext }
def next(): B = (if (hasNext) cur else empty).next()
}
@@ -408,7 +426,7 @@ trait Iterator[+A] extends TraversableOnce[A] {
def corresponds[B](that: GenTraversableOnce[B])(p: (A, B) => Boolean): Boolean = {
val that0 = that.toIterator
while (hasNext && that0.hasNext)
- if (!p(next, that0.next)) return false
+ if (!p(next(), that0.next())) return false
hasNext == that0.hasNext
}
@@ -555,14 +573,13 @@ trait Iterator[+A] extends TraversableOnce[A] {
def span(p: A => Boolean): (Iterator[A], Iterator[A]) = {
val self = buffered
- /**
+ /*
* Giving a name to following iterator (as opposed to trailing) because
* anonymous class is represented as a structural type that trailing
* iterator is referring (the finish() method) and thus triggering
* handling of structural calls. It's not what's intended here.
*/
class Leading extends AbstractIterator[A] {
- private var isDone = false
val lookahead = new mutable.Queue[A]
def advance() = {
self.hasNext && p(self.head) && {
@@ -572,7 +589,6 @@ trait Iterator[+A] extends TraversableOnce[A] {
}
def finish() = {
while (advance()) ()
- isDone = true
}
def hasNext = lookahead.nonEmpty || advance()
def next() = {
@@ -632,7 +648,7 @@ trait Iterator[+A] extends TraversableOnce[A] {
*/
def zip[B](that: Iterator[B]): Iterator[(A, B)] = new AbstractIterator[(A, B)] {
def hasNext = self.hasNext && that.hasNext
- def next = (self.next, that.next)
+ def next = (self.next(), that.next())
}
/** Appends an element value to this iterator until a given target length is reached.
@@ -652,9 +668,9 @@ trait Iterator[+A] extends TraversableOnce[A] {
def hasNext = self.hasNext || count < len
def next = {
count += 1
- if (self.hasNext) self.next
+ if (self.hasNext) self.next()
else if (count <= len) elem
- else empty.next
+ else empty.next()
}
}
@@ -669,7 +685,7 @@ trait Iterator[+A] extends TraversableOnce[A] {
var idx = 0
def hasNext = self.hasNext
def next = {
- val ret = (self.next, idx)
+ val ret = (self.next(), idx)
idx += 1
ret
}
@@ -1054,12 +1070,12 @@ trait Iterator[+A] extends TraversableOnce[A] {
val e = self.next()
gap enqueue e
e
- } else gap.dequeue
+ } else gap.dequeue()
}
// to verify partnerhood we use reference equality on gap because
// type testing does not discriminate based on origin.
private def compareGap(queue: scala.collection.mutable.Queue[A]) = gap eq queue
- override def hashCode = gap.hashCode
+ override def hashCode = gap.hashCode()
override def equals(other: Any) = other match {
case x: Partner => x.compareGap(gap) && gap.isEmpty
case _ => super.equals(other)
@@ -1118,6 +1134,7 @@ trait Iterator[+A] extends TraversableOnce[A] {
xs(i) = next()
i += 1
}
+ // TODO: return i - start so the caller knows how many values read?
}
/** Tests if another iterator produces the same values as this one.
@@ -1140,7 +1157,7 @@ trait Iterator[+A] extends TraversableOnce[A] {
def toTraversable: Traversable[A] = toStream
def toIterator: Iterator[A] = self
def toStream: Stream[A] =
- if (self.hasNext) Stream.cons(self.next, self.toStream)
+ if (self.hasNext) Stream.cons(self.next(), self.toStream)
else Stream.empty[A]