Skip to content

Commit 349b773

Browse files
committed
chore: upgrade and embed the xsync.Map to v4
1 parent 300eb8b commit 349b773

File tree

18 files changed

+3462
-39
lines changed

18 files changed

+3462
-39
lines changed

adapter/adapter.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ import (
1414
"github.com/metacubex/mihomo/common/atomic"
1515
"github.com/metacubex/mihomo/common/queue"
1616
"github.com/metacubex/mihomo/common/utils"
17+
"github.com/metacubex/mihomo/common/xsync"
1718
"github.com/metacubex/mihomo/component/ca"
1819
C "github.com/metacubex/mihomo/constant"
1920
"github.com/metacubex/mihomo/log"
20-
"github.com/puzpuzpuz/xsync/v3"
2121
)
2222

2323
var UnifiedDelay = atomic.NewBool(false)
@@ -35,7 +35,7 @@ type Proxy struct {
3535
C.ProxyAdapter
3636
alive atomic.Bool
3737
history *queue.Queue[C.DelayHistory]
38-
extra *xsync.MapOf[string, *internalProxyState]
38+
extra *xsync.Map[string, *internalProxyState]
3939
}
4040

4141
// Adapter implements C.Proxy
@@ -293,7 +293,7 @@ func NewProxy(adapter C.ProxyAdapter) *Proxy {
293293
ProxyAdapter: adapter,
294294
history: queue.New[C.DelayHistory](defaultHistoriesNum),
295295
alive: atomic.NewBool(true),
296-
extra: xsync.NewMapOf[string, *internalProxyState]()}
296+
extra: xsync.NewMap[string, *internalProxyState]()}
297297
}
298298

299299
func urlToMetadata(rawURL string) (addr C.Metadata, err error) {

common/maphash/common.go

Lines changed: 19 additions & 0 deletions
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+
}

common/maphash/comparable_go120.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
//go:build !go1.24
2+
3+
package maphash
4+
5+
import "unsafe"
6+
7+
func Comparable[T comparable](s Seed, v T) uint64 {
8+
return comparableHash(*(*seedTyp)(unsafe.Pointer(&s)), v)
9+
}
10+
11+
func comparableHash[T comparable](seed seedTyp, v T) uint64 {
12+
s := seed.s
13+
var m map[T]struct{}
14+
mTyp := iTypeOf(m)
15+
var hasher func(unsafe.Pointer, uintptr) uintptr
16+
hasher = (*iMapType)(unsafe.Pointer(mTyp)).Hasher
17+
18+
p := escape(unsafe.Pointer(&v))
19+
20+
if ptrSize == 8 {
21+
return uint64(hasher(p, uintptr(s)))
22+
}
23+
lo := hasher(p, uintptr(s))
24+
hi := hasher(p, uintptr(s>>32))
25+
return uint64(hi)<<32 | uint64(lo)
26+
}
27+
28+
// WriteComparable adds x to the data hashed by h.
29+
func WriteComparable[T comparable](h *Hash, x T) {
30+
// writeComparable (not in purego mode) directly operates on h.state
31+
// without using h.buf. Mix in the buffer length so it won't
32+
// commute with a buffered write, which either changes h.n or changes
33+
// h.state.
34+
hash := (*hashTyp)(unsafe.Pointer(h))
35+
if hash.n != 0 {
36+
hash.state.s = comparableHash(hash.state, hash.n)
37+
}
38+
hash.state.s = comparableHash(hash.state, x)
39+
}
40+
41+
// go/src/hash/maphash/maphash.go
42+
type hashTyp struct {
43+
_ [0]func() // not comparable
44+
seed seedTyp // initial seed used for this hash
45+
state seedTyp // current hash of all flushed bytes
46+
buf [128]byte // unflushed byte buffer
47+
n int // number of unflushed bytes
48+
}
49+
50+
type seedTyp struct {
51+
s uint64
52+
}
53+
54+
type iTFlag uint8
55+
type iKind uint8
56+
type iNameOff int32
57+
58+
// TypeOff is the offset to a type from moduledata.types. See resolveTypeOff in runtime.
59+
type iTypeOff int32
60+
61+
type iType struct {
62+
Size_ uintptr
63+
PtrBytes uintptr // number of (prefix) bytes in the type that can contain pointers
64+
Hash uint32 // hash of type; avoids computation in hash tables
65+
TFlag iTFlag // extra type information flags
66+
Align_ uint8 // alignment of variable with this type
67+
FieldAlign_ uint8 // alignment of struct field with this type
68+
Kind_ iKind // enumeration for C
69+
// function for comparing objects of this type
70+
// (ptr to object A, ptr to object B) -> ==?
71+
Equal func(unsafe.Pointer, unsafe.Pointer) bool
72+
// GCData stores the GC type data for the garbage collector.
73+
// Normally, GCData points to a bitmask that describes the
74+
// ptr/nonptr fields of the type. The bitmask will have at
75+
// least PtrBytes/ptrSize bits.
76+
// If the TFlagGCMaskOnDemand bit is set, GCData is instead a
77+
// **byte and the pointer to the bitmask is one dereference away.
78+
// The runtime will build the bitmask if needed.
79+
// (See runtime/type.go:getGCMask.)
80+
// Note: multiple types may have the same value of GCData,
81+
// including when TFlagGCMaskOnDemand is set. The types will, of course,
82+
// have the same pointer layout (but not necessarily the same size).
83+
GCData *byte
84+
Str iNameOff // string form
85+
PtrToThis iTypeOff // type for pointer to this type, may be zero
86+
}
87+
88+
type iMapType struct {
89+
iType
90+
Key *iType
91+
Elem *iType
92+
Group *iType // internal type representing a slot group
93+
// function for hashing keys (ptr to key, seed) -> hash
94+
Hasher func(unsafe.Pointer, uintptr) uintptr
95+
}
96+
97+
func iTypeOf(a any) *iType {
98+
eface := *(*iEmptyInterface)(unsafe.Pointer(&a))
99+
// Types are either static (for compiler-created types) or
100+
// heap-allocated but always reachable (for reflection-created
101+
// types, held in the central map). So there is no need to
102+
// escape types. noescape here help avoid unnecessary escape
103+
// of v.
104+
return (*iType)(noescape(unsafe.Pointer(eface.Type)))
105+
}
106+
107+
type iEmptyInterface struct {
108+
Type *iType
109+
Data unsafe.Pointer
110+
}
111+
112+
// noescape hides a pointer from escape analysis. noescape is
113+
// the identity function but escape analysis doesn't think the
114+
// output depends on the input. noescape is inlined and currently
115+
// compiles down to zero instructions.
116+
// USE CAREFULLY!
117+
//
118+
// nolint:all
119+
//
120+
//go:nosplit
121+
//goland:noinspection ALL
122+
func noescape(p unsafe.Pointer) unsafe.Pointer {
123+
x := uintptr(p)
124+
return unsafe.Pointer(x ^ 0)
125+
}
126+
127+
var alwaysFalse bool
128+
var escapeSink any
129+
130+
// escape forces any pointers in x to escape to the heap.
131+
func escape[T any](x T) T {
132+
if alwaysFalse {
133+
escapeSink = x
134+
}
135+
return x
136+
}
137+
138+
// ptrSize is the size of a pointer in bytes - unsafe.Sizeof(uintptr(0)) but as an ideal constant.
139+
// It is also the size of the machine's native word size (that is, 4 on 32-bit systems, 8 on 64-bit).
140+
const ptrSize = 4 << (^uintptr(0) >> 63)

common/maphash/comparable_go124.go

Lines changed: 13 additions & 0 deletions
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](seed Seed, v T) uint64 {
8+
return maphash.Comparable(seed, v)
9+
}
10+
11+
func WriteComparable[T comparable](h *Hash, x T) {
12+
maphash.WriteComparable(h, x)
13+
}

0 commit comments

Comments
 (0)