From 6e5ada43bf84b15a8dd4d55f5bee3ba1a9939bfe Mon Sep 17 00:00:00 2001 From: Tim Vermeulen Date: Sat, 31 Aug 2019 23:00:15 +0200 Subject: [PATCH] Add cmp::{min_by, min_by_key, max_by, max_by_key} --- src/libcore/cmp.rs | 90 +++++++++++++++++++++++++++++++++++++++- src/libcore/tests/cmp.rs | 24 ++++++++++- src/libcore/tests/lib.rs | 1 + 3 files changed, 112 insertions(+), 3 deletions(-) diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 7ec2295f97e..4e2b1627e15 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -570,7 +570,7 @@ pub trait Ord: Eq + PartialOrd { #[inline] fn max(self, other: Self) -> Self where Self: Sized { - if other >= self { other } else { self } + max_by(self, other, Ord::cmp) } /// Compares and returns the minimum of two values. @@ -587,7 +587,7 @@ pub trait Ord: Eq + PartialOrd { #[inline] fn min(self, other: Self) -> Self where Self: Sized { - if self <= other { self } else { other } + min_by(self, other, Ord::cmp) } /// Restrict a value to a certain interval. @@ -898,6 +898,49 @@ pub fn min(v1: T, v2: T) -> T { v1.min(v2) } +/// Returns the minimum of two values with respect to the specified comparison function. +/// +/// Returns the first argument if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_min_max_by)] +/// +/// use std::cmp; +/// +/// assert_eq!(cmp::min_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), 1); +/// assert_eq!(cmp::min_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), -2); +/// ``` +#[inline] +#[unstable(feature = "cmp_min_max_by", issue = "64460")] +pub fn min_by Ordering>(v1: T, v2: T, compare: F) -> T { + match compare(&v1, &v2) { + Ordering::Less | Ordering::Equal => v1, + Ordering::Greater => v2, + } +} + +/// Returns the element that gives the minimum value from the specified function. +/// +/// Returns the first argument if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_min_max_by)] +/// +/// use std::cmp; +/// +/// assert_eq!(cmp::min_by_key(-2, 1, |x: &i32| x.abs()), 1); +/// assert_eq!(cmp::min_by_key(-2, 2, |x: &i32| x.abs()), -2); +/// ``` +#[inline] +#[unstable(feature = "cmp_min_max_by", issue = "64460")] +pub fn min_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { + min_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) +} + /// Compares and returns the maximum of two values. /// /// Returns the second argument if the comparison determines them to be equal. @@ -918,6 +961,49 @@ pub fn max(v1: T, v2: T) -> T { v1.max(v2) } +/// Returns the maximum of two values with respect to the specified comparison function. +/// +/// Returns the second argument if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_min_max_by)] +/// +/// use std::cmp; +/// +/// assert_eq!(cmp::max_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), -2); +/// assert_eq!(cmp::max_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), 2); +/// ``` +#[inline] +#[unstable(feature = "cmp_min_max_by", issue = "64460")] +pub fn max_by Ordering>(v1: T, v2: T, compare: F) -> T { + match compare(&v1, &v2) { + Ordering::Less | Ordering::Equal => v2, + Ordering::Greater => v1, + } +} + +/// Returns the element that gives the maximum value from the specified function. +/// +/// Returns the second argument if the comparison determines them to be equal. +/// +/// # Examples +/// +/// ``` +/// #![feature(cmp_min_max_by)] +/// +/// use std::cmp; +/// +/// assert_eq!(cmp::max_by_key(-2, 1, |x: &i32| x.abs()), -2); +/// assert_eq!(cmp::max_by_key(-2, 2, |x: &i32| x.abs()), 2); +/// ``` +#[inline] +#[unstable(feature = "cmp_min_max_by", issue = "64460")] +pub fn max_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { + max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2))) +} + // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types mod impls { use crate::cmp::Ordering::{self, Less, Greater, Equal}; diff --git a/src/libcore/tests/cmp.rs b/src/libcore/tests/cmp.rs index 4e624e5eb12..5e6778e222a 100644 --- a/src/libcore/tests/cmp.rs +++ b/src/libcore/tests/cmp.rs @@ -1,4 +1,4 @@ -use core::cmp::Ordering::{Less, Greater, Equal}; +use core::cmp::{self, Ordering::*}; #[test] fn test_int_totalord() { @@ -28,6 +28,28 @@ fn test_ord_max_min() { assert_eq!(1.min(1), 1); } +#[test] +fn test_ord_min_max_by() { + let f = |x: &i32, y: &i32| x.abs().cmp(&y.abs()); + assert_eq!(cmp::min_by(1, -1, f), 1); + assert_eq!(cmp::min_by(1, -2, f), 1); + assert_eq!(cmp::min_by(2, -1, f), -1); + assert_eq!(cmp::max_by(1, -1, f), -1); + assert_eq!(cmp::max_by(1, -2, f), -2); + assert_eq!(cmp::max_by(2, -1, f), 2); +} + +#[test] +fn test_ord_min_max_by_key() { + let f = |x: &i32| x.abs(); + assert_eq!(cmp::min_by_key(1, -1, f), 1); + assert_eq!(cmp::min_by_key(1, -2, f), 1); + assert_eq!(cmp::min_by_key(2, -1, f), -1); + assert_eq!(cmp::max_by_key(1, -1, f), -1); + assert_eq!(cmp::max_by_key(1, -2, f), -2); + assert_eq!(cmp::max_by_key(2, -1, f), 2); +} + #[test] fn test_ordering_reverse() { assert_eq!(Less.reverse(), Greater); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 050195cd2ef..35661356028 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -34,6 +34,7 @@ #![feature(iter_partition_in_place)] #![feature(iter_is_partitioned)] #![feature(iter_order_by)] +#![feature(cmp_min_max_by)] extern crate test;