use crate::{ALL_ONES, u8x8};
#[allow(non_camel_case_types)]
#[repr(transparent)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct mask8x8 {
pub(crate) n: u64,
}
impl mask8x8 {
pub const ALL_FALSE: Self = Self::new(0);
pub const ALL_TRUE: Self = Self::new(ALL_ONES);
#[inline(always)]
pub const fn from_array(a: [bool; 8]) -> Self {
let a: [u8; 8] = unsafe { core::mem::transmute(a) };
Self {
n: u64::from_ne_bytes(a),
}
}
#[inline(always)]
const fn from_bitmask_raw(mask: u8) -> u64 {
let raw = mask as u64;
(((raw & 0x55) * 0x02040810204081) | ((raw & 0xaa) * 0x02040810204081)) & ALL_ONES
}
#[inline(always)]
pub const fn from_bitmask_le(mask: u8) -> Self {
let raw = Self::from_bitmask_raw(mask).to_le();
Self::new(raw)
}
#[inline(always)]
pub const fn from_bitmask_be(mask: u8) -> Self {
let raw = Self::from_bitmask_raw(mask).to_be();
Self::new(raw)
}
#[inline(always)]
pub(crate) const fn new(n: u64) -> Self {
Self { n }
}
#[inline(always)]
pub const fn to_array(self) -> [bool; 8] {
let u8s = self.n.to_ne_bytes();
unsafe { core::mem::transmute(u8s) }
}
#[inline(always)]
const fn to_bitmask_raw(raw: u64) -> u8 {
const MASK: u64 = 0x0102040810204080;
(raw.wrapping_mul(MASK) >> 56) as u8
}
#[inline(always)]
pub const fn to_bitmask_le(self) -> u8 {
Self::to_bitmask_raw(self.n.to_le())
}
#[inline(always)]
pub const fn to_bitmask_be(self) -> u8 {
Self::to_bitmask_raw(self.n.to_be())
}
#[inline(always)]
pub const fn to_u8x8(self) -> u8x8 {
u8x8::new(self.n)
}
#[inline(always)]
pub const fn to_u8x8_with(self, v: u8) -> u8x8 {
u8x8::new(u8x8::new(self.n).n * u8x8::splat(v).n)
}
#[inline(always)]
pub const fn not(self) -> Self {
Self::new(self.n ^ 0x0101010101010101)
}
#[inline(always)]
pub const fn or(self, other: Self) -> Self {
Self::new(self.n | other.n)
}
#[inline(always)]
pub const fn and(self, other: Self) -> Self {
Self::new(self.n & other.n)
}
#[inline(always)]
pub const fn select(self, true_value: u8, false_value: u8) -> u8x8 {
let true_value = u8x8::splat(true_value).n;
let false_value = u8x8::splat(false_value).n;
let mask = self.n * 0xff;
u8x8::new((true_value & mask) | (false_value & !mask))
}
#[inline(always)]
pub const fn count_true(self) -> u32 {
self.to_u8x8().reduce_sum() as u32
}
#[inline(always)]
pub const fn count_false(self) -> u32 {
8 - self.n.count_ones()
}
}
impl core::fmt::Debug for mask8x8 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("mask8x8").field(&self.to_array()).finish()
}
}
impl core::ops::Not for mask8x8 {
type Output = Self;
#[inline(always)]
fn not(self) -> Self {
self.not()
}
}
impl core::ops::BitOr for mask8x8 {
type Output = Self;
#[inline(always)]
fn bitor(self, rhs: Self) -> Self {
self.or(rhs)
}
}
impl core::ops::BitOrAssign for mask8x8 {
#[inline(always)]
fn bitor_assign(&mut self, rhs: Self) {
*self = self.or(rhs);
}
}
impl core::ops::BitAnd for mask8x8 {
type Output = Self;
#[inline(always)]
fn bitand(self, rhs: Self) -> Self {
self.and(rhs)
}
}
impl core::ops::BitAndAssign for mask8x8 {
#[inline(always)]
fn bitand_assign(&mut self, rhs: Self) {
*self = self.and(rhs);
}
}