@@ -23,20 +23,50 @@ bool __ArrayEq(T1, T2)(T1[] a, T2[] b)
2323 return true ;
2424}
2525
26+ // `lhs == rhs` lowers to `__equals(lhs, rhs)` for dynamic arrays
27+ // The scalar-only overload takes advantage of known properties of scalars to
28+ // consolidate IFTI instances and remove the need for helper functions.
29+ bool __equals (T1 , T2 )(scope const T1 [] lhs, scope const T2 [] rhs)
30+ @nogc nothrow pure @trusted
31+ if (__traits(isScalar, T1 ) && __traits(isScalar, T2 ))
32+ {
33+ if (lhs.length != rhs.length)
34+ return false ;
35+ static if (T1 .sizeof == T2 .sizeof
36+ && __traits(isUnsigned, T1 ) == __traits(isUnsigned, T2 )
37+ && ! __traits(isFloating, T1 ) && ! __traits(isFloating, T2 ))
38+ {
39+ if (! __ctfe)
40+ {
41+ // This would improperly allow equality of integers and pointers
42+ // but the CTFE branch will stop this function from compiling then.
43+ import core.stdc.string : memcmp;
44+ return lhs.length == 0 || 0 == memcmp(lhs.ptr, rhs.ptr, lhs.length * T1 .sizeof);
45+ }
46+ }
47+ foreach (const i; 0 .. lhs.length)
48+ if (lhs.ptr[i] != rhs.ptr[i])
49+ return false ;
50+ return true ;
51+ }
52+
53+ pragma (inline, true )
54+ private @trusted ref at(R)(return scope inout (R)[] r, size_t i) { return r.ptr[i]; }
55+ pragma (inline, true )
56+ private @trusted R trustedCast(R, S)(return scope S[] r) { return cast (R) r; }
57+
2658 // `lhs == rhs` lowers to `__equals(lhs, rhs)` for dynamic arrays
2759bool __equals (T1 , T2 )(T1 [] lhs, T2 [] rhs)
60+ if (! __traits(isScalar, T1 ) || ! __traits(isScalar, T2 ))
2861{
2962 import core.internal.traits : Unqual;
3063 alias U1 = Unqual! T1 ;
3164 alias U2 = Unqual! T2 ;
3265
33- static @trusted ref R at(R)(R[] r, size_t i) { return r.ptr[i]; }
34- static @trusted R trustedCast(R, S)(S[] r) { return cast (R) r; }
35-
3666 if (lhs.length != rhs.length)
3767 return false ;
3868
39- if (lhs.length == 0 && rhs.length == 0 )
69+ if (lhs.length == 0 )
4070 return true ;
4171
4272 static if (is (U1 == void ) && is (U2 == void ))
@@ -64,24 +94,6 @@ bool __equals(T1, T2)(T1[] lhs, T2[] rhs)
6494 }
6595 return true ;
6696 }
67- else static if (__traits(isIntegral, U1 ))
68- {
69-
70- if (! __ctfe)
71- {
72- import core.stdc.string : memcmp;
73- return () @trusted { return memcmp(cast (void * )lhs.ptr, cast (void * )rhs.ptr, lhs.length * U1 .sizeof) == 0 ; }();
74- }
75- else
76- {
77- foreach (const u; 0 .. lhs.length)
78- {
79- if (at(lhs, u) != at(rhs, u))
80- return false ;
81- }
82- return true ;
83- }
84- }
8597 else
8698 {
8799 foreach (const u; 0 .. lhs.length)
@@ -91,11 +103,6 @@ bool __equals(T1, T2)(T1[] lhs, T2[] rhs)
91103 if (! __equals(at(lhs, u), at(rhs, u)))
92104 return false ;
93105 }
94- else static if (__traits(isFloating, U1 ))
95- {
96- if (at(lhs, u) != at(rhs, u))
97- return false ;
98- }
99106 else static if (is (U1 : Object ) && is (U2 : Object ))
100107 {
101108 if (! (cast (Object )at(lhs, u) is cast (Object )at(rhs, u)
0 commit comments