From ed4818b1093d2da67803d24303896a937221239a Mon Sep 17 00:00:00 2001 From: somzzz Date: Thu, 19 Jan 2017 04:51:19 -0800 Subject: [PATCH 1/4] array compare template function --- src/object.d | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) diff --git a/src/object.d b/src/object.d index 38b6144b3b..154827bbc5 100644 --- a/src/object.d +++ b/src/object.d @@ -3241,6 +3241,226 @@ template RTInfo(T) enum RTInfo = null; } +int _adCmpT(T1, T2)(T1[] s1, T2[] s2) +{ + // U1 gets the unqualified version of T1 + static if (is(T1 W == immutable W)) alias U1 = W; + else static if (is(T1 W == const W)) alias U1 = W; + else alias U1 = T1; + + // U2 gets the unqualified version of T2 + static if (is(T2 U == immutable U)) alias U2 = U; + else static if (is(T2 U == const U)) alias U2 = U; + else alias U2 = T2; + + // objects + static if (is(U1 : Object) && is(U2 : Object)) + { + auto c = cast(sizediff_t)(s1.length - s2.length); + if (c == 0) + { + for (size_t u = 0; u < s1.length; u++) + { + Object o1 = s1[u]; + Object o2 = s2[u]; + + if (o1 is o2) + continue; + + // Regard null references as always being "less than" + if (o1) + { + if (!o2) + return 1; + c = o1.opCmp(o2); + if (c == 0) + continue; + break; + } + else + { + return -1; + } + } + } + return c < 0 ? -1 : c > 0 ? 1 : 0; + } + + // floating point types + static if ((is(U1 == float) && is(U2 == float)) + || (is(U1 == double) && is(U2 == double)) + || (is(U1 == real) && is(U2 == real)) + || (is(U1 == ifloat) && is(U2 == ifloat)) + || (is(U1 == idouble) && is(U2 == idouble)) + || (is(U1 == ireal) && is(U2 == ireal)) + || (is(U1 == cfloat) && is(U2 == cfloat)) + || (is(U1 == cdouble) && is(U2 == cdouble)) + || (is(U1 == creal) && is(U2 == creal))) + { + template Floating(T) + if (is(T == cfloat) || is(T == cdouble) || is(T == creal)) + { + pure nothrow @safe: + int compare(T f1, T f2) + { + int result; + + if (f1.re < f2.re) + result = -1; + else if (f1.re > f2.re) + result = 1; + else if (f1.im < f2.im) + result = -1; + else if (f1.im > f2.im) + result = 1; + else + result = 0; + return result; + } + } + + template Floating(T) + if (is(T == float) || is(T == double) || is(T == real)) + { + pure nothrow @safe: + int compare(T d1, T d2) + { + if (d1 != d1 || d2 != d2) // if either are NaN + { + if (d1 != d1) + { + if (d2 != d2) + return 0; + return -1; + } + return 1; + } + return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1); + } + } + + template Array(T) + if (is(T == float) || is(T == double) || is(T == real) || + is(T == cfloat) || is(T == cdouble) || is(T == creal)) + { + pure nothrow @safe: + int compare(T[] s1, T[] s2) + { + size_t len = s1.length; + if (s2.length < len) + len = s2.length; + for (size_t u = 0; u < len; u++) + { + if (int c = Floating!T.compare(s1[u], s2[u])) + return c; + } + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + return 0; + } + } + + static if (is(U1 == ifloat)) alias F = float; + else static if (is(U1 == idouble)) alias F = double; + else static if (is(U1 == ireal)) alias F = real; + else alias F = U1; + + return () @trusted { return Array!F.compare(cast(F[])s1, cast(F[])s2); }(); + } + + // integral, char types + else + { + size_t len = s1.length; + + if (s2.length < len) + len = s2.length; + + for (size_t u = 0; u < len; u++) + { + if (s1[u] < s2[u]) + return -1; + else if (s1[u] > s2[u]) + return 1; + } + + if (s1.length < s2.length) + return -1; + else if (s1.length > s2.length) + return 1; + + return 0; + } +} + +// integral types +unittest +{ + void compareMinMax(T)() + { + T[] a = [T.max, T.max]; + T[] b = [T.min, T.min]; + + assert(a > b); + assert(b < a); + } + + compareMinMax!int; + compareMinMax!uint; + compareMinMax!long; + compareMinMax!ulong; + compareMinMax!short; + compareMinMax!ushort; + compareMinMax!byte; + compareMinMax!ubyte; + compareMinMax!bool; +} + +// char types +unittest +{ + void compareMinMax(T)() + { + T[] a = [T.max, T.max]; + T[] b = [T.min, T.min]; + + assert(a > b); + assert(b < a); + } + + compareMinMax!char; + compareMinMax!dchar; + compareMinMax!wchar; +} + +// fp types +unittest +{ + void compareMinMax(T)() + { + T[] a = [T.max, T.max]; + T[] b = [T.min_normal, T.min_normal]; + + assert(a > b); + assert(b < a); + } + + compareMinMax!real; + compareMinMax!float; + compareMinMax!double; + compareMinMax!ireal; + compareMinMax!ifloat; + compareMinMax!idouble; + compareMinMax!creal; + //compareMinMax!cfloat; + compareMinMax!cdouble; + + // qualifiers + compareMinMax!(const real); + compareMinMax!(immutable real); +} // Helper functions From 3e667945e51472423f27e262aa449878067ef000 Mon Sep 17 00:00:00 2001 From: somzzz Date: Fri, 3 Mar 2017 03:10:32 -0800 Subject: [PATCH 2/4] fixed nits & added tests & dstrcmp --- src/object.d | 273 +++++++++++++++++++++++++++++---------------------- 1 file changed, 158 insertions(+), 115 deletions(-) diff --git a/src/object.d b/src/object.d index 154827bbc5..2692059b2f 100644 --- a/src/object.d +++ b/src/object.d @@ -3241,19 +3241,76 @@ template RTInfo(T) enum RTInfo = null; } -int _adCmpT(T1, T2)(T1[] s1, T2[] s2) +private template Floating1(T) +if (is(T == cfloat) || is(T == cdouble) || is(T == creal)) +{ + // Use rt.cmath2._Ccmp instead ? + int compare(T f1, T f2) + { + int result; + + if (f1.re < f2.re) + result = -1; + else if (f1.re > f2.re) + result = 1; + else if (f1.im < f2.im) + result = -1; + else if (f1.im > f2.im) + result = 1; + else + result = 0; + return result; + } +} + +private template Floating1(T) +if (is(T == float) || is(T == double) || is(T == real)) { - // U1 gets the unqualified version of T1 - static if (is(T1 W == immutable W)) alias U1 = W; - else static if (is(T1 W == const W)) alias U1 = W; - else alias U1 = T1; + int compare(T d1, T d2) + { + if (d1 != d1 || d2 != d2) // if either is NaN + { + if (d1 != d1) + { + if (d2 != d2) + return 0; + return -1; + } + return 1; + } + return d1 < d2 ? -1 : (d1 > d2); + } +} - // U2 gets the unqualified version of T2 - static if (is(T2 U == immutable U)) alias U2 = U; - else static if (is(T2 U == const U)) alias U2 = U; - else alias U2 = T2; +private template Array1(T) +if (is(T == float) || is(T == double) || is(T == real) || + is(T == cfloat) || is(T == cdouble) || is(T == creal)) +{ + int compare(T[] s1, T[] s2) + { + auto len = s1.length; + if (s2.length < len) + len = s2.length; + + foreach (const u; 0 .. len) + { + if (int c = Floating1!T.compare(s1[u], s2[u])) + return c; + } + return s1.length < s2.length ? -1 : (s1.length > s2.length); + } +} + +int _adCmpT(T1, T2)(T1[] s1, T2[] s2) +{ + import core.internal.traits : Unqual; + alias U1 = Unqual!T1; + alias U2 = Unqual!T2; // objects + // Old code went to object.d/TypeInfo_array.compare and then to + // object.d/TypeInfo_Class.compare + // which combined result in the same code as below. static if (is(U1 : Object) && is(U2 : Object)) { auto c = cast(sizediff_t)(s1.length - s2.length); @@ -3261,8 +3318,8 @@ int _adCmpT(T1, T2)(T1[] s1, T2[] s2) { for (size_t u = 0; u < s1.length; u++) { - Object o1 = s1[u]; - Object o2 = s2[u]; + auto o1 = () @trusted { return s1.ptr[u]; }(); + auto o2 = () @trusted { return s2.ptr[u]; }(); if (o1 is o2) continue; @@ -3273,9 +3330,8 @@ int _adCmpT(T1, T2)(T1[] s1, T2[] s2) if (!o2) return 1; c = o1.opCmp(o2); - if (c == 0) - continue; - break; + if (c != 0) + break; } else { @@ -3283,115 +3339,74 @@ int _adCmpT(T1, T2)(T1[] s1, T2[] s2) } } } - return c < 0 ? -1 : c > 0 ? 1 : 0; + return c < 0 ? -1 : (c > 0); } // floating point types - static if ((is(U1 == float) && is(U2 == float)) - || (is(U1 == double) && is(U2 == double)) - || (is(U1 == real) && is(U2 == real)) - || (is(U1 == ifloat) && is(U2 == ifloat)) - || (is(U1 == idouble) && is(U2 == idouble)) - || (is(U1 == ireal) && is(U2 == ireal)) - || (is(U1 == cfloat) && is(U2 == cfloat)) - || (is(U1 == cdouble) && is(U2 == cdouble)) - || (is(U1 == creal) && is(U2 == creal))) - { - template Floating(T) - if (is(T == cfloat) || is(T == cdouble) || is(T == creal)) - { - pure nothrow @safe: - int compare(T f1, T f2) - { - int result; - - if (f1.re < f2.re) - result = -1; - else if (f1.re > f2.re) - result = 1; - else if (f1.im < f2.im) - result = -1; - else if (f1.im > f2.im) - result = 1; - else - result = 0; - return result; - } - } + else static if (__traits(isFloating, U1)) + { + static if (is(U1 == ifloat)) alias F = float; + else static if (is(U1 == idouble)) alias F = double; + else static if (is(U1 == ireal)) alias F = real; + else alias F = U1; - template Floating(T) - if (is(T == float) || is(T == double) || is(T == real)) + return () @trusted { return Array1!F.compare(cast(F[])s1, cast(F[])s2); }(); + } + + // char types = > dstrcmp + else static if ((is(U1 == ubyte) && is(U2 == ubyte)) + || (is(U1 == void) && is(U2 == void)) + || (is(U1 == bool) && is(U2 == bool)) + || (is(U1 == char) && is(U2 == char))) + { + if (!__ctfe) { - pure nothrow @safe: - int compare(T d1, T d2) - { - if (d1 != d1 || d2 != d2) // if either are NaN - { - if (d1 != d1) - { - if (d2 != d2) - return 0; - return -1; - } - return 1; - } - return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1); - } + import core.internal.string : dstrcmp; + return () @trusted { return dstrcmp(cast(char[])s1, cast(char[])s2); }(); } - - template Array(T) - if (is(T == float) || is(T == double) || is(T == real) || - is(T == cfloat) || is(T == cdouble) || is(T == creal)) + else { - pure nothrow @safe: - int compare(T[] s1, T[] s2) + // pretty ugly... + auto len = s1.length; + + if (s2.length < len) + len = s2.length; + + foreach (const u; 0 .. len) { - size_t len = s1.length; - if (s2.length < len) - len = s2.length; - for (size_t u = 0; u < len; u++) - { - if (int c = Floating!T.compare(s1[u], s2[u])) - return c; - } - if (s1.length < s2.length) + auto e1 = () @trusted { return s1.ptr[u]; }(); + auto e2 = () @trusted { return s2.ptr[u]; }(); + + if (e1 < e2) return -1; - else if (s1.length > s2.length) + else if (e1 > e2) return 1; - return 0; } - } - - static if (is(U1 == ifloat)) alias F = float; - else static if (is(U1 == idouble)) alias F = double; - else static if (is(U1 == ireal)) alias F = real; - else alias F = U1; - return () @trusted { return Array!F.compare(cast(F[])s1, cast(F[])s2); }(); + return s1.length < s2.length ? -1 : (s1.length > s2.length); + } } - // integral, char types + // integral else { - size_t len = s1.length; + auto len = s1.length; if (s2.length < len) len = s2.length; - for (size_t u = 0; u < len; u++) + foreach (const u; 0 .. len) { - if (s1[u] < s2[u]) + auto e1 = () @trusted { return s1.ptr[u]; }(); + auto e2 = () @trusted { return s2.ptr[u]; }(); + + if (e1 < e2) return -1; - else if (s1[u] > s2[u]) + else if (e1 > e2) return 1; } - if (s1.length < s2.length) - return -1; - else if (s1.length > s2.length) - return 1; - - return 0; + return s1.length < s2.length ? -1 : (s1.length > s2.length); } } @@ -3400,11 +3415,11 @@ unittest { void compareMinMax(T)() { - T[] a = [T.max, T.max]; - T[] b = [T.min, T.min]; + T[2] a = [T.max, T.max]; + T[2] b = [T.min, T.min]; - assert(a > b); - assert(b < a); + assert(_adCmpT(a, b) > 0); + assert(_adCmpT(b, a) < 0); } compareMinMax!int; @@ -3414,25 +3429,31 @@ unittest compareMinMax!short; compareMinMax!ushort; compareMinMax!byte; - compareMinMax!ubyte; - compareMinMax!bool; + compareMinMax!dchar; + compareMinMax!wchar; } -// char types +// char types (dstrcmp) unittest { void compareMinMax(T)() { - T[] a = [T.max, T.max]; - T[] b = [T.min, T.min]; + T[2] a = [T.max, T.max]; + T[2] b = [T.min, T.min]; - assert(a > b); - assert(b < a); + assert(_adCmpT(a, b) > 0); + assert(_adCmpT(b, a) < 0); } + compareMinMax!ubyte; + compareMinMax!bool; compareMinMax!char; - compareMinMax!dchar; - compareMinMax!wchar; + compareMinMax!(const char); + + string s1 = "aaaa"; + string s2 = "bbbb"; + assert(_adCmpT(s2, s1) > 0); + assert(_adCmpT(s1, s2) < 0); } // fp types @@ -3440,11 +3461,11 @@ unittest { void compareMinMax(T)() { - T[] a = [T.max, T.max]; - T[] b = [T.min_normal, T.min_normal]; + T[2] a = [T.max, T.max]; + T[2] b = [T.min_normal, T.min_normal]; - assert(a > b); - assert(b < a); + assert(_adCmpT(a, b) > 0); + assert(_adCmpT(b, a) < 0); } compareMinMax!real; @@ -3462,6 +3483,28 @@ unittest compareMinMax!(immutable real); } +//objects +unittest +{ + class C + { + int i; + this(int i) { this.i = i; } + + override int opCmp(Object c) const + { + return i - (cast(C)c).i; + } + } + + auto c1 = new C(1); + auto c2 = new C(2); + + assert(_adCmpT([c1, c1], [c2, c2]) < 0); + assert(_adCmpT([c2, c2], [c1, c1]) > 0); +} + + // Helper functions private inout(TypeInfo) getElement(inout TypeInfo value) @trusted pure nothrow From 9afe2122ef28f16c7f9736ff68ecd9afff554550 Mon Sep 17 00:00:00 2001 From: somzzz Date: Sun, 5 Mar 2017 06:38:13 -0800 Subject: [PATCH 3/4] fixed breaking change & code adjustments --- src/object.d | 213 +++++++++++++++++++++++++-------------------------- 1 file changed, 106 insertions(+), 107 deletions(-) diff --git a/src/object.d b/src/object.d index 2692059b2f..8c3b06fb24 100644 --- a/src/object.d +++ b/src/object.d @@ -3241,107 +3241,49 @@ template RTInfo(T) enum RTInfo = null; } -private template Floating1(T) -if (is(T == cfloat) || is(T == cdouble) || is(T == creal)) -{ - // Use rt.cmath2._Ccmp instead ? - int compare(T f1, T f2) - { - int result; - - if (f1.re < f2.re) - result = -1; - else if (f1.re > f2.re) - result = 1; - else if (f1.im < f2.im) - result = -1; - else if (f1.im > f2.im) - result = 1; - else - result = 0; - return result; - } -} - -private template Floating1(T) -if (is(T == float) || is(T == double) || is(T == real)) -{ - int compare(T d1, T d2) - { - if (d1 != d1 || d2 != d2) // if either is NaN - { - if (d1 != d1) - { - if (d2 != d2) - return 0; - return -1; - } - return 1; - } - return d1 < d2 ? -1 : (d1 > d2); - } -} - -private template Array1(T) -if (is(T == float) || is(T == double) || is(T == real) || - is(T == cfloat) || is(T == cdouble) || is(T == creal)) -{ - int compare(T[] s1, T[] s2) - { - auto len = s1.length; - if (s2.length < len) - len = s2.length; - - foreach (const u; 0 .. len) - { - if (int c = Floating1!T.compare(s1[u], s2[u])) - return c; - } - return s1.length < s2.length ? -1 : (s1.length > s2.length); - } -} - -int _adCmpT(T1, T2)(T1[] s1, T2[] s2) +int __cmp(T1, T2)(T1[] s1, T2[] s2) { import core.internal.traits : Unqual; alias U1 = Unqual!T1; alias U2 = Unqual!T2; + static @trusted ref R at(R)(R[] r, size_t i) { return r.ptr[i]; } + // objects // Old code went to object.d/TypeInfo_array.compare and then to // object.d/TypeInfo_Class.compare // which combined result in the same code as below. static if (is(U1 : Object) && is(U2 : Object)) { - auto c = cast(sizediff_t)(s1.length - s2.length); - if (c == 0) + auto len = s1.length; + + if (s2.length < len) + len = s2.length; + + foreach (const u; 0 .. len) { - for (size_t u = 0; u < s1.length; u++) - { - auto o1 = () @trusted { return s1.ptr[u]; }(); - auto o2 = () @trusted { return s2.ptr[u]; }(); + auto o1 = at(s1, u); + auto o2 = at(s2, u); - if (o1 is o2) - continue; + if (o1 is o2) + continue; - // Regard null references as always being "less than" - if (o1) - { - if (!o2) - return 1; - c = o1.opCmp(o2); - if (c != 0) - break; - } - else - { - return -1; - } + // Regard null references as always being "less than" + if (o1) + { + if (!o2) + return 1; + auto c = o1.opCmp(o2); + if (c != 0) + return c < 0 ? -1 : 1; + } + else + { + return -1; } } - return c < 0 ? -1 : (c > 0); + return s1.length < s2.length ? -1 : (s1.length > s2.length); } - // floating point types else static if (__traits(isFloating, U1)) { @@ -3350,9 +3292,52 @@ int _adCmpT(T1, T2)(T1[] s1, T2[] s2) else static if (is(U1 == ireal)) alias F = real; else alias F = U1; - return () @trusted { return Array1!F.compare(cast(F[])s1, cast(F[])s2); }(); - } + static int compare(F f1, F f2) + { + static if (is(F == cfloat) || is(F == cdouble) || is(F == creal)) + { + // Use rt.cmath2._Ccmp instead ? + int result; + + if (f1.re < f2.re) + result = -1; + else if (f1.re > f2.re) + result = 1; + else if (f1.im < f2.im) + result = -1; + else if (f1.im > f2.im) + result = 1; + else + result = 0; + return result; + } + else static if (is(F == float) || is(F == double) || is(F == real)) + { + // d1 is NaN 2^0 + d2 is NaN 2^1 + auto NaNs = (f1 != f1) | ((f2 != f2) << 1); + + return (NaNs == 3) ? 0 : + (NaNs == 2) ? 1 : + (NaNs == 1) ? -1 : + (f1 < f2) ? -1 : (f1 > f2); + } + else static assert(false, "Internal error"); + } + + auto len = s1.length; + if (s2.length < len) + len = s2.length; + + auto fpArray1 = () { return cast(F[])s1; }(); + auto fpArray2 = () { return cast(F[])s2; }(); + foreach (const u; 0 .. len) + { + if (int c = compare(fpArray1[u], fpArray2[u])) + return c; + } + return s1.length < s2.length ? -1 : (s1.length > s2.length); + } // char types = > dstrcmp else static if ((is(U1 == ubyte) && is(U2 == ubyte)) || (is(U1 == void) && is(U2 == void)) @@ -3374,8 +3359,8 @@ int _adCmpT(T1, T2)(T1[] s1, T2[] s2) foreach (const u; 0 .. len) { - auto e1 = () @trusted { return s1.ptr[u]; }(); - auto e2 = () @trusted { return s2.ptr[u]; }(); + auto e1 = at(s1, u); + auto e2 = at(s2, u); if (e1 < e2) return -1; @@ -3386,8 +3371,7 @@ int _adCmpT(T1, T2)(T1[] s1, T2[] s2) return s1.length < s2.length ? -1 : (s1.length > s2.length); } } - - // integral + // integral, struct, nested arrays else { auto len = s1.length; @@ -3397,15 +3381,30 @@ int _adCmpT(T1, T2)(T1[] s1, T2[] s2) foreach (const u; 0 .. len) { - auto e1 = () @trusted { return s1.ptr[u]; }(); - auto e2 = () @trusted { return s2.ptr[u]; }(); + auto e1 = at(s1, u); + auto e2 = at(s2, u); - if (e1 < e2) - return -1; - else if (e1 > e2) - return 1; + // structs + static if (__traits(compiles, e1.opCmp(e2))) + { + auto c = e1.opCmp(e2); + if (c != 0) + return c < 0 ? -1 : 1; + } + else static if (__traits(compiles, _adCmp(e1, e2))) + { + auto c = _adCmp(e1, e2); + if (c != 0) + return c < 0 ? -1 : 1; + } + else + { + if (e1 < e2) + return -1; + else if (e1 > e2) + return 1; + } } - return s1.length < s2.length ? -1 : (s1.length > s2.length); } } @@ -3418,8 +3417,8 @@ unittest T[2] a = [T.max, T.max]; T[2] b = [T.min, T.min]; - assert(_adCmpT(a, b) > 0); - assert(_adCmpT(b, a) < 0); + assert(__cmp(a, b) > 0); + assert(__cmp(b, a) < 0); } compareMinMax!int; @@ -3441,8 +3440,8 @@ unittest T[2] a = [T.max, T.max]; T[2] b = [T.min, T.min]; - assert(_adCmpT(a, b) > 0); - assert(_adCmpT(b, a) < 0); + assert(__cmp(a, b) > 0); + assert(__cmp(b, a) < 0); } compareMinMax!ubyte; @@ -3452,8 +3451,8 @@ unittest string s1 = "aaaa"; string s2 = "bbbb"; - assert(_adCmpT(s2, s1) > 0); - assert(_adCmpT(s1, s2) < 0); + assert(__cmp(s2, s1) > 0); + assert(__cmp(s1, s2) < 0); } // fp types @@ -3464,8 +3463,8 @@ unittest T[2] a = [T.max, T.max]; T[2] b = [T.min_normal, T.min_normal]; - assert(_adCmpT(a, b) > 0); - assert(_adCmpT(b, a) < 0); + assert(__cmp(a, b) > 0); + assert(__cmp(b, a) < 0); } compareMinMax!real; @@ -3500,8 +3499,8 @@ unittest auto c1 = new C(1); auto c2 = new C(2); - assert(_adCmpT([c1, c1], [c2, c2]) < 0); - assert(_adCmpT([c2, c2], [c1, c1]) > 0); + assert(__cmp([c1, c1], [c2, c2]) < 0); + assert(__cmp([c2, c2], [c1, c1]) > 0); } From cbe8288943bc1a1415e3adb1b4a768f54cf4c449 Mon Sep 17 00:00:00 2001 From: somzzz Date: Sun, 5 Mar 2017 13:45:17 -0800 Subject: [PATCH 4/4] Comments and nits --- src/object.d | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/object.d b/src/object.d index 8c3b06fb24..c361c790ab 100644 --- a/src/object.d +++ b/src/object.d @@ -3241,6 +3241,9 @@ template RTInfo(T) enum RTInfo = null; } +// This function is called by the compiler when dealing with array +// comparisons in the semantic analysis phase of CmpExp. The ordering +// comparison is lowered to a call to this template. int __cmp(T1, T2)(T1[] s1, T2[] s2) { import core.internal.traits : Unqual; @@ -3364,7 +3367,8 @@ int __cmp(T1, T2)(T1[] s1, T2[] s2) if (e1 < e2) return -1; - else if (e1 > e2) + + if (e1 > e2) return 1; } @@ -3391,9 +3395,9 @@ int __cmp(T1, T2)(T1[] s1, T2[] s2) if (c != 0) return c < 0 ? -1 : 1; } - else static if (__traits(compiles, _adCmp(e1, e2))) + else static if (__traits(compiles, __cmp(e1, e2))) { - auto c = _adCmp(e1, e2); + auto c = __cmp(e1, e2); if (c != 0) return c < 0 ? -1 : 1; } @@ -3401,7 +3405,8 @@ int __cmp(T1, T2)(T1[] s1, T2[] s2) { if (e1 < e2) return -1; - else if (e1 > e2) + + if (e1 > e2) return 1; } }