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 <cruft/util/bitwise.hpp>
#include <array>
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>
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>
crc<DigestT,Generator>::crc () noexcept
template <
typename DigestT,
DigestT Generator,
DigestT Initial,
DigestT Final,
bool ReflectIn,
bool ReflectOut
>
crc<
DigestT,Generator,Initial,Final,ReflectIn,ReflectOut
>::crc () noexcept
{
reset ();
}
//-----------------------------------------------------------------------------
template <typename DigestT, DigestT Generator>
template <
typename DigestT,
DigestT Generator,
DigestT Initial,
DigestT Final,
bool ReflectIn,
bool ReflectOut
>
void
crc<DigestT,Generator>::reset (void) noexcept
crc<
DigestT,Generator,Initial,Final,ReflectIn,ReflectOut
>::reset (void) noexcept
{
m_digest = 0;
m_digest = ~m_digest;
m_digest = Initial;
}
///////////////////////////////////////////////////////////////////////////////
template <typename DigestT, DigestT Generator>
template <
typename DigestT,
DigestT Generator,
DigestT Initial,
DigestT Final,
bool ReflectIn,
bool ReflectOut
>
void
crc<DigestT,Generator>::update (const uint8_t *restrict first,
const uint8_t *restrict last) noexcept
crc<
DigestT,Generator,Initial,Final,ReflectIn,ReflectOut
>::update (const uint8_t *restrict first,
const uint8_t *restrict last) noexcept
{
CHECK_LE (first, last);
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
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);
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
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
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>
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) {
digest_t c = i;
for (int i = 0; i < 256; ++i) {
digest_t c = i;
for (int k = 0; k < 8; ++k) {
if (c & 1)
c = gen ^ (c >> 1);
else
c >>= 1;
for (int k = 0; k < 8; ++k) {
if (c & 1)
c = gen ^ (c >> 1);
else
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>; // ogg
template class util::hash::crc<uint32_t, 0x04C11DB7, 0xffffffff, 0xffffffff, true, true >; // crc32
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).
// 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 {
public:
static_assert (std::is_same<DigestT, std::uint32_t>::value,
"only 32 bit crc is supported at this time");
using digest_t = DigestT;
static constexpr auto generator = Generator;
crc () noexcept;
void reset (void) noexcept;
@ -46,7 +54,7 @@ namespace util::hash {
digest_t digest (void) const;
static
static constexpr
std::array<DigestT,256>
table (void);
@ -56,7 +64,12 @@ namespace util::hash {
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

View File

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

View File

@ -10,14 +10,20 @@
///////////////////////////////////////////////////////////////////////////////
static const
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 *msg;
} TESTS[] = {
{ 0x00000000, "", "empty" },
{ 0xe8b7be43, "a", "single letter" },
{ 0xa684c7c6, "0123456789", "10 digits" },
{ 0x414fa339, "The quick brown fox jumps over the lazy dog", "quick brown fox" },
{ { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000000000000 }, "", "empty" },
{ { 0xe8b7be43, 0x19939b6b, 0xc1d04330, 0x60819b69, 0x548f120162451c62 }, "a", "single letter" },
{ { 0xa684c7c6, 0x96b0e4e0, 0x280c069e, 0x95ed974e, 0x2a71ab4164c3bbe8 }, "0123456789", "10 digits" },
{ { 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 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 ();

View File

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