65 lines
1.5 KiB
Rust
65 lines
1.5 KiB
Rust
|
// Eryn Wells <eryn@erynwells.me>
|
||
|
|
||
|
pub(crate) struct BitScanner {
|
||
|
bits: u64,
|
||
|
shift: u32,
|
||
|
}
|
||
|
|
||
|
impl BitScanner {
|
||
|
pub(crate) fn new(bits: u64) -> BitScanner {
|
||
|
BitScanner { bits, shift: 0 }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl Iterator for BitScanner {
|
||
|
type Item = u32;
|
||
|
|
||
|
fn next(&mut self) -> Option<Self::Item> {
|
||
|
if self.shift == u64::BITS {
|
||
|
return None;
|
||
|
}
|
||
|
|
||
|
let shifted_bits = self.bits << self.shift;
|
||
|
let leading_zeros = shifted_bits.leading_zeros();
|
||
|
|
||
|
if leading_zeros == u64::BITS {
|
||
|
self.shift = leading_zeros;
|
||
|
return None;
|
||
|
}
|
||
|
|
||
|
let position = u64::BITS - (self.shift + leading_zeros + 1);
|
||
|
// Shift 1 additional place to account for the 1 that `leading_zeros` found.
|
||
|
self.shift += leading_zeros + 1;
|
||
|
|
||
|
Some(position)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[cfg(test)]
|
||
|
mod tests {
|
||
|
use super::*;
|
||
|
|
||
|
#[test]
|
||
|
fn zero() {
|
||
|
let mut scanner = BitScanner::new(0);
|
||
|
assert_eq!(scanner.next(), None);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn one() {
|
||
|
let mut scanner = BitScanner::new(1);
|
||
|
assert_eq!(scanner.next(), Some(0));
|
||
|
assert_eq!(scanner.next(), None);
|
||
|
}
|
||
|
|
||
|
#[test]
|
||
|
fn complex() {
|
||
|
let mut scanner = BitScanner::new(0b11000101);
|
||
|
assert_eq!(scanner.next(), Some(7));
|
||
|
assert_eq!(scanner.next(), Some(6));
|
||
|
assert_eq!(scanner.next(), Some(2));
|
||
|
assert_eq!(scanner.next(), Some(0));
|
||
|
assert_eq!(scanner.next(), None);
|
||
|
}
|
||
|
}
|