// vim:fileencoding=utf-8:foldmethod=marker #include "murmur3.h" #include "hasher.h" #include "../../../common/aliases/aliases.h" #include "../../../common/assert/assert.h" #include "../../../common/misc/misc_utils.h" wp_intern inline void validateMur3HasherData(const WpMur3HasherData *io); wp_intern inline u64 fmix64(u64 k); WpU128Hash wpX64Mur3Hasher128(WpU8Stream *bytes, void *hasher_io) { WpMur3HasherData *io = (WpMur3HasherData *)hasher_io; validateMur3HasherData(io); const i32 nblocks = (bytes->count * bytes->item_size) / 16; u64 h1 = io->seed; u64 h2 = io->seed; const u64 c1 = wpU64Const(0x87c37b91114253d5); const u64 c2 = wpU64Const(0x4cf5ad432745937f); //---------- // body for(int i = 0; i < nblocks; ++i) { u64 k1 = *((u64 *)wpStreamConsumeCount(u8, bytes, sizeof(u64))); u64 k2 = *((u64 *)wpStreamConsumeCount(u8, bytes, sizeof(u64))); k1 *= c1; k1 = wpMiscUtilsRotl64(k1, 31); k1 *= c2; h1 ^= k1; h1 = wpMiscUtilsRotl64(h1, 27); h1 += h2; h1 = h1 * 5 +0x52dce729; k2 *= c2; k2 = wpMiscUtilsRotl64(k2, 33); k2 *= c1; h2 ^= k2; h2 = wpMiscUtilsRotl64(h2, 31); h2 += h1; h2 = h2*5+0x38495ab5; } //---------- // tail const u8 *tail = wpStreamConsumeCount(u8, bytes, bytes->count - bytes->position); u64 k1 = 0; u64 k2 = 0; u64 len = bytes->count * bytes->item_size; switch(len & 15) { case 15: k2 ^= ((u64)tail[14]) << 48; case 14: k2 ^= ((u64)tail[13]) << 40; case 13: k2 ^= ((u64)tail[12]) << 32; case 12: k2 ^= ((u64)tail[11]) << 24; case 11: k2 ^= ((u64)tail[10]) << 16; case 10: k2 ^= ((u64)tail[ 9]) << 8; case 9: k2 ^= ((u64)tail[ 8]) << 0; k2 *= c2; k2 = wpMiscUtilsRotl64(k2,33); k2 *= c1; h2 ^= k2; case 8: k1 ^= ((u64)tail[ 7]) << 56; case 7: k1 ^= ((u64)tail[ 6]) << 48; case 6: k1 ^= ((u64)tail[ 5]) << 40; case 5: k1 ^= ((u64)tail[ 4]) << 32; case 4: k1 ^= ((u64)tail[ 3]) << 24; case 3: k1 ^= ((u64)tail[ 2]) << 16; case 2: k1 ^= ((u64)tail[ 1]) << 8; case 1: k1 ^= ((u64)tail[ 0]) << 0; k1 *= c1; k1 = wpMiscUtilsRotl64(k1,31); k1 *= c2; h1 ^= k1; }; //---------- // finalization h1 ^= len; h2 ^= len; h1 += h2; h2 += h1; h1 = fmix64(h1); h2 = fmix64(h2); h1 += h2; h2 += h1; return (WpU128Hash){ .hash = { [0] = h1, [1] = h2 } }; } wp_intern inline void validateMur3HasherData(const WpMur3HasherData *data) { wpRuntimeAssert(data->magic == WP_MUR3_HASHER_MAGIC, "Invalid Murmur3 hash data"); } wp_intern inline u64 fmix64(u64 k) { k ^= k >> 33; k *= wpU64Const(0xff51afd7ed558ccd); k ^= k >> 33; k *= wpU64Const(0xc4ceb9fe1a85ec53); k ^= k >> 33; return k; }