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;
374 if self.min.is_none() || v.min < self.min {
375 self.min = v.min;
376 }
377 if self.max.is_none() || v.max > self.max {
378 self.max = v.max;
379 }
380
381 self.ascending_pairs += v.ascending_pairs;
383 self.descending_pairs += v.descending_pairs;
384
385 if self.first_value.is_none() {
387 self.first_value.clone_from(&v.first_value);
388 }
389 if let (Some(last), Some(v_first)) = (&self.last_value, &v.first_value) {
390 match v_first.partial_cmp(last) {
391 Some(Ordering::Greater | Ordering::Equal) => self.ascending_pairs += 1,
392 Some(Ordering::Less) => self.descending_pairs += 1,
393 None => {}
394 }
395 }
396 self.last_value = v.last_value;
397 }
398}
399
400impl<T: PartialOrd> Default for MinMax<T> {
401 #[inline]
402 fn default() -> MinMax<T> {
403 MinMax {
404 len: 0,
405 ascending_pairs: 0,
406 descending_pairs: 0,
407 last_value: None,
408 min: None,
409 max: None,
410 first_value: None,
411 }
412 }
413}
414
415impl<T: fmt::Debug> fmt::Debug for MinMax<T> {
416 #[inline]
417 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
418 match (&self.min, &self.max) {
419 (Some(min), Some(max)) => {
420 let sort_status = if let 0 | 1 = self.len {
421 SortOrder::Unsorted
422 } else {
423 let total_pairs = self.ascending_pairs + self.descending_pairs;
424 if total_pairs == 0 {
425 SortOrder::Unsorted
426 } else {
427 let sortiness = (self.ascending_pairs as f64
428 - self.descending_pairs as f64)
429 / total_pairs as f64;
430 match sortiness {
431 1.0 => SortOrder::Ascending,
432 -1.0 => SortOrder::Descending,
433 _ => SortOrder::Unsorted,
434 }
435 }
436 };
437 write!(f, "[{min:?}, {max:?}], sort_order: {sort_status:?}")
438 }
439 (&None, &None) => write!(f, "N/A"),
440 _ => unreachable!(),
441 }
442 }
443}
444
445impl fmt::Display for SortOrder {
446 #[inline]
447 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
448 match self {
449 SortOrder::Unsorted => write!(f, "Unsorted"),
450 SortOrder::Ascending => write!(f, "Ascending"),
451 SortOrder::Descending => write!(f, "Descending"),
452 }
453 }
454}
455
456impl<T: PartialOrd + Clone> FromIterator<T> for MinMax<T> {
457 #[inline]
458 fn from_iter<I: IntoIterator<Item = T>>(it: I) -> MinMax<T> {
459 let mut v = MinMax::new();
460 v.extend(it);
461 v
462 }
463}
464
465impl<T: PartialOrd + Clone> Extend<T> for MinMax<T> {
466 #[inline]
467 fn extend<I: IntoIterator<Item = T>>(&mut self, it: I) {
468 for sample in it {
469 self.add(sample);
470 }
471 }
472}
473
474#[cfg(test)]
475mod test {
476 use super::{MinMax, SortOrder};
477 use crate::Commute;
478
479 #[test]
480 fn minmax() {
481 let minmax: MinMax<u32> = vec![1u32, 4, 2, 3, 10].into_iter().collect();
482 assert_eq!(minmax.min(), Some(&1u32));
483 assert_eq!(minmax.max(), Some(&10u32));
484 assert_eq!(minmax.sort_order(), SortOrder::Unsorted);
485 }
486
487 #[test]
488 fn minmax_sorted_ascending() {
489 let minmax: MinMax<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
490 assert_eq!(minmax.min(), Some(&1u32));
491 assert_eq!(minmax.max(), Some(&5u32));
492 assert_eq!(minmax.sort_order(), SortOrder::Ascending);
493 }
494
495 #[test]
496 fn minmax_sorted_descending() {
497 let minmax: MinMax<u32> = vec![5u32, 4, 3, 2, 1].into_iter().collect();
498 assert_eq!(minmax.min(), Some(&1u32));
499 assert_eq!(minmax.max(), Some(&5u32));
500 assert_eq!(minmax.sort_order(), SortOrder::Descending);
501 }
502
503 #[test]
504 fn minmax_empty() {
505 let minmax: MinMax<u32> = MinMax::new();
506 assert!(minmax.is_empty());
507 assert_eq!(minmax.sort_order(), SortOrder::Unsorted);
508 }
509
510 #[test]
511 fn minmax_merge_empty() {
512 let mut mx1: MinMax<u32> = vec![1, 4, 2, 3, 10].into_iter().collect();
513 assert_eq!(mx1.min(), Some(&1u32));
514 assert_eq!(mx1.max(), Some(&10u32));
515 assert_eq!(mx1.sort_order(), SortOrder::Unsorted);
516
517 mx1.merge(MinMax::default());
518 assert_eq!(mx1.min(), Some(&1u32));
519 assert_eq!(mx1.max(), Some(&10u32));
520 assert_eq!(mx1.sort_order(), SortOrder::Unsorted);
521 }
522
523 #[test]
524 fn minmax_merge_diffsorts() {
525 let mut mx1: MinMax<u32> = vec![1, 2, 2, 2, 3, 3, 4, 10].into_iter().collect();
526 assert_eq!(mx1.min(), Some(&1u32));
527 assert_eq!(mx1.max(), Some(&10u32));
528 assert_eq!(mx1.sort_order(), SortOrder::Ascending);
529
530 let mx2: MinMax<u32> = vec![5, 4, 3, 2, 1].into_iter().collect();
531 assert_eq!(mx2.min(), Some(&1u32));
532 assert_eq!(mx2.max(), Some(&5u32));
533 assert_eq!(mx2.sort_order(), SortOrder::Descending);
534 mx1.merge(mx2);
535 assert_eq!(mx1.min(), Some(&1u32));
536 assert_eq!(mx1.max(), Some(&10u32));
537 assert_eq!(mx1.sort_order(), SortOrder::Unsorted);
538 }
539
540 #[test]
541 fn minmax_merge_asc_sorts() {
542 let mut mx1: MinMax<u32> = vec![2, 2, 2, 5, 10].into_iter().collect();
543 assert_eq!(mx1.min(), Some(&2u32));
544 assert_eq!(mx1.max(), Some(&10u32));
545 assert_eq!(mx1.sort_order(), SortOrder::Ascending);
546
547 let mx2: MinMax<u32> = vec![11, 14, 23, 32, 41].into_iter().collect();
548 assert_eq!(mx2.min(), Some(&11u32));
549 assert_eq!(mx2.max(), Some(&41u32));
550 assert_eq!(mx2.sort_order(), SortOrder::Ascending);
551 mx1.merge(mx2);
552 assert_eq!(mx1.min(), Some(&2u32));
553 assert_eq!(mx1.max(), Some(&41u32));
554 assert_eq!(mx1.sort_order(), SortOrder::Ascending);
555 }
556
557 #[test]
558 fn test_sortiness() {
559 let minmax: MinMax<u32> = MinMax::new();
561 assert_eq!(minmax.sortiness(), 0.0);
562
563 let minmax: MinMax<u32> = vec![1].into_iter().collect();
565 assert_eq!(minmax.sortiness(), 0.0);
566
567 let minmax: MinMax<u32> = vec![1, 2, 3, 4, 5].into_iter().collect();
569 assert_eq!(minmax.sortiness(), 1.0);
570
571 let minmax: MinMax<u32> = vec![5, 4, 3, 2, 1].into_iter().collect();
573 assert_eq!(minmax.sortiness(), -1.0);
574
575 let minmax: MinMax<u32> = vec![1, 1, 1, 1].into_iter().collect();
577 assert_eq!(minmax.sortiness(), 1.0); let minmax: MinMax<u32> = vec![1, 2, 4, 3, 5].into_iter().collect();
581 assert!(minmax.sortiness() > 0.0 && minmax.sortiness() < 1.0);
582 assert_eq!(minmax.sortiness(), 0.5); let minmax: MinMax<u32> = vec![5, 4, 3, 4, 2].into_iter().collect();
586 assert!(minmax.sortiness() < 0.0 && minmax.sortiness() > -1.0);
587 assert_eq!(minmax.sortiness(), -0.5); }
589
590 #[test]
591 fn test_sortiness_merge() {
592 let mut mx1: MinMax<u32> = vec![1, 2, 3].into_iter().collect();
593 let mx2: MinMax<u32> = vec![4, 5, 6].into_iter().collect();
594 assert_eq!(mx1.sortiness(), 1.0);
595 assert_eq!(mx2.sortiness(), 1.0);
596
597 mx1.merge(mx2);
598 assert_eq!(mx1.sortiness(), 1.0); let mut mx3: MinMax<u32> = vec![1, 2, 3].into_iter().collect();
601 let mx4: MinMax<u32> = vec![2, 1, 0].into_iter().collect();
602 mx3.merge(mx4);
603 assert_eq!(mx3, vec![1, 2, 3, 2, 1, 0].into_iter().collect());
604 assert!(mx3.sortiness() < 1.0); assert_eq!(mx3.sortiness(), -0.2);
606 }
607
608 #[test]
609 fn test_merge_single_into_empty() {
610 let mut empty: MinMax<u32> = MinMax::default();
611 let single: MinMax<u32> = vec![42].into_iter().collect();
612
613 assert!(empty.first_value.is_none());
614 assert!(empty.last_value.is_none());
615
616 empty.merge(single);
617
618 assert_eq!(empty.len(), 1);
619 assert_eq!(empty.min(), Some(&42));
620 assert_eq!(empty.max(), Some(&42));
621 assert_eq!(empty.first_value, Some(42));
622 assert_eq!(empty.last_value, Some(42));
627 }
628
629 #[test]
630 fn test_merge_single_into_multi_then_add() {
631 let mut multi: MinMax<u32> = vec![1, 2, 3].into_iter().collect();
635 let single: MinMax<u32> = vec![42].into_iter().collect();
636 multi.merge(single);
637 assert_eq!(multi.len(), 4);
638 assert_eq!(multi.max(), Some(&42));
639 assert!(multi.last_value.is_some());
640 multi.add(100);
642 assert_eq!(multi.max(), Some(&100));
643 assert_eq!(multi.len(), 5);
644 }
645}
646
647#[test]
648fn test_sortiness_simple_alphabetical() {
649 let minmax: MinMax<String> = vec![
650 "a".to_string(),
651 "b".to_string(),
652 "c".to_string(),
653 "d".to_string(),
654 ]
655 .into_iter()
656 .collect();
657 assert_eq!(minmax.sortiness(), 1.0);
658 assert_eq!(minmax.sort_order(), SortOrder::Ascending);
659
660 let minmax: MinMax<String> = vec![
661 "d".to_string(),
662 "c".to_string(),
663 "b".to_string(),
664 "a".to_string(),
665 ]
666 .into_iter()
667 .collect();
668 assert_eq!(minmax.sortiness(), -1.0);
669 assert_eq!(minmax.sort_order(), SortOrder::Descending);
670
671 let minmax: MinMax<String> = vec![
672 "a".to_string(),
673 "b".to_string(),
674 "c".to_string(),
675 "a".to_string(),
676 ]
677 .into_iter()
678 .collect();
679 assert_eq!(minmax.sortiness(), 0.3333333333333333);
680 assert_eq!(minmax.sort_order(), SortOrder::Unsorted);
681}
682
683#[cfg(test)]
684mod test_nan_inf {
685 use super::MinMax;
686
687 #[test]
688 fn test_minmax_nan() {
689 let mut minmax = MinMax::new();
690 minmax.add(1.0f64);
691 minmax.add(f64::NAN);
692 minmax.add(3.0f64);
693 assert_eq!(minmax.min(), Some(&1.0f64));
696 assert_eq!(minmax.max(), Some(&3.0f64));
697 }
698
699 #[test]
700 fn test_minmax_infinity() {
701 let mut minmax = MinMax::new();
702 minmax.add(1.0f64);
703 minmax.add(f64::INFINITY);
704 minmax.add(f64::NEG_INFINITY);
705 assert_eq!(minmax.min(), Some(&f64::NEG_INFINITY));
706 assert_eq!(minmax.max(), Some(&f64::INFINITY));
707 }
708
709 #[test]
710 fn test_minmax_only_infinities() {
711 let mut minmax = MinMax::new();
712 minmax.add(f64::INFINITY);
713 minmax.add(f64::NEG_INFINITY);
714 assert_eq!(minmax.min(), Some(&f64::NEG_INFINITY));
715 assert_eq!(minmax.max(), Some(&f64::INFINITY));
716 assert_eq!(minmax.len(), 2);
717 }
718
719 #[test]
720 fn test_sortiness_with_infinity() {
721 let minmax: MinMax<f64> = vec![1.0, 2.0, f64::INFINITY].into_iter().collect();
722 assert_eq!(minmax.sortiness(), 1.0); }
724}