github.com/bytedance/gopkg@v0.0.0-20240514070511-01b2cbcf35e1/internal/wyhash/wyhash.go (about) 1 // Copyright 2021 ByteDance Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package wyhash implements https://github.com/wangyi-fudan/wyhash 16 package wyhash 17 18 import ( 19 "math/bits" 20 "unsafe" 21 22 "github.com/bytedance/gopkg/internal/hack" 23 "github.com/bytedance/gopkg/internal/runtimex" 24 ) 25 26 const ( 27 DefaultSeed = 0xa0761d6478bd642f // s0 28 s1 = 0xe7037ed1a0b428db 29 s2 = 0x8ebc6af09c88c6e3 30 s3 = 0x589965cc75374cc3 31 s4 = 0x1d8e4e27c47d124f 32 ) 33 34 func _wymix(a, b uint64) uint64 { 35 hi, lo := bits.Mul64(a, b) 36 return hi ^ lo 37 } 38 39 //go:nosplit 40 func add(p unsafe.Pointer, x uintptr) unsafe.Pointer { 41 return unsafe.Pointer(uintptr(p) + x) 42 } 43 44 func Sum64(data []byte) uint64 { 45 return Sum64WithSeed(data, DefaultSeed) 46 } 47 48 func Sum64String(data string) uint64 { 49 return Sum64StringWithSeed(data, DefaultSeed) 50 } 51 52 func Sum64WithSeed(data []byte, seed uint64) uint64 { 53 return Sum64StringWithSeed(hack.BytesToString(data), seed) 54 } 55 56 func Sum64StringWithSeed(data string, seed uint64) uint64 { 57 var ( 58 a, b uint64 59 ) 60 61 length := len(data) 62 i := uintptr(len(data)) 63 paddr := *(*unsafe.Pointer)(unsafe.Pointer(&data)) 64 65 if i > 64 { 66 var see1 = seed 67 for i > 64 { 68 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) 69 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) 70 paddr = add(paddr, 64) 71 i -= 64 72 } 73 seed ^= see1 74 } 75 76 for i > 16 { 77 seed = _wymix(runtimex.ReadUnaligned64(paddr)^s1, runtimex.ReadUnaligned64(add(paddr, 8))^seed) 78 paddr = add(paddr, 16) 79 i -= 16 80 } 81 82 // i <= 16 83 switch { 84 case i == 0: 85 return _wymix(s1, _wymix(s1, seed)) 86 case i < 4: 87 a = uint64(*(*byte)(paddr))<<16 | uint64(*(*byte)(add(paddr, uintptr(i>>1))))<<8 | uint64(*(*byte)(add(paddr, uintptr(i-1)))) 88 // b = 0 89 return _wymix(s1^uint64(length), _wymix(a^s1, seed)) 90 case i == 4: 91 a = runtimex.ReadUnaligned32(paddr) 92 // b = 0 93 return _wymix(s1^uint64(length), _wymix(a^s1, seed)) 94 case i < 8: 95 a = runtimex.ReadUnaligned32(paddr) 96 b = runtimex.ReadUnaligned32(add(paddr, i-4)) 97 return _wymix(s1^uint64(length), _wymix(a^s1, b^seed)) 98 case i == 8: 99 a = runtimex.ReadUnaligned64(paddr) 100 // b = 0 101 return _wymix(s1^uint64(length), _wymix(a^s1, seed)) 102 default: // 8 < i <= 16 103 a = runtimex.ReadUnaligned64(paddr) 104 b = runtimex.ReadUnaligned64(add(paddr, i-8)) 105 return _wymix(s1^uint64(length), _wymix(a^s1, b^seed)) 106 } 107 }