squall/storm/string/bjhash.cpp
2020-11-14 17:20:39 -06:00

87 lines
2.2 KiB
C++

#include "storm/string/bjhash.hpp"
#define mix(a, b, c) \
{ \
a -= b; \
a -= c; \
a ^= (c >> 13); \
b -= c; \
b -= a; \
b ^= (a << 8); \
c -= a; \
c -= b; \
c ^= (b >> 13); \
a -= b; \
a -= c; \
a ^= (c >> 12); \
b -= c; \
b -= a; \
b ^= (a << 16); \
c -= a; \
c -= b; \
c ^= (b >> 5); \
a -= b; \
a -= c; \
a ^= (c >> 3); \
b -= c; \
b -= a; \
b ^= (a << 10); \
c -= a; \
c -= b; \
c ^= (b >> 15); \
}
uint32_t bjhash(uint8_t* k, uint32_t length, uint32_t initval) {
uint32_t a, b, c, len;
len = length; // Set up the internal state
a = b = 0x9e3779b9; // The golden ratio; an arbitrary value
c = initval; // The previous hash value
// Handle most of the key
while (len >= 12) {
a += (k[0] + ((uint32_t)k[1] << 8) + ((uint32_t)k[2] << 16) + ((uint32_t)k[3] << 24));
b += (k[4] + ((uint32_t)k[5] << 8) + ((uint32_t)k[6] << 16) + ((uint32_t)k[7] << 24));
c += (k[8] + ((uint32_t)k[9] << 8) + ((uint32_t)k[10] << 16) + ((uint32_t)k[11] << 24));
mix(a, b, c);
k += 12;
len -= 12;
}
// Handle the last 11 bytes
c += length;
switch (len) {
// All the case statements fall through
case 11:
c += ((uint32_t)k[10] << 24);
case 10:
c += ((uint32_t)k[9] << 16);
case 9:
c += ((uint32_t)k[8] << 8);
case 8:
// The first byte of c is reserved for the length
b += ((uint32_t)k[7] << 24);
case 7:
b += ((uint32_t)k[6] << 16);
case 6:
b += ((uint32_t)k[5] << 8);
case 5:
b += k[4];
case 4:
a += ((uint32_t)k[3] << 24);
case 3:
a += ((uint32_t)k[2] << 16);
case 2:
a += ((uint32_t)k[1] << 8);
case 1:
a += k[0];
case 0:;
// Nothing left to add
}
mix(a, b, c);
// Report the result
return c;
}