github.com/m3db/stackmurmur3@v1.0.1/murmur32.go (about) 1 package murmur3 2 3 // http://code.google.com/p/guava-libraries/source/browse/guava/src/com/google/common/hash/Murmur3_32HashFunction.java 4 5 import ( 6 "fmt" 7 "unsafe" 8 ) 9 10 const ( 11 c1_32 uint32 = 0xcc9e2d51 12 c2_32 uint32 = 0x1b873593 13 ) 14 15 // Digest32 represents a partial evaluation of a 32 bits hash. 16 type Digest32 struct { 17 digest 18 h1 uint32 // Unfinalized running hash. 19 } 20 21 // New32 returns new 32-bit hasher 22 func New32() Digest32 { return New32WithSeed(0) } 23 24 // New32WithSeed returns new 32-bit hasher set with explicit seed value 25 func New32WithSeed(seed uint32) Digest32 { 26 return Digest32{digest: digest{seed: seed}, h1: seed} 27 } 28 29 func (d Digest32) Size() int { 30 return 4 31 } 32 33 func (d Digest32) Sum(b []byte) []byte { 34 h := d.Sum32() 35 return append(b, byte(h>>24), byte(h>>16), byte(h>>8), byte(h)) 36 } 37 38 // Digest as many blocks as possible. 39 func (d Digest32) bmix(p []byte) (Digest32, []byte) { 40 h1 := d.h1 41 42 nblocks := len(p) / 4 43 for i := 0; i < nblocks; i++ { 44 k1 := *(*uint32)(unsafe.Pointer(&p[i*4])) 45 46 k1 *= c1_32 47 k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) 48 k1 *= c2_32 49 50 h1 ^= k1 51 h1 = (h1 << 13) | (h1 >> 19) // rotl32(h1, 13) 52 h1 = h1*4 + h1 + 0xe6546b64 53 } 54 d.h1 = h1 55 return d, p[nblocks*d.Size():] 56 } 57 58 func (d Digest32) bmixbuf() Digest32 { 59 h1 := d.h1 60 61 if d.tail != d.Size() { 62 panic(fmt.Errorf("expected full block")) 63 } 64 65 k1 := d.loadUint32(0) 66 67 k1 *= c1_32 68 k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) 69 k1 *= c2_32 70 71 h1 ^= k1 72 h1 = (h1 << 13) | (h1 >> 19) // rotl32(h1, 13) 73 h1 = h1*4 + h1 + 0xe6546b64 74 75 d.h1 = h1 76 d.tail = 0 77 return d 78 } 79 80 func (d Digest32) Sum32() (h1 uint32) { 81 82 h1 = d.h1 83 84 var k1 uint32 85 switch d.tail & 3 { 86 case 3: 87 k1 ^= uint32(d.buf[2]) << 16 88 fallthrough 89 case 2: 90 k1 ^= uint32(d.buf[1]) << 8 91 fallthrough 92 case 1: 93 k1 ^= uint32(d.buf[0]) 94 k1 *= c1_32 95 k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) 96 k1 *= c2_32 97 h1 ^= k1 98 } 99 100 h1 ^= uint32(d.clen) 101 102 h1 ^= h1 >> 16 103 h1 *= 0x85ebca6b 104 h1 ^= h1 >> 13 105 h1 *= 0xc2b2ae35 106 h1 ^= h1 >> 16 107 108 return h1 109 } 110 111 // Write will write bytes to the digest and return a new digest 112 // representing the derived digest. 113 func (d Digest32) Write(p []byte) Digest32 { 114 n := len(p) 115 d.clen += n 116 117 if d.tail > 0 { 118 // Stick back pending bytes. 119 nfree := d.Size() - d.tail // nfree ∈ [1, d.size-1]. 120 if len(p) <= int(nfree) { 121 // Everything can fit in buf 122 for i := 0; i < len(p); i++ { 123 d.buf[d.tail] = p[i] 124 d.tail++ 125 } 126 if len(p) == int(nfree) { 127 d = d.bmixbuf() 128 } 129 return d 130 } 131 132 // One full block can be formed. 133 add := p[:nfree] 134 for i := 0; i < len(add); i++ { 135 d.buf[d.tail] = add[i] 136 d.tail++ 137 } 138 139 // Process the full block 140 d = d.bmixbuf() 141 142 p = p[nfree:] 143 } 144 145 d, tail := d.bmix(p) 146 147 // Keep own copy of the 0 to Size()-1 pending bytes. 148 d.tail = len(tail) 149 for i := 0; i < d.tail; i++ { 150 d.buf[i] = tail[i] 151 } 152 153 return d 154 } 155 156 /* 157 func rotl32(x uint32, r byte) uint32 { 158 return (x << r) | (x >> (32 - r)) 159 } 160 */ 161 162 // Sum32 returns the MurmurHash3 sum of data. It is equivalent to the 163 // following sequence (without the extra burden and the extra allocation): 164 // hasher := New32() 165 // hasher.Write(data) 166 // return hasher.Sum32() 167 func Sum32(data []byte) uint32 { return Sum32WithSeed(data, 0) } 168 169 // Sum32WithSeed returns the MurmurHash3 sum of data. It is equivalent to the 170 // following sequence (without the extra burden and the extra allocation): 171 // hasher := New32WithSeed(seed) 172 // hasher.Write(data) 173 // return hasher.Sum32() 174 func Sum32WithSeed(data []byte, seed uint32) uint32 { 175 h1 := seed 176 177 nblocks := len(data) / 4 178 var p uintptr 179 if len(data) > 0 { 180 p = uintptr(unsafe.Pointer(&data[0])) 181 } 182 p1 := p + uintptr(4*nblocks) 183 for ; p < p1; p += 4 { 184 k1 := *(*uint32)(unsafe.Pointer(p)) 185 186 k1 *= c1_32 187 k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) 188 k1 *= c2_32 189 190 h1 ^= k1 191 h1 = (h1 << 13) | (h1 >> 19) // rotl32(h1, 13) 192 h1 = h1*4 + h1 + 0xe6546b64 193 } 194 195 tail := data[nblocks*4:] 196 197 var k1 uint32 198 switch len(tail) & 3 { 199 case 3: 200 k1 ^= uint32(tail[2]) << 16 201 fallthrough 202 case 2: 203 k1 ^= uint32(tail[1]) << 8 204 fallthrough 205 case 1: 206 k1 ^= uint32(tail[0]) 207 k1 *= c1_32 208 k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) 209 k1 *= c2_32 210 h1 ^= k1 211 } 212 213 h1 ^= uint32(len(data)) 214 215 h1 ^= h1 >> 16 216 h1 *= 0x85ebca6b 217 h1 ^= h1 >> 13 218 h1 *= 0xc2b2ae35 219 h1 ^= h1 >> 16 220 221 return h1 222 }