use crate::lanes::{ByteLanes, ByteRegister};
pub(crate) const LANE_BYTES: usize = 64;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct Model(pub(crate) [u8; LANE_BYTES]);
fn apply(matrix: u64, input: u8) -> u8 {
let rows = matrix.to_le_bytes();
let mut out = 0u8;
for i in 0..8 {
if (rows[7 - i] & input).count_ones() % 2 == 1 {
out |= 1 << i;
}
}
out
}
impl ByteRegister for Model {
const BYTES: usize = LANE_BYTES;
unsafe fn load(from: *const u8) -> Self {
Self(core::array::from_fn(|i| unsafe { *from.add(i) }))
}
unsafe fn store(to: *mut u8, value: Self) {
for (i, byte) in value.0.into_iter().enumerate() {
unsafe { *to.add(i) = byte };
}
}
fn xor(self, other: Self) -> Self {
Self(core::array::from_fn(|i| self.0[i] ^ other.0[i]))
}
}
impl ByteLanes for Model {
fn rotate_group<const GROUP: usize>(self, shift: usize) -> Self {
assert!(shift < GROUP, "rotation leaves the group");
Self(core::array::from_fn(|p| {
let base = p - p % GROUP;
self.0[base + (p % GROUP + shift) % GROUP]
}))
}
fn affine(self, matrix: u64) -> Self {
Self(core::array::from_fn(|i| apply(matrix, self.0[i])))
}
fn affine_merge(self, source: Self, matrix: u64, mask: u64) -> Self {
Self(core::array::from_fn(|i| {
if (mask >> i) & 1 == 1 {
apply(matrix, source.0[i])
} else {
self.0[i]
}
}))
}
}