Skip to main content

competitive/num/
bounded.rs

1/// Trait for max/min bounds
2pub trait Bounded: Sized + PartialOrd {
3    fn maximum() -> Self;
4    fn minimum() -> Self;
5    fn is_maximum(&self) -> bool {
6        self == &Self::maximum()
7    }
8    fn is_minimum(&self) -> bool {
9        self == &Self::minimum()
10    }
11    fn set_maximum(&mut self) {
12        *self = Self::maximum()
13    }
14    fn set_minimum(&mut self) {
15        *self = Self::minimum()
16    }
17}
18
19macro_rules! impl_bounded_num {
20    ($($t:ident)*) => {
21        $(impl Bounded for $t {
22            fn maximum() -> Self { $t::MAX }
23            fn minimum() -> Self { $t::MIN }
24        })*
25    };
26}
27impl_bounded_num!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize f32 f64);
28
29macro_rules! impl_bounded_tuple {
30    (@impl $($T:ident)*) => {
31        impl<$($T: Bounded),*> Bounded for ($($T,)*) {
32            fn maximum() -> Self { ($(<$T as Bounded>::maximum(),)*) }
33            fn minimum() -> Self { ($(<$T as Bounded>::minimum(),)*) }
34        }
35    };
36    (@inner $($T:ident)*,) => {
37        impl_bounded_tuple!(@impl $($T)*);
38    };
39    (@inner $($T:ident)*, $U:ident $($Rest:ident)*) => {
40        impl_bounded_tuple!(@impl $($T)*);
41        impl_bounded_tuple!(@inner $($T)* $U, $($Rest)*);
42    };
43    ($T:ident $($Rest:ident)*) => {
44        impl_bounded_tuple!(@inner $T, $($Rest)*);
45    };
46}
47impl_bounded_tuple!(A B C D E F G H I J);
48
49impl Bounded for () {
50    fn maximum() -> Self {}
51    fn minimum() -> Self {}
52}
53impl Bounded for bool {
54    fn maximum() -> Self {
55        true
56    }
57    fn minimum() -> Self {
58        false
59    }
60}
61impl<T> Bounded for Option<T>
62where
63    T: Bounded,
64{
65    fn maximum() -> Self {
66        Some(<T as Bounded>::maximum())
67    }
68    fn minimum() -> Self {
69        None
70    }
71}
72impl<T> Bounded for std::cmp::Reverse<T>
73where
74    T: Bounded,
75{
76    fn maximum() -> Self {
77        std::cmp::Reverse(<T as Bounded>::minimum())
78    }
79    fn minimum() -> Self {
80        std::cmp::Reverse(<T as Bounded>::maximum())
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87    use crate::tools::Xorshift;
88    use std::cmp::Reverse;
89
90    fn assert_bounded<T: Bounded>(item: T) {
91        assert!(T::minimum() <= item);
92        assert!(item <= T::maximum());
93    }
94
95    #[test]
96    fn test_bounded() {
97        let mut rng = Xorshift::default();
98        let mut cases = Vec::new();
99        for a in [0u32, 1, u32::MAX] {
100            for b in [i64::MIN, -1, 0, 1, i64::MAX] {
101                for c in [0usize, 1, usize::MAX] {
102                    for d in [false, true] {
103                        cases.push((a, b, c, d));
104                    }
105                }
106            }
107        }
108        cases.extend((0..10_000).map(|_| {
109            (
110                rng.random(..),
111                rng.random(..),
112                rng.random(..),
113                rng.random(0..2) == 0,
114            )
115        }));
116        for (a, b, c, d) in cases {
117            assert_bounded(a);
118            assert_bounded(b);
119            assert_bounded(c);
120            assert_bounded(a as i32);
121            assert_bounded(b as u64);
122            assert_bounded(c as isize);
123            assert_bounded(d);
124            assert_bounded((a, b, c));
125            assert_bounded(((), (a,), (b, c)));
126            assert_bounded(if d { Some((d, b)) } else { None });
127            assert_bounded(Reverse(b));
128        }
129    }
130}