cosmopolitan/third_party/duktape/duk_util_hashbytes.c

58 lines
1.5 KiB
C

/*
* Hash function duk_util_hashbytes().
*
* Currently, 32-bit MurmurHash2.
*
* Don't rely on specific hash values; hash function may be endianness
* dependent, for instance.
*/
#include "third_party/duktape/duk_internal.h"
#if defined(DUK_USE_STRHASH_DENSE)
/* 'magic' constants for Murmurhash2 */
#define DUK__MAGIC_M ((duk_uint32_t) 0x5bd1e995UL)
#define DUK__MAGIC_R 24
DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed) {
duk_uint32_t h = seed ^ ((duk_uint32_t) len);
while (len >= 4) {
/* Portability workaround is required for platforms without
* unaligned access. The replacement code emulates little
* endian access even on big endian architectures, which is
* OK as long as it is consistent for a build.
*/
#if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS)
duk_uint32_t k = *((const duk_uint32_t *) (const void *) data);
#else
duk_uint32_t k = ((duk_uint32_t) data[0]) |
(((duk_uint32_t) data[1]) << 8) |
(((duk_uint32_t) data[2]) << 16) |
(((duk_uint32_t) data[3]) << 24);
#endif
k *= DUK__MAGIC_M;
k ^= k >> DUK__MAGIC_R;
k *= DUK__MAGIC_M;
h *= DUK__MAGIC_M;
h ^= k;
data += 4;
len -= 4;
}
switch (len) {
case 3: h ^= data[2] << 16;
case 2: h ^= data[1] << 8;
case 1: h ^= data[0];
h *= DUK__MAGIC_M;
}
h ^= h >> 13;
h *= DUK__MAGIC_M;
h ^= h >> 15;
return h;
}
#endif /* DUK_USE_STRHASH_DENSE */