malachite_base/num/logic/
bit_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::basic::signeds::PrimitiveSigned;
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::num::conversion::traits::{ExactFrom, WrappingFrom};
12use crate::num::logic::traits::BitIterable;
13use core::cmp::Ordering::*;
14use core::cmp::min;
15use core::marker::PhantomData;
16use core::ops::Index;
17
18/// A double-ended iterator over the bits of an unsigned primitive integer.
19///
20/// This `struct` is created by [`BitIterable::bits`]; see its documentation for more.
21#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
22pub struct PrimitiveUnsignedBitIterator<T: PrimitiveUnsigned> {
23    pub(crate) value: T,
24    pub(crate) remaining: usize,
25    // If `n` is nonzero, this mask initially points to the least-significant bit, and is left-
26    // shifted by next().
27    pub(crate) i_mask: T,
28    // If `n` is nonzero, this mask initially points to the most-significant nonzero bit, and is
29    // right-shifted by next_back().
30    pub(crate) j_mask: T,
31}
32
33impl<T: PrimitiveUnsigned> Iterator for PrimitiveUnsignedBitIterator<T> {
34    type Item = bool;
35
36    fn next(&mut self) -> Option<bool> {
37        if self.remaining != 0 {
38            let bit = self.value & self.i_mask != T::ZERO;
39            self.i_mask <<= 1;
40            self.remaining -= 1;
41            Some(bit)
42        } else {
43            None
44        }
45    }
46
47    fn size_hint(&self) -> (usize, Option<usize>) {
48        (self.remaining, Some(self.remaining))
49    }
50}
51
52impl<T: PrimitiveUnsigned> DoubleEndedIterator for PrimitiveUnsignedBitIterator<T> {
53    fn next_back(&mut self) -> Option<bool> {
54        if self.remaining != 0 {
55            let bit = self.value & self.j_mask != T::ZERO;
56            self.j_mask >>= 1;
57            self.remaining -= 1;
58            Some(bit)
59        } else {
60            None
61        }
62    }
63}
64
65impl<T: PrimitiveUnsigned> ExactSizeIterator for PrimitiveUnsignedBitIterator<T> {}
66
67impl<T: PrimitiveUnsigned> Index<u64> for PrimitiveUnsignedBitIterator<T> {
68    type Output = bool;
69
70    /// A function to retrieve bits by index.
71    ///
72    /// The index is the power of 2 of which the bit is a coefficient. Indexing at or above the
73    /// significant bit count returns false bits.
74    ///
75    /// This is equivalent to [`get_bit`](super::traits::BitAccess::get_bit).
76    ///
77    /// # Worst-case complexity
78    /// Constant time and additional memory.
79    ///
80    /// # Examples
81    /// ```
82    /// use malachite_base::num::logic::traits::BitIterable;
83    ///
84    /// assert_eq!(0u8.bits()[0], false);
85    ///
86    /// // 105 = 1101001b
87    /// let bits = 105u32.bits();
88    /// assert_eq!(bits[0], true);
89    /// assert_eq!(bits[1], false);
90    /// assert_eq!(bits[2], false);
91    /// assert_eq!(bits[3], true);
92    /// assert_eq!(bits[4], false);
93    /// assert_eq!(bits[5], true);
94    /// assert_eq!(bits[6], true);
95    /// assert_eq!(bits[7], false);
96    /// assert_eq!(bits[100], false);
97    /// ```
98    fn index(&self, index: u64) -> &bool {
99        if self.value.get_bit(index) {
100            &true
101        } else {
102            &false
103        }
104    }
105}
106
107fn bits_unsigned<T: PrimitiveUnsigned>(x: T) -> PrimitiveUnsignedBitIterator<T> {
108    let significant_bits = x.significant_bits();
109    PrimitiveUnsignedBitIterator {
110        value: x,
111        remaining: usize::exact_from(significant_bits),
112        i_mask: T::ONE,
113        j_mask: T::power_of_2(significant_bits.saturating_sub(1)),
114    }
115}
116
117macro_rules! impl_bit_iterable_unsigned {
118    ($t:ident) => {
119        impl BitIterable for $t {
120            type BitIterator = PrimitiveUnsignedBitIterator<$t>;
121
122            /// Returns a double-ended iterator over the bits of an unsigned primitive integer.
123            ///
124            /// The forward order is ascending, so that less significant bits appear first. There
125            /// are no trailing false bits going forward, or leading falses going backward.
126            ///
127            /// If it's necessary to get a [`Vec`] of all the bits, consider using
128            /// [`to_bits_asc`](super::traits::BitConvertible::to_bits_asc) or
129            /// [`to_bits_desc`](super::traits::BitConvertible::to_bits_desc) instead.
130            ///
131            /// # Worst-case complexity
132            /// Constant time and additional memory.
133            ///
134            /// # Examples
135            /// See [here](super::bit_iterable#bits).
136            #[inline]
137            fn bits(self) -> PrimitiveUnsignedBitIterator<$t> {
138                bits_unsigned(self)
139            }
140        }
141    };
142}
143apply_to_unsigneds!(impl_bit_iterable_unsigned);
144
145/// A double-ended iterator over the bits of a signed primitive integer.
146///
147/// This `struct` is created by [`BitIterable::bits`]; see its documentation for more.
148#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
149pub struct PrimitiveSignedBitIterator<U: PrimitiveUnsigned, S: PrimitiveSigned> {
150    phantom: PhantomData<*const S>,
151    xs: PrimitiveUnsignedBitIterator<U>,
152}
153
154impl<U: PrimitiveUnsigned, S: PrimitiveSigned> Iterator for PrimitiveSignedBitIterator<U, S> {
155    type Item = bool;
156
157    #[inline]
158    fn next(&mut self) -> Option<bool> {
159        self.xs.next()
160    }
161
162    #[inline]
163    fn size_hint(&self) -> (usize, Option<usize>) {
164        self.xs.size_hint()
165    }
166}
167
168impl<U: PrimitiveUnsigned, S: PrimitiveSigned> DoubleEndedIterator
169    for PrimitiveSignedBitIterator<U, S>
170{
171    #[inline]
172    fn next_back(&mut self) -> Option<bool> {
173        self.xs.next_back()
174    }
175}
176
177impl<U: PrimitiveUnsigned, S: PrimitiveSigned> ExactSizeIterator
178    for PrimitiveSignedBitIterator<U, S>
179{
180}
181
182impl<U: PrimitiveUnsigned, S: PrimitiveSigned> Index<u64> for PrimitiveSignedBitIterator<U, S> {
183    type Output = bool;
184
185    /// A function to retrieve bits by index. The index is the power of 2 of which the bit is a
186    /// coefficient.
187    ///
188    /// Indexing at or above the significant bit count returns false or true bits, depending on the
189    /// value's sign.
190    ///
191    /// This is equivalent to [`get_bit`](super::traits::BitAccess::get_bit).
192    ///
193    /// # Worst-case complexity
194    /// Constant time and additional memory.
195    ///
196    /// # Examples
197    /// ```
198    /// use malachite_base::num::logic::traits::BitIterable;
199    ///
200    /// assert_eq!(0i8.bits()[0], false);
201    ///
202    /// // -105 = 10010111 in two's complement
203    /// let bits = (-105i32).bits();
204    /// assert_eq!(bits[0], true);
205    /// assert_eq!(bits[1], true);
206    /// assert_eq!(bits[2], true);
207    /// assert_eq!(bits[3], false);
208    /// assert_eq!(bits[4], true);
209    /// assert_eq!(bits[5], false);
210    /// assert_eq!(bits[6], false);
211    /// assert_eq!(bits[7], true);
212    /// assert_eq!(bits[100], true);
213    /// ```
214    fn index(&self, index: u64) -> &bool {
215        if self.xs[min(index, U::WIDTH - 1)] {
216            &true
217        } else {
218            &false
219        }
220    }
221}
222
223fn bits_signed<U: PrimitiveUnsigned + WrappingFrom<S>, S: PrimitiveSigned>(
224    x: S,
225) -> PrimitiveSignedBitIterator<U, S> {
226    let unsigned = U::wrapping_from(x);
227    let significant_bits = match x.sign() {
228        Equal => 0,
229        Greater => unsigned.significant_bits() + 1,
230        Less => (!unsigned).significant_bits() + 1,
231    };
232    PrimitiveSignedBitIterator {
233        phantom: PhantomData,
234        xs: PrimitiveUnsignedBitIterator {
235            value: unsigned,
236            remaining: usize::exact_from(significant_bits),
237            i_mask: U::ONE,
238            j_mask: U::power_of_2(significant_bits.saturating_sub(1)),
239        },
240    }
241}
242
243macro_rules! impl_bit_iterable_signed {
244    ($u:ident, $s:ident) => {
245        impl BitIterable for $s {
246            type BitIterator = PrimitiveSignedBitIterator<$u, $s>;
247
248            /// Returns a double-ended iterator over the bits of a signed primitive integer.
249            ///
250            /// The forward order is ascending, so that less significant bits appear first. There
251            /// are no trailing sign bits going forward, or leading sign bits going backward.
252            ///
253            /// If it's necessary to get a [`Vec`] of all the bits, consider using
254            /// [`to_bits_asc`](super::traits::BitConvertible::to_bits_asc) or
255            /// [`to_bits_desc`](super::traits::BitConvertible::to_bits_desc) instead.
256            ///
257            /// # Worst-case complexity
258            /// Constant time and additional memory.
259            ///
260            /// # Examples
261            /// See [here](super::bit_iterable#bits).
262            #[inline]
263            fn bits(self) -> PrimitiveSignedBitIterator<$u, $s> {
264                bits_signed::<$u, $s>(self)
265            }
266        }
267    };
268}
269apply_to_unsigned_signed_pairs!(impl_bit_iterable_signed);