From a86b6690f072742367ade5ad5c55f80b28c95bdf Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Tue, 12 Jun 2018 20:19:06 +0200 Subject: [PATCH] Implement auto-decoding free equal comparison Fix #39. --- arch/x64/linux/memory/cmp.S | 1 + source/tanya/algorithm/comparison.d | 61 +++++++++++++++++++++++++++++ source/tanya/container/array.d | 1 - source/tanya/container/list.d | 3 +- source/tanya/container/string.d | 2 +- source/tanya/math/mp.d | 2 +- source/tanya/memory/op.d | 5 +++ 7 files changed, 70 insertions(+), 5 deletions(-) diff --git a/arch/x64/linux/memory/cmp.S b/arch/x64/linux/memory/cmp.S index 169e2eb..64d3ca6 100644 --- a/arch/x64/linux/memory/cmp.S +++ b/arch/x64/linux/memory/cmp.S @@ -47,6 +47,7 @@ _D5tanya6memory2op9cmpMemoryFNaNbNixAvxAvZi: aligned_1: // Compare the remaining bytes mov %rdx, %rcx + cmp $0x0, %rcx repe cmpsb jl less diff --git a/source/tanya/algorithm/comparison.d b/source/tanya/algorithm/comparison.d index f8e1c60..61dbcf6 100644 --- a/source/tanya/algorithm/comparison.d +++ b/source/tanya/algorithm/comparison.d @@ -16,6 +16,7 @@ module tanya.algorithm.comparison; import tanya.algorithm.mutation; import tanya.math : isNaN; +import tanya.memory.op; import tanya.meta.metafunction; import tanya.meta.trait; import tanya.meta.transform; @@ -270,3 +271,63 @@ if (isForwardRange!Range && isOrderingComparable!(ElementType!Range)) assert(max(s2, s3).s == 3); } } + +/** + * Compares element-wise two ranges for equality. + * + * If the ranges have different lengths, they aren't equal. + * + * Params: + * R1 = First range type. + * R2 = Second range type. + * range1 = First range. + * range2 = Second range. + * + * Returns: $(D_KEYWORD true) if both ranges are equal, $(D_KEYWORD false) + * otherwise. + */ +bool equal(R1, R2)(R1 r1, R2 r2) +if (allSatisfy!(isInputRange, R1, R2) && is(typeof(r1.front == r2.front))) +{ + static if (isDynamicArray!R1 + && is(R1 == R2) + && __traits(isPOD, ElementType!R1)) + { + return cmp(r1, r2) == 0; + } + else + { + static if (hasLength!R1 && hasLength!R2) + { + if (r1.length != r2.length) + { + return false; + } + } + for (; !r1.empty && !r2.empty; r1.popFront(), r2.popFront()) + { + if (r1.front != r2.front) + { + return false; + } + } + static if (hasLength!R1 && hasLength!R2) + { + return true; + } + else + { + return r1.empty && r2.empty; + } + } +} + +/// +@nogc nothrow pure @safe unittest +{ + int[2] range1 = [1, 2]; + assert(equal(range1[], range1[])); + + int[3] range2 = [1, 2, 3]; + assert(!equal(range1[], range2[])); +} diff --git a/source/tanya/container/array.d b/source/tanya/container/array.d index 8f34847..59cc3fb 100644 --- a/source/tanya/container/array.d +++ b/source/tanya/container/array.d @@ -15,7 +15,6 @@ module tanya.container.array; import core.checkedint; -import std.algorithm.comparison : equal; import std.algorithm.mutation : bringToFront, copy, fill, diff --git a/source/tanya/container/list.d b/source/tanya/container/list.d index 23467e5..64ea740 100644 --- a/source/tanya/container/list.d +++ b/source/tanya/container/list.d @@ -15,7 +15,6 @@ */ module tanya.container.list; -import std.algorithm.comparison : equal; import std.algorithm.searching; import tanya.algorithm.comparison; import tanya.algorithm.mutation; @@ -574,7 +573,7 @@ struct SList(T) */ bool opEquals()(auto ref typeof(this) that) inout { - return equal(this[], that[]); + return equal(opIndex(), that[]); } /// diff --git a/source/tanya/container/string.d b/source/tanya/container/string.d index 54c0200..ad8fa82 100644 --- a/source/tanya/container/string.d +++ b/source/tanya/container/string.d @@ -26,7 +26,7 @@ */ module tanya.container.string; -import std.algorithm.comparison : cmp, equal; +import std.algorithm.comparison : cmp; import std.algorithm.mutation : bringToFront, copy; import std.algorithm.searching; import tanya.algorithm.comparison; diff --git a/source/tanya/math/mp.d b/source/tanya/math/mp.d index b98fbd7..ae365de 100644 --- a/source/tanya/math/mp.d +++ b/source/tanya/math/mp.d @@ -14,7 +14,7 @@ */ module tanya.math.mp; -import std.algorithm.comparison : cmp, equal; +import std.algorithm.comparison : cmp; import std.algorithm.mutation : copy, fill, reverse; import std.range; import tanya.algorithm.comparison; diff --git a/source/tanya/memory/op.d b/source/tanya/memory/op.d index 0a73020..ec9bc2e 100644 --- a/source/tanya/memory/op.d +++ b/source/tanya/memory/op.d @@ -40,6 +40,11 @@ version (TanyaNative) fillMemory(buffer[1 .. $], 0); assert(buffer[0] == 1 && buffer[1] == 0); } + + @nogc nothrow pure @safe unittest + { + assert(cmp(null, null) == 0); + } } private enum alignMask = size_t.sizeof - 1;