use super::{Error, Result};
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct BitTable {
num_rows: usize,
num_bits: usize,
data: Vec<u8>,
}
impl BitTable {
pub fn zeros(num_rows: usize, num_bits: usize) -> BitTable {
BitTable { num_rows, num_bits, data: vec![0; num_rows * num_bits.div_ceil(8)] }
}
pub fn from_packed(num_rows: usize, num_bits: usize, data: Vec<u8>) -> Result<BitTable> {
let stride = num_bits.div_ceil(8);
if stride.checked_mul(num_rows) != Some(data.len()) {
return Err(Error::new(format!("{} bytes is not {num_rows} rows of {num_bits} bits", data.len())));
}
Ok(BitTable { num_rows, num_bits, data })
}
pub fn from_rows<R: AsRef<[bool]>>(num_bits: usize, rows: &[R]) -> Result<BitTable> {
let mut t = BitTable::zeros(rows.len(), num_bits);
for (i, row) in rows.iter().enumerate() {
let row = row.as_ref();
if row.len() != num_bits {
return Err(Error::new(format!("row {i} has {} bits, not {num_bits}", row.len())));
}
for (k, &b) in row.iter().enumerate() {
if b {
t.set(i, k, true);
}
}
}
Ok(t)
}
pub fn num_rows(&self) -> usize {
self.num_rows
}
pub fn num_bits(&self) -> usize {
self.num_bits
}
fn stride(&self) -> usize {
self.num_bits.div_ceil(8)
}
pub fn row_bytes(&self, row: usize) -> &[u8] {
let s = self.stride();
&self.data[row * s..(row + 1) * s]
}
pub fn get(&self, row: usize, bit: usize) -> bool {
assert!(row < self.num_rows && bit < self.num_bits, "bit ({row}, {bit}) is outside a {}×{} table", self.num_rows, self.num_bits);
(self.data[row * self.stride() + bit / 8] >> (bit % 8)) & 1 == 1
}
pub fn set(&mut self, row: usize, bit: usize, value: bool) {
assert!(row < self.num_rows && bit < self.num_bits, "bit ({row}, {bit}) is outside a {}×{} table", self.num_rows, self.num_bits);
let i = row * self.stride() + bit / 8;
if value {
self.data[i] |= 1 << (bit % 8);
} else {
self.data[i] &= !(1 << (bit % 8));
}
}
pub fn ones(&self, row: usize) -> Vec<u32> {
let mut out = Vec::new();
crate::shots::defects_from_b8(self.row_bytes(row), self.num_bits, &mut out);
out
}
pub fn row(&self, row: usize) -> Vec<bool> {
(0..self.num_bits).map(|k| self.get(row, k)).collect()
}
pub fn as_bytes(&self) -> &[u8] {
&self.data
}
pub fn into_bytes(self) -> Vec<u8> {
self.data
}
}