-
Notifications
You must be signed in to change notification settings - Fork 1
/
IterArmy.hx
81 lines (68 loc) · 2.58 KB
/
IterArmy.hx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package finitudeiterable;
import FinitudeIterable;
using IterLoop;
using Lambda;
/**
* IterArmy: an Iterator of Iterators, alternating between each inner iterator.
*
* @example
using Lambda;
using IterArmy;
...
public function test_reading_from_2_arrays_simple() {
// we want to read from 2 arrays
// alternating values of squares and cubes:
var squares = [ for (i in 0...10) i*i ];
var cubes = [ for (i in 0...10) i*i*i ];
for (x in new IterArmy<Int>([
squares.iterator(),
cubes.iterator()
]))
trace(x); // we'll get 0,0,1,1,4,16,9,27 etc, alternating
// squares and cubes.
}
* @endexample
* You can also have several soldier iterators running along the _same_
* Iterable. For example see IterPart and IterMeet, they both
* use an IterArmy.
*/
class IterArmy<T> implements FinitudeIterable {
var army : Iterable<Iterator<T>>;
var captain : IterLoop<Iterator<T>>;
var nxtSoldier : Iterator<T>;
var nArmy : Int; ///< Army count
var isInfinite : Bool;
public function new(a:Iterable<Iterator<T>>) {
army = a;
captain = cast army.iterLoop(); // cyclic,infinite
nArmy = army.count();
// Since hasNext() must not change the state of
// the iterator, we must initialize it here
nxtSoldier = getNextSoldierHavingNext_orNull();
isInfinite = army.exists(function(it)
return Std.is(it, FinitudeIterable)
&& cast (it, FinitudeIterable).isInfiniteIter()
);
}
public function hasNext() return nxtSoldier != null;
public function next() {
var ret = nxtSoldier.next();
nxtSoldier = getNextSoldierHavingNext_orNull();
return ret;
}
public function isInfiniteIter() return isInfinite;
private function getNextSoldierHavingNext_orNull() {
var soldier = null;
// went full circle && none => we're done
var n = 0;
while (n++ <= nArmy - 1 && ((soldier = captain.next()) != null)) {
// It would have been nice to allow removal of finished soldiers,
// unfortunately it's not really possible 2016 Sun Feb 21 14:23:30 CST 2016
if (soldier.hasNext()) return soldier;
}
// if we arrive here, IterArmy has finished iterating
return null;
}
/** So IterArmy is an Iterable, and can be used w/ Lambda & cie. */
public function iterator():IterableIterator<T> return new IterArmy(army);
}