1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Pipelined filters and operations on iterators.
17 # This module enhance `Iterator`s with some methods that enable a
18 # pipeline-like programing that offers the manupulation of
19 # collections trough connected filters with reasonable memory constraints.
22 redef interface Iterator[E
]
23 # Filter: sort with ComparableSorter.
24 # SEE: `sort_with` for details
25 # REQUIRE: self isa Iterator[Comparable]
27 # [1,3,2].iterator.sort.to_a #=> [1,2,3]
30 assert self isa Iterator[Comparable]
31 var sorter
= new ComparableSorter[Comparable]
37 # Filter: sort with a given `sorter`.
38 # Important: require O(n) memory.
40 # REQUIRE: self isa Iterator[Object]
41 # FIXME: AbstractSorter[E] is refused
42 fun sort_with
(sorter
: AbstractSorter[Object]): Iterator[E
]
44 assert self isa Iterator[Object]
50 # Filter: reject duplicates.
51 # Elements already seen are rejected.
53 # Important: rely on `==` and `hash`
54 # Important: require O(m) in memory, where m is the total number of uniq items.
56 # [1,2,1,1,1,3,2].iterator.uniq.to_a #=> [1,2,3]
58 # REQUIRE: self isa Iterator[Object]
61 assert self isa Iterator[Object]
62 return new PipeUniq[E
](self)
65 # Filter: reject continuous sequences of duplicates
67 # Important: rely on `==`.
69 # [1,2,1,1,1,3,2].iterator.uniq.to_a #=> [1,2,1,3,2]
70 fun seq_uniq
: Iterator[E
]
72 return new PipeSeqUniq[E
](self)
75 # Combine two iterators.
77 # When the first iterator is terminated, the second is started.
79 # ([1,2].iterator + [3,4].iterator).to_a #=> [1,2,3,4]
80 fun +(other
: Iterator[E
]): Iterator[E
]
82 return new PipeJoin[E
](self, other
)
85 # Alternate each item with `e`.
87 # [1,2,3].iterator.alternate(0).to_a #=> [1,0,2,0,3]
88 fun alternate
(e
: E
): Iterator[E
]
90 return new PipeAlternate[E
](self, e
)
93 # Filter: reject a given `item`.
95 # [1,1,2,1,3].iterator.skip(1).to_a #=> [2,3]
96 fun skip
(item
: E
): Iterator[E
]
98 return new PipeSkip[E
](self, item
)
101 # Filter: keep only the first `length` items.
103 # This filter does not always consume `self'.
105 # var i = [1,2,3,4,5].iterator
106 # i.head(2).to_a #=> [1,2]
108 fun head
(length
: Int): Iterator[E
]
110 return new PipeHead[E
](self, length
)
113 # Filter: reject the first `length` items.
115 # [1,2,3,4,5].iterator.skip_head(2).to_a #=> [3,4,5]
117 # ENSURE: self == return
118 fun skip_head
(length
: Int): Iterator[E
]
120 while length
> 0 and self.is_ok
do
127 # Filter: keep only the last `length` items.
129 # [1,2,3,4,5].iterator.tail(2).to_a #=> [4,5]
131 # Important: require O(length) in memory
132 fun tail
(length
: Int): Iterator[E
]
134 var lasts
= new List[E
]
136 while lasts
.length
>= length
do lasts
.shift
137 lasts
.push
(self.item
)
140 return lasts
.iterator
143 # Filter: reject the last `length` items.
145 # [1,2,3,4,5].iterator.skip_tail(2).to_a #=> [1,2,3]
147 # Important: require O(length) in memory
148 fun skip_tail
(length
: Int): Iterator[E
]
150 return new PipeSkipTail[E
](self, length
)
154 ### Specific private iterator classes
156 private class PipeUniq[E
]
159 var source
: Iterator[E
]
161 var seen
= new HashSet[Object] # FIXME HashSet[E]
163 redef fun is_ok
do return source
.is_ok
165 redef fun item
do return source
.item
169 self.seen
.add
(self.item
.as(Object))
171 while source
.is_ok
and self.seen
.has
(source
.item
.as(Object)) do
177 private class PipeSeqUniq[E
]
180 var source
: Iterator[E
]
182 redef fun is_ok
do return source
.is_ok
184 redef fun item
do return source
.item
190 while source
.is_ok
and seen
== source
.item
do
196 private class PipeJoin[E
]
198 var source1
: Iterator[E
]
199 var source2
: Iterator[E
]
203 return source1
.is_ok
or source2
.is_ok
208 if source1
.is_ok
then return source1
.item
else return source2
.item
213 if source1
.is_ok
then source1
.next
else source2
.next
217 private class PipeAlternate[E
]
220 var source
: Iterator[E
]
224 redef fun is_ok
do return source
.is_ok
244 private class PipeSkip[E
]
247 var source
: Iterator[E
]
250 init(source
: Iterator[E
], skip_item
: E
)
253 self.skip_item
= skip_item
260 while source
.is_ok
and source
.item
== skip_item
do source
.next
263 redef fun is_ok
do return source
.is_ok
265 redef fun item
do return source
.item
274 private class PipeHead[E
]
277 var source
: Iterator[E
]
281 redef fun is_ok
do return length
> 0 and source
.is_ok
283 redef fun item
do return source
.item
292 private class PipeSkipTail[E
]
295 var source
: Iterator[E
]
299 var lasts
= new List[E
]
301 init(source
: Iterator[E
], length
: Int)
305 var lasts
= self.lasts
306 while source
.is_ok
and lasts
.length
< length
do
307 lasts
.push
(source
.item
)
312 redef fun is_ok
do return source
.is_ok
314 redef fun item
do return lasts
.first
319 lasts
.push
(source
.item
)