use std::mem::MaybeUninit;
use std::ops::Deref;
pub const REG_PK: usize = 0;
pub const REG_WEIGHT: usize = 1;
pub const REG_NULL_BMP: usize = 2;
pub const REG_PAYLOAD_START: usize = REG_NULL_BMP + 1;
pub const fn num_regions(num_payload_cols: usize) -> usize {
REG_PAYLOAD_START + num_payload_cols + 1
}
pub const MAX_WIRE_REGIONS: usize = num_regions(crate::MAX_COLUMNS);
pub struct Regions<'a> {
slots: [MaybeUninit<&'a [u8]>; MAX_WIRE_REGIONS],
len: usize,
}
impl<'a> Regions<'a> {
pub const fn new() -> Self {
Regions {
slots: [const { MaybeUninit::uninit() }; MAX_WIRE_REGIONS],
len: 0,
}
}
pub fn push(&mut self, region: &'a [u8]) {
self.slots[self.len].write(region);
self.len += 1;
}
}
impl Default for Regions<'_> {
fn default() -> Self {
Self::new()
}
}
impl<'a> Deref for Regions<'a> {
type Target = [&'a [u8]];
fn deref(&self) -> &Self::Target {
unsafe { std::slice::from_raw_parts(self.slots.as_ptr().cast(), self.len) }
}
}
#[inline(always)]
pub fn null_word_get(word: u64, pi: usize) -> bool {
(word >> pi) & 1 == 1
}
#[inline(always)]
pub fn null_word_set(word: &mut u64, pi: usize, is_null: bool) {
if is_null {
*word |= 1u64 << pi;
} else {
*word &= !(1u64 << pi);
}
}
pub fn first_not_null_violation(not_null: u64, null_bmp: &[u8]) -> Option<(usize, usize)> {
let words = null_bmp.as_chunks::<8>().0;
if not_null == 0 || words.iter().fold(0u64, |a, w| a | u64::from_le_bytes(*w)) & not_null == 0 {
return None;
}
words.iter().enumerate().find_map(|(row, w)| {
let bad = u64::from_le_bytes(*w) & not_null;
(bad != 0).then(|| (row, bad.trailing_zeros() as usize))
})
}
pub fn first_valued_null<'a>(
nullable: u64,
null_bmp: &[u8],
col: impl Fn(usize) -> (&'a [u8], usize),
) -> Option<(usize, usize)> {
for (row, word) in null_bmp.as_chunks::<8>().0.iter().enumerate() {
let mut set = u64::from_le_bytes(*word) & nullable;
while set != 0 {
let slot = set.trailing_zeros() as usize;
set &= set - 1;
let (cells, width) = col(slot);
if cells[row * width..(row + 1) * width].iter().any(|&b| b != 0) {
return Some((row, slot));
}
}
}
None
}
#[inline(always)]
pub fn null_word_at(word: u64, at: usize) -> u64 {
if at < 64 {
word << at
} else {
0
}
}
#[cfg(test)]
#[path = "tests/region.rs"]
mod tests;