1#![allow(clippy::cast_lossless)]
2use serde::{Deserialize, Serialize};
3use std::cmp::Ordering;
4use std::fmt;
5
6use crate::Commute;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
10pub enum SortOrder {
11 Unsorted,
12 Ascending,
13 Descending,
14}
15
16#[derive(Clone, Copy, Deserialize, Serialize, Eq, PartialEq)]
19pub struct MinMax<T> {
20 len: u32,
23 ascending_pairs: u32,
24 descending_pairs: u32,
25 last_value: Option<T>,
26 min: Option<T>,
28 max: Option<T>,
29 first_value: Option<T>,
30}
31
32impl<T: PartialOrd + Clone> MinMax<T> {
33 #[must_use]
35 pub fn new() -> MinMax<T> {
36 Default::default()
37 }
38
39 #[inline(always)]
41 pub fn add(&mut self, sample: T) {
42 match self.len {
43 2.. => {
45 let last = unsafe { self.last_value.as_ref().unwrap_unchecked() };
48 if sample >= *last {
49 self.ascending_pairs += 1;
50 let max = unsafe { self.max.as_mut().unwrap_unchecked() };
53 if sample > *max {
54 max.clone_from(&sample);
55 }
56 } else if sample < *last {
57 self.descending_pairs += 1;
58 let min = unsafe { self.min.as_mut().unwrap_unchecked() };
61 if sample < *min {
62 min.clone_from(&sample);
63 }
64 } else {
65 let min = unsafe { self.min.as_mut().unwrap_unchecked() };
69 if sample < *min {
70 min.clone_from(&sample);
71 } else {
72 let max = unsafe { self.max.as_mut().unwrap_unchecked() };
73 if sample > *max {
74 max.clone_from(&sample);
75 }
76 }
77 }
78 *unsafe { self.last_value.as_mut().unwrap_unchecked() } = sample;
80 self.len += 1;
81 return;
82 }
83 0 => {
84 self.first_value = Some(sample.clone());
89 self.min = Some(sample.clone());
90 self.last_value = Some(sample.clone());
91 self.max = Some(sample);
92 self.len = 1;
93 return;
94 }
95 1 => {
96 if let Some(ref first) = self.first_value {
98 match sample.partial_cmp(first) {
99 Some(Ordering::Greater | Ordering::Equal) => self.ascending_pairs = 1,
100 Some(Ordering::Less) => self.descending_pairs = 1,
101 None => {}
102 }
103 }
104 }
105 }
106
107 if self.min.as_ref().is_none_or(|v| &sample < v) {
110 self.min = Some(sample.clone());
111 } else if self.max.as_ref().is_none_or(|v| &sample > v) {
112 self.max = Some(sample.clone());
113 }
114
115 self.last_value = Some(sample);
117 self.len += 1;
118 }
119
120 #[inline(always)]
130 pub fn add_ref(&mut self, sample: &T) {
131 match self.len {
132 2.. => {
133 let last = unsafe { self.last_value.as_ref().unwrap_unchecked() };
135 if *sample >= *last {
136 self.ascending_pairs += 1;
137 let max = unsafe { self.max.as_mut().unwrap_unchecked() };
138 if *sample > *max {
139 max.clone_from(sample);
140 }
141 } else if *sample < *last {
142 self.descending_pairs += 1;
143 let min = unsafe { self.min.as_mut().unwrap_unchecked() };
144 if *sample < *min {
145 min.clone_from(sample);
146 }
147 } else {
148 let min = unsafe { self.min.as_mut().unwrap_unchecked() };
150 if *sample < *min {
151 min.clone_from(sample);
152 } else {
153 let max = unsafe { self.max.as_mut().unwrap_unchecked() };
154 if *sample > *max {
155 max.clone_from(sample);
156 }
157 }
158 }
159 unsafe { self.last_value.as_mut().unwrap_unchecked() }.clone_from(sample);
161 self.len += 1;
162 return;
163 }
164 0 => {
165 self.first_value = Some(sample.clone());
168 self.min = Some(sample.clone());
169 self.max = Some(sample.clone());
170 self.last_value = Some(sample.clone());
171 self.len = 1;
172 return;
173 }
174 1 => {
175 if let Some(ref first) = self.first_value {
176 match sample.partial_cmp(first) {
177 Some(Ordering::Greater | Ordering::Equal) => self.ascending_pairs = 1,
178 Some(Ordering::Less) => self.descending_pairs = 1,
179 None => {}
180 }
181 }
182 }
183 }
184
185 if self.min.as_ref().is_none_or(|v| sample < v) {
187 self.min = Some(sample.clone());
188 } else if self.max.as_ref().is_none_or(|v| sample > v) {
189 self.max = Some(sample.clone());
190 }
191
192 if let Some(ref mut last) = self.last_value {
194 last.clone_from(sample);
195 } else {
196 self.last_value = Some(sample.clone());
197 }
198 self.len += 1;
199 }
200
201 #[inline]
205 #[must_use]
206 pub const fn min(&self) -> Option<&T> {
207 self.min.as_ref()
208 }
209
210 #[inline]
214 #[must_use]
215 pub const fn max(&self) -> Option<&T> {
216 self.max.as_ref()
217 }
218
219 #[inline]
221 #[must_use]
222 pub const fn len(&self) -> usize {
223 self.len as usize
224 }
225
226 #[inline]
228 #[must_use]
229 pub const fn is_empty(&self) -> bool {
230 self.len == 0
231 }
232
233 #[inline]
235 #[must_use]
236 pub fn sort_order(&self) -> SortOrder {
237 let sortiness = self.sortiness();
238 if (sortiness - 1.0).abs() <= 1e-9 {
241 SortOrder::Ascending
242 } else if (sortiness + 1.0).abs() <= 1e-9 {
243 SortOrder::Descending
244 } else {
245 SortOrder::Unsorted
246 }
247 }
248
249 #[inline]
271 #[must_use]
272 pub fn sortiness(&self) -> f64 {
273 if let 0 | 1 = self.len {
274 0.0
275 } else {
276 let total_pairs = self.ascending_pairs + self.descending_pairs;
277 if total_pairs == 0 {
278 0.0
279 } else {
280 (self.ascending_pairs as f64 - self.descending_pairs as f64) / total_pairs as f64
281 }
282 }
283 }
284}
285
286impl MinMax<Vec<u8>> {
287 #[inline(always)]
295 pub fn add_bytes(&mut self, sample: &[u8]) {
296 match self.len {
297 2.. => {
298 let last = unsafe { self.last_value.as_ref().unwrap_unchecked() };
301 if sample >= last.as_slice() {
302 self.ascending_pairs += 1;
303 let max = unsafe { self.max.as_mut().unwrap_unchecked() };
304 if sample > max.as_slice() {
305 max.clear();
306 max.extend_from_slice(sample);
307 }
308 } else {
309 self.descending_pairs += 1;
310 let min = unsafe { self.min.as_mut().unwrap_unchecked() };
311 if sample < min.as_slice() {
312 min.clear();
313 min.extend_from_slice(sample);
314 }
315 }
316 let last_mut = unsafe { self.last_value.as_mut().unwrap_unchecked() };
318 last_mut.clear();
319 last_mut.extend_from_slice(sample);
320 self.len += 1;
321 return;
322 }
323 0 => {
324 let owned = sample.to_vec();
327 self.first_value = Some(owned.clone());
328 self.min = Some(owned.clone());
329 self.last_value = Some(owned.clone());
330 self.max = Some(owned);
331 self.len = 1;
332 return;
333 }
334 1 => {
335 if let Some(ref first) = self.first_value {
336 match sample.partial_cmp(first.as_slice()) {
337 Some(Ordering::Greater | Ordering::Equal) => self.ascending_pairs = 1,
338 Some(Ordering::Less) => self.descending_pairs = 1,
339 None => {}
340 }
341 }
342 }
343 }
344
345 if self.min.as_ref().is_none_or(|v| sample < v.as_slice()) {
347 self.min = Some(sample.to_vec());
348 } else if self.max.as_ref().is_none_or(|v| sample > v.as_slice()) {
349 self.max = Some(sample.to_vec());
350 }
351
352 if let Some(ref mut last) = self.last_value {
354 last.clear();
355 last.extend_from_slice(sample);
356 } else {
357 self.last_value = Some(sample.to_vec());
358 }
359 self.len += 1;
360 }
361}
362
363impl<T: PartialOrd + Clone> Commute for MinMax<T> {
364 #[inline]
365 fn merge(&mut self, v: MinMax<T>) {
366 if v.min.is_none() {
367 return;
368 }
369 self.len += v.len;
370 if self.min.is_none() || v.min < self.min {
371 self.min = v.min;
372 }
373 if self.max.is_none() || v.max > self.max {
374 self.max = v.max;
375 }
376
377 self.ascending_pairs += v.ascending_pairs;
379 self.descending_pairs += v.descending_pairs;
380
381 if self.first_value.is_none() {
383 self.first_value.clone_from(&v.first_value);
384 }
385 if v.len > 0 {
386 if let (Some(last), Some(v_first)) = (&self.last_value, &v.first_value) {
387 match v_first.partial_cmp(last) {
388 Some(Ordering::Greater | Ordering::Equal) => self.ascending_pairs += 1,
389 Some(Ordering::Less) => self.descending_pairs += 1,
390 None => {}
391 }
392 }
393 self.last_value = v.last_value;
394 }
395 }
396}
397
398impl<T: PartialOrd> Default for MinMax<T> {
399 #[inline]
400 fn default() -> MinMax<T> {
401 MinMax {
402 len: 0,
403 ascending_pairs: 0,
404 descending_pairs: 0,
405 last_value: None,
406 min: None,
407 max: None,
408 first_value: None,
409 }
410 }
411}
412
413impl<T: fmt::Debug> fmt::Debug for MinMax<T> {
414 #[inline]
415 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
416 match (&self.min, &self.max) {
417 (Some(min), Some(max)) => {
418 let sort_status = if let 0 | 1 = self.len {
419 SortOrder::Unsorted
420 } else {
421 let total_pairs = self.ascending_pairs + self.descending_pairs;
422 if total_pairs == 0 {
423 SortOrder::Unsorted
424 } else {
425 let sortiness = (self.ascending_pairs as f64
426 - self.descending_pairs as f64)
427 / total_pairs as f64;
428 match sortiness {
429 1.0 => SortOrder::Ascending,
430 -1.0 => SortOrder::Descending,
431 _ => SortOrder::Unsorted,
432 }
433 }
434 };
435 write!(f, "[{min:?}, {max:?}], sort_order: {sort_status:?}")
436 }
437 (&None, &None) => write!(f, "N/A"),
438 _ => unreachable!(),
439 }
440 }
441}
442
443impl fmt::Display for SortOrder {
444 #[inline]
445 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
446 match self {
447 SortOrder::Unsorted => write!(f, "Unsorted"),
448 SortOrder::Ascending => write!(f, "Ascending"),
449 SortOrder::Descending => write!(f, "Descending"),
450 }
451 }
452}
453
454impl<T: PartialOrd + Clone> FromIterator<T> for MinMax<T> {
455 #[inline]
456 fn from_iter<I: IntoIterator<Item = T>>(it: I) -> MinMax<T> {
457 let mut v = MinMax::new();
458 v.extend(it);
459 v
460 }
461}
462
463impl<T: PartialOrd + Clone> Extend<T> for MinMax<T> {
464 #[inline]
465 fn extend<I: IntoIterator<Item = T>>(&mut self, it: I) {
466 for sample in it {
467 self.add(sample);
468 }
469 }
470}
471
472#[cfg(test)]
473mod test {
474 use super::{MinMax, SortOrder};
475 use crate::Commute;
476
477 #[test]
478 fn minmax() {
479 let minmax: MinMax<u32> = vec![1u32, 4, 2, 3, 10].into_iter().collect();
480 assert_eq!(minmax.min(), Some(&1u32));
481 assert_eq!(minmax.max(), Some(&10u32));
482 assert_eq!(minmax.sort_order(), SortOrder::Unsorted);
483 }
484
485 #[test]
486 fn minmax_sorted_ascending() {
487 let minmax: MinMax<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
488 assert_eq!(minmax.min(), Some(&1u32));
489 assert_eq!(minmax.max(), Some(&5u32));
490 assert_eq!(minmax.sort_order(), SortOrder::Ascending);
491 }
492
493 #[test]
494 fn minmax_sorted_descending() {
495 let minmax: MinMax<u32> = vec![5u32, 4, 3, 2, 1].into_iter().collect();
496 assert_eq!(minmax.min(), Some(&1u32));
497 assert_eq!(minmax.max(), Some(&5u32));
498 assert_eq!(minmax.sort_order(), SortOrder::Descending);
499 }
500
501 #[test]
502 fn minmax_empty() {
503 let minmax: MinMax<u32> = MinMax::new();
504 assert!(minmax.is_empty());
505 assert_eq!(minmax.sort_order(), SortOrder::Unsorted);
506 }
507
508 #[test]
509 fn minmax_merge_empty() {
510 let mut mx1: MinMax<u32> = vec![1, 4, 2, 3, 10].into_iter().collect();
511 assert_eq!(mx1.min(), Some(&1u32));
512 assert_eq!(mx1.max(), Some(&10u32));
513 assert_eq!(mx1.sort_order(), SortOrder::Unsorted);
514
515 mx1.merge(MinMax::default());
516 assert_eq!(mx1.min(), Some(&1u32));
517 assert_eq!(mx1.max(), Some(&10u32));
518 assert_eq!(mx1.sort_order(), SortOrder::Unsorted);
519 }
520
521 #[test]
522 fn minmax_merge_diffsorts() {
523 let mut mx1: MinMax<u32> = vec![1, 2, 2, 2, 3, 3, 4, 10].into_iter().collect();
524 assert_eq!(mx1.min(), Some(&1u32));
525 assert_eq!(mx1.max(), Some(&10u32));
526 assert_eq!(mx1.sort_order(), SortOrder::Ascending);
527
528 let mx2: MinMax<u32> = vec![5, 4, 3, 2, 1].into_iter().collect();
529 assert_eq!(mx2.min(), Some(&1u32));
530 assert_eq!(mx2.max(), Some(&5u32));
531 assert_eq!(mx2.sort_order(), SortOrder::Descending);
532 mx1.merge(mx2);
533 assert_eq!(mx1.min(), Some(&1u32));
534 assert_eq!(mx1.max(), Some(&10u32));
535 assert_eq!(mx1.sort_order(), SortOrder::Unsorted);
536 }
537
538 #[test]
539 fn minmax_merge_asc_sorts() {
540 let mut mx1: MinMax<u32> = vec![2, 2, 2, 5, 10].into_iter().collect();
541 assert_eq!(mx1.min(), Some(&2u32));
542 assert_eq!(mx1.max(), Some(&10u32));
543 assert_eq!(mx1.sort_order(), SortOrder::Ascending);
544
545 let mx2: MinMax<u32> = vec![11, 14, 23, 32, 41].into_iter().collect();
546 assert_eq!(mx2.min(), Some(&11u32));
547 assert_eq!(mx2.max(), Some(&41u32));
548 assert_eq!(mx2.sort_order(), SortOrder::Ascending);
549 mx1.merge(mx2);
550 assert_eq!(mx1.min(), Some(&2u32));
551 assert_eq!(mx1.max(), Some(&41u32));
552 assert_eq!(mx1.sort_order(), SortOrder::Ascending);
553 }
554
555 #[test]
556 fn test_sortiness() {
557 let minmax: MinMax<u32> = MinMax::new();
559 assert_eq!(minmax.sortiness(), 0.0);
560
561 let minmax: MinMax<u32> = vec![1].into_iter().collect();
563 assert_eq!(minmax.sortiness(), 0.0);
564
565 let minmax: MinMax<u32> = vec![1, 2, 3, 4, 5].into_iter().collect();
567 assert_eq!(minmax.sortiness(), 1.0);
568
569 let minmax: MinMax<u32> = vec![5, 4, 3, 2, 1].into_iter().collect();
571 assert_eq!(minmax.sortiness(), -1.0);
572
573 let minmax: MinMax<u32> = vec![1, 1, 1, 1].into_iter().collect();
575 assert_eq!(minmax.sortiness(), 1.0); let minmax: MinMax<u32> = vec![1, 2, 4, 3, 5].into_iter().collect();
579 assert!(minmax.sortiness() > 0.0 && minmax.sortiness() < 1.0);
580 assert_eq!(minmax.sortiness(), 0.5); let minmax: MinMax<u32> = vec![5, 4, 3, 4, 2].into_iter().collect();
584 assert!(minmax.sortiness() < 0.0 && minmax.sortiness() > -1.0);
585 assert_eq!(minmax.sortiness(), -0.5); }
587
588 #[test]
589 fn test_sortiness_merge() {
590 let mut mx1: MinMax<u32> = vec![1, 2, 3].into_iter().collect();
591 let mx2: MinMax<u32> = vec![4, 5, 6].into_iter().collect();
592 assert_eq!(mx1.sortiness(), 1.0);
593 assert_eq!(mx2.sortiness(), 1.0);
594
595 mx1.merge(mx2);
596 assert_eq!(mx1.sortiness(), 1.0); let mut mx3: MinMax<u32> = vec![1, 2, 3].into_iter().collect();
599 let mx4: MinMax<u32> = vec![2, 1, 0].into_iter().collect();
600 mx3.merge(mx4);
601 assert_eq!(mx3, vec![1, 2, 3, 2, 1, 0].into_iter().collect());
602 assert!(mx3.sortiness() < 1.0); assert_eq!(mx3.sortiness(), -0.2);
604 }
605
606 #[test]
607 fn test_merge_single_into_empty() {
608 let mut empty: MinMax<u32> = MinMax::default();
609 let single: MinMax<u32> = vec![42].into_iter().collect();
610
611 assert!(empty.first_value.is_none());
612 assert!(empty.last_value.is_none());
613
614 empty.merge(single);
615
616 assert_eq!(empty.len(), 1);
617 assert_eq!(empty.min(), Some(&42));
618 assert_eq!(empty.max(), Some(&42));
619 assert_eq!(empty.first_value, Some(42));
620 assert_eq!(empty.last_value, Some(42));
625 }
626
627 #[test]
628 fn test_merge_single_into_multi_then_add() {
629 let mut multi: MinMax<u32> = vec![1, 2, 3].into_iter().collect();
633 let single: MinMax<u32> = vec![42].into_iter().collect();
634 multi.merge(single);
635 assert_eq!(multi.len(), 4);
636 assert_eq!(multi.max(), Some(&42));
637 assert!(multi.last_value.is_some());
638 multi.add(100);
640 assert_eq!(multi.max(), Some(&100));
641 assert_eq!(multi.len(), 5);
642 }
643}
644
645#[test]
646fn test_sortiness_simple_alphabetical() {
647 let minmax: MinMax<String> = vec![
648 "a".to_string(),
649 "b".to_string(),
650 "c".to_string(),
651 "d".to_string(),
652 ]
653 .into_iter()
654 .collect();
655 assert_eq!(minmax.sortiness(), 1.0);
656 assert_eq!(minmax.sort_order(), SortOrder::Ascending);
657
658 let minmax: MinMax<String> = vec![
659 "d".to_string(),
660 "c".to_string(),
661 "b".to_string(),
662 "a".to_string(),
663 ]
664 .into_iter()
665 .collect();
666 assert_eq!(minmax.sortiness(), -1.0);
667 assert_eq!(minmax.sort_order(), SortOrder::Descending);
668
669 let minmax: MinMax<String> = vec![
670 "a".to_string(),
671 "b".to_string(),
672 "c".to_string(),
673 "a".to_string(),
674 ]
675 .into_iter()
676 .collect();
677 assert_eq!(minmax.sortiness(), 0.3333333333333333);
678 assert_eq!(minmax.sort_order(), SortOrder::Unsorted);
679}
680
681#[cfg(test)]
682mod test_nan_inf {
683 use super::MinMax;
684
685 #[test]
686 fn test_minmax_nan() {
687 let mut minmax = MinMax::new();
688 minmax.add(1.0f64);
689 minmax.add(f64::NAN);
690 minmax.add(3.0f64);
691 assert_eq!(minmax.min(), Some(&1.0f64));
694 assert_eq!(minmax.max(), Some(&3.0f64));
695 }
696
697 #[test]
698 fn test_minmax_infinity() {
699 let mut minmax = MinMax::new();
700 minmax.add(1.0f64);
701 minmax.add(f64::INFINITY);
702 minmax.add(f64::NEG_INFINITY);
703 assert_eq!(minmax.min(), Some(&f64::NEG_INFINITY));
704 assert_eq!(minmax.max(), Some(&f64::INFINITY));
705 }
706
707 #[test]
708 fn test_minmax_only_infinities() {
709 let mut minmax = MinMax::new();
710 minmax.add(f64::INFINITY);
711 minmax.add(f64::NEG_INFINITY);
712 assert_eq!(minmax.min(), Some(&f64::NEG_INFINITY));
713 assert_eq!(minmax.max(), Some(&f64::INFINITY));
714 assert_eq!(minmax.len(), 2);
715 }
716
717 #[test]
718 fn test_sortiness_with_infinity() {
719 let minmax: MinMax<f64> = vec![1.0, 2.0, f64::INFINITY].into_iter().collect();
720 assert_eq!(minmax.sortiness(), 1.0); }
722}