diff --git a/Cargo.toml b/Cargo.toml index 859745c..a0e8e86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,17 @@ keywords = ["crc", "crc16", "crc32", "crc64", "hash"] categories = ["algorithms", "no-std"] edition = "2018" +[features] +# use the "NoTable" implementation for the default Crc struct, using no additional memory for a lookup table. +# Takes predence over "bytewise-mem-limit" and "slice16-mem-limit" +no-table-mem-limit = [] +# use the "Bytewise" implementation for the default Crc struct, using 256 entries of the respective width for a lookup table. +# Takes predence over "slice16-mem-limit" and is used if no feature is selected +bytewise-mem-limit = [] +# use the "Slice16" implementation for the default Crc struct, using 256 * 16 entries of the respective width for a lookup table. +# Can be overriden by setting "bytewise-mem-limit" and "slice16-mem-limit" +slice16-mem-limit = [] + [dependencies] crc-catalog = "2.1.0" diff --git a/src/crc128.rs b/src/crc128.rs index 11c77e2..a380a0e 100644 --- a/src/crc128.rs +++ b/src/crc128.rs @@ -1,6 +1,5 @@ -use crc_catalog::Algorithm; - use crate::util::crc128; +use crc_catalog::Algorithm; mod bytewise; mod default; @@ -170,10 +169,101 @@ const fn update_slice16( #[cfg(test)] mod test { - use crate::{Bytewise, Crc, NoTable, Slice16}; + use crate::{Bytewise, Crc, Implementation, NoTable, Slice16}; use crc_catalog::{Algorithm, CRC_82_DARC}; - /// Test this opitimized version against the well known implementation to ensure correctness + #[test] + fn default_table_size() { + const TABLE_SIZE: usize = core::mem::size_of::<::Table>(); + const BYTES_PER_ENTRY: usize = 16; + #[cfg(all( + feature = "no-table-mem-limit", + feature = "bytewise-mem-limit", + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + feature = "bytewise-mem-limit", + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + feature = "bytewise-mem-limit", + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + not(feature = "no-table-mem-limit"), + feature = "bytewise-mem-limit", + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 256 * 16 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + let _ = TABLE_SIZE; + let _ = BYTES_PER_ENTRY; + } + + /// Test this optimized version against the well known implementation to ensure correctness #[test] fn correctness() { let data: &[&str] = &[ diff --git a/src/crc128/default.rs b/src/crc128/default.rs index d8d4be9..d623ac4 100644 --- a/src/crc128/default.rs +++ b/src/crc128/default.rs @@ -1,11 +1,62 @@ -use crate::table::crc128_table; -use crate::{Algorithm, Crc, Digest}; +use crate::crc128::{finalize, init}; +use crate::{Algorithm, Crc, Digest, Implementation}; -use super::{finalize, init, update_bytewise}; +#[cfg(feature = "no-table-mem-limit")] +impl Implementation for u128 { + type Width = u128; + type Table = (); +} + +#[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] +impl Implementation for u128 { + type Width = u128; + type Table = [u128; 256]; +} + +#[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" +))] +impl Implementation for u128 { + type Width = u128; + type Table = [[u128; 256]; 16]; +} + +#[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") +))] +impl Implementation for u128 { + type Width = u128; + type Table = [u128; 256]; +} impl Crc { pub const fn new(algorithm: &'static Algorithm) -> Self { - let table = crc128_table(algorithm.width, algorithm.poly, algorithm.refin); + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + let table = + crate::table::crc128_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin); + + #[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] + let table = crate::table::crc128_table(algorithm.width, algorithm.poly, algorithm.refin); + + #[cfg(feature = "no-table-mem-limit")] + #[allow(clippy::let_unit_value)] + let table = (); + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + let table = crate::table::crc128_table(algorithm.width, algorithm.poly, algorithm.refin); + Self { algorithm, table } } @@ -16,7 +67,33 @@ impl Crc { } const fn update(&self, crc: u128, bytes: &[u8]) -> u128 { - update_bytewise(crc, self.algorithm.refin, &self.table, bytes) + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + super::update_slice16(crc, self.algorithm.refin, &self.table, bytes) + } + + #[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] + { + super::update_bytewise(crc, self.algorithm.refin, &self.table, bytes) + } + + #[cfg(feature = "no-table-mem-limit")] + { + super::update_nolookup(crc, self.algorithm, bytes) + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + super::update_bytewise(crc, self.algorithm.refin, &self.table, bytes) + } } pub const fn digest(&self) -> Digest { diff --git a/src/crc16.rs b/src/crc16.rs index bb31de8..9001f2f 100644 --- a/src/crc16.rs +++ b/src/crc16.rs @@ -141,10 +141,101 @@ const fn update_slice16( #[cfg(test)] mod test { - use crate::{Bytewise, Crc, NoTable, Slice16}; + use crate::{Bytewise, Crc, Implementation, NoTable, Slice16}; use crc_catalog::{Algorithm, CRC_16_IBM_SDLC}; - /// Test this opitimized version against the well known implementation to ensure correctness + #[test] + fn default_table_size() { + const TABLE_SIZE: usize = core::mem::size_of::<::Table>(); + const BYTES_PER_ENTRY: usize = 2; + #[cfg(all( + feature = "no-table-mem-limit", + feature = "bytewise-mem-limit", + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + feature = "bytewise-mem-limit", + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + feature = "bytewise-mem-limit", + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + not(feature = "no-table-mem-limit"), + feature = "bytewise-mem-limit", + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 256 * 16 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + let _ = TABLE_SIZE; + let _ = BYTES_PER_ENTRY; + } + + /// Test this optimized version against the well known implementation to ensure correctness #[test] fn correctness() { let data: &[&str] = &[ diff --git a/src/crc16/default.rs b/src/crc16/default.rs index 75123d1..55b72c9 100644 --- a/src/crc16/default.rs +++ b/src/crc16/default.rs @@ -1,12 +1,62 @@ use crate::crc16::{finalize, init}; -use crate::table::crc16_table_slice_16; -use crate::{Algorithm, Crc, Digest}; +use crate::{Algorithm, Crc, Digest, Implementation}; -use super::update_slice16; +#[cfg(feature = "no-table-mem-limit")] +impl Implementation for u16 { + type Width = u16; + type Table = (); +} + +#[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] +impl Implementation for u16 { + type Width = u16; + type Table = [u16; 256]; +} + +#[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" +))] +impl Implementation for u16 { + type Width = u16; + type Table = [[u16; 256]; 16]; +} + +#[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") +))] +impl Implementation for u16 { + type Width = u16; + type Table = [u16; 256]; +} impl Crc { pub const fn new(algorithm: &'static Algorithm) -> Self { - let table = crc16_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin); + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + let table = + crate::table::crc16_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin); + + #[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] + let table = crate::table::crc16_table(algorithm.width, algorithm.poly, algorithm.refin); + + #[cfg(feature = "no-table-mem-limit")] + #[allow(clippy::let_unit_value)] + let table = (); + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + let table = crate::table::crc16_table(algorithm.width, algorithm.poly, algorithm.refin); + Self { algorithm, table } } @@ -17,7 +67,33 @@ impl Crc { } const fn update(&self, crc: u16, bytes: &[u8]) -> u16 { - update_slice16(crc, self.algorithm.refin, &self.table, bytes) + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + super::update_slice16(crc, self.algorithm.refin, &self.table, bytes) + } + + #[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] + { + super::update_bytewise(crc, self.algorithm.refin, &self.table, bytes) + } + + #[cfg(feature = "no-table-mem-limit")] + { + super::update_nolookup(crc, self.algorithm, bytes) + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + super::update_bytewise(crc, self.algorithm.refin, &self.table, bytes) + } } pub const fn digest(&self) -> Digest { diff --git a/src/crc32.rs b/src/crc32.rs index 063814f..0467533 100644 --- a/src/crc32.rs +++ b/src/crc32.rs @@ -1,11 +1,11 @@ +use crate::util::crc32; +use crc_catalog::Algorithm; + mod bytewise; mod default; mod nolookup; mod slice16; -use crate::util::crc32; -use crc_catalog::Algorithm; - // init is shared between all impls const fn init(algorithm: &Algorithm, initial: u32) -> u32 { if algorithm.refin { @@ -152,10 +152,101 @@ const fn update_slice16( #[cfg(test)] mod test { - use crate::{Bytewise, Crc, NoTable, Slice16}; + use crate::{Bytewise, Crc, Implementation, NoTable, Slice16}; use crc_catalog::{Algorithm, CRC_32_ISCSI}; - /// Test this opitimized version against the well known implementation to ensure correctness + #[test] + fn default_table_size() { + const TABLE_SIZE: usize = core::mem::size_of::<::Table>(); + const BYTES_PER_ENTRY: usize = 4; + #[cfg(all( + feature = "no-table-mem-limit", + feature = "bytewise-mem-limit", + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + feature = "bytewise-mem-limit", + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + feature = "bytewise-mem-limit", + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + not(feature = "no-table-mem-limit"), + feature = "bytewise-mem-limit", + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 256 * 16 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + let _ = TABLE_SIZE; + let _ = BYTES_PER_ENTRY; + } + + /// Test this optimized version against the well known implementation to ensure correctness #[test] fn correctness() { let data: &[&str] = &[ diff --git a/src/crc32/default.rs b/src/crc32/default.rs index c35e3be..0aaedd3 100644 --- a/src/crc32/default.rs +++ b/src/crc32/default.rs @@ -1,11 +1,62 @@ -use crate::table::crc32_table_slice_16; -use crate::{Algorithm, Crc, Digest}; +use crate::crc32::{finalize, init}; +use crate::{Algorithm, Crc, Digest, Implementation}; -use super::{finalize, init, update_slice16}; +#[cfg(feature = "no-table-mem-limit")] +impl Implementation for u32 { + type Width = u32; + type Table = (); +} + +#[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] +impl Implementation for u32 { + type Width = u32; + type Table = [u32; 256]; +} + +#[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" +))] +impl Implementation for u32 { + type Width = u32; + type Table = [[u32; 256]; 16]; +} + +#[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") +))] +impl Implementation for u32 { + type Width = u32; + type Table = [u32; 256]; +} impl Crc { pub const fn new(algorithm: &'static Algorithm) -> Self { - let table = crc32_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin); + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + let table = + crate::table::crc32_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin); + + #[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] + let table = crate::table::crc32_table(algorithm.width, algorithm.poly, algorithm.refin); + + #[cfg(feature = "no-table-mem-limit")] + #[allow(clippy::let_unit_value)] + let table = (); + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + let table = crate::table::crc32_table(algorithm.width, algorithm.poly, algorithm.refin); + Self { algorithm, table } } @@ -16,7 +67,33 @@ impl Crc { } const fn update(&self, crc: u32, bytes: &[u8]) -> u32 { - update_slice16(crc, self.algorithm.refin, &self.table, bytes) + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + super::update_slice16(crc, self.algorithm.refin, &self.table, bytes) + } + + #[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] + { + super::update_bytewise(crc, self.algorithm.refin, &self.table, bytes) + } + + #[cfg(feature = "no-table-mem-limit")] + { + super::update_nolookup(crc, self.algorithm, bytes) + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + super::update_bytewise(crc, self.algorithm.refin, &self.table, bytes) + } } pub const fn digest(&self) -> Digest { diff --git a/src/crc64.rs b/src/crc64.rs index b2ff118..9abafd2 100644 --- a/src/crc64.rs +++ b/src/crc64.rs @@ -1,6 +1,5 @@ -use crc_catalog::Algorithm; - use crate::util::crc64; +use crc_catalog::Algorithm; mod bytewise; mod default; @@ -155,10 +154,101 @@ const fn update_slice16( #[cfg(test)] mod test { - use crate::{Bytewise, Crc, NoTable, Slice16}; + use crate::{Bytewise, Crc, Implementation, NoTable, Slice16}; use crc_catalog::{Algorithm, CRC_64_ECMA_182}; - /// Test this opitimized version against the well known implementation to ensure correctness + #[test] + fn default_table_size() { + const TABLE_SIZE: usize = core::mem::size_of::<::Table>(); + const BYTES_PER_ENTRY: usize = 8; + #[cfg(all( + feature = "no-table-mem-limit", + feature = "bytewise-mem-limit", + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + feature = "bytewise-mem-limit", + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + feature = "bytewise-mem-limit", + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + not(feature = "no-table-mem-limit"), + feature = "bytewise-mem-limit", + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 256 * 16 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + let _ = TABLE_SIZE; + let _ = BYTES_PER_ENTRY; + } + + /// Test this optimized version against the well known implementation to ensure correctness #[test] fn correctness() { let data: &[&str] = &[ diff --git a/src/crc64/default.rs b/src/crc64/default.rs index 73628ef..bf41dc8 100644 --- a/src/crc64/default.rs +++ b/src/crc64/default.rs @@ -1,11 +1,62 @@ -use crate::table::crc64_table_slice_16; -use crate::{Algorithm, Crc, Digest}; +use crate::crc64::{finalize, init}; +use crate::{Algorithm, Crc, Digest, Implementation}; -use super::{finalize, init, update_slice16}; +#[cfg(feature = "no-table-mem-limit")] +impl Implementation for u64 { + type Width = u64; + type Table = (); +} + +#[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] +impl Implementation for u64 { + type Width = u64; + type Table = [u64; 256]; +} + +#[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" +))] +impl Implementation for u64 { + type Width = u64; + type Table = [[u64; 256]; 16]; +} + +#[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") +))] +impl Implementation for u64 { + type Width = u64; + type Table = [u64; 256]; +} impl Crc { pub const fn new(algorithm: &'static Algorithm) -> Self { - let table = crc64_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin); + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + let table = + crate::table::crc64_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin); + + #[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] + let table = crate::table::crc64_table(algorithm.width, algorithm.poly, algorithm.refin); + + #[cfg(feature = "no-table-mem-limit")] + #[allow(clippy::let_unit_value)] + let table = (); + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + let table = crate::table::crc64_table(algorithm.width, algorithm.poly, algorithm.refin); + Self { algorithm, table } } @@ -16,7 +67,33 @@ impl Crc { } const fn update(&self, crc: u64, bytes: &[u8]) -> u64 { - update_slice16(crc, self.algorithm.refin, &self.table, bytes) + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + super::update_slice16(crc, self.algorithm.refin, &self.table, bytes) + } + + #[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] + { + super::update_bytewise(crc, self.algorithm.refin, &self.table, bytes) + } + + #[cfg(feature = "no-table-mem-limit")] + { + super::update_nolookup(crc, self.algorithm, bytes) + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + super::update_bytewise(crc, self.algorithm.refin, &self.table, bytes) + } } pub const fn digest(&self) -> Digest { diff --git a/src/crc8.rs b/src/crc8.rs index 9587e2a..d33d906 100644 --- a/src/crc8.rs +++ b/src/crc8.rs @@ -88,10 +88,101 @@ const fn update_slice16(mut crc: u8, table: &[[u8; 256]; 16], bytes: &[u8]) -> u #[cfg(test)] mod test { - use crate::{Bytewise, Crc, NoTable, Slice16}; + use crate::{Bytewise, Crc, Implementation, NoTable, Slice16}; use crc_catalog::{Algorithm, CRC_8_BLUETOOTH}; - /// Test this opitimized version against the well known implementation to ensure correctness + #[test] + fn default_table_size() { + const TABLE_SIZE: usize = core::mem::size_of::<::Table>(); + const BYTES_PER_ENTRY: usize = 1; + #[cfg(all( + feature = "no-table-mem-limit", + feature = "bytewise-mem-limit", + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + feature = "bytewise-mem-limit", + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + feature = "no-table-mem-limit", + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 0; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + feature = "bytewise-mem-limit", + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + #[cfg(all( + not(feature = "no-table-mem-limit"), + feature = "bytewise-mem-limit", + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + const EXPECTED: usize = 256 * 16 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + const EXPECTED: usize = 256 * BYTES_PER_ENTRY; + let _ = EXPECTED; + const _: () = assert!(EXPECTED == TABLE_SIZE); + } + let _ = TABLE_SIZE; + let _ = BYTES_PER_ENTRY; + } + + /// Test this optimized version against the well known implementation to ensure correctness #[test] fn correctness() { let data: &[&str] = &[ diff --git a/src/crc8/default.rs b/src/crc8/default.rs index 2dfec0d..9923b3a 100644 --- a/src/crc8/default.rs +++ b/src/crc8/default.rs @@ -1,12 +1,62 @@ use crate::crc8::{finalize, init}; -use crate::table::crc8_table_slice_16; -use crate::{Algorithm, Crc, Digest}; +use crate::{Algorithm, Crc, Digest, Implementation}; -use super::update_slice16; +#[cfg(feature = "no-table-mem-limit")] +impl Implementation for u8 { + type Width = u8; + type Table = (); +} + +#[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] +impl Implementation for u8 { + type Width = u8; + type Table = [u8; 256]; +} + +#[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" +))] +impl Implementation for u8 { + type Width = u8; + type Table = [[u8; 256]; 16]; +} + +#[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") +))] +impl Implementation for u8 { + type Width = u8; + type Table = [u8; 256]; +} impl Crc { pub const fn new(algorithm: &'static Algorithm) -> Self { - let table = crc8_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin); + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + let table = + crate::table::crc8_table_slice_16(algorithm.width, algorithm.poly, algorithm.refin); + + #[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] + let table = crate::table::crc8_table(algorithm.width, algorithm.poly, algorithm.refin); + + #[cfg(feature = "no-table-mem-limit")] + #[allow(clippy::let_unit_value)] + let table = (); + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + let table = crate::table::crc8_table(algorithm.width, algorithm.poly, algorithm.refin); + Self { algorithm, table } } @@ -17,7 +67,33 @@ impl Crc { } const fn update(&self, crc: u8, bytes: &[u8]) -> u8 { - update_slice16(crc, &self.table, bytes) + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + feature = "slice16-mem-limit" + ))] + { + super::update_slice16(crc, &self.table, bytes) + } + + #[cfg(all(not(feature = "no-table-mem-limit"), feature = "bytewise-mem-limit"))] + { + super::update_bytewise(crc, &self.table, bytes) + } + + #[cfg(feature = "no-table-mem-limit")] + { + super::update_nolookup(crc, self.algorithm, bytes) + } + + #[cfg(all( + not(feature = "no-table-mem-limit"), + not(feature = "bytewise-mem-limit"), + not(feature = "slice16-mem-limit") + ))] + { + super::update_bytewise(crc, &self.table, bytes) + } } pub const fn digest(&self) -> Digest { diff --git a/src/lib.rs b/src/lib.rs index ff16aa9..d0a4ded 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,31 +76,6 @@ pub trait Implementation: private::Sealed { type Table; } -impl Implementation for u8 { - type Width = u8; - type Table = [[u8; 256]; 16]; -} - -impl Implementation for u16 { - type Width = u16; - type Table = [[u16; 256]; 16]; -} - -impl Implementation for u32 { - type Width = u32; - type Table = [[u32; 256]; 16]; -} - -impl Implementation for u64 { - type Width = u64; - type Table = [[u64; 256]; 16]; -} - -impl Implementation for u128 { - type Width = u128; - type Table = [u128; 256]; -} - /// Crc with pluggable implementations ([Nolookup], [Bytewise], [Slice16]). /// To choose the default implementation, use the [Width] directly (e.g. `Crc`). pub struct Crc { diff --git a/tests/test_under_all_feature_combinations.sh b/tests/test_under_all_feature_combinations.sh new file mode 100755 index 0000000..2b44c73 --- /dev/null +++ b/tests/test_under_all_feature_combinations.sh @@ -0,0 +1,15 @@ +set -ex + +cargo test +cargo test --no-default-features + +cargo test --features slice16-mem-limit +cargo test --features bytewise-mem-limit +cargo test --features no-table-mem-limit + +cargo test --features bytewise-mem-limit,slice16-mem-limit +cargo test --features no-table-mem-limit,bytewise-mem-limit +cargo test --features no-table-mem-limit,slice16-mem-limit + +cargo test --features no-table-mem-limit,bytewise-mem-limit,slice16-mem-limit +