hash/crc: adapt implementation from png appendix

This commit is contained in:
Danny Robson 2017-01-25 16:12:12 +11:00
parent ca7f4b739a
commit 5a25f07f8e
4 changed files with 101 additions and 38 deletions

View File

@ -464,6 +464,7 @@ if (TESTS)
geom/aabb
geom/ray
hash/checksum
hash/crc
hash/fasthash
hash/hmac
hash/hotp

View File

@ -18,13 +18,53 @@
#include "../debug.hpp"
#include <array>
using util::hash::crc32;
///////////////////////////////////////////////////////////////////////////////
static
std::array<uint32_t,256>
make_table (void)
{
std::array<uint32_t,256> value {};
for (int i = 0; i < 256; ++i) {
std::uint32_t c = i;
for (int k = 0; k < 8; ++k) {
if (c & 1)
c = 0xEDB88320L ^ (c >> 1);
else
c >>= 1;
}
value[i] = c;
}
return value;
};
//-----------------------------------------------------------------------------
static std::array<uint32_t,256> table = make_table ();
///////////////////////////////////////////////////////////////////////////////
crc32::crc32 () noexcept
{
reset ();
}
//-----------------------------------------------------------------------------
void
crc32::reset (void)
{ ; }
crc32::reset (void) noexcept
{
m_digest = 0;
m_digest = ~m_digest;
}
///////////////////////////////////////////////////////////////////////////////
@ -34,55 +74,32 @@ crc32::update (const uint8_t *restrict first,
{
CHECK_LE (first, last);
return update (first, last - first);
for (auto cursor = first; cursor != last; ++cursor) {
m_digest = table[*cursor ^ (m_digest & 0xFF)] ^ (m_digest >> 8u);
}
}
//-----------------------------------------------------------------------------
void
crc32::update (const void *restrict, size_t) noexcept
crc32::update (const void *restrict _data, size_t len) noexcept
{
not_implemented ();
/*
const uint8_t *restrict data = static_cast<const uint8_t*> (_data);
static const uint32_t POLYNOMIAL = hton (static_cast<uint32_t>(0x04C11DB7));
uint64_t bits = 0;
unsigned int i = 0;
if (size == 0)
return POLYNOMIAL;
switch (size) {
default: bits |= static_cast<uint64_t>(data[3]) << 32U;
case 3: bits |= static_cast<uint64_t>(data[2]) << 40U;
case 2: bits |= static_cast<uint64_t>(data[1]) << 48U;
case 1: bits |= static_cast<uint64_t>(data[0]) << 56U;
}
for (size_t i = 0; i < size; ++i) {
for (unsigned j = 0; j < 32; ++j) {
bool mix = bits 0x7000000000000000ULL;
bits <<= 1;
if (mix)
bits ^= POLYNOMIAL << 32;
}
}
*/
auto data = reinterpret_cast<const uint8_t *restrict> (_data);
return update(data, data + len);
}
//-----------------------------------------------------------------------------
void
crc32::finish (void)
{ not_implemented (); }
{
;
}
//-----------------------------------------------------------------------------
typename crc32::digest_t
crc32::digest (void) const
{ not_implemented (); }
{
return ~m_digest;
}

View File

@ -27,7 +27,9 @@ namespace util::hash {
public:
using digest_t = uint32_t;
void reset (void);
crc32 () noexcept;
void reset (void) noexcept;
void update (const void *restrict data, size_t bytes) noexcept;
void update (const uint8_t *restrict first, const uint8_t *restrict last) noexcept;
@ -35,6 +37,9 @@ namespace util::hash {
void finish (void);
digest_t digest (void) const;
private:
digest_t m_digest;
};
}

40
test/hash/crc.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "tap.hpp"
#include "hash/crc.hpp"
#include "hash/simple.hpp"
#include <cstdint>
#include <utility>
#include <vector>
///////////////////////////////////////////////////////////////////////////////
static const
struct {
uint32_t 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" },
};
///////////////////////////////////////////////////////////////////////////////
int
main (int, char**)
{
util::TAP::logger tap;
for (const auto &t: TESTS) {
auto first = t.dat;
auto last = first + strlen (t.dat);
auto result = util::hash::simple<util::hash::crc32> (first, last);
tap.expect_eq (t.result, result, "%s %xu", t.msg, result);
}
return tap.status ();
}