# Pipelined filters and operations on iterators.
#
-# This module enhance `Iterator`s with some methods that enable a
-# pipeline-like programing that offers the manupulation of
-# collections trough connected filters with reasonable memory constraints.
+# This module enhances `Iterator` with some methods that enable a pipeline-like programing.
+# The processing of elements in a pipeline is done trough connected filters that are implemented with reasonable memory constraints.
module pipeline
redef interface Iterator[E]
# Filter: sort with a given `comparator`.
# Important: require O(n) memory.
- fun sort_with(comparator: Comparator[E]): Iterator[E]
+ #
+ # assert ["a", "c", "b"].iterator.sort_with(alpha_comparator).to_a == ["a", "b", "c"]
+ fun sort_with(comparator: Comparator): Iterator[E]
do
var a = self.to_a
comparator.sort(a)
# 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)
# Alternate each item with `e`.
#
- # assert [1,2,3].iterator.alternate(0).to_a == [1,0,2,0,3]
+ # assert [1,2,3].iterator.alternate(0).to_a == [1,0,2,0,3]
fun alternate(e: E): Iterator[E]
do
return new PipeAlternate[E](self, e)
# Filter: reject a given `item`.
#
- # assert [1,1,2,1,3].iterator.skip(1).to_a == [2,3]
+ # assert [1,1,2,1,3].iterator.skip(1).to_a == [2,3]
fun skip(item: E): Iterator[E]
do
return new PipeSkip[E](self, item)
#
# var i = [1,2,3,4,5].iterator
# assert i.head(2).to_a == [1,2]
- # i.to_a == [3,4,5]
+ # assert i.to_a == [3,4,5]
fun head(length: Int): Iterator[E]
do
return new PipeHead[E](self, length)
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
+# var i: Iterator[Int]
+#
+# i = new NullSkipper[Int]([null, 1, null, 2, null: nullable Int].iterator)
+# assert i.to_a == [1, 2]
+#
+# i = new NullSkipper[Int]([1, null, 2, 3: nullable Int].iterator)
+# assert i.to_a == [1, 2, 3]
+# ~~~
+class NullSkipper[E: Object]
+ super Iterator[E]
+
+ # The inner iterator.
+ var inner: Iterator[nullable E]
+
+ redef fun finish do inner.finish
+
+ redef fun is_ok do
+ skip_nulls
+ return inner.is_ok
+ end
+
+ redef fun item do
+ skip_nulls
+ return inner.item.as(E)
+ end
+
+ redef fun next do
+ inner.next
+ skip_nulls
+ end
+
+ private fun skip_nulls do
+ while inner.is_ok and inner.item == null do inner.next
+ end
+end
+
# Interface that reify a function.
# Concrete subclasses must implements the `apply` method.
#
var source: Iterator[E]
var skip_item: E
- init(source: Iterator[E], skip_item: E)
- do
- self.source = source
- self.skip_item = skip_item
-
- do_skip
- end
+ init do do_skip
fun do_skip
do
var lasts = new List[E]
- init(source: Iterator[E], length: Int)
+ init
do
- self.source = source
- self.length = length
var lasts = self.lasts
while source.is_ok and lasts.length < length do
lasts.push(source.item)
var predicate: Function[E, Bool]
- init(source: Iterator[E], predicate: Function[E, Bool])
- do
- self.source = source
- self.predicate = predicate
-
- do_skip
- end
+ init do do_skip
fun do_skip
do