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(FixedUInt::from_array(self.array))
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(FixedUInt::from_array(self.array))
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(FixedUInt::from_array(self.array))
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(FixedUInt::from_array(self.array))
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);
168 let pow2 = masked.ct_is_zero();
169 nonzero & pow2
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176
177 #[test]
178 fn test_is_power_of_two() {
179 type U16 = FixedUInt<u8, 2>;
180
181 assert!(!IsPowerOfTwo::is_power_of_two(U16::from(0u8)));
182 assert!(IsPowerOfTwo::is_power_of_two(U16::from(1u8)));
183 assert!(IsPowerOfTwo::is_power_of_two(U16::from(2u8)));
184 assert!(!IsPowerOfTwo::is_power_of_two(U16::from(3u8)));
185 assert!(IsPowerOfTwo::is_power_of_two(U16::from(4u8)));
186 assert!(!IsPowerOfTwo::is_power_of_two(U16::from(5u8)));
187 assert!(IsPowerOfTwo::is_power_of_two(U16::from(8u8)));
188 assert!(IsPowerOfTwo::is_power_of_two(U16::from(16u8)));
189 assert!(IsPowerOfTwo::is_power_of_two(U16::from(128u8)));
190 assert!(IsPowerOfTwo::is_power_of_two(U16::from(256u16)));
191 assert!(!IsPowerOfTwo::is_power_of_two(U16::from(255u8)));
192 }
193
194 #[test]
195 fn test_next_power_of_two() {
196 type U16 = FixedUInt<u8, 2>;
197
198 assert_eq!(
199 NextPowerOfTwo::next_power_of_two(U16::from(0u8)),
200 U16::from(1u8)
201 );
202 assert_eq!(
203 NextPowerOfTwo::next_power_of_two(U16::from(1u8)),
204 U16::from(1u8)
205 );
206 assert_eq!(
207 NextPowerOfTwo::next_power_of_two(U16::from(2u8)),
208 U16::from(2u8)
209 );
210 assert_eq!(
211 NextPowerOfTwo::next_power_of_two(U16::from(3u8)),
212 U16::from(4u8)
213 );
214 assert_eq!(
215 NextPowerOfTwo::next_power_of_two(U16::from(4u8)),
216 U16::from(4u8)
217 );
218 assert_eq!(
219 NextPowerOfTwo::next_power_of_two(U16::from(5u8)),
220 U16::from(8u8)
221 );
222 assert_eq!(
223 NextPowerOfTwo::next_power_of_two(U16::from(7u8)),
224 U16::from(8u8)
225 );
226 assert_eq!(
227 NextPowerOfTwo::next_power_of_two(U16::from(8u8)),
228 U16::from(8u8)
229 );
230 assert_eq!(
231 NextPowerOfTwo::next_power_of_two(U16::from(9u8)),
232 U16::from(16u8)
233 );
234 assert_eq!(
235 NextPowerOfTwo::next_power_of_two(U16::from(100u8)),
236 U16::from(128u8)
237 );
238 assert_eq!(
239 NextPowerOfTwo::next_power_of_two(U16::from(128u8)),
240 U16::from(128u8)
241 );
242 assert_eq!(
243 NextPowerOfTwo::next_power_of_two(U16::from(129u8)),
244 U16::from(256u16)
245 );
246 }
247
248 #[test]
249 fn test_checked_next_power_of_two() {
250 type U16 = FixedUInt<u8, 2>;
251
252 assert_eq!(
253 NextPowerOfTwo::checked_next_power_of_two(U16::from(0u8)),
254 Some(U16::from(1u8))
255 );
256 assert_eq!(
257 NextPowerOfTwo::checked_next_power_of_two(U16::from(1u8)),
258 Some(U16::from(1u8))
259 );
260 assert_eq!(
261 NextPowerOfTwo::checked_next_power_of_two(U16::from(100u8)),
262 Some(U16::from(128u8))
263 );
264
265 let large = U16::from(32769u16);
267 assert_eq!(NextPowerOfTwo::checked_next_power_of_two(large), None);
268
269 let pow2 = U16::from(32768u16);
271 assert_eq!(NextPowerOfTwo::checked_next_power_of_two(pow2), Some(pow2));
272 }
273
274 c0nst::c0nst! {
275 pub c0nst fn const_is_power_of_two<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
276 v: &FixedUInt<T, N, P>,
277 ) -> bool {
278 IsPowerOfTwo::is_power_of_two(FixedUInt::<T, N, P>::from_array(v.array))
279 }
280
281 pub c0nst fn const_next_power_of_two<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality>(
282 v: FixedUInt<T, N, P>,
283 ) -> FixedUInt<T, N, P> {
284 NextPowerOfTwo::next_power_of_two(v)
285 }
286 }
287
288 #[test]
289 fn test_const_power_of_two() {
290 type U16 = FixedUInt<u8, 2>;
291
292 assert!(const_is_power_of_two(&U16::from(4u8)));
293 assert!(!const_is_power_of_two(&U16::from(5u8)));
294 assert_eq!(const_next_power_of_two(U16::from(5u8)), U16::from(8u8));
295
296 #[cfg(feature = "nightly")]
297 {
298 const FOUR: U16 = FixedUInt::from_array([4, 0]);
299 const FIVE: U16 = FixedUInt::from_array([5, 0]);
300 const IS_POW2_TRUE: bool = const_is_power_of_two(&FOUR);
301 const IS_POW2_FALSE: bool = const_is_power_of_two(&FIVE);
302 const NEXT_POW2: U16 = const_next_power_of_two(FIVE);
303
304 assert!(IS_POW2_TRUE);
305 assert!(!IS_POW2_FALSE);
306 assert_eq!(NEXT_POW2, FixedUInt::from_array([8, 0]));
307 }
308 }
309
310 #[test]
311 fn wrapping_next_power_of_two_wraps_to_zero_under_both_personalities() {
312 use const_num_traits::{Ct, Nct};
313 type U16Nct = FixedUInt<u8, 2, Nct>;
314 type U16Ct = FixedUInt<u8, 2, Ct>;
315 assert_eq!(
318 U16Nct::from(32769u16).wrapping_next_power_of_two(),
319 U16Nct::from_array([0, 0])
320 );
321 assert_eq!(
322 U16Ct::from(32769u16).wrapping_next_power_of_two(),
323 U16Ct::from_array([0, 0])
324 );
325 assert_eq!(
327 U16Nct::from(0xFFFFu16).wrapping_next_power_of_two(),
328 U16Nct::from_array([0, 0])
329 );
330 assert_eq!(
331 U16Ct::from(0xFFFFu16).wrapping_next_power_of_two(),
332 U16Ct::from_array([0, 0])
333 );
334 assert_eq!(
336 U16Nct::from(100u8).wrapping_next_power_of_two(),
337 U16Nct::from(128u8)
338 );
339 assert_eq!(
340 U16Ct::from(100u8).wrapping_next_power_of_two(),
341 U16Ct::from(128u8)
342 );
343 }
344
345 #[test]
346 fn ct_is_power_of_two_matches_is_power_of_two() {
347 use const_num_traits::ops::ct::CtIsPowerOfTwo;
348 type U16 = FixedUInt<u8, 2>;
349 assert!(!bool::from(CtIsPowerOfTwo::ct_is_power_of_two(&U16::from(
351 0u8
352 ))));
353 for v in [1u16, 2, 4, 8, 16, 128, 256, 32768] {
355 assert!(
356 bool::from(CtIsPowerOfTwo::ct_is_power_of_two(&U16::from(v))),
357 "ct_is_power_of_two({v}) should mask Some"
358 );
359 }
360 for v in [3u16, 5, 6, 7, 9, 100, 255] {
362 assert!(
363 !bool::from(CtIsPowerOfTwo::ct_is_power_of_two(&U16::from(v))),
364 "ct_is_power_of_two({v}) should mask None"
365 );
366 }
367 }
368}