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