1#[macro_export]
12macro_rules! max {
13 ($arg:expr) => { $arg };
14 ($arg1:expr, $($arg:expr),+) => {
15 core::cmp::max($arg1, $crate::max!( $($arg),+ ))
16 };
17}
18
19#[macro_export]
28macro_rules! min {
29 ($arg:expr) => { $arg };
30 ($arg1:expr, $($arg:expr),+) => {
31 core::cmp::min($arg1, $crate::min!( $($arg),+ ))
32 };
33}
34
35#[doc(inline)]
36pub use max;
37
38#[doc(inline)]
39pub use min;
40
41pub trait Logarithm: Sized {
43 fn log2_ceil(self) -> Self;
45
46 fn log2(self) -> Self;
48
49 fn checked_log(self, base: Self) -> Option<Self>;
52
53 fn log(self, base: Self) -> Self;
55}
56
57impl Logarithm for usize {
58 #[inline(always)]
59 fn log2_ceil(self) -> usize {
60 usize_const_log2_ceil(self)
61 }
62
63 #[inline(always)]
64 fn log2(self) -> usize {
65 usize_const_log2(self)
66 }
67
68 #[inline(always)]
69 fn checked_log(self, base: usize) -> Option<Self> {
70 usize_const_checked_log(self, base)
71 }
72
73 #[inline(always)]
74 fn log(self, base: usize) -> Self {
75 match self.checked_log(base) {
76 Some(log) => log,
77 None => panic!("cannot take log base {base} of {self}"),
78 }
79 }
80}
81
82#[inline(always)]
87pub const fn usize_const_log2_ceil(n: usize) -> usize {
88 n.next_power_of_two().trailing_zeros() as usize
89}
90
91#[inline(always)]
97pub const fn usize_const_log2(n: usize) -> usize {
98 (usize::BITS - 1) as usize - n.leading_zeros() as usize
99}
100
101#[inline(always)]
106pub const fn usize_const_checked_log(mut n: usize, base: usize) -> Option<usize> {
107 if n == 0 || base <= 1 {
108 return None;
109 }
110
111 if base == 2 {
112 return Some(usize_const_log2(n));
113 }
114
115 let mut log = 0;
116 while n >= base {
117 n /= base;
118 log += 1;
119 }
120 Some(log)
121}
122
123#[cfg(all(test, not(loom)))]
124#[test]
125fn test_log2_ceil() {
126 assert_eq!(0, 0.log2_ceil());
127 assert_eq!(0, 1.log2_ceil());
128 assert_eq!(1, 2.log2_ceil());
129 assert_eq!(5, 32.log2_ceil());
130 assert_eq!(10, 1024.log2_ceil());
131}