1 #!/usr/bin/env rdmd-dev-module 2 3 /** Predicate extensions to std.algorithm. 4 Copyright: Per Nordlöw 2014-. 5 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 Authors: $(WEB Per Nordlöw) 7 */ 8 module predicates; 9 10 import std.traits: CommonType; 11 import std.range: isIterable, ElementType; 12 import std.algorithm: among; 13 14 /** Return true if $(D x) is a equal to any of $(D ys). 15 TODO Make $(D ys) lazy if any of $(D ys) is a delegate. 16 TODO Reuse $(D among) 17 */ 18 bool of(S, T...)(in S x, in T ys) pure if (ys.length >= 1 && 19 is(typeof({ return S.init == 20 CommonType!(T).init; }))) 21 { 22 foreach (y; ys) 23 { 24 if (x == y) 25 return true; 26 } 27 return false; 28 } 29 30 @safe @nogc pure nothrow unittest 31 { 32 assert(1.of(1, 2, 3)); 33 assert(!4.of(1, 2, 3)); 34 } 35 36 /** Return true if $(D x) is a equal to any of $(D ys). 37 TODO Reuse $(D among) 38 */ 39 bool of(E, R)(E x, R ys) pure if (isIterable!R/* && */ 40 /* is(E.init == ElementType!R.init) */) 41 { 42 import std.range: isNarrowString; 43 static if (isNarrowString!R) 44 { 45 import std.algorithm: canFind; 46 return ys.canFind(x); 47 } 48 else 49 { 50 foreach (y; ys) 51 if (x == y) 52 return true; 53 return false; 54 } 55 } 56 57 @safe pure nothrow unittest 58 { 59 assert(1.of([1, 2, 3])); 60 assert(!4.of([1, 2, 3])); 61 } 62 63 @safe pure unittest 64 { 65 assert('a'.of("abc")); 66 assert(!'z'.of("abc")); 67 assert('å'.of("åäö")); 68 } 69 70 alias isEither = of; 71 72 // ============================================================================================== 73 74 import std.range: isInputRange; 75 76 /** Returns: true iff all elements in range are equal (or range is empty). 77 http://stackoverflow.com/questions/19258556/equality-of-all-elements-in-a-range/19292822?noredirect=1#19292822 78 79 Possible alternatives or aliases: allElementsEqual, haveEqualElements 80 */ 81 bool allEqual(R)(R range) /* pure @safe @nogc nothrow */ if (isInputRange!R) 82 { 83 import std.algorithm: findAdjacent; 84 import std.range: empty; 85 return range.findAdjacent!("a != b").empty; 86 } 87 unittest { assert([11, 11].allEqual); } 88 unittest { assert(![11, 12].allEqual); } 89 unittest { int[] x; assert(x.allEqual); } 90 91 /* See also: http://forum.dlang.org/thread/febepworacvbapkpozjl@forum.dlang.org#post-gbqvablzsbdowqoijxpn:40forum.dlang.org */ 92 /* import std.range: InputRange; */ 93 /* bool allEqual_(T)(InputRange!T range) @safe pure nothrow */ 94 /* { */ 95 /* import std.algorithm: findAdjacent; */ 96 /* import std.range: empty; */ 97 /* return range.findAdjacent!("a != b").empty; */ 98 /* } */ 99 /* unittest { assert([11, 11].allEqual_); } */ 100 /* unittest { assert(![11, 12].allEqual_); } */ 101 /* unittest { int[] x; assert(x.allEqual_); } */ 102 103 /** Returns: true iff all elements in range are equal (or range is empty) to $(D element). 104 105 Possible alternatives or aliases: allElementsEqualTo 106 */ 107 bool allEqualTo(R, E)(R range, E element) @safe pure nothrow if (isInputRange!R && 108 is(ElementType!R == E)) 109 { 110 import std.algorithm: all; 111 return range.all!(a => a == element); 112 } 113 unittest { assert([42, 42].allEqualTo(42)); } 114 115 // ============================================================================================== 116 117 import traits_ex: isStruct, isClass; 118 import std.traits: isStaticArray; 119 120 /** Check if all Elements of $(D x) are zero. */ 121 bool allZero(T, bool useStatic = true)(in T x) @safe @nogc pure nothrow 122 { 123 static if (isStruct!T || isClass!T) 124 { 125 foreach (const ref elt; x.tupleof) 126 { 127 if (!elt.allZero) { return false; } 128 } 129 return true; 130 } 131 else static if (useStatic && isStaticArray!T) 132 { 133 import range_ex: iota; 134 foreach (ix; iota!(0, x.length)) 135 { 136 if (!x[ix].allZero) { return false; } // make use of iota? 137 } 138 return true; 139 } 140 else static if (isIterable!T) 141 { 142 foreach (const ref elt; x) 143 { 144 if (!elt.allZero) { return false; } 145 } 146 return true; 147 } 148 else 149 { 150 return x == 0; 151 } 152 } 153 154 alias zeroed = allZero; 155 156 unittest 157 { 158 ubyte[20] d; 159 assert(d.allZero); // note that [] is needed here 160 161 ubyte[2][2] zeros = [ [0, 0], 162 [0, 0] ]; 163 assert(zeros.allZero); 164 165 ubyte[2][2] one = [ [0, 1], 166 [0, 0] ]; 167 assert(!one.allZero); 168 169 ubyte[2][2] ones = [ [1, 1], 170 [1, 1] ]; 171 assert(!ones.allZero); 172 173 ubyte[2][2][2] zeros3d = [ [ [0, 0], 174 [0, 0] ], 175 [ [0, 0], 176 [0, 0] ] ]; 177 assert(zeros3d.allZero); 178 179 ubyte[2][2][2] ones3d = [ [ [1, 1], 180 [1, 1] ], 181 [ [1, 1], 182 [1, 1] ] ]; 183 assert(!ones3d.allZero); 184 } 185 186 unittest 187 { 188 struct Vec { real x, y; } 189 const v0 = Vec(0, 0); 190 assert(v0.zeroed); 191 const v1 = Vec(1, 1); 192 assert(!v1.zeroed); 193 } 194 195 unittest 196 { 197 class Vec 198 { 199 this(real x, real y) { this.x = x; this.y = y; } 200 real x, y; 201 } 202 const v0 = new Vec(0, 0); 203 assert(v0.zeroed); 204 const v1 = new Vec(1, 1); 205 assert(!v1.zeroed); 206 } 207 208 /** Returns: true iff $(D a) is set to the default/initial value of its type $(D T). 209 */ 210 bool isDefaulted(T)(in T a) @safe pure nothrow @nogc 211 { 212 import std.traits: isInstanceOf; 213 import std.typecons: Nullable; 214 static if (isInstanceOf!(Nullable, T)) 215 { 216 return a.isNull; 217 } 218 else 219 { 220 return a == T.init; 221 } 222 } 223 alias isUntouched = isDefaulted; 224 alias isInited = isDefaulted; 225 226 /** Check if $(D x) is a power of 2 (binary power). 227 See also: http://forum.dlang.org/thread/zumhmosfkvwjymjhmtlt@forum.dlang.org#post-fvnmurrctavpfkunssdf:40forum.dlang.org 228 */ 229 bool isPowerOf2(uint x) @safe pure nothrow @nogc 230 { 231 return (x & -x) > (x - 1); 232 } 233 234 @safe pure nothrow @nogc unittest 235 { 236 assert(!0.isPowerOf2); 237 assert(1.isPowerOf2); 238 assert(2.isPowerOf2); 239 assert(!3.isPowerOf2); 240 assert(4.isPowerOf2); 241 assert(!5.isPowerOf2); 242 assert(!6.isPowerOf2); 243 assert(!7.isPowerOf2); 244 assert(8.isPowerOf2); 245 }