github.com/cnotch/ipchub@v1.1.0/utils/murmur/murmur.go (about) 1 /********************************************************************************** 2 * Copyright (c) 2009-2019 Misakai Ltd. 3 * This program is free software: you can redistribute it and/or modify it under the 4 * terms of the GNU Affero General Public License as published by the Free Software 5 * Foundation, either version 3 of the License, or(at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 8 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 9 * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 10 * 11 * You should have received a copy of the GNU Affero General Public License along 12 * with this program. If not, see<http://www.gnu.org/licenses/>. 13 ************************************************************************************/ 14 15 // Package murmur 是murmur算法的实现,方网站:https://sites.google.com/site/murmurhash/ 16 // 17 // MurmurHash算法:高运算性能,低碰撞率,由Austin Appleby创建于2008年, 18 // 现已应用到Hadoop、libstdc++、nginx、libmemcached等开源系统。 19 // 2011年Appleby被Google雇佣,随后Google推出其变种的CityHash算法。 20 // 21 // 当key的长度大于10字节的时候,MurmurHash的运算速度才快于DJB。 22 // “从计算速度上来看,MurmurHash只适用于已知长度的、长度比较长的字符”。 23 package murmur 24 25 import ( 26 "reflect" 27 "unsafe" 28 ) 29 30 const ( 31 c1_32 uint32 = 0xcc9e2d51 32 c2_32 uint32 = 0x1b873593 33 ) 34 35 // OfString returns a murmur32 hash for the string 36 func OfString(value string) uint32 { 37 return Of(stringToBinary(value)) 38 } 39 40 // Of returns a murmur32 hash for the data slice. 41 func Of(data []byte) uint32 { 42 // Seed is set to 37, same as C# version of emitter 43 var h1 uint32 = 37 44 45 nblocks := len(data) / 4 46 var p uintptr 47 if len(data) > 0 { 48 p = uintptr(unsafe.Pointer(&data[0])) 49 } 50 51 p1 := p + uintptr(4*nblocks) 52 for ; p < p1; p += 4 { 53 k1 := *(*uint32)(unsafe.Pointer(p)) 54 55 k1 *= c1_32 56 k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) 57 k1 *= c2_32 58 59 h1 ^= k1 60 h1 = (h1 << 13) | (h1 >> 19) // rotl32(h1, 13) 61 h1 = h1*5 + 0xe6546b64 62 } 63 64 tail := data[nblocks*4:] 65 66 var k1 uint32 67 switch len(tail) & 3 { 68 case 3: 69 k1 ^= uint32(tail[2]) << 16 70 fallthrough 71 case 2: 72 k1 ^= uint32(tail[1]) << 8 73 fallthrough 74 case 1: 75 k1 ^= uint32(tail[0]) 76 k1 *= c1_32 77 k1 = (k1 << 15) | (k1 >> 17) // rotl32(k1, 15) 78 k1 *= c2_32 79 h1 ^= k1 80 } 81 82 h1 ^= uint32(len(data)) 83 84 h1 ^= h1 >> 16 85 h1 *= 0x85ebca6b 86 h1 ^= h1 >> 13 87 h1 *= 0xc2b2ae35 88 h1 ^= h1 >> 16 89 90 return (h1 << 24) | (((h1 >> 8) << 16) & 0xFF0000) | (((h1 >> 16) << 8) & 0xFF00) | (h1 >> 24) 91 } 92 93 func stringToBinary(v string) (b []byte) { 94 strHeader := (*reflect.StringHeader)(unsafe.Pointer(&v)) 95 byteHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 96 byteHeader.Data = strHeader.Data 97 98 l := len(v) 99 byteHeader.Len = l 100 byteHeader.Cap = l 101 return 102 }