pub struct BitmapReader<'a> {
data: &'a [u8],
bit_count: u64,
}
impl<'a> BitmapReader<'a> {
pub fn new(data: &'a [u8], bit_count: u64) -> Self {
Self { data, bit_count }
}
pub fn bit_count(&self) -> u64 {
self.bit_count
}
#[inline]
pub fn is_bit_set(&self, index: u64) -> bool {
if index >= self.bit_count {
return false;
}
let byte_idx = (index / 8) as usize;
let bit_idx = (index % 8) as u32;
if byte_idx >= self.data.len() {
return false;
}
self.data[byte_idx] & (1u8 << bit_idx) != 0
}
pub fn count_set_bits(&self) -> u64 {
if self.bit_count == 0 {
return 0;
}
let full_bytes = (self.bit_count / 8) as usize;
let remaining_bits = (self.bit_count % 8) as u32;
let mut count: u64 = 0;
for &byte in &self.data[..full_bytes] {
count += byte.count_ones() as u64;
}
if remaining_bits > 0 && full_bytes < self.data.len() {
let mask = (1u8 << remaining_bits) - 1;
count += (self.data[full_bytes] & mask).count_ones() as u64;
}
count
}
pub fn count_clear_bits(&self) -> u64 {
self.bit_count - self.count_set_bits()
}
#[inline]
fn top_set_bit(byte: u8) -> u32 {
debug_assert!(byte != 0, "top_set_bit requires a non-zero byte");
31 - (byte as u32).leading_zeros()
}
pub fn highest_set_bit(&self) -> Option<u64> {
if self.bit_count == 0 {
return None;
}
let full_bytes = (self.bit_count / 8) as usize;
let remaining_bits = (self.bit_count % 8) as u32;
if remaining_bits > 0 && full_bytes < self.data.len() {
let mask = (1u8 << remaining_bits) - 1;
let masked = self.data[full_bytes] & mask;
if masked != 0 {
let top_bit = Self::top_set_bit(masked);
return Some(full_bytes as u64 * 8 + top_bit as u64);
}
}
for i in (0..full_bytes).rev() {
if self.data[i] != 0 {
let top_bit = Self::top_set_bit(self.data[i]);
return Some(i as u64 * 8 + top_bit as u64);
}
}
None
}
pub fn highest_clear_bit(&self) -> Option<u64> {
if self.bit_count == 0 {
return None;
}
let full_bytes = (self.bit_count / 8) as usize;
let remaining_bits = (self.bit_count % 8) as u32;
if remaining_bits > 0 && full_bytes < self.data.len() {
let mask = (1u8 << remaining_bits) - 1;
let inv = (!self.data[full_bytes]) & mask;
if inv != 0 {
let top_bit = Self::top_set_bit(inv);
return Some(full_bytes as u64 * 8 + top_bit as u64);
}
}
for i in (0..full_bytes).rev() {
let inv = !self.data[i];
if inv != 0 {
let top_bit = Self::top_set_bit(inv);
return Some(i as u64 * 8 + top_bit as u64);
}
}
None
}
pub fn lowest_clear_bit(&self) -> Option<u64> {
if self.bit_count == 0 {
return None;
}
let full_bytes = (self.bit_count / 8) as usize;
let remaining_bits = (self.bit_count % 8) as u32;
for i in 0..full_bytes {
if self.data[i] != 0xFF {
let bit = self.data[i].trailing_ones();
return Some(i as u64 * 8 + bit as u64);
}
}
if remaining_bits > 0 && full_bytes < self.data.len() {
let mask = (1u8 << remaining_bits) - 1;
let masked = self.data[full_bytes] & mask;
if masked != mask {
let bit = masked.trailing_ones();
if bit < remaining_bits {
return Some(full_bytes as u64 * 8 + bit as u64);
}
}
}
None
}
pub fn iter_set_bits(&self) -> SetBitsIter<'_> {
SetBitsIter {
bitmap: self,
index: 0,
}
}
pub fn iter_clear_bits(&self) -> ClearBitsIter<'_> {
ClearBitsIter {
bitmap: self,
index: 0,
}
}
}
pub struct SetBitsIter<'a> {
bitmap: &'a BitmapReader<'a>,
index: u64,
}
impl Iterator for SetBitsIter<'_> {
type Item = u64;
fn next(&mut self) -> Option<u64> {
while self.index < self.bitmap.bit_count {
let i = self.index;
self.index += 1;
if self.bitmap.is_bit_set(i) {
return Some(i);
}
}
None
}
}
pub struct ClearBitsIter<'a> {
bitmap: &'a BitmapReader<'a>,
index: u64,
}
impl Iterator for ClearBitsIter<'_> {
type Item = u64;
fn next(&mut self) -> Option<u64> {
while self.index < self.bitmap.bit_count {
let i = self.index;
self.index += 1;
if !self.bitmap.is_bit_set(i) {
return Some(i);
}
}
None
}
}
#[inline]
pub fn bitmap_set_bit(data: &mut [u8], index: u64) {
let byte_idx = (index / 8) as usize;
let bit_idx = (index % 8) as u32;
data[byte_idx] |= 1u8 << bit_idx;
}
#[inline]
pub fn bitmap_clear_bit(data: &mut [u8], index: u64) {
let byte_idx = (index / 8) as usize;
let bit_idx = (index % 8) as u32;
data[byte_idx] &= !(1u8 << bit_idx);
}
pub fn bitmap_find_clear_bit(data: &[u8], bit_count: u64) -> Option<u64> {
let full_bytes = (bit_count / 8) as usize;
let remaining_bits = (bit_count % 8) as u32;
for (i, &byte) in data[..full_bytes].iter().enumerate() {
if byte != 0xFF {
let bit = byte.trailing_ones();
return Some(i as u64 * 8 + bit as u64);
}
}
if remaining_bits > 0 && full_bytes < data.len() {
let mask = (1u8 << remaining_bits) - 1;
let masked = data[full_bytes] & mask;
if masked != mask {
let bit = masked.trailing_ones();
if bit < remaining_bits {
return Some(full_bytes as u64 * 8 + bit as u64);
}
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn top_set_bit_matches_a_plain_scan_for_every_byte() {
for byte in 1u8..=255 {
let expected = (0..8u32).filter(|b| byte & (1 << b) != 0).max().unwrap();
assert_eq!(
BitmapReader::top_set_bit(byte),
expected,
"top_set_bit({byte:#04x})"
);
}
}
#[test]
fn highest_set_and_clear_bits_are_positionally_correct() {
for bit in 0..8u64 {
let data = [1u8 << bit];
let bm = BitmapReader::new(&data, 8);
assert_eq!(bm.highest_set_bit(), Some(bit), "highest_set_bit for {bit}");
let inv = [!(1u8 << bit)];
let bmi = BitmapReader::new(&inv, 8);
assert_eq!(
bmi.highest_clear_bit(),
Some(bit),
"highest_clear_bit for {bit}"
);
}
let data = [0x00u8, 0b0001_0000, 0x00];
assert_eq!(
BitmapReader::new(&data, 24).highest_set_bit(),
Some(8 + 4),
"highest set bit should be byte 1, bit 4"
);
}
#[test]
fn test_single_byte_set_bits() {
let data = [0b10100101u8]; let bm = BitmapReader::new(&data, 8);
assert!(bm.is_bit_set(0));
assert!(!bm.is_bit_set(1));
assert!(bm.is_bit_set(2));
assert!(!bm.is_bit_set(3));
assert!(!bm.is_bit_set(4));
assert!(bm.is_bit_set(5));
assert!(!bm.is_bit_set(6));
assert!(bm.is_bit_set(7));
assert_eq!(bm.count_set_bits(), 4);
assert_eq!(bm.count_clear_bits(), 4);
assert_eq!(bm.highest_set_bit(), Some(7));
}
#[test]
fn test_partial_byte() {
let data = [0xFF];
let bm = BitmapReader::new(&data, 5); assert_eq!(bm.count_set_bits(), 5); assert_eq!(bm.count_clear_bits(), 0);
assert_eq!(bm.highest_set_bit(), Some(4));
}
#[test]
fn test_partial_byte_with_clear_bits() {
let data = [0b11110011u8];
let bm = BitmapReader::new(&data, 6); assert_eq!(bm.count_set_bits(), 4);
assert_eq!(bm.count_clear_bits(), 2);
assert_eq!(bm.highest_set_bit(), Some(5));
}
#[test]
fn test_iter_set_bits() {
let data = [0b00000101u8]; let bm = BitmapReader::new(&data, 8);
let bits: Vec<u64> = bm.iter_set_bits().collect();
assert_eq!(bits, vec![0, 2]);
}
#[test]
fn test_iter_clear_bits() {
let data = [0b11111010u8]; let bm = BitmapReader::new(&data, 8);
let bits: Vec<u64> = bm.iter_clear_bits().collect();
assert_eq!(bits, vec![0, 2]);
}
#[test]
fn test_iter_set_bits_partial() {
let data = [0b11111111u8];
let bm = BitmapReader::new(&data, 3); let bits: Vec<u64> = bm.iter_set_bits().collect();
assert_eq!(bits, vec![0, 1, 2]);
}
#[test]
fn test_multi_byte() {
let data = [0xFF, 0x00, 0b00000011]; let bm = BitmapReader::new(&data, 24);
assert_eq!(bm.count_set_bits(), 10); assert_eq!(bm.count_clear_bits(), 14);
assert_eq!(bm.highest_set_bit(), Some(17)); }
#[test]
fn test_multi_byte_partial() {
let data = [0xFF, 0xFF, 0b00001111];
let bm = BitmapReader::new(&data, 20); assert_eq!(bm.count_set_bits(), 20); assert_eq!(bm.highest_set_bit(), Some(19));
}
#[test]
fn test_highest_set_bit_middle() {
let data = [0x00, 0b10000000, 0x00]; let bm = BitmapReader::new(&data, 24);
assert_eq!(bm.highest_set_bit(), Some(15));
}
#[test]
fn test_highest_set_bit_none() {
let data = [0x00, 0x00];
let bm = BitmapReader::new(&data, 16);
assert_eq!(bm.highest_set_bit(), None);
}
#[test]
fn test_highest_clear_bit_basic() {
let data = [0b10110101u8];
let bm = BitmapReader::new(&data, 8);
assert_eq!(bm.highest_clear_bit(), Some(6));
}
#[test]
fn test_highest_clear_bit_all_set() {
let data = [0xFF, 0xFF];
let bm = BitmapReader::new(&data, 16);
assert_eq!(bm.highest_clear_bit(), None);
}
#[test]
fn test_highest_clear_bit_partial() {
let data = [0xFE, 0xFF];
let bm = BitmapReader::new(&data, 11);
assert_eq!(bm.highest_clear_bit(), Some(0));
}
#[test]
fn test_highest_clear_bit_partial_with_clear() {
let data = [0xFF, 0b00000101]; let bm = BitmapReader::new(&data, 11);
assert_eq!(bm.highest_clear_bit(), Some(9));
}
#[test]
fn test_highest_clear_bit_middle_byte() {
let data = [0xFF, 0b01111111, 0xFF];
let bm = BitmapReader::new(&data, 24);
assert_eq!(bm.highest_clear_bit(), Some(15));
}
#[test]
fn test_highest_clear_bit_empty() {
let data: [u8; 0] = [];
let bm = BitmapReader::new(&data, 0);
assert_eq!(bm.highest_clear_bit(), None);
}
#[test]
fn test_lowest_clear_bit() {
let data = [0xFF, 0b11111110]; let bm = BitmapReader::new(&data, 16);
assert_eq!(bm.lowest_clear_bit(), Some(8)); }
#[test]
fn test_lowest_clear_bit_first() {
let data = [0b11111110]; let bm = BitmapReader::new(&data, 8);
assert_eq!(bm.lowest_clear_bit(), Some(0));
}
#[test]
fn test_lowest_clear_bit_none() {
let data = [0xFF, 0xFF];
let bm = BitmapReader::new(&data, 16);
assert_eq!(bm.lowest_clear_bit(), None);
}
#[test]
fn test_lowest_clear_bit_partial() {
let data = [0xFF, 0b11111011]; let bm = BitmapReader::new(&data, 12); assert_eq!(bm.lowest_clear_bit(), Some(10));
}
#[test]
fn test_empty_bitmap() {
let data = [];
let bm = BitmapReader::new(&data, 0);
assert_eq!(bm.count_set_bits(), 0);
assert_eq!(bm.count_clear_bits(), 0);
assert_eq!(bm.highest_set_bit(), None);
assert_eq!(bm.lowest_clear_bit(), None);
assert!(!bm.is_bit_set(0));
assert_eq!(bm.iter_set_bits().count(), 0);
assert_eq!(bm.iter_clear_bits().count(), 0);
}
#[test]
fn test_out_of_range() {
let data = [0xFF];
let bm = BitmapReader::new(&data, 8);
assert!(!bm.is_bit_set(8));
assert!(!bm.is_bit_set(100));
}
#[test]
fn test_bit_count() {
let data = [0xFF; 4];
let bm = BitmapReader::new(&data, 30);
assert_eq!(bm.bit_count(), 30);
}
#[test]
fn test_large_bitmap() {
let data = vec![0xFF; 128];
let bm = BitmapReader::new(&data, 1024);
assert_eq!(bm.count_set_bits(), 1024);
assert_eq!(bm.count_clear_bits(), 0);
assert_eq!(bm.highest_set_bit(), Some(1023));
assert_eq!(bm.lowest_clear_bit(), None);
}
#[test]
fn test_large_bitmap_sparse() {
let data = vec![0x01; 128];
let bm = BitmapReader::new(&data, 1024);
assert_eq!(bm.count_set_bits(), 128);
assert_eq!(bm.count_clear_bits(), 896);
assert_eq!(bm.highest_set_bit(), Some(1016)); assert_eq!(bm.lowest_clear_bit(), Some(1)); }
#[test]
fn test_iter_set_bits_multi_byte() {
let data = [0b00000001, 0b10000000]; let bm = BitmapReader::new(&data, 16);
let bits: Vec<u64> = bm.iter_set_bits().collect();
assert_eq!(bits, vec![0, 15]);
}
#[test]
fn test_iter_clear_bits_all_set() {
let data = [0xFF];
let bm = BitmapReader::new(&data, 8);
let bits: Vec<u64> = bm.iter_clear_bits().collect();
assert!(bits.is_empty());
}
#[test]
fn test_iter_set_bits_all_clear() {
let data = [0x00];
let bm = BitmapReader::new(&data, 8);
let bits: Vec<u64> = bm.iter_set_bits().collect();
assert!(bits.is_empty());
}
#[test]
fn test_bitmap_set_bit() {
let mut data = [0u8; 2];
bitmap_set_bit(&mut data, 0);
assert_eq!(data[0], 0b00000001);
bitmap_set_bit(&mut data, 7);
assert_eq!(data[0], 0b10000001);
bitmap_set_bit(&mut data, 8);
assert_eq!(data[1], 0b00000001);
bitmap_set_bit(&mut data, 15);
assert_eq!(data[1], 0b10000001);
}
#[test]
fn test_bitmap_clear_bit() {
let mut data = [0xFF, 0xFF];
bitmap_clear_bit(&mut data, 0);
assert_eq!(data[0], 0b11111110);
bitmap_clear_bit(&mut data, 7);
assert_eq!(data[0], 0b01111110);
bitmap_clear_bit(&mut data, 8);
assert_eq!(data[1], 0b11111110);
}
#[test]
fn test_bitmap_set_clear_roundtrip() {
let mut data = [0u8; 4];
for i in 0..32u64 {
bitmap_set_bit(&mut data, i);
}
assert_eq!(data, [0xFF; 4]);
for i in 0..32u64 {
bitmap_clear_bit(&mut data, i);
}
assert_eq!(data, [0x00; 4]);
}
#[test]
fn test_bitmap_find_clear_bit_basic() {
let data = [0xFF, 0b11111110]; assert_eq!(bitmap_find_clear_bit(&data, 16), Some(8));
}
#[test]
fn test_bitmap_find_clear_bit_first() {
let data = [0b11111110]; assert_eq!(bitmap_find_clear_bit(&data, 8), Some(0));
}
#[test]
fn test_bitmap_find_clear_bit_none() {
let data = [0xFF, 0xFF];
assert_eq!(bitmap_find_clear_bit(&data, 16), None);
}
#[test]
fn test_bitmap_find_clear_bit_partial() {
let data = [0xFF, 0b00001111]; assert_eq!(bitmap_find_clear_bit(&data, 12), None); }
#[test]
fn test_bitmap_find_clear_bit_in_partial() {
let data = [0xFF, 0b11111011]; assert_eq!(bitmap_find_clear_bit(&data, 12), Some(10));
}
}