use core::mem::MaybeUninit;
#[inline(always)]
pub fn slice_by_8(buf: &[u8], lookup_table: &[[u32; 256]; 8]) -> u32 {
slice_by_8_with_seed(buf, 0, lookup_table)
}
pub fn slice_by_8_with_seed(buf: &[u8], seed: u32, lookup_table: &[[u32; 256]; 8]) -> u32 {
let mut crc = !seed;
let (prefix, shorts, suffix) = unsafe { buf.align_to::<u64>() };
crc = prefix.iter().fold(crc, |acc, byte| {
lookup_table[0][((acc ^ *byte as u32) & 0xff) as usize] ^ (acc >> 8)
});
#[cfg(target_endian = "big")]
let process_8_bytes_at_once = |acc: u32, byte: &u64| {
let byte = *byte;
let (low, high) = (
(byte as u32) ^ acc.reverse_bits(),
(byte >> u32::BITS) as u32,
);
lookup_table[0][(high & 0xFF) as usize]
^ lookup_table[1][((high >> 8) & 0xFF) as usize]
^ lookup_table[2][((high >> 16) & 0xFF) as usize]
^ lookup_table[3][((high >> 24) & 0xFF) as usize]
^ lookup_table[4][(low & 0xFF) as usize]
^ lookup_table[5][((low >> 8) & 0xFF) as usize]
^ lookup_table[6][((low >> 16) & 0xFF) as usize]
^ lookup_table[7][((low >> 24) & 0xFF) as usize]
};
#[cfg(target_endian = "little")]
let process_8_bytes_at_once = |acc: u32, byte: &u64| {
let byte = *byte;
let (low, high) = ((byte as u32) ^ acc, (byte >> u32::BITS) as u32);
lookup_table[0][((high >> 24) & 0xFF) as usize]
^ lookup_table[1][((high >> 16) & 0xFF) as usize]
^ lookup_table[2][((high >> 8) & 0xFF) as usize]
^ lookup_table[3][(high & 0xFF) as usize]
^ lookup_table[4][((low >> 24) & 0xFF) as usize]
^ lookup_table[5][((low >> 16) & 0xFF) as usize]
^ lookup_table[6][((low >> 8) & 0xFF) as usize]
^ lookup_table[7][(low & 0xFF) as usize]
};
crc = shorts.iter().fold(crc, process_8_bytes_at_once);
!suffix.iter().fold(crc, |acc, byte| {
(acc >> 8) ^ lookup_table[0][((acc ^ *byte as u32) & 0xff) as usize]
})
}
pub fn generate_table(polynomial: u32) -> [[u32; 256]; 8] {
let mut generated_lookup_table = MaybeUninit::<[[u32; 256]; 8]>::uninit();
unsafe {
for (i, x) in generated_lookup_table.assume_init_mut()[0]
.iter_mut()
.enumerate()
{
*x = (0..8).fold(i as u32, |acc, _| {
(acc >> 1) ^ ((acc & 1) * polynomial.reverse_bits())
});
}
let table_0 = &generated_lookup_table.assume_init()[0];
for i in 1..=7 {
let table_before = &generated_lookup_table.assume_init()[i - 1];
for (i, x) in generated_lookup_table.assume_init_mut()[i]
.iter_mut()
.enumerate()
{
*x = (table_before[i] >> 8) ^ table_0[(table_before[i] & 0xFF) as usize];
}
}
*generated_lookup_table.assume_init_mut()
}
}
#[cfg(test)]
mod tests {
use crate as slice_by_8;
use slice_by_8::crc32::LOOKUP_TABLE;
#[test]
fn slice_by_8_no_seed() {
const HASH_ME: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
assert_eq!(slice_by_8::slice_by_8(HASH_ME, &LOOKUP_TABLE), 0x4C2750BD);
}
#[test]
fn slice_by_8_with_seed() {
const HASH_ME: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
assert_eq!(
slice_by_8::slice_by_8_with_seed(HASH_ME, 123456789, &LOOKUP_TABLE),
0xEADB5034
);
}
}