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 }