mirror of
https://github.com/openRuyi-Project/gcc.git
synced 2026-09-07 22:42:06 +00:00
D front-end changes: - Import dmd v2.105.0-beta.1. - Added predefined version identifier VisionOS (ignored by GDC). - Functions can no longer have `enum` storage class. - The deprecation of the `body` keyword has been reverted, it is now an obsolete feature. - The error for `scope class` has been reverted, it is now an obsolete feature. D runtime changes: - Import druntime v2.105.0-beta.1. Phobos changes: - Import phobos v2.105.0-beta.1. - AliasSeq has been removed from std.math. - extern(C) getdelim and getline have been removed from std.stdio. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 26f049fb26. * dmd/VERSION: Bump version to v2.105.0-beta.1. * d-codegen.cc (get_frameinfo): Check useGC in condition. * d-lang.cc (d_handle_option): Set obsolete parameter when compiling with -Wall. (d_post_options): Set useGC to false when compiling with -fno-druntime. Propagate obsolete flag to compileEnv. * expr.cc (ExprVisitor::visit (CatExp *)): Check useGC in condition. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 26f049fb26. * src/MERGE: Merge upstream phobos 330d6a4fd.
263 lines
7.2 KiB
D
263 lines
7.2 KiB
D
/**
|
|
* This module contains compiler support for comparing dynamic arrays
|
|
*
|
|
* Copyright: Copyright Digital Mars 2000 - 2019.
|
|
* License: Distributed under the
|
|
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
|
|
* (See accompanying file LICENSE)
|
|
* Source: $(DRUNTIMESRC core/internal/_array/_comparison.d)
|
|
*/
|
|
|
|
module core.internal.array.comparison;
|
|
|
|
int __cmp(T)(scope const T[] lhs, scope const T[] rhs) @trusted
|
|
if (__traits(isScalar, T))
|
|
{
|
|
// Compute U as the implementation type for T
|
|
static if (is(T == ubyte) || is(T == void) || is(T == bool))
|
|
alias U = char;
|
|
else static if (is(T == wchar))
|
|
alias U = ushort;
|
|
else static if (is(T == dchar))
|
|
alias U = uint;
|
|
else static if (is(T == ifloat))
|
|
alias U = float;
|
|
else static if (is(T == idouble))
|
|
alias U = double;
|
|
else static if (is(T == ireal))
|
|
alias U = real;
|
|
else
|
|
alias U = T;
|
|
|
|
static if (is(U == char))
|
|
{
|
|
import core.internal.string : dstrcmp;
|
|
return dstrcmp(cast(char[]) lhs, cast(char[]) rhs);
|
|
}
|
|
else static if (!is(U == T))
|
|
{
|
|
// Reuse another implementation
|
|
return __cmp(cast(U[]) lhs, cast(U[]) rhs);
|
|
}
|
|
else
|
|
{
|
|
version (BigEndian)
|
|
static if (__traits(isUnsigned, T) ? !is(T == __vector) : is(T : P*, P))
|
|
{
|
|
if (!__ctfe)
|
|
{
|
|
import core.stdc.string : memcmp;
|
|
int c = memcmp(lhs.ptr, rhs.ptr, (lhs.length <= rhs.length ? lhs.length : rhs.length) * T.sizeof);
|
|
if (c)
|
|
return c;
|
|
static if (size_t.sizeof <= uint.sizeof && T.sizeof >= 2)
|
|
return cast(int) lhs.length - cast(int) rhs.length;
|
|
else
|
|
return int(lhs.length > rhs.length) - int(lhs.length < rhs.length);
|
|
}
|
|
}
|
|
|
|
immutable len = lhs.length <= rhs.length ? lhs.length : rhs.length;
|
|
foreach (const u; 0 .. len)
|
|
{
|
|
auto a = lhs.ptr[u], b = rhs.ptr[u];
|
|
static if (is(T : creal))
|
|
{
|
|
// Use rt.cmath2._Ccmp instead ?
|
|
// Also: if NaN is present, numbers will appear equal.
|
|
auto r = (a.re > b.re) - (a.re < b.re);
|
|
if (!r) r = (a.im > b.im) - (a.im < b.im);
|
|
}
|
|
else
|
|
{
|
|
// This pattern for three-way comparison is better than conditional operators
|
|
// See e.g. https://godbolt.org/z/3j4vh1
|
|
const r = (a > b) - (a < b);
|
|
}
|
|
if (r) return r;
|
|
}
|
|
return (lhs.length > rhs.length) - (lhs.length < rhs.length);
|
|
}
|
|
}
|
|
|
|
// 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.
|
|
auto __cmp(T1, T2)(T1[] s1, T2[] s2)
|
|
if (!__traits(isScalar, T1) && !__traits(isScalar, T2))
|
|
{
|
|
import core.internal.traits : Unqual;
|
|
alias U1 = Unqual!T1;
|
|
alias U2 = Unqual!T2;
|
|
|
|
static if (is(U1 == void) && is(U2 == void))
|
|
static @trusted ref inout(ubyte) at(inout(void)[] r, size_t i) { return (cast(inout(ubyte)*) r.ptr)[i]; }
|
|
else
|
|
static @trusted ref R at(R)(R[] r, size_t i) { return r.ptr[i]; }
|
|
|
|
// All unsigned byte-wide types = > dstrcmp
|
|
immutable len = s1.length <= s2.length ? s1.length : s2.length;
|
|
|
|
foreach (const u; 0 .. len)
|
|
{
|
|
static if (__traits(compiles, __cmp(at(s1, u), at(s2, u))))
|
|
{
|
|
auto c = __cmp(at(s1, u), at(s2, u));
|
|
if (c != 0)
|
|
return c;
|
|
}
|
|
else static if (__traits(compiles, at(s1, u).opCmp(at(s2, u))))
|
|
{
|
|
auto c = at(s1, u).opCmp(at(s2, u));
|
|
if (c != 0)
|
|
return c;
|
|
}
|
|
else static if (__traits(compiles, at(s1, u) < at(s2, u)))
|
|
{
|
|
if (int result = (at(s1, u) > at(s2, u)) - (at(s1, u) < at(s2, u)))
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
// TODO: fix this legacy bad behavior, see
|
|
// https://issues.dlang.org/show_bug.cgi?id=17244
|
|
static assert(is(U1 == U2), "Internal error.");
|
|
import core.stdc.string : memcmp;
|
|
auto c = (() @trusted => memcmp(&at(s1, u), &at(s2, u), U1.sizeof))();
|
|
if (c != 0)
|
|
return c;
|
|
}
|
|
}
|
|
return (s1.length > s2.length) - (s1.length < s2.length);
|
|
}
|
|
|
|
// integral types
|
|
@safe unittest
|
|
{
|
|
void compareMinMax(T)()
|
|
{
|
|
T[2] a = [T.max, T.max];
|
|
T[2] b = [T.min, T.min];
|
|
|
|
assert(__cmp(a, b) > 0);
|
|
assert(__cmp(b, a) < 0);
|
|
}
|
|
|
|
compareMinMax!int;
|
|
compareMinMax!uint;
|
|
compareMinMax!long;
|
|
compareMinMax!ulong;
|
|
compareMinMax!short;
|
|
compareMinMax!ushort;
|
|
compareMinMax!byte;
|
|
compareMinMax!dchar;
|
|
compareMinMax!wchar;
|
|
}
|
|
|
|
// char types (dstrcmp)
|
|
@safe unittest
|
|
{
|
|
void compareMinMax(T)()
|
|
{
|
|
T[2] a = [T.max, T.max];
|
|
T[2] b = [T.min, T.min];
|
|
|
|
assert(__cmp(a, b) > 0);
|
|
assert(__cmp(b, a) < 0);
|
|
}
|
|
|
|
compareMinMax!ubyte;
|
|
compareMinMax!bool;
|
|
compareMinMax!char;
|
|
compareMinMax!(const char);
|
|
|
|
string s1 = "aaaa";
|
|
string s2 = "bbbb";
|
|
assert(__cmp(s2, s1) > 0);
|
|
assert(__cmp(s1, s2) < 0);
|
|
}
|
|
|
|
// fp types
|
|
@safe unittest
|
|
{
|
|
void compareMinMax(T)()
|
|
{
|
|
T[2] a = [T.max, T.max];
|
|
T[2] b = [T.min_normal, T.min_normal];
|
|
T[2] c = [T.max, T.min_normal];
|
|
T[1] d = [T.max];
|
|
|
|
assert(__cmp(a, b) > 0);
|
|
assert(__cmp(b, a) < 0);
|
|
assert(__cmp(a, c) > 0);
|
|
assert(__cmp(a, d) > 0);
|
|
assert(__cmp(d, c) < 0);
|
|
assert(__cmp(c, c) == 0);
|
|
}
|
|
|
|
compareMinMax!real;
|
|
compareMinMax!float;
|
|
compareMinMax!double;
|
|
|
|
// qualifiers
|
|
compareMinMax!(const real);
|
|
compareMinMax!(immutable real);
|
|
}
|
|
|
|
// void[]
|
|
@safe unittest
|
|
{
|
|
void[] a;
|
|
const(void)[] b;
|
|
|
|
(() @trusted
|
|
{
|
|
a = cast(void[]) "bb";
|
|
b = cast(const(void)[]) "aa";
|
|
})();
|
|
|
|
assert(__cmp(a, b) > 0);
|
|
assert(__cmp(b, a) < 0);
|
|
}
|
|
|
|
// arrays of arrays with mixed modifiers
|
|
@safe unittest
|
|
{
|
|
// https://issues.dlang.org/show_bug.cgi?id=17876
|
|
bool less1(immutable size_t[][] a, size_t[][] b) { return a < b; }
|
|
bool less2(const void[][] a, void[][] b) { return a < b; }
|
|
bool less3(inout size_t[][] a, size_t[][] b) { return a < b; }
|
|
|
|
immutable size_t[][] a = [[1, 2], [3, 4]];
|
|
size_t[][] b = [[1, 2], [3, 5]];
|
|
assert(less1(a, b));
|
|
assert(less3(a, b));
|
|
|
|
auto va = [cast(immutable void[])a[0], a[1]];
|
|
auto vb = [cast(void[])b[0], b[1]];
|
|
assert(less2(va, vb));
|
|
}
|
|
|
|
// custom aggregate types
|
|
@safe unittest
|
|
{
|
|
// https://issues.dlang.org/show_bug.cgi?id=24044
|
|
// Support float opCmp(...) with array
|
|
static struct F
|
|
{
|
|
float f;
|
|
float opCmp(F other) const { return this.f - other.f; }
|
|
}
|
|
|
|
F[2] a = [F(1.0f), F(float.nan)];
|
|
F[2] b = [F(1.0f), F(1.0f)];
|
|
F[1] c = [F(1.0f)];
|
|
|
|
bool isNan(float f) { return f != f; }
|
|
|
|
assert(isNan(__cmp(a, b)));
|
|
assert(isNan(__cmp(a, a)));
|
|
assert(__cmp(b, b) == 0);
|
|
assert(__cmp(a, c) > 0);
|
|
}
|