Merge: Nitsmell : Adding new code smells and print console updated
[nit.git] / lib / pipeline.nit
index 055823f..54be22b 100644 (file)
@@ -14,9 +14,8 @@
 
 # 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]
@@ -35,7 +34,9 @@ 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)
@@ -72,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)
@@ -79,7 +82,7 @@ redef interface Iterator[E]
 
        # 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)
@@ -87,7 +90,7 @@ redef interface Iterator[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)
@@ -99,7 +102,7 @@ redef interface Iterator[E]
        #
        #     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)
@@ -158,6 +161,134 @@ 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
+# 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.
 #
@@ -294,13 +425,7 @@ private class PipeSkip[E]
        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
@@ -345,10 +470,8 @@ private class PipeSkipTail[E]
 
        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)
@@ -375,13 +498,7 @@ private class PipeSelect[E]
 
        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