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