bit_iter/
lib.rs

1//! Iterate over the bits set in a word.
2//!
3//! A `BitIter` may be constructed from any integral value.
4//!
5//! A `BitIter` may be constructed from any integral value, and returns the positions of the `1`
6//! bits in ascending order.
7//!
8//! `BitIter` implements `DoubleEndedIterator`, so you can iterate over the positions of the set
9//! bits in descending order too.
10//!
11//! ## Example
12//!
13//! ```rust
14//! # use bit_iter::*;
15//! let x : u32 = 0x10001;
16//!
17//! for b in BitIter::from(x) {
18//!     println!("Bit {} is set.", b);
19//! }
20//!
21//! println!("In reverse order:");
22//!
23//! for b in BitIter::from(x).rev() {
24//!     println!("Bit {} is set.", b);
25//! }
26//! ```
27//!
28//! Output:
29//!
30//! ```text
31//! Bit 0 is set.
32//! Bit 16 is set.
33//! In reverse order:
34//! Bit 16 is set.
35//! Bit 0 is set.
36//! ```
37
38#![no_std]
39#![doc(html_root_url = "https://docs.rs/bit-iter/1.3.0")]
40
41use core::iter::{ExactSizeIterator, FusedIterator};
42
43#[cfg(test)]
44mod tests;
45
46/// An iterator which returns the positions of the set bits in a word, in ascending order.
47///
48/// ## Examples
49///
50/// Construct a `BitIter` from an integer:
51///
52/// ```rust
53/// # use bit_iter::*;
54/// let mut iter = BitIter::from(0b10000001);
55/// assert_eq!(iter.next(), Some(0usize));
56/// assert_eq!(iter.next(), Some(7usize));
57/// assert_eq!(iter.next(), None);
58/// ```
59///
60/// Iterate over the bits in an integer in ascending order:
61///
62/// ```rust
63/// # use bit_iter::*;
64/// let v : Vec<usize> = BitIter::from(0b10000001).collect();
65/// assert_eq!(v, vec![0, 7]);
66/// ```
67///
68/// `BitIter` implements `DoubleEndedIterator`, so you can also get the set bit positions in
69/// descending order:
70///
71/// ```rust
72/// # use bit_iter::*;
73/// let v : Vec<usize> = BitIter::from(0b10000001).rev().collect();
74/// assert_eq!(v, vec![7, 0]);
75/// ```
76#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
77pub struct BitIter<T>(T);
78
79macro_rules! iter_impl {
80    ($($t:ty)*) => {$(
81        #[doc(hidden)]
82        impl BitIter<$t> {
83            #[inline]
84            fn rightmost_one_pos(&self) -> usize {
85                self.0.trailing_zeros() as usize
86            }
87
88            #[inline]
89            fn leftmost_one_pos(&self) -> usize {
90                (<$t>::BITS - 1 - self.0.leading_zeros()) as usize
91            }
92
93            #[inline]
94            fn count_ones(&self) -> usize {
95                self.0.count_ones() as usize
96            }
97
98            #[inline]
99            fn clear_rightmost_one(&mut self) {
100                self.0 &= self.0.wrapping_sub(1);
101            }
102        }
103
104        /// `From` implementation for `BitIter`.
105        impl From<$t> for BitIter<$t> {
106            /// Construct a BitIter value.
107            #[inline]
108            fn from(value: $t) -> Self {
109                Self(value)
110            }
111        }
112
113        /// `Iterator` implementation for `BitIter`.
114        impl Iterator for BitIter<$t> {
115            type Item = usize;
116
117            #[inline]
118            fn next(&mut self) -> Option<Self::Item> {
119                if self.0 != 0 {
120                    let trailing = self.rightmost_one_pos();
121                    self.clear_rightmost_one();
122                    Some(trailing)
123                } else {
124                    None
125                }
126            }
127
128            // TODO: next_chunk() - currently nightly only (1.72.0)
129
130            #[inline]
131            fn size_hint(&self) -> (usize, Option<usize>) {
132                let sz = self.count_ones();
133                (sz, Some(sz))
134            }
135
136            #[inline]
137            fn count(self) -> usize {
138                self.count_ones()
139            }
140
141            #[inline]
142            fn last(self) -> Option<Self::Item> {
143                if self.0 != 0 {
144                    Some(self.leftmost_one_pos())
145                } else {
146                    None
147                }
148            }
149
150            // TODO: advance_by() - currently nightly only (1.72.0)
151
152            #[inline]
153            fn nth(&mut self, n: usize) -> Option<Self::Item> {
154                let mut i = 0;
155                while self.0 != 0 && i < n {
156                    self.clear_rightmost_one();
157                    i += 1;
158                }
159                self.next()
160            }
161
162            // TODO: step_by()
163            // TODO: chain()
164            // TODO: zip()
165
166            // TODO: intersperse() - currently nightly only (1.72.0)
167            // TODO: intersperse_with() - currently nightly only (1.72.0)
168
169            // TODO: map()
170            // TODO: for_each()
171            // TODO: filter()
172            // TODO: filter_map()
173            // TODO: enumerate()
174            // TODO: peekable()
175            // TODO: skip_while()
176            // TODO: take_while()
177            // TODO: map_while()
178            // TODO: skip()
179            // TODO: scan()
180            // TODO: flat_map()
181            // TODO: flatten()
182            // TODO: fuse()
183            // TODO: inspect()
184            // TODO: by_ref()
185            // TODO: collect()
186            // TODO: try_collect() - currently nightly only (1.72.0)
187            // TODO: collect_into() - currently nightly only (1.72.0)
188            // TODO: partition()
189            // TODO: partition_in_place() - currently nightly only (1.72.0)
190            // TODO: is_partitioned() - currently nightly only (1.72.0)
191            // TODO: try_fold()
192            // TODO: try_for_each()
193
194            #[inline]
195            fn fold<B, F>(mut self, init: B, mut f: F) -> B
196            where
197                F: FnMut(B, Self::Item) -> B
198            {
199                let mut accum = init;
200                while self.0 != 0 {
201                    accum = f(accum, self.rightmost_one_pos());
202                    self.clear_rightmost_one();
203                }
204                accum
205            }
206
207            // TODO: reduce() - good candidate?
208            // TODO: try_reduce() - currently nightly only (1.72.0)
209            // TODO: all() - good candidate?
210            // TODO: any() - good candidate?
211            // TODO: find() - good candidate?
212            // TODO: find_map()
213            // TODO: try_find() - currently nightly only (1.72.0)
214            // TODO: position() - good candidate?
215            // TODO: rposition() - good candidate?
216
217            #[inline]
218            fn max(self) -> Option<Self::Item> {
219                self.last()
220            }
221
222            #[inline]
223            fn min(self) -> Option<Self::Item> {
224                if self.0 != 0 {
225                    Some(self.rightmost_one_pos())
226                } else {
227                    None
228                }
229            }
230
231            // TODO: max_by_key()
232            // TODO: max_by()
233            // TODO: min_by_key()
234            // TODO: min_by()
235            // TODO: rev()
236            // TODO: unzip() - not applicable
237            // TODO: copied()
238            // TODO: cloned()
239            // TODO: cycle()
240            // TODO: array_chunks() - currently nightly only (1.72.0)
241
242            // TODO: sum() - interesting candidate
243            // TODO: product() - interesting candidate
244
245            // TODO: cmp()
246            // TODO: cmp_by() - currently nightly only (1.72.0)
247            // TODO: partial_cmp()
248            // TODO: partial_cmp_by() - currently nightly only (1.72.0)
249            // TODO: eq()
250            // TODO: eq_by() - currently nightly only (1.72.0)
251            // TODO: ne()
252            // TODO: lt()
253            // TODO: le()
254            // TODO: gt()
255            // TODO: ge()
256
257            fn is_sorted(self) -> bool {
258                true
259            }
260
261            // TODO: is_sorted_by() - currently nightly only (1.72.0)
262            // TODO: is_sorted_by_key() - currently nightly only (1.72.0)
263        }
264
265        /// `FusedIterator` implementation for `BitIter`.
266        impl FusedIterator for BitIter<$t> {}
267
268        /// `DoubleEndedIterator` implementation for `BitIter`.
269        impl DoubleEndedIterator for BitIter<$t> {
270            #[inline]
271            fn next_back(&mut self) -> Option<Self::Item> {
272                if self.0 != 0 {
273                    let highest = self.leftmost_one_pos();
274                    self.0 ^= 1 as $t << highest;
275                    Some(highest)
276                } else {
277                    None
278                }
279            }
280
281            // TODO: advance_back_by() - currently nightly only (1.72.0)
282            // TODO: nth_back()
283            // TODO: try_rfold()
284            // TODO: rfold()
285            // TODO: rfind()
286        }
287
288        /// `ExactSizeIterator` implementation for `BitIter`.
289        impl ExactSizeIterator for BitIter<$t> {
290            #[inline]
291            fn len(&self) -> usize {
292                self.count_ones()
293            }
294
295            // TODO: is_empty() - currently nightly only (1.72.0)
296        }
297    )*}
298}
299
300iter_impl! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }