malachite_base/num/conversion/digits/
power_of_2_digit_iterable.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::num::arithmetic::traits::{DivRound, SaturatingSubAssign};
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::num::conversion::traits::{
12    ExactFrom, PowerOf2DigitIterable, PowerOf2DigitIterator, WrappingFrom,
13};
14use crate::num::logic::traits::BitBlockAccess;
15use crate::rounding_modes::RoundingMode::*;
16use core::marker::PhantomData;
17
18/// A double-ended iterator over the base-$2^k$ digits of an unsigned primitive integer.
19///
20/// This `struct` is created by the [`PowerOf2DigitIterable::power_of_2_digits`] function. See its
21/// documentation for more.
22#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
23pub struct PrimitivePowerOf2DigitIterator<T: PrimitiveUnsigned, U: PrimitiveUnsigned> {
24    pub(crate) value: T,
25    pub(crate) log_base: u64,
26    pub(crate) remaining: usize,
27    // If `n` is nonzero, this index initially points to the least-significant bit of the least-
28    // significant digit, and is left-shifted by `next`.
29    pub(crate) i: u64,
30    // If `n` is nonzero, this mask initially points to the least-significant bit of the most-
31    // significant nonzero digit, and is right-shifted by `next_back`.
32    pub(crate) j: u64,
33    phantom: PhantomData<*const U>,
34}
35
36impl<T: PrimitiveUnsigned, U: PrimitiveUnsigned + WrappingFrom<<T as BitBlockAccess>::Bits>>
37    Iterator for PrimitivePowerOf2DigitIterator<T, U>
38{
39    type Item = U;
40
41    fn next(&mut self) -> Option<U> {
42        if self.remaining != 0 {
43            let digit = U::wrapping_from(self.value.get_bits(self.i, self.i + self.log_base));
44            self.i += self.log_base;
45            self.remaining -= 1;
46            Some(digit)
47        } else {
48            None
49        }
50    }
51
52    fn size_hint(&self) -> (usize, Option<usize>) {
53        (self.remaining, Some(self.remaining))
54    }
55}
56
57impl<T: PrimitiveUnsigned, U: PrimitiveUnsigned + WrappingFrom<<T as BitBlockAccess>::Bits>>
58    DoubleEndedIterator for PrimitivePowerOf2DigitIterator<T, U>
59{
60    fn next_back(&mut self) -> Option<U> {
61        if self.remaining != 0 {
62            let digit = U::wrapping_from(self.value.get_bits(self.j, self.j + self.log_base));
63            self.j.saturating_sub_assign(self.log_base);
64            self.remaining -= 1;
65            Some(digit)
66        } else {
67            None
68        }
69    }
70}
71
72impl<T: PrimitiveUnsigned, U: PrimitiveUnsigned + WrappingFrom<<T as BitBlockAccess>::Bits>>
73    ExactSizeIterator for PrimitivePowerOf2DigitIterator<T, U>
74{
75}
76
77impl<T: PrimitiveUnsigned, U: PrimitiveUnsigned + WrappingFrom<<T as BitBlockAccess>::Bits>>
78    PowerOf2DigitIterator<U> for PrimitivePowerOf2DigitIterator<T, U>
79{
80    /// Retrieves base-$2^k$ digits by index.
81    ///
82    /// Indexing at or above the significant digit count returns zero.
83    ///
84    /// This function doesn't affect, and isn't affected by, the iterator's position.
85    ///
86    /// $f(x, k, i) = d_i$, where $0 \leq d_i < 2^k$ for all $i$ and
87    /// $$
88    /// \sum_{i=0}^\infty2^{ki}d_i = x.
89    /// $$
90    ///
91    /// # Worst-case complexity
92    /// Constant time and additional memory.
93    ///
94    /// # Examples
95    /// ```
96    /// use malachite_base::num::conversion::traits::{
97    ///     PowerOf2DigitIterable, PowerOf2DigitIterator,
98    /// };
99    ///
100    /// let digits = PowerOf2DigitIterable::<u8>::power_of_2_digits(0u8, 2);
101    /// assert_eq!(digits.get(0), 0);
102    ///
103    /// // 107 = 1101011b
104    /// let digits = PowerOf2DigitIterable::<u8>::power_of_2_digits(107u32, 2);
105    /// assert_eq!(digits.get(0), 3);
106    /// assert_eq!(digits.get(1), 2);
107    /// assert_eq!(digits.get(2), 2);
108    /// assert_eq!(digits.get(100), 0);
109    /// ```
110    fn get(&self, index: u64) -> U {
111        let i = index * self.log_base;
112        U::wrapping_from(self.value.get_bits(i, i + self.log_base))
113    }
114}
115
116fn power_of_2_digits<T: PrimitiveUnsigned, U: PrimitiveUnsigned>(
117    x: T,
118    log_base: u64,
119) -> PrimitivePowerOf2DigitIterator<T, U> {
120    assert_ne!(log_base, 0);
121    assert!(
122        log_base <= U::WIDTH,
123        "type {:?} is too small for a digit of width {}",
124        U::NAME,
125        log_base
126    );
127    let significant_digits = x.significant_bits().div_round(log_base, Ceiling).0;
128    PrimitivePowerOf2DigitIterator {
129        value: x,
130        log_base,
131        remaining: usize::exact_from(significant_digits),
132        i: 0,
133        j: significant_digits.saturating_sub(1) * log_base,
134        phantom: PhantomData,
135    }
136}
137
138macro_rules! impl_power_of_2_digit_iterable {
139    ($t:ident) => {
140        macro_rules! impl_power_of_2_digit_iterable_inner {
141            ($u:ident) => {
142                impl PowerOf2DigitIterable<$u> for $t {
143                    type PowerOf2DigitIterator = PrimitivePowerOf2DigitIterator<$t, $u>;
144
145                    /// Returns a double-ended iterator over the base-$2^k$ digits of a primitive
146                    /// unsigned integer.
147                    ///
148                    /// The forward order is ascending, so that less-significant digits appear
149                    /// first. There are no trailing zeros going forward, or leading zeros going
150                    /// backward.
151                    ///
152                    /// If it's necessary to get a [`Vec`] of all the digits, consider using
153                    /// [`to_power_of_2_digits_asc`](super::super::traits::PowerOf2Digits::to_power_of_2_digits_asc)
154                    /// or
155                    /// [`to_power_of_2_digits_desc`](super::super::traits::PowerOf2Digits::to_power_of_2_digits_desc)
156                    /// instead.
157                    ///
158                    /// # Worst-case complexity
159                    /// Constant time and additional memory.
160                    ///
161                    /// # Panics
162                    /// Panics if `log_base` is larger than the width of output type width.
163                    ///
164                    /// # Examples
165                    /// See [here](super::power_of_2_digit_iterable#power_of_2_digits).
166                    #[inline]
167                    fn power_of_2_digits(
168                        self,
169                        log_base: u64,
170                    ) -> PrimitivePowerOf2DigitIterator<$t, $u> {
171                        power_of_2_digits(self, log_base)
172                    }
173                }
174            };
175        }
176        apply_to_unsigneds!(impl_power_of_2_digit_iterable_inner);
177    };
178}
179apply_to_unsigneds!(impl_power_of_2_digit_iterable);