1 /** 2 License: 3 Boost Software License - Version 1.0 - August 17th, 2003 4 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 27 Authors: 28 aermicioi 29 **/ 30 module aermicioi.aedi.util.traits.partial; 31 32 import aermicioi.aedi.util.traits.traits; 33 import std.meta; 34 import std.traits; 35 36 /** 37 Instantiate a template that will check equality of first with second 38 39 Params: 40 first = first element 41 second = second element 42 43 Returns: 44 bool true if equal, false otherwise 45 **/ 46 template eq(alias first) { 47 enum bool eq(alias second) = (first == second); 48 } 49 50 /** 51 Instantiate a template that will check if first is greater than second 52 53 Params: 54 first = first element 55 second = second element 56 57 Returns: 58 bool true if greater, false otherwise 59 **/ 60 template gt(alias first) { 61 enum bool eq(alias second) = (first > second); 62 } 63 64 /** 65 Instantiate a template that will check if first is less than second 66 67 Params: 68 first = first element 69 second = second element 70 71 Returns: 72 bool true if lesser, false otherwise 73 **/ 74 template lt(alias first) { 75 enum bool eq(alias second) = (first < second); 76 } 77 78 /** 79 Instantiate a template that will check if first is greater or equal than second 80 81 Params: 82 first = first element 83 second = second element 84 85 Returns: 86 bool true if greater or equal, false otherwise 87 **/ 88 template gte(alias first) { 89 enum bool eq(alias second) = (first >= second); 90 } 91 92 /** 93 Instantiate a template that will check if first is less or equal than second 94 95 Params: 96 first = first element 97 second = second element 98 99 Returns: 100 bool true if lesser or equal, false otherwise 101 **/ 102 template lte(alias first) { 103 enum bool eq(alias second) = (first <= second); 104 } 105 106 107 static if (__traits(hasMember, std.meta, "ApplyLeft")) { 108 alias partialPrefixed = ApplyLeft; 109 } else { 110 /** 111 Prefix a template with a set of arguments. 112 113 Prefix a template with a set of arguments. 114 A prefixed template will have first arguments to be 115 Args, and rest of passed arguments afterwards (Sargs). 116 117 Params: 118 pred = prefixable template 119 Args = arguments that are prefixed 120 Sargs = arguments that are suffixed 121 **/ 122 template partialPrefixed(alias pred, Args...) { 123 template partialPrefixed(Sargs...) { 124 alias partialPrefixed = pred!(Args, Sargs); 125 } 126 } 127 } 128 129 static if (__traits(hasMember, std.meta, "ApplyLeft")) { 130 131 alias partialSuffixed = ApplyRight; 132 } else { 133 134 /** 135 Suffix a template with a set of arguments. 136 137 Suffix a template with a set of arguments. 138 A suffixed template will have first arguments to be 139 Args, and rest of passed arguments afterwards (Sargs). 140 141 Params: 142 pred = prefixable template 143 Args = arguments that are suffixed 144 Sargs = arguments that are prefixed 145 **/ 146 template partialSuffixed(alias pred, Args...) { 147 template partialSuffixed(Sargs...) { 148 alias partialSuffixed = pred!(Sargs, Args); 149 } 150 } 151 } 152 153 /** 154 Instantiate a template with Args, and apply them 155 to pred. 156 157 Params: 158 Args = contained arguments 159 pred = a template that Args will be passed to. 160 **/ 161 template applyArgs(Args...) { 162 template applyArgs(alias pred) { 163 alias applyArgs = pred!Args; 164 } 165 } 166 167 /** 168 Apply to Preds a set of Args. 169 170 Apply to Preds a set of Args. 171 Given a set of Preds, apply for each Args, 172 and return a Tuple of results. 173 174 Params: 175 Preds = predicates that will receive Args. 176 Args = arguments that are suffixed 177 **/ 178 template partial(Preds...) { 179 180 template partial(Args...) { 181 alias partial = staticMap!( 182 applyArgs!Args, 183 Preds 184 ); 185 } 186 } 187 188 /** 189 Chain a set of templates, and apply Args as input. 190 191 Chain a set of templates, and apply Args as input. 192 Description 193 194 Params: 195 Preds = a set of predicates to be chained. 196 Args = arguments passed to chained predicates. 197 198 Returns: 199 Result of executing chained Preds with Args. 200 **/ 201 template chain(predicates...) { 202 template chain(args...) { 203 204 template impl(predicates...) { 205 static if (predicates.length > 0) { 206 alias predicate = predicates[0]; 207 alias impl = predicate!(impl!(predicates[1 .. $])); 208 } else { 209 alias impl = args; 210 } 211 } 212 213 alias chain = impl!predicates; 214 } 215 } 216 217 /** 218 Reverse the order of arguments. 219 220 Params: 221 args = tuple of template arguments. 222 **/ 223 template reverse(args...) { 224 static if (args.length > 0) { 225 alias reverse = AliasSeq!(args[$ - 1], reverse!(args[0 .. $ - 2])); 226 } else { 227 alias reverse = args[0]; 228 } 229 } 230 231 232 /** 233 Execute trueBranch or falseBranch depending on pred!Args bool result. 234 235 Params: 236 pred = template depending on which a trueBranch or falseBranch will be executed. 237 trueBranch = template to be executed when pred!Args is true. 238 falseBranch = template to be executed when pred!Args is false. 239 240 Return: 241 Result of trueBranch or falseBranch depending on pred!Args 242 **/ 243 template if_(alias pred, alias trueBranch, alias falseBranch) { 244 template if_ (Args...) { 245 static if (pred!Args) { 246 static if (isTemplate!trueBranch) { 247 alias if_ = trueBranch!Args; 248 } else { 249 alias if_ = trueBranch; 250 } 251 } else { 252 static if (isTemplate!trueBranch) { 253 alias if_ = falseBranch!Args; 254 } else { 255 alias if_ = falseBranch; 256 } 257 } 258 } 259 } 260 261 /** 262 Execute pred, if it does not have any compiler errors. 263 264 Params: 265 pred = template that will be executed if it does not contain errors. 266 response = a response if pred will fail. 267 268 Return: 269 Result of pred if it does not contain errors or response otherwise 270 **/ 271 alias failable(alias pred, alias response) = 272 if_!( 273 partialPrefixed!( 274 compiles, 275 pred 276 ), 277 pred, 278 response 279 ); 280 281 template get(size_t index) { 282 template get(args...) { 283 alias get = args[index]; 284 } 285 } 286 287 template tee(alias predicate, args...) { 288 alias tee = args; 289 290 alias executed = predicate!args; 291 } 292 293 alias onFail(alias pred) = 294 if_!( 295 isTrue, 296 isTrue, 297 chain!( 298 get!0, 299 partialPrefixed!( 300 tee, 301 pred 302 ) 303 ) 304 ); 305 306 alias onFailPrint(string error) = 307 onFail!( 308 partialSuffixed!( 309 pragmaMsg, 310 error 311 ) 312 ); 313 314 template staticAssert(alias predicate, string error) { 315 template staticAssert(args...) { 316 static assert(predicate!args, error); 317 318 enum bool staticAssert = predicate!args; 319 } 320 } 321 322 auto curry(Dg, Args...)(Dg func, auto ref Args args) 323 if (isSomeFunction!Dg) { 324 class Curry { 325 private { 326 Args args; 327 Dg func; 328 } 329 330 public { 331 this(ref Args args, Dg func) { 332 this.args = args; 333 this.func = func; 334 } 335 336 ReturnType!Dg opCall(Parameters!Dg[Args.length .. $] args) { 337 static if (is(ReturnType!Dg == void)) { 338 func(this.args, args); 339 } else { 340 return func(this.args, args); 341 } 342 } 343 } 344 } 345 346 Curry curry = new Curry(args, func); 347 348 return &curry.opCall; 349 } 350 351 template allSatisfied(alias T, Predicates...) { 352 353 static if (Predicates.length > 1) { 354 enum bool allSatisfied = allSatisfied!(T, Predicates[0]) && allSatisfied!(T, Predicates[1..$]); 355 } else { 356 alias P = Predicates[0]; 357 enum bool allSatisfied = P!T; 358 } 359 } 360 361 template anySatisfied(alias T, Predicates...) { 362 363 static if (Predicates.length > 1) { 364 enum bool anySatisfied = anySatisfied!(T, Predicates[0]) || anySatisfied!(T, Predicates[1..$]); 365 } else { 366 alias P = Predicates[0]; 367 enum bool anySatisfied = P!T; 368 } 369 }