2 * This module contains compiler support for comparing dynamic arrays
4 * Copyright: Copyright Digital Mars 2000 - 2019.
5 * License: Distributed under the
6 * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
7 * (See accompanying file LICENSE)
8 * Source: $(DRUNTIMESRC core/internal/_array/_comparison.d)
11 module core
.internal
.array
.comparison
;
13 int __cmp(T
)(scope const T
[] lhs
, scope const T
[] rhs
) @trusted
14 if (__traits(isScalar
, T
))
16 // Compute U as the implementation type for T
17 static if (is(T
== ubyte) ||
is(T
== void) ||
is(T
== bool))
19 else static if (is(T
== wchar))
21 else static if (is(T
== dchar))
23 else static if (is(T
== ifloat))
25 else static if (is(T
== idouble))
27 else static if (is(T
== ireal))
32 static if (is(U
== char))
34 import core
.internal
.string
: dstrcmp
;
35 return dstrcmp(cast(char[]) lhs
, cast(char[]) rhs
);
37 else static if (!is(U
== T
))
39 // Reuse another implementation
40 return __cmp(cast(U
[]) lhs
, cast(U
[]) rhs
);
45 static if (__traits(isUnsigned
, T
) ?
!is(T
== __vector
) : is(T
: P
*, P
))
49 import core
.stdc
.string
: memcmp
;
50 int c
= memcmp(lhs
.ptr
, rhs
.ptr
, (lhs
.length
<= rhs
.length ? lhs
.length
: rhs
.length
) * T
.sizeof
);
53 static if (size_t
.sizeof
<= uint.sizeof
&& T
.sizeof
>= 2)
54 return cast(int) lhs
.length
- cast(int) rhs
.length
;
56 return int(lhs
.length
> rhs
.length
) - int(lhs
.length
< rhs
.length
);
60 immutable len
= lhs
.length
<= rhs
.length ? lhs
.length
: rhs
.length
;
61 foreach (const u
; 0 .. len
)
63 auto a
= lhs
.ptr
[u
], b
= rhs
.ptr
[u
];
64 static if (is(T
: creal))
66 // Use rt.cmath2._Ccmp instead ?
67 // Also: if NaN is present, numbers will appear equal.
68 auto r
= (a
.re
> b
.re
) - (a
.re
< b
.re
);
69 if (!r
) r
= (a
.im
> b
.im
) - (a
.im
< b
.im
);
73 // This pattern for three-way comparison is better than conditional operators
74 // See e.g. https://godbolt.org/z/3j4vh1
75 const r
= (a
> b
) - (a
< b
);
79 return (lhs
.length
> rhs
.length
) - (lhs
.length
< rhs
.length
);
83 // This function is called by the compiler when dealing with array
84 // comparisons in the semantic analysis phase of CmpExp. The ordering
85 // comparison is lowered to a call to this template.
86 auto __cmp(T1
, T2
)(T1
[] s1
, T2
[] s2
)
87 if (!__traits(isScalar
, T1
) && !__traits(isScalar
, T2
))
89 import core
.internal
.traits
: Unqual
;
93 static if (is(U1
== void) && is(U2
== void))
94 static @trusted ref inout(ubyte) at(inout(void)[] r
, size_t i
) { return (cast(inout(ubyte)*) r
.ptr
)[i
]; }
96 static @trusted ref R
at(R
)(R
[] r
, size_t i
) { return r
.ptr
[i
]; }
98 // All unsigned byte-wide types = > dstrcmp
99 immutable len
= s1
.length
<= s2
.length ? s1
.length
: s2
.length
;
101 foreach (const u
; 0 .. len
)
103 static if (__traits(compiles
, __cmp(at(s1
, u
), at(s2
, u
))))
105 auto c
= __cmp(at(s1
, u
), at(s2
, u
));
109 else static if (__traits(compiles
, at(s1
, u
).opCmp(at(s2
, u
))))
111 auto c
= at(s1
, u
).opCmp(at(s2
, u
));
115 else static if (__traits(compiles
, at(s1
, u
) < at(s2
, u
)))
117 if (int result
= (at(s1
, u
) > at(s2
, u
)) - (at(s1
, u
) < at(s2
, u
)))
122 // TODO: fix this legacy bad behavior, see
123 // https://issues.dlang.org/show_bug.cgi?id=17244
124 static assert(is(U1
== U2
), "Internal error.");
125 import core
.stdc
.string
: memcmp
;
126 auto c
= (() @trusted => memcmp(&at(s1
, u
), &at(s2
, u
), U1
.sizeof
))();
131 return (s1
.length
> s2
.length
) - (s1
.length
< s2
.length
);
137 void compareMinMax(T
)()
139 T
[2] a
= [T
.max
, T
.max
];
140 T
[2] b
= [T
.min
, T
.min
];
142 assert(__cmp(a
, b
) > 0);
143 assert(__cmp(b
, a
) < 0);
151 compareMinMax
!ushort;
157 // char types (dstrcmp)
160 void compareMinMax(T
)()
162 T
[2] a
= [T
.max
, T
.max
];
163 T
[2] b
= [T
.min
, T
.min
];
165 assert(__cmp(a
, b
) > 0);
166 assert(__cmp(b
, a
) < 0);
172 compareMinMax
!(const char);
176 assert(__cmp(s2
, s1
) > 0);
177 assert(__cmp(s1
, s2
) < 0);
183 void compareMinMax(T
)()
185 T
[2] a
= [T
.max
, T
.max
];
186 T
[2] b
= [T
.min_normal
, T
.min_normal
];
187 T
[2] c
= [T
.max
, T
.min_normal
];
190 assert(__cmp(a
, b
) > 0);
191 assert(__cmp(b
, a
) < 0);
192 assert(__cmp(a
, c
) > 0);
193 assert(__cmp(a
, d
) > 0);
194 assert(__cmp(d
, c
) < 0);
195 assert(__cmp(c
, c
) == 0);
200 compareMinMax
!double;
203 compareMinMax
!(const real);
204 compareMinMax
!(immutable real);
215 a
= cast(void[]) "bb";
216 b
= cast(const(void)[]) "aa";
219 assert(__cmp(a
, b
) > 0);
220 assert(__cmp(b
, a
) < 0);
223 // arrays of arrays with mixed modifiers
226 // https://issues.dlang.org/show_bug.cgi?id=17876
227 bool less1(immutable size_t
[][] a
, size_t
[][] b
) { return a
< b
; }
228 bool less2(const void[][] a
, void[][] b
) { return a
< b
; }
229 bool less3(inout size_t
[][] a
, size_t
[][] b
) { return a
< b
; }
231 immutable size_t
[][] a
= [[1, 2], [3, 4]];
232 size_t
[][] b
= [[1, 2], [3, 5]];
236 auto va
= [cast(immutable void[])a
[0], a
[1]];
237 auto vb
= [cast(void[])b
[0], b
[1]];
238 assert(less2(va
, vb
));
241 // custom aggregate types
244 // https://issues.dlang.org/show_bug.cgi?id=24044
245 // Support float opCmp(...) with array
249 float opCmp(F other
) const { return this.f
- other
.f
; }
252 F
[2] a
= [F(1.0f), F(float.nan
)];
253 F
[2] b
= [F(1.0f), F(1.0f)];
256 bool isNan(float f
) { return f
!= f
; }
258 assert(isNan(__cmp(a
, b
)));
259 assert(isNan(__cmp(a
, a
)));
260 assert(__cmp(b
, b
) == 0);
261 assert(__cmp(a
, c
) > 0);