pub mod dispatch;
#[cfg(feature = "simd")]
pub mod simd;
#[cfg(not(feature = "simd"))]
pub mod std;
use crate::{Bitmask, BitmaskVT};
use core::mem;
pub type Word = u64;
pub const WORD_BITS: usize = mem::size_of::<Word>() * 8;
#[inline(always)]
pub fn words_for(len: usize) -> usize {
(len + WORD_BITS - 1) / WORD_BITS
}
#[inline(always)]
pub unsafe fn mask_bits_as_words(bits: &[u8]) -> *const Word {
bits.as_ptr() as *const Word
}
#[inline(always)]
pub unsafe fn mask_bits_as_words_mut(bits: &mut [u8]) -> *mut Word {
bits.as_mut_ptr() as *mut Word
}
#[inline(always)]
pub fn new_mask(len: usize) -> Bitmask {
Bitmask::new_set_all(len, false)
}
#[inline(always)]
pub fn bitmask_window_bytes(mask: &Bitmask, offset: usize, len: usize) -> &[u8] {
let start = offset / 8;
let end = (offset + len + 7) / 8;
&mask.bits[start..end]
}
#[inline(always)]
pub fn bitmask_window_bytes_mut(mask: &mut Bitmask, offset: usize, len: usize) -> &mut [u8] {
let start = offset / 8;
let end = (offset + len + 7) / 8;
&mut mask.bits[start..end]
}
#[inline(always)]
pub fn clear_trailing_bits(bm: &mut Bitmask) {
if bm.len == 0 {
return;
}
let used = bm.len & 7;
if used != 0 {
let last = bm.bits.last_mut().unwrap();
*last &= (1u8 << used) - 1;
}
}
#[inline(always)]
pub fn popcount_bits(m: BitmaskVT<'_>) -> usize {
#[cfg(feature = "simd")]
{
use crate::kernels::bitmask::simd::popcount_mask_simd;
popcount_mask_simd::<8>(m)
}
#[cfg(not(feature = "simd"))]
{
use crate::kernels::bitmask::std::popcount_mask;
popcount_mask(m)
}
}
#[inline]
pub fn merge_bitmasks_to_new(
lhs: Option<&Bitmask>,
rhs: Option<&Bitmask>,
len: usize,
) -> Option<Bitmask> {
match (lhs, rhs) {
(None, None) => None,
(Some(l), None) | (None, Some(l)) => {
debug_assert!(l.len() >= len, "Bitmask too short in merge");
let mut out = Bitmask::new_set_all(len, true);
for i in 0..len {
out.set(i, l.get(i));
}
Some(out)
}
(Some(l), Some(r)) => {
debug_assert!(l.len() >= len, "Left Bitmask too short in merge");
debug_assert!(r.len() >= len, "Right Bitmask too short in merge");
let mut out = Bitmask::new_set_all(len, true);
for i in 0..len {
out.set(i, l.get(i) && r.get(i));
}
Some(out)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Bitmask;
#[test]
fn test_words_for() {
assert_eq!(words_for(0), 0);
assert_eq!(words_for(1), 1);
assert_eq!(words_for(63), 1);
assert_eq!(words_for(64), 1);
assert_eq!(words_for(65), 2);
assert_eq!(words_for(128), 2);
assert_eq!(words_for(129), 3);
}
#[test]
fn test_mask_bits_as_words_and_mut() {
let mut mask = Bitmask::new_set_all(128, false);
mask.set(0, true);
mask.set(63, true);
mask.set(64, true);
mask.set(127, true);
let bits = &mask.bits;
unsafe {
let words = mask_bits_as_words(bits);
assert_eq!(*words, 1u64 | (1u64 << 63));
assert_eq!(*words.add(1), 1u64 | (1u64 << 63));
}
let mut mask = Bitmask::new_set_all(128, false);
let bits = &mut mask.bits;
unsafe {
let words_mut = mask_bits_as_words_mut(bits);
*words_mut = 0xDEADBEEFDEADBEEF;
*words_mut.add(1) = 0xCAFEBABECAFEBABE;
}
assert_eq!(mask.bits[0], 0xEF);
assert_eq!(mask.bits[7], 0xDE);
assert_eq!(mask.bits[8], 0xBE);
assert_eq!(mask.bits[15], 0xCA);
}
#[test]
fn test_bitmask_window_bytes() {
let mut mask = Bitmask::new_set_all(24, false);
mask.set(0, true);
mask.set(7, true);
mask.set(8, true);
mask.set(15, true);
mask.set(16, true);
mask.set(23, true);
let bytes = bitmask_window_bytes(&mask, 8, 16);
assert_eq!(bytes.len(), 2); assert_eq!(bytes[0], 0b10000001); assert_eq!(bytes[1], 0b10000001); }
#[test]
fn test_bitmask_window_bytes_mut() {
let mut mask = Bitmask::new_set_all(16, false);
{
let window = bitmask_window_bytes_mut(&mut mask, 0, 16);
window[0] = 0xAA;
window[1] = 0x55;
}
assert_eq!(mask.bits[0], 0xAA);
assert_eq!(mask.bits[1], 0x55);
}
#[test]
fn test_clear_trailing_bits() {
let mut mask = Bitmask::new_set_all(10, true);
clear_trailing_bits(&mut mask);
assert_eq!(mask.bits[1], 0x03);
for i in 0..10 {
assert!(mask.get(i));
}
for i in 10..16 {
assert!(!mask.get(i));
}
}
}