|
| 1 | +//go:build !go1.24 |
| 2 | + |
| 3 | +package maphash |
| 4 | + |
| 5 | +import ( |
| 6 | + "github.com/metacubex/backport-std/internal/abi" |
| 7 | + "unsafe" |
| 8 | +) |
| 9 | + |
| 10 | +// ptrSize is the size of a pointer in bytes - unsafe.Sizeof(uintptr(0)) but as an ideal constant. |
| 11 | +// It is also the size of the machine's native word size (that is, 4 on 32-bit systems, 8 on 64-bit). |
| 12 | +const ptrSize = 4 << (^uintptr(0) >> 63) |
| 13 | + |
| 14 | +func Comparable[T comparable](s Seed, v T) uint64 { |
| 15 | + return comparableHash(*(*seedTyp)(unsafe.Pointer(&s)), v) |
| 16 | +} |
| 17 | + |
| 18 | +func comparableHash[T comparable](seed seedTyp, v T) uint64 { |
| 19 | + s := seed.s |
| 20 | + var m map[T]struct{} |
| 21 | + mTyp := abi.TypeOf(m) |
| 22 | + var hasher func(unsafe.Pointer, uintptr) uintptr |
| 23 | + if abi.SwissMap { |
| 24 | + hasher = (*abi.SwissMapType)(unsafe.Pointer(mTyp)).Hasher |
| 25 | + } else { |
| 26 | + hasher = (*abi.OldMapType)(unsafe.Pointer(mTyp)).Hasher |
| 27 | + } |
| 28 | + |
| 29 | + p := abi.Escape(unsafe.Pointer(&v)) |
| 30 | + |
| 31 | + if ptrSize == 8 { |
| 32 | + return uint64(hasher(p, uintptr(s))) |
| 33 | + } |
| 34 | + lo := hasher(p, uintptr(s)) |
| 35 | + hi := hasher(p, uintptr(s>>32)) |
| 36 | + return uint64(hi)<<32 | uint64(lo) |
| 37 | +} |
| 38 | + |
| 39 | +// WriteComparable adds x to the data hashed by h. |
| 40 | +func WriteComparable[T comparable](h *Hash, x T) { |
| 41 | + // writeComparable (not in purego mode) directly operates on h.state |
| 42 | + // without using h.buf. Mix in the buffer length so it won't |
| 43 | + // commute with a buffered write, which either changes h.n or changes |
| 44 | + // h.state. |
| 45 | + hash := (*hashTyp)(unsafe.Pointer(h)) |
| 46 | + if hash.n != 0 { |
| 47 | + hash.state.s = comparableHash(hash.state, hash.n) |
| 48 | + } |
| 49 | + hash.state.s = comparableHash(hash.state, x) |
| 50 | +} |
| 51 | + |
| 52 | +// go/src/hash/maphash/maphash.go |
| 53 | +type hashTyp struct { |
| 54 | + _ [0]func() // not comparable |
| 55 | + seed seedTyp // initial seed used for this hash |
| 56 | + state seedTyp // current hash of all flushed bytes |
| 57 | + buf [128]byte // unflushed byte buffer |
| 58 | + n int // number of unflushed bytes |
| 59 | +} |
| 60 | + |
| 61 | +type seedTyp struct { |
| 62 | + s uint64 |
| 63 | +} |
0 commit comments