1
//! Utilities for working with numbers, particularly powers of two.
2

            
3
/// Returns true when the given value is a power of two.
4
///
5
/// A number is a power of two when exactly a single bit is one.
6
31
pub fn is_power_of_two<T>(value: T) -> bool
7
31
where
8
31
    T: num::PrimInt,
9
{
10
31
    !value.is_zero() && (value & (value - T::one())).is_zero()
11
31
}
12

            
13
/// Returns the smallest power of two that is larger than or equal to the given
14
/// value.
15
///
16
/// # Panics
17
///
18
/// This function will panic if the value is larger than the largest power of
19
/// two that can be represented by the type `T`.
20
///
21
/// # Examples
22
/// ```
23
/// use merc_number::round_up_to_power_of_two;
24
///
25
/// assert_eq!(round_up_to_power_of_two(3u32), 4);
26
/// assert_eq!(round_up_to_power_of_two(4u32), 4);
27
/// assert_eq!(round_up_to_power_of_two(5u32), 8);
28
/// ```
29
17
pub fn round_up_to_power_of_two<T>(value: T) -> T
30
17
where
31
17
    T: num::PrimInt,
32
{
33
17
    if value.is_zero() {
34
1
        return T::one();
35
16
    }
36

            
37
16
    if is_power_of_two(value) {
38
5
        return value;
39
11
    }
40

            
41
11
    let bits = std::mem::size_of::<T>() * 8;
42
11
    let shift = bits - value.leading_zeros() as usize;
43

            
44
    // When `shift == bits` the ceiling is `2^bits`, which is not representable
45
    // in `T`.
46
11
    assert!(
47
11
        shift < bits,
48
        "round_up_to_power_of_two: value has no representable power-of-two ceiling",
49
    );
50

            
51
10
    T::one() << shift
52
16
}
53

            
54
#[cfg(test)]
55
mod tests {
56
    use super::*;
57

            
58
    #[test]
59
1
    fn test_is_power_of_two() {
60
        // Test powers of 2
61
1
        assert!(is_power_of_two(1u32));
62
1
        assert!(is_power_of_two(2u32));
63
1
        assert!(is_power_of_two(4u32));
64
1
        assert!(is_power_of_two(8u32));
65
1
        assert!(is_power_of_two(16u32));
66

            
67
        // Test non-powers of 2
68
1
        assert!(!is_power_of_two(0u32));
69
1
        assert!(!is_power_of_two(3u32));
70
1
        assert!(!is_power_of_two(5u32));
71
1
        assert!(!is_power_of_two(6u32));
72
1
        assert!(!is_power_of_two(7u32));
73
1
    }
74

            
75
    #[test]
76
1
    fn test_round_up_to_power_of_two() {
77
        // Test exact powers of 2
78
1
        assert_eq!(round_up_to_power_of_two(1u32), 1);
79
1
        assert_eq!(round_up_to_power_of_two(2u32), 2);
80
1
        assert_eq!(round_up_to_power_of_two(4u32), 4);
81
1
        assert_eq!(round_up_to_power_of_two(8u32), 8);
82

            
83
        // Test values in between
84
1
        assert_eq!(round_up_to_power_of_two(0u32), 1);
85
1
        assert_eq!(round_up_to_power_of_two(3u32), 4);
86
1
        assert_eq!(round_up_to_power_of_two(5u32), 8);
87
1
        assert_eq!(round_up_to_power_of_two(7u32), 8);
88
1
        assert_eq!(round_up_to_power_of_two(9u32), 16);
89
1
    }
90

            
91
    #[test]
92
1
    fn test_different_types() {
93
1
        assert!(is_power_of_two(4u8));
94
1
        assert!(is_power_of_two(8u16));
95
1
        assert!(is_power_of_two(16u32));
96
1
        assert!(is_power_of_two(32u64));
97
1
        assert!(is_power_of_two(64usize));
98

            
99
1
        assert_eq!(round_up_to_power_of_two(3u8), 4);
100
1
        assert_eq!(round_up_to_power_of_two(5u16), 8);
101
1
        assert_eq!(round_up_to_power_of_two(9u32), 16);
102
1
        assert_eq!(round_up_to_power_of_two(17u64), 32);
103
1
        assert_eq!(round_up_to_power_of_two(33usize), 64);
104
1
    }
105

            
106
    #[test]
107
1
    fn test_round_up_to_largest_representable() {
108
        // The largest power of two that fits is returned unchanged.
109
1
        assert_eq!(round_up_to_power_of_two(128u8), 128);
110
        // Values just below it still round up correctly without overflowing.
111
1
        assert_eq!(round_up_to_power_of_two(65u8), 128);
112
1
    }
113

            
114
    #[test]
115
    #[should_panic(expected = "no representable power-of-two ceiling")]
116
1
    fn test_round_up_unrepresentable_panics() {
117
        // 200 rounds up to 256, which does not fit in a u8. This must panic in
118
        // every build profile, not silently return a wrong value.
119
1
        let _ = round_up_to_power_of_two(200u8);
120
1
    }
121
}
122

            
123
#[cfg(kani)]
124
mod verification {
125
    use super::is_power_of_two;
126
    use super::round_up_to_power_of_two;
127

            
128
    /// `is_power_of_two` holds exactly when a single bit is set, for every
129
    /// `u16`. Kani also checks the implementation is free of overflow.
130
    #[kani::proof]
131
    fn is_power_of_two_matches_count_ones() {
132
        let value: u16 = kani::any();
133
        assert_eq!(is_power_of_two(value), value.count_ones() == 1);
134
    }
135

            
136
    /// For every representable input, `round_up_to_power_of_two` returns the
137
    /// smallest power of two that is `>=` the input (and never overflows).
138
    #[kani::proof]
139
    fn round_up_is_smallest_power_of_two() {
140
        let value: u16 = kani::any();
141
        // Restrict to inputs whose ceiling is representable in u16.
142
        kani::assume(value <= 1u16 << 15);
143

            
144
        let result = round_up_to_power_of_two(value);
145

            
146
        assert!(is_power_of_two(result));
147
        assert!(result >= value.max(1));
148

            
149
        // Halving drops strictly below the input, so no smaller power qualifies.
150
        if result > 1 {
151
            assert!(result / 2 < value.max(1));
152
        }
153
    }
154
}