crc32c/
sw.rs

1//! Implements crc32c without hardware support.
2
3use crate::util::{self, U64Le};
4
5/// 8-KiB lookup table.
6pub struct CrcTable([[u32; 256]; 8]);
7
8impl CrcTable {
9    /// Returns an entry from the table.
10    #[inline]
11    pub fn at(&self, i: u8, j: u8) -> u64 {
12        let i = i as usize;
13        let j = j as usize;
14        u64::from(self.0[i][j])
15    }
16}
17
18const CRC_TABLE: CrcTable = CrcTable(include!(concat!(env!("OUT_DIR"), "/", "sw.table")));
19
20/// Software implementation of the algorithm.
21pub fn crc32c(crci: u32, buffer: &[u8]) -> u32 {
22    let mut crc = u64::from(!crci);
23
24    let (start, mid, end) = util::split(buffer);
25
26    crc = crc_u8(crc, start);
27
28    crc = crc_u64(crc, mid);
29
30    crc = crc_u8(crc, end);
31
32    !(crc as u32)
33}
34
35#[inline]
36fn crc_u8(crc: u64, buffer: &[u8]) -> u64 {
37    buffer.iter().fold(crc, |crc, &next| {
38        let index = (crc ^ u64::from(next)) as u8;
39        CRC_TABLE.at(0, index) ^ (crc >> 8)
40    })
41}
42
43#[inline]
44fn crc_u64(crci: u64, buffer: &[U64Le]) -> u64 {
45    buffer.iter().fold(crci, |crc, &next| {
46        let crc = crc ^ next.get();
47
48        // Note: I've tried refactoring this to a for-loop,
49        // but then it gets worse performance.
50        CRC_TABLE.at(7, crc as u8)
51            ^ CRC_TABLE.at(6, (crc >> 8) as u8)
52            ^ CRC_TABLE.at(5, (crc >> 16) as u8)
53            ^ CRC_TABLE.at(4, (crc >> 24) as u8)
54            ^ CRC_TABLE.at(3, (crc >> 32) as u8)
55            ^ CRC_TABLE.at(2, (crc >> 40) as u8)
56            ^ CRC_TABLE.at(1, (crc >> 48) as u8)
57            ^ CRC_TABLE.at(0, (crc >> 56) as u8)
58    })
59}