mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-12-19 08:20:05 +08:00
Some checks are pending
Test / test (1.20, macos-15-intel) (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-15-intel) (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-15-intel) (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-15-intel) (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-15-intel) (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
Test / test (1.25, macos-15-intel) (push) Waiting to run
Test / test (1.25, macos-latest) (push) Waiting to run
Test / test (1.25, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.25, ubuntu-latest) (push) Waiting to run
Test / test (1.25, windows-latest) (push) Waiting to run
Trigger CMFA Update / trigger-CMFA-update (push) Waiting to run
143 lines
4.3 KiB
Go
143 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)
|
|
|
|
const testComparableAllocations = false
|