Cavil-Matcher
view release on metacpan or search on metacpan
src/SpookyV2.cpp view on Meta::CPAN
uint64* hash1,
uint64* hash2)
{
if (length < sc_bufSize) {
Short(message, length, hash1, hash2);
return;
}
uint64 h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11;
uint64 buf[sc_numVars];
uint64* end;
union {
const uint8* p8;
uint64* p64;
size_t i;
} u;
size_t remainder;
h0 = h3 = h6 = h9 = *hash1;
h1 = h4 = h7 = h10 = *hash2;
h2 = h5 = h8 = h11 = sc_const;
u.p8 = (const uint8*)message;
end = u.p64 + (length / sc_blockSize) * sc_numVars;
// handle all whole sc_blockSize blocks of bytes
if (ALLOW_UNALIGNED_READS || ((u.i & 0x7) == 0)) {
while (u.p64 < end) {
Mix(u.p64, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11);
u.p64 += sc_numVars;
}
} else {
while (u.p64 < end) {
memcpy(buf, u.p64, sc_blockSize);
Mix(buf, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11);
u.p64 += sc_numVars;
}
}
// handle the last partial block of sc_blockSize bytes
remainder = (length - ((const uint8*)end - (const uint8*)message));
memcpy(buf, end, remainder);
memset(((uint8*)buf) + remainder, 0, sc_blockSize - remainder);
((uint8*)buf)[sc_blockSize - 1] = remainder;
// do some final mixing
End(buf, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11);
*hash1 = h0;
*hash2 = h1;
}
// init spooky state
void SpookyHash::Init(uint64 seed1, uint64 seed2)
{
m_length = 0;
m_remainder = 0;
m_state[0] = seed1;
m_state[1] = seed2;
}
// add a message fragment to the state
void SpookyHash::Update(const void* message, size_t length)
{
uint64 h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11;
size_t newLength = length + m_remainder;
uint8 remainder;
union {
const uint8* p8;
uint64* p64;
size_t i;
} u;
const uint64* end;
// Is this message fragment too short? If it is, stuff it away.
if (newLength < sc_bufSize) {
memcpy(&((uint8*)m_data)[m_remainder], message, length);
m_length = length + m_length;
m_remainder = (uint8)newLength;
return;
}
// init the variables
if (m_length < sc_bufSize) {
h0 = h3 = h6 = h9 = m_state[0];
h1 = h4 = h7 = h10 = m_state[1];
h2 = h5 = h8 = h11 = sc_const;
} else {
h0 = m_state[0];
h1 = m_state[1];
h2 = m_state[2];
h3 = m_state[3];
h4 = m_state[4];
h5 = m_state[5];
h6 = m_state[6];
h7 = m_state[7];
h8 = m_state[8];
h9 = m_state[9];
h10 = m_state[10];
h11 = m_state[11];
}
m_length = length + m_length;
// if we've got anything stuffed away, use it now
if (m_remainder) {
uint8 prefix = sc_bufSize - m_remainder;
memcpy(&(((uint8*)m_data)[m_remainder]), message, prefix);
u.p64 = m_data;
Mix(u.p64, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11);
Mix(&u.p64[sc_numVars], h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11);
u.p8 = ((const uint8*)message) + prefix;
length -= prefix;
} else {
u.p8 = (const uint8*)message;
}
// handle all whole blocks of sc_blockSize bytes
end = u.p64 + (length / sc_blockSize) * sc_numVars;
remainder = (uint8)(length - ((const uint8*)end - u.p8));
if (ALLOW_UNALIGNED_READS || (u.i & 0x7) == 0) {
while (u.p64 < end) {
Mix(u.p64, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11);
u.p64 += sc_numVars;
}
} else {
while (u.p64 < end) {
memcpy(m_data, u.p8, sc_blockSize);
Mix(m_data, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11);
u.p64 += sc_numVars;
}
}
// stuff away the last few bytes
m_remainder = remainder;
memcpy(m_data, end, remainder);
// stuff away the variables
m_state[0] = h0;
m_state[1] = h1;
m_state[2] = h2;
m_state[3] = h3;
m_state[4] = h4;
m_state[5] = h5;
m_state[6] = h6;
m_state[7] = h7;
m_state[8] = h8;
m_state[9] = h9;
m_state[10] = h10;
m_state[11] = h11;
}
// report the hash for the concatenation of all message fragments so far
void SpookyHash::Final(uint64* hash1, uint64* hash2)
{
// init the variables
if (m_length < sc_bufSize) {
*hash1 = m_state[0];
*hash2 = m_state[1];
Short(m_data, m_length, hash1, hash2);
return;
}
const uint64* data = (const uint64*)m_data;
uint8 remainder = m_remainder;
uint64 h0 = m_state[0];
uint64 h1 = m_state[1];
uint64 h2 = m_state[2];
uint64 h3 = m_state[3];
uint64 h4 = m_state[4];
uint64 h5 = m_state[5];
uint64 h6 = m_state[6];
uint64 h7 = m_state[7];
uint64 h8 = m_state[8];
uint64 h9 = m_state[9];
uint64 h10 = m_state[10];
uint64 h11 = m_state[11];
if (remainder >= sc_blockSize) {
// m_data can contain two blocks; handle any whole first block
Mix(data, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11);
data += sc_numVars;
remainder -= sc_blockSize;
}
// mix in the last partial block, and the length mod sc_blockSize
memset(&((uint8*)data)[remainder], 0, (sc_blockSize - remainder));
((uint8*)data)[sc_blockSize - 1] = remainder;
// do some final mixing
End(data, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11);
*hash1 = h0;
*hash2 = h1;
}
( run in 0.541 second using v1.01-cache-2.11-cpan-364913b4093 )