From: Jean-Christophe Beaupré Date: Thu, 25 Aug 2016 20:59:34 +0000 (-0400) Subject: pipeline: Introduce `Iterator2` X-Git-Url: http://nitlanguage.org?hp=7e3a73ceb584bbac76b73da33ac6120b89629a9b pipeline: Introduce `Iterator2` Add a generalization of `PipeJoin`. Signed-off-by: Jean-Christophe Beaupré --- diff --git a/lib/pipeline.nit b/lib/pipeline.nit index d3428f0..54be22b 100644 --- a/lib/pipeline.nit +++ b/lib/pipeline.nit @@ -73,6 +73,8 @@ redef interface Iterator[E] # When the first iterator is terminated, the second is started. # # assert ([1..20[.iterator + [20..40[.iterator).to_a == ([1..40[).to_a + # + # SEE: `Iterator2` fun +(other: Iterator[E]): Iterator[E] do return new PipeJoin[E](self, other) @@ -159,6 +161,95 @@ redef interface Iterator[E] end end +# Concatenates a sequence of iterators. +# +# Wraps an iterator of sub-iterators and iterates over the elements of the +# sub-iterators. +# +# ~~~nit +# var i: Iterator[Int] +# var empty = new Array[Int] +# +# i = new Iterator2[Int]([ +# [1, 2, 3].iterator, +# empty.iterator, +# [4, 5].iterator +# ].iterator) +# assert i.to_a == [1, 2, 3, 4, 5] +# +# i = new Iterator2[Int]([ +# empty.iterator, +# [42].iterator, +# empty.iterator +# ].iterator) +# assert i.to_a == [42] +# ~~~ +# +# SEE: `Iterator::+` +class Iterator2[E] + super Iterator[E] + + # The inner iterator over sub-iterators. + var inner: Iterator[Iterator[E]] + + redef fun finish + do + var i = current_iterator + if i != null then i.finish + end + + redef fun is_ok + do + var i = current_iterator + if i == null then return false + return i.is_ok + end + + redef fun item + do + var i = current_iterator + assert i != null + return i.item + end + + redef fun next + do + var i = current_iterator + assert i != null + i.next + end + + redef fun start + do + var i = current_iterator + if i != null then i.start + end + + private var previous_iterator: nullable Iterator[E] = null + + private fun current_iterator: nullable Iterator[E] + do + if previous_iterator == null then + # Get the first sub-iterator. + if inner.is_ok then + previous_iterator = inner.item + previous_iterator.start + inner.next + else + return null + end + end + # Get the first sub-iterator that has a current item. + while inner.is_ok and not previous_iterator.is_ok do + previous_iterator.finish + previous_iterator = inner.item + previous_iterator.start + inner.next + end + return previous_iterator + end +end + # Wraps an iterator to skip nulls. # # ~~~nit