@safe unittest { import std.functional; // Strings are compiled into functions: alias isEven = unaryFun!("(a & 1) == 0"); assert(isEven(2) && !isEven(1)); } @safe unittest { import std.functional; alias less = binaryFun!("a < b"); assert(less(1, 2) && !less(2, 1)); alias greater = binaryFun!("a > b"); assert(!greater("1", "2") && greater("2", "1")); } pure @safe @nogc nothrow unittest { import std.functional; assert(lessThan(2, 3)); assert(lessThan(2U, 3U)); assert(lessThan(2, 3.0)); assert(lessThan(-2, 3U)); assert(lessThan(2, 3U)); assert(!lessThan(3U, -2)); assert(!lessThan(3U, 2)); assert(!lessThan(0, 0)); assert(!lessThan(0U, 0)); assert(!lessThan(0, 0U)); } @safe unittest { import std.functional; assert(!greaterThan(2, 3)); assert(!greaterThan(2U, 3U)); assert(!greaterThan(2, 3.0)); assert(!greaterThan(-2, 3U)); assert(!greaterThan(2, 3U)); assert(greaterThan(3U, -2)); assert(greaterThan(3U, 2)); assert(!greaterThan(0, 0)); assert(!greaterThan(0U, 0)); assert(!greaterThan(0, 0U)); } @safe unittest { import std.functional; assert(equalTo(0U, 0)); assert(equalTo(0, 0U)); assert(!equalTo(-1, ~0U)); } @safe unittest { import std.functional; alias gt = reverseArgs!(binaryFun!("a < b")); assert(gt(2, 1) && !gt(1, 1)); } @safe unittest { import std.functional; int x = 42; bool xyz(int a, int b) { return a * x < b / x; } auto foo = &xyz; foo(4, 5); alias zyx = reverseArgs!(foo); assert(zyx(5, 4) == foo(4, 5)); } @safe unittest { import std.functional; alias gt = reverseArgs!(binaryFun!("a < b")); assert(gt(2, 1) && !gt(1, 1)); int x = 42; bool xyz(int a, int b) { return a * x < b / x; } auto foo = &xyz; foo(4, 5); alias zyx = reverseArgs!(foo); assert(zyx(5, 4) == foo(4, 5)); } @safe unittest { import std.functional; int abc(int a, int b, int c) { return a * b + c; } alias cba = reverseArgs!abc; assert(abc(91, 17, 32) == cba(32, 17, 91)); } @safe unittest { import std.functional; int a(int a) { return a * 2; } alias _a = reverseArgs!a; assert(a(2) == _a(2)); } @safe unittest { import std.functional; int b() { return 4; } alias _b = reverseArgs!b; assert(b() == _b()); } @safe unittest { import std.functional; import std.algorithm.searching : find; import std.uni : isWhite; string a = " Hello, world!"; assert(find!(not!isWhite)(a) == "Hello, world!"); } @safe unittest { import std.functional; int fun(int a, int b) { return a + b; } alias fun5 = partial!(fun, 5); assert(fun5(6) == 11); // Note that in most cases you'd use an alias instead of a value // assignment. Using an alias allows you to partially evaluate template // functions without committing to a particular type of the function. } @safe unittest { import std.functional; // Overloads are resolved when the partially applied function is called // with the remaining arguments. struct S { static char fun(int i, string s) { return s[i]; } static int fun(int a, int b) { return a * b; } } alias fun3 = partial!(S.fun, 3); assert(fun3("hello") == 'l'); assert(fun3(10) == 30); } pure @safe @nogc nothrow unittest { import std.functional; int f(int x, int y, int z) { return x + y + z; } auto cf = curry!f; auto cf1 = cf(1); auto cf2 = cf(2); assert(cf1(2)(3) == f(1, 2, 3)); assert(cf2(2)(3) == f(2, 2, 3)); } pure @safe @nogc nothrow unittest { import std.functional; //works with callable structs too struct S { int w; int opCall(int x, int y, int z) { return w + x + y + z; } } S s; s.w = 5; auto cs = curry(s); auto cs1 = cs(1); auto cs2 = cs(2); assert(cs1(2)(3) == s(1, 2, 3)); assert(cs1(2)(3) == (1 + 2 + 3 + 5)); assert(cs2(2)(3) ==s(2, 2, 3)); } @safe unittest { import std.functional; import std.typecons : Tuple; static bool f1(int a) { return a != 0; } static int f2(int a) { return a / 2; } auto x = adjoin!(f1, f2)(5); assert(is(typeof(x) == Tuple!(bool, int))); assert(x[0] == true && x[1] == 2); } @safe unittest { import std.functional; import std.algorithm.comparison : equal; import std.algorithm.iteration : map; import std.array : split; import std.conv : to; // First split a string in whitespace-separated tokens and then // convert each token into an integer assert(compose!(map!(to!(int)), split)("1 2 3").equal([1, 2, 3])); } @safe unittest { import std.functional; import std.conv : to; string foo(int a) { return to!(string)(a); } int bar(string a) { return to!(int)(a) + 1; } double baz(int a) { return a + 0.5; } assert(compose!(baz, bar, foo)(1) == 2.5); assert(pipe!(foo, bar, baz)(1) == 2.5); assert(compose!(baz, `to!(int)(a) + 1`, foo)(1) == 2.5); assert(compose!(baz, bar)("1"[]) == 2.5); assert(compose!(baz, bar)("1") == 2.5); assert(compose!(`a + 0.5`, `to!(int)(a) + 1`, foo)(1) == 2.5); } @safe nothrow unittest { import std.functional; ulong fib(ulong n) @safe nothrow { return n < 2 ? n : memoize!fib(n - 2) + memoize!fib(n - 1); } assert(fib(10) == 55); } @safe unittest { import std.functional; ulong fact(ulong n) @safe { return n < 2 ? 1 : n * memoize!fact(n - 1); } assert(fact(10) == 3628800); } @safe unittest { import std.functional; ulong factImpl(ulong n) @safe { return n < 2 ? 1 : n * factImpl(n - 1); } alias fact = memoize!factImpl; assert(fact(10) == 3628800); } @system unittest { import std.functional; ulong fact(ulong n) { // Memoize no more than 8 values return n < 2 ? 1 : n * memoize!(fact, 8)(n - 1); } assert(fact(8) == 40320); // using more entries than maxSize will overwrite existing entries assert(fact(10) == 3628800); } @safe unittest { import std.functional; static int inc(ref uint num) { num++; return 8675309; } uint myNum = 0; auto incMyNumDel = toDelegate(&inc); auto returnVal = incMyNumDel(myNum); assert(myNum == 1); } @safe unittest { import std.functional; import std.typecons : tuple; auto name = tuple("John", "Doe"); string full = name.bind!((first, last) => first ~ " " ~ last); assert(full == "John Doe"); } @safe unittest { import std.functional; import std.algorithm.comparison : min, max; struct Pair { int a; int b; } auto p = Pair(123, 456); assert(p.bind!min == 123); // min(p.a, p.b) assert(p.bind!max == 456); // max(p.a, p.b) } @safe unittest { import std.functional; import std.algorithm.iteration : map, filter; import std.algorithm.comparison : equal; import std.typecons : tuple; auto ages = [ tuple("Alice", 35), tuple("Bob", 64), tuple("Carol", 21), tuple("David", 39), tuple("Eve", 50) ]; auto overForty = ages .filter!(bind!((name, age) => age > 40)) .map!(bind!((name, age) => name)); assert(overForty.equal(["Bob", "Eve"])); } @safe unittest { import std.functional; import std.math : abs; // No explicit `enum` needed. float result = ctEval!(abs(-3)); assert(result == 3); // Can be statically asserted. static assert(ctEval!(abs(-4)) == 4); static assert(ctEval!(abs( 9)) == 9); } @safe unittest { import std.functional; import core.stdc.math : round; import std.conv : to; import std.math : abs, PI, sin; // `round` from the C standard library cannot be interpreted at compile // time, because it has no available source code. However the function // calls preceding `round` can be evaluated during compile time. int result = ctEval!(abs(sin(1.0)) * 180 / PI) .round() .to!int(); assert(result == 48); }