use std::num::NonZeroU64;
pub const GROUP_SIZE: usize = 8;
type GroupWord = u64;
type NonZeroGroupWord = NonZeroU64;
pub struct GroupQuery {
eq_mask: GroupWord,
empty_mask: GroupWord,
}
#[inline]
fn repeat(byte: u8) -> GroupWord {
GroupWord::from_ne_bytes([byte; GROUP_SIZE])
}
impl GroupQuery {
#[inline]
pub fn from(group: &[u8; GROUP_SIZE], h2: u8) -> GroupQuery {
let group = GroupWord::from_le_bytes(*group);
let cmp = group ^ repeat(h2);
let high_bit_greater_than_128 = (!cmp) & repeat(0x80);
let high_bit_greater_than_128_or_zero = cmp.wrapping_sub(repeat(0x01));
let eq_mask = high_bit_greater_than_128_or_zero & high_bit_greater_than_128;
let empty_mask = group & repeat(0x80);
GroupQuery {
eq_mask,
empty_mask,
}
}
#[inline]
pub fn any_empty(&self) -> bool {
self.empty_mask != 0
}
#[inline]
pub fn first_empty(&self) -> Option<usize> {
Some((NonZeroGroupWord::new(self.empty_mask)?.trailing_zeros() / 8) as usize)
}
}
impl Iterator for GroupQuery {
type Item = usize;
#[inline]
fn next(&mut self) -> Option<usize> {
let index = NonZeroGroupWord::new(self.eq_mask)?.trailing_zeros() / 8;
self.eq_mask &= self.eq_mask - 1;
Some(index as usize)
}
}