pub trait MinMax: Sized {
fn nan_min_lt(&self, other: &Self) -> bool;
fn nan_max_lt(&self, other: &Self) -> bool;
#[inline(always)]
fn min_propagate_nan(self, other: Self) -> Self {
if self.nan_min_lt(&other) { self } else { other }
}
#[inline(always)]
fn max_propagate_nan(self, other: Self) -> Self {
if self.nan_max_lt(&other) { other } else { self }
}
#[inline(always)]
fn min_ignore_nan(self, other: Self) -> Self {
if self.nan_max_lt(&other) { self } else { other }
}
#[inline(always)]
fn max_ignore_nan(self, other: Self) -> Self {
if self.nan_min_lt(&other) { other } else { self }
}
}
macro_rules! impl_trivial_min_max {
($T: ty) => {
impl MinMax for $T {
#[inline(always)]
fn nan_min_lt(&self, other: &Self) -> bool {
self < other
}
#[inline(always)]
fn nan_max_lt(&self, other: &Self) -> bool {
self < other
}
}
};
}
impl_trivial_min_max!(bool);
impl_trivial_min_max!(u8);
impl_trivial_min_max!(u16);
impl_trivial_min_max!(u32);
impl_trivial_min_max!(u64);
impl_trivial_min_max!(u128);
impl_trivial_min_max!(usize);
impl_trivial_min_max!(i8);
impl_trivial_min_max!(i16);
impl_trivial_min_max!(i32);
impl_trivial_min_max!(i64);
impl_trivial_min_max!(i128);
impl_trivial_min_max!(isize);
impl_trivial_min_max!(char);
impl_trivial_min_max!(&str);
impl_trivial_min_max!(&[u8]);
impl_trivial_min_max!(String);
macro_rules! impl_float_min_max {
($T: ty) => {
impl MinMax for $T {
#[inline(always)]
fn nan_min_lt(&self, other: &Self) -> bool {
!(other.is_nan() | (self >= other))
}
#[inline(always)]
fn nan_max_lt(&self, other: &Self) -> bool {
!(self.is_nan() | (self >= other))
}
#[inline(always)]
fn min_ignore_nan(self, other: Self) -> Self {
<$T>::min(self, other)
}
#[inline(always)]
fn max_ignore_nan(self, other: Self) -> Self {
<$T>::max(self, other)
}
#[inline(always)]
fn min_propagate_nan(self, other: Self) -> Self {
if (self < other) | self.is_nan() {
self
} else {
other
}
}
#[inline(always)]
fn max_propagate_nan(self, other: Self) -> Self {
if (self > other) | self.is_nan() {
self
} else {
other
}
}
}
};
}
impl_float_min_max!(f32);
impl_float_min_max!(f64);
pub trait MinMaxPolicy {
fn is_better<T: MinMax>(a: &T, b: &T) -> bool;
fn best<T: MinMax>(a: T, b: T) -> T;
}
#[derive(Copy, Clone, Debug)]
pub struct MinIgnoreNan;
impl MinMaxPolicy for MinIgnoreNan {
fn is_better<T: MinMax>(a: &T, b: &T) -> bool {
T::nan_max_lt(a, b)
}
fn best<T: MinMax>(a: T, b: T) -> T {
T::min_ignore_nan(a, b)
}
}
#[derive(Copy, Clone, Debug)]
pub struct MinPropagateNan;
impl MinMaxPolicy for MinPropagateNan {
fn is_better<T: MinMax>(a: &T, b: &T) -> bool {
T::nan_min_lt(a, b)
}
fn best<T: MinMax>(a: T, b: T) -> T {
T::min_propagate_nan(a, b)
}
}
#[derive(Copy, Clone, Debug)]
pub struct MaxIgnoreNan;
impl MinMaxPolicy for MaxIgnoreNan {
fn is_better<T: MinMax>(a: &T, b: &T) -> bool {
T::nan_min_lt(b, a)
}
fn best<T: MinMax>(a: T, b: T) -> T {
T::max_ignore_nan(a, b)
}
}
#[derive(Copy, Clone, Debug)]
pub struct MaxPropagateNan;
impl MinMaxPolicy for MaxPropagateNan {
fn is_better<T: MinMax>(a: &T, b: &T) -> bool {
T::nan_max_lt(b, a)
}
fn best<T: MinMax>(a: T, b: T) -> T {
T::max_propagate_nan(a, b)
}
}