Skip to content

Commit

Permalink
Add feature flags to select default implementation
Browse files Browse the repository at this point in the history
Introduce three crate features which enable choosing the default implementations. The implementation is chosen based on the flag with the most hardware compatibility (the highest restrictions on memory usage).

1. NoTable takes precedence over both others
2. Bytewise takes precedence over Slice16 and is the default if no feature is selected
3. Slice16 is used only if no other features are selected
  • Loading branch information
KillingSpark committed Apr 23, 2023
1 parent b4f0cf1 commit 5726647
Show file tree
Hide file tree
Showing 13 changed files with 904 additions and 67 deletions.
11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ categories = ["algorithms", "no-std"]
edition = "2021"
rust-version = "1.56"

[features]
# use the "NoTable" implementation for the default Crc<uXXX> 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<uXXX> 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<uXXX> 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"

Expand Down
98 changes: 94 additions & 4 deletions src/crc128.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crc_catalog::Algorithm;

use crate::util::crc128;
use crc_catalog::Algorithm;

mod bytewise;
mod default;
Expand Down Expand Up @@ -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::<<u128 as Implementation>::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] = &[
Expand Down
87 changes: 82 additions & 5 deletions src/crc128/default.rs
Original file line number Diff line number Diff line change
@@ -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<u128> {
pub const fn new(algorithm: &'static Algorithm<u128>) -> 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 }
}

Expand All @@ -16,7 +67,33 @@ impl Crc<u128> {
}

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<u128> {
Expand Down
95 changes: 93 additions & 2 deletions src/crc16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<<u16 as Implementation>::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] = &[
Expand Down
Loading

0 comments on commit 5726647

Please sign in to comment.