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/