use std::{fmt::Debug, mem::size_of};
mod bitref;
use bitref::{BitRef, BitRefMut};
pub mod bititer;
pub use bititer::*;
use num_traits::{PrimInt, Unsigned};
#[derive(Default)]
pub struct CompactBitset<T: PrimInt + Unsigned> {
data: T,
}
impl<'parent, T: PrimInt + Unsigned> CompactBitset<T> {
pub const BITS: usize = size_of::<T>() * 8;
pub fn new() -> Self {
Self {
data: T::from(0).unwrap(),
}
}
pub fn from_slice<const N: usize>(slice: [bool; N]) -> Self {
assert_eq!(
N,
Self::BITS,
"Slice and bitset are different sizes: expected slice of length {}, got {}",
Self::BITS,
N
);
let mut bitset = Self::new();
for (idx, item) in slice.iter().enumerate() {
bitset.at_mut(idx).set(*item);
}
bitset
}
pub fn iter<'this>(&'this self) -> BitIter<'this, T> {
BitIter { bitref: self.at(0) }
}
pub fn to_vec(&self) -> Vec<bool> {
self.iter().collect()
}
pub const fn len(&self) -> usize {
Self::BITS
}
pub fn at<'this>(&'this self, index: usize) -> BitRef<'this, T> {
assert!(index < Self::BITS);
BitRef::<'this, T> {
parent: self,
idx: index,
}
}
pub fn at_mut<'this>(&'this mut self, index: usize) -> BitRefMut<'this, T> {
assert!(index < Self::BITS);
BitRefMut::<'this, T> {
parent: self,
idx: index,
}
}
pub fn set_at(&mut self, index: usize, value: bool) {
self.at_mut(index).set(value);
}
}
impl<T: PrimInt + Unsigned> PartialEq for CompactBitset<T> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.data == other.data
}
}
impl<T: PrimInt + Unsigned> Debug for CompactBitset<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut string = String::new();
for item in self.iter() {
string.push_str(format!("{}, ", *item).as_str());
}
string.remove(string.len() - 1);
string.remove(string.len() - 1);
write!(f, "CompactBitset([{string}])")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn creation() {
let bitset = CompactBitset::<u8>::new();
assert_eq!(bitset.at(0), false);
}
#[test]
fn alteration() {
let mut bitset = CompactBitset::<u8>::new();
bitset.at_mut(3).set(true);
println!("set at 3:");
assert_eq!(*bitset.at(3), true);
}
#[test]
#[should_panic]
fn out_of_bounds() {
let mut bitset = CompactBitset::<u16>::new();
bitset.at_mut(16).set(true);
}
#[test]
fn stored_bitref() {
let mut bitset = CompactBitset::<u32>::new();
bitset.at_mut(2).set(true);
assert_eq!(bitset.at(2), true);
}
#[test]
fn iter_zip_map() {
let alternating =
CompactBitset::<u8>::from_slice([true, false, true, false, true, false, true, false]);
let alternating_double =
CompactBitset::<u8>::from_slice([true, true, false, false, true, true, false, false]);
let anded: CompactBitset<u8> = alternating
.iter()
.zip(alternating_double.iter())
.map(|(a, b)| *a & *b)
.collect();
assert_eq!(
anded,
CompactBitset::<u8>::from_slice([true, false, false, false, true, false, false, false])
);
}
#[test]
fn iter_next() {
let alternating =
CompactBitset::<u8>::from_slice([true, false, true, false, true, false, true, false]);
let mut iter = alternating.iter().enumerate();
let mut final_i = 0;
while let Some((i, b)) = iter.next() {
assert_eq!(b, (i % 2) == 0);
final_i = i;
}
assert_eq!(final_i, alternating.len() - 1);
assert!(iter.next().is_none());
assert!(iter.next().is_none());
}
}