1 module evx.meta.predicate; 2 3 private {//imports 4 import std.typetuple: templateAnd, templateOr; 5 import std.functional: compose, adjoin; 6 import std.algorithm: all, any; 7 } 8 9 /** 10 string-mixin-based anonymous templates. 11 mixing this in allows the λ/Λ definitions reference symbols in the mixed-in scope 12 */ 13 template LambdaCapture () 14 { 15 /** 16 Λ is an alias 17 */ 18 static template Λ (string op) 19 { 20 mixin(q{ 21 alias Λ } ~ op ~ q{; 22 }); 23 } 24 /** 25 λ is an enum 26 */ 27 static template λ (string op) 28 { 29 mixin(q{ 30 enum λ } ~ op ~ q{; 31 }); 32 } 33 } 34 /// 35 unittest { 36 import std.typetuple: Map = staticMap, Cons = TypeTuple; 37 38 static assert ( 39 Map!(λ!q{(T) = T.sizeof}, 40 int, bool, long 41 ) == Cons!( 42 4,1,8 43 ) 44 ); 45 static assert (is ( 46 Map!(Λ!q{(T) = T[]}, 47 int, bool, long 48 ) == Cons!( 49 int[], bool[], long[] 50 ) 51 )); 52 } 53 54 /* mixin captures local symbols 55 */ 56 mixin LambdaCapture; 57 58 /** 59 combine several template predicates with a logical conjunctive 60 */ 61 alias And = templateAnd; 62 /** 63 ditto 64 */ 65 alias Or = templateOr; 66 67 /** 68 invert a template predicate 69 */ 70 static template Not (alias predicate) 71 { 72 enum Not (Args...) = !predicate!Args; 73 } 74 75 /** 76 named logical not operator (!), 77 runtime predicate inversion, 78 and boolean symbol inversion 79 */ 80 template not () 81 { 82 bool not (T)(T value) 83 { 84 return !value; 85 } 86 } 87 /** 88 ditto 89 */ 90 template not (alias predicate) 91 { 92 bool not (Args...)(Args args) 93 if (is(typeof(predicate (args) == true))) 94 { 95 return !(predicate (args)); 96 } 97 98 bool not (Args...)() 99 if (is(typeof(predicate == true)) && !(is(typeof(predicate(Args.init))))) 100 { 101 return !predicate; 102 } 103 104 bool not (Args...)() 105 if (__traits(compiles, {enum x = predicate!Args;})) 106 { 107 return !(predicate!Args); 108 } 109 } 110 /// 111 unittest { 112 assert (not (false)); 113 assert (not!false); 114 115 auto a = false; 116 117 assert (not (a)); 118 assert (not!a); 119 120 enum b = false; 121 assert (not (b)); 122 assert (not!b); 123 124 auto c () {return false;} 125 126 assert (not (c)); 127 assert (not!c); 128 129 auto d (int x){return x == 1;} 130 131 assert (not (d(0))); 132 assert (not!d (0)); 133 134 alias e = not!d; 135 136 assert (e(0)); 137 assert (not!e (1)); 138 139 assert (not!(x => x % 2 == 0)(1)); 140 } 141 142 template funcs_to_list (funcs...) 143 { 144 import std.range: only; 145 146 alias funcs_to_list = compose!(result => result.expand.only, adjoin!funcs); 147 } 148 149 /** 150 combine several runtime predicates with a logical conjunctive 151 */ 152 alias and (funcs...) = compose!(all, funcs_to_list!funcs); 153 /** 154 ditto 155 */ 156 alias or (funcs...) = compose!(any, funcs_to_list!funcs); 157 /// 158 unittest { 159 static f (int x){return x > 5;} 160 static g (int x){return x < 10;} 161 static h (int x){return x == 7;} 162 163 alias q = and!(f,g,h); 164 alias p = or!(f,g,h); 165 166 assert (q(5) == false); 167 assert (q(6) == false); 168 assert (q(7) == true); 169 assert (q(10) == false); 170 171 assert (p(5) == true); 172 assert (p(6) == true); 173 assert (p(7) == true); 174 assert (p(10) == true); 175 }