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.util.traits.partial; 31 32 import aermicioi.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 Prefix a template with a set of arguments. 108 109 Prefix a template with a set of arguments. 110 A prefixed template will have first arguments to be 111 Args, and rest of passed arguments afterwards (Sargs). 112 113 Params: 114 pred = prefixable template 115 Args = arguments that are prefixed 116 Sargs = arguments that are suffixed 117 **/ 118 template partialPrefixed(alias pred, Args...) { 119 template partialPrefixed(Sargs...) { 120 alias partialPrefixed = pred!(Args, Sargs); 121 } 122 } 123 124 /** 125 Suffix a template with a set of arguments. 126 127 Suffix a template with a set of arguments. 128 A suffixed template will have first arguments to be 129 Args, and rest of passed arguments afterwards (Sargs). 130 131 Params: 132 pred = prefixable template 133 Args = arguments that are suffixed 134 Sargs = arguments that are prefixed 135 **/ 136 template partialSuffixed(alias pred, Args...) { 137 template partialSuffixed(Sargs...) { 138 alias partialSuffixed = pred!(Sargs, Args); 139 } 140 } 141 142 /** 143 Instantiate a template with Args, and apply them 144 to pred. 145 146 Params: 147 Args = contained arguments 148 pred = a template that Args will be passed to. 149 **/ 150 template applyArgs(Args...) { 151 template applyArgs(alias pred) { 152 alias applyArgs = pred!Args; 153 } 154 } 155 156 /** 157 Apply to Preds a set of Args. 158 159 Apply to Preds a set of Args. 160 Given a set of Preds, apply for each Args, 161 and return a Tuple of results. 162 163 Params: 164 Preds = predicates that will receive Args. 165 Args = arguments that are suffixed 166 **/ 167 template partial(Preds...) { 168 169 template partial(Args...) { 170 alias partial = staticMap!( 171 applyArgs!Args, 172 Preds 173 ); 174 } 175 } 176 177 /** 178 Chain a set of templates, and apply Args as input. 179 180 Chain a set of templates, and apply Args as input. 181 Description 182 183 Params: 184 Preds = a set of predicates to be chained. 185 Args = arguments passed to chained predicates. 186 187 Returns: 188 Result of executing chained Preds with Args. 189 **/ 190 template chain(predicates...) { 191 template chain(args...) { 192 193 template impl(predicates...) { 194 static if (predicates.length > 0) { 195 alias predicate = predicates[0]; 196 alias impl = predicate!(impl!(predicates[1 .. $])); 197 } else { 198 alias impl = args; 199 } 200 } 201 202 alias chain = impl!predicates; 203 } 204 } 205 206 /** 207 Reverse the order of arguments. 208 209 Params: 210 args = tuple of template arguments. 211 **/ 212 template reverse(args...) { 213 static if (args.length > 0) { 214 alias reverse = AliasSeq!(args[$ - 1], reverse!(args[0 .. $ - 2])); 215 } else { 216 alias reverse = args[0]; 217 } 218 } 219 220 221 /** 222 Execute trueBranch or falseBranch depending on pred!Args bool result. 223 224 Params: 225 pred = template depending on which a trueBranch or falseBranch will be executed. 226 trueBranch = template to be executed when pred!Args is true. 227 falseBranch = template to be executed when pred!Args is false. 228 229 Return: 230 Result of trueBranch or falseBranch depending on pred!Args 231 **/ 232 template if_(alias pred, alias trueBranch, alias falseBranch) { 233 template if_ (Args...) { 234 static if (pred!Args) { 235 static if (isTemplate!trueBranch) { 236 alias if_ = trueBranch!Args; 237 } else { 238 alias if_ = trueBranch; 239 } 240 } else { 241 static if (isTemplate!trueBranch) { 242 alias if_ = falseBranch!Args; 243 } else { 244 alias if_ = falseBranch; 245 } 246 } 247 } 248 } 249 250 /** 251 Execute pred, if it does not have any compiler errors. 252 253 Params: 254 pred = template that will be executed if it does not contain errors. 255 response = a response if pred will fail. 256 257 Return: 258 Result of pred if it does not contain errors or response otherwise 259 **/ 260 alias failable(alias pred, alias response) = 261 if_!( 262 partialPrefixed!( 263 compiles, 264 pred 265 ), 266 pred, 267 response 268 ); 269 270 template get(size_t index) { 271 template get(args...) { 272 alias get = args[index]; 273 } 274 } 275 276 template tee(alias predicate, args...) { 277 alias tee = args; 278 279 alias executed = predicate!args; 280 } 281 282 alias onFail(alias pred) = 283 if_!( 284 isTrue, 285 isTrue, 286 chain!( 287 get!0, 288 partialPrefixed!( 289 tee, 290 pred 291 ) 292 ) 293 ); 294 295 alias onFailPrint(string error) = 296 onFail!( 297 partialSuffixed!( 298 pragmaMsg, 299 error 300 ) 301 ); 302 303 template staticAssert(alias predicate, string error) { 304 template staticAssert(args...) { 305 static assert(predicate!args, error); 306 307 enum bool staticAssert = predicate!args; 308 } 309 } 310 311 auto curry(Dg, Args...)(Dg func, auto ref Args args) 312 if (isSomeFunction!Dg) { 313 import std.typecons; 314 class Curry { 315 private { 316 Tuple!Args args; 317 Dg func; 318 } 319 320 public { 321 this(ref Args args, Dg func) { 322 this.args = tuple!(args); 323 this.func = func; 324 } 325 326 ReturnType!Dg opCall(Parameters!Dg[Args.length .. $] args) { 327 static if (is(ReturnType!Dg == void)) { 328 func(this.args.expand, args); 329 } else { 330 return func(this.args.expand, args); 331 } 332 } 333 } 334 } 335 336 Curry curry = new Curry(args, func); 337 338 return &curry.opCall; 339 }