1 // 2 // Tuplize multiple iterators. 3 // It takes iterators and builds on them a new iterator from tuples of 4 // aggregated iterators. 5 // 6 7 module vest.range.tuplizer; 8 9 import std.range : empty, popFront, front; 10 import std.typecons : Tuple, tuple; 11 import std.functional : forward; 12 import std.conv : to; 13 14 auto tuplizer(Ranges...)(auto ref Ranges ranges) 15 { 16 static assert(Ranges.length, "don't call with emprty args"); 17 return Tuplizer!Ranges(forward!ranges); 18 } 19 20 private struct Tuplizer(Ranges...) 21 { 22 private: 23 Tuple!(Ranges) _ranges; 24 public: 25 this(Ranges ranges) 26 { 27 _ranges = tuple(ranges); 28 } 29 30 @property 31 bool empty() const 32 { 33 // _ranges[0].empty || _ranges[1].empty ... 34 return mixin(_ct_join!(Ranges.length, "empty", " || ")); 35 } 36 37 @property 38 auto front() const 39 { 40 // tuple(_ranges[0].front, _ranges[1].front, ...) 41 return mixin("tuple(" ~ _ct_join!(Ranges.length, "front", ", ") ~ ")"); 42 } 43 44 @property 45 auto front() 46 { 47 // tuple(_ranges[0].front, _ranges[1].front, ...) 48 return mixin("tuple(" ~ _ct_join!(Ranges.length, "front", ", ") ~ ")"); 49 } 50 51 // Remove the first element 52 void popFront() 53 { 54 // _ranges[0].popFront; _ranges[1].popFront; ... 55 mixin(_ct_join!(Ranges.length, "popFront", "; ") ~ ";"); 56 } 57 58 private template _ct_join(size_t len, string caller, string glue) 59 { 60 static assert(len, "len mast be greater than zero"); 61 static if(0 == len) { 62 enum string _ct_join = ""; 63 } else static if(1 == len) { 64 enum string _ct_join = "_ranges[0]." ~ caller; 65 } else { 66 enum string _ct_join = 67 _ct_join!(len-1, caller, glue) ~ 68 glue ~ 69 "_ranges[" ~ (len-1).to!string ~ "]." ~ 70 caller; 71 } 72 } 73 74 // just for test 75 //pragma(msg, _ct_join!(Ranges.length, "caller()", " ;glue; ") ); 76 //pragma(msg, _ct_join!(Ranges.length, "front", ", ") ); 77 //pragma(msg, _ct_join!(Ranges.length, "popFront", "; ") ~ ";" ); 78 } 79 80 81 // cd source 82 // rdmd -unittest -main vest/range/tuplizer 83 unittest { 84 import std.typecons : tuple, Tuple; 85 import std.range : iota; 86 import std.array : array; 87 import std.algorithm : map, equal; 88 89 auto rf = iota(0.5, 0.0, -0.1); // 0.5, 0.4, 0.3, 0.2, 0.1 90 auto ri = iota(50, 101, 10); // 50, 60, 70, 80, 90, 100 91 auto as = ["str1", "str2", "str3"]; 92 93 94 auto rt = tuplizer(ri, rf, as); 95 Tuple!(int, double, string)[] at = [ 96 tuple(50, 0.5, "str1"), 97 tuple(60, 0.4, "str2"), 98 tuple(70, 0.3, "str3") 99 ]; 100 101 assert(rt.equal(at)); 102 assert(rt.map!"a[2]".equal(as)); 103 assert(rt.map!"a[0]".equal(ri.array[0..3]) ); 104 }