1 module vest.range.itarable;
2 
3 import std.functional : forward;
4 import std.range : ElementType, front, empty, popFront;
5 
6 
7 interface iItarable(ElType)
8 {
9     @property 
10     ElType front();
11 
12     @property
13     bool empty();
14 
15     void popFront();
16 }
17 
18 class Itarable(Range, ElType = ElementType!Range) : iItarable!ElType
19 {
20 private:
21     Range r;
22 public:
23     this()(auto ref Range r) {
24         //this.r = forward!r; <-- ldc2 incompatible
25         this.r = r;
26     }
27 
28     @property final
29     ElType front()     {return r.front;}
30     
31     @property final
32     bool empty()       {return r.empty;}
33     
34     void popFront()    {return r.popFront;}
35 }
36 
37 iItarable!(ElementType!Range) getItarable(Range)(Range r) {
38     return new Itarable!(Range, ElementType!Range)(forward!r);
39 }
40 iItarable!(ElType) getItarable(ElType, Range)(Range r) {
41     return new Itarable!(Range, ElType)(forward!r);
42 }
43 
44 
45 ////////////////////////////////////////////////
46 
47 // cd source 
48 // rdmd -unittest -main  vest/range/itarable
49 
50 unittest {
51     //import std.stdio     : writeln;
52     import std.range     : iota;
53     import std.algorithm : map;
54     //import std.array     : array;
55     import std.math      : approxEqual;
56     import std.algorithm.comparison : equal;
57 
58     import vest.range    : expandNested;
59 
60 
61     assert(iota(20, 25, 1)
62         .map!(x => iota(21, x, 1))
63         .expandNested
64         .equal([21, 21, 22, 21, 22, 23]));
65 
66     assert([
67             [1,2].getItarable,
68             iota(10, 16).getItarable,
69         ]
70         .expandNested
71         .equal([1, 2, 10, 11, 12, 13, 14, 15]));
72 
73     assert([
74             [1.1,2.1].getItarable!float,
75             iota(10, 16).getItarable!float,
76         ]
77         .expandNested
78         .approxEqual([1.1, 2.1, 10.0, 11.0, 12.0, 13.0, 14.0, 15]));
79 
80 
81     interface iTest {
82         int get() const;
83     }
84     class Test1 : iTest
85     {
86         int i;
87         this(int i) {this.i = i;}
88         int get() const {return i*i;}
89     }
90     class Test2 : iTest
91     {
92         int i;
93         this(int i) {this.i = i;}
94         int get() const {return i*i*i;}
95     }
96 
97     assert([
98             [1,2,3]
99                 .map!(x => new Test1(x))
100                 .getItarable,
101             [1,2,3]
102                 .map!(x => new Test1(x))
103                 .getItarable,
104         ]
105         .expandNested
106         .map!(x => x.get)
107         .equal([1, 4, 9, 1, 4, 9]));
108     
109     assert([
110             [1,2,3]
111                 .map!(x => new Test1(x))
112                 .getItarable!iTest,
113             [1,2,3]
114                 .map!(x => new Test2(x))
115                 .getItarable!iTest,
116         ]
117         .expandNested
118         .map!(x => x.get)
119         .equal([1, 4, 9, 1, 8, 27]));
120 }