use super::super::add::{read, write};
use super::{AND, AND_NOT, NOT_AND, OR, XOR};
#[inline(always)]
fn op<const OP: u8>(x: u64, y: u64) -> u64 {
match OP {
AND => x & y,
OR => x | y,
XOR => x ^ y,
AND_NOT => x & !y,
_ => {
debug_assert!(OP == NOT_AND);
!x & y
}
}
}
#[inline(always)]
unsafe fn word<const OP: u8, const MIXED: bool>(
x: *const u8,
y: *const u8,
n: usize,
k: usize,
) -> u64 {
unsafe {
let a = u64::from_ne_bytes(read(x.add(k)));
let b = if MIXED {
u64::from_ne_bytes(read(y.add(n - 8 - k))).swap_bytes()
} else {
u64::from_ne_bytes(read(y.add(k)))
};
op::<OP>(a, b)
}
}
#[inline]
pub(super) unsafe fn logic<const OP: u8, const MIXED: bool, const DOWN: bool>(
dst: *mut u8,
x: *const u8,
y: *const u8,
n: usize,
) {
unsafe {
if n >= 8 {
let last = if DOWN { 0 } else { n - 8 };
let w = word::<OP, MIXED>(x, y, n, last);
if DOWN {
let mut k = n;
while k > 8 {
k -= 8;
write(dst.add(k), word::<OP, MIXED>(x, y, n, k).to_ne_bytes());
}
} else {
let mut k = 0;
while k + 8 < n {
write(dst.add(k), word::<OP, MIXED>(x, y, n, k).to_ne_bytes());
k += 8;
}
}
write(dst.add(last), w.to_ne_bytes());
} else {
for i in 0..n {
let k = if DOWN { n - 1 - i } else { i };
let b = if MIXED { *y.add(n - 1 - k) } else { *y.add(k) };
*dst.add(k) = op::<OP>(u64::from(*x.add(k)), u64::from(b)) as u8;
}
}
}
}
#[inline(never)]
pub(super) unsafe fn copy_reversed(dst: *mut u8, src: *const u8, n: usize) {
let mut k = 0;
unsafe {
while k + 8 <= n {
let w = u64::from_ne_bytes(read(src.add(n - 8 - k))).swap_bytes();
write(dst.add(k), w.to_ne_bytes());
k += 8;
}
while k < n {
*dst.add(k) = *src.add(n - 1 - k);
k += 1;
}
}
}
#[inline(never)]
pub(super) unsafe fn count_ones(p: *const u8, n: usize) -> u64 {
let (mut k, mut ones) = (0, 0u64);
unsafe {
while k + 8 <= n {
ones += u64::from(u64::from_ne_bytes(read(p.add(k))).count_ones());
k += 8;
}
while k < n {
ones += u64::from((*p.add(k)).count_ones());
k += 1;
}
}
ones
}