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