1 module reggae.range; 2 3 import reggae.build; 4 import std.range; 5 import std.algorithm; 6 7 @safe: 8 9 struct DepthFirst { 10 const(Target)[] targets; 11 12 this(in Target target) pure nothrow { 13 this.targets = depthFirstTargets(target); 14 } 15 16 const(Target)[] depthFirstTargets(in Target target) pure nothrow { 17 //if leaf, return 18 if(target.isLeaf) return target.expandCommand is null ? [] : [target]; 19 20 //if not, add ourselves to the end to get depth-first 21 return reduce!((a, b) => a ~ depthFirstTargets(b))(typeof(return).init, target.dependencies) ~ 22 reduce!((a, b) => a ~ depthFirstTargets(b))(typeof(return).init, target.implicits) ~ 23 target; 24 } 25 26 Target front() pure nothrow { 27 return targets.front; 28 } 29 30 void popFront() pure nothrow { 31 targets.popFront; 32 } 33 34 bool empty() pure nothrow { 35 return targets.empty; 36 } 37 38 static assert(isInputRange!DepthFirst); 39 } 40 41 42 struct ByDepthLevel { 43 const(Target)[][] targets; 44 45 this(in Target target) pure nothrow { 46 this.targets = sortTargets(target); 47 } 48 49 auto front() pure nothrow { 50 return targets.front; 51 } 52 53 void popFront() pure nothrow { 54 targets.popFront; 55 } 56 57 bool empty() pure nothrow { 58 return targets.empty; 59 } 60 61 private const(Target)[][] sortTargets(in Target target) pure nothrow { 62 if(target.isLeaf) return []; 63 64 const(Target)[][] targets = [[target]]; 65 rec(0, [target], targets); 66 return targets.retro.array; 67 } 68 69 private void rec(int level, in Target[] targets, ref const(Target)[][] soFar) @trusted pure nothrow { 70 const notLeaves = targets. 71 map!(a => chain(a.dependencies, a.implicits)). //get all dependencies 72 flatten. //flatten into a regular range 73 filter!(a => !a.isLeaf). //don't care about leaves 74 array; 75 if(notLeaves.empty) return; 76 77 soFar ~= notLeaves; 78 rec(level + 1, notLeaves, soFar); 79 } 80 81 static assert(isInputRange!ByDepthLevel); 82 } 83 84 struct Leaves { 85 this(in Target target) pure nothrow { 86 recurse(target); 87 } 88 89 Target front() pure nothrow { 90 return targets.front; 91 } 92 93 void popFront() pure nothrow { 94 targets.popFront; 95 } 96 97 bool empty() pure nothrow { 98 return targets.empty; 99 } 100 101 102 private: 103 104 const(Target)[] targets; 105 106 void recurse(in Target target) pure nothrow { 107 if(target.isLeaf) { 108 targets ~= target; 109 return; 110 } 111 112 foreach(dep; target.dependencies ~ target.implicits) { 113 if(dep.isLeaf) { 114 targets ~= dep; 115 } else { 116 recurse(dep); 117 } 118 } 119 } 120 121 static assert(isInputRange!Leaves); 122 } 123 124 125 //TODO: a non-allocating version with no arrays 126 auto flatten(R)(R range) @trusted pure nothrow { 127 alias rangeType = ElementType!R; 128 alias T = ElementType!rangeType; 129 T[] res; 130 foreach(x; range) res ~= x.array; 131 return res; 132 }