#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Bitfield {
bits: Vec<u8>,
num_bits: usize,
}
impl Bitfield {
pub fn new(num_bits: usize) -> Self {
let num_bytes = num_bits.div_ceil(8);
Bitfield {
bits: vec![0u8; num_bytes],
num_bits,
}
}
pub fn all_set(num_bits: usize) -> Self {
let num_bytes = num_bits.div_ceil(8);
let mut bits = vec![0xFFu8; num_bytes];
let remaining_bits = num_bits % 8;
if remaining_bits > 0 && num_bytes > 0 {
let mask = ((1u8 << remaining_bits) - 1) << (8 - remaining_bits);
bits[num_bytes - 1] = mask;
}
Bitfield { bits, num_bits }
}
pub fn from_bytes(data: &[u8], num_bits: usize) -> Self {
let num_bytes = num_bits.div_ceil(8);
let mut bits = vec![0u8; num_bytes];
let copy_len = std::cmp::min(data.len(), num_bytes);
if copy_len > 0 {
bits[..copy_len].copy_from_slice(&data[..copy_len]);
}
let remaining_bits = num_bits % 8;
if remaining_bits > 0 && num_bytes > 0 {
let mask = ((1u8 << remaining_bits) - 1) << (8 - remaining_bits);
bits[num_bytes - 1] &= mask;
}
Bitfield { bits, num_bits }
}
pub fn as_bytes(&self) -> &[u8] {
&self.bits
}
pub fn len(&self) -> usize {
self.num_bits
}
pub fn is_empty(&self) -> bool {
self.num_bits == 0
}
pub fn set(&mut self, index: usize) -> Option<()> {
if index >= self.num_bits {
return None;
}
let byte_index = index / 8;
let bit_offset = index % 8;
self.bits[byte_index] |= 1 << (7 - bit_offset);
Some(())
}
pub fn clear(&mut self, index: usize) -> Option<()> {
if index >= self.num_bits {
return None;
}
let byte_index = index / 8;
let bit_offset = index % 8;
self.bits[byte_index] &= !(1 << (7 - bit_offset));
Some(())
}
pub fn test(&self, index: usize) -> bool {
if index >= self.num_bits {
return false;
}
let byte_index = index / 8;
let bit_offset = index % 8;
(self.bits[byte_index] & (1 << (7 - bit_offset))) != 0
}
pub fn count_set(&self) -> usize {
let mut count = 0;
let full_bytes = self.num_bits / 8;
for i in 0..full_bytes {
count += self.bits[i].count_ones() as usize;
}
let remaining_bits = self.num_bits % 8;
if remaining_bits > 0 && full_bytes < self.bits.len() {
let last_byte = self.bits[full_bytes];
for bit in 0..remaining_bits {
if last_byte & (1 << (7 - bit)) != 0 {
count += 1;
}
}
}
count
}
pub fn count_clear(&self) -> usize {
self.num_bits - self.count_set()
}
pub fn is_all_set(&self) -> bool {
self.count_set() == self.num_bits
}
pub fn is_all_clear(&self) -> bool {
self.bits.iter().all(|&b| b == 0)
}
pub fn find_first_set(&self) -> Option<usize> {
for (byte_index, &byte) in self.bits.iter().enumerate() {
if byte != 0 {
for bit_offset in 0..8 {
let index = byte_index * 8 + bit_offset;
if index < self.num_bits && (byte & (1 << (7 - bit_offset))) != 0 {
return Some(index);
}
}
}
}
None
}
pub fn find_first_clear(&self) -> Option<usize> {
for (byte_index, &byte) in self.bits.iter().enumerate() {
let start_bit = byte_index * 8;
let end_bit = std::cmp::min(start_bit + 8, self.num_bits);
for bit_offset in 0..(end_bit - start_bit) {
let index = start_bit + bit_offset;
if (byte & (1 << (7 - bit_offset))) == 0 {
return Some(index);
}
}
}
None
}
pub fn find_next_set(&self, after: usize) -> Option<usize> {
let start = after + 1;
if start >= self.num_bits {
return None;
}
let byte_index = start / 8;
let bit_offset = start % 8;
let byte = self.bits[byte_index];
for bit in bit_offset..8 {
let index = byte_index * 8 + bit;
if index < self.num_bits && (byte & (1 << (7 - bit))) != 0 {
return Some(index);
}
}
for (bi, &b) in self.bits.iter().enumerate().skip(byte_index + 1) {
if b != 0 {
for bit_offset in 0..8 {
let index = bi * 8 + bit_offset;
if index < self.num_bits && (b & (1 << (7 - bit_offset))) != 0 {
return Some(index);
}
}
}
}
None
}
pub fn iter_set(&self) -> SetBitIter<'_> {
SetBitIter::new(self)
}
pub fn iter_clear(&self) -> ClearBitIter<'_> {
ClearBitIter::new(self)
}
pub fn memory_usage(&self) -> usize {
self.bits.len()
}
pub fn vec_bool_memory_usage(&self) -> usize {
self.num_bits
}
pub fn memory_savings_ratio(&self) -> f64 {
if self.bits.is_empty() {
return 1.0;
}
self.num_bits as f64 / self.bits.len() as f64
}
pub fn set_all(&mut self) {
self.bits.fill(0xFF);
let remaining_bits = self.num_bits % 8;
if remaining_bits > 0 && !self.bits.is_empty() {
let mask = ((1u8 << remaining_bits) - 1) << (8 - remaining_bits);
let last_idx = self.bits.len() - 1;
self.bits[last_idx] = mask;
}
}
pub fn clear_all(&mut self) {
self.bits.fill(0);
}
pub fn bitand_assign(&mut self, other: &Bitfield) {
assert_eq!(self.num_bits, other.num_bits, "Bitfield lengths must match");
for (a, b) in self.bits.iter_mut().zip(other.bits.iter()) {
*a &= b;
}
}
pub fn bitor_assign(&mut self, other: &Bitfield) {
assert_eq!(self.num_bits, other.num_bits, "Bitfield lengths must match");
for (a, b) in self.bits.iter_mut().zip(other.bits.iter()) {
*a |= b;
}
}
pub fn bitxor_assign(&mut self, other: &Bitfield) {
assert_eq!(self.num_bits, other.num_bits, "Bitfield lengths must match");
for (a, b) in self.bits.iter_mut().zip(other.bits.iter()) {
*a ^= b;
}
}
}
pub struct SetBitIter<'a> {
bitfield: &'a Bitfield,
current: usize,
}
impl<'a> SetBitIter<'a> {
fn new(bitfield: &'a Bitfield) -> Self {
SetBitIter {
bitfield,
current: 0,
}
}
}
impl<'a> Iterator for SetBitIter<'a> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
while self.current < self.bitfield.num_bits {
if self.bitfield.test(self.current) {
let result = self.current;
self.current += 1;
return Some(result);
}
self.current += 1;
}
None
}
}
pub struct ClearBitIter<'a> {
bitfield: &'a Bitfield,
current: usize,
}
impl<'a> ClearBitIter<'a> {
fn new(bitfield: &'a Bitfield) -> Self {
ClearBitIter {
bitfield,
current: 0,
}
}
}
impl<'a> Iterator for ClearBitIter<'a> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
while self.current < self.bitfield.num_bits {
if !self.bitfield.test(self.current) {
let result = self.current;
self.current += 1;
return Some(result);
}
self.current += 1;
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_bitfield() {
let bf = Bitfield::new(100);
assert_eq!(bf.len(), 100);
assert!(bf.is_all_clear());
assert!(!bf.is_all_set());
assert_eq!(bf.count_set(), 0);
assert_eq!(bf.count_clear(), 100);
}
#[test]
fn test_all_set() {
let bf = Bitfield::all_set(50);
assert_eq!(bf.len(), 50);
assert!(bf.is_all_set());
assert!(!bf.is_all_clear());
assert_eq!(bf.count_set(), 50);
assert_eq!(bf.count_clear(), 0);
}
#[test]
fn test_set_and_test() {
let mut bf = Bitfield::new(10);
assert!(!bf.test(5));
bf.set(5).unwrap();
assert!(bf.test(5));
assert!(!bf.test(4));
assert!(!bf.test(6));
assert!(bf.set(100).is_none());
assert!(!bf.test(100));
}
#[test]
fn test_clear() {
let mut bf = Bitfield::new(10);
bf.set(3).unwrap();
assert!(bf.test(3));
bf.clear(3).unwrap();
assert!(!bf.test(3));
assert!(bf.clear(100).is_none());
}
#[test]
fn test_count_bits() {
let mut bf = Bitfield::new(100);
bf.set(0).unwrap();
bf.set(10).unwrap();
bf.set(50).unwrap();
bf.set(99).unwrap();
assert_eq!(bf.count_set(), 4);
assert_eq!(bf.count_clear(), 96);
}
#[test]
fn test_from_bytes() {
let bf = Bitfield::from_bytes(&[0x81], 8);
assert!(bf.test(0));
assert!(!bf.test(1));
assert!(!bf.test(6));
assert!(bf.test(7));
let bf2 = Bitfield::from_bytes(&[0xFF, 0x00], 16);
assert!(bf2.test(0));
assert!(bf2.test(7));
assert!(!bf2.test(8));
assert!(!bf2.test(15));
}
#[test]
fn test_as_bytes() {
let mut bf = Bitfield::new(16);
bf.set(0).unwrap();
bf.set(7).unwrap();
bf.set(15).unwrap();
let bytes = bf.as_bytes();
assert_eq!(bytes.len(), 2);
assert_eq!(bytes[0], 0x81); assert_eq!(bytes[1], 0x01); }
#[test]
fn test_find_first_set() {
let mut bf = Bitfield::new(100);
assert!(bf.find_first_set().is_none());
bf.set(42).unwrap();
assert_eq!(bf.find_first_set(), Some(42));
bf.set(10).unwrap();
assert_eq!(bf.find_first_set(), Some(10));
}
#[test]
fn test_find_first_clear() {
let bf = Bitfield::new(100);
assert_eq!(bf.find_first_clear(), Some(0));
let bf2 = Bitfield::all_set(50);
assert!(bf2.find_first_clear().is_none());
}
#[test]
fn test_find_next_set() {
let mut bf = Bitfield::new(100);
bf.set(5).unwrap();
bf.set(10).unwrap();
bf.set(20).unwrap();
assert_eq!(bf.find_next_set(0), Some(5));
assert_eq!(bf.find_next_set(5), Some(10));
assert_eq!(bf.find_next_set(10), Some(20));
assert_eq!(bf.find_next_set(20), None);
}
#[test]
fn test_iter_set() {
let mut bf = Bitfield::new(20);
bf.set(1).unwrap();
bf.set(5).unwrap();
bf.set(10).unwrap();
let set_bits: Vec<usize> = bf.iter_set().collect();
assert_eq!(set_bits, vec![1, 5, 10]);
}
#[test]
fn test_iter_clear() {
let mut bf = Bitfield::new(5);
bf.set(1).unwrap();
bf.set(3).unwrap();
let clear_bits: Vec<usize> = bf.iter_clear().collect();
assert_eq!(clear_bits, vec![0, 2, 4]);
}
#[test]
fn test_memory_usage() {
let bf = Bitfield::new(100);
assert_eq!(bf.memory_usage(), 13); assert_eq!(bf.vec_bool_memory_usage(), 100);
let ratio = bf.memory_savings_ratio();
assert!(
ratio > 7.5 && ratio < 8.0,
"Memory savings ratio should be close to 8x"
);
}
#[test]
fn test_large_bitfield() {
let mut bf = Bitfield::new(10_000);
for i in (0..10_000).step_by(100) {
bf.set(i).unwrap();
}
assert_eq!(bf.count_set(), 100);
assert_eq!(bf.count_clear(), 9900);
assert_eq!(bf.memory_usage(), 1250);
assert_eq!(bf.vec_bool_memory_usage(), 10_000);
let ratio = bf.memory_savings_ratio();
assert!(ratio > 7.9, "Should achieve close to 8x memory savings");
}
#[test]
fn test_bitwise_operations() {
let mut bf1 = Bitfield::new(16);
bf1.set(0).unwrap();
bf1.set(1).unwrap();
bf1.set(2).unwrap();
let mut bf2 = Bitfield::new(16);
bf2.set(1).unwrap();
bf2.set(2).unwrap();
bf2.set(3).unwrap();
let mut result = bf1.clone();
result.bitand_assign(&bf2);
assert!(result.test(1));
assert!(result.test(2));
assert!(!result.test(0));
assert!(!result.test(3));
let mut result = bf1.clone();
result.bitor_assign(&bf2);
assert!(result.test(0));
assert!(result.test(1));
assert!(result.test(2));
assert!(result.test(3));
let mut result = bf1.clone();
result.bitxor_assign(&bf2);
assert!(result.test(0));
assert!(!result.test(1));
assert!(!result.test(2));
assert!(result.test(3));
}
#[test]
fn test_set_all_and_clear_all() {
let mut bf = Bitfield::new(100);
bf.set_all();
assert!(bf.is_all_set());
assert_eq!(bf.count_set(), 100);
bf.clear_all();
assert!(bf.is_all_clear());
assert_eq!(bf.count_set(), 0);
}
#[test]
fn test_edge_cases() {
let bf = Bitfield::new(0);
assert!(bf.is_empty());
assert_eq!(bf.count_set(), 0);
let mut bf = Bitfield::new(1);
assert!(!bf.test(0));
bf.set(0).unwrap();
assert!(bf.test(0));
assert!(bf.is_all_set());
let mut bf = Bitfield::new(7);
bf.set(6).unwrap();
assert!(bf.test(6));
assert!(!bf.test(7));
let mut bf = Bitfield::new(8);
bf.set(7).unwrap();
assert!(bf.test(7));
}
#[test]
fn test_roundtrip_bytes() {
let mut bf1 = Bitfield::new(100);
bf1.set(0).unwrap();
bf1.set(50).unwrap();
bf1.set(99).unwrap();
let bytes = bf1.as_bytes().to_vec();
let bf2 = Bitfield::from_bytes(&bytes, 100);
assert_eq!(bf1, bf2);
}
#[test]
fn test_partial_byte_handling() {
let mut bf = Bitfield::new(10);
bf.set(8).unwrap();
bf.set(9).unwrap();
assert!(bf.test(8));
assert!(bf.test(9));
assert_eq!(bf.count_set(), 2);
assert!(!bf.test(10));
let bf2 = Bitfield::from_bytes(&[0x00, 0xC0], 10); assert!(!bf2.test(7));
assert!(bf2.test(8));
assert!(bf2.test(9));
}
}