Skip to content

Commit

Permalink
core: make documentation clearer, rename slice comparison specializat…
Browse files Browse the repository at this point in the history
…ion trait
  • Loading branch information
joboet committed Aug 12, 2024
1 parent b927541 commit 4b816b4
Showing 1 changed file with 25 additions and 15 deletions.
40 changes: 25 additions & 15 deletions core/src/slice/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,30 +183,40 @@ impl<A: Ord> SliceOrd for A {
}
}

// The type should be treated as an unsigned byte for comparisons.
/// Marks that a type should be treated as an unsigned byte for comparisons.
///
/// # Safety
/// * The type must be readable as an `u8`, meaning it has to have the same
/// layout as `u8` and always be initialized.
/// * For every `x` and `y` of this type, `Ord(x, y)` must return the same
/// value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`.
#[rustc_specialization_trait]
unsafe trait UnsignedByte {}
unsafe trait UnsignedBytewiseOrd {}

unsafe impl UnsignedByte for bool {}
unsafe impl UnsignedByte for u8 {}
unsafe impl UnsignedByte for NonZero<u8> {}
unsafe impl UnsignedByte for Option<NonZero<u8>> {}
unsafe impl UnsignedByte for ascii::Char {}
unsafe impl UnsignedBytewiseOrd for bool {}
unsafe impl UnsignedBytewiseOrd for u8 {}
unsafe impl UnsignedBytewiseOrd for NonZero<u8> {}
unsafe impl UnsignedBytewiseOrd for Option<NonZero<u8>> {}
unsafe impl UnsignedBytewiseOrd for ascii::Char {}

// `compare_bytes` compares a sequence of unsigned bytes lexicographically.
impl<A: Ord + UnsignedByte> SliceOrd for A {
// `compare_bytes` compares a sequence of unsigned bytes lexicographically, so
// use it if the requirements for `UnsignedBytewiseOrd` are fulfilled.
impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
#[inline]
fn compare(left: &[Self], right: &[Self]) -> Ordering {
// Since the length of a slice is always less than or equal to isize::MAX, this never underflows.
// Since the length of a slice is always less than or equal to
// isize::MAX, this never underflows.
let diff = left.len() as isize - right.len() as isize;
// This comparison gets optimized away (on x86_64 and ARM) because the subtraction updates flags.
// This comparison gets optimized away (on x86_64 and ARM) because the
// subtraction updates flags.
let len = if left.len() < right.len() { left.len() } else { right.len() };
let left = left.as_ptr().cast();
let right = right.as_ptr().cast();
// SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
// `UnsignedByte` is only implemented for types that are valid u8s. We use the
// minimum of both lengths which guarantees that both regions are valid for reads
// in that interval.
// SAFETY: `left` and `right` are references and are thus guaranteed to
// be valid. `UnsignedBytewiseOrd` is only implemented for types that
// are valid u8s and can be compared the same way. We use the minimum
// of both lengths which guarantees that both regions are valid for
// reads in that interval.
let mut order = unsafe { compare_bytes(left, right, len) as isize };
if order == 0 {
order = diff;
Expand Down

0 comments on commit 4b816b4

Please sign in to comment.