Skip to content

Commit

Permalink
cksum: generate CRC table in a const fn (#1744)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arcterus authored Mar 20, 2021
1 parent d1fc42a commit e9adc50
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 51 deletions.
46 changes: 0 additions & 46 deletions src/uu/cksum/build.rs

This file was deleted.

99 changes: 94 additions & 5 deletions src/uu/cksum/src/cksum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,101 @@ use std::fs::File;
use std::io::{self, stdin, BufReader, Read};
use std::path::Path;

include!(concat!(env!("OUT_DIR"), "/crc_table.rs"));
// NOTE: CRC_TABLE_LEN *must* be <= 256 as we cast 0..CRC_TABLE_LEN to u8
const CRC_TABLE_LEN: usize = 256;
const CRC_TABLE: [u32; CRC_TABLE_LEN] = generate_crc_table();

const SYNTAX: &str = "[OPTIONS] [FILE]...";
const SUMMARY: &str = "Print CRC and size for each file";
const LONG_HELP: &str = "";

// this is basically a hack to get "loops" to work on Rust 1.33. Once we update to Rust 1.46 or
// greater, we can just use while loops
macro_rules! unroll {
(256, |$i:ident| $s:expr) => {{
unroll!(@ 32, 0 * 32, $i, $s);
unroll!(@ 32, 1 * 32, $i, $s);
unroll!(@ 32, 2 * 32, $i, $s);
unroll!(@ 32, 3 * 32, $i, $s);
unroll!(@ 32, 4 * 32, $i, $s);
unroll!(@ 32, 5 * 32, $i, $s);
unroll!(@ 32, 6 * 32, $i, $s);
unroll!(@ 32, 7 * 32, $i, $s);
}};
(8, |$i:ident| $s:expr) => {{
unroll!(@ 8, 0, $i, $s);
}};

(@ 32, $start:expr, $i:ident, $s:expr) => {{
unroll!(@ 8, $start + 0 * 8, $i, $s);
unroll!(@ 8, $start + 1 * 8, $i, $s);
unroll!(@ 8, $start + 2 * 8, $i, $s);
unroll!(@ 8, $start + 3 * 8, $i, $s);
}};
(@ 8, $start:expr, $i:ident, $s:expr) => {{
unroll!(@ 4, $start, $i, $s);
unroll!(@ 4, $start + 4, $i, $s);
}};
(@ 4, $start:expr, $i:ident, $s:expr) => {{
unroll!(@ 2, $start, $i, $s);
unroll!(@ 2, $start + 2, $i, $s);
}};
(@ 2, $start:expr, $i:ident, $s:expr) => {{
unroll!(@ 1, $start, $i, $s);
unroll!(@ 1, $start + 1, $i, $s);
}};
(@ 1, $start:expr, $i:ident, $s:expr) => {{
let $i = $start;
let _ = $s;
}};
}

const fn generate_crc_table() -> [u32; CRC_TABLE_LEN] {
let mut table = [0; CRC_TABLE_LEN];

// NOTE: works on Rust 1.46
//let mut i = 0;
//while i < CRC_TABLE_LEN {
// table[i] = crc_entry(i as u8) as u32;
//
// i += 1;
//}
unroll!(256, |i| {
table[i] = crc_entry(i as u8) as u32;
});

table
}

static SYNTAX: &str = "[OPTIONS] [FILE]...";
static SUMMARY: &str = "Print CRC and size for each file";
static LONG_HELP: &str = "";
const fn crc_entry(input: u8) -> u32 {
let mut crc = (input as u32) << 24;

// NOTE: this does not work on Rust 1.33, but *does* on 1.46
//let mut i = 0;
//while i < 8 {
// if crc & 0x8000_0000 != 0 {
// crc <<= 1;
// crc ^= 0x04c1_1db7;
// } else {
// crc <<= 1;
// }
//
// i += 1;
//}
unroll!(8, |_i| {
let if_cond = crc & 0x8000_0000;
let if_body = (crc << 1) ^ 0x04c1_1db7;
let else_body = crc << 1;

// NOTE: i feel like this is easier to understand than emulating an if statement in bitwise
// ops
let cond_table = [else_body, if_body];

crc = cond_table[(if_cond != 0) as usize];
});

crc
}

#[inline]
fn crc_update(crc: u32, input: u8) -> u32 {
Expand Down Expand Up @@ -68,7 +158,6 @@ fn cksum(fname: &str) -> io::Result<(u32, usize)> {
Err(err) => return Err(err),
}
}
//Ok((0 as u32,0 as usize))
}

pub fn uumain(args: impl uucore::Args) -> i32 {
Expand Down

0 comments on commit e9adc50

Please sign in to comment.