github.com/fufuok/utils@v1.0.10/xhash/hasher_xxhash.go (about) 1 //go:build go1.18 2 // +build go1.18 3 4 package xhash 5 6 /* 7 From https://github.com/cespare/xxhash 8 9 Copyright (c) 2016 Caleb Spare 10 11 MIT License 12 13 Permission is hereby granted, free of charge, to any person obtaining 14 a copy of this software and associated documentation files (the 15 "Software"), to deal in the Software without restriction, including 16 without limitation the rights to use, copy, modify, merge, publish, 17 distribute, sublicense, and/or sell copies of the Software, and to 18 permit persons to whom the Software is furnished to do so, subject to 19 the following conditions: 20 The above copyright notice and this permission notice shall be 21 included in all copies or substantial portions of the Software. 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 27 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 */ 30 31 import ( 32 "encoding/binary" 33 "fmt" 34 "hash/maphash" 35 "math/bits" 36 "reflect" 37 "strconv" 38 "unsafe" 39 ) 40 41 const ( 42 // hash input allowed sizes 43 byteSize = 1 << iota 44 wordSize 45 dwordSize 46 qwordSize 47 owordSize 48 ) 49 50 const ( 51 prime1 uint64 = 11400714785074694791 52 prime2 uint64 = 14029467366897019727 53 prime3 uint64 = 1609587929392839161 54 prime4 uint64 = 9650029242287828579 55 prime5 uint64 = 2870177450012600261 56 ) 57 58 const intSizeBytes = strconv.IntSize >> 3 59 60 var prime1v = prime1 61 62 // Hashable allowed map key types constraint 63 type Hashable interface { 64 ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | 65 ~float32 | ~float64 | ~string | ~complex64 | ~complex128 66 } 67 68 // GenHasher64 按数据类型生成哈希函数 69 // Ref: cespare/xxhash, smallnest/safemap, alphadose/haxmap, cornelk/hashmap 70 func GenHasher64[K comparable]() func(K) uint64 { 71 hasher := GenHasher[K]() 72 return func(k K) uint64 { 73 return uint64(hasher(k)) 74 } 75 } 76 77 func GenSeedHasher64[K comparable]() func(maphash.Seed, K) uint64 { 78 hasher := GenHasher[K]() 79 return func(_ maphash.Seed, k K) uint64 { 80 return uint64(hasher(k)) 81 } 82 } 83 84 func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) } 85 func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) } 86 87 func round(acc, input uint64) uint64 { 88 acc += input * prime2 89 acc = rol31(acc) 90 acc *= prime1 91 return acc 92 } 93 94 func mergeRound(acc, val uint64) uint64 { 95 val = round(0, val) 96 acc ^= val 97 acc = acc*prime1 + prime4 98 return acc 99 } 100 101 func rol1(x uint64) uint64 { return bits.RotateLeft64(x, 1) } 102 func rol7(x uint64) uint64 { return bits.RotateLeft64(x, 7) } 103 func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) } 104 func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) } 105 func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) } 106 func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) } 107 func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) } 108 func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) } 109 110 // xxHash implementation for known key type sizes, minimal with no branching 111 var ( 112 // byte hasher, key size -> 1 byte 113 byteHasher = func(key uint8) uintptr { 114 h := prime5 + 1 115 h ^= uint64(key) * prime5 116 h = bits.RotateLeft64(h, 11) * prime1 117 h ^= h >> 33 118 h *= prime2 119 h ^= h >> 29 120 h *= prime3 121 h ^= h >> 32 122 return uintptr(h) 123 } 124 125 // word hasher, key size -> 2 bytes 126 wordHasher = func(key uint16) uintptr { 127 h := prime5 + 2 128 h ^= (uint64(key) & 0xff) * prime5 129 h = bits.RotateLeft64(h, 11) * prime1 130 h ^= ((uint64(key) >> 8) & 0xff) * prime5 131 h = bits.RotateLeft64(h, 11) * prime1 132 h ^= h >> 33 133 h *= prime2 134 h ^= h >> 29 135 h *= prime3 136 h ^= h >> 32 137 return uintptr(h) 138 } 139 140 // dword hasher, key size -> 4 bytes 141 dwordHasher = func(key uint32) uintptr { 142 h := prime5 + 4 143 h ^= uint64(key) * prime1 144 h = bits.RotateLeft64(h, 23)*prime2 + prime3 145 h ^= h >> 33 146 h *= prime2 147 h ^= h >> 29 148 h *= prime3 149 h ^= h >> 32 150 return uintptr(h) 151 } 152 153 // qword hasher, key size -> 8 bytes 154 qwordHasher = func(key uint64) uintptr { 155 k1 := key * prime2 156 k1 = bits.RotateLeft64(k1, 31) 157 k1 *= prime1 158 h := (prime5 + 8) ^ k1 159 h = bits.RotateLeft64(h, 27)*prime1 + prime4 160 h ^= h >> 33 161 h *= prime2 162 h ^= h >> 29 163 h *= prime3 164 h ^= h >> 32 165 return uintptr(h) 166 } 167 168 float32Hasher = func(key float32) uintptr { 169 k := *(*uint32)(unsafe.Pointer(&key)) 170 h := prime5 + 4 171 h ^= uint64(k) * prime1 172 h = bits.RotateLeft64(h, 23)*prime2 + prime3 173 h ^= h >> 33 174 h *= prime2 175 h ^= h >> 29 176 h *= prime3 177 h ^= h >> 32 178 return uintptr(h) 179 } 180 181 float64Hasher = func(key float64) uintptr { 182 k := *(*uint64)(unsafe.Pointer(&key)) 183 h := prime5 + 4 184 h ^= uint64(k) * prime1 185 h = bits.RotateLeft64(h, 23)*prime2 + prime3 186 h ^= h >> 33 187 h *= prime2 188 h ^= h >> 29 189 h *= prime3 190 h ^= h >> 32 191 return uintptr(h) 192 } 193 ) 194 195 func GenHasher[K comparable]() func(K) uintptr { 196 var hasher func(K) uintptr 197 var key K 198 kind := reflect.ValueOf(&key).Elem().Type().Kind() 199 switch kind { 200 case reflect.String: 201 // use default xxHash algorithm for key of any size for golang string data type 202 hasher = func(key K) uintptr { 203 sh := (*reflect.StringHeader)(unsafe.Pointer(&key)) 204 b := unsafe.Slice((*byte)(unsafe.Pointer(sh.Data)), sh.Len) 205 n := sh.Len 206 var h uint64 207 208 if n >= 32 { 209 v1 := prime1v + prime2 210 v2 := prime2 211 v3 := uint64(0) 212 v4 := -prime1v 213 for len(b) >= 32 { 214 v1 = round(v1, u64(b[0:8:len(b)])) 215 v2 = round(v2, u64(b[8:16:len(b)])) 216 v3 = round(v3, u64(b[16:24:len(b)])) 217 v4 = round(v4, u64(b[24:32:len(b)])) 218 b = b[32:len(b):len(b)] 219 } 220 h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4) 221 h = mergeRound(h, v1) 222 h = mergeRound(h, v2) 223 h = mergeRound(h, v3) 224 h = mergeRound(h, v4) 225 } else { 226 h = prime5 227 } 228 229 h += uint64(n) 230 231 i, end := 0, len(b) 232 for ; i+8 <= end; i += 8 { 233 k1 := round(0, u64(b[i:i+8:len(b)])) 234 h ^= k1 235 h = rol27(h)*prime1 + prime4 236 } 237 if i+4 <= end { 238 h ^= uint64(u32(b[i:i+4:len(b)])) * prime1 239 h = rol23(h)*prime2 + prime3 240 i += 4 241 } 242 for ; i < end; i++ { 243 h ^= uint64(b[i]) * prime5 244 h = rol11(h) * prime1 245 } 246 247 h ^= h >> 33 248 h *= prime2 249 h ^= h >> 29 250 h *= prime3 251 h ^= h >> 32 252 253 return uintptr(h) 254 } 255 case reflect.Int, reflect.Uint, reflect.Uintptr: 256 switch intSizeBytes { 257 case 2: 258 // word hasher 259 hasher = *(*func(K) uintptr)(unsafe.Pointer(&wordHasher)) 260 case 4: 261 // Dword hasher 262 hasher = *(*func(K) uintptr)(unsafe.Pointer(&dwordHasher)) 263 case 8: 264 // Qword Hash 265 hasher = *(*func(K) uintptr)(unsafe.Pointer(&qwordHasher)) 266 } 267 case reflect.Int8, reflect.Uint8: 268 // byte hasher 269 hasher = *(*func(K) uintptr)(unsafe.Pointer(&byteHasher)) 270 case reflect.Int16, reflect.Uint16: 271 // word hasher 272 hasher = *(*func(K) uintptr)(unsafe.Pointer(&wordHasher)) 273 case reflect.Int32, reflect.Uint32: 274 // Dword hasher 275 hasher = *(*func(K) uintptr)(unsafe.Pointer(&dwordHasher)) 276 case reflect.Float32: 277 hasher = *(*func(K) uintptr)(unsafe.Pointer(&float32Hasher)) 278 case reflect.Int64, reflect.Uint64: 279 // Qword hasher 280 hasher = *(*func(K) uintptr)(unsafe.Pointer(&qwordHasher)) 281 case reflect.Float64: 282 hasher = *(*func(K) uintptr)(unsafe.Pointer(&float64Hasher)) 283 case reflect.Complex64: 284 hasher = func(key K) uintptr { 285 k := *(*uint64)(unsafe.Pointer(&key)) 286 h := prime5 + 4 287 h ^= uint64(k) * prime1 288 h = bits.RotateLeft64(h, 23)*prime2 + prime3 289 h ^= h >> 33 290 h *= prime2 291 h ^= h >> 29 292 h *= prime3 293 h ^= h >> 32 294 return uintptr(h) 295 } 296 case reflect.Complex128: 297 // Oword hasher, key size -> 16 bytes 298 hasher = func(key K) uintptr { 299 b := *(*[owordSize]byte)(unsafe.Pointer(&key)) 300 h := prime5 + 16 301 302 val := uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | 303 uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 304 305 k1 := val * prime2 306 k1 = bits.RotateLeft64(k1, 31) 307 k1 *= prime1 308 309 h ^= k1 310 h = bits.RotateLeft64(h, 27)*prime1 + prime4 311 312 val = uint64(b[8]) | uint64(b[9])<<8 | uint64(b[10])<<16 | uint64(b[11])<<24 | 313 uint64(b[12])<<32 | uint64(b[13])<<40 | uint64(b[14])<<48 | uint64(b[15])<<56 314 315 k1 = val * prime2 316 k1 = bits.RotateLeft64(k1, 31) 317 k1 *= prime1 318 319 h ^= k1 320 h = bits.RotateLeft64(h, 27)*prime1 + prime4 321 322 h ^= h >> 33 323 h *= prime2 324 h ^= h >> 29 325 h *= prime3 326 h ^= h >> 32 327 328 return uintptr(h) 329 } 330 case reflect.Pointer: 331 hasher = func(key K) uintptr { 332 k := reflect.ValueOf(key).Pointer() 333 switch intSizeBytes { 334 case 2: 335 return wordHasher(uint16(k)) 336 case 4: 337 return dwordHasher(uint32(k)) 338 case 8: 339 return qwordHasher(uint64(k)) 340 default: 341 return uintptr(unsafe.Pointer(&key)) 342 } 343 } 344 default: 345 panic(fmt.Errorf("unsupported key type %T of kind %v", key, kind)) 346 } 347 348 return hasher 349 }