github.com/songzhibin97/gkit@v1.2.13/internal/wyhash/wyhash.go (about) 1 // Package wyhash implements https://github.com/wangyi-fudan/wyhash 2 package wyhash 3 4 import ( 5 "github.com/songzhibin97/gkit/internal/hack" 6 "math/bits" 7 "unsafe" 8 9 "github.com/songzhibin97/gkit/internal/runtimex" 10 ) 11 12 const ( 13 DefaultSeed = 0xa0761d6478bd642f // s0 14 s1 = 0xe7037ed1a0b428db 15 s2 = 0x8ebc6af09c88c6e3 16 s3 = 0x589965cc75374cc3 17 s4 = 0x1d8e4e27c47d124f 18 ) 19 20 func _wymix(a, b uint64) uint64 { 21 hi, lo := bits.Mul64(a, b) 22 return hi ^ lo 23 } 24 25 //go:nosplit 26 func add(p unsafe.Pointer, x uintptr) unsafe.Pointer { 27 return unsafe.Pointer(uintptr(p) + x) 28 } 29 30 func Sum64(data []byte) uint64 { 31 return Sum64WithSeed(data, DefaultSeed) 32 } 33 34 func Sum64String(data string) uint64 { 35 return Sum64StringWithSeed(data, DefaultSeed) 36 } 37 38 func Sum64WithSeed(data []byte, seed uint64) uint64 { 39 return Sum64StringWithSeed(hack.BytesToString(data), seed) 40 } 41 42 func Sum64StringWithSeed(data string, seed uint64) uint64 { 43 var ( 44 a, b uint64 45 ) 46 47 length := len(data) 48 i := uintptr(len(data)) 49 paddr := *(*unsafe.Pointer)(unsafe.Pointer(&data)) 50 51 if i > 64 { 52 var see1 = seed 53 for i > 64 { 54 seed = _wymix(runtimex.ReadUnaligned64(paddr)^s1, runtimex.ReadUnaligned64(add(paddr, 8))^seed) ^ _wymix(runtimex.ReadUnaligned64(add(paddr, 16))^s2, runtimex.ReadUnaligned64(add(paddr, 24))^seed) 55 see1 = _wymix(runtimex.ReadUnaligned64(add(paddr, 32))^s3, runtimex.ReadUnaligned64(add(paddr, 40))^see1) ^ _wymix(runtimex.ReadUnaligned64(add(paddr, 48))^s4, runtimex.ReadUnaligned64(add(paddr, 56))^see1) 56 paddr = add(paddr, 64) 57 i -= 64 58 } 59 seed ^= see1 60 } 61 62 for i > 16 { 63 seed = _wymix(runtimex.ReadUnaligned64(paddr)^s1, runtimex.ReadUnaligned64(add(paddr, 8))^seed) 64 paddr = add(paddr, 16) 65 i -= 16 66 } 67 68 // i <= 16 69 switch { 70 case i == 0: 71 return _wymix(s1, _wymix(s1, seed)) 72 case i < 4: 73 a = uint64(*(*byte)(paddr))<<16 | uint64(*(*byte)(add(paddr, uintptr(i>>1))))<<8 | uint64(*(*byte)(add(paddr, uintptr(i-1)))) 74 // b = 0 75 return _wymix(s1^uint64(length), _wymix(a^s1, seed)) 76 case i == 4: 77 a = runtimex.ReadUnaligned32(paddr) 78 // b = 0 79 return _wymix(s1^uint64(length), _wymix(a^s1, seed)) 80 case i < 8: 81 a = runtimex.ReadUnaligned32(paddr) 82 b = runtimex.ReadUnaligned32(add(paddr, i-4)) 83 return _wymix(s1^uint64(length), _wymix(a^s1, b^seed)) 84 case i == 8: 85 a = runtimex.ReadUnaligned64(paddr) 86 // b = 0 87 return _wymix(s1^uint64(length), _wymix(a^s1, seed)) 88 default: // 8 < i <= 16 89 a = runtimex.ReadUnaligned64(paddr) 90 b = runtimex.ReadUnaligned64(add(paddr, i-8)) 91 return _wymix(s1^uint64(length), _wymix(a^s1, b^seed)) 92 } 93 }