| @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); |
| } |
| |