github.com/duomi520/utils@v0.0.0-20240430123446-e03a4cddd6ec/hash64.go (about)

     1  package utils
     2  
     3  //代码抄自 https://github.com/zeebo/wyhash
     4  import (
     5  	"encoding/binary"
     6  	"math/bits"
     7  	"unsafe"
     8  )
     9  
    10  const (
    11  	_wyp0 = 0xa0761d6478bd642f
    12  	_wyp1 = 0xe7037ed1a0b428db
    13  	_wyp2 = 0x8ebc6af09c88c6e3
    14  	_wyp3 = 0x589965cc75374cc3
    15  	_wyp4 = 0x1d8e4e27c47d124f
    16  )
    17  
    18  func _wymum(A, B uint64) uint64 {
    19  	hi, lo := bits.Mul64(A, B)
    20  	return hi ^ lo
    21  }
    22  
    23  func _wyr8(p unsafe.Pointer) uint64 {
    24  	return binary.LittleEndian.Uint64((*[8]byte)(p)[:])
    25  }
    26  
    27  func _wyr4(p unsafe.Pointer) uint64 {
    28  	return uint64(binary.LittleEndian.Uint32((*[4]byte)(p)[:]))
    29  }
    30  
    31  func _wyr3(p unsafe.Pointer, k uintptr) uint64 {
    32  	b0 := uint64(*(*byte)(p))
    33  	b1 := uint64(*(*byte)(offset(p, k>>1)))
    34  	b2 := uint64(*(*byte)(offset(p, k-1)))
    35  	return b0<<16 | b1<<8 | b2
    36  }
    37  
    38  func _wyr9(p unsafe.Pointer) uint64 {
    39  	b := (*[8]byte)(p)
    40  	return uint64(uint32(b[0])|uint32(b[1])<<8|uint32(b[2])<<16|uint32(b[3])<<24)<<32 |
    41  		uint64(uint32(b[4])|uint32(b[5])<<8|uint32(b[6])<<16|uint32(b[7])<<24)
    42  }
    43  
    44  func hash(data string, seed uint64) uint64 {
    45  	p, len := *(*unsafe.Pointer)(unsafe.Pointer(&data)), uintptr(len(data))
    46  	see1, off := seed, len
    47  
    48  	switch {
    49  	case len <= 0x03:
    50  		return _wymum(_wymum(_wyr3(p, len)^seed^_wyp0, seed^_wyp1)^seed, uint64(len)^_wyp4)
    51  
    52  	case len <= 0x08:
    53  		return _wymum(_wymum(_wyr4(offset(p, 0x00))^seed^_wyp0, _wyr4(offset(p, len-0x04))^seed^_wyp1)^seed, uint64(len)^_wyp4)
    54  
    55  	case len <= 0x10:
    56  		return _wymum(_wymum(_wyr9(offset(p, 0x00))^seed^_wyp0, _wyr9(offset(p, len-0x08))^seed^_wyp1)^seed, uint64(len)^_wyp4)
    57  
    58  	case len <= 0x18:
    59  		return _wymum(_wymum(_wyr9(offset(p, 0x00))^seed^_wyp0, _wyr9(offset(p, 0x08))^seed^_wyp1)^_wymum(_wyr9(offset(p, len-0x08))^seed^_wyp2, seed^_wyp3), uint64(len)^_wyp4)
    60  
    61  	case len <= 0x20:
    62  		return _wymum(_wymum(_wyr9(offset(p, 0x00))^seed^_wyp0, _wyr9(offset(p, 0x08))^seed^_wyp1)^_wymum(_wyr9(offset(p, 0x10))^seed^_wyp2, _wyr9(offset(p, len-0x08))^seed^_wyp3), uint64(len)^_wyp4)
    63  
    64  	case len <= 0x100:
    65  		seed = _wymum(_wyr8(offset(p, 0x00))^seed^_wyp0, _wyr8(offset(p, 0x08))^seed^_wyp1)
    66  		see1 = _wymum(_wyr8(offset(p, 0x10))^see1^_wyp2, _wyr8(offset(p, 0x18))^see1^_wyp3)
    67  		if len > 0x40 {
    68  			seed = _wymum(_wyr8(offset(p, 0x20))^seed^_wyp0, _wyr8(offset(p, 0x28))^seed^_wyp1)
    69  			see1 = _wymum(_wyr8(offset(p, 0x30))^see1^_wyp2, _wyr8(offset(p, 0x38))^see1^_wyp3)
    70  			if len > 0x60 {
    71  				seed = _wymum(_wyr8(offset(p, 0x40))^seed^_wyp0, _wyr8(offset(p, 0x48))^seed^_wyp1)
    72  				see1 = _wymum(_wyr8(offset(p, 0x50))^see1^_wyp2, _wyr8(offset(p, 0x58))^see1^_wyp3)
    73  				if len > 0x80 {
    74  					seed = _wymum(_wyr8(offset(p, 0x60))^seed^_wyp0, _wyr8(offset(p, 0x68))^seed^_wyp1)
    75  					see1 = _wymum(_wyr8(offset(p, 0x70))^see1^_wyp2, _wyr8(offset(p, 0x78))^see1^_wyp3)
    76  					if len > 0xa0 {
    77  						seed = _wymum(_wyr8(offset(p, 0x80))^seed^_wyp0, _wyr8(offset(p, 0x88))^seed^_wyp1)
    78  						see1 = _wymum(_wyr8(offset(p, 0x90))^see1^_wyp2, _wyr8(offset(p, 0x98))^see1^_wyp3)
    79  						if len > 0xc0 {
    80  							seed = _wymum(_wyr8(offset(p, 0xa0))^seed^_wyp0, _wyr8(offset(p, 0xa8))^seed^_wyp1)
    81  							see1 = _wymum(_wyr8(offset(p, 0xb0))^see1^_wyp2, _wyr8(offset(p, 0xb8))^see1^_wyp3)
    82  							if len > 0xe0 {
    83  								seed = _wymum(_wyr8(offset(p, 0xc0))^seed^_wyp0, _wyr8(offset(p, 0xc8))^seed^_wyp1)
    84  								see1 = _wymum(_wyr8(offset(p, 0xd0))^see1^_wyp2, _wyr8(offset(p, 0xd8))^see1^_wyp3)
    85  							}
    86  						}
    87  					}
    88  				}
    89  			}
    90  		}
    91  
    92  		off = (off-1)%0x20 + 1
    93  		p = offset(p, len-off)
    94  
    95  	default:
    96  		for ; off > 0x100; off, p = off-0x100, offset(p, 0x100) {
    97  			seed = _wymum(_wyr8(offset(p, 0x00))^seed^_wyp0, _wyr8(offset(p, 0x08))^seed^_wyp1) ^ _wymum(_wyr8(offset(p, 0x10))^seed^_wyp2, _wyr8(offset(p, 0x18))^seed^_wyp3)
    98  			see1 = _wymum(_wyr8(offset(p, 0x20))^see1^_wyp1, _wyr8(offset(p, 0x28))^see1^_wyp2) ^ _wymum(_wyr8(offset(p, 0x30))^see1^_wyp3, _wyr8(offset(p, 0x38))^see1^_wyp0)
    99  			seed = _wymum(_wyr8(offset(p, 0x40))^seed^_wyp0, _wyr8(offset(p, 0x48))^seed^_wyp1) ^ _wymum(_wyr8(offset(p, 0x50))^seed^_wyp2, _wyr8(offset(p, 0x58))^seed^_wyp3)
   100  			see1 = _wymum(_wyr8(offset(p, 0x60))^see1^_wyp1, _wyr8(offset(p, 0x68))^see1^_wyp2) ^ _wymum(_wyr8(offset(p, 0x70))^see1^_wyp3, _wyr8(offset(p, 0x78))^see1^_wyp0)
   101  			seed = _wymum(_wyr8(offset(p, 0x80))^seed^_wyp0, _wyr8(offset(p, 0x88))^seed^_wyp1) ^ _wymum(_wyr8(offset(p, 0x90))^seed^_wyp2, _wyr8(offset(p, 0x98))^seed^_wyp3)
   102  			see1 = _wymum(_wyr8(offset(p, 0xa0))^see1^_wyp1, _wyr8(offset(p, 0xa8))^see1^_wyp2) ^ _wymum(_wyr8(offset(p, 0xb0))^see1^_wyp3, _wyr8(offset(p, 0xb8))^see1^_wyp0)
   103  			seed = _wymum(_wyr8(offset(p, 0xc0))^seed^_wyp0, _wyr8(offset(p, 0xc8))^seed^_wyp1) ^ _wymum(_wyr8(offset(p, 0xd0))^seed^_wyp2, _wyr8(offset(p, 0xd8))^seed^_wyp3)
   104  			see1 = _wymum(_wyr8(offset(p, 0xe0))^see1^_wyp1, _wyr8(offset(p, 0xe8))^see1^_wyp2) ^ _wymum(_wyr8(offset(p, 0xf0))^see1^_wyp3, _wyr8(offset(p, 0xf8))^see1^_wyp0)
   105  		}
   106  		for ; off > 0x20; off, p = off-0x20, offset(p, 0x20) {
   107  			seed = _wymum(_wyr8(offset(p, 0x00))^seed^_wyp0, _wyr8(offset(p, 0x08))^seed^_wyp1)
   108  			see1 = _wymum(_wyr8(offset(p, 0x10))^see1^_wyp2, _wyr8(offset(p, 0x18))^see1^_wyp3)
   109  		}
   110  	}
   111  
   112  	switch {
   113  	case off > 0x18:
   114  		seed = _wymum(_wyr9(offset(p, 0x00))^seed^_wyp0, _wyr9(offset(p, 0x08))^seed^_wyp1)
   115  		see1 = _wymum(_wyr9(offset(p, 0x10))^see1^_wyp2, _wyr9(offset(p, off-0x08))^see1^_wyp3)
   116  
   117  	case off > 0x10:
   118  		seed = _wymum(_wyr9(offset(p, 0x00))^seed^_wyp0, _wyr9(offset(p, 0x08))^seed^_wyp1)
   119  		see1 = _wymum(_wyr9(offset(p, off-0x08))^see1^_wyp2, see1^_wyp3)
   120  
   121  	case off > 0x08:
   122  		seed = _wymum(_wyr9(offset(p, 0x00))^seed^_wyp0, _wyr9(offset(p, off-0x08))^seed^_wyp1)
   123  
   124  	case off > 0x03:
   125  		seed = _wymum(_wyr4(offset(p, 0x00))^seed^_wyp0, _wyr4(offset(p, off-0x04))^seed^_wyp1)
   126  
   127  	default:
   128  		seed = _wymum(_wyr3(p, off)^seed^_wyp0, seed^_wyp1)
   129  	}
   130  
   131  	return _wymum(seed^see1, uint64(len)^_wyp4)
   132  }
   133  
   134  // Hash64WY returns a 64bit digest of the data with different ones for every seed.
   135  func Hash64WY[T string | []byte](data T, seed uint64) uint64 {
   136  	if len(data) == 0 {
   137  		return seed
   138  	}
   139  	return hash(*(*string)(unsafe.Pointer(&data)), seed)
   140  }
   141  
   142  var prime64 uint64 = 1099511628211
   143  
   144  // FNV-1a算法
   145  func Hash64FNV1A[T string | []byte](data T) uint64 {
   146  	var result uint64 = 14695981039346656037
   147  	for i := 0; i < len(data); i++ {
   148  		result ^= uint64(data[i])
   149  		result *= prime64
   150  	}
   151  	return result
   152  }
   153  
   154  // https://github.com/wangyi-fudan/wyhash
   155  // https://github.com/dgryski/go-wyhash/