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