hash/crc: parameterise crc for reflection, and 64 bits

This commit is contained in:
Danny Robson 2017-02-14 19:47:12 +11:00
parent 2bd094ab9f
commit bec24535fc
5 changed files with 187 additions and 54 deletions

View File

@ -18,53 +18,104 @@
#include "../debug.hpp" #include "../debug.hpp"
#include <cruft/util/bitwise.hpp>
#include <array> #include <array>
using util::hash::crc; using util::hash::crc;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
template <typename DigestT, DigestT Generator> template <
typename DigestT,
DigestT Generator,
DigestT Initial,
DigestT Final,
bool ReflectIn,
bool ReflectOut
>
const std::array<DigestT,256> const std::array<DigestT,256>
crc<DigestT,Generator>::s_table = crc<DigestT,Generator>::table (); crc<
DigestT,Generator,Initial,Final,ReflectIn,ReflectOut
>::s_table = crc<DigestT,Generator,Initial,Final,ReflectIn,ReflectOut>::table ();
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
template <typename DigestT, DigestT Generator> template <
crc<DigestT,Generator>::crc () noexcept typename DigestT,
DigestT Generator,
DigestT Initial,
DigestT Final,
bool ReflectIn,
bool ReflectOut
>
crc<
DigestT,Generator,Initial,Final,ReflectIn,ReflectOut
>::crc () noexcept
{ {
reset (); reset ();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename DigestT, DigestT Generator> template <
typename DigestT,
DigestT Generator,
DigestT Initial,
DigestT Final,
bool ReflectIn,
bool ReflectOut
>
void void
crc<DigestT,Generator>::reset (void) noexcept crc<
DigestT,Generator,Initial,Final,ReflectIn,ReflectOut
>::reset (void) noexcept
{ {
m_digest = 0; m_digest = Initial;
m_digest = ~m_digest;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
template <typename DigestT, DigestT Generator> template <
typename DigestT,
DigestT Generator,
DigestT Initial,
DigestT Final,
bool ReflectIn,
bool ReflectOut
>
void void
crc<DigestT,Generator>::update (const uint8_t *restrict first, crc<
const uint8_t *restrict last) noexcept DigestT,Generator,Initial,Final,ReflectIn,ReflectOut
>::update (const uint8_t *restrict first,
const uint8_t *restrict last) noexcept
{ {
CHECK_LE (first, last); CHECK_LE (first, last);
for (auto cursor = first; cursor != last; ++cursor) { for (auto cursor = first; cursor != last; ++cursor) {
m_digest = s_table[*cursor ^ (m_digest & 0xFF)] ^ (m_digest >> 8u); if (ReflectIn)
m_digest = s_table[*cursor ^ (m_digest & 0xFFu)] ^ (m_digest >> 8u);
else {
constexpr auto shift = sizeof (DigestT) * 8u - 8u;
m_digest = (m_digest << 8u) ^ s_table[(m_digest >> shift) ^ *cursor];
}
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename DigestT, DigestT Generator> template <
typename DigestT,
DigestT Generator,
DigestT Initial,
DigestT Final,
bool ReflectIn,
bool ReflectOut
>
void void
crc<DigestT,Generator>::update (const void *restrict _data, size_t len) noexcept crc<
DigestT,Generator,Initial,Final,ReflectIn,ReflectOut
>::update (const void *restrict _data, size_t len) noexcept
{ {
auto data = reinterpret_cast<const uint8_t *restrict> (_data); auto data = reinterpret_cast<const uint8_t *restrict> (_data);
return update(data, data + len); return update(data, data + len);
@ -72,49 +123,101 @@ crc<DigestT,Generator>::update (const void *restrict _data, size_t len) noexcept
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename DigestT, DigestT Generator> template <
typename DigestT,
DigestT Generator,
DigestT Initial,
DigestT Final,
bool ReflectIn,
bool ReflectOut
>
void void
crc<DigestT,Generator>::finish (void) crc<
DigestT,Generator,Initial,Final,ReflectIn,ReflectOut
>::finish (void)
{ {
; ;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename DigestT, DigestT Generator> template <
typename DigestT,
DigestT Generator,
DigestT Initial,
DigestT Final,
bool ReflectIn,
bool ReflectOut
>
DigestT DigestT
crc<DigestT,Generator>::digest (void) const crc<
DigestT,Generator,Initial,Final,ReflectIn,ReflectOut
>::digest (void) const
{ {
return ~m_digest; return (ReflectIn != ReflectOut ? util::reverse (m_digest) : m_digest) ^ Final;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
template <typename DigestT, DigestT Generator> template <
typename DigestT,
DigestT Generator,
DigestT Initial,
DigestT Final,
bool ReflectIn,
bool ReflectOut
>
constexpr
std::array<DigestT,256> std::array<DigestT,256>
util::hash::crc<DigestT,Generator>::table (void) util::hash::crc<
DigestT,Generator,Initial,Final,ReflectIn,ReflectOut
>::table (void)
{ {
auto gen = Generator; std::array<digest_t,256> values {};
std::array<digest_t,256> value {}; if (ReflectIn) {
constexpr auto gen = util::reverse (Generator);
for (int i = 0; i < 256; ++i) { for (int i = 0; i < 256; ++i) {
digest_t c = i; digest_t c = i;
for (int k = 0; k < 8; ++k) { for (int k = 0; k < 8; ++k) {
if (c & 1) if (c & 1)
c = gen ^ (c >> 1); c = gen ^ (c >> 1);
else else
c >>= 1; c >>= 1;
}
values.data ()[i] = c;
} }
} else {
constexpr DigestT shift = sizeof (DigestT) * 8u - 8u;
constexpr DigestT highbit = DigestT(1) << (sizeof (DigestT) * 8u - 1u);
value[i] = c; for (int idx = 0; idx < 256; ++idx) {
DigestT c = DigestT (idx) << shift;
for (int i = 0; i < 8; ++i) {
if (c & highbit)
c = (c << DigestT (1)) ^ Generator;
else
c <<= DigestT(1);
}
values.data()[idx] = c;
}
} }
return value; return values;
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
template class util::hash::crc<uint32_t, 0xEDB88320>; // png template class util::hash::crc<uint32_t, 0x04C11DB7, 0xffffffff, 0xffffffff, true, true >; // crc32
//template class util::hash::crc<uint32_t, 0X04C11DB7>; // ogg template class util::hash::crc<uint32_t, 0x04C11DB7, 0xffffffff, 0xffffffff, false, false>; // crc32b
template class util::hash::crc<uint32_t, 0x1edc6f41, 0xffffffff, 0xffffffff, true, true>; // crc32c
template class util::hash::crc<uint32_t, 0xa833982b, 0xffffffff, 0xffffffff, true, true>; // crc32d
template class util::hash::crc<uint32_t, 0x04C11DB7, 0x00000000, 0x00000000, false, false>; // ogg
template class util::hash::crc<uint64_t, 0x42f0e1eba9ea3693, 0, 0, false, false>; // crc64

View File

@ -24,17 +24,25 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
namespace util::hash { namespace util { namespace hash {
// Implements the crc checksum (from ethernet, png, etc). // Implements the crc checksum (from ethernet, png, etc).
// Adapted from the PNG specification (ISO/IEC 15948:2003), appendix D. //
template <typename DigestT = uint32_t, DigestT Generator = 0xEDB88320> // Adapted from the PNG specification (ISO/IEC 15948:2003), appendix D and
// the public domain implementation of Ross Williams.
template <
typename DigestT,
DigestT Generator,
DigestT Initial,
DigestT Final,
bool ReflectIn,
bool ReflectOut
>
class crc { class crc {
public: public:
static_assert (std::is_same<DigestT, std::uint32_t>::value,
"only 32 bit crc is supported at this time");
using digest_t = DigestT; using digest_t = DigestT;
static constexpr auto generator = Generator;
crc () noexcept; crc () noexcept;
void reset (void) noexcept; void reset (void) noexcept;
@ -46,7 +54,7 @@ namespace util::hash {
digest_t digest (void) const; digest_t digest (void) const;
static static constexpr
std::array<DigestT,256> std::array<DigestT,256>
table (void); table (void);
@ -56,7 +64,12 @@ namespace util::hash {
static const std::array<DigestT,256> s_table; static const std::array<DigestT,256> s_table;
}; };
using crc32 = crc<uint32_t, 0xEDB88320>; using crc32 = crc<uint32_t, 0x04c11db7, 0xffffffff, 0xffffffff, true, true>;
} using crc32b = crc<uint32_t, 0x04c11db7, 0xffffffff, 0xffffffff, false, false>;
using crc32c = crc<uint32_t, 0x1edc6f41, 0xffffffff, 0xffffffff, true, true>;
using crc32d = crc<uint32_t, 0xa833982b, 0xffffffff, 0xffffffff, true, true>;
using crc64 = crc<uint64_t, 0x42f0e1eba9ea3693, 0, 0, false, false>;
} }
#endif #endif

View File

@ -22,7 +22,7 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
namespace util::hash { namespace util { namespace hash {
//template <class H, class InputT> //template <class H, class InputT>
template <class H, typename ...Args> template <class H, typename ...Args>
typename H::digest_t typename H::digest_t
@ -38,6 +38,6 @@ namespace util::hash {
return h.digest (); return h.digest ();
} }
} } }
#endif #endif

View File

@ -10,14 +10,20 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
static const static const
struct { struct {
uint32_t result; struct {
uint32_t crc32;
uint32_t crc32b;
uint32_t crc32c;
uint32_t crc32d;
uint64_t crc64;
} result;
const char *dat; const char *dat;
const char *msg; const char *msg;
} TESTS[] = { } TESTS[] = {
{ 0x00000000, "", "empty" }, { { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000000000000 }, "", "empty" },
{ 0xe8b7be43, "a", "single letter" }, { { 0xe8b7be43, 0x19939b6b, 0xc1d04330, 0x60819b69, 0x548f120162451c62 }, "a", "single letter" },
{ 0xa684c7c6, "0123456789", "10 digits" }, { { 0xa684c7c6, 0x96b0e4e0, 0x280c069e, 0x95ed974e, 0x2a71ab4164c3bbe8 }, "0123456789", "10 digits" },
{ 0x414fa339, "The quick brown fox jumps over the lazy dog", "quick brown fox" }, { { 0x414fa339, 0x459dee61, 0x22620404, 0x9d251c62, 0x41e05242ffa9883b }, "The quick brown fox jumps over the lazy dog", "quick brown fox" },
}; };
@ -31,9 +37,20 @@ main (int, char**)
auto first = t.dat; auto first = t.dat;
auto last = first + strlen (t.dat); auto last = first + strlen (t.dat);
auto result = util::hash::simple<util::hash::crc32> (first, last); #define TEST(KLASS) do { \
auto computed = \
util::hash::simple< \
util::hash::KLASS \
> (first, last); \
\
tap.expect_eq (t.result.KLASS, computed, "%s: %s", #KLASS, t.msg); \
} while (0)
tap.expect_eq (t.result, result, "%s %xu", t.msg, result); TEST(crc32);
TEST(crc32b);
TEST(crc32c);
TEST(crc32d);
TEST(crc64);
} }
return tap.status (); return tap.status ();

View File

@ -80,12 +80,12 @@ compute (const std::string &name,
const unsigned char *restrict first, const unsigned char *restrict first,
const unsigned char *restrict last) const unsigned char *restrict last)
{ {
#define stream(TYPE) do { \ #define stream(TYPE, ...) do { \
if (name != #TYPE) \ if (name != #TYPE) \
break; \ break; \
\ \
auto sum = util::hash::simple<util::hash::TYPE> ( \ auto sum = util::hash::simple<util::hash::TYPE> ( \
first, last \ first, last, ##__VA_ARGS__ \
); \ ); \
\ \
print_digest (std::cout, sum) << '\n'; \ print_digest (std::cout, sum) << '\n'; \