1 // Written in the D programming language. 2 3 /** 4 Functions that manipulate other functions. 5 6 This module provides functions for compile time function composition. These 7 functions are helpful when constructing predicates for the algorithms in 8 $(MREF std, algorithm) or $(MREF std, range). 9 10 $(SCRIPT inhibitQuickIndex = 1;) 11 $(DIVC quickindex, 12 $(BOOKTABLE , 13 $(TR $(TH Function Name) $(TH Description) 14 ) 15 $(TR $(TD $(LREF adjoin)) 16 $(TD Joins a couple of functions into one that executes the original 17 functions independently and returns a tuple with all the results. 18 )) 19 $(TR $(TD $(LREF compose), $(LREF pipe)) 20 $(TD Join a couple of functions into one that executes the original 21 functions one after the other, using one function's result for the next 22 function's argument. 23 )) 24 $(TR $(TD $(LREF lessThan), $(LREF greaterThan), $(LREF equalTo)) 25 $(TD Ready-made predicate functions to compare two values. 26 )) 27 $(TR $(TD $(LREF memoize)) 28 $(TD Creates a function that caches its result for fast re-evaluation. 29 )) 30 $(TR $(TD $(LREF not)) 31 $(TD Creates a function that negates another. 32 )) 33 $(TR $(TD $(LREF partial)) 34 $(TD Creates a function that binds the first argument of a given function 35 to a given value. 36 )) 37 $(TR $(TD $(LREF curry)) 38 $(TD Converts a multi-argument function into a series of single-argument 39 functions. f(x, y) == curry(f)(x)(y) 40 )) 41 $(TR $(TD $(LREF reverseArgs)) 42 $(TD Predicate that reverses the order of its arguments. 43 )) 44 $(TR $(TD $(LREF toDelegate)) 45 $(TD Converts a callable to a delegate. 46 )) 47 $(TR $(TD $(LREF unaryFun), $(LREF binaryFun)) 48 $(TD Create a unary or binary function from a string. Most often 49 used when defining algorithms on ranges. 50 )) 51 $(TR $(TD $(LREF bind)) 52 $(TD Passes the fields of a struct as arguments to a function. 53 )) 54 $(TR $(TD $(LREF ctEval)) 55 $(TD Enforces the evaluation of an expression during compile-time. 56 )) 57 )) 58 59 Copyright: Copyright Andrei Alexandrescu 2008 - 2009. 60 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 61 Authors: $(HTTP erdani.org, Andrei Alexandrescu) 62 Source: $(PHOBOSSRC std/functional.d) 63 */ 64 /* 65 Copyright Andrei Alexandrescu 2008 - 2009. 66 Distributed under the Boost Software License, Version 1.0. 67 (See accompanying file LICENSE_1_0.txt or copy at 68 http://www.boost.org/LICENSE_1_0.txt) 69 */ 70 module std.functional; 71 72 import std.meta : AliasSeq, Reverse; 73 import std.traits : isCallable, Parameters; 74 import std.conv : toCtString; 75 76 import std.internal.attributes : betterC; 77 78 public import core.lifetime : forward; 79 80 private template needOpCallAlias(alias fun) 81 { 82 /* Determine whether or not unaryFun and binaryFun need to alias to fun or 83 * fun.opCall. Basically, fun is a function object if fun(...) compiles. We 84 * want is(unaryFun!fun) (resp., is(binaryFun!fun)) to be true if fun is 85 * any function object. There are 4 possible cases: 86 * 87 * 1) fun is the type of a function object with static opCall; 88 * 2) fun is an instance of a function object with static opCall; 89 * 3) fun is the type of a function object with non-static opCall; 90 * 4) fun is an instance of a function object with non-static opCall. 91 * 92 * In case (1), is(unaryFun!fun) should compile, but does not if unaryFun 93 * aliases itself to fun, because typeof(fun) is an error when fun itself 94 * is a type. So it must be aliased to fun.opCall instead. All other cases 95 * should be aliased to fun directly. 96 */ 97 static if (is(typeof(fun.opCall) == function)) 98 { 99 enum needOpCallAlias = !is(typeof(fun)) && __traits(compiles, () { 100 return fun(Parameters!fun.init); 101 }); 102 } 103 else 104 enum needOpCallAlias = false; 105 } 106 107 /** 108 Transforms a `string` representing an expression into a unary 109 function. The `string` must either use symbol name `a` as 110 the parameter or provide the symbol via the `parmName` argument. 111 112 Params: 113 fun = a `string` or a callable 114 parmName = the name of the parameter if `fun` is a string. Defaults 115 to `"a"`. 116 Returns: 117 If `fun` is a `string`, a new single parameter function 118 119 If `fun` is not a `string`, an alias to `fun`. 120 */ 121 template unaryFun(alias fun, string parmName = "a") 122 { 123 static if (is(typeof(fun) : string)) 124 { 125 static if (!fun._ctfeMatchUnary(parmName)) 126 { 127 import std.algorithm, std.conv, std.exception, std.math, std.range, std.string; 128 import std.meta, std.traits, std.typecons; 129 } 130 auto unaryFun(ElementType)(auto ref ElementType __a) 131 { 132 mixin("alias " ~ parmName ~ " = __a ;"); 133 return mixin(fun); 134 } 135 } 136 else static if (needOpCallAlias!fun) 137 { 138 // https://issues.dlang.org/show_bug.cgi?id=9906 139 alias unaryFun = fun.opCall; 140 } 141 else 142 { 143 alias unaryFun = fun; 144 } 145 } 146 147 /// 148 @safe unittest 149 { 150 // Strings are compiled into functions: 151 alias isEven = unaryFun!("(a & 1) == 0"); 152 assert(isEven(2) && !isEven(1)); 153 } 154 155 @safe unittest 156 { 157 static int f1(int a) { return a + 1; } 158 static assert(is(typeof(unaryFun!(f1)(1)) == int)); 159 assert(unaryFun!(f1)(41) == 42); 160 int f2(int a) { return a + 1; } 161 static assert(is(typeof(unaryFun!(f2)(1)) == int)); 162 assert(unaryFun!(f2)(41) == 42); 163 assert(unaryFun!("a + 1")(41) == 42); 164 //assert(unaryFun!("return a + 1;")(41) == 42); 165 166 int num = 41; 167 assert(unaryFun!"a + 1"(num) == 42); 168 169 // https://issues.dlang.org/show_bug.cgi?id=9906 170 struct Seen 171 { 172 static bool opCall(int n) { return true; } 173 } 174 static assert(needOpCallAlias!Seen); 175 static assert(is(typeof(unaryFun!Seen(1)))); 176 assert(unaryFun!Seen(1)); 177 178 Seen s; 179 static assert(!needOpCallAlias!s); 180 static assert(is(typeof(unaryFun!s(1)))); 181 assert(unaryFun!s(1)); 182 183 struct FuncObj 184 { 185 bool opCall(int n) { return true; } 186 } 187 FuncObj fo; 188 static assert(!needOpCallAlias!fo); 189 static assert(is(typeof(unaryFun!fo))); 190 assert(unaryFun!fo(1)); 191 192 // Function object with non-static opCall can only be called with an 193 // instance, not with merely the type. 194 static assert(!is(typeof(unaryFun!FuncObj))); 195 } 196 197 /** 198 Transforms a `string` representing an expression into a binary function. The 199 `string` must either use symbol names `a` and `b` as the parameters or 200 provide the symbols via the `parm1Name` and `parm2Name` arguments. 201 202 Params: 203 fun = a `string` or a callable 204 parm1Name = the name of the first parameter if `fun` is a string. 205 Defaults to `"a"`. 206 parm2Name = the name of the second parameter if `fun` is a string. 207 Defaults to `"b"`. 208 Returns: 209 If `fun` is not a string, `binaryFun` aliases itself away to 210 `fun`. 211 */ 212 template binaryFun(alias fun, string parm1Name = "a", 213 string parm2Name = "b") 214 { 215 static if (is(typeof(fun) : string)) 216 { 217 static if (!fun._ctfeMatchBinary(parm1Name, parm2Name)) 218 { 219 import std.algorithm, std.conv, std.exception, std.math, std.range, std.string; 220 import std.meta, std.traits, std.typecons; 221 } 222 auto binaryFun(ElementType1, ElementType2) 223 (auto ref ElementType1 __a, auto ref ElementType2 __b) 224 { 225 mixin("alias "~parm1Name~" = __a ;"); 226 mixin("alias "~parm2Name~" = __b ;"); 227 return mixin(fun); 228 } 229 } 230 else static if (needOpCallAlias!fun) 231 { 232 // https://issues.dlang.org/show_bug.cgi?id=9906 233 alias binaryFun = fun.opCall; 234 } 235 else 236 { 237 alias binaryFun = fun; 238 } 239 } 240 241 /// 242 @safe unittest 243 { 244 alias less = binaryFun!("a < b"); 245 assert(less(1, 2) && !less(2, 1)); 246 alias greater = binaryFun!("a > b"); 247 assert(!greater("1", "2") && greater("2", "1")); 248 } 249 250 @safe unittest 251 { 252 static int f1(int a, string b) { return a + 1; } 253 static assert(is(typeof(binaryFun!(f1)(1, "2")) == int)); 254 assert(binaryFun!(f1)(41, "a") == 42); 255 string f2(int a, string b) { return b ~ "2"; } 256 static assert(is(typeof(binaryFun!(f2)(1, "1")) == string)); 257 assert(binaryFun!(f2)(1, "4") == "42"); 258 assert(binaryFun!("a + b")(41, 1) == 42); 259 //@@BUG 260 //assert(binaryFun!("return a + b;")(41, 1) == 42); 261 262 // https://issues.dlang.org/show_bug.cgi?id=9906 263 struct Seen 264 { 265 static bool opCall(int x, int y) { return true; } 266 } 267 static assert(is(typeof(binaryFun!Seen))); 268 assert(binaryFun!Seen(1,1)); 269 270 struct FuncObj 271 { 272 bool opCall(int x, int y) { return true; } 273 } 274 FuncObj fo; 275 static assert(!needOpCallAlias!fo); 276 static assert(is(typeof(binaryFun!fo))); 277 assert(unaryFun!fo(1,1)); 278 279 // Function object with non-static opCall can only be called with an 280 // instance, not with merely the type. 281 static assert(!is(typeof(binaryFun!FuncObj))); 282 } 283 284 // skip all ASCII chars except a .. z, A .. Z, 0 .. 9, '_' and '.'. 285 private uint _ctfeSkipOp(ref string op) 286 { 287 if (!__ctfe) assert(false); 288 import std.ascii : isASCII, isAlphaNum; 289 immutable oldLength = op.length; 290 while (op.length) 291 { 292 immutable front = op[0]; 293 if (front.isASCII() && !(front.isAlphaNum() || front == '_' || front == '.')) 294 op = op[1..$]; 295 else 296 break; 297 } 298 return oldLength != op.length; 299 } 300 301 // skip all digits 302 private uint _ctfeSkipInteger(ref string op) 303 { 304 if (!__ctfe) assert(false); 305 import std.ascii : isDigit; 306 immutable oldLength = op.length; 307 while (op.length) 308 { 309 immutable front = op[0]; 310 if (front.isDigit()) 311 op = op[1..$]; 312 else 313 break; 314 } 315 return oldLength != op.length; 316 } 317 318 // skip name 319 private uint _ctfeSkipName(ref string op, string name) 320 { 321 if (!__ctfe) assert(false); 322 if (op.length >= name.length && op[0 .. name.length] == name) 323 { 324 op = op[name.length..$]; 325 return 1; 326 } 327 return 0; 328 } 329 330 // returns 1 if `fun` is trivial unary function 331 private uint _ctfeMatchUnary(string fun, string name) 332 { 333 if (!__ctfe) assert(false); 334 fun._ctfeSkipOp(); 335 for (;;) 336 { 337 immutable h = fun._ctfeSkipName(name) + fun._ctfeSkipInteger(); 338 if (h == 0) 339 { 340 fun._ctfeSkipOp(); 341 break; 342 } 343 else if (h == 1) 344 { 345 if (!fun._ctfeSkipOp()) 346 break; 347 } 348 else 349 return 0; 350 } 351 return fun.length == 0; 352 } 353 354 @safe unittest 355 { 356 static assert(!_ctfeMatchUnary("sqrt(ё)", "ё")); 357 static assert(!_ctfeMatchUnary("ё.sqrt", "ё")); 358 static assert(!_ctfeMatchUnary(".ё+ё", "ё")); 359 static assert(!_ctfeMatchUnary("_ё+ё", "ё")); 360 static assert(!_ctfeMatchUnary("ёё", "ё")); 361 static assert(_ctfeMatchUnary("a+a", "a")); 362 static assert(_ctfeMatchUnary("a + 10", "a")); 363 static assert(_ctfeMatchUnary("4 == a", "a")); 364 static assert(_ctfeMatchUnary("2 == a", "a")); 365 static assert(_ctfeMatchUnary("1 != a", "a")); 366 static assert(_ctfeMatchUnary("a != 4", "a")); 367 static assert(_ctfeMatchUnary("a< 1", "a")); 368 static assert(_ctfeMatchUnary("434 < a", "a")); 369 static assert(_ctfeMatchUnary("132 > a", "a")); 370 static assert(_ctfeMatchUnary("123 >a", "a")); 371 static assert(_ctfeMatchUnary("a>82", "a")); 372 static assert(_ctfeMatchUnary("ё>82", "ё")); 373 static assert(_ctfeMatchUnary("ё[ё(ё)]", "ё")); 374 static assert(_ctfeMatchUnary("ё[21]", "ё")); 375 } 376 377 // returns 1 if `fun` is trivial binary function 378 private uint _ctfeMatchBinary(string fun, string name1, string name2) 379 { 380 if (!__ctfe) assert(false); 381 fun._ctfeSkipOp(); 382 for (;;) 383 { 384 immutable h = fun._ctfeSkipName(name1) + fun._ctfeSkipName(name2) + fun._ctfeSkipInteger(); 385 if (h == 0) 386 { 387 fun._ctfeSkipOp(); 388 break; 389 } 390 else if (h == 1) 391 { 392 if (!fun._ctfeSkipOp()) 393 break; 394 } 395 else 396 return 0; 397 } 398 return fun.length == 0; 399 } 400 401 @safe unittest 402 { 403 404 static assert(!_ctfeMatchBinary("sqrt(ё)", "ё", "b")); 405 static assert(!_ctfeMatchBinary("ё.sqrt", "ё", "b")); 406 static assert(!_ctfeMatchBinary(".ё+ё", "ё", "b")); 407 static assert(!_ctfeMatchBinary("_ё+ё", "ё", "b")); 408 static assert(!_ctfeMatchBinary("ёё", "ё", "b")); 409 static assert(_ctfeMatchBinary("a+a", "a", "b")); 410 static assert(_ctfeMatchBinary("a + 10", "a", "b")); 411 static assert(_ctfeMatchBinary("4 == a", "a", "b")); 412 static assert(_ctfeMatchBinary("2 == a", "a", "b")); 413 static assert(_ctfeMatchBinary("1 != a", "a", "b")); 414 static assert(_ctfeMatchBinary("a != 4", "a", "b")); 415 static assert(_ctfeMatchBinary("a< 1", "a", "b")); 416 static assert(_ctfeMatchBinary("434 < a", "a", "b")); 417 static assert(_ctfeMatchBinary("132 > a", "a", "b")); 418 static assert(_ctfeMatchBinary("123 >a", "a", "b")); 419 static assert(_ctfeMatchBinary("a>82", "a", "b")); 420 static assert(_ctfeMatchBinary("ё>82", "ё", "q")); 421 static assert(_ctfeMatchBinary("ё[ё(10)]", "ё", "q")); 422 static assert(_ctfeMatchBinary("ё[21]", "ё", "q")); 423 424 static assert(!_ctfeMatchBinary("sqrt(ё)+b", "b", "ё")); 425 static assert(!_ctfeMatchBinary("ё.sqrt-b", "b", "ё")); 426 static assert(!_ctfeMatchBinary(".ё+b", "b", "ё")); 427 static assert(!_ctfeMatchBinary("_b+ё", "b", "ё")); 428 static assert(!_ctfeMatchBinary("ba", "b", "a")); 429 static assert(_ctfeMatchBinary("a+b", "b", "a")); 430 static assert(_ctfeMatchBinary("a + b", "b", "a")); 431 static assert(_ctfeMatchBinary("b == a", "b", "a")); 432 static assert(_ctfeMatchBinary("b == a", "b", "a")); 433 static assert(_ctfeMatchBinary("b != a", "b", "a")); 434 static assert(_ctfeMatchBinary("a != b", "b", "a")); 435 static assert(_ctfeMatchBinary("a< b", "b", "a")); 436 static assert(_ctfeMatchBinary("b < a", "b", "a")); 437 static assert(_ctfeMatchBinary("b > a", "b", "a")); 438 static assert(_ctfeMatchBinary("b >a", "b", "a")); 439 static assert(_ctfeMatchBinary("a>b", "b", "a")); 440 static assert(_ctfeMatchBinary("ё>b", "b", "ё")); 441 static assert(_ctfeMatchBinary("b[ё(-1)]", "b", "ё")); 442 static assert(_ctfeMatchBinary("ё[-21]", "b", "ё")); 443 } 444 445 //undocumented 446 template safeOp(string S) 447 if (S=="<"||S==">"||S=="<="||S==">="||S=="=="||S=="!=") 448 { 449 import std.traits : isIntegral; 450 private bool unsafeOp(ElementType1, ElementType2)(ElementType1 a, ElementType2 b) pure 451 if (isIntegral!ElementType1 && isIntegral!ElementType2) 452 { 453 import std.traits : CommonType; 454 alias T = CommonType!(ElementType1, ElementType2); 455 return mixin("cast(T)a "~S~" cast(T) b"); 456 } 457 458 bool safeOp(T0, T1)(auto ref T0 a, auto ref T1 b) 459 { 460 import std.traits : mostNegative; 461 static if (isIntegral!T0 && isIntegral!T1 && 462 (mostNegative!T0 < 0) != (mostNegative!T1 < 0)) 463 { 464 static if (S == "<=" || S == "<") 465 { 466 static if (mostNegative!T0 < 0) 467 immutable result = a < 0 || unsafeOp(a, b); 468 else 469 immutable result = b >= 0 && unsafeOp(a, b); 470 } 471 else 472 { 473 static if (mostNegative!T0 < 0) 474 immutable result = a >= 0 && unsafeOp(a, b); 475 else 476 immutable result = b < 0 || unsafeOp(a, b); 477 } 478 } 479 else 480 { 481 static assert(is(typeof(mixin("a "~S~" b"))), 482 "Invalid arguments: Cannot compare types " ~ T0.stringof ~ " and " ~ T1.stringof ~ "."); 483 484 immutable result = mixin("a "~S~" b"); 485 } 486 return result; 487 } 488 } 489 490 @safe unittest //check user defined types 491 { 492 import std.algorithm.comparison : equal; 493 struct Foo 494 { 495 int a; 496 auto opEquals(Foo foo) 497 { 498 return a == foo.a; 499 } 500 } 501 assert(safeOp!"!="(Foo(1), Foo(2))); 502 } 503 504 /** 505 Predicate that returns $(D_PARAM a < b). 506 Correctly compares signed and unsigned integers, ie. -1 < 2U. 507 */ 508 alias lessThan = safeOp!"<"; 509 510 /// 511 pure @safe @nogc nothrow unittest 512 { 513 assert(lessThan(2, 3)); 514 assert(lessThan(2U, 3U)); 515 assert(lessThan(2, 3.0)); 516 assert(lessThan(-2, 3U)); 517 assert(lessThan(2, 3U)); 518 assert(!lessThan(3U, -2)); 519 assert(!lessThan(3U, 2)); 520 assert(!lessThan(0, 0)); 521 assert(!lessThan(0U, 0)); 522 assert(!lessThan(0, 0U)); 523 } 524 525 /** 526 Predicate that returns $(D_PARAM a > b). 527 Correctly compares signed and unsigned integers, ie. 2U > -1. 528 */ 529 alias greaterThan = safeOp!">"; 530 531 /// 532 @safe unittest 533 { 534 assert(!greaterThan(2, 3)); 535 assert(!greaterThan(2U, 3U)); 536 assert(!greaterThan(2, 3.0)); 537 assert(!greaterThan(-2, 3U)); 538 assert(!greaterThan(2, 3U)); 539 assert(greaterThan(3U, -2)); 540 assert(greaterThan(3U, 2)); 541 assert(!greaterThan(0, 0)); 542 assert(!greaterThan(0U, 0)); 543 assert(!greaterThan(0, 0U)); 544 } 545 546 /** 547 Predicate that returns $(D_PARAM a == b). 548 Correctly compares signed and unsigned integers, ie. !(-1 == ~0U). 549 */ 550 alias equalTo = safeOp!"=="; 551 552 /// 553 @safe unittest 554 { 555 assert(equalTo(0U, 0)); 556 assert(equalTo(0, 0U)); 557 assert(!equalTo(-1, ~0U)); 558 } 559 /** 560 N-ary predicate that reverses the order of arguments, e.g., given 561 $(D pred(a, b, c)), returns $(D pred(c, b, a)). 562 563 Params: 564 pred = A callable 565 Returns: 566 A function which calls `pred` after reversing the given parameters 567 */ 568 template reverseArgs(alias pred) 569 { 570 auto reverseArgs(Args...)(auto ref Args args) 571 if (is(typeof(pred(Reverse!args)))) 572 { 573 return pred(Reverse!args); 574 } 575 } 576 577 /// 578 @safe unittest 579 { 580 alias gt = reverseArgs!(binaryFun!("a < b")); 581 assert(gt(2, 1) && !gt(1, 1)); 582 } 583 584 /// 585 @safe unittest 586 { 587 int x = 42; 588 bool xyz(int a, int b) { return a * x < b / x; } 589 auto foo = &xyz; 590 foo(4, 5); 591 alias zyx = reverseArgs!(foo); 592 assert(zyx(5, 4) == foo(4, 5)); 593 } 594 595 /// 596 @safe unittest 597 { 598 alias gt = reverseArgs!(binaryFun!("a < b")); 599 assert(gt(2, 1) && !gt(1, 1)); 600 int x = 42; 601 bool xyz(int a, int b) { return a * x < b / x; } 602 auto foo = &xyz; 603 foo(4, 5); 604 alias zyx = reverseArgs!(foo); 605 assert(zyx(5, 4) == foo(4, 5)); 606 } 607 608 /// 609 @safe unittest 610 { 611 int abc(int a, int b, int c) { return a * b + c; } 612 alias cba = reverseArgs!abc; 613 assert(abc(91, 17, 32) == cba(32, 17, 91)); 614 } 615 616 /// 617 @safe unittest 618 { 619 int a(int a) { return a * 2; } 620 alias _a = reverseArgs!a; 621 assert(a(2) == _a(2)); 622 } 623 624 /// 625 @safe unittest 626 { 627 int b() { return 4; } 628 alias _b = reverseArgs!b; 629 assert(b() == _b()); 630 } 631 632 /** 633 Negates predicate `pred`. 634 635 Params: 636 pred = A string or a callable 637 Returns: 638 A function which calls `pred` and returns the logical negation of its 639 return value. 640 */ 641 template not(alias pred) 642 { 643 auto not(T...)(auto ref T args) 644 { 645 static if (is(typeof(!pred(args)))) 646 return !pred(args); 647 else static if (T.length == 1) 648 return !unaryFun!pred(args); 649 else static if (T.length == 2) 650 return !binaryFun!pred(args); 651 else 652 static assert(0); 653 } 654 } 655 656 /// 657 @safe unittest 658 { 659 import std.algorithm.searching : find; 660 import std.uni : isWhite; 661 string a = " Hello, world!"; 662 assert(find!(not!isWhite)(a) == "Hello, world!"); 663 } 664 665 @safe unittest 666 { 667 assert(not!"a != 5"(5)); 668 assert(not!"a != b"(5, 5)); 669 670 assert(not!(() => false)()); 671 assert(not!(a => a != 5)(5)); 672 assert(not!((a, b) => a != b)(5, 5)); 673 assert(not!((a, b, c) => a * b * c != 125 )(5, 5, 5)); 674 } 675 676 /** 677 $(LINK2 http://en.wikipedia.org/wiki/Partial_application, Partially 678 applies) $(D_PARAM fun) by tying its first argument to $(D_PARAM arg). 679 680 Params: 681 fun = A callable 682 arg = The first argument to apply to `fun` 683 Returns: 684 A new function which calls `fun` with `arg` plus the passed parameters. 685 */ 686 template partial(alias fun, alias arg) 687 { 688 import std.traits : isCallable; 689 // Check whether fun is a user defined type which implements opCall or a template. 690 // As opCall itself can be templated, std.traits.isCallable does not work here. 691 enum isSomeFunctor = (is(typeof(fun) == struct) || is(typeof(fun) == class)) && __traits(hasMember, fun, "opCall"); 692 static if (isSomeFunctor || __traits(isTemplate, fun)) 693 { 694 auto partial(Ts...)(Ts args2) 695 { 696 static if (is(typeof(fun(arg, args2)))) 697 { 698 return fun(arg, args2); 699 } 700 else 701 { 702 static string errormsg() 703 { 704 string msg = "Cannot call '" ~ fun.stringof ~ "' with arguments " ~ 705 "(" ~ arg.stringof; 706 foreach (T; Ts) 707 msg ~= ", " ~ T.stringof; 708 msg ~= ")."; 709 return msg; 710 } 711 static assert(0, errormsg()); 712 } 713 } 714 } 715 else static if (!isCallable!fun) 716 { 717 static assert(false, "Cannot apply partial to a non-callable '" ~ fun.stringof ~ "'."); 718 } 719 else 720 { 721 import std.meta : Filter; 722 723 static if (__traits(compiles, __traits(getOverloads, 724 __traits(parent, fun), __traits(identifier, fun)))) 725 alias overloads = __traits(getOverloads, __traits(parent, fun), 726 __traits(identifier, fun)); 727 else 728 alias overloads = AliasSeq!(fun); 729 730 enum isCallableWithArg(alias fun) = Parameters!fun.length > 0 && 731 is(typeof(arg) : Parameters!fun[0]); 732 alias candidates = Filter!(isCallableWithArg, overloads); 733 734 static if (overloads.length == 1 && Parameters!fun.length == 0) 735 { 736 static assert(0, "Cannot partially apply '" ~ fun.stringof ~ "'." ~ 737 "'" ~ fun.stringof ~ "' has 0 arguments."); 738 } 739 else static if (candidates.length == 0) 740 { 741 import std.meta : NoDuplicates, staticMap; 742 743 enum hasParameters(alias fun) = Parameters!fun.length > 0; 744 alias firstParameter(alias fun) = Parameters!fun[0]; 745 alias firstParameters = NoDuplicates!( 746 staticMap!(firstParameter, Filter!(hasParameters, overloads))); 747 748 string errorMsg() 749 { 750 string msg = "Argument mismatch for '" ~ fun.stringof ~ 751 "': expected " ~ firstParameters[0].stringof; 752 static foreach (firstParam; firstParameters[1 .. $]) 753 msg ~= " or " ~ firstParam.stringof; 754 msg ~= ", but got " ~ typeof(arg).stringof ~ "."; 755 756 return msg; 757 } 758 static assert(0, errorMsg()); 759 } 760 else 761 { 762 import std.traits : ReturnType; 763 static foreach (candidate; candidates) 764 ReturnType!candidate partial(Parameters!candidate[1..$] args2) 765 { 766 return candidate(arg, args2); 767 } 768 } 769 } 770 } 771 772 /// 773 @safe unittest 774 { 775 int fun(int a, int b) { return a + b; } 776 alias fun5 = partial!(fun, 5); 777 assert(fun5(6) == 11); 778 // Note that in most cases you'd use an alias instead of a value 779 // assignment. Using an alias allows you to partially evaluate template 780 // functions without committing to a particular type of the function. 781 } 782 783 // https://issues.dlang.org/show_bug.cgi?id=21457 784 /// 785 @safe unittest 786 { 787 // Overloads are resolved when the partially applied function is called 788 // with the remaining arguments. 789 struct S 790 { 791 static char fun(int i, string s) { return s[i]; } 792 static int fun(int a, int b) { return a * b; } 793 } 794 alias fun3 = partial!(S.fun, 3); 795 assert(fun3("hello") == 'l'); 796 assert(fun3(10) == 30); 797 } 798 799 // tests for partially evaluating callables 800 @safe unittest 801 { 802 static int f1(int a, int b) { return a + b; } 803 assert(partial!(f1, 5)(6) == 11); 804 805 int f2(int a, int b) { return a + b; } 806 int x = 5; 807 assert(partial!(f2, x)(6) == 11); 808 x = 7; 809 assert(partial!(f2, x)(6) == 13); 810 static assert(partial!(f2, 5)(6) == 11); 811 812 auto dg = &f2; 813 auto f3 = &partial!(dg, x); 814 assert(f3(6) == 13); 815 816 static int funOneArg(int a) { return a; } 817 assert(partial!(funOneArg, 1)() == 1); 818 819 static int funThreeArgs(int a, int b, int c) { return a + b + c; } 820 alias funThreeArgs1 = partial!(funThreeArgs, 1); 821 assert(funThreeArgs1(2, 3) == 6); 822 static assert(!is(typeof(funThreeArgs1(2)))); 823 824 enum xe = 5; 825 alias fe = partial!(f2, xe); 826 static assert(fe(6) == 11); 827 } 828 829 // tests for partially evaluating templated/overloaded callables 830 @safe unittest 831 { 832 static auto add(A, B)(A x, B y) 833 { 834 return x + y; 835 } 836 837 alias add5 = partial!(add, 5); 838 assert(add5(6) == 11); 839 static assert(!is(typeof(add5()))); 840 static assert(!is(typeof(add5(6, 7)))); 841 842 // taking address of templated partial evaluation needs explicit type 843 auto dg = &add5!(int); 844 assert(dg(6) == 11); 845 846 int x = 5; 847 alias addX = partial!(add, x); 848 assert(addX(6) == 11); 849 850 static struct Callable 851 { 852 static string opCall(string a, string b) { return a ~ b; } 853 int opCall(int a, int b) { return a * b; } 854 double opCall(double a, double b) { return a + b; } 855 } 856 Callable callable; 857 assert(partial!(Callable, "5")("6") == "56"); 858 assert(partial!(callable, 5)(6) == 30); 859 assert(partial!(callable, 7.0)(3.0) == 7.0 + 3.0); 860 861 static struct TCallable 862 { 863 auto opCall(A, B)(A a, B b) 864 { 865 return a + b; 866 } 867 } 868 TCallable tcallable; 869 assert(partial!(tcallable, 5)(6) == 11); 870 static assert(!is(typeof(partial!(tcallable, "5")(6)))); 871 872 static struct NonCallable{} 873 static assert(!__traits(compiles, partial!(NonCallable, 5)), "Partial should not work on non-callable structs."); 874 static assert(!__traits(compiles, partial!(NonCallable.init, 5)), 875 "Partial should not work on instances of non-callable structs."); 876 877 static A funOneArg(A)(A a) { return a; } 878 alias funOneArg1 = partial!(funOneArg, 1); 879 assert(funOneArg1() == 1); 880 881 static auto funThreeArgs(A, B, C)(A a, B b, C c) { return a + b + c; } 882 alias funThreeArgs1 = partial!(funThreeArgs, 1); 883 assert(funThreeArgs1(2, 3) == 6); 884 static assert(!is(typeof(funThreeArgs1(1)))); 885 886 auto dg2 = &funOneArg1!(); 887 assert(dg2() == 1); 888 } 889 890 // Fix https://issues.dlang.org/show_bug.cgi?id=15732 891 @safe unittest 892 { 893 // Test whether it works with functions. 894 auto partialFunction(){ 895 auto fullFunction = (float a, float b, float c) => a + b / c; 896 alias apply1 = partial!(fullFunction, 1); 897 return &apply1; 898 } 899 auto result = partialFunction()(2, 4); 900 assert(result == 1.5f); 901 902 // And with delegates. 903 auto partialDelegate(float c){ 904 auto fullDelegate = (float a, float b) => a + b / c; 905 alias apply1 = partial!(fullDelegate, 1); 906 return &apply1; 907 } 908 auto result2 = partialDelegate(4)(2); 909 assert(result2 == 1.5f); 910 } 911 912 /** 913 Takes a function of (potentially) many arguments, and returns a function taking 914 one argument and returns a callable taking the rest. f(x, y) == curry(f)(x)(y) 915 916 Params: 917 F = a function taking at least one argument 918 t = a callable object whose opCall takes at least 1 object 919 Returns: 920 A single parameter callable object 921 */ 922 template curry(alias F) 923 if (isCallable!F && Parameters!F.length) 924 { 925 //inspired from the implementation from Artur Skawina here: 926 //https://forum.dlang.org/post/mailman.1626.1340110492.24740.digitalmars-d@puremagic.com 927 //This implementation stores a copy of all filled in arguments with each curried result 928 //this way, the curried functions are independent and don't share any references 929 //eg: auto fc = curry!f; auto fc1 = fc(1); auto fc2 = fc(2); fc1(3) != fc2(3) 930 struct CurryImpl(size_t N) 931 { 932 alias FParams = Parameters!F; 933 FParams[0 .. N] storedArguments; 934 static if (N > 0) 935 { 936 this(U : FParams[N - 1])(ref CurryImpl!(N - 1) prev, ref U arg) 937 { 938 storedArguments[0 .. N - 1] = prev.storedArguments[]; 939 storedArguments[N-1] = arg; 940 } 941 } 942 943 auto opCall(U : FParams[N])(auto ref U arg) return scope 944 { 945 static if (N == FParams.length - 1) 946 { 947 return F(storedArguments, arg); 948 } 949 else 950 { 951 return CurryImpl!(N + 1)(this, arg); 952 } 953 } 954 } 955 956 auto curry() 957 { 958 CurryImpl!0 res; 959 return res; // return CurryImpl!0.init segfaults for delegates on Windows 960 } 961 } 962 963 /// 964 pure @safe @nogc nothrow unittest 965 { 966 int f(int x, int y, int z) 967 { 968 return x + y + z; 969 } 970 auto cf = curry!f; 971 auto cf1 = cf(1); 972 auto cf2 = cf(2); 973 974 assert(cf1(2)(3) == f(1, 2, 3)); 975 assert(cf2(2)(3) == f(2, 2, 3)); 976 } 977 978 ///ditto 979 auto curry(T)(T t) 980 if (isCallable!T && Parameters!T.length) 981 { 982 static auto fun(ref T inst, ref Parameters!T args) 983 { 984 return inst(args); 985 } 986 987 return curry!fun()(t); 988 } 989 990 /// 991 pure @safe @nogc nothrow unittest 992 { 993 //works with callable structs too 994 struct S 995 { 996 int w; 997 int opCall(int x, int y, int z) 998 { 999 return w + x + y + z; 1000 } 1001 } 1002 1003 S s; 1004 s.w = 5; 1005 1006 auto cs = curry(s); 1007 auto cs1 = cs(1); 1008 auto cs2 = cs(2); 1009 1010 assert(cs1(2)(3) == s(1, 2, 3)); 1011 assert(cs1(2)(3) == (1 + 2 + 3 + 5)); 1012 assert(cs2(2)(3) ==s(2, 2, 3)); 1013 } 1014 1015 1016 @safe pure @nogc nothrow unittest 1017 { 1018 //currying a single argument function does nothing 1019 int pork(int a){ return a*2;} 1020 auto curryPork = curry!pork; 1021 assert(curryPork(0) == pork(0)); 1022 assert(curryPork(1) == pork(1)); 1023 assert(curryPork(-1) == pork(-1)); 1024 assert(curryPork(1000) == pork(1000)); 1025 1026 //test 2 argument function 1027 double mixedVeggies(double a, int b, bool) 1028 { 1029 return a + b; 1030 } 1031 1032 auto mixedCurry = curry!mixedVeggies; 1033 assert(mixedCurry(10)(20)(false) == mixedVeggies(10, 20, false)); 1034 assert(mixedCurry(100)(200)(true) == mixedVeggies(100, 200, true)); 1035 1036 // struct with opCall 1037 struct S 1038 { 1039 double opCall(int x, double y, short z) const pure nothrow @nogc 1040 { 1041 return x*y*z; 1042 } 1043 } 1044 1045 S s; 1046 auto curriedStruct = curry(s); 1047 assert(curriedStruct(1)(2)(short(3)) == s(1, 2, short(3))); 1048 assert(curriedStruct(300)(20)(short(10)) == s(300, 20, short(10))); 1049 } 1050 1051 pure @safe nothrow unittest 1052 { 1053 auto cfl = curry!((double a, int b) => a + b); 1054 assert(cfl(13)(2) == 15); 1055 1056 int c = 42; 1057 auto cdg = curry!((double a, int b) => a + b + c); 1058 assert(cdg(13)(2) == 57); 1059 1060 static class C 1061 { 1062 int opCall(int mult, int add) pure @safe nothrow @nogc scope 1063 { 1064 return mult * 42 + add; 1065 } 1066 } 1067 1068 scope C ci = new C(); 1069 scope cc = curry(ci); 1070 assert(cc(2)(4) == ci(2, 4)); 1071 } 1072 1073 // Disallows callables without parameters 1074 pure @safe @nogc nothrow unittest 1075 { 1076 static void noargs() {} 1077 static assert(!__traits(compiles, curry!noargs())); 1078 1079 static struct NoArgs 1080 { 1081 void opCall() {} 1082 } 1083 1084 static assert(!__traits(compiles, curry(NoArgs.init))); 1085 } 1086 1087 private template Iota(size_t n) 1088 { 1089 static if (n == 0) 1090 alias Iota = AliasSeq!(); 1091 else 1092 alias Iota = AliasSeq!(Iota!(n - 1), n - 1); 1093 } 1094 1095 /** 1096 Takes multiple functions and adjoins them together. 1097 1098 Params: 1099 F = the call-able(s) to adjoin 1100 Returns: 1101 A new function which returns a $(REF Tuple, std,typecons). Each of the 1102 elements of the tuple will be the return values of `F`. 1103 1104 Note: In the special case where only a single function is provided 1105 ($(D F.length == 1)), adjoin simply aliases to the single passed function 1106 (`F[0]`). 1107 */ 1108 template adjoin(F...) 1109 if (F.length >= 1) 1110 { 1111 static if (F.length == 1) 1112 alias adjoin = F[0]; 1113 else 1114 auto adjoin(V...)(auto ref V a) 1115 { 1116 import std.typecons : tuple; 1117 import std.meta : staticMap; 1118 1119 auto resultElement(size_t i)() 1120 { 1121 return F[i](a); 1122 } 1123 1124 return tuple(staticMap!(resultElement, Iota!(F.length))); 1125 } 1126 } 1127 1128 /// 1129 @safe unittest 1130 { 1131 import std.typecons : Tuple; 1132 static bool f1(int a) { return a != 0; } 1133 static int f2(int a) { return a / 2; } 1134 auto x = adjoin!(f1, f2)(5); 1135 assert(is(typeof(x) == Tuple!(bool, int))); 1136 assert(x[0] == true && x[1] == 2); 1137 } 1138 1139 @safe unittest 1140 { 1141 import std.typecons : Tuple; 1142 static bool F1(int a) { return a != 0; } 1143 auto x1 = adjoin!(F1)(5); 1144 static int F2(int a) { return a / 2; } 1145 auto x2 = adjoin!(F1, F2)(5); 1146 assert(is(typeof(x2) == Tuple!(bool, int))); 1147 assert(x2[0] && x2[1] == 2); 1148 auto x3 = adjoin!(F1, F2, F2)(5); 1149 assert(is(typeof(x3) == Tuple!(bool, int, int))); 1150 assert(x3[0] && x3[1] == 2 && x3[2] == 2); 1151 1152 bool F4(int a) { return a != x1; } 1153 alias eff4 = adjoin!(F4); 1154 static struct S 1155 { 1156 bool delegate(int) @safe store; 1157 int fun() { return 42 + store(5); } 1158 } 1159 S s; 1160 s.store = (int a) { return eff4(a); }; 1161 auto x4 = s.fun(); 1162 assert(x4 == 43); 1163 } 1164 1165 @safe unittest 1166 { 1167 import std.meta : staticMap; 1168 import std.typecons : Tuple, tuple; 1169 alias funs = staticMap!(unaryFun, "a", "a * 2", "a * 3", "a * a", "-a"); 1170 alias afun = adjoin!funs; 1171 assert(afun(5) == tuple(5, 10, 15, 25, -5)); 1172 1173 static class C{} 1174 alias IC = immutable(C); 1175 IC foo(){return typeof(return).init;} 1176 Tuple!(IC, IC, IC, IC) ret1 = adjoin!(foo, foo, foo, foo)(); 1177 1178 static struct S{int* p;} 1179 alias IS = immutable(S); 1180 IS bar(){return typeof(return).init;} 1181 enum Tuple!(IS, IS, IS, IS) ret2 = adjoin!(bar, bar, bar, bar)(); 1182 } 1183 1184 // https://issues.dlang.org/show_bug.cgi?id=21347 1185 @safe @betterC unittest 1186 { 1187 alias f = (int n) => n + 1; 1188 alias g = (int n) => n + 2; 1189 alias h = (int n) => n + 3; 1190 alias i = (int n) => n + 4; 1191 1192 auto result = adjoin!(f, g, h, i)(0); 1193 1194 assert(result[0] == 1); 1195 assert(result[1] == 2); 1196 assert(result[2] == 3); 1197 assert(result[3] == 4); 1198 } 1199 1200 /** 1201 Composes passed-in functions $(D fun[0], fun[1], ...). 1202 1203 Params: 1204 fun = the call-able(s) or `string`(s) to compose into one function 1205 Returns: 1206 A new function `f(x)` that in turn returns `fun[0](fun[1](...(x)))...`. 1207 1208 See_Also: $(LREF pipe) 1209 */ 1210 template compose(fun...) 1211 if (fun.length > 0) 1212 { 1213 static if (fun.length == 1) 1214 { 1215 alias compose = unaryFun!(fun[0]); 1216 } 1217 else 1218 { 1219 alias fun0 = unaryFun!(fun[0]); 1220 alias rest = compose!(fun[1 .. $]); 1221 1222 auto compose(Args...)(Args args) 1223 { 1224 return fun0(rest(args)); 1225 } 1226 } 1227 } 1228 1229 /// 1230 @safe unittest 1231 { 1232 import std.algorithm.comparison : equal; 1233 import std.algorithm.iteration : map; 1234 import std.array : split; 1235 import std.conv : to; 1236 1237 // First split a string in whitespace-separated tokens and then 1238 // convert each token into an integer 1239 assert(compose!(map!(to!(int)), split)("1 2 3").equal([1, 2, 3])); 1240 } 1241 1242 // https://issues.dlang.org/show_bug.cgi?id=6484 1243 @safe unittest 1244 { 1245 int f(int a) { return a; } 1246 int g(int a) { return a; } 1247 int h(int a,int b,int c) { return a * b * c; } 1248 1249 alias F = compose!(f,g,h); 1250 assert(F(1,2,3) == f(g(h(1,2,3)))); 1251 } 1252 1253 /** 1254 Pipes functions in sequence. Offers the same functionality as $(D 1255 compose), but with functions specified in reverse order. This may 1256 lead to more readable code in some situation because the order of 1257 execution is the same as lexical order. 1258 1259 Params: 1260 fun = the call-able(s) or `string`(s) to compose into one function 1261 Returns: 1262 A new function `f(x)` that in turn returns `fun[$-1](...fun[1](fun[0](x)))...`. 1263 1264 Example: 1265 1266 ---- 1267 // Read an entire text file, split the resulting string in 1268 // whitespace-separated tokens, and then convert each token into an 1269 // integer 1270 int[] a = pipe!(readText, split, map!(to!(int)))("file.txt"); 1271 ---- 1272 1273 See_Also: $(LREF compose) 1274 */ 1275 alias pipe(fun...) = compose!(Reverse!(fun)); 1276 1277 /// 1278 @safe unittest 1279 { 1280 import std.conv : to; 1281 string foo(int a) { return to!(string)(a); } 1282 int bar(string a) { return to!(int)(a) + 1; } 1283 double baz(int a) { return a + 0.5; } 1284 assert(compose!(baz, bar, foo)(1) == 2.5); 1285 assert(pipe!(foo, bar, baz)(1) == 2.5); 1286 1287 assert(compose!(baz, `to!(int)(a) + 1`, foo)(1) == 2.5); 1288 assert(compose!(baz, bar)("1"[]) == 2.5); 1289 1290 assert(compose!(baz, bar)("1") == 2.5); 1291 1292 assert(compose!(`a + 0.5`, `to!(int)(a) + 1`, foo)(1) == 2.5); 1293 } 1294 1295 private template getOverloads(alias fun) 1296 { 1297 import std.meta : AliasSeq; 1298 static if (__traits(compiles, __traits(getOverloads, __traits(parent, fun), __traits(identifier, fun), true))) 1299 alias getOverloads = __traits(getOverloads, __traits(parent, fun), __traits(identifier, fun), true); 1300 else 1301 alias getOverloads = AliasSeq!fun; 1302 } 1303 1304 /** 1305 * $(LINK2 https://en.wikipedia.org/wiki/Memoization, Memoizes) a function so as 1306 * to avoid repeated computation. The memoization structure is a hash table keyed by a 1307 * tuple of the function's arguments. There is a speed gain if the 1308 * function is repeatedly called with the same arguments and is more 1309 * expensive than a hash table lookup. For more information on memoization, refer to $(HTTP docs.google.com/viewer?url=http%3A%2F%2Fhop.perl.plover.com%2Fbook%2Fpdf%2F03CachingAndMemoization.pdf, this book chapter). 1310 1311 Example: 1312 ---- 1313 double transmogrify(int a, string b) 1314 { 1315 ... expensive computation ... 1316 } 1317 alias fastTransmogrify = memoize!transmogrify; 1318 unittest 1319 { 1320 auto slow = transmogrify(2, "hello"); 1321 auto fast = fastTransmogrify(2, "hello"); 1322 assert(slow == fast); 1323 } 1324 ---- 1325 1326 Params: 1327 fun = the call-able to memozie 1328 maxSize = The maximum size of the GC buffer to hold the return values 1329 Returns: 1330 A new function which calls `fun` and caches its return values. 1331 1332 Note: 1333 Technically the memoized function should be pure because `memoize` assumes it will 1334 always return the same result for a given tuple of arguments. However, `memoize` does not 1335 enforce that because sometimes it is useful to memoize an impure function, too. 1336 */ 1337 template memoize(alias fun) 1338 { 1339 import std.traits : Parameters; 1340 import std.meta : anySatisfy; 1341 1342 // Specific overloads: 1343 alias overloads = getOverloads!fun; 1344 static foreach (fn; overloads) 1345 static if (is(Parameters!fn)) 1346 alias memoize = impl!(Parameters!fn); 1347 1348 enum isTemplate(alias a) = __traits(isTemplate, a); 1349 static if (anySatisfy!(isTemplate, overloads)) 1350 { 1351 // Generic implementation 1352 alias memoize = impl; 1353 } 1354 1355 auto impl(Args...)(Args args) 1356 if (is(typeof(fun(args)))) 1357 { 1358 import std.typecons : Tuple, tuple; 1359 import std.traits : Unqual; 1360 1361 static if (args.length > 0) 1362 { 1363 static Unqual!(typeof(fun(args)))[Tuple!(typeof(args))] memo; 1364 1365 auto t = Tuple!Args(args); 1366 if (auto p = t in memo) 1367 return *p; 1368 auto r = fun(args); 1369 memo[t] = r; 1370 return r; 1371 } 1372 else 1373 { 1374 static typeof(fun(args)) result; 1375 result = fun(args); 1376 return result; 1377 } 1378 } 1379 } 1380 1381 /// ditto 1382 template memoize(alias fun, uint maxSize) 1383 { 1384 import std.traits : Parameters; 1385 import std.meta : anySatisfy; 1386 1387 // Specific overloads: 1388 alias overloads = getOverloads!fun; 1389 static foreach (fn; overloads) 1390 static if (is(Parameters!fn)) 1391 alias memoize = impl!(Parameters!fn); 1392 1393 enum isTemplate(alias a) = __traits(isTemplate, a); 1394 static if (anySatisfy!(isTemplate, overloads)) 1395 { 1396 // Generic implementation 1397 alias memoize = impl; 1398 } 1399 1400 auto impl(Args...)(Args args) 1401 if (is(typeof(fun(args)))) 1402 { 1403 static if (args.length > 0) 1404 { 1405 import std.meta : staticMap; 1406 import std.traits : hasIndirections, Unqual; 1407 import std.typecons : tuple; 1408 alias returnType = typeof(fun(args)); 1409 static struct Value { staticMap!(Unqual, Args) args; Unqual!returnType res; } 1410 static Value[] memo; 1411 static size_t[] initialized; 1412 1413 if (!memo.length) 1414 { 1415 import core.memory : GC; 1416 1417 // Ensure no allocation overflows 1418 static assert(maxSize < size_t.max / Value.sizeof); 1419 static assert(maxSize < size_t.max - (8 * size_t.sizeof - 1)); 1420 1421 enum attr = GC.BlkAttr.NO_INTERIOR | (hasIndirections!Value ? 0 : GC.BlkAttr.NO_SCAN); 1422 memo = (cast(Value*) GC.malloc(Value.sizeof * maxSize, attr))[0 .. maxSize]; 1423 enum nwords = (maxSize + 8 * size_t.sizeof - 1) / (8 * size_t.sizeof); 1424 initialized = (cast(size_t*) GC.calloc(nwords * size_t.sizeof, attr | GC.BlkAttr.NO_SCAN))[0 .. nwords]; 1425 } 1426 1427 import core.bitop : bt, bts; 1428 import core.lifetime : emplace; 1429 1430 size_t hash; 1431 foreach (ref arg; args) 1432 hash = hashOf(arg, hash); 1433 // cuckoo hashing 1434 immutable idx1 = hash % maxSize; 1435 if (!bt(initialized.ptr, idx1)) 1436 { 1437 emplace(&memo[idx1], args, fun(args)); 1438 // only set to initialized after setting args and value 1439 // https://issues.dlang.org/show_bug.cgi?id=14025 1440 bts(initialized.ptr, idx1); 1441 return memo[idx1].res; 1442 } 1443 else if (memo[idx1].args == args) 1444 return memo[idx1].res; 1445 // FNV prime 1446 immutable idx2 = (hash * 16_777_619) % maxSize; 1447 if (!bt(initialized.ptr, idx2)) 1448 { 1449 emplace(&memo[idx2], memo[idx1]); 1450 bts(initialized.ptr, idx2); 1451 } 1452 else if (memo[idx2].args == args) 1453 return memo[idx2].res; 1454 else if (idx1 != idx2) 1455 memo[idx2] = memo[idx1]; 1456 1457 memo[idx1] = Value(args, fun(args)); 1458 return memo[idx1].res; 1459 } 1460 else 1461 { 1462 static typeof(fun(args)) result; 1463 result = fun(args); 1464 return result; 1465 } 1466 } 1467 } 1468 1469 /** 1470 * To _memoize a recursive function, simply insert the memoized call in lieu of the plain recursive call. 1471 * For example, to transform the exponential-time Fibonacci implementation into a linear-time computation: 1472 */ 1473 @safe nothrow 1474 unittest 1475 { 1476 ulong fib(ulong n) @safe nothrow 1477 { 1478 return n < 2 ? n : memoize!fib(n - 2) + memoize!fib(n - 1); 1479 } 1480 assert(fib(10) == 55); 1481 } 1482 1483 /** 1484 * To improve the speed of the factorial function, 1485 */ 1486 @safe unittest 1487 { 1488 ulong fact(ulong n) @safe 1489 { 1490 return n < 2 ? 1 : n * memoize!fact(n - 1); 1491 } 1492 assert(fact(10) == 3628800); 1493 } 1494 1495 /** 1496 * This memoizes all values of `fact` up to the largest argument. To only cache the final 1497 * result, move `memoize` outside the function as shown below. 1498 */ 1499 @safe unittest 1500 { 1501 ulong factImpl(ulong n) @safe 1502 { 1503 return n < 2 ? 1 : n * factImpl(n - 1); 1504 } 1505 alias fact = memoize!factImpl; 1506 assert(fact(10) == 3628800); 1507 } 1508 1509 /** 1510 * When the `maxSize` parameter is specified, memoize will used 1511 * a fixed size hash table to limit the number of cached entries. 1512 */ 1513 @system unittest // not @safe due to memoize 1514 { 1515 ulong fact(ulong n) 1516 { 1517 // Memoize no more than 8 values 1518 return n < 2 ? 1 : n * memoize!(fact, 8)(n - 1); 1519 } 1520 assert(fact(8) == 40320); 1521 // using more entries than maxSize will overwrite existing entries 1522 assert(fact(10) == 3628800); 1523 } 1524 1525 // Issue 20099 1526 @system unittest // not @safe due to memoize 1527 { 1528 int i = 3; 1529 alias a = memoize!((n) => i + n); 1530 alias b = memoize!((n) => i + n, 3); 1531 1532 assert(a(3) == 6); 1533 assert(b(3) == 6); 1534 } 1535 1536 @system unittest // not @safe due to memoize 1537 { 1538 static Object objNum(int a) { return new Object(); } 1539 assert(memoize!objNum(0) is memoize!objNum(0U)); 1540 assert(memoize!(objNum, 3)(0) is memoize!(objNum, 3)(0U)); 1541 } 1542 1543 @system unittest // not @safe due to memoize 1544 { 1545 struct S 1546 { 1547 static int fun() { return 0; } 1548 static int fun(int i) { return 1; } 1549 } 1550 assert(memoize!(S.fun)() == 0); 1551 assert(memoize!(S.fun)(3) == 1); 1552 assert(memoize!(S.fun, 3)() == 0); 1553 assert(memoize!(S.fun, 3)(3) == 1); 1554 } 1555 1556 @system unittest // not @safe due to memoize 1557 { 1558 import core.math : sqrt; 1559 alias msqrt = memoize!(function double(double x) { return sqrt(x); }); 1560 auto y = msqrt(2.0); 1561 assert(y == msqrt(2.0)); 1562 y = msqrt(4.0); 1563 assert(y == sqrt(4.0)); 1564 1565 // alias mrgb2cmyk = memoize!rgb2cmyk; 1566 // auto z = mrgb2cmyk([43, 56, 76]); 1567 // assert(z == mrgb2cmyk([43, 56, 76])); 1568 1569 //alias mfib = memoize!fib; 1570 1571 static ulong fib(ulong n) @safe 1572 { 1573 alias mfib = memoize!fib; 1574 return n < 2 ? 1 : mfib(n - 2) + mfib(n - 1); 1575 } 1576 1577 auto z = fib(10); 1578 assert(z == 89); 1579 1580 static ulong fact(ulong n) @safe 1581 { 1582 alias mfact = memoize!fact; 1583 return n < 2 ? 1 : n * mfact(n - 1); 1584 } 1585 assert(fact(10) == 3628800); 1586 1587 // https://issues.dlang.org/show_bug.cgi?id=12568 1588 static uint len2(const string s) { // Error 1589 alias mLen2 = memoize!len2; 1590 if (s.length == 0) 1591 return 0; 1592 else 1593 return 1 + mLen2(s[1 .. $]); 1594 } 1595 1596 int _func(int x) @safe { return 1; } 1597 alias func = memoize!(_func, 10); 1598 assert(func(int.init) == 1); 1599 assert(func(int.init) == 1); 1600 } 1601 1602 // https://issues.dlang.org/show_bug.cgi?id=16079 1603 // memoize should work with arrays 1604 @system unittest // not @safe with -dip1000 due to memoize 1605 { 1606 int executed = 0; 1607 T median(T)(const T[] nums) { 1608 import std.algorithm.sorting : sort; 1609 executed++; 1610 auto arr = nums.dup; 1611 arr.sort(); 1612 if (arr.length % 2) 1613 return arr[$ / 2]; 1614 else 1615 return (arr[$ / 2 - 1] 1616 + arr[$ / 2]) / 2; 1617 } 1618 1619 alias fastMedian = memoize!(median!int); 1620 1621 assert(fastMedian([7, 5, 3]) == 5); 1622 assert(fastMedian([7, 5, 3]) == 5); 1623 1624 assert(executed == 1); 1625 } 1626 1627 // https://issues.dlang.org/show_bug.cgi?id=16079: memoize should work with structs 1628 @safe unittest 1629 { 1630 int executed = 0; 1631 T pickFirst(T)(T first) 1632 { 1633 executed++; 1634 return first; 1635 } 1636 1637 struct Foo { int k; } 1638 Foo A = Foo(3); 1639 1640 alias first = memoize!(pickFirst!Foo); 1641 assert(first(Foo(3)) == A); 1642 assert(first(Foo(3)) == A); 1643 assert(executed == 1); 1644 } 1645 1646 // https://issues.dlang.org/show_bug.cgi?id=20439 memoize should work with void opAssign 1647 @safe unittest 1648 { 1649 static struct S 1650 { 1651 void opAssign(S) {} 1652 } 1653 1654 assert(memoize!(() => S()) == S()); 1655 } 1656 1657 // https://issues.dlang.org/show_bug.cgi?id=16079: memoize should work with classes 1658 @system unittest // not @safe with -dip1000 due to memoize 1659 { 1660 int executed = 0; 1661 T pickFirst(T)(T first) 1662 { 1663 executed++; 1664 return first; 1665 } 1666 1667 class Bar 1668 { 1669 size_t k; 1670 this(size_t k) 1671 { 1672 this.k = k; 1673 } 1674 override size_t toHash() 1675 { 1676 return k; 1677 } 1678 override bool opEquals(Object o) 1679 { 1680 auto b = cast(Bar) o; 1681 return b && k == b.k; 1682 } 1683 } 1684 1685 alias firstClass = memoize!(pickFirst!Bar); 1686 assert(firstClass(new Bar(3)).k == 3); 1687 assert(firstClass(new Bar(3)).k == 3); 1688 assert(executed == 1); 1689 } 1690 1691 // https://issues.dlang.org/show_bug.cgi?id=20302 1692 @system unittest 1693 { 1694 version (none) // TODO change `none` to `all` and fix remaining limitations 1695 struct S { const int len; } 1696 else 1697 struct S { int len; } 1698 1699 static string fun000( string str, S s) { return str[0 .. s.len] ~ "123"; } 1700 static string fun001( string str, const S s) { return str[0 .. s.len] ~ "123"; } 1701 static string fun010(const string str, S s) { return str[0 .. s.len] ~ "123"; } 1702 static string fun011(const string str, const S s) { return str[0 .. s.len] ~ "123"; } 1703 static const(string) fun100( string str, S s) { return str[0 .. s.len] ~ "123"; } 1704 static const(string) fun101( string str, const S s) { return str[0 .. s.len] ~ "123"; } 1705 static const(string) fun110(const string str, S s) { return str[0 .. s.len] ~ "123"; } 1706 static const(string) fun111(const string str, const S s) { return str[0 .. s.len] ~ "123"; } 1707 1708 static foreach (fun; AliasSeq!(fun000, fun001, fun010, fun011, fun100, fun101, fun110, fun111)) 1709 {{ 1710 alias mfun = memoize!fun; 1711 assert(mfun("abcdefgh", S(3)) == "abc123"); 1712 1713 alias mfun2 = memoize!(fun, 42); 1714 assert(mfun2("asd", S(3)) == "asd123"); 1715 }} 1716 } 1717 1718 // memoize should continue to work with functions that cannot be evaluated at compile time 1719 @system unittest 1720 { 1721 __gshared string[string] glob; 1722 1723 static bool foo() 1724 { 1725 return (":-)" in glob) is null; 1726 } 1727 1728 assert(memoize!foo); 1729 } 1730 1731 private struct DelegateFaker(F) 1732 { 1733 import std.typecons : FuncInfo, MemberFunctionGenerator; 1734 1735 // for @safe 1736 static F castToF(THIS)(THIS x) @trusted 1737 { 1738 return cast(F) x; 1739 } 1740 1741 /* 1742 * What all the stuff below does is this: 1743 *-------------------- 1744 * struct DelegateFaker(F) { 1745 * extern(linkage) 1746 * [ref] ReturnType!F doIt(Parameters!F args) [@attributes] 1747 * { 1748 * auto fp = cast(F) &this; 1749 * return fp(args); 1750 * } 1751 * } 1752 *-------------------- 1753 */ 1754 1755 // We will use MemberFunctionGenerator in std.typecons. This is a policy 1756 // configuration for generating the doIt(). 1757 template GeneratingPolicy() 1758 { 1759 // Inform the genereator that we only have type information. 1760 enum WITHOUT_SYMBOL = true; 1761 1762 // Generate the function body of doIt(). 1763 template generateFunctionBody(unused...) 1764 { 1765 enum generateFunctionBody = 1766 // [ref] ReturnType doIt(Parameters args) @attributes 1767 q{ 1768 // When this function gets called, the this pointer isn't 1769 // really a this pointer (no instance even really exists), but 1770 // a function pointer that points to the function to be called. 1771 // Cast it to the correct type and call it. 1772 1773 auto fp = castToF(&this); 1774 return fp(args); 1775 }; 1776 } 1777 } 1778 // Type information used by the generated code. 1779 alias FuncInfo_doIt = FuncInfo!(F); 1780 1781 // Generate the member function doIt(). 1782 mixin( MemberFunctionGenerator!(GeneratingPolicy!()) 1783 .generateFunction!("FuncInfo_doIt", "doIt", F) ); 1784 } 1785 1786 /** 1787 * Convert a callable to a delegate with the same parameter list and 1788 * return type, avoiding heap allocations and use of auxiliary storage. 1789 * 1790 * Params: 1791 * fp = a function pointer or an aggregate type with `opCall` defined. 1792 * Returns: 1793 * A delegate with the context pointer pointing to nothing. 1794 * 1795 * Example: 1796 * ---- 1797 * void doStuff() { 1798 * writeln("Hello, world."); 1799 * } 1800 * 1801 * void runDelegate(void delegate() myDelegate) { 1802 * myDelegate(); 1803 * } 1804 * 1805 * auto delegateToPass = toDelegate(&doStuff); 1806 * runDelegate(delegateToPass); // Calls doStuff, prints "Hello, world." 1807 * ---- 1808 * 1809 * BUGS: 1810 * $(UL 1811 * $(LI Does not work with `@safe` functions.) 1812 * $(LI Ignores C-style / D-style variadic arguments.) 1813 * ) 1814 */ 1815 auto toDelegate(F)(auto ref F fp) 1816 if (isCallable!(F)) 1817 { 1818 static if (is(F == delegate)) 1819 { 1820 return fp; 1821 } 1822 else static if (is(F Func == Func*) && is(Func == function)) 1823 { 1824 return function(ref F fp) @trusted 1825 { 1826 return buildDelegate(fp); 1827 }(fp); 1828 } 1829 else static if (is(typeof(&F.opCall) == delegate) 1830 || (is(typeof(&F.opCall) V : V*) && is(V == function))) 1831 { 1832 return toDelegate(&fp.opCall); 1833 } 1834 else static if (is(typeof(&fp.opCall!()))) 1835 { 1836 return toDelegate(&fp.opCall!()); 1837 } 1838 else 1839 { 1840 static assert(false, "Unsupported type of callable, please open an issue."); 1841 } 1842 } 1843 1844 /// 1845 @safe unittest 1846 { 1847 static int inc(ref uint num) { 1848 num++; 1849 return 8675309; 1850 } 1851 1852 uint myNum = 0; 1853 auto incMyNumDel = toDelegate(&inc); 1854 auto returnVal = incMyNumDel(myNum); 1855 assert(myNum == 1); 1856 } 1857 1858 private template buildDelegate(F) 1859 { 1860 auto buildDelegate(auto ref F fp) { 1861 alias DelType = typeof(&(new DelegateFaker!(F)).doIt); 1862 1863 static struct DelegateFields { 1864 union { 1865 DelType del; 1866 //pragma(msg, typeof(del)); 1867 1868 struct { 1869 void* contextPtr; 1870 void* funcPtr; 1871 } 1872 } 1873 } 1874 1875 // fp is stored in the returned delegate's context pointer. 1876 // The returned delegate's function pointer points to 1877 // DelegateFaker.doIt. 1878 DelegateFields df; 1879 1880 df.contextPtr = cast(void*) fp; 1881 1882 DelegateFaker!(F) dummy; 1883 auto dummyDel = &dummy.doIt; 1884 df.funcPtr = dummyDel.funcptr; 1885 1886 return df.del; 1887 } 1888 } 1889 1890 @safe unittest 1891 { 1892 static int inc(ref int num) { 1893 num++; 1894 return 8675309; 1895 } 1896 1897 struct S1 1898 { 1899 static int myNum = 0x1337; 1900 static int opCall() { inc(myNum); return myNum; } 1901 } 1902 1903 S1 s1; 1904 auto getvals1 = toDelegate(s1); 1905 static assert(!is(typeof(&s1.opCall) == delegate)); 1906 static assert( is(typeof(toDelegate(s1)) == delegate)); 1907 assert(getvals1() == 0x1338); 1908 } 1909 1910 @system unittest 1911 { 1912 static int inc(ref uint num) { 1913 num++; 1914 return 8675309; 1915 } 1916 1917 uint myNum = 0; 1918 auto incMyNumDel = toDelegate(&inc); 1919 int delegate(ref uint) dg = incMyNumDel; 1920 auto returnVal = incMyNumDel(myNum); 1921 assert(myNum == 1); 1922 1923 interface I { int opCall(); } 1924 class C: I { int opCall() { inc(myNum); return myNum;} } 1925 auto c = new C; 1926 auto i = cast(I) c; 1927 1928 auto getvalc = toDelegate(c); 1929 assert(getvalc() == 2); 1930 1931 auto getvali = toDelegate(i); 1932 assert(getvali() == 3); 1933 1934 struct S1 { int opCall() { inc(myNum); return myNum; } } 1935 S1 s1; 1936 auto getvals1 = toDelegate(s1); 1937 static assert(is(typeof(&s1.opCall) == delegate)); 1938 static assert(is(typeof(getvals1) == delegate)); 1939 assert(&s1.opCall is getvals1); 1940 assert(getvals1() == 4); 1941 1942 struct S2 { static int opCall() { return 123456; } } 1943 S2 s2; 1944 auto getvals2 = toDelegate(s2); 1945 static assert(!is(typeof(&S2.opCall) == delegate)); 1946 static assert( is(typeof(getvals2) == delegate)); 1947 assert(getvals2() == 123456); 1948 1949 /* test for attributes */ 1950 { 1951 static int refvar = 0xDeadFace; 1952 1953 static ref int func_ref() { return refvar; } 1954 static int func_pure() pure { return 1; } 1955 static int func_nothrow() nothrow { return 2; } 1956 static int func_property() @property { return 3; } 1957 static int func_safe() @safe { return 4; } 1958 static int func_trusted() @trusted { return 5; } 1959 static int func_system() @system { return 6; } 1960 static int func_pure_nothrow() pure nothrow { return 7; } 1961 static int func_pure_nothrow_safe() pure nothrow @safe { return 8; } 1962 1963 auto dg_ref = toDelegate(&func_ref); 1964 int delegate() pure dg_pure = toDelegate(&func_pure); 1965 int delegate() nothrow dg_nothrow = toDelegate(&func_nothrow); 1966 int delegate() @property dg_property = toDelegate(&func_property); 1967 int delegate() @safe dg_safe = toDelegate(&func_safe); 1968 int delegate() @trusted dg_trusted = toDelegate(&func_trusted); 1969 int delegate() @system dg_system = toDelegate(&func_system); 1970 int delegate() pure nothrow dg_pure_nothrow = toDelegate(&func_pure_nothrow); 1971 int delegate() @safe pure nothrow dg_pure_nothrow_safe = toDelegate(&func_pure_nothrow_safe); 1972 1973 //static assert(is(typeof(dg_ref) == ref int delegate())); // [BUG@DMD] 1974 1975 assert(dg_ref() == refvar); 1976 assert(dg_pure() == 1); 1977 assert(dg_nothrow() == 2); 1978 assert(dg_property() == 3); 1979 assert(dg_safe() == 4); 1980 assert(dg_trusted() == 5); 1981 assert(dg_system() == 6); 1982 assert(dg_pure_nothrow() == 7); 1983 assert(dg_pure_nothrow_safe() == 8); 1984 } 1985 /* test for linkage */ 1986 { 1987 struct S 1988 { 1989 extern(C) static void xtrnC() {} 1990 extern(D) static void xtrnD() {} 1991 } 1992 auto dg_xtrnC = toDelegate(&S.xtrnC); 1993 auto dg_xtrnD = toDelegate(&S.xtrnD); 1994 static assert(! is(typeof(dg_xtrnC) == typeof(dg_xtrnD))); 1995 } 1996 } 1997 1998 1999 @safe unittest 2000 { 2001 static struct S1 { static void opCall()() { } } 2002 static struct S2 { static T opCall(T = int)(T x) {return x; } } 2003 2004 S1 i1; 2005 const dg1 = toDelegate(i1); 2006 dg1(); 2007 2008 S2 i2; 2009 assert(toDelegate(i2)(0xBED) == 0xBED); 2010 } 2011 2012 @safe unittest 2013 { 2014 static void fun() @system pure nothrow @nogc 2015 { 2016 return; 2017 } 2018 2019 auto fn = &fun; 2020 static assert( is(typeof(fn) == void function() @system pure nothrow @nogc)); 2021 static assert(!is(typeof(fn) == void function() @safe pure nothrow @nogc)); 2022 2023 auto dg = fn.toDelegate(); 2024 static assert( is(typeof(dg) == void delegate() @system pure nothrow @nogc)); 2025 static assert(!is(typeof(dg) == void delegate() @safe pure nothrow @nogc)); 2026 } 2027 2028 /** 2029 * Passes the fields of a struct as arguments to a function. 2030 * 2031 * Can be used with a $(LINK2 https://dlang.org/spec/expression.html#function_literals, 2032 * function literal) to give temporary names to the fields of a struct or 2033 * tuple. 2034 * 2035 * Params: 2036 * fun = Callable that the struct's fields will be passed to. 2037 * 2038 * Returns: 2039 * A function that accepts a single struct as an argument and passes its 2040 * fields to `fun` when called. 2041 */ 2042 template bind(alias fun) 2043 { 2044 /** 2045 * Params: 2046 * args = The struct or tuple whose fields will be used as arguments. 2047 * 2048 * Returns: `fun(args.tupleof)` 2049 */ 2050 auto ref bind(T)(auto ref T args) 2051 if (is(T == struct)) 2052 { 2053 import std.meta : Map = staticMap; 2054 import core.lifetime : move; 2055 2056 // Forwards the i'th member of `args` 2057 // Needed because core.lifetime.forward doesn't work on struct members 2058 template forwardArg(size_t i) 2059 { 2060 static if (__traits(isRef, args) || !is(typeof(move(args.tupleof[i])))) 2061 enum forwardArg = "args.tupleof[" ~ toCtString!i ~ "], "; 2062 else 2063 enum forwardArg = "move(args.tupleof[" ~ toCtString!i ~ "]), "; 2064 } 2065 2066 static if (args.tupleof.length == 0) 2067 enum argList = ""; 2068 else 2069 alias argList = Map!(forwardArg, Iota!(args.tupleof.length)); 2070 2071 return mixin("fun(", argList, ")"); 2072 } 2073 } 2074 2075 /// Giving names to tuple elements 2076 @safe unittest 2077 { 2078 import std.typecons : tuple; 2079 2080 auto name = tuple("John", "Doe"); 2081 string full = name.bind!((first, last) => first ~ " " ~ last); 2082 assert(full == "John Doe"); 2083 } 2084 2085 /// Passing struct fields to a function 2086 @safe unittest 2087 { 2088 import std.algorithm.comparison : min, max; 2089 2090 struct Pair 2091 { 2092 int a; 2093 int b; 2094 } 2095 2096 auto p = Pair(123, 456); 2097 assert(p.bind!min == 123); // min(p.a, p.b) 2098 assert(p.bind!max == 456); // max(p.a, p.b) 2099 } 2100 2101 /// In a range pipeline 2102 @safe unittest 2103 { 2104 import std.algorithm.iteration : map, filter; 2105 import std.algorithm.comparison : equal; 2106 import std.typecons : tuple; 2107 2108 auto ages = [ 2109 tuple("Alice", 35), 2110 tuple("Bob", 64), 2111 tuple("Carol", 21), 2112 tuple("David", 39), 2113 tuple("Eve", 50) 2114 ]; 2115 2116 auto overForty = ages 2117 .filter!(bind!((name, age) => age > 40)) 2118 .map!(bind!((name, age) => name)); 2119 2120 assert(overForty.equal(["Bob", "Eve"])); 2121 } 2122 2123 // Zero arguments 2124 @safe unittest 2125 { 2126 struct Empty {} 2127 2128 assert(Empty().bind!(() => 123) == 123); 2129 } 2130 2131 // Non-copyable arguments 2132 @safe unittest 2133 { 2134 import std.typecons : tuple; 2135 2136 static struct NoCopy 2137 { 2138 int n; 2139 @disable this(this); 2140 } 2141 2142 static struct Pair 2143 { 2144 NoCopy a, b; 2145 } 2146 2147 static auto fun(NoCopy a, NoCopy b) 2148 { 2149 return tuple(a.n, b.n); 2150 } 2151 2152 auto expected = fun(NoCopy(1), NoCopy(2)); 2153 assert(Pair(NoCopy(1), NoCopy(2)).bind!fun == expected); 2154 } 2155 2156 // ref arguments 2157 @safe unittest 2158 { 2159 import std.typecons : tuple; 2160 2161 auto t = tuple(123, 456); 2162 t.bind!((ref int a, int b) { a = 789; b = 1011; }); 2163 2164 assert(t[0] == 789); 2165 assert(t[1] == 456); 2166 } 2167 2168 // auto ref arguments 2169 @safe unittest 2170 { 2171 import std.typecons : tuple; 2172 2173 auto t = tuple(123); 2174 t.bind!((auto ref x) { 2175 static assert(__traits(isRef, x)); 2176 }); 2177 tuple(123).bind!((auto ref x) { 2178 static assert(!__traits(isRef, x)); 2179 }); 2180 } 2181 2182 /** 2183 * Enforces the evaluation of an expression during compile-time. 2184 * 2185 * Computes the value of an expression during compilation (CTFE). 2186 * 2187 * This is useful for call chains in functional programming 2188 * where declaring an `enum` constant would require splitting 2189 * the pipeline. 2190 * 2191 * Params: 2192 * expr = expression to evaluate 2193 * See_also: 2194 * $(LINK https://dlang.org/spec/function.html#interpretation) 2195 */ 2196 enum ctEval(alias expr) = expr; 2197 2198 /// 2199 @safe unittest 2200 { 2201 import std.math : abs; 2202 2203 // No explicit `enum` needed. 2204 float result = ctEval!(abs(-3)); 2205 assert(result == 3); 2206 2207 // Can be statically asserted. 2208 static assert(ctEval!(abs(-4)) == 4); 2209 static assert(ctEval!(abs( 9)) == 9); 2210 } 2211 2212 /// 2213 @safe unittest 2214 { 2215 import core.stdc.math : round; 2216 import std.conv : to; 2217 import std.math : abs, PI, sin; 2218 2219 // `round` from the C standard library cannot be interpreted at compile 2220 // time, because it has no available source code. However the function 2221 // calls preceding `round` can be evaluated during compile time. 2222 int result = ctEval!(abs(sin(1.0)) * 180 / PI) 2223 .round() 2224 .to!int(); 2225 2226 assert(result == 48); 2227 }