1// Written in the D programming language. 2 3/** 4Functions that manipulate other functions. 5 6This module provides functions for compile time function composition. These 7functions are helpful when constructing predicates for the algorithms in 8$(MREF std, algorithm) or $(MREF std, range). 9 10$(SCRIPT inhibitQuickIndex = 1;) 11$(BOOKTABLE , 12$(TR $(TH Function Name) $(TH Description) 13) 14 $(TR $(TD $(LREF adjoin)) 15 $(TD Joins a couple of functions into one that executes the original 16 functions independently and returns a tuple with all the results. 17 )) 18 $(TR $(TD $(LREF compose), $(LREF pipe)) 19 $(TD Join a couple of functions into one that executes the original 20 functions one after the other, using one function's result for the next 21 function's argument. 22 )) 23 $(TR $(TD $(LREF forward)) 24 $(TD Forwards function arguments while saving ref-ness. 25 )) 26 $(TR $(TD $(LREF lessThan), $(LREF greaterThan), $(LREF equalTo)) 27 $(TD Ready-made predicate functions to compare two values. 28 )) 29 $(TR $(TD $(LREF memoize)) 30 $(TD Creates a function that caches its result for fast re-evaluation. 31 )) 32 $(TR $(TD $(LREF not)) 33 $(TD Creates a function that negates another. 34 )) 35 $(TR $(TD $(LREF partial)) 36 $(TD Creates a function that binds the first argument of a given function 37 to a given value. 38 )) 39 $(TR $(TD $(LREF reverseArgs), $(LREF binaryReverseArgs)) 40 $(TD Predicate that reverses the order of its arguments. 41 )) 42 $(TR $(TD $(LREF toDelegate)) 43 $(TD Converts a callable to a delegate. 44 )) 45 $(TR $(TD $(LREF unaryFun), $(LREF binaryFun)) 46 $(TD Create a unary or binary function from a string. Most often 47 used when defining algorithms on ranges. 48 )) 49) 50 51Copyright: Copyright Andrei Alexandrescu 2008 - 2009. 52License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 53Authors: $(HTTP erdani.org, Andrei Alexandrescu) 54Source: $(PHOBOSSRC std/_functional.d) 55*/ 56/* 57 Copyright Andrei Alexandrescu 2008 - 2009. 58Distributed under the Boost Software License, Version 1.0. 59 (See accompanying file LICENSE_1_0.txt or copy at 60 http://www.boost.org/LICENSE_1_0.txt) 61*/ 62module std.functional; 63 64import std.meta; // AliasSeq, Reverse 65import std.traits; // isCallable, Parameters 66 67 68private template needOpCallAlias(alias fun) 69{ 70 /* Determine whether or not unaryFun and binaryFun need to alias to fun or 71 * fun.opCall. Basically, fun is a function object if fun(...) compiles. We 72 * want is(unaryFun!fun) (resp., is(binaryFun!fun)) to be true if fun is 73 * any function object. There are 4 possible cases: 74 * 75 * 1) fun is the type of a function object with static opCall; 76 * 2) fun is an instance of a function object with static opCall; 77 * 3) fun is the type of a function object with non-static opCall; 78 * 4) fun is an instance of a function object with non-static opCall. 79 * 80 * In case (1), is(unaryFun!fun) should compile, but does not if unaryFun 81 * aliases itself to fun, because typeof(fun) is an error when fun itself 82 * is a type. So it must be aliased to fun.opCall instead. All other cases 83 * should be aliased to fun directly. 84 */ 85 static if (is(typeof(fun.opCall) == function)) 86 { 87 enum needOpCallAlias = !is(typeof(fun)) && __traits(compiles, () { 88 return fun(Parameters!fun.init); 89 }); 90 } 91 else 92 enum needOpCallAlias = false; 93} 94 95/** 96Transforms a string representing an expression into a unary 97function. The string must either use symbol name $(D a) as 98the parameter or provide the symbol via the $(D parmName) argument. 99If $(D fun) is not a string, $(D unaryFun) aliases itself away to $(D fun). 100*/ 101 102template unaryFun(alias fun, string parmName = "a") 103{ 104 static if (is(typeof(fun) : string)) 105 { 106 static if (!fun._ctfeMatchUnary(parmName)) 107 { 108 import std.algorithm, std.conv, std.exception, std.math, std.range, std.string; 109 import std.meta, std.traits, std.typecons; 110 } 111 auto unaryFun(ElementType)(auto ref ElementType __a) 112 { 113 mixin("alias " ~ parmName ~ " = __a ;"); 114 return mixin(fun); 115 } 116 } 117 else static if (needOpCallAlias!fun) 118 { 119 // Issue 9906 120 alias unaryFun = fun.opCall; 121 } 122 else 123 { 124 alias unaryFun = fun; 125 } 126} 127 128/// 129@safe unittest 130{ 131 // Strings are compiled into functions: 132 alias isEven = unaryFun!("(a & 1) == 0"); 133 assert(isEven(2) && !isEven(1)); 134} 135 136@safe unittest 137{ 138 static int f1(int a) { return a + 1; } 139 static assert(is(typeof(unaryFun!(f1)(1)) == int)); 140 assert(unaryFun!(f1)(41) == 42); 141 int f2(int a) { return a + 1; } 142 static assert(is(typeof(unaryFun!(f2)(1)) == int)); 143 assert(unaryFun!(f2)(41) == 42); 144 assert(unaryFun!("a + 1")(41) == 42); 145 //assert(unaryFun!("return a + 1;")(41) == 42); 146 147 int num = 41; 148 assert(unaryFun!"a + 1"(num) == 42); 149 150 // Issue 9906 151 struct Seen 152 { 153 static bool opCall(int n) { return true; } 154 } 155 static assert(needOpCallAlias!Seen); 156 static assert(is(typeof(unaryFun!Seen(1)))); 157 assert(unaryFun!Seen(1)); 158 159 Seen s; 160 static assert(!needOpCallAlias!s); 161 static assert(is(typeof(unaryFun!s(1)))); 162 assert(unaryFun!s(1)); 163 164 struct FuncObj 165 { 166 bool opCall(int n) { return true; } 167 } 168 FuncObj fo; 169 static assert(!needOpCallAlias!fo); 170 static assert(is(typeof(unaryFun!fo))); 171 assert(unaryFun!fo(1)); 172 173 // Function object with non-static opCall can only be called with an 174 // instance, not with merely the type. 175 static assert(!is(typeof(unaryFun!FuncObj))); 176} 177 178/** 179Transforms a string representing an expression into a binary function. The 180string must either use symbol names $(D a) and $(D b) as the parameters or 181provide the symbols via the $(D parm1Name) and $(D parm2Name) arguments. 182If $(D fun) is not a string, $(D binaryFun) aliases itself away to 183$(D fun). 184*/ 185 186template binaryFun(alias fun, string parm1Name = "a", 187 string parm2Name = "b") 188{ 189 static if (is(typeof(fun) : string)) 190 { 191 static if (!fun._ctfeMatchBinary(parm1Name, parm2Name)) 192 { 193 import std.algorithm, std.conv, std.exception, std.math, std.range, std.string; 194 import std.meta, std.traits, std.typecons; 195 } 196 auto binaryFun(ElementType1, ElementType2) 197 (auto ref ElementType1 __a, auto ref ElementType2 __b) 198 { 199 mixin("alias "~parm1Name~" = __a ;"); 200 mixin("alias "~parm2Name~" = __b ;"); 201 return mixin(fun); 202 } 203 } 204 else static if (needOpCallAlias!fun) 205 { 206 // Issue 9906 207 alias binaryFun = fun.opCall; 208 } 209 else 210 { 211 alias binaryFun = fun; 212 } 213} 214 215/// 216@safe unittest 217{ 218 alias less = binaryFun!("a < b"); 219 assert(less(1, 2) && !less(2, 1)); 220 alias greater = binaryFun!("a > b"); 221 assert(!greater("1", "2") && greater("2", "1")); 222} 223 224@safe unittest 225{ 226 static int f1(int a, string b) { return a + 1; } 227 static assert(is(typeof(binaryFun!(f1)(1, "2")) == int)); 228 assert(binaryFun!(f1)(41, "a") == 42); 229 string f2(int a, string b) { return b ~ "2"; } 230 static assert(is(typeof(binaryFun!(f2)(1, "1")) == string)); 231 assert(binaryFun!(f2)(1, "4") == "42"); 232 assert(binaryFun!("a + b")(41, 1) == 42); 233 //@@BUG 234 //assert(binaryFun!("return a + b;")(41, 1) == 42); 235 236 // Issue 9906 237 struct Seen 238 { 239 static bool opCall(int x, int y) { return true; } 240 } 241 static assert(is(typeof(binaryFun!Seen))); 242 assert(binaryFun!Seen(1,1)); 243 244 struct FuncObj 245 { 246 bool opCall(int x, int y) { return true; } 247 } 248 FuncObj fo; 249 static assert(!needOpCallAlias!fo); 250 static assert(is(typeof(binaryFun!fo))); 251 assert(unaryFun!fo(1,1)); 252 253 // Function object with non-static opCall can only be called with an 254 // instance, not with merely the type. 255 static assert(!is(typeof(binaryFun!FuncObj))); 256} 257 258// skip all ASCII chars except a .. z, A .. Z, 0 .. 9, '_' and '.'. 259private uint _ctfeSkipOp(ref string op) 260{ 261 if (!__ctfe) assert(false); 262 import std.ascii : isASCII, isAlphaNum; 263 immutable oldLength = op.length; 264 while (op.length) 265 { 266 immutable front = op[0]; 267 if (front.isASCII() && !(front.isAlphaNum() || front == '_' || front == '.')) 268 op = op[1..$]; 269 else 270 break; 271 } 272 return oldLength != op.length; 273} 274 275// skip all digits 276private uint _ctfeSkipInteger(ref string op) 277{ 278 if (!__ctfe) assert(false); 279 import std.ascii : isDigit; 280 immutable oldLength = op.length; 281 while (op.length) 282 { 283 immutable front = op[0]; 284 if (front.isDigit()) 285 op = op[1..$]; 286 else 287 break; 288 } 289 return oldLength != op.length; 290} 291 292// skip name 293private uint _ctfeSkipName(ref string op, string name) 294{ 295 if (!__ctfe) assert(false); 296 if (op.length >= name.length && op[0 .. name.length] == name) 297 { 298 op = op[name.length..$]; 299 return 1; 300 } 301 return 0; 302} 303 304// returns 1 if $(D fun) is trivial unary function 305private uint _ctfeMatchUnary(string fun, string name) 306{ 307 if (!__ctfe) assert(false); 308 fun._ctfeSkipOp(); 309 for (;;) 310 { 311 immutable h = fun._ctfeSkipName(name) + fun._ctfeSkipInteger(); 312 if (h == 0) 313 { 314 fun._ctfeSkipOp(); 315 break; 316 } 317 else if (h == 1) 318 { 319 if (!fun._ctfeSkipOp()) 320 break; 321 } 322 else 323 return 0; 324 } 325 return fun.length == 0; 326} 327 328@safe unittest 329{ 330 static assert(!_ctfeMatchUnary("sqrt(��)", "��")); 331 static assert(!_ctfeMatchUnary("��.sqrt", "��")); 332 static assert(!_ctfeMatchUnary(".��+��", "��")); 333 static assert(!_ctfeMatchUnary("_��+��", "��")); 334 static assert(!_ctfeMatchUnary("����", "��")); 335 static assert(_ctfeMatchUnary("a+a", "a")); 336 static assert(_ctfeMatchUnary("a + 10", "a")); 337 static assert(_ctfeMatchUnary("4 == a", "a")); 338 static assert(_ctfeMatchUnary("2 == a", "a")); 339 static assert(_ctfeMatchUnary("1 != a", "a")); 340 static assert(_ctfeMatchUnary("a != 4", "a")); 341 static assert(_ctfeMatchUnary("a< 1", "a")); 342 static assert(_ctfeMatchUnary("434 < a", "a")); 343 static assert(_ctfeMatchUnary("132 > a", "a")); 344 static assert(_ctfeMatchUnary("123 >a", "a")); 345 static assert(_ctfeMatchUnary("a>82", "a")); 346 static assert(_ctfeMatchUnary("��>82", "��")); 347 static assert(_ctfeMatchUnary("��[��(��)]", "��")); 348 static assert(_ctfeMatchUnary("��[21]", "��")); 349} 350 351// returns 1 if $(D fun) is trivial binary function 352private uint _ctfeMatchBinary(string fun, string name1, string name2) 353{ 354 if (!__ctfe) assert(false); 355 fun._ctfeSkipOp(); 356 for (;;) 357 { 358 immutable h = fun._ctfeSkipName(name1) + fun._ctfeSkipName(name2) + fun._ctfeSkipInteger(); 359 if (h == 0) 360 { 361 fun._ctfeSkipOp(); 362 break; 363 } 364 else if (h == 1) 365 { 366 if (!fun._ctfeSkipOp()) 367 break; 368 } 369 else 370 return 0; 371 } 372 return fun.length == 0; 373} 374 375@safe unittest 376{ 377 378 static assert(!_ctfeMatchBinary("sqrt(��)", "��", "b")); 379 static assert(!_ctfeMatchBinary("��.sqrt", "��", "b")); 380 static assert(!_ctfeMatchBinary(".��+��", "��", "b")); 381 static assert(!_ctfeMatchBinary("_��+��", "��", "b")); 382 static assert(!_ctfeMatchBinary("����", "��", "b")); 383 static assert(_ctfeMatchBinary("a+a", "a", "b")); 384 static assert(_ctfeMatchBinary("a + 10", "a", "b")); 385 static assert(_ctfeMatchBinary("4 == a", "a", "b")); 386 static assert(_ctfeMatchBinary("2 == a", "a", "b")); 387 static assert(_ctfeMatchBinary("1 != a", "a", "b")); 388 static assert(_ctfeMatchBinary("a != 4", "a", "b")); 389 static assert(_ctfeMatchBinary("a< 1", "a", "b")); 390 static assert(_ctfeMatchBinary("434 < a", "a", "b")); 391 static assert(_ctfeMatchBinary("132 > a", "a", "b")); 392 static assert(_ctfeMatchBinary("123 >a", "a", "b")); 393 static assert(_ctfeMatchBinary("a>82", "a", "b")); 394 static assert(_ctfeMatchBinary("��>82", "��", "q")); 395 static assert(_ctfeMatchBinary("��[��(10)]", "��", "q")); 396 static assert(_ctfeMatchBinary("��[21]", "��", "q")); 397 398 static assert(!_ctfeMatchBinary("sqrt(��)+b", "b", "��")); 399 static assert(!_ctfeMatchBinary("��.sqrt-b", "b", "��")); 400 static assert(!_ctfeMatchBinary(".��+b", "b", "��")); 401 static assert(!_ctfeMatchBinary("_b+��", "b", "��")); 402 static assert(!_ctfeMatchBinary("ba", "b", "a")); 403 static assert(_ctfeMatchBinary("a+b", "b", "a")); 404 static assert(_ctfeMatchBinary("a + b", "b", "a")); 405 static assert(_ctfeMatchBinary("b == a", "b", "a")); 406 static assert(_ctfeMatchBinary("b == a", "b", "a")); 407 static assert(_ctfeMatchBinary("b != a", "b", "a")); 408 static assert(_ctfeMatchBinary("a != b", "b", "a")); 409 static assert(_ctfeMatchBinary("a< b", "b", "a")); 410 static assert(_ctfeMatchBinary("b < a", "b", "a")); 411 static assert(_ctfeMatchBinary("b > a", "b", "a")); 412 static assert(_ctfeMatchBinary("b >a", "b", "a")); 413 static assert(_ctfeMatchBinary("a>b", "b", "a")); 414 static assert(_ctfeMatchBinary("��>b", "b", "��")); 415 static assert(_ctfeMatchBinary("b[��(-1)]", "b", "��")); 416 static assert(_ctfeMatchBinary("��[-21]", "b", "��")); 417} 418 419//undocumented 420template safeOp(string S) 421if (S=="<"||S==">"||S=="<="||S==">="||S=="=="||S=="!=") 422{ 423 import std.traits : isIntegral; 424 private bool unsafeOp(ElementType1, ElementType2)(ElementType1 a, ElementType2 b) pure 425 if (isIntegral!ElementType1 && isIntegral!ElementType2) 426 { 427 import std.traits : CommonType; 428 alias T = CommonType!(ElementType1, ElementType2); 429 return mixin("cast(T)a "~S~" cast(T) b"); 430 } 431 432 bool safeOp(T0, T1)(auto ref T0 a, auto ref T1 b) 433 { 434 import std.traits : mostNegative; 435 static if (isIntegral!T0 && isIntegral!T1 && 436 (mostNegative!T0 < 0) != (mostNegative!T1 < 0)) 437 { 438 static if (S == "<=" || S == "<") 439 { 440 static if (mostNegative!T0 < 0) 441 immutable result = a < 0 || unsafeOp(a, b); 442 else 443 immutable result = b >= 0 && unsafeOp(a, b); 444 } 445 else 446 { 447 static if (mostNegative!T0 < 0) 448 immutable result = a >= 0 && unsafeOp(a, b); 449 else 450 immutable result = b < 0 || unsafeOp(a, b); 451 } 452 } 453 else 454 { 455 static assert(is(typeof(mixin("a "~S~" b"))), 456 "Invalid arguments: Cannot compare types " ~ T0.stringof ~ " and " ~ T1.stringof ~ "."); 457 458 immutable result = mixin("a "~S~" b"); 459 } 460 return result; 461 } 462} 463 464@safe unittest //check user defined types 465{ 466 import std.algorithm.comparison : equal; 467 struct Foo 468 { 469 int a; 470 auto opEquals(Foo foo) 471 { 472 return a == foo.a; 473 } 474 } 475 assert(safeOp!"!="(Foo(1), Foo(2))); 476} 477 478/** 479 Predicate that returns $(D_PARAM a < b). 480 Correctly compares signed and unsigned integers, ie. -1 < 2U. 481*/ 482alias lessThan = safeOp!"<"; 483 484/// 485pure @safe @nogc nothrow unittest 486{ 487 assert(lessThan(2, 3)); 488 assert(lessThan(2U, 3U)); 489 assert(lessThan(2, 3.0)); 490 assert(lessThan(-2, 3U)); 491 assert(lessThan(2, 3U)); 492 assert(!lessThan(3U, -2)); 493 assert(!lessThan(3U, 2)); 494 assert(!lessThan(0, 0)); 495 assert(!lessThan(0U, 0)); 496 assert(!lessThan(0, 0U)); 497} 498 499/** 500 Predicate that returns $(D_PARAM a > b). 501 Correctly compares signed and unsigned integers, ie. 2U > -1. 502*/ 503alias greaterThan = safeOp!">"; 504 505/// 506@safe unittest 507{ 508 assert(!greaterThan(2, 3)); 509 assert(!greaterThan(2U, 3U)); 510 assert(!greaterThan(2, 3.0)); 511 assert(!greaterThan(-2, 3U)); 512 assert(!greaterThan(2, 3U)); 513 assert(greaterThan(3U, -2)); 514 assert(greaterThan(3U, 2)); 515 assert(!greaterThan(0, 0)); 516 assert(!greaterThan(0U, 0)); 517 assert(!greaterThan(0, 0U)); 518} 519 520/** 521 Predicate that returns $(D_PARAM a == b). 522 Correctly compares signed and unsigned integers, ie. !(-1 == ~0U). 523*/ 524alias equalTo = safeOp!"=="; 525 526/// 527@safe unittest 528{ 529 assert(equalTo(0U, 0)); 530 assert(equalTo(0, 0U)); 531 assert(!equalTo(-1, ~0U)); 532} 533/** 534 N-ary predicate that reverses the order of arguments, e.g., given 535 $(D pred(a, b, c)), returns $(D pred(c, b, a)). 536*/ 537template reverseArgs(alias pred) 538{ 539 auto reverseArgs(Args...)(auto ref Args args) 540 if (is(typeof(pred(Reverse!args)))) 541 { 542 return pred(Reverse!args); 543 } 544} 545 546/// 547@safe unittest 548{ 549 alias gt = reverseArgs!(binaryFun!("a < b")); 550 assert(gt(2, 1) && !gt(1, 1)); 551 int x = 42; 552 bool xyz(int a, int b) { return a * x < b / x; } 553 auto foo = &xyz; 554 foo(4, 5); 555 alias zyx = reverseArgs!(foo); 556 assert(zyx(5, 4) == foo(4, 5)); 557} 558 559/// 560@safe unittest 561{ 562 int abc(int a, int b, int c) { return a * b + c; } 563 alias cba = reverseArgs!abc; 564 assert(abc(91, 17, 32) == cba(32, 17, 91)); 565} 566 567/// 568@safe unittest 569{ 570 int a(int a) { return a * 2; } 571 alias _a = reverseArgs!a; 572 assert(a(2) == _a(2)); 573} 574 575/// 576@safe unittest 577{ 578 int b() { return 4; } 579 alias _b = reverseArgs!b; 580 assert(b() == _b()); 581} 582 583/** 584 Binary predicate that reverses the order of arguments, e.g., given 585 $(D pred(a, b)), returns $(D pred(b, a)). 586*/ 587template binaryReverseArgs(alias pred) 588{ 589 auto binaryReverseArgs(ElementType1, ElementType2) 590 (auto ref ElementType1 a, auto ref ElementType2 b) 591 { 592 return pred(b, a); 593 } 594} 595 596/// 597@safe unittest 598{ 599 alias gt = binaryReverseArgs!(binaryFun!("a < b")); 600 assert(gt(2, 1) && !gt(1, 1)); 601} 602 603/// 604@safe unittest 605{ 606 int x = 42; 607 bool xyz(int a, int b) { return a * x < b / x; } 608 auto foo = &xyz; 609 foo(4, 5); 610 alias zyx = binaryReverseArgs!(foo); 611 assert(zyx(5, 4) == foo(4, 5)); 612} 613 614/** 615Negates predicate $(D pred). 616 */ 617template not(alias pred) 618{ 619 auto not(T...)(auto ref T args) 620 { 621 static if (is(typeof(!pred(args)))) 622 return !pred(args); 623 else static if (T.length == 1) 624 return !unaryFun!pred(args); 625 else static if (T.length == 2) 626 return !binaryFun!pred(args); 627 else 628 static assert(0); 629 } 630} 631 632/// 633@safe unittest 634{ 635 import std.algorithm.searching : find; 636 import std.functional; 637 import std.uni : isWhite; 638 string a = " Hello, world!"; 639 assert(find!(not!isWhite)(a) == "Hello, world!"); 640} 641 642@safe unittest 643{ 644 assert(not!"a != 5"(5)); 645 assert(not!"a != b"(5, 5)); 646 647 assert(not!(() => false)()); 648 assert(not!(a => a != 5)(5)); 649 assert(not!((a, b) => a != b)(5, 5)); 650 assert(not!((a, b, c) => a * b * c != 125 )(5, 5, 5)); 651} 652 653/** 654$(LINK2 http://en.wikipedia.org/wiki/Partial_application, Partially 655applies) $(D_PARAM fun) by tying its first argument to $(D_PARAM arg). 656 */ 657template partial(alias fun, alias arg) 658{ 659 static if (is(typeof(fun) == delegate) || is(typeof(fun) == function)) 660 { 661 import std.traits : ReturnType; 662 ReturnType!fun partial(Parameters!fun[1..$] args2) 663 { 664 return fun(arg, args2); 665 } 666 } 667 else 668 { 669 auto partial(Ts...)(Ts args2) 670 { 671 static if (is(typeof(fun(arg, args2)))) 672 { 673 return fun(arg, args2); 674 } 675 else 676 { 677 static string errormsg() 678 { 679 string msg = "Cannot call '" ~ fun.stringof ~ "' with arguments " ~ 680 "(" ~ arg.stringof; 681 foreach (T; Ts) 682 msg ~= ", " ~ T.stringof; 683 msg ~= ")."; 684 return msg; 685 } 686 static assert(0, errormsg()); 687 } 688 } 689 } 690} 691 692/// 693@safe unittest 694{ 695 int fun(int a, int b) { return a + b; } 696 alias fun5 = partial!(fun, 5); 697 assert(fun5(6) == 11); 698 // Note that in most cases you'd use an alias instead of a value 699 // assignment. Using an alias allows you to partially evaluate template 700 // functions without committing to a particular type of the function. 701} 702 703// tests for partially evaluating callables 704@safe unittest 705{ 706 static int f1(int a, int b) { return a + b; } 707 assert(partial!(f1, 5)(6) == 11); 708 709 int f2(int a, int b) { return a + b; } 710 int x = 5; 711 assert(partial!(f2, x)(6) == 11); 712 x = 7; 713 assert(partial!(f2, x)(6) == 13); 714 static assert(partial!(f2, 5)(6) == 11); 715 716 auto dg = &f2; 717 auto f3 = &partial!(dg, x); 718 assert(f3(6) == 13); 719 720 static int funOneArg(int a) { return a; } 721 assert(partial!(funOneArg, 1)() == 1); 722 723 static int funThreeArgs(int a, int b, int c) { return a + b + c; } 724 alias funThreeArgs1 = partial!(funThreeArgs, 1); 725 assert(funThreeArgs1(2, 3) == 6); 726 static assert(!is(typeof(funThreeArgs1(2)))); 727 728 enum xe = 5; 729 alias fe = partial!(f2, xe); 730 static assert(fe(6) == 11); 731} 732 733// tests for partially evaluating templated/overloaded callables 734@safe unittest 735{ 736 static auto add(A, B)(A x, B y) 737 { 738 return x + y; 739 } 740 741 alias add5 = partial!(add, 5); 742 assert(add5(6) == 11); 743 static assert(!is(typeof(add5()))); 744 static assert(!is(typeof(add5(6, 7)))); 745 746 // taking address of templated partial evaluation needs explicit type 747 auto dg = &add5!(int); 748 assert(dg(6) == 11); 749 750 int x = 5; 751 alias addX = partial!(add, x); 752 assert(addX(6) == 11); 753 754 static struct Callable 755 { 756 static string opCall(string a, string b) { return a ~ b; } 757 int opCall(int a, int b) { return a * b; } 758 double opCall(double a, double b) { return a + b; } 759 } 760 Callable callable; 761 assert(partial!(Callable, "5")("6") == "56"); 762 assert(partial!(callable, 5)(6) == 30); 763 assert(partial!(callable, 7.0)(3.0) == 7.0 + 3.0); 764 765 static struct TCallable 766 { 767 auto opCall(A, B)(A a, B b) 768 { 769 return a + b; 770 } 771 } 772 TCallable tcallable; 773 assert(partial!(tcallable, 5)(6) == 11); 774 static assert(!is(typeof(partial!(tcallable, "5")(6)))); 775 776 static A funOneArg(A)(A a) { return a; } 777 alias funOneArg1 = partial!(funOneArg, 1); 778 assert(funOneArg1() == 1); 779 780 static auto funThreeArgs(A, B, C)(A a, B b, C c) { return a + b + c; } 781 alias funThreeArgs1 = partial!(funThreeArgs, 1); 782 assert(funThreeArgs1(2, 3) == 6); 783 static assert(!is(typeof(funThreeArgs1(1)))); 784 785 auto dg2 = &funOneArg1!(); 786 assert(dg2() == 1); 787} 788 789/** 790Takes multiple functions and adjoins them together. The result is a 791$(REF Tuple, std,typecons) with one element per passed-in function. Upon 792invocation, the returned tuple is the adjoined results of all 793functions. 794 795Note: In the special case where only a single function is provided 796($(D F.length == 1)), adjoin simply aliases to the single passed function 797($(D F[0])). 798*/ 799template adjoin(F...) 800if (F.length == 1) 801{ 802 alias adjoin = F[0]; 803} 804/// ditto 805template adjoin(F...) 806if (F.length > 1) 807{ 808 auto adjoin(V...)(auto ref V a) 809 { 810 import std.typecons : tuple; 811 static if (F.length == 2) 812 { 813 return tuple(F[0](a), F[1](a)); 814 } 815 else static if (F.length == 3) 816 { 817 return tuple(F[0](a), F[1](a), F[2](a)); 818 } 819 else 820 { 821 import std.format : format; 822 import std.range : iota; 823 return mixin (q{tuple(%(F[%s](a)%|, %))}.format(iota(0, F.length))); 824 } 825 } 826} 827 828/// 829@safe unittest 830{ 831 import std.functional, std.typecons : Tuple; 832 static bool f1(int a) { return a != 0; } 833 static int f2(int a) { return a / 2; } 834 auto x = adjoin!(f1, f2)(5); 835 assert(is(typeof(x) == Tuple!(bool, int))); 836 assert(x[0] == true && x[1] == 2); 837} 838 839@safe unittest 840{ 841 import std.typecons : Tuple; 842 static bool F1(int a) { return a != 0; } 843 auto x1 = adjoin!(F1)(5); 844 static int F2(int a) { return a / 2; } 845 auto x2 = adjoin!(F1, F2)(5); 846 assert(is(typeof(x2) == Tuple!(bool, int))); 847 assert(x2[0] && x2[1] == 2); 848 auto x3 = adjoin!(F1, F2, F2)(5); 849 assert(is(typeof(x3) == Tuple!(bool, int, int))); 850 assert(x3[0] && x3[1] == 2 && x3[2] == 2); 851 852 bool F4(int a) { return a != x1; } 853 alias eff4 = adjoin!(F4); 854 static struct S 855 { 856 bool delegate(int) @safe store; 857 int fun() { return 42 + store(5); } 858 } 859 S s; 860 s.store = (int a) { return eff4(a); }; 861 auto x4 = s.fun(); 862 assert(x4 == 43); 863} 864 865@safe unittest 866{ 867 import std.meta : staticMap; 868 import std.typecons : Tuple, tuple; 869 alias funs = staticMap!(unaryFun, "a", "a * 2", "a * 3", "a * a", "-a"); 870 alias afun = adjoin!funs; 871 assert(afun(5) == tuple(5, 10, 15, 25, -5)); 872 873 static class C{} 874 alias IC = immutable(C); 875 IC foo(){return typeof(return).init;} 876 Tuple!(IC, IC, IC, IC) ret1 = adjoin!(foo, foo, foo, foo)(); 877 878 static struct S{int* p;} 879 alias IS = immutable(S); 880 IS bar(){return typeof(return).init;} 881 enum Tuple!(IS, IS, IS, IS) ret2 = adjoin!(bar, bar, bar, bar)(); 882} 883 884/** 885 Composes passed-in functions $(D fun[0], fun[1], ...) returning a 886 function $(D f(x)) that in turn returns $(D 887 fun[0](fun[1](...(x)))...). Each function can be a regular 888 functions, a delegate, or a string. 889 890 See_Also: $(LREF pipe) 891*/ 892template compose(fun...) 893{ 894 static if (fun.length == 1) 895 { 896 alias compose = unaryFun!(fun[0]); 897 } 898 else static if (fun.length == 2) 899 { 900 // starch 901 alias fun0 = unaryFun!(fun[0]); 902 alias fun1 = unaryFun!(fun[1]); 903 904 // protein: the core composition operation 905 typeof({ E a; return fun0(fun1(a)); }()) compose(E)(E a) 906 { 907 return fun0(fun1(a)); 908 } 909 } 910 else 911 { 912 // protein: assembling operations 913 alias compose = compose!(fun[0], compose!(fun[1 .. $])); 914 } 915} 916 917/// 918@safe unittest 919{ 920 import std.algorithm.comparison : equal; 921 import std.algorithm.iteration : map; 922 import std.array : split; 923 import std.conv : to; 924 925 // First split a string in whitespace-separated tokens and then 926 // convert each token into an integer 927 assert(compose!(map!(to!(int)), split)("1 2 3").equal([1, 2, 3])); 928} 929 930/** 931 Pipes functions in sequence. Offers the same functionality as $(D 932 compose), but with functions specified in reverse order. This may 933 lead to more readable code in some situation because the order of 934 execution is the same as lexical order. 935 936 Example: 937 938---- 939// Read an entire text file, split the resulting string in 940// whitespace-separated tokens, and then convert each token into an 941// integer 942int[] a = pipe!(readText, split, map!(to!(int)))("file.txt"); 943---- 944 945 See_Also: $(LREF compose) 946 */ 947alias pipe(fun...) = compose!(Reverse!(fun)); 948 949@safe unittest 950{ 951 import std.conv : to; 952 string foo(int a) { return to!(string)(a); } 953 int bar(string a) { return to!(int)(a) + 1; } 954 double baz(int a) { return a + 0.5; } 955 assert(compose!(baz, bar, foo)(1) == 2.5); 956 assert(pipe!(foo, bar, baz)(1) == 2.5); 957 958 assert(compose!(baz, `to!(int)(a) + 1`, foo)(1) == 2.5); 959 assert(compose!(baz, bar)("1"[]) == 2.5); 960 961 assert(compose!(baz, bar)("1") == 2.5); 962 963 assert(compose!(`a + 0.5`, `to!(int)(a) + 1`, foo)(1) == 2.5); 964} 965 966/** 967 * $(LINK2 https://en.wikipedia.org/wiki/Memoization, Memoizes) a function so as 968 * to avoid repeated computation. The memoization structure is a hash table keyed by a 969 * tuple of the function's arguments. There is a speed gain if the 970 * function is repeatedly called with the same arguments and is more 971 * 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). 972 973Example: 974---- 975double transmogrify(int a, string b) 976{ 977 ... expensive computation ... 978} 979alias fastTransmogrify = memoize!transmogrify; 980unittest 981{ 982 auto slow = transmogrify(2, "hello"); 983 auto fast = fastTransmogrify(2, "hello"); 984 assert(slow == fast); 985} 986---- 987 988Technically the memoized function should be pure because $(D memoize) assumes it will 989always return the same result for a given tuple of arguments. However, $(D memoize) does not 990enforce that because sometimes it 991is useful to memoize an impure function, too. 992*/ 993template memoize(alias fun) 994{ 995 import std.traits : ReturnType; 996 // alias Args = Parameters!fun; // Bugzilla 13580 997 998 ReturnType!fun memoize(Parameters!fun args) 999 { 1000 alias Args = Parameters!fun; 1001 import std.typecons : Tuple; 1002 1003 static ReturnType!fun[Tuple!Args] memo; 1004 auto t = Tuple!Args(args); 1005 if (auto p = t in memo) 1006 return *p; 1007 return memo[t] = fun(args); 1008 } 1009} 1010 1011/// ditto 1012template memoize(alias fun, uint maxSize) 1013{ 1014 import std.traits : ReturnType; 1015 // alias Args = Parameters!fun; // Bugzilla 13580 1016 ReturnType!fun memoize(Parameters!fun args) 1017 { 1018 import std.traits : hasIndirections; 1019 import std.typecons : tuple; 1020 static struct Value { Parameters!fun args; ReturnType!fun res; } 1021 static Value[] memo; 1022 static size_t[] initialized; 1023 1024 if (!memo.length) 1025 { 1026 import core.memory : GC; 1027 1028 // Ensure no allocation overflows 1029 static assert(maxSize < size_t.max / Value.sizeof); 1030 static assert(maxSize < size_t.max - (8 * size_t.sizeof - 1)); 1031 1032 enum attr = GC.BlkAttr.NO_INTERIOR | (hasIndirections!Value ? 0 : GC.BlkAttr.NO_SCAN); 1033 memo = (cast(Value*) GC.malloc(Value.sizeof * maxSize, attr))[0 .. maxSize]; 1034 enum nwords = (maxSize + 8 * size_t.sizeof - 1) / (8 * size_t.sizeof); 1035 initialized = (cast(size_t*) GC.calloc(nwords * size_t.sizeof, attr | GC.BlkAttr.NO_SCAN))[0 .. nwords]; 1036 } 1037 1038 import core.bitop : bt, bts; 1039 import std.conv : emplace; 1040 1041 size_t hash; 1042 foreach (ref arg; args) 1043 hash = hashOf(arg, hash); 1044 // cuckoo hashing 1045 immutable idx1 = hash % maxSize; 1046 if (!bt(initialized.ptr, idx1)) 1047 { 1048 emplace(&memo[idx1], args, fun(args)); 1049 bts(initialized.ptr, idx1); // only set to initialized after setting args and value (bugzilla 14025) 1050 return memo[idx1].res; 1051 } 1052 else if (memo[idx1].args == args) 1053 return memo[idx1].res; 1054 // FNV prime 1055 immutable idx2 = (hash * 16_777_619) % maxSize; 1056 if (!bt(initialized.ptr, idx2)) 1057 { 1058 emplace(&memo[idx2], memo[idx1]); 1059 bts(initialized.ptr, idx2); // only set to initialized after setting args and value (bugzilla 14025) 1060 } 1061 else if (memo[idx2].args == args) 1062 return memo[idx2].res; 1063 else if (idx1 != idx2) 1064 memo[idx2] = memo[idx1]; 1065 1066 memo[idx1] = Value(args, fun(args)); 1067 return memo[idx1].res; 1068 } 1069} 1070 1071/** 1072 * To _memoize a recursive function, simply insert the memoized call in lieu of the plain recursive call. 1073 * For example, to transform the exponential-time Fibonacci implementation into a linear-time computation: 1074 */ 1075@safe unittest 1076{ 1077 ulong fib(ulong n) @safe 1078 { 1079 return n < 2 ? n : memoize!fib(n - 2) + memoize!fib(n - 1); 1080 } 1081 assert(fib(10) == 55); 1082} 1083 1084/** 1085 * To improve the speed of the factorial function, 1086 */ 1087@safe unittest 1088{ 1089 ulong fact(ulong n) @safe 1090 { 1091 return n < 2 ? 1 : n * memoize!fact(n - 1); 1092 } 1093 assert(fact(10) == 3628800); 1094} 1095 1096/** 1097 * This memoizes all values of $(D fact) up to the largest argument. To only cache the final 1098 * result, move $(D memoize) outside the function as shown below. 1099 */ 1100@safe unittest 1101{ 1102 ulong factImpl(ulong n) @safe 1103 { 1104 return n < 2 ? 1 : n * factImpl(n - 1); 1105 } 1106 alias fact = memoize!factImpl; 1107 assert(fact(10) == 3628800); 1108} 1109 1110/** 1111 * When the $(D maxSize) parameter is specified, memoize will used 1112 * a fixed size hash table to limit the number of cached entries. 1113 */ 1114@system unittest // not @safe due to memoize 1115{ 1116 ulong fact(ulong n) 1117 { 1118 // Memoize no more than 8 values 1119 return n < 2 ? 1 : n * memoize!(fact, 8)(n - 1); 1120 } 1121 assert(fact(8) == 40320); 1122 // using more entries than maxSize will overwrite existing entries 1123 assert(fact(10) == 3628800); 1124} 1125 1126@system unittest // not @safe due to memoize 1127{ 1128 import core.math : sqrt; 1129 alias msqrt = memoize!(function double(double x) { return sqrt(x); }); 1130 auto y = msqrt(2.0); 1131 assert(y == msqrt(2.0)); 1132 y = msqrt(4.0); 1133 assert(y == sqrt(4.0)); 1134 1135 // alias mrgb2cmyk = memoize!rgb2cmyk; 1136 // auto z = mrgb2cmyk([43, 56, 76]); 1137 // assert(z == mrgb2cmyk([43, 56, 76])); 1138 1139 //alias mfib = memoize!fib; 1140 1141 static ulong fib(ulong n) @safe 1142 { 1143 alias mfib = memoize!fib; 1144 return n < 2 ? 1 : mfib(n - 2) + mfib(n - 1); 1145 } 1146 1147 auto z = fib(10); 1148 assert(z == 89); 1149 1150 static ulong fact(ulong n) @safe 1151 { 1152 alias mfact = memoize!fact; 1153 return n < 2 ? 1 : n * mfact(n - 1); 1154 } 1155 assert(fact(10) == 3628800); 1156 1157 // Issue 12568 1158 static uint len2(const string s) { // Error 1159 alias mLen2 = memoize!len2; 1160 if (s.length == 0) 1161 return 0; 1162 else 1163 return 1 + mLen2(s[1 .. $]); 1164 } 1165 1166 int _func(int x) @safe { return 1; } 1167 alias func = memoize!(_func, 10); 1168 assert(func(int.init) == 1); 1169 assert(func(int.init) == 1); 1170} 1171 1172// 16079: memoize should work with arrays 1173@safe unittest 1174{ 1175 int executed = 0; 1176 T median(T)(const T[] nums) { 1177 import std.algorithm.sorting : sort; 1178 executed++; 1179 auto arr = nums.dup; 1180 arr.sort(); 1181 if (arr.length % 2) 1182 return arr[$ / 2]; 1183 else 1184 return (arr[$ / 2 - 1] 1185 + arr[$ / 2]) / 2; 1186 } 1187 1188 alias fastMedian = memoize!(median!int); 1189 1190 assert(fastMedian([7, 5, 3]) == 5); 1191 assert(fastMedian([7, 5, 3]) == 5); 1192 1193 assert(executed == 1); 1194} 1195 1196// 16079: memoize should work with structs 1197@safe unittest 1198{ 1199 int executed = 0; 1200 T pickFirst(T)(T first) 1201 { 1202 executed++; 1203 return first; 1204 } 1205 1206 struct Foo { int k; } 1207 Foo A = Foo(3); 1208 1209 alias first = memoize!(pickFirst!Foo); 1210 assert(first(Foo(3)) == A); 1211 assert(first(Foo(3)) == A); 1212 assert(executed == 1); 1213} 1214 1215// 16079: memoize should work with classes 1216@safe unittest 1217{ 1218 int executed = 0; 1219 T pickFirst(T)(T first) 1220 { 1221 executed++; 1222 return first; 1223 } 1224 1225 class Bar 1226 { 1227 size_t k; 1228 this(size_t k) 1229 { 1230 this.k = k; 1231 } 1232 override size_t toHash() 1233 { 1234 return k; 1235 } 1236 override bool opEquals(Object o) 1237 { 1238 auto b = cast(Bar) o; 1239 return b && k == b.k; 1240 } 1241 } 1242 1243 alias firstClass = memoize!(pickFirst!Bar); 1244 assert(firstClass(new Bar(3)).k == 3); 1245 assert(firstClass(new Bar(3)).k == 3); 1246 assert(executed == 1); 1247} 1248 1249private struct DelegateFaker(F) 1250{ 1251 import std.typecons : FuncInfo, MemberFunctionGenerator; 1252 1253 // for @safe 1254 static F castToF(THIS)(THIS x) @trusted 1255 { 1256 return cast(F) x; 1257 } 1258 1259 /* 1260 * What all the stuff below does is this: 1261 *-------------------- 1262 * struct DelegateFaker(F) { 1263 * extern(linkage) 1264 * [ref] ReturnType!F doIt(Parameters!F args) [@attributes] 1265 * { 1266 * auto fp = cast(F) &this; 1267 * return fp(args); 1268 * } 1269 * } 1270 *-------------------- 1271 */ 1272 1273 // We will use MemberFunctionGenerator in std.typecons. This is a policy 1274 // configuration for generating the doIt(). 1275 template GeneratingPolicy() 1276 { 1277 // Inform the genereator that we only have type information. 1278 enum WITHOUT_SYMBOL = true; 1279 1280 // Generate the function body of doIt(). 1281 template generateFunctionBody(unused...) 1282 { 1283 enum generateFunctionBody = 1284 // [ref] ReturnType doIt(Parameters args) @attributes 1285 q{ 1286 // When this function gets called, the this pointer isn't 1287 // really a this pointer (no instance even really exists), but 1288 // a function pointer that points to the function to be called. 1289 // Cast it to the correct type and call it. 1290 1291 auto fp = castToF(&this); 1292 return fp(args); 1293 }; 1294 } 1295 } 1296 // Type information used by the generated code. 1297 alias FuncInfo_doIt = FuncInfo!(F); 1298 1299 // Generate the member function doIt(). 1300 mixin( MemberFunctionGenerator!(GeneratingPolicy!()) 1301 .generateFunction!("FuncInfo_doIt", "doIt", F) ); 1302} 1303 1304/** 1305 * Convert a callable to a delegate with the same parameter list and 1306 * return type, avoiding heap allocations and use of auxiliary storage. 1307 * 1308 * Example: 1309 * ---- 1310 * void doStuff() { 1311 * writeln("Hello, world."); 1312 * } 1313 * 1314 * void runDelegate(void delegate() myDelegate) { 1315 * myDelegate(); 1316 * } 1317 * 1318 * auto delegateToPass = toDelegate(&doStuff); 1319 * runDelegate(delegateToPass); // Calls doStuff, prints "Hello, world." 1320 * ---- 1321 * 1322 * BUGS: 1323 * $(UL 1324 * $(LI Does not work with $(D @safe) functions.) 1325 * $(LI Ignores C-style / D-style variadic arguments.) 1326 * ) 1327 */ 1328auto toDelegate(F)(auto ref F fp) 1329if (isCallable!(F)) 1330{ 1331 static if (is(F == delegate)) 1332 { 1333 return fp; 1334 } 1335 else static if (is(typeof(&F.opCall) == delegate) 1336 || (is(typeof(&F.opCall) V : V*) && is(V == function))) 1337 { 1338 return toDelegate(&fp.opCall); 1339 } 1340 else 1341 { 1342 alias DelType = typeof(&(new DelegateFaker!(F)).doIt); 1343 1344 static struct DelegateFields { 1345 union { 1346 DelType del; 1347 //pragma(msg, typeof(del)); 1348 1349 struct { 1350 void* contextPtr; 1351 void* funcPtr; 1352 } 1353 } 1354 } 1355 1356 // fp is stored in the returned delegate's context pointer. 1357 // The returned delegate's function pointer points to 1358 // DelegateFaker.doIt. 1359 DelegateFields df; 1360 1361 df.contextPtr = cast(void*) fp; 1362 1363 DelegateFaker!(F) dummy; 1364 auto dummyDel = &dummy.doIt; 1365 df.funcPtr = dummyDel.funcptr; 1366 1367 return df.del; 1368 } 1369} 1370 1371/// 1372@system unittest 1373{ 1374 static int inc(ref uint num) { 1375 num++; 1376 return 8675309; 1377 } 1378 1379 uint myNum = 0; 1380 auto incMyNumDel = toDelegate(&inc); 1381 auto returnVal = incMyNumDel(myNum); 1382 assert(myNum == 1); 1383} 1384 1385@system unittest // not @safe due to toDelegate 1386{ 1387 static int inc(ref uint num) { 1388 num++; 1389 return 8675309; 1390 } 1391 1392 uint myNum = 0; 1393 auto incMyNumDel = toDelegate(&inc); 1394 int delegate(ref uint) dg = incMyNumDel; 1395 auto returnVal = incMyNumDel(myNum); 1396 assert(myNum == 1); 1397 1398 interface I { int opCall(); } 1399 class C: I { int opCall() { inc(myNum); return myNum;} } 1400 auto c = new C; 1401 auto i = cast(I) c; 1402 1403 auto getvalc = toDelegate(c); 1404 assert(getvalc() == 2); 1405 1406 auto getvali = toDelegate(i); 1407 assert(getvali() == 3); 1408 1409 struct S1 { int opCall() { inc(myNum); return myNum; } } 1410 static assert(!is(typeof(&s1.opCall) == delegate)); 1411 S1 s1; 1412 auto getvals1 = toDelegate(s1); 1413 assert(getvals1() == 4); 1414 1415 struct S2 { static int opCall() { return 123456; } } 1416 static assert(!is(typeof(&S2.opCall) == delegate)); 1417 S2 s2; 1418 auto getvals2 =&S2.opCall; 1419 assert(getvals2() == 123456); 1420 1421 /* test for attributes */ 1422 { 1423 static int refvar = 0xDeadFace; 1424 1425 static ref int func_ref() { return refvar; } 1426 static int func_pure() pure { return 1; } 1427 static int func_nothrow() nothrow { return 2; } 1428 static int func_property() @property { return 3; } 1429 static int func_safe() @safe { return 4; } 1430 static int func_trusted() @trusted { return 5; } 1431 static int func_system() @system { return 6; } 1432 static int func_pure_nothrow() pure nothrow { return 7; } 1433 static int func_pure_nothrow_safe() pure nothrow @safe { return 8; } 1434 1435 auto dg_ref = toDelegate(&func_ref); 1436 int delegate() pure dg_pure = toDelegate(&func_pure); 1437 int delegate() nothrow dg_nothrow = toDelegate(&func_nothrow); 1438 int delegate() @property dg_property = toDelegate(&func_property); 1439 int delegate() @safe dg_safe = toDelegate(&func_safe); 1440 int delegate() @trusted dg_trusted = toDelegate(&func_trusted); 1441 int delegate() @system dg_system = toDelegate(&func_system); 1442 int delegate() pure nothrow dg_pure_nothrow = toDelegate(&func_pure_nothrow); 1443 int delegate() @safe pure nothrow dg_pure_nothrow_safe = toDelegate(&func_pure_nothrow_safe); 1444 1445 //static assert(is(typeof(dg_ref) == ref int delegate())); // [BUG@DMD] 1446 1447 assert(dg_ref() == refvar); 1448 assert(dg_pure() == 1); 1449 assert(dg_nothrow() == 2); 1450 assert(dg_property() == 3); 1451 assert(dg_safe() == 4); 1452 assert(dg_trusted() == 5); 1453 assert(dg_system() == 6); 1454 assert(dg_pure_nothrow() == 7); 1455 assert(dg_pure_nothrow_safe() == 8); 1456 } 1457 /* test for linkage */ 1458 { 1459 struct S 1460 { 1461 extern(C) static void xtrnC() {} 1462 extern(D) static void xtrnD() {} 1463 } 1464 auto dg_xtrnC = toDelegate(&S.xtrnC); 1465 auto dg_xtrnD = toDelegate(&S.xtrnD); 1466 static assert(! is(typeof(dg_xtrnC) == typeof(dg_xtrnD))); 1467 } 1468} 1469 1470/** 1471Forwards function arguments with saving ref-ness. 1472*/ 1473template forward(args...) 1474{ 1475 static if (args.length) 1476 { 1477 import std.algorithm.mutation : move; 1478 1479 alias arg = args[0]; 1480 static if (__traits(isRef, arg)) 1481 alias fwd = arg; 1482 else 1483 @property fwd()(){ return move(arg); } 1484 alias forward = AliasSeq!(fwd, forward!(args[1..$])); 1485 } 1486 else 1487 alias forward = AliasSeq!(); 1488} 1489 1490/// 1491@safe unittest 1492{ 1493 class C 1494 { 1495 static int foo(int n) { return 1; } 1496 static int foo(ref int n) { return 2; } 1497 } 1498 int bar()(auto ref int x) { return C.foo(forward!x); } 1499 1500 assert(bar(1) == 1); 1501 int i; 1502 assert(bar(i) == 2); 1503} 1504 1505/// 1506@safe unittest 1507{ 1508 void foo(int n, ref string s) { s = null; foreach (i; 0 .. n) s ~= "Hello"; } 1509 1510 // forwards all arguments which are bound to parameter tuple 1511 void bar(Args...)(auto ref Args args) { return foo(forward!args); } 1512 1513 // forwards all arguments with swapping order 1514 void baz(Args...)(auto ref Args args) { return foo(forward!args[$/2..$], forward!args[0..$/2]); } 1515 1516 string s; 1517 bar(1, s); 1518 assert(s == "Hello"); 1519 baz(s, 2); 1520 assert(s == "HelloHello"); 1521} 1522 1523@safe unittest 1524{ 1525 auto foo(TL...)(auto ref TL args) 1526 { 1527 string result = ""; 1528 foreach (i, _; args) 1529 { 1530 //pragma(msg, "[",i,"] ", __traits(isRef, args[i]) ? "L" : "R"); 1531 result ~= __traits(isRef, args[i]) ? "L" : "R"; 1532 } 1533 return result; 1534 } 1535 1536 string bar(TL...)(auto ref TL args) 1537 { 1538 return foo(forward!args); 1539 } 1540 string baz(TL...)(auto ref TL args) 1541 { 1542 int x; 1543 return foo(forward!args[3], forward!args[2], 1, forward!args[1], forward!args[0], x); 1544 } 1545 1546 struct S {} 1547 S makeS(){ return S(); } 1548 int n; 1549 string s; 1550 assert(bar(S(), makeS(), n, s) == "RRLL"); 1551 assert(baz(S(), makeS(), n, s) == "LLRRRL"); 1552} 1553 1554@safe unittest 1555{ 1556 ref int foo(return ref int a) { return a; } 1557 ref int bar(Args)(auto ref Args args) 1558 { 1559 return foo(forward!args); 1560 } 1561 static assert(!__traits(compiles, { auto x1 = bar(3); })); // case of NG 1562 int value = 3; 1563 auto x2 = bar(value); // case of OK 1564} 1565