crate::ix!();
#[derive(Getters, Debug)]
pub struct BitPackedAtomicFlags {
#[get = "pub(crate)"]
mem: Box<[AtomicU8]>,
}
impl BitPackedAtomicFlags {
#[inline]
pub fn new(size: u32) -> Self {
trace!(size, "initialising BitPackedAtomicFlags");
let cells = ((size + 7) / 8) as usize;
let boxed: Box<[AtomicU8]> = (0..cells)
.map(|_| AtomicU8::new(0xFF))
.collect::<Vec<_>>()
.into_boxed_slice();
debug!(cells, "allocated atomic byte array");
Self { mem: boxed }
}
#[inline]
pub fn setup(&mut self, b: u32) {
trace!(b, "re‑initialising BitPackedAtomicFlags via setup()");
*self = Self::new(b);
}
#[inline]
pub fn bit_set(&self, s: u32) {
let idx = (s >> 3) as usize;
let mask = 1u8 << (s & 7);
self.mem[idx].fetch_or(mask, atomic::Ordering::Relaxed); trace!(index = s, mask, "bit_set()");
}
#[inline]
pub fn bit_unset(&self, s: u32) {
let idx = (s >> 3) as usize;
let mask = !(1u8 << (s & 7));
self.mem[idx].fetch_and(mask, atomic::Ordering::Relaxed); trace!(index = s, mask, "bit_unset()");
}
#[inline]
pub fn bit_is_set(&self, s: u32) -> bool {
let idx = (s >> 3) as usize;
let mask = 1u8 << (s & 7);
let value = (self.mem[idx].load(atomic::Ordering::Relaxed) & mask) != 0; trace!(index = s, mask, value, "bit_is_set()");
value
}
}
#[cfg(test)]
mod bit_packed_atomic_flags_suite {
use super::*;
fn assert_all_set(flags: &BitPackedAtomicFlags, bits: u32) {
for i in 0..bits {
assert!(
flags.bit_is_set(i),
"bit {i} expected to be set after construction"
);
}
}
#[traced_test]
fn constructor_sets_all_bits() {
let bits = 20;
let flags = BitPackedAtomicFlags::new(bits);
assert_all_set(&flags, bits);
}
#[traced_test]
fn bit_set_and_unset_roundtrip() {
let bits = 16;
let flags = BitPackedAtomicFlags::new(bits);
for i in 0..bits {
flags.bit_unset(i);
assert!(!flags.bit_is_set(i), "bit {i} should be unset");
flags.bit_set(i);
assert!(flags.bit_is_set(i), "bit {i} should be set again");
}
}
#[traced_test]
fn setup_reinitialises_capacity_and_state() {
let mut flags = BitPackedAtomicFlags::new(8);
flags.bit_unset(3);
flags.bit_unset(5);
let new_bits = 40;
flags.setup(new_bits);
assert_all_set(&flags, new_bits);
assert!(
flags.mem().len() >= ((new_bits + 7) / 8) as usize,
"internal capacity did not grow as expected"
);
}
}