1 /++ Algorithms that either improve or complement std.algorithm.comparison.`
2  +/
3 module nxt.algorithm.comparison;
4 
5 // version = unittestAsBetterC; // Run_As: dmd -betterC -unittest -run $(__FILE__).d
6 
7 import std.range.primitives : isInputRange, isInfinite, ElementType;
8 
9 // Use until `std.algorithm.comparison.equal` supports uncopyable parameters.
10 bool equal(T, U)(scope T a, scope U b)
11 if (!(isInfinite!T &&
12 	  isInfinite!U)) {
13 	static if ((is(T == TE[M], TE, size_t M)) &&
14 			   (is(U == UE[N], UE, size_t N)) &&
15 			   is(typeof(TE.init == UE.init) : bool)) /+ static array +/ {
16 		static if (M != N)
17 			return false;
18 		else {
19 			foreach (const i; 0 .. M)
20 				if (a[i] != b[i])
21 					return false;
22 			return true;
23 		}
24 	} else static if ((is(T == TA[], TA)) &&
25 					(is(U == UA[], UA)) &&
26 					is(typeof(TA.init == UA.init) : bool)) /+ dynamic array +/ {
27 		if (a.length != b.length)
28 			return false;
29 		const N = a.length;
30 		foreach (const i; 0 .. N)
31 			if (a[i] != b[i])
32 				return false;
33 		return true;
34 	} else static if (is(typeof(ElementType!T.init == ElementType!U.init) : bool)) {
35 		static if (is(typeof(a[size_t.init]))) {
36 			import std.algorithm.mutation : move;
37 			size_t i = 0;
38 			foreach (const ref be; move(b))
39 				if (a[i++] != be)
40 					return false;
41 			return true;
42 		} else static if (is(typeof(b[size_t.init]))) {
43 			import std.algorithm.mutation : move;
44 			size_t i = 0;
45 			foreach (const ref ae; move(a))
46 				if (ae != b[i++])
47 					return false;
48 			return true;
49 		} else {
50 			while (true) {
51 				if (a.empty())
52 					return b.empty();
53 				if (b.empty())
54 					return a.empty();
55 				if (a.front != b.front)
56 					return false;
57 				a.popFront();
58 				b.popFront();
59 			}
60 		}
61 	} else
62 		static assert(0, "Cannot compare " ~ T.stringof ~ "with" ~ U.stringof);
63 }
64 /// ditto
65 bool equal(T, U)(scope const(T)[] a, scope const(U)[] b)
66 if (is(typeof(T.init == U.init) : bool)) {
67 }
68 
69 /// dynamic arrays
70 pure nothrow @safe @nogc unittest {
71 	assert(!equal([1, 2   ].s[], [1, 2, 3].s[]));
72 	assert(!equal([1, 2, 3].s[], [1, 2,  ].s[]));
73 	assert( equal([1, 2, 3].s[], [1, 2, 3].s[]));
74 }
75 
76 /// static arrays
77 pure nothrow @safe @nogc unittest {
78 	assert(!equal([1, 2   ].s, [1, 2, 3].s));
79 	assert(!equal([1, 2, 3].s, [1, 2,  ].s));
80 	assert( equal([1, 2, 3].s, [1, 2, 3].s));
81 }
82 
83 version (unittest) {
84 	import nxt.array_help : s;
85 }
86 
87 // See_Also: https://dlang.org/spec/betterc.html#unittests
88 version (unittestAsBetterC)
89 extern(C) void main() {
90 	static foreach (u; __traits(getUnitTests, __traits(parent, main))) {
91 		u();
92 	}
93 }