Skip to main content

const_num_traits/ops/
pow2.rs

1//! Power-of-two operations on unsigned integers, mirroring
2//! `is_power_of_two` / `next_power_of_two` / `checked_next_power_of_two`
3//! (stable since Rust 1.0) and the still-unstable
4//! `wrapping_next_power_of_two`.
5//!
6//! Split: the predicate (`is_power_of_two`, a branchless
7//! `count_ones == 1` check) is separate from the constructors (the three
8//! `next_power_of_two` flavors, which share the `one_less` shift trick).
9//!
10//! **CT tiers**: [`IsPowerOfTwo`] is Tier B (popcount plus a boolean);
11//! [`NextPowerOfTwo`] is Tier C (data-dependent early-out and overflow
12//! panic).
13
14c0nst::c0nst! {
15/// Power-of-two predicate, for unsigned integers.
16pub c0nst trait IsPowerOfTwo: Sized {
17    /// Returns `true` if and only if `self == 2^k` for some integer `k`.
18    /// Zero is not a power of two.
19    ///
20    /// ```
21    /// use const_num_traits::IsPowerOfTwo;
22    ///
23    /// assert!(IsPowerOfTwo::is_power_of_two(16u8));
24    /// assert!(!IsPowerOfTwo::is_power_of_two(10u8));
25    /// assert!(!IsPowerOfTwo::is_power_of_two(0u8));
26    /// ```
27    fn is_power_of_two(self) -> bool;
28}
29}
30
31c0nst::c0nst! {
32/// Rounding up to a power of two, for unsigned integers.
33pub c0nst trait NextPowerOfTwo: Sized {
34    /// Returns the smallest power of two greater than or equal to `self`.
35    ///
36    /// # Panics
37    ///
38    /// With overflow checks enabled, panics if the next power of two doesn't
39    /// fit in the type; without them, the result is wrapped (and wrong),
40    /// matching the inherent method.
41    type Output;
42    fn next_power_of_two(self) -> Self::Output;
43
44    /// Returns the smallest power of two greater than or equal to `self`,
45    /// or `None` if it doesn't fit in the type.
46    ///
47    /// ```
48    /// use const_num_traits::NextPowerOfTwo;
49    ///
50    /// assert_eq!(NextPowerOfTwo::checked_next_power_of_two(200u8), None);
51    /// assert_eq!(NextPowerOfTwo::checked_next_power_of_two(3u8), Some(4));
52    /// ```
53    fn checked_next_power_of_two(self) -> Option<Self::Output>;
54
55    /// Returns the smallest power of two greater than or equal to `self`,
56    /// or 0 if it doesn't fit in the type (i.e. the result wraps to zero).
57    ///
58    /// This mirrors the still-unstable `wrapping_next_power_of_two` inherent
59    /// method.
60    fn wrapping_next_power_of_two(self) -> Self::Output;
61}
62}
63
64macro_rules! power_of_two_impl {
65    ($($t:ty)*) => {$(
66        c0nst::c0nst! {
67        c0nst impl IsPowerOfTwo for $t {
68            #[inline]
69            fn is_power_of_two(self) -> bool {
70                <$t>::is_power_of_two(self)
71            }
72        }
73        }
74
75        c0nst::c0nst! {
76        c0nst impl NextPowerOfTwo for $t {
77            type Output = $t;
78            #[inline]
79            fn next_power_of_two(self) -> Self {
80                <$t>::next_power_of_two(self)
81            }
82
83            #[inline]
84            fn checked_next_power_of_two(self) -> Option<Self> {
85                <$t>::checked_next_power_of_two(self)
86            }
87
88            // unstable in std; same one-less-than trick as core
89            #[inline]
90            fn wrapping_next_power_of_two(self) -> Self {
91                if self <= 1 {
92                    return 1;
93                }
94                let one_less = <$t>::MAX >> <$t>::leading_zeros(self - 1);
95                one_less.wrapping_add(1)
96            }
97        }
98        }
99    )*};
100}
101
102power_of_two_impl!(usize u8 u16 u32 u64 u128);
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107
108    #[test]
109    fn power_of_two() {
110        assert!(IsPowerOfTwo::is_power_of_two(1u8));
111        assert!(IsPowerOfTwo::is_power_of_two(128u8));
112        assert!(!IsPowerOfTwo::is_power_of_two(0u8));
113        assert_eq!(NextPowerOfTwo::next_power_of_two(0u8), 1);
114        assert_eq!(NextPowerOfTwo::next_power_of_two(100u8), 128);
115        assert_eq!(NextPowerOfTwo::checked_next_power_of_two(128u8), Some(128));
116        assert_eq!(NextPowerOfTwo::checked_next_power_of_two(129u8), None);
117        assert_eq!(NextPowerOfTwo::wrapping_next_power_of_two(129u8), 0);
118        assert_eq!(NextPowerOfTwo::wrapping_next_power_of_two(0u8), 1);
119        assert_eq!(NextPowerOfTwo::wrapping_next_power_of_two(65u8), 128);
120    }
121}