Skip to content

Commit 680730f

Browse files
committed
add maphash
1 parent 1b8fa16 commit 680730f

11 files changed

+1626
-0
lines changed

hash/maphash/common.go

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package maphash
2+
3+
import "hash/maphash"
4+
5+
type Seed = maphash.Seed
6+
7+
func MakeSeed() Seed {
8+
return maphash.MakeSeed()
9+
}
10+
11+
type Hash = maphash.Hash
12+
13+
func Bytes(seed Seed, b []byte) uint64 {
14+
return maphash.Bytes(seed, b)
15+
}
16+
17+
func String(seed Seed, s string) uint64 {
18+
return maphash.String(seed, s)
19+
}

hash/maphash/comparable_go120.go

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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+
}

hash/maphash/comparable_go124.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//go:build go1.24
2+
3+
package maphash
4+
5+
import "hash/maphash"
6+
7+
func Comparable[T comparable](s Seed, v T) uint64 {
8+
return maphash.Comparable(s, v)
9+
}
10+
11+
func WriteComparable[T comparable](h *Hash, x T) {
12+
maphash.WriteComparable(h, x)
13+
}

0 commit comments

Comments
 (0)