hash/crc: parameterise crc for reflection, and 64 bits
This commit is contained in:
parent
2bd094ab9f
commit
bec24535fc
171
hash/crc.cpp
171
hash/crc.cpp
@ -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
|
31
hash/crc.hpp
31
hash/crc.hpp
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 ();
|
||||
|
@ -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'; \
|
||||
|
Loading…
Reference in New Issue
Block a user