pabigot  0.1.1
C++ support classes
crc.hpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0 */
2 /* Copyright 2015-2019 Peter A. Bigot */
3 
8 #ifndef PABIGOT_CRC_HPP
9 #define PABIGOT_CRC_HPP
10 #pragma once
11 
12 #include <array>
13 #include <cstdint>
14 #include <limits>
15 #include <tuple>
16 #include <type_traits>
17 #include <utility>
18 
19 #include <pabigot/byteorder.hpp>
20 
21 namespace pabigot {
22 
28 namespace crc {
29 
33 namespace details {
34 
47 template <typename UI>
48 static constexpr UI
49 reverse_low_bits (const UI& v,
50  unsigned int bits)
51 {
52  UI msb = (static_cast<UI>(1) << (bits - 1));
53  UI lsb = 1;
54  UI out = 0;
55 
56  /* msb right-shifts; when it becomes zero we're done. */
57  while (msb) {
58  if (msb & v) {
59  out |= lsb;
60  }
61  msb >>= 1;
62  lsb <<= 1;
63  }
64  return out;
65 }
66 
72 template <unsigned int B>
73 constexpr unsigned int uint_category ()
74 {
75  return (B<=8) + (B<=16) + (B<=32) + (B<=64);
76 }
77 
96 template <unsigned int C>
98 { };
99 
100 template <>
102 {
103  static constexpr unsigned int width = 8;
104  using fast_type = uint_fast8_t;
105  using least_type = uint_least8_t;
106 };
107 
108 template <>
110 {
111  static constexpr unsigned int width = 16;
112  using fast_type = uint_fast16_t;
113  using least_type = uint_least16_t;
114 };
115 
116 template <>
118 {
119  static constexpr unsigned int width = 32;
120  using fast_type = uint_fast32_t;
121  using least_type = uint_least32_t;
122 };
123 
124 template <>
126 {
127  static constexpr unsigned int width = 64;
128  using fast_type = uint_fast64_t;
129  using least_type = uint_least64_t;
130 };
131 
138 template <unsigned int C>
139 struct uint_traits : public uint_size_traits<C>
140 {
141  using super = uint_size_traits<C>;
142  using typename super::fast_type;
143  using typename super::least_type;
144  using fast_limits = std::numeric_limits<fast_type>;
145 
149  static constexpr fast_type
150  reverse (const fast_type& v,
151  unsigned int bits)
152  {
153  return reverse_low_bits<fast_type>(v, bits);
154  }
155 
167  static constexpr fast_type
168  mask_for_bits (unsigned int bits)
169  {
170  return ((bits == fast_limits::digits)
171  ? static_cast<fast_type>(-1)
172  : ((static_cast<fast_type>(1) << bits) - 1));
173  }
174 
175 };
176 
185 
189 template <unsigned int B>
191 {
197  static constexpr unsigned int width = B;
198 
202 
207  using fast_type = typename uint_traits::fast_type;
208 
212  using least_type = typename uint_traits::least_type;
213 
215  static constexpr unsigned int fast_width = std::numeric_limits<fast_type>::digits;
216 
218  static constexpr unsigned int least_width = std::numeric_limits<least_type>::digits;
219 
223 
225  static constexpr fast_type msbit{static_cast<fast_type>(1) << (width - 1)};
226 
228  static constexpr fast_type lsbit{static_cast<fast_type>(1)};
229 
239  static constexpr fast_type
240  reflect (const fast_type& v,
241  unsigned int n = width)
242  {
243  return uint_traits::reverse(v, n);
244  }
245 
260  static constexpr fast_type
261  crc_apply (const fast_type& poly,
262  const fast_type& crc,
263  const fast_type& msg,
264  const unsigned int n)
265  {
266  auto rv = crc;
267  rv ^= msg << (width - n);
268  for (unsigned int bi{}; bi < n; ++bi) {
269  bool xor_poly{msbit & rv};
270  rv <<= 1;
271  if (xor_poly) {
272  rv ^= poly;
273  }
274  }
275  return mask & rv;
276  }
277 };
278 
281 template <typename CRC,
282  size_t... n>
283 constexpr auto lookup_table (std::index_sequence<n...>)
284 {
285  using least_type = typename CRC::least_type;
286  return std::array<least_type, sizeof...(n)>{{CRC::lookup_for_byte(n)...}};
287 }
288 
295 template <typename CRC>
296 constexpr auto lookup_table()
297 {
298  return lookup_table<CRC>(std::make_integer_sequence<size_t, 256>{});
299 }
300 
309 template <unsigned int W,
310  bool Rin = false>
311 class base_crc
312 {
313 public:
315  static constexpr unsigned int width = W;
316 
318  static constexpr unsigned int size = (7 + width) / 8;
319 
320 protected:
324 
325 public:
326  using uint_traits = typename support_traits::uint_traits;
327 
334 
341 
344  static constexpr fast_type mask = support_traits::mask;
345 
359  static constexpr bool refin = Rin;
360 
362  static constexpr fast_type
363  reflect (const fast_type& v)
364  {
365  return support_traits::reflect(v, width);
366  }
367 
381  static constexpr uint8_t*
383  uint8_t* bp)
384  {
385  auto nb = size;
386  while (nb--) {
387  if (refin) {
388  *bp++ = crc;
389  crc >>= 8;
390  } else {
391  *bp++ = crc >> (8 * nb);
392  }
393  }
394  return bp;
395  }
396 
397 protected:
398 
410  static constexpr least_type
412  std::uint_fast8_t byte)
413  {
414  if (refin) {
415  byte = support_traits::reflect(byte, 8);
416  }
417 
418  auto rv = crc_apply(poly, 0, byte, 8);
419  /* Assume the common case that refin==refout. For cross-endian we need to
420  * correct this during finalize. */
421  if (refin) {
422  rv = reflect(rv);
423  }
424  return mask & rv;
425  }
426 
439  static constexpr fast_type
440  crc_apply (const fast_type& poly,
441  const fast_type& crc,
442  fast_type msg,
443  unsigned int n)
444  {
445  auto rv = crc;
446  while (n > width) {
447  fast_type submsg = msg >> (n - width);
448  rv = support_traits::crc_apply(poly, rv, submsg, width);
449  n -= width;
450  }
451  return support_traits::crc_apply(poly, rv, msg, n);
452  }
453 };
454 
455 } // ns details
456 
479 template <typename CRC>
480 class Tabler : public CRC::uint_traits
481 {
482  using super_ = typename CRC::uint_traits;
483 
484 public:
486  using crc_type = CRC;
487 
489  using typename super_::fast_type;
490 
492  using typename super_::least_type;
493 
495  using table_type = std::array<least_type, 256>;
496 
499  struct params {
501  static constexpr unsigned int width = CRC::width;
503  static constexpr least_type poly = CRC::poly;
505  static constexpr least_type init = CRC::init;
507  static constexpr least_type xorout = CRC::xorout;
509  static constexpr bool refin = CRC::refin;
511  static constexpr bool refout = CRC::refout;
512  };
513 
515  static constexpr size_t size = CRC::size;
516 
517 private:
518 
523  static constexpr fast_type
524  make_init ()
525  {
526  fast_type crc = CRC::init;
527 
528  /* The table incorporates the effects of input reflection, but for that to
529  * work the initial value needs to be reflected. */
530  if (CRC::refin) {
531  crc = super_::reverse(crc, CRC::width);
532  }
533  return crc;
534  }
535 
536  // CRC is the only thing allowed to construct these. Nobody can copy them.
537  friend CRC;
538 
539  constexpr Tabler () :
540  table{details::lookup_table<CRC>()}
541  { }
542 
543  Tabler (const Tabler&) = delete;
544  Tabler& operator= (const Tabler&) = delete;
545  Tabler (const Tabler&&) = delete;
546  Tabler& operator= (const Tabler&&) = delete;
547 
548 public:
549 
559  uint8_t*
560  store (least_type crc,
561  uint8_t* bp) const
562  {
563  size_t nb{size};
564  while (nb--) {
565  if (CRC::refin) {
566  *bp++ = crc;
567  crc >>= 8;
568  } else {
569  *bp++ = crc >> (8 * nb);
570  }
571  }
572  return bp;
573  }
574 
586  constexpr fast_type
587  append (uint8_t octet,
588  fast_type crc = init) const
589  {
590  constexpr fast_type index_mask = 0xFFu;
591  if (CRC::refin) {
592  crc = table[(crc ^ octet) & index_mask] ^ (crc >> 8);
593  } else {
594  crc = table[((crc >> (CRC::width - 8)) ^ octet) & index_mask] ^ (crc << 8);
595  }
596  return CRC::mask & crc;
597  }
598 
616  template <typename InputIterator>
617  constexpr fast_type
618  append (InputIterator first,
619  InputIterator last,
620  fast_type crc = init) const
621  {
622  using src_type = typename std::iterator_traits<InputIterator>::value_type;
623  using limits = std::numeric_limits<src_type>;
624 
625  /* Unsigned 8-bit or signed 7-bit data passes this test */
626  constexpr auto bits_per_chunk = limits::digits + (limits::is_signed ? 1U : 0U);
627  static_assert(bits_per_chunk == 8,
628  "cannot do table-driven from non-octet source");
629 
630  auto rv = crc;
631  while (last != first) {
632  rv = append(static_cast<uint8_t>(*first), rv);
633  ++first;
634  }
635  return rv;
636  }
637 
643  constexpr least_type
644  finalize (fast_type crc) const
645  {
646  crc ^= CRC::xorout;
647 
648  /* As long as the input and output endian match the result doesn't need
649  * additional processing because the tables values are already reflected.
650  * If they differ, then the output needs to be reflected. */
651  if (CRC::refin ^ CRC::refout) {
652  crc = super_::reverse(crc, CRC::width);
653  }
654  return static_cast<least_type>(crc);
655  }
656 
658  static constexpr fast_type init = make_init();
659 
662  static constexpr least_type residue = CRC::residue();
663 
666 };
667 
695 template <unsigned int W,
696  uintmax_t Poly,
697  bool Rin = false,
698  bool Rout = false,
699  uintmax_t Init = 0,
700  uintmax_t XorOut = 0>
701 class crc : public details::base_crc<W, Rin>
702 {
705 
706 protected:
707  using typename super_::support_traits;
708 
709 public:
710  using typename super_::fast_type;
711  using typename super_::least_type;
712 
715 
717  static constexpr bool refout = Rout;
718 
737  static constexpr least_type residue ()
738  {
739  uint8_t buf[super_::size]{};
740  store(finalize(init), buf);
741  return finalize(append(buf, buf + sizeof(buf)));
742  }
743 
744  using super_::store;
745 
748  static constexpr fast_type poly = super_::mask & Poly;
749 
752  static constexpr least_type init = super_::mask & Init;
753 
756  static constexpr least_type xorout = super_::mask & XorOut;
757 
775  template <typename InputIterator>
776  static constexpr fast_type
777  append (InputIterator first,
778  InputIterator last,
779  const fast_type& crc = init)
780  {
781  using src_type = typename std::iterator_traits<InputIterator>::value_type;
782  constexpr auto bits_per_chunk =
783  std::numeric_limits<src_type>::digits
784  + (std::numeric_limits<src_type>::is_signed ? 1U : 0U);
785  static_assert(bits_per_chunk <= support_traits::fast_width,
786  "cannot aggregate from source exceeding CRC operating type capacity");
787  auto rv = crc;
788  while (last != first) {
789  /* Support signed values (viz. `signed char`) by first casting them to
790  * the unsigned least type, so they can promote to the unsigned fast type
791  * without violating narrowing rules. */
792  fast_type chunk = static_cast<least_type>(*first);
793  ++first;
794  if (super_::refin) {
795  chunk = support_traits::reflect(chunk, bits_per_chunk);
796  }
797  rv = super_::crc_apply(poly, rv, chunk, bits_per_chunk);
798  }
799  return rv;
800  }
801 
803  static constexpr least_type
804  lookup_for_byte (std::uint_fast8_t byte)
805  {
806  return super_::lookup_for_byte(poly, byte);
807  }
808 
823  static constexpr least_type
825  {
826  if (refout) {
828  }
829  crc ^= xorout;
830  return static_cast<least_type>(crc);
831  }
832 
835  static constexpr tabler_type instantiate_tabler ()
836  {
837  return {};
838  }
839 };
840 
844 using CRC32 = crc<32, 0x04c11db7, true, true, -1, -1>;
845 
846 } // ns crc
847 } // ns pabigot
848 
849 #endif /* PABIGOT_CRC_HPP */
pabigot::crc::crc
CRC calculation using Rocksoft^tm Model characteristics.
Definition: crc.hpp:701
pabigot::crc::details::uint_support::lsbit
static constexpr fast_type lsbit
Mask isolating the least significant bit in a value.
Definition: crc.hpp:228
pabigot::crc::crc::refout
static constexpr bool refout
true iff the output CRC is to be reflected.
Definition: crc.hpp:717
pabigot::crc::Tabler::params::refin
static constexpr bool refin
true iff input data is to be reflected
Definition: crc.hpp:509
pabigot::crc::Tabler::append
constexpr fast_type append(InputIterator first, InputIterator last, fast_type crc=init) const
Table-driven calculation of a CRC from a sequence of octet values.
Definition: crc.hpp:618
pabigot::crc::details::base_crc::width
static constexpr unsigned int width
The width of the CRC in bits.
Definition: crc.hpp:315
pabigot::crc::details::uint_support::crc_apply
static constexpr fast_type crc_apply(const fast_type &poly, const fast_type &crc, const fast_type &msg, const unsigned int n)
Apply message bits into the CRC.
Definition: crc.hpp:261
pabigot::crc::details::uint_support::least_width
static constexpr unsigned int least_width
The number of bits used in least_type, should that be useful.
Definition: crc.hpp:218
pabigot::crc::crc::poly
static constexpr fast_type poly
The CRC polynomial in normal form (all bits except bit width which is known to be 1 are provided).
Definition: crc.hpp:748
pabigot::crc::crc::xorout
static constexpr least_type xorout
A value subtracted (xor'd) from the calculated result prior to returning it.
Definition: crc.hpp:756
pabigot::crc::details::uint_traits::reverse
static constexpr fast_type reverse(const fast_type &v, unsigned int bits)
Reverse bits [0..bits) of v.
Definition: crc.hpp:150
pabigot::crc::details::base_crc::mask
static constexpr fast_type mask
The mask that discards bits of a fast_type that would be outside the width limit.
Definition: crc.hpp:344
byteorder.hpp
Support for byte order manipulation and packed storage.
pabigot::crc::details::uint_category
constexpr unsigned int uint_category()
Compute the #uint_size_traits category value for a required bit length.
Definition: crc.hpp:73
pabigot::crc::details::uint_support::fast_type
typename uint_traits::fast_type fast_type
The type used to hold values while they're being operated on.
Definition: crc.hpp:207
pabigot::crc::details::base_crc::support_traits
details::uint_support< width > support_traits
Traits class providing native integral types and parameter-independent values supporting width-bit op...
Definition: crc.hpp:323
pabigot::crc::Tabler::crc_type
CRC crc_type
The underlying crc type.
Definition: crc.hpp:486
pabigot::crc::Tabler::params::refout
static constexpr bool refout
true iff the final CRC is to be reflected
Definition: crc.hpp:511
pabigot::crc::details::base_crc::size
static constexpr unsigned int size
The width of the CRC in bytes.
Definition: crc.hpp:318
pabigot::crc::details::lookup_table
constexpr auto lookup_table(std::index_sequence< n... >)
Use a template parameter pack to fill out a 256-element std::initializer_list for a std::array.
Definition: crc.hpp:283
pabigot::crc::Tabler::finalize
constexpr least_type finalize(fast_type crc) const
Perform necessary post-processing to get the final checksum.
Definition: crc.hpp:644
pabigot::crc::Tabler::params::init
static constexpr least_type init
CRC initial value before message bits are processed.
Definition: crc.hpp:505
pabigot::crc::details::base_crc::least_type
typename support_traits::least_type least_type
A small native unsigned integral type capable of holding width-bit CRC values.
Definition: crc.hpp:340
pabigot::crc::details::uint_support::least_type
typename uint_traits::least_type least_type
The type used to hold values while they're being stored.
Definition: crc.hpp:212
pabigot::crc::Tabler::residue
static constexpr least_type residue
The value expected when calculating the finalized CRC over an aggregate of a message and its store()d...
Definition: crc.hpp:662
pabigot::crc::details::uint_traits
Extend the size-related traits with functionality operating on the specific types.
Definition: crc.hpp:139
pabigot::crc::details::uint_support::reflect
static constexpr fast_type reflect(const fast_type &v, unsigned int n=width)
Reflect a value around its center.
Definition: crc.hpp:240
pabigot::crc::details::base_crc::refin
static constexpr bool refin
true iff the input message bit stream is reflected.
Definition: crc.hpp:359
pabigot::crc::Tabler::size
static constexpr size_t size
The number of bytes required to store a CRC value of #width bits.
Definition: crc.hpp:515
pabigot::crc::details::uint_size_traits
Entry-point to identifying unsigned integral types supporting a specific number of bits.
Definition: crc.hpp:97
pabigot::crc::Tabler::params::width
static constexpr unsigned int width
Number of bits in the CRC.
Definition: crc.hpp:501
pabigot::crc::Tabler::store
uint8_t * store(least_type crc, uint8_t *bp) const
Store a finalized CRC into a buffer in a way that enables crc::residue().
Definition: crc.hpp:560
pabigot::crc::details::uint_support::mask
static constexpr fast_type mask
A mask value that will discard bits at and above bit number width in a value.
Definition: crc.hpp:222
pabigot::crc::Tabler::table_type
std::array< least_type, 256 > table_type
How the CRC table elements are stored.
Definition: crc.hpp:495
pabigot::crc::details::reverse_low_bits
static constexpr UI reverse_low_bits(const UI &v, unsigned int bits)
Reverse bits [0..bits) of v.
Definition: crc.hpp:49
pabigot::crc::crc::residue
static constexpr least_type residue()
Value expected for CRC(x || XE(CRC(x))).
Definition: crc.hpp:737
pabigot
Root for all pabigot namespaces.
Definition: gap.hpp:15
pabigot::crc::details::base_crc::store
static constexpr uint8_t * store(fast_type crc, uint8_t *bp)
Store a finalized CRC into a buffer in a way that enables crc::residue().
Definition: crc.hpp:382
pabigot::crc::Tabler::append
constexpr fast_type append(uint8_t octet, fast_type crc=init) const
Table-driven update of a CRC given a data octet.
Definition: crc.hpp:587
pabigot::crc::Tabler::params
Rocksoft^TM model parameters for the checksum algorithm supported by this type.
Definition: crc.hpp:499
pabigot::crc::details::uint_support::width
static constexpr unsigned int width
The number of bits for which this class is targeted.
Definition: crc.hpp:197
pabigot::crc::Tabler::table
const table_type table
The CRC table, indexed by unreflected input octet.
Definition: crc.hpp:665
pabigot::crc::details::base_crc::lookup_for_byte
static constexpr least_type lookup_for_byte(const fast_type &poly, std::uint_fast8_t byte)
Calculate a single lookup table entry using the given polynomial.
Definition: crc.hpp:411
pabigot::crc::Tabler::init
static constexpr fast_type init
The CRC initial value in the form required for table calculations.
Definition: crc.hpp:658
pabigot::crc::details::uint_support::msbit
static constexpr fast_type msbit
Mask isolating the most significant bit in a value.
Definition: crc.hpp:225
pabigot::crc::crc::append
static constexpr fast_type append(InputIterator first, InputIterator last, const fast_type &crc=init)
Augment a checksum with additional data.
Definition: crc.hpp:777
pabigot::crc::crc::init
static constexpr least_type init
The initial value of the CRC register before any message bits have been processed.
Definition: crc.hpp:752
pabigot::crc::crc::lookup_for_byte
static constexpr least_type lookup_for_byte(std::uint_fast8_t byte)
Delegate to super_::lookup_for_byte.
Definition: crc.hpp:804
pabigot::crc::crc::finalize
static constexpr least_type finalize(fast_type crc)
Calculate the final CRC value for a sequence.
Definition: crc.hpp:824
pabigot::crc::Tabler
Class encapsulating everything necessary for table-driven CRC calculations.
Definition: crc.hpp:480
pabigot::crc::details::uint_traits::mask_for_bits
static constexpr fast_type mask_for_bits(unsigned int bits)
Helper to calculate the value of a B-bit mask as an instance of the unsigned type T.
Definition: crc.hpp:168
pabigot::crc::details::uint_support::fast_width
static constexpr unsigned int fast_width
The number of bits used in fast_type, should that be useful.
Definition: crc.hpp:215
pabigot::crc::Tabler::params::poly
static constexpr least_type poly
CRC polynomial.
Definition: crc.hpp:503
pabigot::crc::details::base_crc::fast_type
typename support_traits::fast_type fast_type
A fast native unsigned integral type capable of holding width-bit CRC values.
Definition: crc.hpp:333
pabigot::crc::crc::instantiate_tabler
static constexpr tabler_type instantiate_tabler()
Construct an object that does table-driven CRC calculations for this algorithm.
Definition: crc.hpp:835
pabigot::crc::details::base_crc::reflect
static constexpr fast_type reflect(const fast_type &v)
Delegate to support_traits::reflect.
Definition: crc.hpp:363
pabigot::crc::details::base_crc
CRC core framework using Rocksoft^tm Model characteristics.
Definition: crc.hpp:311
pabigot::crc::details::uint_support
Type and policy traits providing support for operations on B-bit values.
Definition: crc.hpp:190
pabigot::crc::Tabler::params::xorout
static constexpr least_type xorout
Value used to mutate unreflected final CRC.
Definition: crc.hpp:507
pabigot::crc::details::base_crc::crc_apply
static constexpr fast_type crc_apply(const fast_type &poly, const fast_type &crc, fast_type msg, unsigned int n)
Apply message bits into a CRC.
Definition: crc.hpp:440
pabigot::crc::details::uint_support::uint_traits
details::uint_traits< uint_category< B >()> uint_traits
Characteristics of the unsigned integer support required for a width-bit value.
Definition: crc.hpp:201