@@ -55,15 +55,56 @@ impl<A, B> SlicePartialEq<B> for [A]
55
55
where
56
56
A : PartialEq < B > ,
57
57
{
58
+ #[ inline]
58
59
default fn equal ( & self , other : & [ B ] ) -> bool {
59
60
if self . len ( ) != other. len ( ) {
60
61
return false ;
61
62
}
62
63
63
- self . iter ( ) . zip ( other. iter ( ) ) . all ( |( x, y) | x == y)
64
+ // at least 8 items for unrolling to make sense (4 peeled + 4+ unrolled)
65
+ if self . len ( ) < 8 {
66
+ return eq_small ( self , other) ;
67
+ }
68
+
69
+ eq_unroll ( self , other)
64
70
}
65
71
}
66
72
73
+ #[ inline]
74
+ fn eq_small < A , B > ( a : & [ A ] , b : & [ B ] ) -> bool
75
+ where
76
+ A : PartialEq < B > ,
77
+ {
78
+ a. iter ( ) . zip ( b) . all ( |( a, b) | a == b)
79
+ }
80
+
81
+ fn eq_unroll < A , B > ( a : & [ A ] , b : & [ B ] ) -> bool
82
+ where
83
+ A : PartialEq < B > ,
84
+ {
85
+ let ( mut chunks_a, residual_a) = a. as_chunks :: < 4 > ( ) ;
86
+ let ( mut chunks_b, residual_b) = b. as_chunks :: < 4 > ( ) ;
87
+ let peeled_a = chunks_a. take_first ( ) . unwrap ( ) ;
88
+ let peeled_b = chunks_b. take_first ( ) . unwrap ( ) ;
89
+
90
+ // peel the first chunk and do a short-circuiting comparison to bail early on mismatches
91
+ // in case comparisons are expensive
92
+ let mut result = eq_small ( peeled_a, peeled_b) ;
93
+
94
+ // then check the residual, another chance to bail early
95
+ result = result && eq_small ( residual_a, residual_b) ;
96
+
97
+ // iter.all short-circuits which means the backend can't unroll the loop due to early exits.
98
+ // So we unroll it manually.
99
+ result = result
100
+ && chunks_a
101
+ . iter ( )
102
+ . zip ( chunks_b)
103
+ . all ( |( a, b) | ( a[ 0 ] == b[ 0 ] ) & ( a[ 1 ] == b[ 1 ] ) & ( a[ 2 ] == b[ 2 ] ) & ( a[ 3 ] == b[ 3 ] ) ) ;
104
+
105
+ result
106
+ }
107
+
67
108
// When each element can be compared byte-wise, we can compare all the bytes
68
109
// from the whole size in one call to the intrinsics.
69
110
impl < A , B > SlicePartialEq < B > for [ A ]
0 commit comments