mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 12:07:46 +00:00
cksum: generate CRC table in a const fn (#1744)
This commit is contained in:
parent
d1fc42a7c9
commit
e9adc5067b
2 changed files with 94 additions and 51 deletions
|
@ -1,46 +0,0 @@
|
|||
// This file is part of the uutils coreutils package.
|
||||
//
|
||||
// (c) Alex Lyon <arcterus@mail.com>
|
||||
// (c) Michael Gehring <mg@ebfe.org>
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
const CRC_TABLE_LEN: usize = 256;
|
||||
|
||||
fn main() {
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
|
||||
let mut table = Vec::with_capacity(CRC_TABLE_LEN);
|
||||
for num in 0..CRC_TABLE_LEN {
|
||||
table.push(crc_entry(num as u8) as u32);
|
||||
}
|
||||
let file = File::create(&Path::new(&out_dir).join("crc_table.rs")).unwrap();
|
||||
write!(
|
||||
&file,
|
||||
"#[allow(clippy::unreadable_literal)]\nconst CRC_TABLE: [u32; {}] = {:?};",
|
||||
CRC_TABLE_LEN, table
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn crc_entry(input: u8) -> u32 {
|
||||
let mut crc = (input as u32) << 24;
|
||||
|
||||
for _ in 0..8 {
|
||||
if crc & 0x8000_0000 != 0 {
|
||||
crc <<= 1;
|
||||
crc ^= 0x04c1_1db7;
|
||||
} else {
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
crc
|
||||
}
|
|
@ -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();
|
||||
|
||||
static SYNTAX: &str = "[OPTIONS] [FILE]...";
|
||||
static SUMMARY: &str = "Print CRC and size for each file";
|
||||
static LONG_HELP: &str = "";
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue