pub trait Mask: Copy + PartialEq + std::fmt::Debug {
fn none() -> Self;
fn first(n: usize) -> Self;
fn has(self, lane: usize) -> bool;
fn insert(&mut self, lane: usize);
fn remove(&mut self, lane: usize);
fn and(self, other: Self) -> Self;
fn or(self, other: Self) -> Self;
fn minus(self, other: Self) -> Self;
fn is_empty(self) -> bool;
}
fn shift(lane: usize) -> u32 {
u32::try_from(lane).unwrap_or(u32::MAX)
}
macro_rules! bits {
($($t:ty),*) => {$(
impl Mask for $t {
fn none() -> Self {
0
}
fn first(n: usize) -> Self {
(1 as $t).checked_shl(shift(n)).map_or(<$t>::MAX, |one| one.wrapping_sub(1))
}
fn has(self, lane: usize) -> bool {
self.checked_shr(shift(lane)).is_some_and(|rest| rest & 1 != 0)
}
fn insert(&mut self, lane: usize) {
if let Some(bit) = (1 as $t).checked_shl(shift(lane)) {
*self |= bit;
}
}
fn remove(&mut self, lane: usize) {
if let Some(bit) = (1 as $t).checked_shl(shift(lane)) {
*self &= !bit;
}
}
fn and(self, other: Self) -> Self {
self & other
}
fn or(self, other: Self) -> Self {
self | other
}
fn minus(self, other: Self) -> Self {
self & !other
}
fn is_empty(self) -> bool {
self == 0
}
}
)*};
}
bits!(u8, u16, u32);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Wide([u64; 16]);
impl Wide {
fn place(lane: usize) -> (usize, u64) {
(lane / 64, 1u64.checked_shl(shift(lane % 64)).unwrap_or(0))
}
fn zip(self, other: Self, combine: impl Fn(u64, u64) -> u64) -> Self {
let mut words = self.0;
for (word, other) in words.iter_mut().zip(other.0) {
*word = combine(*word, other);
}
Wide(words)
}
}
impl Mask for Wide {
fn none() -> Self {
Wide([0; 16])
}
fn first(n: usize) -> Self {
let mut w = [0u64; 16];
for (i, word) in w.iter_mut().enumerate() {
let taken = n.saturating_sub(i.saturating_mul(64));
*word = 1u64
.checked_shl(shift(taken))
.map_or(u64::MAX, |one| one.wrapping_sub(1));
}
Wide(w)
}
fn has(self, lane: usize) -> bool {
let (word, bit) = Self::place(lane);
self.0.get(word).is_some_and(|w| w & bit != 0)
}
fn insert(&mut self, lane: usize) {
let (word, bit) = Self::place(lane);
if let Some(w) = self.0.get_mut(word) {
*w |= bit;
}
}
fn remove(&mut self, lane: usize) {
let (word, bit) = Self::place(lane);
if let Some(w) = self.0.get_mut(word) {
*w &= !bit;
}
}
fn and(self, other: Self) -> Self {
self.zip(other, |a, b| a & b)
}
fn or(self, other: Self) -> Self {
self.zip(other, |a, b| a | b)
}
fn minus(self, other: Self) -> Self {
self.zip(other, |a, b| a & !b)
}
fn is_empty(self) -> bool {
self.0.iter().all(|w| *w == 0)
}
}