diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index ec6525485f7a1..dc1f2981a50ad 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -481,6 +481,30 @@ pub trait Ord: Eq + PartialOrd { where Self: Sized { if self <= other { self } else { other } } + + /// Returns max if self is greater than max, and min if self is less than min. + /// Otherwise this will return self. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// + /// assert!((-3).clamp(-2, 1) == -2); + /// assert!(0.clamp(-2, 1) == 0); + /// assert!(2.clamp(-2, 1) == 1); + /// ``` + /// + /// # Panics + /// Panics if min > max. + #[unstable(feature = "clamp", issue = "44095")] + fn clamp(self, min: Self, max: Self) -> Self + where Self: Sized { + assert!(min <= max); + if self < min { min } + else if self > max { max } + else { self } + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 0135cd0a588cf..69ca77f54b44a 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -1080,6 +1080,32 @@ impl f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + /// Returns max if self is greater than max, and min if self is less than min. + /// Otherwise this returns self. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// use std::f32::NAN; + /// assert!((-3.0f32).clamp(-2.0f32, 1.0f32) == -2.0f32); + /// assert!((0.0f32).clamp(-2.0f32, 1.0f32) == 0.0f32); + /// assert!((2.0f32).clamp(-2.0f32, 1.0f32) == 1.0f32); + /// assert!((NAN).clamp(-2.0f32, 1.0f32).is_nan()); + /// ``` + /// + /// # Panics + /// Panics if min > max, min is NaN, or max is NaN. + #[unstable(feature = "clamp", issue = "44095")] + #[inline] + pub fn clamp(self, min: f32, max: f32) -> f32 { + assert!(min <= max); + let mut x = self; + if x < min { x = min; } + if x > max { x = max; } + x + } + /// Raw transmutation to `u32`. /// /// Converts the `f32` into its raw memory representation, @@ -1751,4 +1777,22 @@ mod tests { assert_ne!(nan_masked & QNAN_MASK, 0); assert!(nan_masked_fl.is_nan()); } + + #[test] + #[should_panic] + fn test_clamp_min_greater_than_max() { + 1.0f32.clamp(3.0, 1.0); + } + + #[test] + #[should_panic] + fn test_clamp_min_is_nan() { + 1.0f32.clamp(NAN, 1.0); + } + + #[test] + #[should_panic] + fn test_clamp_max_is_nan() { + 1.0f32.clamp(3.0, NAN); + } } diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index d73d7cd2c7bd1..6ec633bfaaac1 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -970,6 +970,32 @@ impl f64 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } + /// Returns max if self is greater than max, and min if self is less than min. + /// Otherwise this returns self. + /// + /// # Examples + /// + /// ``` + /// #![feature(clamp)] + /// use std::f64::NAN; + /// assert!((-3.0f64).clamp(-2.0f64, 1.0f64) == -2.0f64); + /// assert!((0.0f64).clamp(-2.0f64, 1.0f64) == 0.0f64); + /// assert!((2.0f64).clamp(-2.0f64, 1.0f64) == 1.0f64); + /// assert!((NAN).clamp(-2.0f64, 1.0f64).is_nan()); + /// ``` + /// + /// # Panics + /// Panics if min > max, min is NaN, or max is NaN. + #[unstable(feature = "clamp", issue = "44095")] + #[inline] + pub fn clamp(self, min: f64, max: f64) -> f64 { + assert!(min <= max); + let mut x = self; + if x < min { x = min; } + if x > max { x = max; } + x + } + // Solaris/Illumos requires a wrapper around log, log2, and log10 functions // because of their non-standard behavior (e.g. log(-n) returns -Inf instead // of expected NaN). @@ -1642,4 +1668,22 @@ mod tests { assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0); assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25); } + + #[test] + #[should_panic] + fn test_clamp_min_greater_than_max() { + 1.0f64.clamp(3.0, 1.0); + } + + #[test] + #[should_panic] + fn test_clamp_min_is_nan() { + 1.0f64.clamp(NAN, 1.0); + } + + #[test] + #[should_panic] + fn test_clamp_max_is_nan() { + 1.0f64.clamp(3.0, NAN); + } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index cf1eb5cd52ea4..191f7fe648ed2 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -249,6 +249,7 @@ #![feature(cfg_target_vendor)] #![feature(char_error_internals)] #![feature(char_internals)] +#![feature(clamp)] #![feature(collections_range)] #![feature(compiler_builtins_lib)] #![feature(const_fn)]