Skip to content

Commit 71970f7

Browse files
authored
Add a zeroes iterator (#89)
1 parent a3283c0 commit 71970f7

1 file changed

Lines changed: 90 additions & 1 deletion

File tree

src/lib.rs

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use std::fmt::{Binary, Display, Error, Formatter};
3434

3535
pub use range::IndexRange;
3636
use std::cmp::{Ord, Ordering};
37-
use std::iter::{Chain, FromIterator};
37+
use std::iter::{Chain, FromIterator, FusedIterator};
3838
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Index};
3939

4040
const BITS: usize = std::mem::size_of::<Block>() * 8;
@@ -403,6 +403,27 @@ impl FixedBitSet {
403403
}
404404
}
405405

406+
/// Iterates over all disabled bits.
407+
///
408+
/// Iterator element is the index of the `0` bit, type `usize`.
409+
#[inline]
410+
pub fn zeroes(&self) -> Zeroes {
411+
match self.as_slice().split_first() {
412+
Some((&block, rem)) => Zeroes {
413+
bitset: !block,
414+
block_idx: 0,
415+
len: self.len(),
416+
remaining_blocks: rem.iter(),
417+
},
418+
None => Zeroes {
419+
bitset: !0,
420+
block_idx: 0,
421+
len: self.len(),
422+
remaining_blocks: [].iter(),
423+
},
424+
}
425+
}
426+
406427
/// Returns a lazy iterator over the intersection of two `FixedBitSet`s
407428
pub fn intersection<'a>(&'a self, other: &'a FixedBitSet) -> Intersection<'a> {
408429
Intersection {
@@ -700,6 +721,46 @@ impl<'a> Iterator for Ones<'a> {
700721
}
701722
}
702723

724+
/// An iterator producing the indices of the set bit in a set.
725+
///
726+
/// This struct is created by the [`FixedBitSet::ones`] method.
727+
pub struct Zeroes<'a> {
728+
bitset: Block,
729+
block_idx: usize,
730+
len: usize,
731+
remaining_blocks: std::slice::Iter<'a, Block>,
732+
}
733+
734+
impl<'a> Iterator for Zeroes<'a> {
735+
type Item = usize; // the bit position of the '1'
736+
737+
#[inline]
738+
fn next(&mut self) -> Option<Self::Item> {
739+
while self.bitset == 0 {
740+
self.bitset = !*self.remaining_blocks.next()?;
741+
self.block_idx += BITS;
742+
}
743+
let t = self.bitset & (0 as Block).wrapping_sub(self.bitset);
744+
let r = self.bitset.trailing_zeros() as usize;
745+
self.bitset ^= t;
746+
let bit = self.block_idx + r;
747+
// The remaining zeroes beyond the length of the bitset must be excluded.
748+
if bit < self.len {
749+
Some(bit)
750+
} else {
751+
None
752+
}
753+
}
754+
755+
#[inline]
756+
fn size_hint(&self) -> (usize, Option<usize>) {
757+
(0, Some(self.len))
758+
}
759+
}
760+
761+
// Zeroes will stop returning Some when exhausted.
762+
impl<'a> FusedIterator for Zeroes<'a> {}
763+
703764
impl Clone for FixedBitSet {
704765
#[inline]
705766
fn clone(&self) -> Self {
@@ -1638,6 +1699,34 @@ mod tests {
16381699
);
16391700
}
16401701

1702+
#[test]
1703+
fn zeroes() {
1704+
let len = 232;
1705+
let mut fb = FixedBitSet::with_capacity(len);
1706+
for i in (0..len).filter(|i| i % 7 == 0) {
1707+
fb.insert(i);
1708+
}
1709+
let zeroes = fb.zeroes().collect::<Vec<usize>>();
1710+
1711+
assert_eq!(
1712+
zeroes,
1713+
vec![
1714+
1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26,
1715+
27, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 48, 50, 51,
1716+
52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75,
1717+
76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 99,
1718+
100, 101, 102, 103, 104, 106, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117,
1719+
118, 120, 121, 122, 123, 124, 125, 127, 128, 129, 130, 131, 132, 134, 135, 136,
1720+
137, 138, 139, 141, 142, 143, 144, 145, 146, 148, 149, 150, 151, 152, 153, 155,
1721+
156, 157, 158, 159, 160, 162, 163, 164, 165, 166, 167, 169, 170, 171, 172, 173,
1722+
174, 176, 177, 178, 179, 180, 181, 183, 184, 185, 186, 187, 188, 190, 191, 192,
1723+
193, 194, 195, 197, 198, 199, 200, 201, 202, 204, 205, 206, 207, 208, 209, 211,
1724+
212, 213, 214, 215, 216, 218, 219, 220, 221, 222, 223, 225, 226, 227, 228, 229,
1725+
230
1726+
]
1727+
);
1728+
}
1729+
16411730
#[cfg(feature = "std")]
16421731
#[test]
16431732
fn binary_trait() {

0 commit comments

Comments
 (0)