1 /**
2     Contains types that determine the semantics of predicates
3 */
4 module ddash.functional.pred;
5 
6 ///
7 unittest {
8     static struct S(alias pred) {
9         auto f(int a, int b) {
10             static if (isEq!pred) {
11                 return pred(a, b);
12             } else static if (isLt!pred) {
13                 return !pred(a, b) && !pred(b, a);
14             } else {
15                 import std.functional: binaryFun;
16                 return binaryFun!pred(a, b);
17             }
18         }
19     }
20 
21     alias A = S!(eq!((a, b) => a == b));
22     alias B = S!(lt!((a, b) => a < b));
23 
24     assert( A().f(1, 1));
25     assert( B().f(1, 1));
26     assert(!A().f(2, 1));
27     assert(!B().f(2, 1));
28 
29     static bool feq(int a, int b) { return a == b; }
30     static bool flt(int a, int b) { return a < b; }
31 
32     alias C = S!(eq!feq);
33     alias D = S!(lt!flt);
34 
35     assert( C().f(1, 1));
36     assert( D().f(1, 1));
37     assert(!C().f(1, 2));
38     assert(!D().f(1, 2));
39 
40     assert(S!"a == b"().f(1, 1));
41 }
42 
43 /**
44     Used to signify that `pred` is an equality predicate.
45 
46     It must be a function over two arguments that returns a boolean if they are equal
47 */
48 struct eq(alias pred) {
49     alias eq = pred;
50     static auto ref opCall(T, U)(auto ref T a, auto ref U b) { return pred(a, b); }
51 }
52 
53 /// Is true if `pred` is an `eq`
54 template isEq(alias pred) {
55     static if (is(pred : eq!p, p...)) {
56         enum isEq = true;
57     } else {
58         enum isEq = false;
59     }
60 }
61 
62 /**
63     Used to signify that `pred` is a less than predicate
64 
65     It must be a function over two arguments that returns a boolean if arg1 < argb
66 */
67 struct lt(alias pred) {
68     alias lt = pred;
69     static auto ref opCall(T, U)(auto ref T a, auto ref U b) { return pred(a, b); }
70 }
71 
72 /// Is true if `pred` is an `lt`
73 template isLt(alias pred) {
74     static if (is(pred : lt!p, p...)) {
75         enum isLt = true;
76     } else {
77         enum isLt = false;
78     }
79 }
80 
81 unittest {
82     alias plt = lt!((a, b) => a < b);
83     alias peq = eq!((a, b) => a == b);
84 
85     static assert( isEq!peq);
86     static assert(!isEq!plt);
87     static assert( isLt!plt);
88     static assert(!isLt!peq);
89 
90     assert( plt(1, 2));
91     assert(!plt(1, 1));
92     assert(!plt(2, 1));
93 
94     assert(!peq(2, 1));
95     assert(!peq(1, 2));
96     assert( peq(1, 1));
97 }