From 1da862044e500de24e0dd6db42116248c7302e19 Mon Sep 17 00:00:00 2001 From: Alex Schneider <alex.schneider@sevenval.com> Date: Fri, 7 Feb 2020 09:35:43 +0100 Subject: [PATCH] Faster and dependency-free MurmurHash3_32 implementation --- murmur32.go | 61 ++++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/murmur32.go b/murmur32.go index 552976a..9a6e3c0 100644 --- a/murmur32.go +++ b/murmur32.go @@ -18,6 +18,9 @@ var ( const ( c1_32 uint32 = 0xcc9e2d51 c2_32 uint32 = 0x1b873593 + c3_32 uint32 = 0x85ebca6b + c4_32 uint32 = 0xc2b2ae35 + c5_32 uint32 = 0xe6546b64 ) // digest32 represents a partial evaluation of a 32 bites hash. @@ -114,49 +117,39 @@ func Sum32WithSeed(data []byte, seed uint32) uint32 { h1 := seed - nblocks := len(data) / 4 - var p uintptr - if len(data) > 0 { - p = uintptr(unsafe.Pointer(&data[0])) - } - p1 := p + uintptr(4*nblocks) - for ; p < p1; p += 4 { - k1 := *(*uint32)(unsafe.Pointer(p)) - - k1 *= c1_32 - k1 = bits.RotateLeft32(k1, 15) - k1 *= c2_32 + dlen := len(data) + var k uint32 - h1 ^= k1 - h1 = bits.RotateLeft32(h1, 13) - h1 = h1*4 + h1 + 0xe6546b64 + for i := dlen >> 2; i != 0; i-- { + k = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) + data = data[4:] + h1 ^= mix(k) + h1 = (h1 << 13) | (h1 >> 19) + h1 = h1*5 + c5_32 } - tail := data[nblocks*4:] - - var k1 uint32 - switch len(tail) & 3 { - case 3: - k1 ^= uint32(tail[2]) << 16 - fallthrough - case 2: - k1 ^= uint32(tail[1]) << 8 - fallthrough - case 1: - k1 ^= uint32(tail[0]) - k1 *= c1_32 - k1 = bits.RotateLeft32(k1, 15) - k1 *= c2_32 - h1 ^= k1 + k = 0 + for i := dlen & 3; i != 0; i-- { + k <<= 8 + k |= uint32(data[i-1]) } - h1 ^= uint32(len(data)) + h1 ^= mix(k) + h1 ^= uint32(dlen) h1 ^= h1 >> 16 - h1 *= 0x85ebca6b + h1 *= c3_32 h1 ^= h1 >> 13 - h1 *= 0xc2b2ae35 + h1 *= c4_32 h1 ^= h1 >> 16 return h1 } + +func mix(k uint32) uint32 { + k *= c1_32 + k = (k << 15) | (k >> 17) + k *= c2_32 + + return k +}