Skip to main content

competitive/tools/
ord_tools.rs

1pub trait PartialOrdExt: Sized {
2    fn chmin(&mut self, other: Self);
3    fn chmax(&mut self, other: Self);
4    fn minmax(self, other: Self) -> (Self, Self);
5}
6impl<T> PartialOrdExt for T
7where
8    T: PartialOrd,
9{
10    #[inline]
11    fn chmin(&mut self, other: Self) {
12        if *self > other {
13            *self = other;
14        }
15    }
16    #[inline]
17    fn chmax(&mut self, other: Self) {
18        if *self < other {
19            *self = other;
20        }
21    }
22    #[inline]
23    fn minmax(self, other: Self) -> (Self, Self) {
24        if self < other {
25            (self, other)
26        } else {
27            (other, self)
28        }
29    }
30}
31
32#[macro_export]
33macro_rules! min {
34    ($l:expr) => { $l };
35    ($l:expr,) => { $crate::min!($l) };
36    ($l:expr, $r:expr) => { ($l).min($r) };
37    ($l:expr, $r:expr,) => { $crate::min!($l, $r) };
38    ($l:expr, $r:expr, $($t:tt)*) => { $crate::min!($crate::min!($l, $r), $($t)*) };
39}
40
41#[macro_export]
42macro_rules! chmin {
43    ($l:expr) => {};
44    ($l:expr,) => {};
45    ($l:expr, $r:expr) => {{ let r = $r; if $l > r { $l = r; } }};
46    ($l:expr, $r:expr,) => { $crate::chmin!($l, $r) };
47    ($l:expr, $r:expr, $($t:tt)*) => { $crate::chmin!($l, $r); $crate::chmin!($l, $($t)*) };
48}
49
50#[macro_export]
51macro_rules! max {
52    ($l:expr) => { $l };
53    ($l:expr,) => { $crate::max!($l) };
54    ($l:expr, $r:expr) => { ($l).max($r) };
55    ($l:expr, $r:expr,) => { $crate::max!($l, $r) };
56    ($l:expr, $r:expr, $($t:tt)*) => { $crate::max!($crate::max!($l, $r), $($t)*) };
57}
58
59#[macro_export]
60macro_rules! chmax {
61    ($l:expr) => {};
62    ($l:expr,) => {};
63    ($l:expr, $r:expr) => {{ let r = $r; if $l < r { $l = r; } }};
64    ($l:expr, $r:expr,) => { $crate::chmax!($l, $r) };
65    ($l:expr, $r:expr, $($t:tt)*) => { $crate::chmax!($l, $r); $crate::chmax!($l, $($t)*) };
66}
67
68#[macro_export]
69macro_rules! minmax {
70    ($($t:tt)*) => { ($crate::min!($($t)*), $crate::max!($($t)*)) };
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76    use crate::tools::Xorshift;
77    use std::array;
78
79    #[test]
80    fn test_order_operations() {
81        let mut rng = Xorshift::default();
82        for _ in 0..10_000 {
83            let values: [i32; 4] = array::from_fn(|_| rng.random(-100..=100));
84            let [a, b, c, d] = values;
85            let lo = *values.iter().min().unwrap();
86            let hi = *values.iter().max().unwrap();
87            assert_eq!(min!(a), a);
88            assert_eq!(max!(a), a);
89            assert_eq!(min!(a, b), a.min(b));
90            assert_eq!(max!(a, b), a.max(b));
91            assert_eq!(min!(a, b, c, d,), lo);
92            assert_eq!(max!(a, b, c, d,), hi);
93            assert_eq!(minmax!(a, b, c, d), (lo, hi));
94            let mut x = a;
95            chmin!(x, b, c, d);
96            assert_eq!(x, lo);
97            let mut x = a;
98            chmax!(x, b, c, d);
99            assert_eq!(x, hi);
100            let mut x = a;
101            x.chmin(b);
102            assert_eq!(x, a.min(b));
103            x.chmax(c);
104            assert_eq!(x, a.min(b).max(c));
105            assert_eq!(a.minmax(b), (a.min(b), a.max(b)));
106            assert_eq!(min!(a as f64, b as f64, c as f64, d as f64), lo as f64);
107            assert_eq!(max!(a as f64, b as f64, c as f64, d as f64), hi as f64);
108        }
109    }
110}