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  	"internal/goexperiment"
    13  	"unsafe"
    14  )
    15  
    16  const purego = false
    17  
    18  //go:linkname runtime_rand runtime.rand
    19  func runtime_rand() uint64
    20  
    21  //go:linkname runtime_memhash runtime.memhash
    22  //go:noescape
    23  func runtime_memhash(p unsafe.Pointer, seed, s uintptr) uintptr
    24  
    25  func rthash(buf []byte, seed uint64) uint64 {
    26  	if len(buf) == 0 {
    27  		return seed
    28  	}
    29  	len := len(buf)
    30  	// The runtime hasher only works on uintptr. For 64-bit
    31  	// architectures, we use the hasher directly. Otherwise,
    32  	// we use two parallel hashers on the lower and upper 32 bits.
    33  	if goarch.PtrSize == 8 {
    34  		return uint64(runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed), uintptr(len)))
    35  	}
    36  	lo := runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed), uintptr(len))
    37  	hi := runtime_memhash(unsafe.Pointer(&buf[0]), uintptr(seed>>32), uintptr(len))
    38  	return uint64(hi)<<32 | uint64(lo)
    39  }
    40  
    41  func rthashString(s string, state uint64) uint64 {
    42  	buf := unsafe.Slice(unsafe.StringData(s), len(s))
    43  	return rthash(buf, state)
    44  }
    45  
    46  func randUint64() uint64 {
    47  	return runtime_rand()
    48  }
    49  
    50  func comparableHash[T comparable](v T, seed Seed) uint64 {
    51  	s := seed.s
    52  	var m map[T]struct{}
    53  	mTyp := abi.TypeOf(m)
    54  	var hasher func(unsafe.Pointer, uintptr) uintptr
    55  	if goexperiment.SwissMap {
    56  		hasher = (*abi.SwissMapType)(unsafe.Pointer(mTyp)).Hasher
    57  	} else {
    58  		hasher = (*abi.OldMapType)(unsafe.Pointer(mTyp)).Hasher
    59  	}
    60  	if goarch.PtrSize == 8 {
    61  		return uint64(hasher(abi.NoEscape(unsafe.Pointer(&v)), uintptr(s)))
    62  	}
    63  	lo := hasher(abi.NoEscape(unsafe.Pointer(&v)), uintptr(s))
    64  	hi := hasher(abi.NoEscape(unsafe.Pointer(&v)), uintptr(s>>32))
    65  	return uint64(hi)<<32 | uint64(lo)
    66  }
    67  
    68  func writeComparable[T comparable](h *Hash, v T) {
    69  	h.state.s = comparableHash(v, h.state)
    70  }
    71  

View as plain text