bit_ops/bitpos_iter.rs
1//! Module providing iterators to iterate over set bits in unsigned integers.
2//!
3//! See [`BitsIter`] and [`BitmapIter`]. The latter is included into Rust's
4//! [`Iterator`] API via [`BitposIteratorExt`].
5//!
6//! # Performance
7//!
8//! These iterators have been trimmed for performance and were benchmarked. See
9//! the project's README on GitHub for more details.
10
11use core::fmt::Debug;
12use core::ops::{Add, BitAndAssign, Sub};
13
14/// **Internal helper** trait for [`BitsIter`].
15pub trait Uint:
16 Copy + Eq + Add<Output = Self> + Sub<Output = Self> + Sized + BitAndAssign + TryInto<usize>
17{
18 /// Number of bits of that type.
19 const BITS: usize;
20 /// `0` value of the underlying primitive type.
21 const ZERO: Self;
22 /// `1` value of the underlying primitive type.
23 const ONE: Self;
24 /// Number of trailing zeroes.
25 fn trailing_zeros(self) -> Self;
26}
27
28/// Implements the relevant bit operations for the specified primitive type.
29///
30/// Note that the bit positions start at `0`. The highest `bit` position thus
31/// is `BITS - 1`.
32macro_rules! impl_uint_trait {
33 ($primitive_ty:ty) => {
34 impl Uint for $primitive_ty {
35 const BITS: usize = <$primitive_ty>::BITS as usize;
36 const ZERO: Self = 0;
37 const ONE: Self = 1;
38
39 fn trailing_zeros(self) -> Self {
40 <$primitive_ty>::trailing_zeros(self) as Self
41 }
42 }
43 };
44}
45
46impl_uint_trait!(u8);
47impl_uint_trait!(u16);
48impl_uint_trait!(u32);
49impl_uint_trait!(u64);
50impl_uint_trait!(u128);
51impl_uint_trait!(usize);
52
53/// Iterator over set bits of an unsigned integer.
54///
55/// The index / bit position starts at `0`, the last bit position is
56/// `n_bits - 1`.
57///
58/// The iterator can be used with [`u8`], [`u16`], [`u32`], [`u64`], [`u128`],
59/// and [`usize`].
60///
61/// # Example
62/// ```rust
63/// # use bit_ops::BitsIter;
64/// // also works with u16, u32, u64, u128, and usize
65/// let iter = BitsIter::<u8>::new(0);
66/// assert_eq!(&iter.collect::<Vec<_>>(), &[]);
67///
68/// let iter = BitsIter::<u8>::new(1);
69/// assert_eq!(&iter.collect::<Vec<_>>(), &[0]);
70///
71/// let iter = BitsIter::<u8>::new(0b1010_1010);
72/// assert_eq!(&iter.collect::<Vec<_>>(), &[1, 3, 5, 7]);
73/// ```
74#[derive(Debug)]
75pub struct BitsIter<U> {
76 value: U,
77}
78
79impl<U: Uint> BitsIter<U>
80where
81 <U as TryInto<usize>>::Error: Debug,
82{
83 /// Creates a new iterator.
84 pub const fn new(value: U) -> Self {
85 Self { value }
86 }
87}
88
89impl<U: Uint> Iterator for BitsIter<U>
90where
91 <U as TryInto<usize>>::Error: Debug,
92{
93 type Item = U;
94
95 #[inline]
96 fn next(&mut self) -> Option<Self::Item> {
97 if self.value == U::ZERO {
98 return None;
99 }
100 let tz = self.value.trailing_zeros();
101 self.value &= self.value - U::ONE; // clear lowest set bit
102 Some(tz)
103 }
104}
105
106/// Iterator over set bits in (large) bitmaps, i.e., collection of unsigned
107/// integers.
108///
109/// This wraps an iterator emitting corresponding unsigned integers and
110/// uses [`BitsIter`] on each element. While doing so, [`BitmapIter`] keeps
111/// track of consumed elements to properly report the bit position relative to
112/// the very first bit. We basically treat the incoming [`Uint`]s as one
113/// gigantic integer and just spit out which bits are set.
114///
115/// The iterator can be used with [`u8`], [`u16`], [`u32`], [`u64`], [`u128`],
116/// and [`usize`]. The [`BitposIteratorExt`] offers a convenient way to
117/// integrate this iterator in typical iterator chains.
118///
119/// # Example
120///
121/// ## Direct Usage of Iterator
122/// ```rust
123/// use bit_ops::BitmapIter;
124///
125/// // also works with u16, u32, u64, u128, and usize
126/// let iter = BitmapIter::<u8, _>::new([0b1111_0010, 0b1000, 1].into_iter());
127/// assert_eq!(&iter.collect::<Vec<_>>(), &[1, 4, 5, 6, 7, 11, 16]);
128/// ```
129///
130/// ## Use via Iterator Trait Extension
131/// ```rust
132/// use bit_ops::BitposIteratorExt;
133///
134/// // also works with u16, u32, u64, u128, and usize
135/// let bit_pos = [0b1111_0010_u8, 0b1000, 1].into_iter()
136/// .bit_positions()
137/// .collect::<Vec<_>>();
138/// assert_eq!(&bit_pos, &[1, 4, 5, 6, 7, 11, 16]);
139/// ```
140#[derive(Debug)]
141pub struct BitmapIter<U, I> {
142 bitmap_iter: I,
143 consumed_count: usize,
144 current_element_it: BitsIter<U>,
145}
146
147impl<U: Uint, I: Iterator<Item = U>> BitmapIter<U, I>
148where
149 <U as TryInto<usize>>::Error: Debug,
150{
151 /// Creates a new iterator.
152 ///
153 /// This consumes everything that implements [`IntoIterator`] for an
154 /// [`Iterator`] of the corresponding [`Uint`].
155 ///
156 /// # Example
157 /// ```rust
158 /// # use bit_ops::BitmapIter;
159 /// let _ = BitmapIter::<u8, _>::new([0_u8]);
160 /// let _ = BitmapIter::<u16, _>::new([0_u16].iter().copied());
161 /// let _ = BitmapIter::<u16, _>::new((&[0_u16]).iter().copied());
162 /// let _ = BitmapIter::<usize, _>::new((vec![42_usize]));
163 /// ```
164 pub fn new<In: IntoIterator<IntoIter = I>>(bitmap_iter: In) -> Self {
165 let mut bitmap_iter = bitmap_iter.into_iter();
166 let current_element_it = BitsIter::new(bitmap_iter.next().unwrap_or(U::ZERO));
167 Self {
168 bitmap_iter,
169 consumed_count: 0,
170 current_element_it,
171 }
172 }
173}
174
175impl<U: Uint, I: Iterator<Item = U>> Iterator for BitmapIter<U, I>
176where
177 <U as TryInto<usize>>::Error: Debug,
178{
179 type Item = usize;
180
181 #[inline]
182 fn next(&mut self) -> Option<Self::Item> {
183 loop {
184 // We return here, if we currently have an element.
185 if let Some(bit) = self.current_element_it.next() {
186 let bit: usize = bit.try_into().unwrap();
187 return Some(bit + self.consumed_count);
188 }
189
190 // Current byte exhausted: load next one or return `None` / exit.
191 let next_byte = self.bitmap_iter.next()?;
192 self.consumed_count += U::BITS;
193 self.current_element_it = BitsIter::new(next_byte);
194 }
195 }
196}
197
198/// Extension for the Rust standard libraries [`Iterator`] for convenient
199/// integration of [`BitmapIter`].
200pub trait BitposIteratorExt<U: Uint>: Iterator<Item = U> + Sized
201where
202 <U as TryInto<usize>>::Error: Debug,
203{
204 /// Creates an iterator that emits which bits are set.
205 ///
206 /// See [`BitmapIter`] for more details.
207 ///
208 /// # Example
209 /// ```rust
210 /// use bit_ops::BitposIteratorExt;
211 /// let ones = [0b101_u64, 0, 1].into_iter()
212 /// .bit_positions()
213 /// .collect::<Vec<_>>();
214 /// assert_eq!(&ones, &[0, 2, 2*64]);
215 /// ```
216 fn bit_positions(self) -> BitmapIter<U, Self> {
217 BitmapIter::new(self)
218 }
219}
220
221// Blanked implementation for all matching iterators.
222impl<U: Uint, I: Iterator<Item = U> + Sized> BitposIteratorExt<U> for I where
223 <U as TryInto<usize>>::Error: Debug
224{
225}
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230 use std::vec::Vec;
231
232 #[test]
233 fn test_bits_iter() {
234 let iter = BitsIter::<u8>::new(0);
235 assert_eq!(&iter.collect::<Vec<_>>(), &[]);
236
237 let iter = BitsIter::<u8>::new(1);
238 assert_eq!(&iter.collect::<Vec<_>>(), &[0]);
239
240 let iter = BitsIter::<u8>::new(0b1010_1010);
241 assert_eq!(&iter.collect::<Vec<_>>(), &[1, 3, 5, 7]);
242
243 let iter = BitsIter::<u8>::new(0b1111_1111);
244 assert_eq!(&iter.collect::<Vec<_>>(), &[0, 1, 2, 3, 4, 5, 6, 7]);
245
246 let iter = BitsIter::<u128>::new(0b1111_1111);
247 assert_eq!(&iter.collect::<Vec<_>>(), &[0, 1, 2, 3, 4, 5, 6, 7]);
248 }
249
250 #[test]
251 fn test_bitmap_iter() {
252 let iter = BitmapIter::<u8, _>::new([0_u8]);
253 assert_eq!(&iter.collect::<Vec<_>>(), &[]);
254
255 let iter = BitmapIter::<u8, _>::new([0b1111_0010, 0b1000, 1]);
256 assert_eq!(&iter.collect::<Vec<_>>(), &[1, 4, 5, 6, 7, 11, 16]);
257
258 let iter = BitmapIter::<u128, _>::new([0b10, 0b10, 0b11]);
259 assert_eq!(&iter.collect::<Vec<_>>(), &[1, 129, 256, 257]);
260 }
261}