github.com/songzhibin97/gkit@v1.2.13/sys/xxhash3/hash128.go (about)

     1  // Package xxhash3 implements https://github.com/Cyan4973/xxHash/blob/dev/xxhash.h
     2  package xxhash3
     3  
     4  import (
     5  	"github.com/songzhibin97/gkit/internal/hack"
     6  	"github.com/songzhibin97/gkit/internal/runtimex"
     7  	"math/bits"
     8  	"unsafe"
     9  )
    10  
    11  // Hash128 returns the hash value of the byte slice in 128bits.
    12  func Hash128(data []byte) [2]uint64 {
    13  	funcPointer := hashSmall
    14  
    15  	if len(data) > 16 {
    16  		funcPointer = hashLarge
    17  	}
    18  	return hashfunc128[funcPointer](*(*unsafe.Pointer)(unsafe.Pointer(&data)), len(data))
    19  
    20  }
    21  
    22  // Hash128String returns the hash value of the string in 128bits.
    23  func Hash128String(s string) [2]uint64 {
    24  	return Hash128(hack.StringToBytes(s))
    25  }
    26  
    27  func xxh3HashSmall128(xinput unsafe.Pointer, l int) [2]uint64 {
    28  	length := uint64(l)
    29  	var h128Low64 uint64
    30  	var h128High64 uint64
    31  
    32  	if length > 8 {
    33  		bitflipl := xsecret_032 ^ xsecret_040
    34  		bitfliph := xsecret_048 ^ xsecret_056
    35  		inputLow := runtimex.ReadUnaligned64(xinput)
    36  		inputHigh := runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput) + uintptr(length) - 8))
    37  		m128High64, m128Low64 := bits.Mul64(inputLow^inputHigh^bitflipl, prime64_1)
    38  
    39  		m128Low64 += uint64(length-1) << 54
    40  		inputHigh ^= bitfliph
    41  
    42  		m128High64 += inputHigh + uint64(uint32(inputHigh))*(prime32_2-1)
    43  		m128Low64 ^= bits.ReverseBytes64(m128High64)
    44  
    45  		h128High64, h128Low64 = bits.Mul64(m128Low64, prime64_2)
    46  		h128High64 += m128High64 * prime64_2
    47  
    48  		h128Low64 = xxh3Avalanche(h128Low64)
    49  		h128High64 = xxh3Avalanche(h128High64)
    50  
    51  		return [2]uint64{h128High64, h128Low64}
    52  	} else if length >= 4 {
    53  		inputLow := runtimex.ReadUnaligned32(xinput)
    54  		inputHigh := runtimex.ReadUnaligned32(unsafe.Pointer(uintptr(xinput) + uintptr(length) - 4))
    55  		input64 := inputLow + (uint64(inputHigh) << 32)
    56  		bitflip := xsecret_016 ^ xsecret_024
    57  		keyed := input64 ^ bitflip
    58  
    59  		h128High64, h128Low64 = bits.Mul64(keyed, prime64_1+(length)<<2)
    60  		h128High64 += h128Low64 << 1
    61  		h128Low64 ^= h128High64 >> 3
    62  
    63  		h128Low64 ^= h128Low64 >> 35
    64  		h128Low64 *= 0x9fb21c651e98df25
    65  		h128Low64 ^= h128Low64 >> 28
    66  
    67  		h128High64 = xxh3Avalanche(h128High64)
    68  		return [2]uint64{h128High64, h128Low64}
    69  	} else if length == 3 {
    70  		c12 := runtimex.ReadUnaligned16(xinput)
    71  		c3 := uint64(*(*uint8)(unsafe.Pointer(uintptr(xinput) + 2)))
    72  		h128Low64 = c12<<16 + c3 + 3<<8
    73  	} else if length == 2 {
    74  		c12 := runtimex.ReadUnaligned16(xinput)
    75  		h128Low64 = c12*(1<<24+1)>>8 + 2<<8
    76  	} else if length == 1 {
    77  		c1 := uint64(*(*uint8)(xinput))
    78  		h128Low64 = c1*(1<<24+1<<16+1) + 1<<8
    79  	} else if length == 0 {
    80  		return [2]uint64{0x99aa06d3014798d8, 0x6001c324468d497f}
    81  	}
    82  	h128High64 = uint64(bits.RotateLeft32(bits.ReverseBytes32(uint32(h128Low64)), 13))
    83  	bitflipl := uint64(xsecret32_000 ^ xsecret32_004)
    84  	bitfliph := uint64(xsecret32_008 ^ xsecret32_012)
    85  
    86  	h128Low64 = h128Low64 ^ bitflipl
    87  	h128High64 = h128High64 ^ bitfliph
    88  
    89  	h128Low64 = xxh64Avalanche(h128Low64)
    90  	h128High64 = xxh64Avalanche(h128High64)
    91  	return [2]uint64{h128High64, h128Low64}
    92  }
    93  
    94  func xxh3HashLarge128(xinput unsafe.Pointer, l int) (acc [2]uint64) {
    95  	length := uintptr(l)
    96  
    97  	if length <= 128 {
    98  
    99  		accHigh := uint64(0)
   100  		accLow := uint64(length * prime64_1)
   101  
   102  		if length > 32 {
   103  			if length > 64 {
   104  				if length > 96 {
   105  					accLow += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+48))^xsecret_096, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+56))^xsecret_104)
   106  					accLow ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-64))) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-56)))
   107  					accHigh += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-64)))^xsecret_112, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-56)))^xsecret_120)
   108  					accHigh ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+48)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+56))
   109  				}
   110  				accLow += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32))^xsecret_064, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+40))^xsecret_072)
   111  				accLow ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-48))) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-40)))
   112  				accHigh += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-48)))^xsecret_080, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-40)))^xsecret_088)
   113  				accHigh ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+40))
   114  			}
   115  			accLow += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16))^xsecret_032, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+3*8))^xsecret_040)
   116  			accLow ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-32))) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-3*8)))
   117  			accHigh += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-32)))^xsecret_048, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-3*8)))^xsecret_056)
   118  			accHigh ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+3*8))
   119  		}
   120  
   121  		accLow += mix(runtimex.ReadUnaligned64(xinput)^xsecret_000, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+8))^xsecret_008)
   122  		accLow ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-16))) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-8)))
   123  		accHigh += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-16)))^xsecret_016, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(length-8)))^xsecret_024)
   124  		accHigh ^= runtimex.ReadUnaligned64(xinput) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+8))
   125  
   126  		h128Low := accHigh + accLow
   127  		h128High := (accLow * prime64_1) + (accHigh * prime64_4) + uint64(length*prime64_2)
   128  
   129  		h128Low = xxh3Avalanche(h128Low)
   130  		h128High = -xxh3Avalanche(h128High)
   131  
   132  		return [2]uint64{h128High, h128Low}
   133  	} else if length <= 240 {
   134  		accLow64 := uint64(length * prime64_1)
   135  		accHigh64 := uint64(0)
   136  
   137  		accLow64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*0))^xsecret_000, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+8))^xsecret_008)
   138  		accLow64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*0+16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+24))
   139  		accHigh64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*0+16))^xsecret_016, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+24))^xsecret_024)
   140  		accHigh64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*0)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+8))
   141  
   142  		accLow64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1))^xsecret_032, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1+8))^xsecret_040)
   143  		accLow64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1+16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1+24))
   144  		accHigh64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1+16))^xsecret_048, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1+24))^xsecret_056)
   145  		accHigh64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*1)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+uintptr(32*1)+8))
   146  
   147  		accLow64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2))^xsecret_064, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2+8))^xsecret_072)
   148  		accLow64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2+16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2+24))
   149  		accHigh64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2+16))^xsecret_080, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2+24))^xsecret_088)
   150  		accHigh64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*2+8))
   151  
   152  		accLow64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3))^xsecret_096, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3+8))^xsecret_104)
   153  		accLow64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3+16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3+24))
   154  		accHigh64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3+16))^xsecret_112, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3+24))^xsecret_120)
   155  		accHigh64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+32*3+8))
   156  
   157  		accLow64 = xxh3Avalanche(accLow64)
   158  		accHigh64 = xxh3Avalanche(accHigh64)
   159  
   160  		nbRounds := uintptr(length >> 5 << 5)
   161  		for i := uintptr(4 * 32); i < nbRounds; i += 32 {
   162  			accHigh64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i+16))^runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xsecret)+i-109)), runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i+24))^runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xsecret)+i-101)))
   163  			accHigh64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i+8))
   164  
   165  			accLow64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i))^runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xsecret)+i-125)), runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i+8))^runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xsecret)+i-117)))
   166  			accLow64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i+16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+i+24))
   167  		}
   168  
   169  		// last 32 bytes
   170  		accLow64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-16))^xsecret_103, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-8))^xsecret_111)
   171  		accLow64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-32)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-24))
   172  		accHigh64 += mix(runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-32))^xsecret_119, runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-24))^xsecret_127)
   173  		accHigh64 ^= runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-16)) + runtimex.ReadUnaligned64(unsafe.Pointer(uintptr(xinput)+length-8))
   174  
   175  		accHigh64, accLow64 = (accLow64*prime64_1)+(accHigh64*prime64_4)+uint64(length*prime64_2), accHigh64+accLow64
   176  
   177  		accLow64 = xxh3Avalanche(accLow64)
   178  		accHigh64 = -xxh3Avalanche(accHigh64)
   179  
   180  		return [2]uint64{accHigh64, accLow64}
   181  	}
   182  
   183  	var xacc = [8]uint64{
   184  		prime32_3, prime64_1, prime64_2, prime64_3,
   185  		prime64_4, prime32_2, prime64_5, prime32_1}
   186  
   187  	acc[1] = uint64(length * prime64_1)
   188  	acc[0] = uint64(^(length * prime64_2))
   189  
   190  	accum(&xacc, xinput, xsecret, length)
   191  
   192  	// merge xacc
   193  	acc[1] += mix(xacc[0]^xsecret_011, xacc[1]^xsecret_019)
   194  	acc[1] += mix(xacc[2]^xsecret_027, xacc[3]^xsecret_035)
   195  	acc[1] += mix(xacc[4]^xsecret_043, xacc[5]^xsecret_051)
   196  	acc[1] += mix(xacc[6]^xsecret_059, xacc[7]^xsecret_067)
   197  	acc[1] = xxh3Avalanche(acc[1])
   198  
   199  	acc[0] += mix(xacc[0]^xsecret_117, xacc[1]^xsecret_125)
   200  	acc[0] += mix(xacc[2]^xsecret_133, xacc[3]^xsecret_141)
   201  	acc[0] += mix(xacc[4]^xsecret_149, xacc[5]^xsecret_157)
   202  	acc[0] += mix(xacc[6]^xsecret_165, xacc[7]^xsecret_173)
   203  	acc[0] = xxh3Avalanche(acc[0])
   204  
   205  	return acc
   206  }