1use super::{FixedUInt, MachineWord};
18use crate::machineword::ConstMachineWord;
19use const_num_traits::{
20 Bounded, ConstOne, ConstZero, IsPowerOfTwo, NextPowerOfTwo, One, PrimBits, WrappingSub, Zero,
21};
22use const_num_traits::{Personality, PersonalityTag};
23
24c0nst::c0nst! {
25 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> IsPowerOfTwo for FixedUInt<T, N, P> {
26 fn is_power_of_two(self) -> bool {
27 match P::TAG {
28 PersonalityTag::Nct => {
29 !<Self as Zero>::is_zero(&self) && <Self as Zero>::is_zero(&(self & (self - <Self as One>::one())))
30 }
31 PersonalityTag::Ct => {
32 let a = core::hint::black_box(!<Self as Zero>::is_zero(&self));
36 let b = <Self as Zero>::is_zero(&(self & <Self as WrappingSub>::wrapping_sub(self, <Self as One>::one())));
37 a & b
38 }
39 }
40 }
41
42 }
43
44 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> NextPowerOfTwo for FixedUInt<T, N, P> {
45 type Output = Self;
46
47 fn wrapping_next_power_of_two(self) -> Self {
48 match P::TAG {
53 PersonalityTag::Nct => match self.checked_next_power_of_two() {
54 Some(v) => v,
55 None => <Self as ConstZero>::ZERO,
56 },
57 PersonalityTag::Ct => {
58 let m_one = <Self as WrappingSub>::wrapping_sub(self, Self::one());
59 let leading = PrimBits::leading_zeros(m_one);
60 let bits = Self::BIT_SIZE as u32 - leading;
61 let shifted = Self::one() << (bits as usize);
62 let is_zero = <Self as Zero>::is_zero(&self) as u8;
63 let overflow = ((bits >= Self::BIT_SIZE as u32) as u8) & (1u8 ^ is_zero);
64 let wrapped = crate::fixeduint::const_ct_select(
65 shifted,
66 <Self as ConstZero>::ZERO,
67 overflow,
68 );
69 crate::fixeduint::const_ct_select(wrapped, Self::one(), is_zero)
70 }
71 }
72 }
73
74 fn next_power_of_two(self) -> Self {
75 match P::TAG {
76 PersonalityTag::Nct => {
77 match self.checked_next_power_of_two() {
78 Some(v) => v,
79 None => panic!("FixedUInt::next_power_of_two overflow: result exceeds type capacity"),
80 }
81 }
82 PersonalityTag::Ct => {
83 let m_one = <Self as WrappingSub>::wrapping_sub(self, Self::one());
89 let leading = PrimBits::leading_zeros(m_one);
90 let bits = Self::BIT_SIZE as u32 - leading;
91 let shifted = Self::one() << (bits as usize);
92 let is_zero = <Self as Zero>::is_zero(&self) as u8;
93 let overflow = ((bits >= Self::BIT_SIZE as u32) as u8) & (1u8 ^ is_zero);
95 let saturated = crate::fixeduint::const_ct_select(
96 shifted,
97 <Self as Bounded>::max_value(),
98 overflow,
99 );
100 crate::fixeduint::const_ct_select(saturated, Self::one(), is_zero)
101 }
102 }
103 }
104
105 fn checked_next_power_of_two(self) -> Option<Self> {
112 if self.is_zero() {
113 return Some(Self::one());
114 }
115 let m_one = self - Self::one();
119 let leading = PrimBits::leading_zeros(m_one);
120 let bits = Self::BIT_SIZE as u32 - leading;
121
122 if bits >= Self::BIT_SIZE as u32 {
124 return None;
125 }
126 Some(Self::one() << (bits as usize))
127 }
128 }
129
130 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> IsPowerOfTwo for &FixedUInt<T, N, P> {
131 fn is_power_of_two(self) -> bool {
132 <FixedUInt<T, N, P> as IsPowerOfTwo>::is_power_of_two(*self)
133 }
134 }
135
136 c0nst impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> NextPowerOfTwo for &FixedUInt<T, N, P> {
137 type Output = FixedUInt<T, N, P>;
138 fn next_power_of_two(self) -> FixedUInt<T, N, P> {
139 <FixedUInt<T, N, P> as NextPowerOfTwo>::next_power_of_two(*self)
140 }
141 fn checked_next_power_of_two(self) -> Option<FixedUInt<T, N, P>> {
142 <FixedUInt<T, N, P> as NextPowerOfTwo>::checked_next_power_of_two(*self)
143 }
144 fn wrapping_next_power_of_two(self) -> FixedUInt<T, N, P> {
145 <FixedUInt<T, N, P> as NextPowerOfTwo>::wrapping_next_power_of_two(*self)
146 }
147 }
148}
149
150impl<T, const N: usize, P: Personality> const_num_traits::ops::ct::CtIsPowerOfTwo
156 for FixedUInt<T, N, P>
157where
158 T: MachineWord + subtle::ConstantTimeEq,
159{
160 fn ct_is_power_of_two(&self) -> subtle::Choice {
161 use const_num_traits::ops::ct::CtIsZero;
162 let nonzero = !self.ct_is_zero();
163 let one = <Self as ConstOne>::ONE;
164 let masked = *self & <Self as WrappingSub>::wrapping_sub(*self, one);
165 let pow2 = masked.ct_is_zero();
166 nonzero & pow2
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[test]
175 fn test_is_power_of_two() {
176 type U16 = FixedUInt<u8, 2>;
177
178 assert!(!IsPowerOfTwo::is_power_of_two(U16::from(0u8)));
179 assert!(IsPowerOfTwo::is_power_of_two(U16::from(1u8)));
180 assert!(IsPowerOfTwo::is_power_of_two(U16::from(2u8)));
181 assert!(!IsPowerOfTwo::is_power_of_two(U16::from(3u8)));
182 assert!(IsPowerOfTwo::is_power_of_two(U16::from(4u8)));
183 assert!(!IsPowerOfTwo::is_power_of_two(U16::from(5u8)));
184 assert!(IsPowerOfTwo::is_power_of_two(U16::from(8u8)));
185 assert!(IsPowerOfTwo::is_power_of_two(U16::from(16u8)));
186 assert!(IsPowerOfTwo::is_power_of_two(U16::from(128u8)));
187 assert!(IsPowerOfTwo::is_power_of_two(U16::from(256u16)));
188 assert!(!IsPowerOfTwo::is_power_of_two(U16::from(255u8)));
189 }
190
191 #[test]
192 fn test_next_power_of_two() {
193 type U16 = FixedUInt<u8, 2>;
194
195 assert_eq!(
196 NextPowerOfTwo::next_power_of_two(U16::from(0u8)),
197 U16::from(1u8)
198 );
199 assert_eq!(
200 NextPowerOfTwo::next_power_of_two(U16::from(1u8)),
201 U16::from(1u8)
202 );
203 assert_eq!(
204 NextPowerOfTwo::next_power_of_two(U16::from(2u8)),
205 U16::from(2u8)
206 );
207 assert_eq!(
208 NextPowerOfTwo::next_power_of_two(U16::from(3u8)),
209 U16::from(4u8)
210 );
211 assert_eq!(
212 NextPowerOfTwo::next_power_of_two(U16::from(4u8)),
213 U16::from(4u8)
214 );
215 assert_eq!(
216 NextPowerOfTwo::next_power_of_two(U16::from(5u8)),
217 U16::from(8u8)
218 );
219 assert_eq!(
220 NextPowerOfTwo::next_power_of_two(U16::from(7u8)),
221 U16::from(8u8)
222 );
223 assert_eq!(
224 NextPowerOfTwo::next_power_of_two(U16::from(8u8)),
225 U16::from(8u8)
226 );
227 assert_eq!(
228 NextPowerOfTwo::next_power_of_two(U16::from(9u8)),
229 U16::from(16u8)
230 );
231 assert_eq!(
232 NextPowerOfTwo::next_power_of_two(U16::from(100u8)),
233 U16::from(128u8)
234 );
235 assert_eq!(
236 NextPowerOfTwo::next_power_of_two(U16::from(128u8)),
237 U16::from(128u8)
238 );
239 assert_eq!(
240 NextPowerOfTwo::next_power_of_two(U16::from(129u8)),
241 U16::from(256u16)
242 );
243 }
244
245 #[test]
246 fn test_checked_next_power_of_two() {
247 type U16 = FixedUInt<u8, 2>;
248
249 assert_eq!(
250 NextPowerOfTwo::checked_next_power_of_two(U16::from(0u8)),
251 Some(U16::from(1u8))
252 );
253 assert_eq!(
254 NextPowerOfTwo::checked_next_power_of_two(U16::from(1u8)),
255 Some(U16::from(1u8))
256 );
257 assert_eq!(
258 NextPowerOfTwo::checked_next_power_of_two(U16::from(100u8)),
259 Some(U16::from(128u8))
260 );
261
262 let large = U16::from(32769u16);
264 assert_eq!(NextPowerOfTwo::checked_next_power_of_two(large), None);
265
266 let pow2 = U16::from(32768u16);
268 assert_eq!(NextPowerOfTwo::checked_next_power_of_two(pow2), Some(pow2));
269 }
270
271 c0nst::c0nst! {
272 pub c0nst fn const_is_power_of_two<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
273 v: &FixedUInt<T, N, P>,
274 ) -> bool {
275 IsPowerOfTwo::is_power_of_two(*v)
276 }
277
278 pub c0nst fn const_next_power_of_two<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
279 v: FixedUInt<T, N, P>,
280 ) -> FixedUInt<T, N, P> {
281 NextPowerOfTwo::next_power_of_two(v)
282 }
283 }
284
285 #[test]
286 fn test_const_power_of_two() {
287 type U16 = FixedUInt<u8, 2>;
288
289 assert!(const_is_power_of_two(&U16::from(4u8)));
290 assert!(!const_is_power_of_two(&U16::from(5u8)));
291 assert_eq!(const_next_power_of_two(U16::from(5u8)), U16::from(8u8));
292
293 #[cfg(feature = "nightly")]
294 {
295 const FOUR: U16 = FixedUInt::from_array([4, 0]);
296 const FIVE: U16 = FixedUInt::from_array([5, 0]);
297 const IS_POW2_TRUE: bool = const_is_power_of_two(&FOUR);
298 const IS_POW2_FALSE: bool = const_is_power_of_two(&FIVE);
299 const NEXT_POW2: U16 = const_next_power_of_two(FIVE);
300
301 assert!(IS_POW2_TRUE);
302 assert!(!IS_POW2_FALSE);
303 assert_eq!(NEXT_POW2, FixedUInt::from_array([8, 0]));
304 }
305 }
306
307 #[test]
308 fn wrapping_next_power_of_two_wraps_to_zero_under_both_personalities() {
309 use const_num_traits::{Ct, Nct};
310 type U16Nct = FixedUInt<u8, 2, Nct>;
311 type U16Ct = FixedUInt<u8, 2, Ct>;
312 assert_eq!(
315 U16Nct::from(32769u16).wrapping_next_power_of_two(),
316 U16Nct::from_array([0, 0])
317 );
318 assert_eq!(
319 U16Ct::from(32769u16).wrapping_next_power_of_two(),
320 U16Ct::from_array([0, 0])
321 );
322 assert_eq!(
324 U16Nct::from(0xFFFFu16).wrapping_next_power_of_two(),
325 U16Nct::from_array([0, 0])
326 );
327 assert_eq!(
328 U16Ct::from(0xFFFFu16).wrapping_next_power_of_two(),
329 U16Ct::from_array([0, 0])
330 );
331 assert_eq!(
333 U16Nct::from(100u8).wrapping_next_power_of_two(),
334 U16Nct::from(128u8)
335 );
336 assert_eq!(
337 U16Ct::from(100u8).wrapping_next_power_of_two(),
338 U16Ct::from(128u8)
339 );
340 }
341
342 #[test]
343 fn ct_is_power_of_two_matches_is_power_of_two() {
344 use const_num_traits::ops::ct::CtIsPowerOfTwo;
345 type U16 = FixedUInt<u8, 2>;
346 assert!(!bool::from(CtIsPowerOfTwo::ct_is_power_of_two(&U16::from(
348 0u8
349 ))));
350 for v in [1u16, 2, 4, 8, 16, 128, 256, 32768] {
352 assert!(
353 bool::from(CtIsPowerOfTwo::ct_is_power_of_two(&U16::from(v))),
354 "ct_is_power_of_two({v}) should mask Some"
355 );
356 }
357 for v in [3u16, 5, 6, 7, 9, 100, 255] {
359 assert!(
360 !bool::from(CtIsPowerOfTwo::ct_is_power_of_two(&U16::from(v))),
361 "ct_is_power_of_two({v}) should mask None"
362 );
363 }
364 }
365}