ospf_rust_math/algebra/operator/algorithmic/
trailing_zeros.rs

1use std::borrow::Borrow;
2use std::ops::{BitOr, ShrAssign};
3
4use crate::algebra::concept::{Arithmetic, SemiArithmetic};
5
6pub trait TrailingZeros {
7    fn trailing_zeros(self) -> usize;
8}
9
10default impl<T: Arithmetic + ShrAssign<usize>> TrailingZeros for T
11where
12    for<'a> &'a T: BitOr<&'a T, Output = T>,
13{
14    fn trailing_zeros(mut self) -> usize {
15        if &self == T::ZERO {
16            return size_of::<T>();
17        }
18
19        let mut counter = 0;
20        while &(&self | T::ONE) == T::ZERO {
21            counter += 1;
22            self >>= 1;
23        }
24        counter
25    }
26}
27
28macro_rules! int_trailing_zeros_impl {
29    ($($type:ident)*) => ($(
30        impl TrailingZeros for $type {
31            fn trailing_zeros(self) -> usize {
32                <$type>::trailing_zeros(self) as usize
33            }
34        }
35
36        impl TrailingZeros for &$type {
37            fn trailing_zeros(self) -> usize {
38                <$type>::trailing_zeros(*self) as usize
39            }
40        }
41    )*);
42}
43int_trailing_zeros_impl! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
44
45#[cfg(test)]
46mod tests {
47    use std::fmt::Debug;
48    use std::ops::Mul;
49
50    use crate::algebra::concept::Integer;
51
52    use super::*;
53
54    fn test_int<T: Integer + TrailingZeros + Debug>()
55    where
56        for<'a> &'a T: Mul<Output = T>,
57    {
58        assert_eq!(
59            T::ZERO.clone().trailing_zeros(),
60            size_of::<T>() * 8
61        );
62        assert_eq!(T::ONE.clone().trailing_zeros(), 0);
63        assert_eq!(T::TWO.clone().trailing_zeros(), 1);
64        assert_eq!(T::THREE.clone().trailing_zeros(), 0);
65        assert_eq!(T::FIVE.clone().trailing_zeros(), 0);
66        assert_eq!(T::TEN.clone().trailing_zeros(), 1);
67        assert_eq!((T::TWO * T::TEN).trailing_zeros(), 2);
68    }
69
70    #[test]
71    fn test() {
72        test_int::<i8>();
73        test_int::<i16>();
74        test_int::<i32>();
75        test_int::<i64>();
76        test_int::<i128>();
77        test_int::<u8>();
78        test_int::<u16>();
79        test_int::<u32>();
80        test_int::<u64>();
81        test_int::<u128>();
82    }
83}