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.1")]
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            #[inline]
129            fn size_hint(&self) -> (usize, Option<usize>) {
130                let sz = self.count_ones();
131                (sz, Some(sz))
132            }
133
134            #[inline]
135            fn count(self) -> usize {
136                self.count_ones()
137            }
138
139            #[inline]
140            fn last(self) -> Option<Self::Item> {
141                if self.0 != 0 {
142                    Some(self.leftmost_one_pos())
143                } else {
144                    None
145                }
146            }
147
148            #[inline]
149            fn nth(&mut self, n: usize) -> Option<Self::Item> {
150                let mut i = 0;
151                while self.0 != 0 && i < n {
152                    self.clear_rightmost_one();
153                    i += 1;
154                }
155                self.next()
156            }
157
158            #[inline]
159            fn fold<B, F>(mut self, init: B, mut f: F) -> B
160            where
161                F: FnMut(B, Self::Item) -> B
162            {
163                let mut accum = init;
164                while self.0 != 0 {
165                    accum = f(accum, self.rightmost_one_pos());
166                    self.clear_rightmost_one();
167                }
168                accum
169            }
170
171            #[inline]
172            fn max(self) -> Option<Self::Item> {
173                self.last()
174            }
175
176            #[inline]
177            fn min(self) -> Option<Self::Item> {
178                if self.0 != 0 {
179                    Some(self.rightmost_one_pos())
180                } else {
181                    None
182                }
183            }
184
185            fn is_sorted(self) -> bool {
186                true
187            }
188        }
189
190        /// `FusedIterator` implementation for `BitIter`.
191        impl FusedIterator for BitIter<$t> {}
192
193        /// `DoubleEndedIterator` implementation for `BitIter`.
194        impl DoubleEndedIterator for BitIter<$t> {
195            #[inline]
196            fn next_back(&mut self) -> Option<Self::Item> {
197                if self.0 != 0 {
198                    let highest = self.leftmost_one_pos();
199                    self.0 ^= 1 as $t << highest;
200                    Some(highest)
201                } else {
202                    None
203                }
204            }
205        }
206
207        /// `ExactSizeIterator` implementation for `BitIter`.
208        impl ExactSizeIterator for BitIter<$t> {
209            #[inline]
210            fn len(&self) -> usize {
211                self.count_ones()
212            }
213        }
214    )*}
215}
216
217iter_impl! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }