Skip to content

Commit

Permalink
Add a zeroes iterator (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
james7132 authored Jan 16, 2023
1 parent a3283c0 commit 71970f7
Showing 1 changed file with 90 additions and 1 deletion.
91 changes: 90 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use std::fmt::{Binary, Display, Error, Formatter};

pub use range::IndexRange;
use std::cmp::{Ord, Ordering};
use std::iter::{Chain, FromIterator};
use std::iter::{Chain, FromIterator, FusedIterator};
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Index};

const BITS: usize = std::mem::size_of::<Block>() * 8;
Expand Down Expand Up @@ -403,6 +403,27 @@ impl FixedBitSet {
}
}

/// Iterates over all disabled bits.
///
/// Iterator element is the index of the `0` bit, type `usize`.
#[inline]
pub fn zeroes(&self) -> Zeroes {
match self.as_slice().split_first() {
Some((&block, rem)) => Zeroes {
bitset: !block,
block_idx: 0,
len: self.len(),
remaining_blocks: rem.iter(),
},
None => Zeroes {
bitset: !0,
block_idx: 0,
len: self.len(),
remaining_blocks: [].iter(),
},
}
}

/// Returns a lazy iterator over the intersection of two `FixedBitSet`s
pub fn intersection<'a>(&'a self, other: &'a FixedBitSet) -> Intersection<'a> {
Intersection {
Expand Down Expand Up @@ -700,6 +721,46 @@ impl<'a> Iterator for Ones<'a> {
}
}

/// An iterator producing the indices of the set bit in a set.
///
/// This struct is created by the [`FixedBitSet::ones`] method.
pub struct Zeroes<'a> {
bitset: Block,
block_idx: usize,
len: usize,
remaining_blocks: std::slice::Iter<'a, Block>,
}

impl<'a> Iterator for Zeroes<'a> {
type Item = usize; // the bit position of the '1'

#[inline]
fn next(&mut self) -> Option<Self::Item> {
while self.bitset == 0 {
self.bitset = !*self.remaining_blocks.next()?;
self.block_idx += BITS;
}
let t = self.bitset & (0 as Block).wrapping_sub(self.bitset);
let r = self.bitset.trailing_zeros() as usize;
self.bitset ^= t;
let bit = self.block_idx + r;
// The remaining zeroes beyond the length of the bitset must be excluded.
if bit < self.len {
Some(bit)
} else {
None
}
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(self.len))
}
}

// Zeroes will stop returning Some when exhausted.
impl<'a> FusedIterator for Zeroes<'a> {}

impl Clone for FixedBitSet {
#[inline]
fn clone(&self) -> Self {
Expand Down Expand Up @@ -1638,6 +1699,34 @@ mod tests {
);
}

#[test]
fn zeroes() {
let len = 232;
let mut fb = FixedBitSet::with_capacity(len);
for i in (0..len).filter(|i| i % 7 == 0) {
fb.insert(i);
}
let zeroes = fb.zeroes().collect::<Vec<usize>>();

assert_eq!(
zeroes,
vec![
1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 15, 16, 17, 18, 19, 20, 22, 23, 24, 25, 26,
27, 29, 30, 31, 32, 33, 34, 36, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 48, 50, 51,
52, 53, 54, 55, 57, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75,
76, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 99,
100, 101, 102, 103, 104, 106, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117,
118, 120, 121, 122, 123, 124, 125, 127, 128, 129, 130, 131, 132, 134, 135, 136,
137, 138, 139, 141, 142, 143, 144, 145, 146, 148, 149, 150, 151, 152, 153, 155,
156, 157, 158, 159, 160, 162, 163, 164, 165, 166, 167, 169, 170, 171, 172, 173,
174, 176, 177, 178, 179, 180, 181, 183, 184, 185, 186, 187, 188, 190, 191, 192,
193, 194, 195, 197, 198, 199, 200, 201, 202, 204, 205, 206, 207, 208, 209, 211,
212, 213, 214, 215, 216, 218, 219, 220, 221, 222, 223, 225, 226, 227, 228, 229,
230
]
);
}

#[cfg(feature = "std")]
#[test]
fn binary_trait() {
Expand Down

0 comments on commit 71970f7

Please sign in to comment.