CppSerdes  1.0
A serialization/deserialization library designed with embedded systems in mind
cppcrc.h
Go to the documentation of this file.
1 
9 #ifndef CPPCRC_H_
10 #define CPPCRC_H_
11 
12 #include <stddef.h>
13 #include <stdint.h>
14 #include <utility>
15 
16 //
17 // Backend implementation:
18 //
19 
20 namespace crc_utils
21 {
22  inline constexpr uint8_t reverse_bits(uint8_t x)
23  {
24  constexpr uint8_t lookup[16] = {0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf};
25  return (lookup[x & 0x0F] << 4) | lookup[x >> 4];
26  }
27  inline constexpr uint16_t reverse_bits(uint16_t x)
28  {
29  return uint16_t(reverse_bits(uint8_t(x))) << 8 | uint16_t(reverse_bits(uint8_t(x >> 8)));
30  }
31  inline constexpr uint32_t reverse_bits(uint32_t x)
32  {
33  return uint32_t(reverse_bits(uint16_t(x))) << 16 | uint32_t(reverse_bits(uint16_t(x >> 16)));
34  }
35  inline constexpr uint64_t reverse_bits(uint64_t x)
36  {
37  return uint64_t(reverse_bits(uint32_t(x))) << 32 | uint64_t(reverse_bits(uint32_t(x >> 32)));
38  }
39  template <typename out_t, out_t poly, bool refl_in, bool refl_out, size_t index>
40  constexpr out_t get_crc_table_value_at_index()
41  {
42  constexpr size_t bit_width = sizeof(out_t) * 8;
43  out_t remainder = refl_in ? reverse_bits(static_cast<out_t>(index)) >> (bit_width - 8u) : static_cast<out_t>(index);
44  constexpr out_t mask = static_cast<out_t>(1) << (bit_width - 1u);
45  for (size_t i = 0; i < bit_width; i++)
46  {
47  if (remainder & mask)
48  remainder = (remainder << 1) ^ poly;
49  else
50  remainder <<= 1;
51  }
52  return refl_in ? reverse_bits(remainder) : remainder;
53  }
54 
55  template <typename out_t, out_t poly, bool refl_in, bool refl_out, size_t size = 256, typename = std::make_index_sequence<size>>
57 
58  template <typename out_t, out_t poly, bool refl_in, bool refl_out, size_t size, size_t... indexes>
59  struct crc_lookup_table<out_t, poly, refl_in, refl_out, size, std::index_sequence<indexes...>>
60  {
61  static constexpr out_t value[size] = {get_crc_table_value_at_index<out_t, poly, refl_in, refl_out, indexes>()...};
62  };
63 
64 #if ((defined(_MSVC_LANG) && _MSVC_LANG < 201703L) || (defined(__cplusplus) && __cplusplus < 201703L)) // redeclaration is only needed before C++17
65  template <typename out_t, out_t poly, bool refl_in, bool refl_out, size_t size, size_t... indexes>
66  constexpr out_t crc_lookup_table<out_t, poly, refl_in, refl_out, size, std::index_sequence<indexes...>>::value[size];
67 #endif
68 
69  template <typename out_t, out_t poly, bool refl_in, bool refl_out, out_t x_or_out, typename std::enable_if<refl_in, int *>::type = nullptr>
70  constexpr out_t calculate_crc(const uint8_t *bytes, size_t n, out_t crc)
71  {
72  constexpr auto &lookup = crc_lookup_table<out_t, poly, refl_in, refl_out>().value;
73  crc = reverse_bits(crc);
74  while (n--)
75  crc = lookup[static_cast<uint8_t>(*bytes++ ^ crc)] ^ (crc >> 8);
76  return (refl_out != refl_in ? reverse_bits(crc) : crc) ^ x_or_out; // needed since the reflections are baked into the table for speed
77  }
78 
79  template <typename out_t, out_t poly, bool refl_in, bool refl_out, out_t x_or_out, typename std::enable_if<!refl_in, int *>::type = nullptr>
80  constexpr out_t calculate_crc(const uint8_t *bytes, size_t n, out_t crc)
81  {
82  constexpr auto &lookup = crc_lookup_table<out_t, poly, refl_in, refl_out>().value;
83  constexpr size_t bit_width_minus_8 = sizeof(out_t) * 8 - 8U;
84  while (n--)
85  crc = lookup[static_cast<uint8_t>(*bytes++ ^ (crc >> bit_width_minus_8))] ^ (crc << 8);
86  return (refl_out ? reverse_bits(crc) : crc) ^ x_or_out;
87  }
88 
89  template <typename out_t, out_t poly_arg, out_t init_arg, bool refl_in_arg, bool refl_out_arg, out_t x_or_out_arg>
90  struct crc
91  {
92  using type = out_t; // base type of the crc algorithm
93  static constexpr out_t poly = poly_arg; // polynomial of the crc algorithm
94  static constexpr out_t init = init_arg; // initial CRC internal state, WARNING: may be different from "null_crc"
95  static constexpr bool refl_in = refl_in_arg; // true if the bits of the crc should be reflected/reversed on input
96  static constexpr bool refl_out = refl_out_arg; // true if the bits of the crc should be reflected/reversed on output
97  static constexpr out_t x_or_out = x_or_out_arg; // the value to X-OR the output with
98  static constexpr out_t null_crc = (refl_out ? reverse_bits(init) : init) ^ x_or_out; // CRC value of no/null data
99 
101  static constexpr out_t calc(const uint8_t *bytes = nullptr, size_t num_bytes = 0u, out_t prior_crc_value = null_crc)
102  {
103  prior_crc_value = x_or_out ? prior_crc_value ^ x_or_out : prior_crc_value;
104  prior_crc_value = refl_out ? reverse_bits(prior_crc_value) : prior_crc_value;
105  return calculate_crc<out_t, poly, refl_in, refl_out, x_or_out>(bytes, num_bytes, prior_crc_value);
106  }
108  static constexpr auto &table()
109  {
111  }
112  };
113 } // namespace crc_utils
114 
115 //
116 // Default CRC Configurations: <type, poly, init, refl_in, refl_out, x_or_out>
117 //
118 
119 namespace CRC8
120 {
131 } // namespace CRC8
132 namespace CRC16
133 {
157 } // namespace CRC16
158 namespace CRC32
159 {
170 } // namespace CRC32
171 namespace CRC64
172 {
177 } // namespace CRC64
178 
179 #endif // CPPCRC_H_
crc_utils::crc::table
static constexpr auto & table()
the underlying pre-computed CRC table used for fast lookup-table-based calculations
Definition: cppcrc.h:108
crc_utils::crc_lookup_table
Definition: cppcrc.h:56
crc_utils::crc::calc
static constexpr out_t calc(const uint8_t *bytes=nullptr, size_t num_bytes=0u, out_t prior_crc_value=null_crc)
Calculate the checksum of some bytes, or continue an existing calculation by passing in the prior crc...
Definition: cppcrc.h:101
crc_utils::crc
Definition: cppcrc.h:90