#[repr(align(64))]
#[derive(Default)]
pub struct BitBlock {
pub data: [u64; 8], }
impl BitBlock {
#[inline(always)]
pub fn is_full(&self) -> bool {
#[cfg(all(target_arch = "x86_64", target_feature = "avx512f"))]
unsafe {
self.is_full_x86_512()
}
#[cfg(all(
target_arch = "x86_64",
target_feature = "avx2",
not(target_feature = "avx512f")
))]
unsafe {
self.is_full_x86_256()
}
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
unsafe {
self.is_full_arm_neon()
}
#[cfg(not(any(
all(target_arch = "x86_64", target_feature = "avx512f"),
all(target_arch = "x86_64", target_feature = "avx2"),
all(target_arch = "aarch64", target_feature = "neon")
)))]
{
self.data.iter().all(|&x| x == u64::MAX)
}
}
#[cfg(all(target_arch = "x86_64", target_feature = "avx512f"))]
#[target_feature(enable = "avx512f")]
unsafe fn is_full_x86_512(&self) -> bool {
use std::arch::x86_64::*;
unsafe {
let data = _mm512_load_si512(self.data.as_ptr() as *const __m512i);
let full = _mm512_set1_epi64(-1);
let mask = _mm512_cmpeq_epu64_mask(data, full);
mask == 0xFF
}
}
#[cfg(all(
target_arch = "x86_64",
target_feature = "avx2",
not(target_feature = "avx512f")
))]
#[target_feature(enable = "avx2")]
unsafe fn is_full_x86_256(&self) -> bool {
use std::arch::x86_64::*;
let ptr = self.data.as_ptr() as *const __m256i;
let full = _mm256_set1_epi64x(-1);
unsafe {
let res1 = _mm256_testc_si256(_mm256_load_si256(ptr), full);
let res2 = _mm256_testc_si256(_mm256_load_si256(ptr.add(1)), full);
(res1 != 0) && (res2 != 0)
}
}
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
#[target_feature(enable = "neon")]
unsafe fn is_full_arm_neon(&self) -> bool {
use std::arch::aarch64::*;
let ptr = self.data.as_ptr();
let v1 = vld1q_u64(ptr); let v2 = vld1q_u64(ptr.add(2)); let v3 = vld1q_u64(ptr.add(4)); let v4 = vld1q_u64(ptr.add(6));
let res = vandq_u64(vandq_u64(v1, v2), vandq_u64(v3, v4));
vgetq_lane_u64(res, 0) == u64::MAX && vgetq_lane_u64(res, 1) == u64::MAX
}
}
impl BitBlock {
#[inline(always)]
pub fn find_first_free(&self) -> Option<usize> {
#[cfg(all(target_arch = "x86_64", target_feature = "avx512f"))]
unsafe {
self.find_x86_512()
}
#[cfg(all(
target_arch = "x86_64",
target_feature = "avx2",
not(target_feature = "avx512f")
))]
unsafe {
self.find_x86_256()
}
#[cfg(not(any(
all(target_arch = "x86_64", target_feature = "avx512f"),
all(target_arch = "x86_64", target_feature = "avx2")
)))]
{
for (i, &word) in self.data.iter().enumerate() {
if word != u64::MAX {
let bit_idx = (!word).trailing_zeros() as usize;
return Some(i * 64 + bit_idx);
}
}
None
}
}
#[cfg(all(target_arch = "x86_64", target_feature = "avx512f"))]
unsafe fn find_x86_512(&self) -> Option<usize> {
use std::arch::x86_64::*;
unsafe {
let data = _mm512_load_si512(self.data.as_ptr() as *const __m512i);
let full = _mm512_set1_epi64(-1);
let mask = _mm512_cmpneq_epu64_mask(data, full);
if mask == 0 {
return None;
}
let u64_idx = mask.trailing_zeros() as usize;
let word = *self.data.get_unchecked(u64_idx);
let bit_idx = (!word).trailing_zeros() as usize;
Some(u64_idx * 64 + bit_idx)
}
}
#[cfg(all(
target_arch = "x86_64",
target_feature = "avx2",
not(target_feature = "avx512f")
))]
unsafe fn find_x86_256(&self) -> Option<usize> {
use std::arch::x86_64::*;
let ptr = self.data.as_ptr() as *const __m256i;
unsafe {
let full = _mm256_set1_epi64x(-1);
for i in 0..2 {
let chunk = _mm256_load_si256(ptr.add(i));
if _mm256_testc_si256(chunk, full) == 0 {
for j in (i * 4)..(i * 4 + 4) {
let word = *self.data.get_unchecked(j);
if word != u64::MAX {
return Some(j * 64 + (!word).trailing_zeros() as usize);
}
}
}
}
None
}
}
}
impl BitBlock {
#[inline(always)]
pub fn set_bit_and_check_full(&mut self, bit_idx: usize) -> bool {
debug_assert!(bit_idx < 512);
let word_idx = bit_idx >> 6;
let bit = bit_idx & 63;
unsafe {
let word = self.data.get_unchecked_mut(word_idx);
*word |= 1 << bit;
if *word != u64::MAX {
return false;
}
}
self.is_full()
}
#[inline(always)]
pub fn clear_bit_and_was_full(&mut self, bit_idx: usize) -> bool {
debug_assert!(bit_idx < 512);
let word_idx = bit_idx >> 6;
let bit = bit_idx & 63;
let was_full = self.is_full();
unsafe {
let word = self.data.get_unchecked_mut(word_idx);
let bit_mask = 1 << bit;
*word &= !bit_mask;
}
was_full
}
#[inline(always)]
pub fn is_set(&self,bit_idx:usize)->bool{
debug_assert!(bit_idx < 512);
let word_idx = bit_idx >> 6;
let word = self.data[word_idx];
let mask =1<<(bit_idx&63);
word&mask!=0
}
}