1use serde::{Deserialize, Serialize};
2use std::cmp::Ordering;
3use std::fmt;
4
5use crate::Commute;
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
9pub enum SortOrder {
10 Unsorted,
11 Ascending,
12 Descending,
13}
14
15#[derive(Clone, Copy, Deserialize, Serialize, Eq, PartialEq)]
18pub struct MinMax<T> {
19 len: u32,
20 min: Option<T>,
21 max: Option<T>,
22 first_value: Option<T>,
23 last_value: Option<T>,
24 ascending_pairs: u32,
25 descending_pairs: u32,
26}
27
28impl<T: PartialOrd + Clone> MinMax<T> {
29 #[must_use]
31 pub fn new() -> MinMax<T> {
32 Default::default()
33 }
34
35 #[inline]
37 pub fn add(&mut self, sample: T) {
38 match self.len {
39 2.. => {
41 if let Some(ref last) = self.last_value {
42 #[allow(clippy::match_same_arms)]
43 match sample.partial_cmp(last) {
44 Some(Ordering::Greater) => self.ascending_pairs += 1,
45 Some(Ordering::Less) => self.descending_pairs += 1,
46 Some(Ordering::Equal) => self.ascending_pairs += 1,
48 None => {}
49 }
50 }
51 }
52 0 => {
53 self.first_value = Some(sample.clone());
55 self.min = Some(sample.clone());
56 self.max = Some(sample);
57 self.len = 1;
58 return;
59 }
60 1 => {
61 if let Some(ref first) = self.first_value {
63 match sample.partial_cmp(first) {
64 Some(Ordering::Greater | Ordering::Equal) => self.ascending_pairs = 1,
65 Some(Ordering::Less) => self.descending_pairs = 1,
66 None => {}
67 }
68 }
69 }
70 }
71
72 if self.min.as_ref().is_none_or(|v| &sample < v) {
74 self.min = Some(sample.clone());
75 } else if self.max.as_ref().is_none_or(|v| &sample > v) {
76 self.max = Some(sample.clone());
77 }
78
79 self.last_value = Some(sample);
81 self.len += 1;
82 }
83
84 #[inline]
88 #[must_use]
89 pub const fn min(&self) -> Option<&T> {
90 self.min.as_ref()
91 }
92
93 #[inline]
97 #[must_use]
98 pub const fn max(&self) -> Option<&T> {
99 self.max.as_ref()
100 }
101
102 #[inline]
104 #[must_use]
105 pub const fn len(&self) -> usize {
106 self.len as usize
107 }
108
109 #[inline]
111 #[must_use]
112 pub const fn is_empty(&self) -> bool {
113 self.len == 0
114 }
115
116 #[inline]
118 #[must_use]
119 pub fn sort_order(&self) -> SortOrder {
120 match self.sortiness() {
121 1.0 => SortOrder::Ascending,
122 -1.0 => SortOrder::Descending,
123 _ => SortOrder::Unsorted,
124 }
125 }
126
127 #[inline]
149 #[must_use]
150 pub fn sortiness(&self) -> f64 {
151 if let 0 | 1 = self.len {
152 0.0
153 } else {
154 let total_pairs = self.ascending_pairs + self.descending_pairs;
155 if total_pairs == 0 {
156 0.0
157 } else {
158 (self.ascending_pairs as f64 - self.descending_pairs as f64) / total_pairs as f64
159 }
160 }
161 }
162}
163
164impl<T: PartialOrd + Clone> Commute for MinMax<T> {
165 #[inline]
166 fn merge(&mut self, v: MinMax<T>) {
167 self.len += v.len;
168 if self.min.is_none() || (v.min.is_some() && v.min < self.min) {
169 self.min = v.min;
170 }
171 if self.max.is_none() || (v.max.is_some() && v.max > self.max) {
172 self.max = v.max;
173 }
174
175 self.ascending_pairs += v.ascending_pairs;
177 self.descending_pairs += v.descending_pairs;
178
179 if self.len > 1 && v.len > 0 {
181 if self.first_value.is_none() {
182 self.first_value.clone_from(&v.first_value);
183 }
184 if let (Some(last), Some(v_first)) = (&self.last_value, &v.first_value) {
185 match v_first.partial_cmp(last) {
186 Some(Ordering::Greater | Ordering::Equal) => self.ascending_pairs += 1,
187 Some(Ordering::Less) => self.descending_pairs += 1,
188 None => {}
189 }
190 }
191 self.last_value = v.last_value;
192 }
193 }
194}
195
196impl<T: PartialOrd> Default for MinMax<T> {
197 #[inline]
198 fn default() -> MinMax<T> {
199 MinMax {
200 len: 0,
201 min: None,
202 max: None,
203 first_value: None,
204 last_value: None,
205 ascending_pairs: 0,
206 descending_pairs: 0,
207 }
208 }
209}
210
211#[cfg(debug_assertions)]
212impl<T: fmt::Debug> fmt::Debug for MinMax<T> {
213 #[inline]
214 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
215 match (&self.min, &self.max) {
216 (Some(min), Some(max)) => {
217 let sort_status = if let 0 | 1 = self.len {
218 SortOrder::Unsorted
219 } else {
220 let total_pairs = self.ascending_pairs + self.descending_pairs;
221 if total_pairs == 0 {
222 SortOrder::Unsorted
223 } else {
224 let sortiness = (self.ascending_pairs as f64
225 - self.descending_pairs as f64)
226 / total_pairs as f64;
227 match sortiness {
228 1.0 => SortOrder::Ascending,
229 -1.0 => SortOrder::Descending,
230 _ => SortOrder::Unsorted,
231 }
232 }
233 };
234 write!(f, "[{min:?}, {max:?}], sort_order: {sort_status:?}")
235 }
236 (&None, &None) => write!(f, "N/A"),
237 _ => unreachable!(),
238 }
239 }
240}
241
242impl fmt::Display for SortOrder {
243 #[inline]
244 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245 match self {
246 SortOrder::Unsorted => write!(f, "Unsorted"),
247 SortOrder::Ascending => write!(f, "Ascending"),
248 SortOrder::Descending => write!(f, "Descending"),
249 }
250 }
251}
252
253impl<T: PartialOrd + Clone> FromIterator<T> for MinMax<T> {
254 #[inline]
255 fn from_iter<I: IntoIterator<Item = T>>(it: I) -> MinMax<T> {
256 let mut v = MinMax::new();
257 v.extend(it);
258 v
259 }
260}
261
262impl<T: PartialOrd + Clone> Extend<T> for MinMax<T> {
263 #[inline]
264 fn extend<I: IntoIterator<Item = T>>(&mut self, it: I) {
265 for sample in it {
266 self.add(sample);
267 }
268 }
269}
270
271#[cfg(test)]
272mod test {
273 use super::{MinMax, SortOrder};
274 use crate::Commute;
275
276 #[test]
277 fn minmax() {
278 let minmax: MinMax<u32> = vec![1u32, 4, 2, 3, 10].into_iter().collect();
279 assert_eq!(minmax.min(), Some(&1u32));
280 assert_eq!(minmax.max(), Some(&10u32));
281 assert_eq!(minmax.sort_order(), SortOrder::Unsorted);
282 }
283
284 #[test]
285 fn minmax_sorted_ascending() {
286 let minmax: MinMax<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
287 assert_eq!(minmax.min(), Some(&1u32));
288 assert_eq!(minmax.max(), Some(&5u32));
289 assert_eq!(minmax.sort_order(), SortOrder::Ascending);
290 }
291
292 #[test]
293 fn minmax_sorted_descending() {
294 let minmax: MinMax<u32> = vec![5u32, 4, 3, 2, 1].into_iter().collect();
295 assert_eq!(minmax.min(), Some(&1u32));
296 assert_eq!(minmax.max(), Some(&5u32));
297 assert_eq!(minmax.sort_order(), SortOrder::Descending);
298 }
299
300 #[test]
301 fn minmax_empty() {
302 let minmax: MinMax<u32> = MinMax::new();
303 assert!(minmax.is_empty());
304 assert_eq!(minmax.sort_order(), SortOrder::Unsorted);
305 }
306
307 #[test]
308 fn minmax_merge_empty() {
309 let mut mx1: MinMax<u32> = vec![1, 4, 2, 3, 10].into_iter().collect();
310 assert_eq!(mx1.min(), Some(&1u32));
311 assert_eq!(mx1.max(), Some(&10u32));
312 assert_eq!(mx1.sort_order(), SortOrder::Unsorted);
313
314 mx1.merge(MinMax::default());
315 assert_eq!(mx1.min(), Some(&1u32));
316 assert_eq!(mx1.max(), Some(&10u32));
317 assert_eq!(mx1.sort_order(), SortOrder::Unsorted);
318 }
319
320 #[test]
321 fn minmax_merge_diffsorts() {
322 let mut mx1: MinMax<u32> = vec![1, 2, 2, 2, 3, 3, 4, 10].into_iter().collect();
323 assert_eq!(mx1.min(), Some(&1u32));
324 assert_eq!(mx1.max(), Some(&10u32));
325 assert_eq!(mx1.sort_order(), SortOrder::Ascending);
326
327 let mx2: MinMax<u32> = vec![5, 4, 3, 2, 1].into_iter().collect();
328 assert_eq!(mx2.min(), Some(&1u32));
329 assert_eq!(mx2.max(), Some(&5u32));
330 assert_eq!(mx2.sort_order(), SortOrder::Descending);
331 mx1.merge(mx2);
332 assert_eq!(mx1.min(), Some(&1u32));
333 assert_eq!(mx1.max(), Some(&10u32));
334 assert_eq!(mx1.sort_order(), SortOrder::Unsorted);
335 }
336
337 #[test]
338 fn minmax_merge_asc_sorts() {
339 let mut mx1: MinMax<u32> = vec![2, 2, 2, 5, 10].into_iter().collect();
340 assert_eq!(mx1.min(), Some(&2u32));
341 assert_eq!(mx1.max(), Some(&10u32));
342 assert_eq!(mx1.sort_order(), SortOrder::Ascending);
343
344 let mx2: MinMax<u32> = vec![11, 14, 23, 32, 41].into_iter().collect();
345 assert_eq!(mx2.min(), Some(&11u32));
346 assert_eq!(mx2.max(), Some(&41u32));
347 assert_eq!(mx2.sort_order(), SortOrder::Ascending);
348 mx1.merge(mx2);
349 assert_eq!(mx1.min(), Some(&2u32));
350 assert_eq!(mx1.max(), Some(&41u32));
351 assert_eq!(mx1.sort_order(), SortOrder::Ascending);
352 }
353
354 #[test]
355 fn test_sortiness() {
356 let minmax: MinMax<u32> = MinMax::new();
358 assert_eq!(minmax.sortiness(), 0.0);
359
360 let minmax: MinMax<u32> = vec![1].into_iter().collect();
362 assert_eq!(minmax.sortiness(), 0.0);
363
364 let minmax: MinMax<u32> = vec![1, 2, 3, 4, 5].into_iter().collect();
366 assert_eq!(minmax.sortiness(), 1.0);
367
368 let minmax: MinMax<u32> = vec![5, 4, 3, 2, 1].into_iter().collect();
370 assert_eq!(minmax.sortiness(), -1.0);
371
372 let minmax: MinMax<u32> = vec![1, 1, 1, 1].into_iter().collect();
374 assert_eq!(minmax.sortiness(), 1.0); let minmax: MinMax<u32> = vec![1, 2, 4, 3, 5].into_iter().collect();
378 assert!(minmax.sortiness() > 0.0 && minmax.sortiness() < 1.0);
379 assert_eq!(minmax.sortiness(), 0.5); let minmax: MinMax<u32> = vec![5, 4, 3, 4, 2].into_iter().collect();
383 assert!(minmax.sortiness() < 0.0 && minmax.sortiness() > -1.0);
384 assert_eq!(minmax.sortiness(), -0.5); }
386
387 #[test]
388 fn test_sortiness_merge() {
389 let mut mx1: MinMax<u32> = vec![1, 2, 3].into_iter().collect();
390 let mx2: MinMax<u32> = vec![4, 5, 6].into_iter().collect();
391 assert_eq!(mx1.sortiness(), 1.0);
392 assert_eq!(mx2.sortiness(), 1.0);
393
394 mx1.merge(mx2);
395 assert_eq!(mx1.sortiness(), 1.0); let mut mx3: MinMax<u32> = vec![1, 2, 3].into_iter().collect();
398 let mx4: MinMax<u32> = vec![2, 1, 0].into_iter().collect();
399 mx3.merge(mx4);
400 assert_eq!(mx3, vec![1, 2, 3, 2, 1, 0].into_iter().collect());
401 assert!(mx3.sortiness() < 1.0); assert_eq!(mx3.sortiness(), -0.2);
403 }
404}