Skip to content

Commit f4ef0bf

Browse files
authored
Support constexpr initialization and calculation (#17)
The `crc` class did not have members marked as `constexpr` and so could not be used at compile time. This has been corrected and a test added to static assert in a failure to generate successfully at compile time.
1 parent 91c2b8c commit f4ef0bf

3 files changed

Lines changed: 44 additions & 11 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,5 @@
3232
*.app
3333

3434
bin/
35+
.idea/
36+

include/crc_cpp.h

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@
2828
#include <cstdint>
2929
#include <array>
3030

31+
32+
//
33+
// C++20 feature toggle
34+
//
35+
#if __cplusplus >= 202002L
36+
#define CRC_CPP_STD20_MODE 1
37+
#endif
38+
39+
3140
namespace crc_cpp
3241
{
3342
// Select the table size to use. This trades speed for size.
@@ -337,7 +346,7 @@ namespace impl
337346
// If we are C++20 or above, we can leverage cleaner constexpr initialisation
338347
// otherwise we will attempt to use a static table builder metaprogramming pattern
339348
// NOTE: Only C++17 will work, other constexpr code prevents C++14 and below working.
340-
#if __cplusplus >= 202002L
349+
#ifdef CRC_CPP_STD20_MODE
341350
[[nodiscard]] static constexpr typename traits::table_type Generate()
342351
{
343352
typename traits::table_type table;
@@ -402,17 +411,17 @@ namespace impl
402411
//
403412
// Update the accumulator with a new byte
404413
//
405-
void update(uint8_t value) { m_Crc = table_impl::update(m_Crc, value); }
414+
constexpr void update(uint8_t value) { m_Crc = table_impl::update(m_Crc, value); }
406415

407416
//
408417
// Extract the final value of the accumulator.
409418
//
410-
[[nodiscard]] accumulator_type final() { return m_Crc ^ algorithm::xor_out_value; }
419+
[[nodiscard]] constexpr accumulator_type final() { return m_Crc ^ algorithm::xor_out_value; }
411420

412421
//
413422
// Reset the state of the accumulator back to the INITIAL value.
414423
//
415-
void reset() { m_Crc = table_impl::make_initial_value(algorithm::initial_value); }
424+
constexpr void reset() { m_Crc = table_impl::make_initial_value(algorithm::initial_value); }
416425

417426

418427
private:
@@ -658,11 +667,7 @@ namespace large
658667
using crc32_d = family::crc32_d <table_size::large>;
659668
using crc32_mpeg2 = family::crc32_mpeg2 <table_size::large>;
660669
using crc32_posix = family::crc32_posix <table_size::large>;
661-
using crc32_q = family::crc32_q <table_size::large>;
662-
using crc32_jamcrc = family::crc32_jamcrc <table_size::large>;
663-
using crc32_xfer = family::crc32_xfer <table_size::large>;
664-
665-
using crc64_ecma = family::crc64_ecma <table_size::large>;
670+
using crc32_q = family::crc32_q <table_size::large>; using crc32_jamcrc = family::crc32_jamcrc <table_size::large>; using crc32_xfer = family::crc32_xfer <table_size::large>; using crc64_ecma = family::crc64_ecma <table_size::large>;
666671

667672
} // namespace large
668673

@@ -727,4 +732,8 @@ using namespace small;
727732

728733
} // namespace crc_cpp
729734

735+
#undef CRC_CPP_STD20_MODE
736+
#undef CRC_CPP_API_CONSTEXPR
737+
738+
730739
#endif // CRC_CPP_H_INCLUDED

test/test.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <iomanip>
2828
#include <string>
2929
#include <vector>
30+
#include <array>
3031

3132
#include "crc_cpp.h"
3233

@@ -119,6 +120,27 @@ bool test_crc(
119120
return result;
120121
}
121122

123+
//------------------------------------------------------------------------
124+
// Constexpr test
125+
//
126+
// Verify that the CRC can be calculated in a constexpr (compile-time) context
127+
template<std::size_t N>
128+
constexpr bool constexpr_check_message(std::array<uint8_t, N> data, uint8_t const expected)
129+
{
130+
crc_cpp::crc8 crc;
131+
for(const auto b : data) {
132+
crc.update(b);
133+
}
134+
return expected == crc.final();
135+
}
136+
137+
constexpr std::array<uint8_t, 9> constexpr_message{'1', '2', '3', '4', '5', '6', '7', '8', '9'};
138+
[[maybe_unused]] constexpr bool constexpr_test_result = constexpr_check_message(constexpr_message, 0xF4);
139+
140+
static_assert(constexpr_test_result, "Failed to compute crc at compile time");
141+
//------------------------------------------------------------------------
142+
143+
122144

123145
int main()
124146
{
@@ -136,10 +158,10 @@ int main()
136158

137159
// Test vector and result from https://crccalc.com
138160
// except crc64_ecma which comes from https://etlcppp.com
139-
std::vector<uint8_t> message{'1', '2', '3', '4', '5', '6', '7', '8', '9' };
161+
std::vector<uint8_t> message{ '1', '2', '3', '4', '5', '6', '7', '8', '9' };
140162

141163

142-
// we are exeucting the tests per family (table size set, same algorithm).
164+
// we are executing the tests per family (table size set, same algorithm).
143165
status &= test_crc<family::crc8>("crc8", message, 0xF4);
144166
status &= test_crc<family::crc8_cdma2000>("crc8_cdma2000", message, 0xDA);
145167
status &= test_crc<family::crc8_darc>("crc8_darc", message, 0x15);

0 commit comments

Comments
 (0)