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 "../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
|
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).
|
// 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
|
||||||
|
@ -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
|
||||||
|
@ -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 ();
|
||||||
|
@ -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'; \
|
||||||
|
Loading…
Reference in New Issue
Block a user