Skip to content

Commit

Permalink
Tweak the default PartialOrd::{lt,le,gt,ge}
Browse files Browse the repository at this point in the history
  • Loading branch information
scottmcm committed Dec 22, 2022
1 parent e5e4eef commit 6e1c3f0
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 16 deletions.
54 changes: 38 additions & 16 deletions library/core/src/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,12 +360,18 @@ impl Ordering {
/// assert_eq!(Ordering::Equal.is_eq(), true);
/// assert_eq!(Ordering::Greater.is_eq(), false);
/// ```
#[inline]
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")]
#[stable(feature = "ordering_helpers", since = "1.53.0")]
pub const fn is_eq(self) -> bool {
matches!(self, Equal)
// Implementation note: It appears (as of 2022-12) that LLVM has an
// easier time with a comparison against zero like this, as opposed
// to looking for the `Less` value (-1) specifically, maybe because
// it's not always obvious to it that -2 isn't possible.
// Thus this and its siblings below are written this way, rather
// than the potentially-more-obvious `matches!` version.
(self as i8) == 0
}

/// Returns `true` if the ordering is not the `Equal` variant.
Expand All @@ -379,12 +385,12 @@ impl Ordering {
/// assert_eq!(Ordering::Equal.is_ne(), false);
/// assert_eq!(Ordering::Greater.is_ne(), true);
/// ```
#[inline]
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")]
#[stable(feature = "ordering_helpers", since = "1.53.0")]
pub const fn is_ne(self) -> bool {
!matches!(self, Equal)
(self as i8) != 0
}

/// Returns `true` if the ordering is the `Less` variant.
Expand All @@ -398,12 +404,12 @@ impl Ordering {
/// assert_eq!(Ordering::Equal.is_lt(), false);
/// assert_eq!(Ordering::Greater.is_lt(), false);
/// ```
#[inline]
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")]
#[stable(feature = "ordering_helpers", since = "1.53.0")]
pub const fn is_lt(self) -> bool {
matches!(self, Less)
(self as i8) < 0
}

/// Returns `true` if the ordering is the `Greater` variant.
Expand All @@ -417,12 +423,12 @@ impl Ordering {
/// assert_eq!(Ordering::Equal.is_gt(), false);
/// assert_eq!(Ordering::Greater.is_gt(), true);
/// ```
#[inline]
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")]
#[stable(feature = "ordering_helpers", since = "1.53.0")]
pub const fn is_gt(self) -> bool {
matches!(self, Greater)
(self as i8) > 0
}

/// Returns `true` if the ordering is either the `Less` or `Equal` variant.
Expand All @@ -436,12 +442,12 @@ impl Ordering {
/// assert_eq!(Ordering::Equal.is_le(), true);
/// assert_eq!(Ordering::Greater.is_le(), false);
/// ```
#[inline]
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")]
#[stable(feature = "ordering_helpers", since = "1.53.0")]
pub const fn is_le(self) -> bool {
!matches!(self, Greater)
(self as i8) <= 0
}

/// Returns `true` if the ordering is either the `Greater` or `Equal` variant.
Expand All @@ -455,12 +461,12 @@ impl Ordering {
/// assert_eq!(Ordering::Equal.is_ge(), true);
/// assert_eq!(Ordering::Greater.is_ge(), true);
/// ```
#[inline]
#[inline(always)]
#[must_use]
#[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")]
#[stable(feature = "ordering_helpers", since = "1.53.0")]
pub const fn is_ge(self) -> bool {
!matches!(self, Less)
(self as i8) >= 0
}

/// Reverses the `Ordering`.
Expand Down Expand Up @@ -1124,7 +1130,11 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
fn lt(&self, other: &Rhs) -> bool {
matches!(self.partial_cmp(other), Some(Less))
if let Some(ordering) = self.partial_cmp(other) {
ordering.is_lt()
} else {
false
}
}

/// This method tests less than or equal to (for `self` and `other`) and is used by the `<=`
Expand All @@ -1143,7 +1153,11 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
fn le(&self, other: &Rhs) -> bool {
matches!(self.partial_cmp(other), Some(Less | Equal))
if let Some(ordering) = self.partial_cmp(other) {
ordering.is_le()
} else {
false
}
}

/// This method tests greater than (for `self` and `other`) and is used by the `>` operator.
Expand All @@ -1161,7 +1175,11 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
fn gt(&self, other: &Rhs) -> bool {
matches!(self.partial_cmp(other), Some(Greater))
if let Some(ordering) = self.partial_cmp(other) {
ordering.is_gt()
} else {
false
}
}

/// This method tests greater than or equal to (for `self` and `other`) and is used by the `>=`
Expand All @@ -1180,7 +1198,11 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
fn ge(&self, other: &Rhs) -> bool {
matches!(self.partial_cmp(other), Some(Greater | Equal))
if let Some(ordering) = self.partial_cmp(other) {
ordering.is_ge()
} else {
false
}
}
}

Expand Down
49 changes: 49 additions & 0 deletions src/test/codegen/newtype-relational-operators.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// The `derive(PartialOrd)` for a newtype doesn't override `lt`/`le`/`gt`/`ge`.
// This double-checks that the `Option<Ordering>` intermediate values used
// in the operators for such a type all optimize away.

// compile-flags: -C opt-level=1
// min-llvm-version: 15.0

#![crate_type = "lib"]

use std::cmp::Ordering;

#[derive(PartialOrd, PartialEq)]
pub struct Foo(u16);

// CHECK-LABEL: @check_lt
// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]])
#[no_mangle]
pub fn check_lt(a: Foo, b: Foo) -> bool {
// CHECK: %[[R:.+]] = icmp ult i16 %[[A]], %[[B]]
// CHECK-NEXT: ret i1 %[[R]]
a < b
}

// CHECK-LABEL: @check_le
// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]])
#[no_mangle]
pub fn check_le(a: Foo, b: Foo) -> bool {
// CHECK: %[[R:.+]] = icmp ule i16 %[[A]], %[[B]]
// CHECK-NEXT: ret i1 %[[R]]
a <= b
}

// CHECK-LABEL: @check_gt
// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]])
#[no_mangle]
pub fn check_gt(a: Foo, b: Foo) -> bool {
// CHECK: %[[R:.+]] = icmp ugt i16 %[[A]], %[[B]]
// CHECK-NEXT: ret i1 %[[R]]
a > b
}

// CHECK-LABEL: @check_ge
// CHECK-SAME: (i16 %[[A:.+]], i16 %[[B:.+]])
#[no_mangle]
pub fn check_ge(a: Foo, b: Foo) -> bool {
// CHECK: %[[R:.+]] = icmp uge i16 %[[A]], %[[B]]
// CHECK-NEXT: ret i1 %[[R]]
a >= b
}

0 comments on commit 6e1c3f0

Please sign in to comment.