#![allow(clippy::indexing_slicing)]
#[cfg(feature = "crc16")]
#[must_use]
pub const fn crc16_table_entry(poly: u16, index: u8) -> u16 {
let mut crc = index as u16;
let mut i: u32 = 0;
while i < 8 {
if crc & 1 != 0 {
crc = (crc >> 1) ^ poly;
} else {
crc >>= 1;
}
i = i.strict_add(1);
}
crc
}
#[cfg(feature = "crc16")]
#[must_use]
pub const fn generate_crc16_tables_8(poly: u16) -> [[u16; 256]; 8] {
let mut tables = [[0u16; 256]; 8];
let mut i = 0u16;
while i < 256 {
tables[0][i as usize] = crc16_table_entry(poly, i as u8);
i = i.strict_add(1);
}
let mut k = 1usize;
while k < 8 {
i = 0;
while i < 256 {
let prev = tables[k - 1][i as usize];
tables[k][i as usize] = tables[0][(prev & 0xFF) as usize] ^ (prev >> 8);
i = i.strict_add(1);
}
k = k.strict_add(1);
}
tables
}
#[cfg(feature = "crc24")]
#[must_use]
pub const fn crc24_table_entry(poly: u32, index: u8) -> u32 {
let poly = poly.strict_shl(8);
let mut crc = (index as u32).strict_shl(24);
let mut i: u32 = 0;
while i < 8 {
if crc & 0x8000_0000 != 0 {
crc = (crc.strict_shl(1)) ^ poly;
} else {
crc = crc.strict_shl(1);
}
i = i.strict_add(1);
}
crc & 0xFFFF_FF00
}
#[cfg(feature = "crc24")]
#[must_use]
pub const fn generate_crc24_tables_8(poly: u32) -> [[u32; 256]; 8] {
let mut tables = [[0u32; 256]; 8];
let mut i = 0u16;
while i < 256 {
tables[0][i as usize] = crc24_table_entry(poly, i as u8);
i = i.strict_add(1);
}
let mut k = 1usize;
while k < 8 {
i = 0;
while i < 256 {
let prev = tables[k - 1][i as usize];
tables[k][i as usize] = tables[0][(prev >> 24) as usize] ^ (prev.strict_shl(8));
i = i.strict_add(1);
}
k = k.strict_add(1);
}
tables
}
#[cfg(feature = "crc32")]
#[must_use]
pub const fn crc32_table_entry(poly: u32, index: u8) -> u32 {
let mut crc = index as u32;
let mut i: u32 = 0;
while i < 8 {
if crc & 1 != 0 {
crc = (crc >> 1) ^ poly;
} else {
crc >>= 1;
}
i = i.strict_add(1);
}
crc
}
#[cfg(all(test, feature = "crc32"))]
#[must_use]
pub const fn generate_crc32_tables_8(poly: u32) -> [[u32; 256]; 8] {
let mut tables = [[0u32; 256]; 8];
let mut i: u16 = 0;
while i < 256 {
tables[0][i as usize] = crc32_table_entry(poly, i as u8);
i = i.strict_add(1);
}
let mut k: usize = 1;
while k < 8 {
i = 0;
while i < 256 {
let prev = tables[k - 1][i as usize];
tables[k][i as usize] = tables[0][(prev & 0xFF) as usize] ^ (prev >> 8);
i = i.strict_add(1);
}
k = k.strict_add(1);
}
tables
}
#[cfg(feature = "crc32")]
#[must_use]
pub const fn generate_crc32_tables_16(poly: u32) -> [[u32; 256]; 16] {
let mut tables = [[0u32; 256]; 16];
let mut i: u16 = 0;
while i < 256 {
tables[0][i as usize] = crc32_table_entry(poly, i as u8);
i = i.strict_add(1);
}
let mut k: usize = 1;
while k < 16 {
i = 0;
while i < 256 {
let prev = tables[k - 1][i as usize];
tables[k][i as usize] = tables[0][(prev & 0xFF) as usize] ^ (prev >> 8);
i = i.strict_add(1);
}
k = k.strict_add(1);
}
tables
}
#[cfg(feature = "crc64")]
#[must_use]
pub const fn crc64_table_entry(poly: u64, index: u8) -> u64 {
let mut crc = index as u64;
let mut i: u32 = 0;
while i < 8 {
if crc & 1 != 0 {
crc = (crc >> 1) ^ poly;
} else {
crc >>= 1;
}
i = i.strict_add(1);
}
crc
}
#[cfg(all(feature = "crc64", any(target_arch = "x86_64", target_arch = "aarch64", test)))]
#[must_use]
pub const fn generate_crc64_tables_8(poly: u64) -> [[u64; 256]; 8] {
let mut tables = [[0u64; 256]; 8];
let mut i = 0u16;
while i < 256 {
tables[0][i as usize] = crc64_table_entry(poly, i as u8);
i = i.strict_add(1);
}
let mut k = 1usize;
while k < 8 {
i = 0;
while i < 256 {
let prev = tables[k - 1][i as usize];
tables[k][i as usize] = tables[0][(prev & 0xFF) as usize] ^ (prev >> 8);
i = i.strict_add(1);
}
k = k.strict_add(1);
}
tables
}
#[cfg(feature = "crc64")]
#[must_use]
pub const fn generate_crc64_tables_16(poly: u64) -> [[u64; 256]; 16] {
let mut tables = [[0u64; 256]; 16];
let mut i = 0u16;
while i < 256 {
tables[0][i as usize] = crc64_table_entry(poly, i as u8);
i = i.strict_add(1);
}
let mut k = 1usize;
while k < 16 {
i = 0;
while i < 256 {
let prev = tables[k - 1][i as usize];
tables[k][i as usize] = tables[0][(prev & 0xFF) as usize] ^ (prev >> 8);
i = i.strict_add(1);
}
k = k.strict_add(1);
}
tables
}
#[cfg(feature = "crc16")]
pub const CRC16_CCITT_POLY: u16 = 0x8408;
#[cfg(feature = "crc16")]
pub const CRC16_IBM_POLY: u16 = 0xA001;
#[cfg(feature = "crc24")]
pub const CRC24_OPENPGP_POLY: u32 = 0x0086_4CFB;
#[cfg(feature = "crc32")]
pub const CRC32_IEEE_POLY: u32 = 0xEDB8_8320;
#[cfg(feature = "crc32")]
pub const CRC32C_POLY: u32 = 0x82F6_3B78;
#[cfg(feature = "crc64")]
pub const CRC64_XZ_POLY: u64 = 0xC96C_5795_D787_0F42;
#[cfg(feature = "crc64")]
pub const CRC64_NVME_POLY: u64 = 0x9A6C_9329_AC4B_C9B5;
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(feature = "crc16")]
fn test_crc16_tables_8_consistency() {
let tables8 = generate_crc16_tables_8(CRC16_CCITT_POLY);
for k in 1..8 {
for i in 0..256 {
let prev = tables8[k - 1][i];
let expected = tables8[0][(prev & 0xFF) as usize] ^ (prev >> 8);
assert_eq!(tables8[k][i], expected);
}
}
}
#[test]
#[cfg(feature = "crc32")]
fn test_crc32_tables_8_consistency() {
let tables = generate_crc32_tables_8(CRC32_IEEE_POLY);
assert_eq!(tables[0][0], 0);
assert_ne!(tables[0][1], 0);
for k in 1..8 {
for i in 0..256 {
let prev = tables[k - 1][i];
let expected = tables[0][(prev & 0xFF) as usize] ^ (prev >> 8);
assert_eq!(tables[k][i], expected);
}
}
}
#[test]
#[cfg(feature = "crc32")]
fn test_crc32_tables_16_consistency() {
let tables = generate_crc32_tables_16(CRC32_IEEE_POLY);
assert_eq!(tables[0][0], 0);
assert_ne!(tables[0][1], 0);
for k in 1..16 {
for i in 0..256 {
let prev = tables[k - 1][i];
let expected = tables[0][(prev & 0xFF) as usize] ^ (prev >> 8);
assert_eq!(tables[k][i], expected);
}
}
}
#[test]
#[cfg(feature = "crc24")]
fn test_crc24_tables_8_consistency() {
let tables8 = generate_crc24_tables_8(CRC24_OPENPGP_POLY);
for k in 1..8 {
for i in 0..256 {
let prev = tables8[k - 1][i];
let expected = tables8[0][(prev >> 24) as usize] ^ (prev << 8);
assert_eq!(tables8[k][i], expected);
assert_eq!(tables8[k][i] & 0xFF, 0);
}
}
}
#[test]
#[cfg(feature = "crc64")]
fn test_crc64_tables_8_consistency() {
let tables = generate_crc64_tables_8(CRC64_XZ_POLY);
assert_eq!(tables[0][0], 0);
assert_ne!(tables[0][1], 0);
for k in 1..8 {
for i in 0..256 {
let prev = tables[k - 1][i];
let expected = tables[0][(prev & 0xFF) as usize] ^ (prev >> 8);
assert_eq!(tables[k][i], expected);
}
}
}
#[test]
#[cfg(feature = "crc64")]
fn test_crc64_tables_16_consistency() {
let tables8 = generate_crc64_tables_8(CRC64_XZ_POLY);
let tables16 = generate_crc64_tables_16(CRC64_XZ_POLY);
assert_eq!(tables16[0][0], 0);
assert_ne!(tables16[0][1], 0);
for k in 0..8 {
assert_eq!(tables16[k], tables8[k]);
}
for k in 1..16 {
for i in 0..256 {
let prev = tables16[k - 1][i];
let expected = tables16[0][(prev & 0xFF) as usize] ^ (prev >> 8);
assert_eq!(tables16[k][i], expected);
}
}
}
#[test]
#[cfg(feature = "crc64")]
fn test_crc64_nvme_tables_consistency() {
let xz = generate_crc64_tables_8(CRC64_XZ_POLY);
let nvme = generate_crc64_tables_8(CRC64_NVME_POLY);
assert_ne!(xz[0], nvme[0]);
}
}