Replace memory.op.cmp with optimized equal version
Deprecate cmp. Fix #68.
This commit is contained in:
		@@ -6,9 +6,9 @@ rule archive
 | 
			
		||||
 | 
			
		||||
build abs.o: gas x64/linux/math/abs.S
 | 
			
		||||
build log.o: gas x64/linux/math/log.S
 | 
			
		||||
build cmp.o: gas x64/linux/memory/cmp.S
 | 
			
		||||
build equal.o: gas x64/linux/memory/equal.S
 | 
			
		||||
build fill.o: gas x64/linux/memory/fill.S
 | 
			
		||||
build copy.o: gas x64/linux/memory/copy.S
 | 
			
		||||
build syscall.o: gas x64/linux/syscall.S
 | 
			
		||||
 | 
			
		||||
build tanya.a: archive syscall.o copy.o fill.o cmp.o log.o abs.o
 | 
			
		||||
build tanya.a: archive syscall.o copy.o fill.o equal.o log.o abs.o
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +1,19 @@
 | 
			
		||||
	.text
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * cmpMemory.
 | 
			
		||||
 * equalMemory.
 | 
			
		||||
 *
 | 
			
		||||
 * rdi - r1 length
 | 
			
		||||
 * rsi - r1 data.
 | 
			
		||||
 * rdx - r2 length.
 | 
			
		||||
 * rcx - r2 data.
 | 
			
		||||
 */
 | 
			
		||||
	.globl _D5tanya6memory2op9cmpMemoryFNaNbNixAvxQdZi
 | 
			
		||||
	.type _D5tanya6memory2op9cmpMemoryFNaNbNixAvxQdZi, @function
 | 
			
		||||
_D5tanya6memory2op9cmpMemoryFNaNbNixAvxQdZi:
 | 
			
		||||
	.globl _D5tanya6memory2op11equalMemoryFNaNbNixAvxQdZb
 | 
			
		||||
	.type _D5tanya6memory2op11equalMemoryFNaNbNixAvxQdZb, @function
 | 
			
		||||
_D5tanya6memory2op11equalMemoryFNaNbNixAvxQdZb:
 | 
			
		||||
		// Compare the lengths
 | 
			
		||||
		cmp %rdx, %rdi
 | 
			
		||||
		jl  less
 | 
			
		||||
		jg  greater
 | 
			
		||||
		jne not_equal
 | 
			
		||||
 | 
			
		||||
		mov %rcx, %rdi
 | 
			
		||||
 | 
			
		||||
@@ -26,8 +25,7 @@ _D5tanya6memory2op9cmpMemoryFNaNbNixAvxQdZi:
 | 
			
		||||
 | 
			
		||||
	naligned:
 | 
			
		||||
		cmpsb
 | 
			
		||||
		jl less
 | 
			
		||||
		jg greater
 | 
			
		||||
		jne not_equal
 | 
			
		||||
 | 
			
		||||
		dec %rdx
 | 
			
		||||
		test $0x07, %edi
 | 
			
		||||
@@ -38,8 +36,7 @@ _D5tanya6memory2op9cmpMemoryFNaNbNixAvxQdZi:
 | 
			
		||||
		shr $0x03, %rcx
 | 
			
		||||
 | 
			
		||||
		repe cmpsq
 | 
			
		||||
		jl less
 | 
			
		||||
		jg greater
 | 
			
		||||
		jne not_equal
 | 
			
		||||
 | 
			
		||||
		and $0x07, %edx
 | 
			
		||||
		jz equal
 | 
			
		||||
@@ -49,19 +46,14 @@ _D5tanya6memory2op9cmpMemoryFNaNbNixAvxQdZi:
 | 
			
		||||
		cmp $0x0, %rcx
 | 
			
		||||
 | 
			
		||||
		repe cmpsb
 | 
			
		||||
		jl less
 | 
			
		||||
		jg greater
 | 
			
		||||
		jne not_equal
 | 
			
		||||
 | 
			
		||||
	equal:
 | 
			
		||||
		mov $0x01, %rax // Return 1
 | 
			
		||||
		jmp end
 | 
			
		||||
 | 
			
		||||
	not_equal:
 | 
			
		||||
		xor %rax, %rax // Return 0
 | 
			
		||||
		jmp end
 | 
			
		||||
 | 
			
		||||
	greater:
 | 
			
		||||
		mov $0x01, %rax
 | 
			
		||||
		jmp end
 | 
			
		||||
 | 
			
		||||
	less:
 | 
			
		||||
		mov $-0x01, %rax
 | 
			
		||||
 | 
			
		||||
	end:
 | 
			
		||||
		ret
 | 
			
		||||
@@ -15,8 +15,8 @@
 | 
			
		||||
module tanya.algorithm.comparison;
 | 
			
		||||
 | 
			
		||||
import tanya.algorithm.mutation;
 | 
			
		||||
import tanya.math : isNaN;
 | 
			
		||||
import tanya.memory.op;
 | 
			
		||||
import tanya.math;
 | 
			
		||||
static import tanya.memory.op;
 | 
			
		||||
import tanya.meta.metafunction;
 | 
			
		||||
import tanya.meta.trait;
 | 
			
		||||
import tanya.meta.transform;
 | 
			
		||||
@@ -296,7 +296,7 @@ if (allSatisfy!(isInputRange, R1, R2)
 | 
			
		||||
            && is(R1 == R2)
 | 
			
		||||
            && __traits(isPOD, ElementType!R1))
 | 
			
		||||
    {
 | 
			
		||||
        return cmp(r1, r2) == 0;
 | 
			
		||||
        return tanya.memory.op.equal(r1, r2);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ import tanya.algorithm.comparison;
 | 
			
		||||
import tanya.container.string;
 | 
			
		||||
import tanya.encoding.ascii;
 | 
			
		||||
import tanya.math;
 | 
			
		||||
import tanya.memory.op;
 | 
			
		||||
static import tanya.memory.op;
 | 
			
		||||
import tanya.meta.metafunction;
 | 
			
		||||
import tanya.meta.trait;
 | 
			
		||||
import tanya.meta.transform;
 | 
			
		||||
@@ -1351,7 +1351,7 @@ do
 | 
			
		||||
        intSlice.popBack();
 | 
			
		||||
    }
 | 
			
		||||
    const begin = buffer.length - intSlice.length;
 | 
			
		||||
    copy(intSlice, buffer[begin .. $]);
 | 
			
		||||
    tanya.memory.op.copy(intSlice, buffer[begin .. $]);
 | 
			
		||||
 | 
			
		||||
    exponent = cast(int) (intSlice.length + mismatch);
 | 
			
		||||
 | 
			
		||||
@@ -1388,7 +1388,7 @@ do
 | 
			
		||||
 | 
			
		||||
    char[21] intBuffer;
 | 
			
		||||
    auto intSlice = integral2String(decimal, intBuffer);
 | 
			
		||||
    copy(intSlice, buffer);
 | 
			
		||||
    tanya.memory.op.copy(intSlice, buffer);
 | 
			
		||||
    exponent = cast(int) intSlice.length;
 | 
			
		||||
 | 
			
		||||
    size_t position = exponent;
 | 
			
		||||
@@ -1903,7 +1903,7 @@ private char[] errol3(double value,
 | 
			
		||||
        if (pathologies[middle].representation == bits.integral)
 | 
			
		||||
        {
 | 
			
		||||
            exponent = pathologies[middle].exponent;
 | 
			
		||||
            copy(pathologies[middle].digits, buffer);
 | 
			
		||||
            tanya.memory.op.copy(pathologies[middle].digits, buffer);
 | 
			
		||||
            return buffer[0 .. pathologies[middle].digits.length];
 | 
			
		||||
        }
 | 
			
		||||
        else if (pathologies[middle].representation < bits.integral)
 | 
			
		||||
@@ -2054,7 +2054,7 @@ if (isFloatingPoint!T)
 | 
			
		||||
        {
 | 
			
		||||
            length = precision + 1;
 | 
			
		||||
        }
 | 
			
		||||
        realString[1 .. length].copy(bufferSlice);
 | 
			
		||||
        tanya.memory.op.copy(realString[1 .. length], bufferSlice);
 | 
			
		||||
        bufferSlice.popFrontExactly(length - 1);
 | 
			
		||||
 | 
			
		||||
        // Dump the exponent.
 | 
			
		||||
@@ -2116,7 +2116,7 @@ if (isFloatingPoint!T)
 | 
			
		||||
                n = precision;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            fill!'0'(bufferSlice[0 .. n]);
 | 
			
		||||
            tanya.memory.op.fill!'0'(bufferSlice[0 .. n]);
 | 
			
		||||
            bufferSlice.popFrontExactly(n);
 | 
			
		||||
 | 
			
		||||
            if ((length + n) > precision)
 | 
			
		||||
@@ -2124,7 +2124,7 @@ if (isFloatingPoint!T)
 | 
			
		||||
                length = precision - n;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            realString[0 .. length].copy(bufferSlice);
 | 
			
		||||
            tanya.memory.op.copy(realString[0 .. length], bufferSlice);
 | 
			
		||||
            bufferSlice.popFrontExactly(length);
 | 
			
		||||
        }
 | 
			
		||||
        else if (cast(uint) decimalPoint >= length)
 | 
			
		||||
@@ -2142,7 +2142,7 @@ if (isFloatingPoint!T)
 | 
			
		||||
            {
 | 
			
		||||
                n = decimalPoint - n;
 | 
			
		||||
 | 
			
		||||
                fill!'0'(bufferSlice[0 .. n]);
 | 
			
		||||
                tanya.memory.op.fill!'0'(bufferSlice[0 .. n]);
 | 
			
		||||
                bufferSlice.popFrontExactly(n);
 | 
			
		||||
            }
 | 
			
		||||
            if (precision != 0)
 | 
			
		||||
@@ -2173,7 +2173,7 @@ if (isFloatingPoint!T)
 | 
			
		||||
                length = precision + decimalPoint;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            realString[n .. length].copy(bufferSlice);
 | 
			
		||||
            tanya.memory.op.copy(realString[n .. length], bufferSlice);
 | 
			
		||||
            bufferSlice.popFrontExactly(length - n);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@ version (TanyaNative)
 | 
			
		||||
    extern private void moveMemory(const void[], void[])
 | 
			
		||||
    pure nothrow @system @nogc;
 | 
			
		||||
 | 
			
		||||
    extern private int cmpMemory(const void[], const void[])
 | 
			
		||||
    extern private bool equalMemory(const void[], const void[])
 | 
			
		||||
    pure nothrow @system @nogc;
 | 
			
		||||
}
 | 
			
		||||
else
 | 
			
		||||
@@ -43,7 +43,7 @@ version (TanyaNative)
 | 
			
		||||
 | 
			
		||||
    @nogc nothrow pure @safe unittest
 | 
			
		||||
    {
 | 
			
		||||
        assert(cmp(null, null) == 0);
 | 
			
		||||
        assert(equal(null, null));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -91,7 +91,7 @@ do
 | 
			
		||||
    ubyte[9] source = [1, 2, 3, 4, 5, 6, 7, 8, 9];
 | 
			
		||||
    ubyte[9] target;
 | 
			
		||||
    source.copy(target);
 | 
			
		||||
    assert(cmp(source, target) == 0);
 | 
			
		||||
    assert(equal(source, target));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@nogc nothrow pure @safe unittest
 | 
			
		||||
@@ -110,7 +110,7 @@ do
 | 
			
		||||
        ubyte[8] source = [1, 2, 3, 4, 5, 6, 7, 8];
 | 
			
		||||
        ubyte[8] target;
 | 
			
		||||
        source.copy(target);
 | 
			
		||||
        assert(cmp(source, target) == 0);
 | 
			
		||||
        assert(equal(source, target));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -212,7 +212,7 @@ do
 | 
			
		||||
    ubyte[6] expected = [ 'a', 'a', 'a', 'a', 'b', 'b' ];
 | 
			
		||||
 | 
			
		||||
    copyBackward(mem[0 .. 4], mem[2 .. $]);
 | 
			
		||||
    assert(cmp(expected, mem) == 0);
 | 
			
		||||
    assert(equal(expected, mem));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@nogc nothrow pure @safe unittest
 | 
			
		||||
@@ -221,7 +221,7 @@ do
 | 
			
		||||
    ubyte[9] r2;
 | 
			
		||||
 | 
			
		||||
    copyBackward(r1, r2);
 | 
			
		||||
    assert(cmp(r1, r2) == 0);
 | 
			
		||||
    assert(equal(r1, r2));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -241,6 +241,7 @@ do
 | 
			
		||||
 *          negative integer if $(D_INLINECODE r2 > r1),
 | 
			
		||||
 *          `0` if $(D_INLINECODE r1 == r2).
 | 
			
		||||
 */
 | 
			
		||||
deprecated("Use tanya.memory.op.equal() or tanya.algorithm.comparison.compare() instead")
 | 
			
		||||
int cmp(const void[] r1, const void[] r2) @nogc nothrow pure @trusted
 | 
			
		||||
in
 | 
			
		||||
{
 | 
			
		||||
@@ -249,48 +250,13 @@ in
 | 
			
		||||
}
 | 
			
		||||
do
 | 
			
		||||
{
 | 
			
		||||
    version (TanyaNative)
 | 
			
		||||
    import core.stdc.string : memcmp;
 | 
			
		||||
 | 
			
		||||
    if (r1.length > r2.length)
 | 
			
		||||
    {
 | 
			
		||||
        return cmpMemory(r1, r2);
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        if (r1.length > r2.length)
 | 
			
		||||
        {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
        return r1.length < r2.length ? -1 : memcmp(r1.ptr, r2.ptr, r1.length);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
@nogc nothrow pure @safe unittest
 | 
			
		||||
{
 | 
			
		||||
    ubyte[4] r1 = [ 'a', 'b', 'c', 'd' ];
 | 
			
		||||
    ubyte[3] r2 = [ 'c', 'a', 'b' ];
 | 
			
		||||
 | 
			
		||||
    assert(cmp(r1[0 .. 3], r2[]) < 0);
 | 
			
		||||
    assert(cmp(r2[], r1[0 .. 3]) > 0);
 | 
			
		||||
 | 
			
		||||
    assert(cmp(r1, r2) > 0);
 | 
			
		||||
    assert(cmp(r2, r1) < 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@nogc nothrow pure @safe unittest
 | 
			
		||||
{
 | 
			
		||||
    ubyte[16] r1 = [
 | 
			
		||||
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
 | 
			
		||||
        'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
 | 
			
		||||
    ];
 | 
			
		||||
    ubyte[16] r2 = [
 | 
			
		||||
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
 | 
			
		||||
        'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    assert(cmp(r1, r2) == 0);
 | 
			
		||||
    assert(cmp(r1[1 .. $], r2[1 .. $]) == 0);
 | 
			
		||||
    assert(cmp(r1[0 .. $ - 1], r2[0 .. $ - 1]) == 0);
 | 
			
		||||
    assert(cmp(r1[0 .. 8], r2[0 .. 8]) == 0);
 | 
			
		||||
    return r1.length < r2.length ? -1 : memcmp(r1.ptr, r2.ptr, r1.length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -362,13 +328,13 @@ do
 | 
			
		||||
{
 | 
			
		||||
    const ubyte[9] haystack = ['a', 'b', 'c', 'd', 'e', 'f', 'b', 'g', 'h'];
 | 
			
		||||
 | 
			
		||||
    assert(cmp(find(haystack, 'a'), haystack[]) == 0);
 | 
			
		||||
    assert(cmp(find(haystack, 'b'), haystack[1 .. $]) == 0);
 | 
			
		||||
    assert(cmp(find(haystack, 'c'), haystack[2 .. $]) == 0);
 | 
			
		||||
    assert(cmp(find(haystack, 'd'), haystack[3 .. $]) == 0);
 | 
			
		||||
    assert(cmp(find(haystack, 'e'), haystack[4 .. $]) == 0);
 | 
			
		||||
    assert(cmp(find(haystack, 'f'), haystack[5 .. $]) == 0);
 | 
			
		||||
    assert(cmp(find(haystack, 'h'), haystack[8 .. $]) == 0);
 | 
			
		||||
    assert(equal(find(haystack, 'a'), haystack[]));
 | 
			
		||||
    assert(equal(find(haystack, 'b'), haystack[1 .. $]));
 | 
			
		||||
    assert(equal(find(haystack, 'c'), haystack[2 .. $]));
 | 
			
		||||
    assert(equal(find(haystack, 'd'), haystack[3 .. $]));
 | 
			
		||||
    assert(equal(find(haystack, 'e'), haystack[4 .. $]));
 | 
			
		||||
    assert(equal(find(haystack, 'f'), haystack[5 .. $]));
 | 
			
		||||
    assert(equal(find(haystack, 'h'), haystack[8 .. $]));
 | 
			
		||||
    assert(find(haystack, 'i').length == 0);
 | 
			
		||||
 | 
			
		||||
    assert(find(null, 'a').length == 0);
 | 
			
		||||
@@ -441,10 +407,66 @@ do
 | 
			
		||||
///
 | 
			
		||||
@nogc nothrow pure @safe unittest
 | 
			
		||||
{
 | 
			
		||||
    assert(cmp(findNullTerminated("abcdef\0gh"), "abcdef") == 0);
 | 
			
		||||
    assert(cmp(findNullTerminated("\0garbage"), "") == 0);
 | 
			
		||||
    assert(cmp(findNullTerminated("\0"), "") == 0);
 | 
			
		||||
    assert(cmp(findNullTerminated("cstring\0"), "cstring") == 0);
 | 
			
		||||
    assert(equal(findNullTerminated("abcdef\0gh"), "abcdef"));
 | 
			
		||||
    assert(equal(findNullTerminated("\0garbage"), ""));
 | 
			
		||||
    assert(equal(findNullTerminated("\0"), ""));
 | 
			
		||||
    assert(equal(findNullTerminated("cstring\0"), "cstring"));
 | 
			
		||||
    assert(findNullTerminated(null) is null);
 | 
			
		||||
    assert(findNullTerminated("abcdef") is null);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Compares two memory areas $(D_PARAM r1) and $(D_PARAM r2) for equality.
 | 
			
		||||
 *
 | 
			
		||||
 * Params:
 | 
			
		||||
 *  haystack = First memory block.
 | 
			
		||||
 *  needle   = First memory block.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: $(D_KEYWORD true) if $(D_PARAM r1) and $(D_PARAM r2) are equal,
 | 
			
		||||
 *          $(D_KEYWORD false) otherwise.
 | 
			
		||||
 */
 | 
			
		||||
bool equal(const void[] r1, const void[] r2) @nogc nothrow pure @trusted
 | 
			
		||||
in
 | 
			
		||||
{
 | 
			
		||||
    assert(r1.length == 0 || r1.ptr !is null);
 | 
			
		||||
    assert(r2.length == 0 || r2.ptr !is null);
 | 
			
		||||
}
 | 
			
		||||
do
 | 
			
		||||
{
 | 
			
		||||
    version (TanyaNative)
 | 
			
		||||
    {
 | 
			
		||||
        return equalMemory(r1, r2);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        return r1.length == r2.length
 | 
			
		||||
            && memcmp(r1.ptr, r2.ptr, r1.length) == 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///
 | 
			
		||||
@nogc nothrow pure @safe unittest
 | 
			
		||||
{
 | 
			
		||||
    assert(equal("asdf", "asdf"));
 | 
			
		||||
    assert(!equal("asd", "asdf"));
 | 
			
		||||
    assert(!equal("asdf", "asd"));
 | 
			
		||||
    assert(!equal("asdf", "qwer"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Compares unanligned memory
 | 
			
		||||
@nogc nothrow pure @safe unittest
 | 
			
		||||
{
 | 
			
		||||
    ubyte[16] r1 = [
 | 
			
		||||
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
 | 
			
		||||
        'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
 | 
			
		||||
    ];
 | 
			
		||||
    ubyte[16] r2 = [
 | 
			
		||||
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
 | 
			
		||||
        'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    assert(equal(r1, r2));
 | 
			
		||||
    assert(equal(r1[1 .. $], r2[1 .. $]));
 | 
			
		||||
    assert(equal(r1[0 .. $ - 1], r2[0 .. $ - 1]));
 | 
			
		||||
    assert(equal(r1[0 .. 8], r2[0 .. 8]));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user