Warning: this library is under construction. It's functional, but its main selling point—SIMD acceleration—is not yet implemented.
A C++20 SIMD-accelerated high-performance constexpr-capable single-header-only CRC library with over 100 predefined CRCs and the ability to create custom ones.
Most likely, all you're looking for is a simple function that computes a common CRC variant. There are two fundamental CRC operations: building a CRC to append to your message, and verifying whether an existing message is valid:
#include <crc/crc.hpp> // Or: import crc;
// Build a CRC:
std::string_view data {"Hello world!"};
std::uint32_t crc {crc::crc32c::compute(data)};
// Verify a CRC:
if (!crc::crc8_bluetooth::is_valid(some_message)) {
throw std::runtime_error {"Message is corrupted!"};
}
You can pass in any random access (not necessarily sized!) range. For more complex cases, the CRC can be built up incrementally:
// Step 1: initialize CRC state.
crc::crc64_xz crc {};
// Step 2: feed it data.
// Notice how you can pass in any byte-like type, without any casts.
crc = crc::process(crc, "Some data"sv);
crc = crc::process(crc, u8" processed in "sv);
crc = crc::process(crc, std::vector<std::uint8_t> {'p', 'a', 'r', 't', 's'});
// Step 3: extract the final CRC.
std::uint64_t result {crc::finalize(crc)};
assert(result == crc::crc64_xz::compute("Some data processed in parts"sv));
All the functions above also have overloads taking iterator pairs instead of ranges.
There are many algorithms for calculating CRCs.
The library will pick a good default (crc::default_algorithm
; currently, that's crc::slice_by<8>
),
but it isn't omniscient,
so you have the ability to specify which algorithm you want.
The following algorithms are available:
crc::slice_by<N>
: processN
bytes at a time. Requires anN * 256 * sizeof(crc::<...>::crc_type)
byte lookup table. For example, CRC32C implemented with slice-by-4 requires a 4 KiB lookup table.
To specify an algorithm, pass it as the first parameter to crc::<...>::compute
, crc::<...>::is_valid
, or crc::process
:
crc::crc32_mpeg2::compute(crc::slice_by<8>, ...);
if (!crc::crc32_mpeg2::is_valid(crc::slice_by<8>, ...)) {
...
}
crc::crc32_mpeg2 crc {};
crc = crc::process(crc::slice_by<8>, crc, ...);
If you want to write your own functions that take CRC algorithms as arguments,
constrain them with the crc::algorithm
concept:
void my_function(crc::algorithm auto algo, ...) {
crc::crc32c::compute(algo, ...); // Pass along the algorithm.
}
Computing CRCs is an embarrassingly parallel problem.
To enable parallelization,
simply wrap an ordinary algorithm with the crc::parallel
adaptor and pass it to crc::<...>::compute
, crc::<...>::is_valid
, or crc::process
as you normally would:
crc::crc32c::compute(crc::parallel<crc::slice_by<8>>, ...);
(The function is still constexpr! It'll just dispatch to a sequential algorithm if evaluated at compile time.)
Note that parallelizing CRCs of width greater than 32 is currently unsupported.
The parallel algorithm divides the message into as many chunks as the system has hardware threads.
Each thread processes its chunk using the wrapped algorithm (in this case, crc::slice_by<8>
).
Here's what the scaling can look like:
To get specific numbers for your system, build the benchmarks as described in Building.
The CRC you're looking for almost certainly comes predefined (if it's missing, consider filing an issue), but you can define your own too:
using crc32c = crc::crc<
32, // The polynomial's width.
0x1EDC6F41, // The polynomial, with an implicit leading term.
0xFFFFFFFF, // The initial value of the CRC register.
true, // True if the bits in a byte should be ordered from LSb to MSb, false if vice-versa.
true, // True if the result should be reflected during finalization.
0xFFFFFFFF // The value XORed into the result at the very end, after any reflection.
>;
Or you can adapt existing CRCs:
// Identical to crc::crc32, but with the opposite bit ordering.
using crc32_reflected = crc::crc<
crc::crc32::width,
crc::crc32::poly,
crc::crc32::initial,
!crc::crc32::refin, // ⭐
!crc::crc32::refout, // ⭐
crc::crc32::xorout
>;
Note that CRCs of width greater than 64 are currently unsupported.
All provided functions are function objects and can be passed to other algorithms:
std::vector<std::string> strings {"Apple", "Banana", "Cherry", "Dragonfruit"};
std::vector<std::uint32_t> crcs {std::from_range, strings | std::views::transform(crc::crc32c::compute)};
// Compute a CRC over several noncontiguous chunks.
std::vector<std::vector<unsigned char>> data {...};
std::uint32_t crc {crc::finalize(std::ranges::fold_left(data, crc::crc32c {}, crc::process))};
FetchContent_Declare(crc
GIT_REPOSITORY https://github.com/LocalSpook/crc
GIT_TAG ... # You should use the latest commit on the main branch.
SYSTEM
)
FetchContent_MakeAvailable(crc)
target_link_libraries(... crc::crc)
find_package(crc REQUIRED)
target_link_libraries(... crc::crc)
Just copy include/crc/crc.hpp
into your directory structure.
For any serious project, you're highly recommended to use a proper dependency management
system instead, but this method is officially supported.
Simply run:
cmake -B build [-G Ninja]
cmake --build build
To also build the module, add -DCRC_MODULE=ON
, then pass crc::crc-module
to target_link_libraries
.
The module cannot currently be installed, so this is only available when using FetchContent.
To build tests, add -DCRC_TEST=ON
.
The resulting test binary will be build/bin/tests
.
Our testing framework is Catch2;
it will be downloaded automatically using FetchContent.
If you also configured with -DCRC_MODULE=ON
,
the module tests will be added to the binary.
We have a 2 by 2 testing matrix:
compile versus run time, and header versus module.
To test just the header, run ./build/bin/tests [header]
.
To test just the module, run ./build/bin/tests [module]
.
To build the benchmarks, add -DCRC_BENCHMARK=ON
.
The benchmarking framework is also Catch2,
and the resulting binary will be build/bin/benchmarks
.
- This library provides zero ABI stability guarantees.
- It should compile cleanly even at very high warning levels. If you see a warning, file an issue.