Skip to content

Commit b93e3ab

Browse files
authored
Rollup merge of rust-lang#128495 - joboet:more_memcmp, r=scottmcm
core: use `compare_bytes` for more slice element types `bool`, `NonZero<u8>`, `Option<NonZero<u8>>` and `ascii::Char` can be compared the same way as `u8`.
2 parents d432698 + 4b816b4 commit b93e3ab

File tree

1 file changed

+33
-10
lines changed

1 file changed

+33
-10
lines changed

Diff for: core/src/slice/cmp.rs

+33-10
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
use super::{from_raw_parts, memchr};
44
use crate::cmp::{self, BytewiseEq, Ordering};
55
use crate::intrinsics::compare_bytes;
6-
use crate::mem;
6+
use crate::num::NonZero;
7+
use crate::{ascii, mem};
78

89
#[stable(feature = "rust1", since = "1.0.0")]
910
impl<T, U> PartialEq<[U]> for [T]
@@ -182,19 +183,41 @@ impl<A: Ord> SliceOrd for A {
182183
}
183184
}
184185

185-
// `compare_bytes` compares a sequence of unsigned bytes lexicographically.
186-
// this matches the order we want for [u8], but no others (not even [i8]).
187-
impl SliceOrd for u8 {
186+
/// Marks that a type should be treated as an unsigned byte for comparisons.
187+
///
188+
/// # Safety
189+
/// * The type must be readable as an `u8`, meaning it has to have the same
190+
/// layout as `u8` and always be initialized.
191+
/// * For every `x` and `y` of this type, `Ord(x, y)` must return the same
192+
/// value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`.
193+
#[rustc_specialization_trait]
194+
unsafe trait UnsignedBytewiseOrd {}
195+
196+
unsafe impl UnsignedBytewiseOrd for bool {}
197+
unsafe impl UnsignedBytewiseOrd for u8 {}
198+
unsafe impl UnsignedBytewiseOrd for NonZero<u8> {}
199+
unsafe impl UnsignedBytewiseOrd for Option<NonZero<u8>> {}
200+
unsafe impl UnsignedBytewiseOrd for ascii::Char {}
201+
202+
// `compare_bytes` compares a sequence of unsigned bytes lexicographically, so
203+
// use it if the requirements for `UnsignedBytewiseOrd` are fulfilled.
204+
impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
188205
#[inline]
189206
fn compare(left: &[Self], right: &[Self]) -> Ordering {
190-
// Since the length of a slice is always less than or equal to isize::MAX, this never underflows.
207+
// Since the length of a slice is always less than or equal to
208+
// isize::MAX, this never underflows.
191209
let diff = left.len() as isize - right.len() as isize;
192-
// This comparison gets optimized away (on x86_64 and ARM) because the subtraction updates flags.
210+
// This comparison gets optimized away (on x86_64 and ARM) because the
211+
// subtraction updates flags.
193212
let len = if left.len() < right.len() { left.len() } else { right.len() };
194-
// SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
195-
// We use the minimum of both lengths which guarantees that both regions are
196-
// valid for reads in that interval.
197-
let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize };
213+
let left = left.as_ptr().cast();
214+
let right = right.as_ptr().cast();
215+
// SAFETY: `left` and `right` are references and are thus guaranteed to
216+
// be valid. `UnsignedBytewiseOrd` is only implemented for types that
217+
// are valid u8s and can be compared the same way. We use the minimum
218+
// of both lengths which guarantees that both regions are valid for
219+
// reads in that interval.
220+
let mut order = unsafe { compare_bytes(left, right, len) as isize };
198221
if order == 0 {
199222
order = diff;
200223
}

0 commit comments

Comments
 (0)