1 module tupleops; 2 3 import std.typecons; 4 5 auto depthFirstMap(alias func, Ts ...)(return auto ref Ts ts) 6 { 7 static if (isTuple!(typeof(ts[0]))) 8 { 9 static if (ts.length == 1) 10 { 11 return depthFirstMap!func(ts[0].expand); 12 } 13 else 14 { 15 return tuple(depthFirstMap!func(ts[0].expand).expand, 16 depthFirstMap!func(ts[1..$]).expand); 17 } 18 } 19 else 20 { 21 static if (ts.length == 1) 22 { 23 return tuple(func(ts[0])); 24 } 25 else 26 { 27 return tuple(func(ts[0]), 28 depthFirstMap!func(ts[1..$]).expand); 29 } 30 } 31 } 32 33 auto flatten(Ts ...)(return auto ref Ts ts) 34 { 35 return depthFirstMap!((return auto ref x) => x)(ts); 36 } 37 38 auto ptrs(Ts ...)(return ref Ts ts) 39 { 40 return depthFirstMap!((return ref x) => &x)(ts); 41 } 42 43 unittest 44 { 45 enum t = tuple(1, 2, tuple(3, tuple(tuple(4, 5), 6), 7)); 46 static assert(t.flatten == tuple(1, 2, 3, 4, 5, 6, 7)); 47 } 48 49 unittest 50 { 51 auto t = tuple(1, 2, tuple(3, tuple(tuple(4, 5), 6), 7)); 52 auto p = t.ptrs; 53 t[1] = 222; 54 auto d = t.flatten; 55 assert(d == tuple(1, 222, 3, 4, 5, 6, 7)); 56 57 static foreach (i; 0 .. t.length) { 58 assert(*p[i] == d[i]); 59 } 60 } 61 62 struct UnzipRange(Z) 63 { 64 Z zipped; 65 alias Tp = typeof(Z.init.front()); 66 const size_t length = Tp.length; 67 68 static auto opIndex(D...)(auto ref D i) 69 { 70 import std.array : array; 71 import std.algorithm : map; 72 return this.zipped.map!(x => x[i]); 73 } 74 } 75 76 77 auto unzip(Z)(Z zipped) 78 { 79 import std.algorithm : map; 80 mixin( 81 { 82 import std.conv : to; 83 alias Tp = typeof(Z.init.front()); 84 auto m = "return tuple("; 85 foreach (i; 0 .. Tp.length) 86 { 87 m ~= "zipped.map!(x => x[" ~ i.to!string ~ "]),"; 88 } 89 return m[0 .. $-1] ~ ");"; 90 }()); 91 } 92 93 unittest 94 { 95 import std.algorithm : equal; 96 import std.range : zip; 97 immutable a = [1, 2, 3]; 98 immutable b = ["a", "b", "c"]; 99 immutable c = [0.1, 0.2, 0.3]; 100 101 auto x = tuple(a, b, c); 102 auto z = zip(x.expand); 103 auto u = unzip(zip(a, b, c)); 104 static foreach (i; 0 .. x.length) 105 { 106 assert(u[i].equal(x[i])); 107 } 108 }