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  }