reweb3_num/buint/
mod.rs

1use crate::errors::{self, option_expect};
2
3use crate::digit;
4use crate::doc;
5use crate::ExpType;
6// use core::mem::MaybeUninit;
7
8use core::default::Default;
9
10use core::iter::{Iterator, Product, Sum};
11
12macro_rules! mod_impl {
13    ($BUint: ident, $BInt: ident, $Digit: ident) => {
14        /// Unsigned integer type composed of
15        #[doc = concat!("`", stringify!($Digit), "`")]
16        /// digits, of arbitrary fixed size which must be known at compile time.
17        ///
18        /// Digits are stored in little endian (least significant digit first). This integer type aims to exactly replicate the behaviours of Rust's built-in unsigned integer types: `u8`, `u16`, `u32`, `u64`, `u128` and `usize`. The const generic parameter `N` is the number of
19        #[doc = concat!("`", stringify!($Digit), "`")]
20        /// digits that are stored.
21        ///
22        #[doc = doc::arithmetic_doc!($BUint)]
23        #[derive(Clone, Copy, Hash, PartialEq, Eq)]
24        #[repr(transparent)]
25        pub struct $BUint<const N: usize> {
26            pub(crate) digits: [$Digit; N],
27        }
28
29        impl<const N: usize> $BUint<N> {
30            #[doc = doc::count_ones!(U 1024)]
31            #[must_use = doc::must_use_op!()]
32            #[inline]
33            pub const fn count_ones(self) -> ExpType {
34                let mut ones = 0;
35                let mut i = 0;
36                while i < N {
37                    ones += self.digits[i].count_ones() as ExpType;
38                    i += 1;
39                }
40                ones
41            }
42
43            #[doc = doc::count_zeros!(U 1024)]
44            #[must_use = doc::must_use_op!()]
45            #[inline]
46            pub const fn count_zeros(self) -> ExpType {
47                let mut zeros = 0;
48                let mut i = 0;
49                while i < N {
50                    zeros += self.digits[i].count_zeros() as ExpType;
51                    i += 1;
52                }
53                zeros
54            }
55
56            #[doc = doc::leading_zeros!(U 1024)]
57            #[must_use = doc::must_use_op!()]
58            #[inline]
59            pub const fn leading_zeros(self) -> ExpType {
60                let mut zeros = 0;
61                let mut i = N;
62                while i > 0 {
63                    i -= 1;
64                    let digit = self.digits[i];
65                    zeros += digit.leading_zeros() as ExpType;
66                    if digit != $Digit::MIN {
67                        break;
68                    }
69                }
70                zeros
71            }
72
73            #[doc = doc::trailing_zeros!(U 1024)]
74            #[must_use = doc::must_use_op!()]
75            #[inline]
76            pub const fn trailing_zeros(self) -> ExpType {
77                let mut zeros = 0;
78                let mut i = 0;
79                while i < N {
80                    let digit = self.digits[i];
81                    zeros += digit.trailing_zeros() as ExpType;
82                    if digit != $Digit::MIN {
83                        break;
84                    }
85                    i += 1;
86                }
87                zeros
88            }
89
90            #[doc = doc::leading_ones!(U 1024, MAX)]
91            #[must_use = doc::must_use_op!()]
92            #[inline]
93            pub const fn leading_ones(self) -> ExpType {
94                let mut ones = 0;
95                let mut i = N;
96                while i > 0 {
97                    i -= 1;
98                    let digit = self.digits[i];
99                    ones += digit.leading_ones() as ExpType;
100                    if digit != $Digit::MAX {
101                        break;
102                    }
103                }
104                ones
105            }
106
107            #[doc = doc::trailing_ones!(U 1024)]
108            #[must_use = doc::must_use_op!()]
109            #[inline]
110            pub const fn trailing_ones(self) -> ExpType {
111                let mut ones = 0;
112                let mut i = 0;
113                while i < N {
114                    let digit = self.digits[i];
115                    ones += digit.trailing_ones() as ExpType;
116                    if digit != $Digit::MAX {
117                        break;
118                    }
119                    i += 1;
120                }
121                ones
122            }
123
124            #[inline]
125            const unsafe fn rotate_digits_left(self, n: usize) -> Self {
126                let mut out = Self::ZERO;
127                let mut i = n;
128                while i < N {
129                    out.digits[i] = self.digits[i - n];
130                    i += 1;
131                }
132                let init_index = N - n;
133                let mut i = init_index;
134                while i < N {
135                    out.digits[i - init_index] = self.digits[i];
136                    i += 1;
137                }
138
139                out
140            }
141
142            #[inline]
143            const unsafe fn unchecked_rotate_left(self, rhs: ExpType) -> Self {
144                let digit_shift = (rhs >> digit::$Digit::BIT_SHIFT) as usize;
145                let bit_shift = rhs & digit::$Digit::BITS_MINUS_1;
146
147                let mut out = self.rotate_digits_left(digit_shift);
148
149                if bit_shift != 0 {
150                    let carry_shift = digit::$Digit::BITS - bit_shift;
151                    let mut carry = 0;
152
153                    let mut i = 0;
154                    while i < N {
155                        let current_digit = out.digits[i];
156                        out.digits[i] = (current_digit << bit_shift) | carry;
157                        carry = current_digit >> carry_shift;
158                        i += 1;
159                    }
160                    out.digits[0] |= carry;
161                }
162
163                out
164            }
165
166            const BITS_MINUS_1: ExpType = (Self::BITS - 1) as ExpType;
167
168            #[doc = doc::rotate_left!(U 256, "u")]
169            #[must_use = doc::must_use_op!()]
170            #[inline]
171            pub const fn rotate_left(self, n: ExpType) -> Self {
172                unsafe { self.unchecked_rotate_left(n & Self::BITS_MINUS_1) }
173            }
174
175            #[doc = doc::rotate_right!(U 256, "u")]
176            #[must_use = doc::must_use_op!()]
177            #[inline]
178            pub const fn rotate_right(self, n: ExpType) -> Self {
179                let n = n & Self::BITS_MINUS_1;
180                unsafe { self.unchecked_rotate_left(Self::BITS as ExpType - n) }
181            }
182
183            const N_MINUS_1: usize = N - 1;
184
185            #[doc = doc::swap_bytes!(U 256, "u")]
186            #[must_use = doc::must_use_op!()]
187            #[inline]
188            pub const fn swap_bytes(self) -> Self {
189                let mut uint = Self::ZERO;
190                let mut i = 0;
191                while i < N {
192                    uint.digits[i] = self.digits[Self::N_MINUS_1 - i].swap_bytes();
193                    i += 1;
194                }
195                uint
196            }
197
198            #[doc = doc::reverse_bits!(U 256, "u")]
199            #[must_use = doc::must_use_op!()]
200            #[inline]
201            pub const fn reverse_bits(self) -> Self {
202                let mut uint = Self::ZERO;
203                let mut i = 0;
204                while i < N {
205                    uint.digits[i] = self.digits[Self::N_MINUS_1 - i].reverse_bits();
206                    i += 1;
207                }
208                uint
209            }
210
211            #[doc = doc::pow!(U 256)]
212            #[must_use = doc::must_use_op!()]
213            #[inline]
214            pub const fn pow(self, exp: ExpType) -> Self {
215                #[cfg(debug_assertions)]
216                return option_expect!(
217                    self.checked_pow(exp),
218                    errors::err_msg!("attempt to calculate power with overflow")
219                );
220                #[cfg(not(debug_assertions))]
221                self.wrapping_pow(exp)
222            }
223
224            #[doc = doc::div_euclid!(U)]
225            #[must_use = doc::must_use_op!()]
226            #[inline]
227            pub const fn div_euclid(self, rhs: Self) -> Self {
228                self.wrapping_div_euclid(rhs)
229            }
230
231            #[doc = doc::rem_euclid!(U)]
232            #[must_use = doc::must_use_op!()]
233            #[inline]
234            pub const fn rem_euclid(self, rhs: Self) -> Self {
235                self.wrapping_rem_euclid(rhs)
236            }
237
238            #[doc = doc::doc_comment! {
239                        U 256,
240                        "Returns `true` if and only if `self == 2^k` for some integer `k`.",
241
242                        "let n = " stringify!(U256) "::from(1u16 << 14);\n"
243                        "assert!(n.is_power_of_two());\n"
244                        "let m = " stringify!(U256) "::from(100u8);\n"
245                        "assert!(!m.is_power_of_two());"
246                    }]
247            #[must_use]
248            #[inline]
249            pub const fn is_power_of_two(self) -> bool {
250                let mut i = 0;
251                let mut ones = 0;
252                while i < N {
253                    ones += (&self.digits)[i].count_ones();
254                    if ones > 1 {
255                        return false;
256                    }
257                    i += 1;
258                }
259                ones == 1
260            }
261
262            #[doc = doc::next_power_of_two!(U 256, "0", "ZERO")]
263            #[must_use = doc::must_use_op!()]
264            #[inline]
265            pub const fn next_power_of_two(self) -> Self {
266                #[cfg(debug_assertions)]
267                return option_expect!(
268                    self.checked_next_power_of_two(),
269                    errors::err_msg!("attempt to calculate next power of two with overflow")
270                );
271                #[cfg(not(debug_assertions))]
272                self.wrapping_next_power_of_two()
273            }
274
275            #[doc = doc::ilog2!(U)]
276            #[must_use = doc::must_use_op!()]
277            #[inline]
278            pub const fn ilog2(self) -> ExpType {
279                option_expect!(
280                    self.checked_ilog2(),
281                    errors::err_msg!(errors::non_positive_log_message!())
282                )
283            }
284
285            #[doc = doc::ilog10!(U)]
286            #[must_use = doc::must_use_op!()]
287            #[inline]
288            pub const fn ilog10(self) -> ExpType {
289                option_expect!(
290                    self.checked_ilog10(),
291                    errors::err_msg!(errors::non_positive_log_message!())
292                )
293            }
294
295            #[doc = doc::ilog!(U)]
296            #[must_use = doc::must_use_op!()]
297            #[inline]
298            pub const fn ilog(self, base: Self) -> ExpType {
299                if base.le(&Self::ONE) {
300                    panic!("{}", errors::err_msg!(errors::invalid_log_base!()));
301                }
302                option_expect!(
303                    self.checked_ilog(base),
304                    errors::err_msg!(errors::non_positive_log_message!())
305                )
306            }
307
308            #[doc = doc::abs_diff!(U)]
309            #[must_use = doc::must_use_op!()]
310            #[inline]
311            pub const fn abs_diff(self, other: Self) -> Self {
312                if self.lt(&other) {
313                    other.wrapping_sub(self)
314                } else {
315                    self.wrapping_sub(other)
316                }
317            }
318
319            #[doc = doc::next_multiple_of!(U)]
320            #[must_use = doc::must_use_op!()]
321            #[inline]
322            pub const fn next_multiple_of(self, rhs: Self) -> Self {
323                let rem = self.wrapping_rem(rhs);
324                if rem.is_zero() {
325                    self
326                } else {
327                    self.add(rhs.sub(rem))
328                }
329            }
330
331            #[doc = doc::div_floor!(U)]
332            #[must_use = doc::must_use_op!()]
333            #[inline]
334            pub const fn div_floor(self, rhs: Self) -> Self {
335                self.wrapping_div(rhs)
336            }
337
338            #[doc = doc::div_ceil!(U)]
339            #[must_use = doc::must_use_op!()]
340            #[inline]
341            pub const fn div_ceil(self, rhs: Self) -> Self {
342                let (div, rem) = self.div_rem(rhs);
343                if rem.is_zero() {
344                    div
345                } else {
346                    div.add(Self::ONE)
347                }
348            }
349        }
350
351        impl<const N: usize> $BUint<N> {
352            #[inline]
353            pub(crate) const unsafe fn unchecked_shl_internal(self, rhs: ExpType) -> Self {
354                let mut out = $BUint::ZERO;
355                let digit_shift = (rhs >> digit::$Digit::BIT_SHIFT) as usize;
356                let bit_shift = rhs & digit::$Digit::BITS_MINUS_1;
357
358                // let num_copies = N.saturating_sub(digit_shift); // TODO: use unchecked_ methods from primitives when these are stablised and constified
359
360                if bit_shift != 0 {
361                    let carry_shift = digit::$Digit::BITS - bit_shift;
362                    let mut carry = 0;
363
364                    let mut i = digit_shift;
365                    while i < N {
366                        let current_digit = self.digits[i - digit_shift];
367                        out.digits[i] = (current_digit << bit_shift) | carry;
368                        carry = current_digit >> carry_shift;
369                        i += 1;
370                    }
371                } else {
372                    let mut i = digit_shift;
373                    while i < N {
374                        // we start i at digit_shift, not 0, since the compiler can elide bounds checks when i < N
375                        out.digits[i] = self.digits[i - digit_shift];
376                        i += 1;
377                    }
378                }
379
380                out
381            }
382
383            #[inline]
384            pub(crate) const unsafe fn unchecked_shr_pad_internal<const NEG: bool>(
385                self,
386                rhs: ExpType,
387            ) -> Self {
388                let mut out = if NEG { $BUint::MAX } else { $BUint::ZERO };
389                let digit_shift = (rhs >> digit::$Digit::BIT_SHIFT) as usize;
390                let bit_shift = rhs & digit::$Digit::BITS_MINUS_1;
391
392                let num_copies = N.saturating_sub(digit_shift); // TODO: use unchecked_ methods from primitives when these are stablised and constified
393
394                if bit_shift != 0 {
395                    let carry_shift = digit::$Digit::BITS - bit_shift;
396                    let mut carry = 0;
397
398                    let mut i = digit_shift;
399                    while i < N {
400                        // we use an increment while loop because the compiler can elide the array bounds check, which results in big performance gains
401                        let index = N - 1 - i;
402                        let current_digit = self.digits[index + digit_shift];
403                        out.digits[index] = (current_digit >> bit_shift) | carry;
404                        carry = current_digit << carry_shift;
405                        i += 1;
406                    }
407
408                    if NEG {
409                        out.digits[num_copies - 1] |= $Digit::MAX << carry_shift;
410                    }
411                } else {
412                    let mut i = digit_shift;
413                    while i < N {
414                        // we start i at digit_shift, not 0, since the compiler can elide bounds checks when i < N
415                        out.digits[i - digit_shift] = self.digits[i];
416                        i += 1;
417                    }
418                }
419
420                out
421            }
422
423            pub(crate) const unsafe fn unchecked_shr_internal(
424                u: $BUint<N>,
425                rhs: ExpType,
426            ) -> $BUint<N> {
427                Self::unchecked_shr_pad_internal::<false>(u, rhs)
428            }
429
430            #[doc = doc::bits!(U 256)]
431            #[must_use]
432            #[inline]
433            pub const fn bits(&self) -> ExpType {
434                Self::BITS as ExpType - self.leading_zeros()
435            }
436
437            #[doc = doc::bit!(U 256)]
438            #[must_use]
439            #[inline]
440            pub const fn bit(&self, index: ExpType) -> bool {
441                let digit = self.digits[index as usize >> digit::$Digit::BIT_SHIFT];
442                digit & (1 << (index & digit::$Digit::BITS_MINUS_1)) != 0
443            }
444
445            /// Returns an integer whose value is `2^power`. This is faster than using a shift left on `Self::ONE`.
446            ///
447            /// # Panics
448            ///
449            /// This function will panic if `power` is greater than or equal to `Self::BITS`.
450            ///
451            /// # Examples
452            ///
453            /// ```
454            /// use reweb3_num::types::U256;
455            ///
456            /// let power = 11;
457            /// assert_eq!(U256::power_of_two(11), (1u128 << 11).into());
458            /// ```
459            #[must_use]
460            #[inline]
461            pub const fn power_of_two(power: ExpType) -> Self {
462                let mut out = Self::ZERO;
463                out.digits[power as usize >> digit::$Digit::BIT_SHIFT] =
464                    1 << (power & (digit::$Digit::BITS - 1));
465                out
466            }
467
468            /// Returns the digits stored in `self` as an array. Digits are little endian (least significant digit first).
469            #[must_use]
470            #[inline(always)]
471            pub const fn digits(&self) -> &[$Digit; N] {
472                &self.digits
473            }
474
475            /// Creates a new unsigned integer from the given array of digits. Digits are stored as little endian (least significant digit first).
476            #[must_use]
477            #[inline(always)]
478            pub const fn from_digits(digits: [$Digit; N]) -> Self {
479                Self { digits }
480            }
481
482            /// Creates a new unsigned integer from the given digit. The given digit is stored as the least significant digit.
483            #[must_use]
484            #[inline(always)]
485            pub const fn from_digit(digit: $Digit) -> Self {
486                let mut out = Self::ZERO;
487                out.digits[0] = digit;
488                out
489            }
490
491            #[doc = doc::is_zero!(U 256)]
492            #[must_use]
493            #[inline]
494            pub const fn is_zero(&self) -> bool {
495                let mut i = 0;
496                while i < N {
497                    if (&self.digits)[i] != 0 {
498                        return false;
499                    }
500                    i += 1;
501                }
502                true
503            }
504
505            #[doc = doc::is_one!(U 256)]
506            #[must_use]
507            #[inline]
508            pub const fn is_one(&self) -> bool {
509                if N == 0 || self.digits[0] != 1 {
510                    return false;
511                }
512                let mut i = 1;
513                while i < N {
514                    if (&self.digits)[i] != 0 {
515                        return false;
516                    }
517                    i += 1;
518                }
519                true
520            }
521
522            #[inline]
523            pub(crate) const fn last_digit_index(&self) -> usize {
524                let mut index = 0;
525                let mut i = 1;
526                while i < N {
527                    if (&self.digits)[i] != 0 {
528                        index = i;
529                    }
530                    i += 1;
531                }
532                index
533            }
534
535            #[allow(unused)]
536            #[inline]
537            fn square(self) -> Self {
538                // TODO: optimise this method, this will make exponentiation by squaring faster
539                self * self
540            }
541        }
542
543        impl<const N: usize> Default for $BUint<N> {
544            #[doc = doc::default!()]
545            #[inline]
546            fn default() -> Self {
547                Self::ZERO
548            }
549        }
550
551        impl<const N: usize> Product<Self> for $BUint<N> {
552            #[inline]
553            fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
554                iter.fold(Self::ONE, |a, b| a * b)
555            }
556        }
557
558        impl<'a, const N: usize> Product<&'a Self> for $BUint<N> {
559            #[inline]
560            fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
561                iter.fold(Self::ONE, |a, b| a * b)
562            }
563        }
564
565        impl<const N: usize> Sum<Self> for $BUint<N> {
566            #[inline]
567            fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
568                iter.fold(Self::ZERO, |a, b| a + b)
569            }
570        }
571
572        impl<'a, const N: usize> Sum<&'a Self> for $BUint<N> {
573            #[inline]
574            fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
575                iter.fold(Self::ZERO, |a, b| a + b)
576            }
577        }
578
579        #[cfg(any(test))]
580        impl<const N: usize> quickcheck::Arbitrary for $BUint<N> {
581            fn arbitrary(g: &mut quickcheck::Gen) -> Self {
582                let mut out = Self::ZERO;
583                for digit in out.digits.iter_mut() {
584                    *digit = <$Digit as quickcheck::Arbitrary>::arbitrary(g);
585                }
586                out
587            }
588        }
589    };
590}
591
592crate::main_impl!(mod_impl);
593
594pub mod as_float;
595mod bigint_helpers;
596pub mod cast;
597mod checked;
598mod cmp;
599mod const_trait_fillers;
600mod consts;
601mod convert;
602mod endian;
603pub mod float_as;
604mod fmt;
605#[cfg(feature = "numtraits")]
606mod numtraits;
607mod ops;
608mod overflowing;
609mod radix;
610mod saturating;
611mod unchecked;
612mod wrapping;