github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/sys/xxhash3/hash.go (about)

     1  // Package xxhash3 implements https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h
     2  package xxhash3
     3  
     4  import (
     5  	"math/bits"
     6  	"unsafe"
     7  
     8  	"github.com/songzhibin97/go-baseutils/internal/hack"
     9  	"github.com/songzhibin97/go-baseutils/internal/runtimex"
    10  )
    11  
    12  // Hash returns the hash value of the byte slice in 64bits.
    13  func Hash(data []byte) uint64 {
    14  	funcPointer := hashSmall
    15  
    16  	if len(data) > 16 {
    17  		funcPointer = hashLarge
    18  	}
    19  	return hashfunc[funcPointer](*(*unsafe.Pointer)(unsafe.Pointer(&data)), len(data))
    20  
    21  }
    22  
    23  // HashString returns the hash value of the string in 64bits.
    24  func HashString(s string) uint64 {
    25  	return Hash(hack.StringToBytes(s))
    26  }
    27  
    28  func xxh3HashSmall(xinput unsafe.Pointer, length int) uint64 {
    29  
    30  	if length > 8 {
    31  		inputlo := runtimex.ReadUnaligned64(xinput) ^ xsecret_024 ^ xsecret_032
    32  		inputhi := runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-8))) ^ xsecret_040 ^ xsecret_048
    33  		return xxh3Avalanche(uint64(length) + bits.ReverseBytes64(inputlo) + inputhi + mix(inputlo, inputhi))
    34  	} else if length >= 4 {
    35  		input1 := runtimex.ReadUnaligned32(xinput)
    36  		input2 := runtimex.ReadUnaligned32(unsafe.Pointer(uintptr(xinput) + uintptr(length-4)))
    37  		input64 := input2 + input1<<32
    38  		keyed := input64 ^ xsecret_008 ^ xsecret_016
    39  		return xxh3RRMXMX(keyed, uint64(length))
    40  	} else if length == 3 {
    41  		c12 := runtimex.ReadUnaligned16(xinput)
    42  		c3 := uint64(*(*uint8)(unsafe.Pointer(uintptr(xinput) + 2)))
    43  		acc := c12<<16 + c3 + 3<<8
    44  		acc ^= uint64(xsecret32_000 ^ xsecret32_004)
    45  		return xxh64Avalanche(acc)
    46  	} else if length == 2 {
    47  		c12 := runtimex.ReadUnaligned16(xinput)
    48  		acc := c12*(1<<24+1)>>8 + 2<<8
    49  		acc ^= uint64(xsecret32_000 ^ xsecret32_004)
    50  		return xxh64Avalanche(acc)
    51  	} else if length == 1 {
    52  		c1 := uint64(*(*uint8)(xinput))
    53  		acc := c1*(1<<24+1<<16+1) + 1<<8
    54  		acc ^= uint64(xsecret32_000 ^ xsecret32_004)
    55  		return xxh64Avalanche(acc)
    56  	}
    57  	return 0x2d06800538d394c2
    58  }
    59  
    60  func xxh3HashLarge(xinput unsafe.Pointer, l int) (acc uint64) {
    61  	length := uintptr(l)
    62  
    63  	if length <= 128 {
    64  		acc := uint64(length * prime64_1)
    65  		if length > 32 {
    66  			if length > 64 {
    67  				if length > 96 {
    68  					acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+48))^xsecret_096, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+56))^xsecret_104)
    69  					acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-64)))^xsecret_112, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-56)))^xsecret_120)
    70  				}
    71  				acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32))^xsecret_064, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+40))^xsecret_072)
    72  				acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-48)))^xsecret_080, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-40)))^xsecret_088)
    73  			}
    74  			acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16))^xsecret_032, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+24))^xsecret_040)
    75  			acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-32)))^xsecret_048, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-24)))^xsecret_056)
    76  		}
    77  		acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+0))^xsecret_000, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+8))^xsecret_008)
    78  		acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-16)))^xsecret_016, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-8)))^xsecret_024)
    79  
    80  		return xxh3Avalanche(acc)
    81  
    82  	} else if length <= 240 {
    83  		acc := uint64(length * prime64_1)
    84  
    85  		acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*0))^xsecret_000, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*0+8))^xsecret_008)
    86  		acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*1))^xsecret_016, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*1+8))^xsecret_024)
    87  		acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*2))^xsecret_032, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*2+8))^xsecret_040)
    88  		acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*3))^xsecret_048, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*3+8))^xsecret_056)
    89  		acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*4))^xsecret_064, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*4+8))^xsecret_072)
    90  		acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*5))^xsecret_080, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*5+8))^xsecret_088)
    91  		acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*6))^xsecret_096, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*6+8))^xsecret_104)
    92  		acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*7))^xsecret_112, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16*7+8))^xsecret_120)
    93  
    94  		acc = xxh3Avalanche(acc)
    95  		nbRounds := uint64(length >> 4 << 4)
    96  
    97  		for i := uint64(8 * 16); i < nbRounds; i += 16 {
    98  			acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(i)))^runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xsecret)+uintptr(i-125))), runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(i+8)))^runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xsecret)+uintptr(i-117))))
    99  		}
   100  
   101  		acc += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-16)))^xsecret_119, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-8)))^xsecret_127)
   102  
   103  		return xxh3Avalanche(acc)
   104  	}
   105  
   106  	var xacc = [8]uint64{
   107  		prime32_3, prime64_1, prime64_2, prime64_3,
   108  		prime64_4, prime32_2, prime64_5, prime32_1}
   109  
   110  	acc = uint64(length * prime64_1)
   111  
   112  	accum(&xacc, xinput, xsecret, length)
   113  
   114  	//merge xacc
   115  	acc += mix(xacc[0]^xsecret_011, xacc[1]^xsecret_019)
   116  	acc += mix(xacc[2]^xsecret_027, xacc[3]^xsecret_035)
   117  	acc += mix(xacc[4]^xsecret_043, xacc[5]^xsecret_051)
   118  	acc += mix(xacc[6]^xsecret_059, xacc[7]^xsecret_067)
   119  
   120  	return xxh3Avalanche(acc)
   121  }