competitive/num/
bounded.rs1pub 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}