blob: 50b37f35d4ccf3fa585296b0ba9d82842e1ce510 [file] [log] [blame]
@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);
}