Source file src/hash/maphash/maphash_runtime.go

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build !purego
     6  
     7  package maphash
     8  
     9  import (
    10  	"internal/abi"
    11  	"internal/goarch"
    12  	"unsafe"
    13  )
    14  
    15  const purego = false
    16  
    17  //go:linkname runtime_rand runtime.rand
    18  func runtime_rand() uint64
    19  
    20  //go:linkname runtime_memhash runtime.memhash
    21  //go:noescape
    22  func runtime_memhash(p unsafe.Pointer, seed, s uintptr) uintptr
    23  
    24  func rthash(buf []byte, seed uint64) uint64 {
    25  	if len(buf) == 0 {
    26  		return seed
    27  	}
    28  	len := len(buf)
    29  	// The runtime hasher only works on uintptr. For 64-bit
    30  	// architectures, we use the hasher directly. Otherwise,
    31  	// we use two parallel hashers on the lower and upper 32 bits.
    32  	if goarch.PtrSize == 8 {
    33  		return uint64(runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed), uintptr(len)))
    34  	}
    35  	lo := runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed), uintptr(len))
    36  	hi := runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed>>32), uintptr(len))
    37  	return uint64(hi)<<32 | uint64(lo)
    38  }
    39  
    40  func rthashString(s string, state uint64) uint64 {
    41  	buf := unsafe.Slice(unsafe.StringData(s), len(s))
    42  	return rthash(buf, state)
    43  }
    44  
    45  func randUint64() uint64 {
    46  	return runtime_rand()
    47  }
    48  
    49  func comparableHash[T comparable](v T, seed Seed) uint64 {
    50  	s := seed.s
    51  	var m map[T]struct{}
    52  	mTyp := abi.TypeOf(m)
    53  	hasher := (*abi.MapType)(unsafe.Pointer(mTyp)).Hasher
    54  	if goarch.PtrSize == 8 {
    55  		return uint64(hasher(abi.NoEscape(unsafe.Pointer(&v)), uintptr(s)))
    56  	}
    57  	lo := hasher(abi.NoEscape(unsafe.Pointer(&v)), uintptr(s))
    58  	hi := hasher(abi.NoEscape(unsafe.Pointer(&v)), uintptr(s>>32))
    59  	return uint64(hi)<<32 | uint64(lo)
    60  }
    61  
    62  func writeComparable[T comparable](h *Hash, v T) {
    63  	h.state.s = comparableHash(v, h.state)
    64  }
    65  

View as plain text