-
Notifications
You must be signed in to change notification settings - Fork 1
/
IterChain2.hx
149 lines (136 loc) · 4.63 KB
/
IterChain2.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package finitudeiterable;
import FinitudeIterable;
using Lambda;
/**
* Sequential iteration. Subiterators are chained sequentially.
* Once first subiterator is finished, the second subiterator is iterated,
* and so on until all subiterators have been iterated.
*
* @example
* ```haxe
* for (i in new IterChain([
* new IterRange(0, 3),
* new IterRange(-10, -13),
* new IterRange(3, 6)
* ])
* trace(i);
*
* // Will show 0, 1, 2, -10, -11, -12, 3, 4, 5.
*
* // This will yield the same output:
*
* import IterRange.range as range;
*
* [ range(0, 3 ),
* range(-10, -13),
* range(3, 6 ),
* ].iter(trace);
*
* @endexample
*
* You can also use the andThen() notation, with `using IterChain`:
*
* @example
* ```haxe
* using IterChain;
* using IterLoop;
* import IterRange.range as range;
*
* range(3,0).andThen([0].loop());
*
* // /!\ If you iterate through the above line, it will create an infinite
* // iterator generating 3, 2, 1, 0, 0, 0, 0, ...
* // The following example will show how this dangerous-looking perspective
* // can be used.
* @endexample
*
* This style can be used along with IterDual. For example let's say we have
* an IterLine which takes 2 points and iterate through the points joining
* them. Using the previous example, we could then associate a radiation measure
* expressed as an Int depending on the distance from the first one:
*
* ```haxe
* using IterChain;
* using IterLoop;
* using IterDual;
* import IterRange.range as range;
* import IterLine;
*
* for (i in dual(
* new IterLine({x: -19, y: 24}, {x:100, y: 100}),
* range(50, 0).andThen( [0].loop())
* )) {
* trace( i._1 ); // Point: point from the line ({x: ?, y: ?})
* trace( i._2 ); // Int: radiation level, decreasing from 50 to 0
* }
* ```
*/
class IterChain2<T> {
var all : Iterable<Iterable<T>>;
var master : Iterator<Iterable<T>>;
var inner : Iterator<T>;
var isInfinite : Bool;
public function new(a:Array<Iterable<T>>) {
all = a;
master = all.iterator();
inner = getNextInnerHavingNext_orNull();
isInfinite = all.exists(function(itb)
return Std.is(itb, "FinitudeIterable")
&& untyped itb.isInfiniteIter()
);
}
public inline static function andThenIter<T>(a:Iterable<T>, b:Iterable<T>)
return new IterChain([a, b]);
public inline static function iterChain<T>(a:Array<Iterable<T>>)
return new IterChain(a);
public macro static function chain<T>(ae:Array<haxe.macro.Expr>) {
var a = [];
for (e in ae) { a.push(e); }
var args = macro $a{a};
return macro new IterChain2($args);
// var a : Array<Iterator<T>> = [];
// for (e in ae)
// a.push(macro
// // Nadako sol. 0
// // >> Reification
// ($e : Iterator<T>)
// // Nadako sol. 1 & 2: ECheckType
// // ${ {
// // expr: ECheckType(
// // e,
// // TPath({
// // pack: [],
// // name: "Iterator",
// // params: [
// // // Nadako sol. 1
// // // TPType(TPath({
// // // pack: [],
// // // name: "T"
// // // }))
// // // Nadako sol. 2
// // // >> Reification
// // TPType(macro : T)
// // ]
// // })
// // ),
// // pos: e.pos
// // } }
// );
// var args = macro $a{a};
// return macro new IterChain2($args);
}
public inline function isInfiniteIter():Bool return isInfinite;
public inline function iterator():IterableIterator<T> return new IterChain(all);
public inline function next() return inner.next();
public function hasNext()
return inner.hasNext()
|| ((inner = getNextInnerHavingNext_orNull()) != null)
;
public function getNextInnerHavingNext_orNull() {
while (inner == null || !inner.hasNext()) {
if (master.hasNext()) inner = master.next().iterator();
else return null;
}
return inner;
}
}