use super::kernel_tables;
use crate::checksum::common::portable;
#[cfg_attr(miri, allow(dead_code))]
#[inline]
#[cfg(all(test, any(target_arch = "x86_64", target_arch = "aarch64")))]
pub fn crc64_slice8_xz(crc: u64, data: &[u8]) -> u64 {
crc64_slice8(crc, data, &kernel_tables::XZ_TABLES_8)
}
#[cfg_attr(miri, allow(dead_code))]
#[inline]
#[cfg(all(test, any(target_arch = "x86_64", target_arch = "aarch64")))]
pub fn crc64_slice8_nvme(crc: u64, data: &[u8]) -> u64 {
crc64_slice8(crc, data, &kernel_tables::NVME_TABLES_8)
}
#[inline]
pub fn crc64_slice16_xz(crc: u64, data: &[u8]) -> u64 {
crc64_slice16(crc, data, &kernel_tables::XZ_TABLES_16)
}
#[inline]
pub fn crc64_slice16_nvme(crc: u64, data: &[u8]) -> u64 {
crc64_slice16(crc, data, &kernel_tables::NVME_TABLES_16)
}
#[inline(always)]
pub fn crc64_xz_bytewise(crc: u64, data: &[u8]) -> u64 {
crc64_bytewise(crc, data, &kernel_tables::XZ_TABLES_16[0])
}
#[inline(always)]
pub fn crc64_nvme_bytewise(crc: u64, data: &[u8]) -> u64 {
crc64_bytewise(crc, data, &kernel_tables::NVME_TABLES_16[0])
}
#[inline(always)]
#[allow(clippy::indexing_slicing)] fn crc64_bytewise(mut crc: u64, data: &[u8], table: &[u64; 256]) -> u64 {
for &b in data {
let index = ((crc ^ (b as u64)) & 0xFF) as usize;
crc = table[index] ^ (crc >> 8);
}
crc
}
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
#[inline]
pub fn crc64_slice8(crc: u64, data: &[u8], tables: &[[u64; 256]; 8]) -> u64 {
portable::slice8_64(crc, data, tables)
}
#[inline]
pub fn crc64_slice16(crc: u64, data: &[u8], tables: &[[u64; 256]; 16]) -> u64 {
portable::slice16_64(crc, data, tables)
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
use crate::checksum::common::tables::generate_crc64_tables_8;
use crate::checksum::common::tables::{CRC64_XZ_POLY, generate_crc64_tables_16};
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
#[test]
fn test_slice8_empty() {
let tables = generate_crc64_tables_8(CRC64_XZ_POLY);
let crc = crc64_slice8(!0, &[], &tables);
assert_eq!(crc, !0);
}
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
#[test]
fn test_slice8_consistency_with_byte_at_a_time() {
let tables = generate_crc64_tables_8(CRC64_XZ_POLY);
let data = b"The quick brown fox jumps over the lazy dog";
let slice8_result = crc64_slice8(!0, data, &tables);
let mut byte_result = !0u64;
for &b in data.iter() {
let index = ((byte_result ^ (b as u64)) & 0xFF) as usize;
byte_result = tables[0][index] ^ (byte_result >> 8);
}
assert_eq!(slice8_result, byte_result);
}
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
#[test]
fn test_slice8_incremental() {
let tables = generate_crc64_tables_8(CRC64_XZ_POLY);
let data = b"hello world, this is a longer test string";
let full = crc64_slice8(!0, data, &tables);
for split in [1, 7, 8, 9, 15, 16, 17, 20] {
if split < data.len() {
let crc1 = crc64_slice8(!0, &data[..split], &tables);
let crc2 = crc64_slice8(crc1, &data[split..], &tables);
assert_eq!(crc2, full, "Incremental failed at split {split}");
}
}
}
#[test]
fn test_slice16_empty() {
let tables = generate_crc64_tables_16(CRC64_XZ_POLY);
let crc = crc64_slice16(!0, &[], &tables);
assert_eq!(crc, !0);
}
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
#[test]
fn test_slice16_matches_slice8() {
let tables8 = generate_crc64_tables_8(CRC64_XZ_POLY);
let tables16 = generate_crc64_tables_16(CRC64_XZ_POLY);
let data = b"The quick brown fox jumps over the lazy dog";
let a = crc64_slice8(!0, data, &tables8);
let b = crc64_slice16(!0, data, &tables16);
assert_eq!(a, b);
}
#[test]
fn test_slice16_incremental() {
let tables = generate_crc64_tables_16(CRC64_XZ_POLY);
let data = b"hello world, this is a longer test string";
let full = crc64_slice16(!0, data, &tables);
for split in [1, 7, 8, 9, 15, 16, 17, 20] {
if split < data.len() {
let crc1 = crc64_slice16(!0, &data[..split], &tables);
let crc2 = crc64_slice16(crc1, &data[split..], &tables);
assert_eq!(crc2, full, "Incremental failed at split {split}");
}
}
}
}