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 }