Skip to content

Commit 6e5ada4

Browse files
committed
Add cmp::{min_by, min_by_key, max_by, max_by_key}
1 parent 2c0931e commit 6e5ada4

File tree

3 files changed

+112
-3
lines changed

3 files changed

+112
-3
lines changed

src/libcore/cmp.rs

+88-2
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ pub trait Ord: Eq + PartialOrd<Self> {
570570
#[inline]
571571
fn max(self, other: Self) -> Self
572572
where Self: Sized {
573-
if other >= self { other } else { self }
573+
max_by(self, other, Ord::cmp)
574574
}
575575

576576
/// Compares and returns the minimum of two values.
@@ -587,7 +587,7 @@ pub trait Ord: Eq + PartialOrd<Self> {
587587
#[inline]
588588
fn min(self, other: Self) -> Self
589589
where Self: Sized {
590-
if self <= other { self } else { other }
590+
min_by(self, other, Ord::cmp)
591591
}
592592

593593
/// Restrict a value to a certain interval.
@@ -898,6 +898,49 @@ pub fn min<T: Ord>(v1: T, v2: T) -> T {
898898
v1.min(v2)
899899
}
900900

901+
/// Returns the minimum of two values with respect to the specified comparison function.
902+
///
903+
/// Returns the first argument if the comparison determines them to be equal.
904+
///
905+
/// # Examples
906+
///
907+
/// ```
908+
/// #![feature(cmp_min_max_by)]
909+
///
910+
/// use std::cmp;
911+
///
912+
/// assert_eq!(cmp::min_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), 1);
913+
/// assert_eq!(cmp::min_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), -2);
914+
/// ```
915+
#[inline]
916+
#[unstable(feature = "cmp_min_max_by", issue = "64460")]
917+
pub fn min_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
918+
match compare(&v1, &v2) {
919+
Ordering::Less | Ordering::Equal => v1,
920+
Ordering::Greater => v2,
921+
}
922+
}
923+
924+
/// Returns the element that gives the minimum value from the specified function.
925+
///
926+
/// Returns the first argument if the comparison determines them to be equal.
927+
///
928+
/// # Examples
929+
///
930+
/// ```
931+
/// #![feature(cmp_min_max_by)]
932+
///
933+
/// use std::cmp;
934+
///
935+
/// assert_eq!(cmp::min_by_key(-2, 1, |x: &i32| x.abs()), 1);
936+
/// assert_eq!(cmp::min_by_key(-2, 2, |x: &i32| x.abs()), -2);
937+
/// ```
938+
#[inline]
939+
#[unstable(feature = "cmp_min_max_by", issue = "64460")]
940+
pub fn min_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
941+
min_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
942+
}
943+
901944
/// Compares and returns the maximum of two values.
902945
///
903946
/// Returns the second argument if the comparison determines them to be equal.
@@ -918,6 +961,49 @@ pub fn max<T: Ord>(v1: T, v2: T) -> T {
918961
v1.max(v2)
919962
}
920963

964+
/// Returns the maximum of two values with respect to the specified comparison function.
965+
///
966+
/// Returns the second argument if the comparison determines them to be equal.
967+
///
968+
/// # Examples
969+
///
970+
/// ```
971+
/// #![feature(cmp_min_max_by)]
972+
///
973+
/// use std::cmp;
974+
///
975+
/// assert_eq!(cmp::max_by(-2, 1, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), -2);
976+
/// assert_eq!(cmp::max_by(-2, 2, |x: &i32, y: &i32| x.abs().cmp(&y.abs())), 2);
977+
/// ```
978+
#[inline]
979+
#[unstable(feature = "cmp_min_max_by", issue = "64460")]
980+
pub fn max_by<T, F: FnOnce(&T, &T) -> Ordering>(v1: T, v2: T, compare: F) -> T {
981+
match compare(&v1, &v2) {
982+
Ordering::Less | Ordering::Equal => v2,
983+
Ordering::Greater => v1,
984+
}
985+
}
986+
987+
/// Returns the element that gives the maximum value from the specified function.
988+
///
989+
/// Returns the second argument if the comparison determines them to be equal.
990+
///
991+
/// # Examples
992+
///
993+
/// ```
994+
/// #![feature(cmp_min_max_by)]
995+
///
996+
/// use std::cmp;
997+
///
998+
/// assert_eq!(cmp::max_by_key(-2, 1, |x: &i32| x.abs()), -2);
999+
/// assert_eq!(cmp::max_by_key(-2, 2, |x: &i32| x.abs()), 2);
1000+
/// ```
1001+
#[inline]
1002+
#[unstable(feature = "cmp_min_max_by", issue = "64460")]
1003+
pub fn max_by_key<T, F: FnMut(&T) -> K, K: Ord>(v1: T, v2: T, mut f: F) -> T {
1004+
max_by(v1, v2, |v1, v2| f(v1).cmp(&f(v2)))
1005+
}
1006+
9211007
// Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
9221008
mod impls {
9231009
use crate::cmp::Ordering::{self, Less, Greater, Equal};

src/libcore/tests/cmp.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::cmp::Ordering::{Less, Greater, Equal};
1+
use core::cmp::{self, Ordering::*};
22

33
#[test]
44
fn test_int_totalord() {
@@ -28,6 +28,28 @@ fn test_ord_max_min() {
2828
assert_eq!(1.min(1), 1);
2929
}
3030

31+
#[test]
32+
fn test_ord_min_max_by() {
33+
let f = |x: &i32, y: &i32| x.abs().cmp(&y.abs());
34+
assert_eq!(cmp::min_by(1, -1, f), 1);
35+
assert_eq!(cmp::min_by(1, -2, f), 1);
36+
assert_eq!(cmp::min_by(2, -1, f), -1);
37+
assert_eq!(cmp::max_by(1, -1, f), -1);
38+
assert_eq!(cmp::max_by(1, -2, f), -2);
39+
assert_eq!(cmp::max_by(2, -1, f), 2);
40+
}
41+
42+
#[test]
43+
fn test_ord_min_max_by_key() {
44+
let f = |x: &i32| x.abs();
45+
assert_eq!(cmp::min_by_key(1, -1, f), 1);
46+
assert_eq!(cmp::min_by_key(1, -2, f), 1);
47+
assert_eq!(cmp::min_by_key(2, -1, f), -1);
48+
assert_eq!(cmp::max_by_key(1, -1, f), -1);
49+
assert_eq!(cmp::max_by_key(1, -2, f), -2);
50+
assert_eq!(cmp::max_by_key(2, -1, f), 2);
51+
}
52+
3153
#[test]
3254
fn test_ordering_reverse() {
3355
assert_eq!(Less.reverse(), Greater);

src/libcore/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#![feature(iter_partition_in_place)]
3535
#![feature(iter_is_partitioned)]
3636
#![feature(iter_order_by)]
37+
#![feature(cmp_min_max_by)]
3738

3839
extern crate test;
3940

0 commit comments

Comments
 (0)