1use num_traits::Bounded;
2
3use crate::float::IsFloat;
4use crate::float16::pf16;
5
6pub trait MinMax: Sized {
16 fn nan_min_lt(&self, other: &Self) -> bool;
20 fn nan_max_lt(&self, other: &Self) -> bool;
21
22 #[inline(always)]
23 fn nan_min_gt(&self, other: &Self) -> bool {
24 other.nan_min_lt(self)
25 }
26
27 #[inline(always)]
28 fn nan_max_gt(&self, other: &Self) -> bool {
29 other.nan_max_lt(self)
30 }
31
32 #[inline(always)]
34 fn min_propagate_nan(self, other: Self) -> Self {
35 if self.nan_min_lt(&other) { self } else { other }
36 }
37
38 #[inline(always)]
39 fn max_propagate_nan(self, other: Self) -> Self {
40 if self.nan_max_lt(&other) { other } else { self }
41 }
42
43 #[inline(always)]
44 fn min_ignore_nan(self, other: Self) -> Self {
45 if self.nan_max_lt(&other) { self } else { other }
46 }
47
48 #[inline(always)]
49 fn max_ignore_nan(self, other: Self) -> Self {
50 if self.nan_min_lt(&other) { other } else { self }
51 }
52}
53
54macro_rules! impl_trivial_min_max {
55 ($T: ty) => {
56 impl MinMax for $T {
57 #[inline(always)]
58 fn nan_min_lt(&self, other: &Self) -> bool {
59 self < other
60 }
61
62 #[inline(always)]
63 fn nan_max_lt(&self, other: &Self) -> bool {
64 self < other
65 }
66 }
67 };
68}
69
70impl_trivial_min_max!(bool);
73impl_trivial_min_max!(u8);
74impl_trivial_min_max!(u16);
75impl_trivial_min_max!(u32);
76impl_trivial_min_max!(u64);
77impl_trivial_min_max!(u128);
78impl_trivial_min_max!(usize);
79impl_trivial_min_max!(i8);
80impl_trivial_min_max!(i16);
81impl_trivial_min_max!(i32);
82impl_trivial_min_max!(i64);
83impl_trivial_min_max!(i128);
84impl_trivial_min_max!(isize);
85impl_trivial_min_max!(char);
86impl_trivial_min_max!(&str);
87impl_trivial_min_max!(&[u8]);
88impl_trivial_min_max!(String);
89
90macro_rules! impl_float_min_max {
91 ($T: ty) => {
92 impl MinMax for $T {
93 #[inline(always)]
94 fn nan_min_lt(&self, other: &Self) -> bool {
95 !(other.is_nan() | (self >= other))
96 }
97
98 #[inline(always)]
99 fn nan_max_lt(&self, other: &Self) -> bool {
100 !(self.is_nan() | (self >= other))
101 }
102
103 #[inline(always)]
104 fn min_ignore_nan(self, other: Self) -> Self {
105 <$T>::min(self, other)
106 }
107
108 #[inline(always)]
109 fn max_ignore_nan(self, other: Self) -> Self {
110 <$T>::max(self, other)
111 }
112
113 #[inline(always)]
114 fn min_propagate_nan(self, other: Self) -> Self {
115 if (self < other) | self.is_nan() {
116 self
117 } else {
118 other
119 }
120 }
121
122 #[inline(always)]
123 fn max_propagate_nan(self, other: Self) -> Self {
124 if (self > other) | self.is_nan() {
125 self
126 } else {
127 other
128 }
129 }
130 }
131 };
132}
133
134impl_float_min_max!(pf16);
135impl_float_min_max!(f32);
136impl_float_min_max!(f64);
137
138pub trait MinMaxPolicy {
139 fn is_better<T: MinMax>(a: &T, b: &T) -> bool;
141 fn best<T: MinMax>(a: T, b: T) -> T;
142
143 #[inline]
145 fn identity<T: MinMax + IsFloat + Bounded>() -> T {
146 let (lo, hi) = if T::is_float() {
147 (T::neg_inf_value(), T::pos_inf_value())
148 } else {
149 (T::min_value(), T::max_value())
150 };
151 if Self::is_better(&lo, &hi) { hi } else { lo }
152 }
153}
154
155#[derive(Copy, Clone, Debug)]
156pub struct MinIgnoreNan;
157impl MinMaxPolicy for MinIgnoreNan {
158 fn is_better<T: MinMax>(a: &T, b: &T) -> bool {
159 T::nan_max_lt(a, b)
160 }
161
162 fn best<T: MinMax>(a: T, b: T) -> T {
163 T::min_ignore_nan(a, b)
164 }
165}
166
167#[derive(Copy, Clone, Debug)]
168pub struct MinPropagateNan;
169impl MinMaxPolicy for MinPropagateNan {
170 fn is_better<T: MinMax>(a: &T, b: &T) -> bool {
171 T::nan_min_lt(a, b)
172 }
173
174 fn best<T: MinMax>(a: T, b: T) -> T {
175 T::min_propagate_nan(a, b)
176 }
177}
178
179#[derive(Copy, Clone, Debug)]
180pub struct MaxIgnoreNan;
181impl MinMaxPolicy for MaxIgnoreNan {
182 fn is_better<T: MinMax>(a: &T, b: &T) -> bool {
183 T::nan_min_lt(b, a)
184 }
185
186 fn best<T: MinMax>(a: T, b: T) -> T {
187 T::max_ignore_nan(a, b)
188 }
189}
190
191#[derive(Copy, Clone, Debug)]
192pub struct MaxPropagateNan;
193impl MinMaxPolicy for MaxPropagateNan {
194 fn is_better<T: MinMax>(a: &T, b: &T) -> bool {
195 T::nan_max_lt(b, a)
196 }
197
198 fn best<T: MinMax>(a: T, b: T) -> T {
199 T::max_propagate_nan(a, b)
200 }
201}