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