use std::ops::Index;
use std::vec::Vec;
type BitArrayAtom = u64;
const BIT_ARRAY_BITS_IN_ATOM: usize = 64;
#[derive(Clone)]
pub struct BitArray {
array: Vec<BitArrayAtom>,
bit_count: usize,
number_of_bits_set: usize,
}
impl BitArray {
#[must_use]
pub fn new(bit_count: usize) -> Self {
assert_ne!(bit_count, 0, "bit_count must be greater than zero");
let atom_count = bit_count.div_ceil(BIT_ARRAY_BITS_IN_ATOM);
let array = vec![0; atom_count];
Self {
array,
bit_count,
number_of_bits_set: 0,
}
}
pub fn reset(&mut self) {
self.array.fill(0);
self.number_of_bits_set = 0;
}
#[inline]
#[must_use]
pub const fn all_set(&self) -> bool {
self.bit_count == self.number_of_bits_set
}
#[must_use]
pub fn first_unset_bit(&self) -> Option<usize> {
for (i, &atom) in self.array.iter().enumerate() {
if atom != u64::MAX {
return (0..BIT_ARRAY_BITS_IN_ATOM).find_map(|bit| {
if atom & (1 << bit) == 0 {
Some(i * BIT_ARRAY_BITS_IN_ATOM + bit)
} else {
None
}
});
}
}
None
}
#[must_use]
pub fn first_set_bit(&self) -> Option<usize> {
for (i, &atom) in self.array.iter().enumerate() {
if atom != 0 {
return (0..BIT_ARRAY_BITS_IN_ATOM).find_map(|bit| {
if atom & (1 << bit) != 0 {
Some(i * BIT_ARRAY_BITS_IN_ATOM + bit)
} else {
None
}
});
}
}
None
}
#[inline]
#[must_use]
pub const fn count_set_bits(&self) -> usize {
self.number_of_bits_set
}
#[inline]
#[must_use]
pub const fn bit_count(&self) -> usize {
self.bit_count
}
#[inline]
pub fn set(&mut self, index: usize) {
assert!(index < self.bit_count, "Index out of bounds");
let array_index = index / BIT_ARRAY_BITS_IN_ATOM;
let bit_index = index % BIT_ARRAY_BITS_IN_ATOM;
let mask = 1 << bit_index;
if self.array[array_index] & mask == 0 {
self.number_of_bits_set += 1;
}
self.array[array_index] |= mask;
}
#[inline]
pub fn unset(&mut self, index: usize) {
assert!(index < self.bit_count, "Index out of bounds");
let array_index = index / BIT_ARRAY_BITS_IN_ATOM;
let bit_index = index % BIT_ARRAY_BITS_IN_ATOM;
let mask = 1 << bit_index;
if self.array[array_index] & mask != 0 {
self.number_of_bits_set -= 1;
}
self.array[array_index] &= !mask;
}
pub fn set_bit(&mut self, index: usize, set: bool) {
assert!(index < self.bit_count, "Index out of bounds");
let array_index = index / BIT_ARRAY_BITS_IN_ATOM;
let bit_index = index % BIT_ARRAY_BITS_IN_ATOM;
let mask = 1 << bit_index;
if set {
if self.array[array_index] & mask == 0 {
self.number_of_bits_set += 1;
}
self.array[array_index] |= mask;
} else {
if self.array[array_index] & mask != 0 {
self.number_of_bits_set -= 1;
}
self.array[array_index] &= !mask;
}
}
#[must_use]
pub fn atom_from_index(&self, from_index: usize) -> BitArrayAtom {
let mut result: u64 = 0;
for i in 0..BIT_ARRAY_BITS_IN_ATOM {
let index = from_index + (BIT_ARRAY_BITS_IN_ATOM - 1) - i;
result <<= 1;
if index < self.bit_count {
result |= u64::from(self.get(index));
}
}
result
}
#[must_use]
pub fn get(&self, index: usize) -> bool {
assert!(index < self.bit_count, "Index out of bounds");
let array_index = index / BIT_ARRAY_BITS_IN_ATOM;
let bit_index = index % BIT_ARRAY_BITS_IN_ATOM;
((self.array[array_index] >> bit_index) & 0x1) != 0
}
}
impl Index<usize> for BitArray {
type Output = bool;
fn index(&self, index: usize) -> &Self::Output {
if self.get(index) {
&true
} else {
&false
}
}
}
impl std::fmt::Debug for BitArray {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for i in 0..self.bit_count {
if i > 0 && i % 8 == 0 {
write!(f, " ")?;
}
write!(f, "{}", u8::from(self.get(i)))?;
}
Ok(())
}
}
impl std::fmt::Display for BitArray {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for i in 0..self.bit_count {
write!(f, "{}", u8::from(self.get(i)))?;
}
Ok(())
}
}