Skip to main content

fixed_bigint/fixeduint/
prim_int_impl.rs

1use super::{
2    const_leading_zeros, const_leading_zeros_ct, const_trailing_zeros, const_trailing_zeros_ct,
3    FixedUInt, MachineWord,
4};
5use crate::const_numtraits::{ConstBitPrimInt, ConstPrimInt};
6use crate::machineword::ConstMachineWord;
7
8use crate::personality::{Nct, Personality, PersonalityTag};
9use num_traits::One;
10
11c0nst::c0nst! {
12    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize, P: Personality> c0nst ConstBitPrimInt for FixedUInt<T, N, P> {
13        fn count_ones(self) -> u32 {
14            let mut count = 0u32;
15            let mut i = 0;
16            while i < N {
17                count += self.array[i].count_ones();
18                i += 1;
19            }
20            count
21        }
22        fn count_zeros(self) -> u32 {
23            let mut count = 0u32;
24            let mut i = 0;
25            while i < N {
26                count += self.array[i].count_zeros();
27                i += 1;
28            }
29            count
30        }
31        fn leading_zeros(self) -> u32 {
32            match P::TAG {
33                PersonalityTag::Nct => const_leading_zeros(&self.array),
34                PersonalityTag::Ct => const_leading_zeros_ct(&self.array),
35            }
36        }
37        fn trailing_zeros(self) -> u32 {
38            match P::TAG {
39                PersonalityTag::Nct => const_trailing_zeros(&self.array),
40                PersonalityTag::Ct => const_trailing_zeros_ct(&self.array),
41            }
42        }
43        fn swap_bytes(self) -> Self {
44            let mut ret = <Self as crate::const_numtraits::ConstZero>::zero();
45            let mut i = 0;
46            while i < N {
47                ret.array[i] = self.array[N - 1 - i].swap_bytes();
48                i += 1;
49            }
50            ret
51        }
52        fn rotate_left(self, n: u32) -> Self {
53            let bit_size = Self::BIT_SIZE as u32;
54            if bit_size == 0 {
55                return self;
56            }
57            let shift = n % bit_size;
58            let a = core::ops::Shl::<u32>::shl(self, shift);
59            let b = core::ops::Shr::<u32>::shr(self, bit_size - shift);
60            core::ops::BitOr::bitor(a, b)
61        }
62        fn rotate_right(self, n: u32) -> Self {
63            let bit_size = Self::BIT_SIZE as u32;
64            if bit_size == 0 {
65                return self;
66            }
67            let shift = n % bit_size;
68            let a = core::ops::Shr::<u32>::shr(self, shift);
69            let b = core::ops::Shl::<u32>::shl(self, bit_size - shift);
70            core::ops::BitOr::bitor(a, b)
71        }
72        fn unsigned_shl(self, n: u32) -> Self {
73            core::ops::Shl::<u32>::shl(self, n)
74        }
75        fn unsigned_shr(self, n: u32) -> Self {
76            core::ops::Shr::<u32>::shr(self, n)
77        }
78        fn reverse_bits(self) -> Self {
79            let mut ret = <Self as crate::const_numtraits::ConstZero>::zero();
80            let mut i = 0;
81            while i < N {
82                ret.array[N - 1 - i] = self.array[i].reverse_bits();
83                i += 1;
84            }
85            ret
86        }
87        // TODO: Add big-endian support via #[cfg(target_endian = "big")]
88        fn from_be(x: Self) -> Self {
89            x.swap_bytes()
90        }
91        fn from_le(x: Self) -> Self {
92            x
93        }
94        fn to_be(self) -> Self {
95            self.swap_bytes()
96        }
97        fn to_le(self) -> Self {
98            self
99        }
100    }
101    impl<T: [c0nst] ConstMachineWord + MachineWord, const N: usize> c0nst ConstPrimInt for FixedUInt<T, N, Nct> {
102        fn pow(self, exp: u32) -> Self {
103            if exp == 0 {
104                return <Self as crate::const_numtraits::ConstOne>::one();
105            }
106            // Exponentiation by squaring: O(log exp) instead of O(exp)
107            let mut result = <Self as crate::const_numtraits::ConstOne>::one();
108            let mut base = self;
109            let mut e = exp;
110            while e > 0 {
111                if (e & 1) == 1 {
112                    result = core::ops::Mul::mul(result, base);
113                }
114                e >>= 1;
115                if e > 0 {
116                    base = core::ops::Mul::mul(base, base);
117                }
118            }
119            result
120        }
121    }
122}
123
124impl<T: MachineWord, const N: usize> num_traits::PrimInt for FixedUInt<T, N, Nct> {
125    fn count_ones(self) -> u32 {
126        self.array.iter().map(|&val| val.count_ones()).sum()
127    }
128    fn count_zeros(self) -> u32 {
129        self.array.iter().map(|&val| val.count_zeros()).sum()
130    }
131    fn leading_zeros(self) -> u32 {
132        const_leading_zeros(&self.array)
133    }
134    fn trailing_zeros(self) -> u32 {
135        const_trailing_zeros(&self.array)
136    }
137    fn rotate_left(self, bits: u32) -> Self {
138        let bit_size = Self::BIT_SIZE as u32;
139        if bit_size == 0 {
140            return self;
141        }
142        let shift = bits % bit_size;
143        let a = self << shift;
144        let b = self >> (bit_size - shift);
145        a | b
146    }
147    fn rotate_right(self, bits: u32) -> Self {
148        let bit_size = Self::BIT_SIZE as u32;
149        if bit_size == 0 {
150            return self;
151        }
152        let shift = bits % bit_size;
153        let a = self >> shift;
154        let b = self << (bit_size - shift);
155        a | b
156    }
157    fn signed_shl(self, bits: u32) -> Self {
158        <Self as num_traits::PrimInt>::unsigned_shl(self, bits)
159    }
160    fn signed_shr(self, bits: u32) -> Self {
161        <Self as num_traits::PrimInt>::unsigned_shr(self, bits)
162    }
163    fn unsigned_shl(self, bits: u32) -> Self {
164        self << bits
165    }
166    fn unsigned_shr(self, bits: u32) -> Self {
167        self >> bits
168    }
169    fn swap_bytes(self) -> Self {
170        let mut ret = Self::new();
171        for index in 0..N {
172            ret.array[index] = self.array[N - 1 - index].swap_bytes();
173        }
174
175        ret
176    }
177    // TODO: Add big-endian support via #[cfg(target_endian = "big")]
178    fn from_be(source: Self) -> Self {
179        <Self as num_traits::PrimInt>::swap_bytes(source)
180    }
181    fn from_le(source: Self) -> Self {
182        source
183    }
184    fn to_be(self) -> Self {
185        <Self as num_traits::PrimInt>::swap_bytes(self)
186    }
187    fn to_le(self) -> Self {
188        self
189    }
190    fn pow(self, exp: u32) -> Self {
191        if exp == 0 {
192            return Self::one();
193        }
194        // Exponentiation by squaring: O(log exp) instead of O(exp)
195        let mut result = Self::one();
196        let mut base = self;
197        let mut e = exp;
198        while e > 0 {
199            if (e & 1) == 1 {
200                result *= base;
201            }
202            e >>= 1;
203            if e > 0 {
204                base *= base;
205            }
206        }
207        result
208    }
209}