mihomo/common/maphash/comparable_go120.go
wwqgtxx 349b773b40
Some checks are pending
Test / test (1.20, macos-13) (push) Waiting to run
Test / test (1.20, macos-latest) (push) Waiting to run
Test / test (1.20, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.20, ubuntu-latest) (push) Waiting to run
Test / test (1.20, windows-latest) (push) Waiting to run
Test / test (1.21, macos-13) (push) Waiting to run
Test / test (1.21, macos-latest) (push) Waiting to run
Test / test (1.21, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.21, ubuntu-latest) (push) Waiting to run
Test / test (1.21, windows-latest) (push) Waiting to run
Test / test (1.22, macos-13) (push) Waiting to run
Test / test (1.22, macos-latest) (push) Waiting to run
Test / test (1.22, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.22, ubuntu-latest) (push) Waiting to run
Test / test (1.22, windows-latest) (push) Waiting to run
Test / test (1.23, macos-13) (push) Waiting to run
Test / test (1.23, macos-latest) (push) Waiting to run
Test / test (1.23, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.23, ubuntu-latest) (push) Waiting to run
Test / test (1.23, windows-latest) (push) Waiting to run
Test / test (1.24, macos-13) (push) Waiting to run
Test / test (1.24, macos-latest) (push) Waiting to run
Test / test (1.24, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.24, ubuntu-latest) (push) Waiting to run
Test / test (1.24, windows-latest) (push) Waiting to run
Trigger CMFA Update / trigger-CMFA-update (push) Waiting to run
chore: upgrade and embed the xsync.Map to v4
2025-07-15 13:39:03 +08:00

141 lines
4.3 KiB
Go

//go:build !go1.24
package maphash
import "unsafe"
func Comparable[T comparable](s Seed, v T) uint64 {
return comparableHash(*(*seedTyp)(unsafe.Pointer(&s)), v)
}
func comparableHash[T comparable](seed seedTyp, v T) uint64 {
s := seed.s
var m map[T]struct{}
mTyp := iTypeOf(m)
var hasher func(unsafe.Pointer, uintptr) uintptr
hasher = (*iMapType)(unsafe.Pointer(mTyp)).Hasher
p := escape(unsafe.Pointer(&v))
if ptrSize == 8 {
return uint64(hasher(p, uintptr(s)))
}
lo := hasher(p, uintptr(s))
hi := hasher(p, uintptr(s>>32))
return uint64(hi)<<32 | uint64(lo)
}
// WriteComparable adds x to the data hashed by h.
func WriteComparable[T comparable](h *Hash, x T) {
// writeComparable (not in purego mode) directly operates on h.state
// without using h.buf. Mix in the buffer length so it won't
// commute with a buffered write, which either changes h.n or changes
// h.state.
hash := (*hashTyp)(unsafe.Pointer(h))
if hash.n != 0 {
hash.state.s = comparableHash(hash.state, hash.n)
}
hash.state.s = comparableHash(hash.state, x)
}
// go/src/hash/maphash/maphash.go
type hashTyp struct {
_ [0]func() // not comparable
seed seedTyp // initial seed used for this hash
state seedTyp // current hash of all flushed bytes
buf [128]byte // unflushed byte buffer
n int // number of unflushed bytes
}
type seedTyp struct {
s uint64
}
type iTFlag uint8
type iKind uint8
type iNameOff int32
// TypeOff is the offset to a type from moduledata.types. See resolveTypeOff in runtime.
type iTypeOff int32
type iType struct {
Size_ uintptr
PtrBytes uintptr // number of (prefix) bytes in the type that can contain pointers
Hash uint32 // hash of type; avoids computation in hash tables
TFlag iTFlag // extra type information flags
Align_ uint8 // alignment of variable with this type
FieldAlign_ uint8 // alignment of struct field with this type
Kind_ iKind // enumeration for C
// function for comparing objects of this type
// (ptr to object A, ptr to object B) -> ==?
Equal func(unsafe.Pointer, unsafe.Pointer) bool
// GCData stores the GC type data for the garbage collector.
// Normally, GCData points to a bitmask that describes the
// ptr/nonptr fields of the type. The bitmask will have at
// least PtrBytes/ptrSize bits.
// If the TFlagGCMaskOnDemand bit is set, GCData is instead a
// **byte and the pointer to the bitmask is one dereference away.
// The runtime will build the bitmask if needed.
// (See runtime/type.go:getGCMask.)
// Note: multiple types may have the same value of GCData,
// including when TFlagGCMaskOnDemand is set. The types will, of course,
// have the same pointer layout (but not necessarily the same size).
GCData *byte
Str iNameOff // string form
PtrToThis iTypeOff // type for pointer to this type, may be zero
}
type iMapType struct {
iType
Key *iType
Elem *iType
Group *iType // internal type representing a slot group
// function for hashing keys (ptr to key, seed) -> hash
Hasher func(unsafe.Pointer, uintptr) uintptr
}
func iTypeOf(a any) *iType {
eface := *(*iEmptyInterface)(unsafe.Pointer(&a))
// Types are either static (for compiler-created types) or
// heap-allocated but always reachable (for reflection-created
// types, held in the central map). So there is no need to
// escape types. noescape here help avoid unnecessary escape
// of v.
return (*iType)(noescape(unsafe.Pointer(eface.Type)))
}
type iEmptyInterface struct {
Type *iType
Data unsafe.Pointer
}
// noescape hides a pointer from escape analysis. noescape is
// the identity function but escape analysis doesn't think the
// output depends on the input. noescape is inlined and currently
// compiles down to zero instructions.
// USE CAREFULLY!
//
// nolint:all
//
//go:nosplit
//goland:noinspection ALL
func noescape(p unsafe.Pointer) unsafe.Pointer {
x := uintptr(p)
return unsafe.Pointer(x ^ 0)
}
var alwaysFalse bool
var escapeSink any
// escape forces any pointers in x to escape to the heap.
func escape[T any](x T) T {
if alwaysFalse {
escapeSink = x
}
return x
}
// ptrSize is the size of a pointer in bytes - unsafe.Sizeof(uintptr(0)) but as an ideal constant.
// It is also the size of the machine's native word size (that is, 4 on 32-bit systems, 8 on 64-bit).
const ptrSize = 4 << (^uintptr(0) >> 63)