diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index a1ed993b7d9bf..961b54ee0aec9 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -25,8 +25,8 @@ #![stable(feature = "rust1", since = "1.0.0")] -mod bytewise; -pub(crate) use bytewise::BytewiseEq; +mod spec; +pub(crate) use spec::{AlwaysApplicableOrd, BytewiseEq, UnsignedBytewiseOrd}; use self::Ordering::*; @@ -817,7 +817,9 @@ impl Clone for Reverse { #[doc(alias = ">=")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Ord"] -pub trait Ord: Eq + PartialOrd { +pub trait Ord<#[unstable(feature = "generic_ord", issue = "none")] Rhs: ?Sized = Self>: + Eq + PartialOrd +{ /// This method returns an [`Ordering`] between `self` and `other`. /// /// By convention, `self.cmp(&other)` returns the ordering matching the expression @@ -835,7 +837,7 @@ pub trait Ord: Eq + PartialOrd { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "ord_cmp_method"] - fn cmp(&self, other: &Self) -> Ordering; + fn cmp(&self, other: &Rhs) -> Ordering; /// Compares and returns the maximum of two values. /// @@ -851,11 +853,12 @@ pub trait Ord: Eq + PartialOrd { #[inline] #[must_use] #[rustc_diagnostic_item = "cmp_ord_max"] - fn max(self, other: Self) -> Self + fn max(self, other: Rhs) -> Self where Self: Sized, + Rhs: Sized + Into, { - max_by(self, other, Ord::cmp) + if self > other { self } else { other.into() } } /// Compares and returns the minimum of two values. @@ -872,11 +875,12 @@ pub trait Ord: Eq + PartialOrd { #[inline] #[must_use] #[rustc_diagnostic_item = "cmp_ord_min"] - fn min(self, other: Self) -> Self + fn min(self, other: Rhs) -> Self where Self: Sized, + Rhs: Sized + Into, { - min_by(self, other, Ord::cmp) + if self <= other { self } else { other.into() } } /// Restrict a value to a certain interval. @@ -898,16 +902,16 @@ pub trait Ord: Eq + PartialOrd { #[must_use] #[inline] #[stable(feature = "clamp", since = "1.50.0")] - fn clamp(self, min: Self, max: Self) -> Self + fn clamp(self, min: Rhs, max: Rhs) -> Self where Self: Sized, - Self: PartialOrd, + Rhs: Sized + PartialOrd + Into, { assert!(min <= max); if self < min { - min + min.into() } else if self > max { - max + max.into() } else { self } @@ -1692,12 +1696,12 @@ mod impls { } } #[stable(feature = "rust1", since = "1.0.0")] - impl Ord for &A + impl Ord<&B> for &A where - A: Ord, + A: Ord, { #[inline] - fn cmp(&self, other: &Self) -> Ordering { + fn cmp(&self, other: &&B) -> Ordering { Ord::cmp(*self, *other) } } @@ -1747,12 +1751,12 @@ mod impls { } } #[stable(feature = "rust1", since = "1.0.0")] - impl Ord for &mut A + impl Ord<&mut B> for &mut A where - A: Ord, + A: Ord, { #[inline] - fn cmp(&self, other: &Self) -> Ordering { + fn cmp(&self, other: &&mut B) -> Ordering { Ord::cmp(*self, *other) } } diff --git a/library/core/src/cmp/bytewise.rs b/library/core/src/cmp/spec.rs similarity index 67% rename from library/core/src/cmp/bytewise.rs rename to library/core/src/cmp/spec.rs index a06a5227fe285..354c397b57d3a 100644 --- a/library/core/src/cmp/bytewise.rs +++ b/library/core/src/cmp/spec.rs @@ -1,3 +1,4 @@ +use crate::ascii; use crate::num::NonZero; /// Types where `==` & `!=` are equivalent to comparing their underlying bytes. @@ -80,3 +81,40 @@ macro_rules! is_bytewise_comparable_array_length { // error: specializing impl repeats parameter `N` // so just do it for a couple of plausibly-common ones. is_bytewise_comparable_array_length!(0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64); + +/// 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] +pub(crate) unsafe trait UnsignedBytewiseOrd: Ord + Sized {} + +unsafe impl UnsignedBytewiseOrd for bool {} +unsafe impl UnsignedBytewiseOrd for u8 {} +unsafe impl UnsignedBytewiseOrd for NonZero {} +unsafe impl UnsignedBytewiseOrd for Option> {} +unsafe impl UnsignedBytewiseOrd for ascii::Char {} + +/// Marks that a type's [`Ord`] impl can always be used instead of its [`PartialOrd`] impl, +/// so that we can specialize slice `Ord`. +#[rustc_specialization_trait] +pub(crate) trait AlwaysApplicableOrd: Ord {} + +macro_rules! always_applicable_ord { + ($($t:ty,)*) => { + $(impl AlwaysApplicableOrd for $t {})* + } +} + +always_applicable_ord! { + u8, u16, u32, u64, u128, usize, + i8, i16, i32, i64, i128, isize, + bool, char, +} + +// to ensure soundness, these must have differing types +impl AlwaysApplicableOrd<&U> for &T where T: AlwaysApplicableOrd {} +impl AlwaysApplicableOrd<&mut U> for &mut T where T: AlwaysApplicableOrd {} diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 1769612def0a5..bc39240922739 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -1,10 +1,9 @@ //! Comparison traits for `[T]`. use super::{from_raw_parts, memchr}; -use crate::cmp::{self, BytewiseEq, Ordering}; +use crate::cmp::{self, AlwaysApplicableOrd, BytewiseEq, Ordering, UnsignedBytewiseOrd}; use crate::intrinsics::compare_bytes; -use crate::num::NonZero; -use crate::{ascii, mem}; +use crate::mem; #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq<[U]> for [T] @@ -20,51 +19,32 @@ where } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for [T] {} - -/// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison). -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for [T] { - fn cmp(&self, other: &[T]) -> Ordering { - SliceOrd::compare(self, other) - } -} - -/// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison). -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for [T] { - fn partial_cmp(&self, other: &[T]) -> Option { - SlicePartialOrd::partial_compare(self, other) - } -} - #[doc(hidden)] // intermediate trait for specialization of slice's PartialEq -trait SlicePartialEq { - fn equal(&self, other: &[B]) -> bool; +trait SlicePartialEq: Sized { + fn equal(left: &[Self], right: &[B]) -> bool; - fn not_equal(&self, other: &[B]) -> bool { - !self.equal(other) + fn not_equal(left: &[Self], right: &[B]) -> bool { + !Self::equal(left, right) } } // Generic slice equality -impl SlicePartialEq for [A] +impl SlicePartialEq for A where A: PartialEq, { - default fn equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { + default fn equal(left: &[A], right: &[B]) -> bool { + if left.len() != right.len() { return false; } // Implemented as explicit indexing rather // than zipped iterators for performance reasons. // See PR https://github.com/rust-lang/rust/pull/116846 - for idx in 0..self.len() { + for idx in 0..left.len() { // bound checks are optimized away - if self[idx] != other[idx] { + if left[idx] != right[idx] { return false; } } @@ -75,32 +55,49 @@ where // When each element can be compared byte-wise, we can compare all the bytes // from the whole size in one call to the intrinsics. -impl SlicePartialEq for [A] +impl SlicePartialEq for A where A: BytewiseEq, { - fn equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { + fn equal(left: &[A], right: &[B]) -> bool { + if left.len() != right.len() { return false; } // SAFETY: `self` and `other` are references and are thus guaranteed to be valid. // The two slices have been checked to have the same size above. unsafe { - let size = mem::size_of_val(self); - compare_bytes(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 + let size = mem::size_of_val(left); + compare_bytes(left.as_ptr() as *const u8, right.as_ptr() as *const u8, size) == 0 } } } +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for [T] {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd<[U]> for [T] +where + T: PartialOrd, +{ + fn partial_cmp(&self, other: &[U]) -> Option { + SlicePartialOrd::partial_compare(self, other) + } +} + #[doc(hidden)] // intermediate trait for specialization of slice's PartialOrd -trait SlicePartialOrd: Sized { - fn partial_compare(left: &[Self], right: &[Self]) -> Option; +trait SlicePartialOrd: Sized { + fn partial_compare(left: &[Self], right: &[B]) -> Option; } -impl SlicePartialOrd for A { - default fn partial_compare(left: &[A], right: &[A]) -> Option { +/// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison). +impl SlicePartialOrd for A +where + A: PartialOrd, +{ + default fn partial_compare(left: &[A], right: &[B]) -> Option { let l = cmp::min(left.len(), right.len()); // Slice to the loop iteration range to enable bound check @@ -119,52 +116,37 @@ impl SlicePartialOrd for A { } } -// This is the impl that we would like to have. Unfortunately it's not sound. -// See `partial_ord_slice.rs`. -/* -impl SlicePartialOrd for A +impl SlicePartialOrd for A where - A: Ord, + A: AlwaysApplicableOrd, { - default fn partial_compare(left: &[A], right: &[A]) -> Option { - Some(SliceOrd::compare(left, right)) - } -} -*/ - -impl SlicePartialOrd for A { - fn partial_compare(left: &[A], right: &[A]) -> Option { + fn partial_compare(left: &[A], right: &[B]) -> Option { Some(SliceOrd::compare(left, right)) } } -#[rustc_specialization_trait] -trait AlwaysApplicableOrd: SliceOrd + Ord {} - -macro_rules! always_applicable_ord { - ($([$($p:tt)*] $t:ty,)*) => { - $(impl<$($p)*> AlwaysApplicableOrd for $t {})* +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for [T] +where + T: Ord, +{ + fn cmp(&self, other: &[T]) -> Ordering { + SliceOrd::compare(self, other) } } -always_applicable_ord! { - [] u8, [] u16, [] u32, [] u64, [] u128, [] usize, - [] i8, [] i16, [] i32, [] i64, [] i128, [] isize, - [] bool, [] char, - [T: ?Sized] *const T, [T: ?Sized] *mut T, - [T: AlwaysApplicableOrd] &T, - [T: AlwaysApplicableOrd] &mut T, - [T: AlwaysApplicableOrd] Option, -} - #[doc(hidden)] // intermediate trait for specialization of slice's Ord -trait SliceOrd: Sized { - fn compare(left: &[Self], right: &[Self]) -> Ordering; +trait SliceOrd: Sized + Ord { + fn compare(left: &[Self], right: &[B]) -> Ordering; } -impl SliceOrd for A { - default fn compare(left: &[Self], right: &[Self]) -> Ordering { +/// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison). +impl SliceOrd for A +where + A: Ord, +{ + default fn compare(left: &[A], right: &[B]) -> Ordering { let l = cmp::min(left.len(), right.len()); // Slice to the loop iteration range to enable bound check @@ -183,27 +165,14 @@ impl SliceOrd for A { } } -/// 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 UnsignedBytewiseOrd {} - -unsafe impl UnsignedBytewiseOrd for bool {} -unsafe impl UnsignedBytewiseOrd for u8 {} -unsafe impl UnsignedBytewiseOrd for NonZero {} -unsafe impl UnsignedBytewiseOrd for Option> {} -unsafe impl UnsignedBytewiseOrd for ascii::Char {} - // `compare_bytes` compares a sequence of unsigned bytes lexicographically, so // use it if the requirements for `UnsignedBytewiseOrd` are fulfilled. -impl SliceOrd for A { +impl SliceOrd for A +where + A: UnsignedBytewiseOrd, +{ #[inline] - fn compare(left: &[Self], right: &[Self]) -> Ordering { + fn compare(left: &[A], right: &[B]) -> Ordering { // 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; @@ -225,6 +194,7 @@ impl SliceOrd for A { } } +// trait for specialization of `slice::contains` pub(super) trait SliceContains: Sized { fn slice_contains(&self, x: &[Self]) -> bool; }