├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── murmur.go ├── murmur128.go ├── murmur32.go ├── murmur64.go └── murmur_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.x 5 | - master 6 | 7 | script: go test 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013, Sébastien Paolacci. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the library nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | murmur3 2 | ======= 3 | 4 | [![Build Status](https://travis-ci.org/spaolacci/murmur3.svg?branch=master)](https://travis-ci.org/spaolacci/murmur3) 5 | 6 | Native Go implementation of Austin Appleby's third MurmurHash revision (aka 7 | MurmurHash3). 8 | 9 | Reference algorithm has been slightly hacked as to support the streaming mode 10 | required by Go's standard [Hash interface](http://golang.org/pkg/hash/#Hash). 11 | 12 | 13 | Benchmarks 14 | ---------- 15 | 16 | Go tip as of 2014-06-12 (i.e almost go1.3), core i7 @ 3.4 Ghz. All runs 17 | include hasher instantiation and sequence finalization. 18 | 19 |
20 | 
21 | Benchmark32_1        500000000     7.69 ns/op      130.00 MB/s
22 | Benchmark32_2        200000000     8.83 ns/op      226.42 MB/s
23 | Benchmark32_4        500000000     7.99 ns/op      500.39 MB/s
24 | Benchmark32_8        200000000     9.47 ns/op      844.69 MB/s
25 | Benchmark32_16       100000000     12.1 ns/op     1321.61 MB/s
26 | Benchmark32_32       100000000     18.3 ns/op     1743.93 MB/s
27 | Benchmark32_64        50000000     30.9 ns/op     2071.64 MB/s
28 | Benchmark32_128       50000000     57.6 ns/op     2222.96 MB/s
29 | Benchmark32_256       20000000      116 ns/op     2188.60 MB/s
30 | Benchmark32_512       10000000      226 ns/op     2260.59 MB/s
31 | Benchmark32_1024       5000000      452 ns/op     2263.73 MB/s
32 | Benchmark32_2048       2000000      891 ns/op     2296.02 MB/s
33 | Benchmark32_4096       1000000     1787 ns/op     2290.92 MB/s
34 | Benchmark32_8192        500000     3593 ns/op     2279.68 MB/s
35 | Benchmark128_1       100000000     26.1 ns/op       38.33 MB/s
36 | Benchmark128_2       100000000     29.0 ns/op       69.07 MB/s
37 | Benchmark128_4        50000000     29.8 ns/op      134.17 MB/s
38 | Benchmark128_8        50000000     31.6 ns/op      252.86 MB/s
39 | Benchmark128_16      100000000     26.5 ns/op      603.42 MB/s
40 | Benchmark128_32      100000000     28.6 ns/op     1117.15 MB/s
41 | Benchmark128_64       50000000     35.5 ns/op     1800.97 MB/s
42 | Benchmark128_128      50000000     50.9 ns/op     2515.50 MB/s
43 | Benchmark128_256      20000000     76.9 ns/op     3330.11 MB/s
44 | Benchmark128_512      20000000      135 ns/op     3769.09 MB/s
45 | Benchmark128_1024     10000000      250 ns/op     4094.38 MB/s
46 | Benchmark128_2048      5000000      477 ns/op     4290.75 MB/s
47 | Benchmark128_4096      2000000      940 ns/op     4353.29 MB/s
48 | Benchmark128_8192      1000000     1838 ns/op     4455.47 MB/s
49 | 
50 | 
51 | 52 | 53 |
54 | 
55 | benchmark              Go1.0 MB/s    Go1.1 MB/s  speedup    Go1.2 MB/s  speedup    Go1.3 MB/s  speedup
56 | Benchmark32_1               98.90        118.59    1.20x        114.79    0.97x        130.00    1.13x
57 | Benchmark32_2              168.04        213.31    1.27x        210.65    0.99x        226.42    1.07x
58 | Benchmark32_4              414.01        494.19    1.19x        490.29    0.99x        500.39    1.02x
59 | Benchmark32_8              662.19        836.09    1.26x        836.46    1.00x        844.69    1.01x
60 | Benchmark32_16             917.46       1304.62    1.42x       1297.63    0.99x       1321.61    1.02x
61 | Benchmark32_32            1141.93       1737.54    1.52x       1728.24    0.99x       1743.93    1.01x
62 | Benchmark32_64            1289.47       2039.51    1.58x       2038.20    1.00x       2071.64    1.02x
63 | Benchmark32_128           1299.23       2097.63    1.61x       2177.13    1.04x       2222.96    1.02x
64 | Benchmark32_256           1369.90       2202.34    1.61x       2213.15    1.00x       2188.60    0.99x
65 | Benchmark32_512           1399.56       2255.72    1.61x       2264.49    1.00x       2260.59    1.00x
66 | Benchmark32_1024          1410.90       2285.82    1.62x       2270.99    0.99x       2263.73    1.00x
67 | Benchmark32_2048          1422.14       2297.62    1.62x       2269.59    0.99x       2296.02    1.01x
68 | Benchmark32_4096          1420.53       2307.81    1.62x       2273.43    0.99x       2290.92    1.01x
69 | Benchmark32_8192          1424.79       2312.87    1.62x       2286.07    0.99x       2279.68    1.00x
70 | Benchmark128_1               8.32         30.15    3.62x         30.84    1.02x         38.33    1.24x
71 | Benchmark128_2              16.38         59.72    3.65x         59.37    0.99x         69.07    1.16x
72 | Benchmark128_4              32.26        112.96    3.50x        114.24    1.01x        134.17    1.17x
73 | Benchmark128_8              62.68        217.88    3.48x        218.18    1.00x        252.86    1.16x
74 | Benchmark128_16            128.47        451.57    3.51x        474.65    1.05x        603.42    1.27x
75 | Benchmark128_32            246.18        910.42    3.70x        871.06    0.96x       1117.15    1.28x
76 | Benchmark128_64            449.05       1477.64    3.29x       1449.24    0.98x       1800.97    1.24x
77 | Benchmark128_128           762.61       2222.42    2.91x       2217.30    1.00x       2515.50    1.13x
78 | Benchmark128_256          1179.92       3005.46    2.55x       2931.55    0.98x       3330.11    1.14x
79 | Benchmark128_512          1616.51       3590.75    2.22x       3592.08    1.00x       3769.09    1.05x
80 | Benchmark128_1024         1964.36       3979.67    2.03x       4034.01    1.01x       4094.38    1.01x
81 | Benchmark128_2048         2225.07       4156.93    1.87x       4244.17    1.02x       4290.75    1.01x
82 | Benchmark128_4096         2360.15       4299.09    1.82x       4392.35    1.02x       4353.29    0.99x
83 | Benchmark128_8192         2411.50       4356.84    1.81x       4480.68    1.03x       4455.47    0.99x
84 | 
85 | 
86 | 87 | -------------------------------------------------------------------------------- /murmur.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013, Sébastien Paolacci. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | /* 6 | Package murmur3 implements Austin Appleby's non-cryptographic MurmurHash3. 7 | 8 | Reference implementation: 9 | http://code.google.com/p/smhasher/wiki/MurmurHash3 10 | 11 | History, characteristics and (legacy) perfs: 12 | https://sites.google.com/site/murmurhash/ 13 | https://sites.google.com/site/murmurhash/statistics 14 | */ 15 | package murmur3 16 | 17 | type bmixer interface { 18 | bmix(p []byte) (tail []byte) 19 | Size() (n int) 20 | reset() 21 | } 22 | 23 | type digest struct { 24 | clen int // Digested input cumulative length. 25 | tail []byte // 0 to Size()-1 bytes view of `buf'. 26 | buf [16]byte // Expected (but not required) to be Size() large. 27 | seed uint32 // Seed for initializing the hash. 28 | bmixer 29 | } 30 | 31 | func (d *digest) BlockSize() int { return 1 } 32 | 33 | func (d *digest) Write(p []byte) (n int, err error) { 34 | n = len(p) 35 | d.clen += n 36 | 37 | if len(d.tail) > 0 { 38 | // Stick back pending bytes. 39 | nfree := d.Size() - len(d.tail) // nfree ∈ [1, d.Size()-1]. 40 | if nfree < len(p) { 41 | // One full block can be formed. 42 | block := append(d.tail, p[:nfree]...) 43 | p = p[nfree:] 44 | _ = d.bmix(block) // No tail. 45 | } else { 46 | // Tail's buf is large enough to prevent reallocs. 47 | p = append(d.tail, p...) 48 | } 49 | } 50 | 51 | d.tail = d.bmix(p) 52 | 53 | // Keep own copy of the 0 to Size()-1 pending bytes. 54 | nn := copy(d.buf[:], d.tail) 55 | d.tail = d.buf[:nn] 56 | 57 | return n, nil 58 | } 59 | 60 | func (d *digest) Reset() { 61 | d.clen = 0 62 | d.tail = nil 63 | d.bmixer.reset() 64 | } 65 | -------------------------------------------------------------------------------- /murmur128.go: -------------------------------------------------------------------------------- 1 | package murmur3 2 | 3 | import ( 4 | //"encoding/binary" 5 | "hash" 6 | "math/bits" 7 | "unsafe" 8 | ) 9 | 10 | const ( 11 | c1_128 = 0x87c37b91114253d5 12 | c2_128 = 0x4cf5ad432745937f 13 | ) 14 | 15 | // Make sure interfaces are correctly implemented. 16 | var ( 17 | _ hash.Hash = new(digest128) 18 | _ Hash128 = new(digest128) 19 | _ bmixer = new(digest128) 20 | ) 21 | 22 | // Hash128 represents a 128-bit hasher 23 | // Hack: the standard api doesn't define any Hash128 interface. 24 | type Hash128 interface { 25 | hash.Hash 26 | Sum128() (uint64, uint64) 27 | } 28 | 29 | // digest128 represents a partial evaluation of a 128 bites hash. 30 | type digest128 struct { 31 | digest 32 | h1 uint64 // Unfinalized running hash part 1. 33 | h2 uint64 // Unfinalized running hash part 2. 34 | } 35 | 36 | // New128 returns a 128-bit hasher 37 | func New128() Hash128 { return New128WithSeed(0) } 38 | 39 | // New128WithSeed returns a 128-bit hasher set with explicit seed value 40 | func New128WithSeed(seed uint32) Hash128 { 41 | d := new(digest128) 42 | d.seed = seed 43 | d.bmixer = d 44 | d.Reset() 45 | return d 46 | } 47 | 48 | func (d *digest128) Size() int { return 16 } 49 | 50 | func (d *digest128) reset() { d.h1, d.h2 = uint64(d.seed), uint64(d.seed) } 51 | 52 | func (d *digest128) Sum(b []byte) []byte { 53 | h1, h2 := d.Sum128() 54 | return append(b, 55 | byte(h1>>56), byte(h1>>48), byte(h1>>40), byte(h1>>32), 56 | byte(h1>>24), byte(h1>>16), byte(h1>>8), byte(h1), 57 | 58 | byte(h2>>56), byte(h2>>48), byte(h2>>40), byte(h2>>32), 59 | byte(h2>>24), byte(h2>>16), byte(h2>>8), byte(h2), 60 | ) 61 | } 62 | 63 | func (d *digest128) bmix(p []byte) (tail []byte) { 64 | h1, h2 := d.h1, d.h2 65 | 66 | nblocks := len(p) / 16 67 | for i := 0; i < nblocks; i++ { 68 | t := (*[2]uint64)(unsafe.Pointer(&p[i*16])) 69 | k1, k2 := t[0], t[1] 70 | 71 | k1 *= c1_128 72 | k1 = bits.RotateLeft64(k1, 31) 73 | k1 *= c2_128 74 | h1 ^= k1 75 | 76 | h1 = bits.RotateLeft64(h1, 27) 77 | h1 += h2 78 | h1 = h1*5 + 0x52dce729 79 | 80 | k2 *= c2_128 81 | k2 = bits.RotateLeft64(k2, 33) 82 | k2 *= c1_128 83 | h2 ^= k2 84 | 85 | h2 = bits.RotateLeft64(h2, 31) 86 | h2 += h1 87 | h2 = h2*5 + 0x38495ab5 88 | } 89 | d.h1, d.h2 = h1, h2 90 | return p[nblocks*d.Size():] 91 | } 92 | 93 | func (d *digest128) Sum128() (h1, h2 uint64) { 94 | 95 | h1, h2 = d.h1, d.h2 96 | 97 | var k1, k2 uint64 98 | switch len(d.tail) & 15 { 99 | case 15: 100 | k2 ^= uint64(d.tail[14]) << 48 101 | fallthrough 102 | case 14: 103 | k2 ^= uint64(d.tail[13]) << 40 104 | fallthrough 105 | case 13: 106 | k2 ^= uint64(d.tail[12]) << 32 107 | fallthrough 108 | case 12: 109 | k2 ^= uint64(d.tail[11]) << 24 110 | fallthrough 111 | case 11: 112 | k2 ^= uint64(d.tail[10]) << 16 113 | fallthrough 114 | case 10: 115 | k2 ^= uint64(d.tail[9]) << 8 116 | fallthrough 117 | case 9: 118 | k2 ^= uint64(d.tail[8]) << 0 119 | 120 | k2 *= c2_128 121 | k2 = bits.RotateLeft64(k2, 33) 122 | k2 *= c1_128 123 | h2 ^= k2 124 | 125 | fallthrough 126 | 127 | case 8: 128 | k1 ^= uint64(d.tail[7]) << 56 129 | fallthrough 130 | case 7: 131 | k1 ^= uint64(d.tail[6]) << 48 132 | fallthrough 133 | case 6: 134 | k1 ^= uint64(d.tail[5]) << 40 135 | fallthrough 136 | case 5: 137 | k1 ^= uint64(d.tail[4]) << 32 138 | fallthrough 139 | case 4: 140 | k1 ^= uint64(d.tail[3]) << 24 141 | fallthrough 142 | case 3: 143 | k1 ^= uint64(d.tail[2]) << 16 144 | fallthrough 145 | case 2: 146 | k1 ^= uint64(d.tail[1]) << 8 147 | fallthrough 148 | case 1: 149 | k1 ^= uint64(d.tail[0]) << 0 150 | k1 *= c1_128 151 | k1 = bits.RotateLeft64(k1, 31) 152 | k1 *= c2_128 153 | h1 ^= k1 154 | } 155 | 156 | h1 ^= uint64(d.clen) 157 | h2 ^= uint64(d.clen) 158 | 159 | h1 += h2 160 | h2 += h1 161 | 162 | h1 = fmix64(h1) 163 | h2 = fmix64(h2) 164 | 165 | h1 += h2 166 | h2 += h1 167 | 168 | return h1, h2 169 | } 170 | 171 | func fmix64(k uint64) uint64 { 172 | k ^= k >> 33 173 | k *= 0xff51afd7ed558ccd 174 | k ^= k >> 33 175 | k *= 0xc4ceb9fe1a85ec53 176 | k ^= k >> 33 177 | return k 178 | } 179 | 180 | // Sum128 returns the MurmurHash3 sum of data. It is equivalent to the 181 | // following sequence (without the extra burden and the extra allocation): 182 | // hasher := New128() 183 | // hasher.Write(data) 184 | // return hasher.Sum128() 185 | func Sum128(data []byte) (h1 uint64, h2 uint64) { return Sum128WithSeed(data, 0) } 186 | 187 | // Sum128WithSeed returns the MurmurHash3 sum of data. It is equivalent to the 188 | // following sequence (without the extra burden and the extra allocation): 189 | // hasher := New128WithSeed(seed) 190 | // hasher.Write(data) 191 | // return hasher.Sum128() 192 | func Sum128WithSeed(data []byte, seed uint32) (h1 uint64, h2 uint64) { 193 | d := digest128{h1: uint64(seed), h2: uint64(seed)} 194 | d.seed = seed 195 | d.tail = d.bmix(data) 196 | d.clen = len(data) 197 | return d.Sum128() 198 | } 199 | -------------------------------------------------------------------------------- /murmur32.go: -------------------------------------------------------------------------------- 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 | "hash" 7 | "math/bits" 8 | "unsafe" 9 | ) 10 | 11 | // Make sure interfaces are correctly implemented. 12 | var ( 13 | _ hash.Hash = new(digest32) 14 | _ hash.Hash32 = new(digest32) 15 | _ bmixer = new(digest32) 16 | ) 17 | 18 | const ( 19 | c1_32 uint32 = 0xcc9e2d51 20 | c2_32 uint32 = 0x1b873593 21 | ) 22 | 23 | // digest32 represents a partial evaluation of a 32 bites hash. 24 | type digest32 struct { 25 | digest 26 | h1 uint32 // Unfinalized running hash. 27 | } 28 | 29 | // New32 returns new 32-bit hasher 30 | func New32() hash.Hash32 { return New32WithSeed(0) } 31 | 32 | // New32WithSeed returns new 32-bit hasher set with explicit seed value 33 | func New32WithSeed(seed uint32) hash.Hash32 { 34 | d := new(digest32) 35 | d.seed = seed 36 | d.bmixer = d 37 | d.Reset() 38 | return d 39 | } 40 | 41 | func (d *digest32) Size() int { return 4 } 42 | 43 | func (d *digest32) reset() { d.h1 = d.seed } 44 | 45 | func (d *digest32) Sum(b []byte) []byte { 46 | h := d.Sum32() 47 | return append(b, byte(h>>24), byte(h>>16), byte(h>>8), byte(h)) 48 | } 49 | 50 | // Digest as many blocks as possible. 51 | func (d *digest32) bmix(p []byte) (tail []byte) { 52 | h1 := d.h1 53 | 54 | nblocks := len(p) / 4 55 | for i := 0; i < nblocks; i++ { 56 | k1 := *(*uint32)(unsafe.Pointer(&p[i*4])) 57 | 58 | k1 *= c1_32 59 | k1 = bits.RotateLeft32(k1, 15) 60 | k1 *= c2_32 61 | 62 | h1 ^= k1 63 | h1 = bits.RotateLeft32(h1, 13) 64 | h1 = h1*4 + h1 + 0xe6546b64 65 | } 66 | d.h1 = h1 67 | return p[nblocks*d.Size():] 68 | } 69 | 70 | func (d *digest32) Sum32() (h1 uint32) { 71 | 72 | h1 = d.h1 73 | 74 | var k1 uint32 75 | switch len(d.tail) & 3 { 76 | case 3: 77 | k1 ^= uint32(d.tail[2]) << 16 78 | fallthrough 79 | case 2: 80 | k1 ^= uint32(d.tail[1]) << 8 81 | fallthrough 82 | case 1: 83 | k1 ^= uint32(d.tail[0]) 84 | k1 *= c1_32 85 | k1 = bits.RotateLeft32(k1, 15) 86 | k1 *= c2_32 87 | h1 ^= k1 88 | } 89 | 90 | h1 ^= uint32(d.clen) 91 | 92 | h1 ^= h1 >> 16 93 | h1 *= 0x85ebca6b 94 | h1 ^= h1 >> 13 95 | h1 *= 0xc2b2ae35 96 | h1 ^= h1 >> 16 97 | 98 | return h1 99 | } 100 | 101 | // Sum32 returns the MurmurHash3 sum of data. It is equivalent to the 102 | // following sequence (without the extra burden and the extra allocation): 103 | // hasher := New32() 104 | // hasher.Write(data) 105 | // return hasher.Sum32() 106 | func Sum32(data []byte) uint32 { return Sum32WithSeed(data, 0) } 107 | 108 | // Sum32WithSeed returns the MurmurHash3 sum of data. It is equivalent to the 109 | // following sequence (without the extra burden and the extra allocation): 110 | // hasher := New32WithSeed(seed) 111 | // hasher.Write(data) 112 | // return hasher.Sum32() 113 | func Sum32WithSeed(data []byte, seed uint32) uint32 { 114 | 115 | h1 := seed 116 | 117 | nblocks := len(data) / 4 118 | var p uintptr 119 | if len(data) > 0 { 120 | p = uintptr(unsafe.Pointer(&data[0])) 121 | } 122 | p1 := p + uintptr(4*nblocks) 123 | for ; p < p1; p += 4 { 124 | k1 := *(*uint32)(unsafe.Pointer(p)) 125 | 126 | k1 *= c1_32 127 | k1 = bits.RotateLeft32(k1, 15) 128 | k1 *= c2_32 129 | 130 | h1 ^= k1 131 | h1 = bits.RotateLeft32(h1, 13) 132 | h1 = h1*4 + h1 + 0xe6546b64 133 | } 134 | 135 | tail := data[nblocks*4:] 136 | 137 | var k1 uint32 138 | switch len(tail) & 3 { 139 | case 3: 140 | k1 ^= uint32(tail[2]) << 16 141 | fallthrough 142 | case 2: 143 | k1 ^= uint32(tail[1]) << 8 144 | fallthrough 145 | case 1: 146 | k1 ^= uint32(tail[0]) 147 | k1 *= c1_32 148 | k1 = bits.RotateLeft32(k1, 15) 149 | k1 *= c2_32 150 | h1 ^= k1 151 | } 152 | 153 | h1 ^= uint32(len(data)) 154 | 155 | h1 ^= h1 >> 16 156 | h1 *= 0x85ebca6b 157 | h1 ^= h1 >> 13 158 | h1 *= 0xc2b2ae35 159 | h1 ^= h1 >> 16 160 | 161 | return h1 162 | } 163 | -------------------------------------------------------------------------------- /murmur64.go: -------------------------------------------------------------------------------- 1 | package murmur3 2 | 3 | import ( 4 | "hash" 5 | ) 6 | 7 | // Make sure interfaces are correctly implemented. 8 | var ( 9 | _ hash.Hash = new(digest64) 10 | _ hash.Hash64 = new(digest64) 11 | _ bmixer = new(digest64) 12 | ) 13 | 14 | // digest64 is half a digest128. 15 | type digest64 digest128 16 | 17 | // New64 returns a 64-bit hasher 18 | func New64() hash.Hash64 { return New64WithSeed(0) } 19 | 20 | // New64WithSeed returns a 64-bit hasher set with explicit seed value 21 | func New64WithSeed(seed uint32) hash.Hash64 { 22 | d := (*digest64)(New128WithSeed(seed).(*digest128)) 23 | return d 24 | } 25 | 26 | func (d *digest64) Sum(b []byte) []byte { 27 | h1 := d.Sum64() 28 | return append(b, 29 | byte(h1>>56), byte(h1>>48), byte(h1>>40), byte(h1>>32), 30 | byte(h1>>24), byte(h1>>16), byte(h1>>8), byte(h1)) 31 | } 32 | 33 | func (d *digest64) Sum64() uint64 { 34 | h1, _ := (*digest128)(d).Sum128() 35 | return h1 36 | } 37 | 38 | // Sum64 returns the MurmurHash3 sum of data. It is equivalent to the 39 | // following sequence (without the extra burden and the extra allocation): 40 | // hasher := New64() 41 | // hasher.Write(data) 42 | // return hasher.Sum64() 43 | func Sum64(data []byte) uint64 { return Sum64WithSeed(data, 0) } 44 | 45 | // Sum64WithSeed returns the MurmurHash3 sum of data. It is equivalent to the 46 | // following sequence (without the extra burden and the extra allocation): 47 | // hasher := New64WithSeed(seed) 48 | // hasher.Write(data) 49 | // return hasher.Sum64() 50 | func Sum64WithSeed(data []byte, seed uint32) uint64 { 51 | d := digest128{h1: uint64(seed), h2: uint64(seed)} 52 | d.seed = seed 53 | d.tail = d.bmix(data) 54 | d.clen = len(data) 55 | h1, _ := d.Sum128() 56 | return h1 57 | } 58 | -------------------------------------------------------------------------------- /murmur_test.go: -------------------------------------------------------------------------------- 1 | package murmur3 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "testing" 7 | ) 8 | 9 | var data = []struct { 10 | seed uint32 11 | h32 uint32 12 | h64_1 uint64 13 | h64_2 uint64 14 | s string 15 | }{ 16 | {0x00, 0x00000000, 0x0000000000000000, 0x0000000000000000, ""}, 17 | {0x00, 0x248bfa47, 0xcbd8a7b341bd9b02, 0x5b1e906a48ae1d19, "hello"}, 18 | {0x00, 0x149bbb7f, 0x342fac623a5ebc8e, 0x4cdcbc079642414d, "hello, world"}, 19 | {0x00, 0xe31e8a70, 0xb89e5988b737affc, 0x664fc2950231b2cb, "19 Jan 2038 at 3:14:07 AM"}, 20 | {0x00, 0xd5c48bfc, 0xcd99481f9ee902c9, 0x695da1a38987b6e7, "The quick brown fox jumps over the lazy dog."}, 21 | 22 | {0x01, 0x514e28b7, 0x4610abe56eff5cb5, 0x51622daa78f83583, ""}, 23 | {0x01, 0xbb4abcad, 0xa78ddff5adae8d10, 0x128900ef20900135, "hello"}, 24 | {0x01, 0x6f5cb2e9, 0x8b95f808840725c6, 0x1597ed5422bd493b, "hello, world"}, 25 | {0x01, 0xf50e1f30, 0x2a929de9c8f97b2f, 0x56a41d99af43a2db, "19 Jan 2038 at 3:14:07 AM"}, 26 | {0x01, 0x846f6a36, 0xfb3325171f9744da, 0xaaf8b92a5f722952, "The quick brown fox jumps over the lazy dog."}, 27 | 28 | {0x2a, 0x087fcd5c, 0xf02aa77dfa1b8523, 0xd1016610da11cbb9, ""}, 29 | {0x2a, 0xe2dbd2e1, 0xc4b8b3c960af6f08, 0x2334b875b0efbc7a, "hello"}, 30 | {0x2a, 0x7ec7c6c2, 0xb91864d797caa956, 0xd5d139a55afe6150, "hello, world"}, 31 | {0x2a, 0x58f745f6, 0xfd8f19ebdc8c6b6a, 0xd30fdc310fa08ff9, "19 Jan 2038 at 3:14:07 AM"}, 32 | {0x2a, 0xc02d1434, 0x74f33c659cda5af7, 0x4ec7a891caf316f0, "The quick brown fox jumps over the lazy dog."}, 33 | } 34 | 35 | func TestRefStrings(t *testing.T) { 36 | for _, elem := range data { 37 | 38 | h32 := New32WithSeed(elem.seed) 39 | h32.Write([]byte(elem.s)) 40 | if v := h32.Sum32(); v != elem.h32 { 41 | t.Errorf("[Hash32] key: '%s', seed: '%d': 0x%x (want 0x%x)", elem.s, elem.seed, v, elem.h32) 42 | } 43 | 44 | h32.Reset() 45 | h32.Write([]byte(elem.s)) 46 | target := fmt.Sprintf("%08x", elem.h32) 47 | if p := fmt.Sprintf("%x", h32.Sum(nil)); p != target { 48 | t.Errorf("[Hash32] key: '%s', seed: '%d': %s (want %s)", elem.s, elem.seed, p, target) 49 | } 50 | 51 | if v := Sum32WithSeed([]byte(elem.s), elem.seed); v != elem.h32 { 52 | t.Errorf("[Hash32] key '%s', seed: '%d': 0x%x (want 0x%x)", elem.s, elem.seed, v, elem.h32) 53 | } 54 | 55 | h64 := New64WithSeed(elem.seed) 56 | h64.Write([]byte(elem.s)) 57 | if v := h64.Sum64(); v != elem.h64_1 { 58 | t.Errorf("'[Hash64] key: '%s', seed: '%d': 0x%x (want 0x%x)", elem.s, elem.seed, v, elem.h64_1) 59 | } 60 | 61 | h64.Reset() 62 | h64.Write([]byte(elem.s)) 63 | target = fmt.Sprintf("%016x", elem.h64_1) 64 | if p := fmt.Sprintf("%x", h64.Sum(nil)); p != target { 65 | t.Errorf("[Hash64] key: '%s', seed: '%d': %s (want %s)", elem.s, elem.seed, p, target) 66 | } 67 | 68 | if v := Sum64WithSeed([]byte(elem.s), elem.seed); v != elem.h64_1 { 69 | t.Errorf("[Hash64] key: '%s', seed: '%d': 0x%x (want 0x%x)", elem.s, elem.seed, v, elem.h64_1) 70 | } 71 | 72 | h128 := New128WithSeed(elem.seed) 73 | 74 | h128.Write([]byte(elem.s)) 75 | if v1, v2 := h128.Sum128(); v1 != elem.h64_1 || v2 != elem.h64_2 { 76 | t.Errorf("[Hash128] key: '%s', seed: '%d': 0x%x-0x%x (want 0x%x-0x%x)", elem.s, elem.seed, v1, v2, elem.h64_1, elem.h64_2) 77 | } 78 | 79 | h128.Reset() 80 | h128.Write([]byte(elem.s)) 81 | target = fmt.Sprintf("%016x%016x", elem.h64_1, elem.h64_2) 82 | if p := fmt.Sprintf("%x", h128.Sum(nil)); p != target { 83 | t.Errorf("[Hash128] key: '%s', seed: '%d': %s (want %s)", elem.s, elem.seed, p, target) 84 | } 85 | 86 | if v1, v2 := Sum128WithSeed([]byte(elem.s), elem.seed); v1 != elem.h64_1 || v2 != elem.h64_2 { 87 | t.Errorf("[Hash128] key: '%s', seed: '%d': 0x%x-0x%x (want 0x%x-0x%x)", elem.s, elem.seed, v1, v2, elem.h64_1, elem.h64_2) 88 | } 89 | } 90 | } 91 | 92 | func TestIncremental(t *testing.T) { 93 | for _, elem := range data { 94 | h32 := New32WithSeed(elem.seed) 95 | h128 := New128WithSeed(elem.seed) 96 | var i, j int 97 | for k := len(elem.s); i < k; i = j { 98 | j = 2*i + 3 99 | if j > k { 100 | j = k 101 | } 102 | s := elem.s[i:j] 103 | print(s + "|") 104 | h32.Write([]byte(s)) 105 | h128.Write([]byte(s)) 106 | } 107 | println() 108 | if v := h32.Sum32(); v != elem.h32 { 109 | t.Errorf("[Hash32] key: '%s', seed: '%d': 0x%x (want 0x%x)", elem.s, elem.seed, v, elem.h32) 110 | } 111 | if v1, v2 := h128.Sum128(); v1 != elem.h64_1 || v2 != elem.h64_2 { 112 | t.Errorf("[Hash128] key: '%s', seed: '%d': 0x%x-0x%x (want 0x%x-0x%x)", elem.s, elem.seed, v1, v2, elem.h64_1, elem.h64_2) 113 | } 114 | } 115 | } 116 | 117 | func Benchmark32(b *testing.B) { 118 | buf := make([]byte, 8192) 119 | for length := 1; length <= cap(buf); length *= 2 { 120 | b.Run(strconv.Itoa(length), func(b *testing.B) { 121 | buf = buf[:length] 122 | b.SetBytes(int64(length)) 123 | b.ReportAllocs() 124 | b.ResetTimer() 125 | for i := 0; i < b.N; i++ { 126 | Sum32(buf) 127 | } 128 | }) 129 | } 130 | } 131 | 132 | func BenchmarkPartial32(b *testing.B) { 133 | buf := make([]byte, 128) 134 | for length := 8; length <= cap(buf); length *= 2 { 135 | b.Run(strconv.Itoa(length), func(b *testing.B) { 136 | buf = buf[:length] 137 | b.SetBytes(int64(length)) 138 | b.ReportAllocs() 139 | 140 | start := (32 / 8) / 2 141 | chunks := 7 142 | k := length / chunks 143 | tail := (length - start) % k 144 | 145 | b.ResetTimer() 146 | for i := 0; i < b.N; i++ { 147 | hasher := New32() 148 | hasher.Write(buf[0:start]) 149 | 150 | for j := start; j+k <= length; j += k { 151 | hasher.Write(buf[j : j+k]) 152 | } 153 | 154 | hasher.Write(buf[length-tail:]) 155 | hasher.Sum32() 156 | } 157 | }) 158 | } 159 | } 160 | 161 | func Benchmark64(b *testing.B) { 162 | buf := make([]byte, 8192) 163 | for length := 1; length <= cap(buf); length *= 2 { 164 | b.Run(strconv.Itoa(length), func(b *testing.B) { 165 | buf = buf[:length] 166 | b.SetBytes(int64(length)) 167 | b.ReportAllocs() 168 | b.ResetTimer() 169 | for i := 0; i < b.N; i++ { 170 | Sum64(buf) 171 | } 172 | }) 173 | } 174 | } 175 | 176 | func Benchmark128(b *testing.B) { 177 | buf := make([]byte, 8192) 178 | for length := 1; length <= cap(buf); length *= 2 { 179 | b.Run(strconv.Itoa(length), func(b *testing.B) { 180 | buf = buf[:length] 181 | b.SetBytes(int64(length)) 182 | b.ReportAllocs() 183 | b.ResetTimer() 184 | for i := 0; i < b.N; i++ { 185 | Sum128(buf) 186 | } 187 | }) 188 | } 189 | } 190 | --------------------------------------------------------------------------------