1 /** Predicate extensions to std.algorithm.
2     Copyright: Per Nordlöw 2022-.
3     License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
4     Authors: $(WEB Per Nordlöw)
5    */
6 module nxt.predicates;
7 
8 import std.range.primitives : ElementType;
9 
10 // ==============================================================================================
11 
12 import std.range: isInputRange;
13 
14 /** Returns: `true` iff all elements in range are equal (or range is empty).
15     http://stackoverflow.com/questions/19258556/equality-of-all-elements-in-a-range/19292822?noredirect=1#19292822
16 
17     Possible alternatives or aliases: allElementsEqual, haveEqualElements
18 */
19 bool allEqual(R)(R range)
20 if (isInputRange!R)
21 {
22     import std.algorithm: findAdjacent;
23     import std.range: empty;
24     return range.findAdjacent!("a != b").empty;
25 }
26 @safe pure nothrow unittest { assert([11, 11].allEqual); }
27 @safe pure nothrow unittest { assert(![11, 12].allEqual); }
28 @safe pure nothrow unittest { int[] x; assert(x.allEqual); }
29 
30 /* See_Also: http://forum.dlang.org/thread/febepworacvbapkpozjl@forum.dlang.org#post-gbqvablzsbdowqoijxpn:40forum.dlang.org */
31 /* import std.range: InputRange; */
32 /* bool allEqual_(T)(InputRange!T range) @safe pure nothrow */
33 /* { */
34 /*     import std.algorithm: findAdjacent; */
35 /*     import std.range: empty; */
36 /*     return range.findAdjacent!("a != b").empty; */
37 /* } */
38 /* @safe pure nothrow unittest { assert([11, 11].allEqual_); } */
39 /* @safe pure nothrow unittest { assert(![11, 12].allEqual_); } */
40 /* @safe pure nothrow unittest { int[] x; assert(x.allEqual_); } */
41 
42 /** Returns: `true` iff all elements in range are equal (or range is empty) to $(D element).
43 
44     Possible alternatives or aliases: allElementsEqualTo
45 */
46 bool allEqualTo(R, E)(R range, E element)
47 if (isInputRange!R &&
48     is(ElementType!R == E))
49 {
50     import std.algorithm: all;
51     return range.all!(a => a == element);
52 }
53 
54 ///
55 @safe pure nothrow unittest
56 {
57 	assert([42, 42].allEqualTo(42));
58 }
59 
60 // ==============================================================================================
61 
62 /** Check if all Elements of $(D x) are zero. */
63 bool allZero(T, bool useStatic = true)(in T x)
64 {
65     static if (is(T == struct) || is(T == class))
66     {
67         foreach (const ref elt; x.tupleof)
68             if (!elt.allZero)
69 				return false;
70         return true;
71     }
72 	else
73 	{
74 		import std.traits : isIterable;
75 		static if (useStatic && __traits(isStaticArray, T))
76 		{
77 			static foreach (ix; 0 .. x.length) // TODO: do we need static iota here?
78 				if (!x[ix].allZero)
79 					return false; // make use of iota?
80 			return true;
81 		}
82 		else static if (isIterable!T)
83 		{
84 			foreach (const ref elt; x)
85 				if (!elt.allZero)
86 					return false;
87 			return true;
88 		}
89 		else
90 			return x == 0;
91 	}
92 }
93 /// ditto
94 alias zeroed = allZero;
95 
96 ///
97 @safe pure nothrow unittest
98 {
99     ubyte[20] d;
100     assert(d.allZero);     // note that [] is needed here
101 
102     ubyte[2][2] zeros = [ [0, 0],
103                           [0, 0] ];
104     assert(zeros.allZero);
105 
106     ubyte[2][2] one = [ [0, 1],
107                         [0, 0] ];
108     assert(!one.allZero);
109 
110     ubyte[2][2] ones = [ [1, 1],
111                          [1, 1] ];
112     assert(!ones.allZero);
113 
114     ubyte[2][2][2] zeros3d = [ [ [0, 0],
115                                  [0, 0] ],
116                                [ [0, 0],
117                                  [0, 0] ] ];
118     assert(zeros3d.allZero);
119 
120     ubyte[2][2][2] ones3d = [ [ [1, 1],
121                                 [1, 1] ],
122                               [ [1, 1],
123                                 [1, 1] ] ];
124     assert(!ones3d.allZero);
125 }
126 
127 ///
128 @safe pure nothrow unittest
129 {
130     struct Vec { real x, y; }
131     const v0 = Vec(0, 0);
132     assert(v0.zeroed);
133     const v1 = Vec(1, 1);
134     assert(!v1.zeroed);
135 }
136 
137 ///
138 @safe pure nothrow unittest
139 {
140     class Vec
141     {
142         this(real x, real y) { this.x = x; this.y = y; }
143         real x, y;
144     }
145     const v0 = new Vec(0, 0);
146     assert(v0.zeroed);
147     const v1 = new Vec(1, 1);
148     assert(!v1.zeroed);
149 }