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  }