-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathmapEntry.go
More file actions
108 lines (88 loc) · 2.98 KB
/
mapEntry.go
File metadata and controls
108 lines (88 loc) · 2.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
package frozen
import (
"sync"
"github.com/arr-ai/frozen/internal/pkg/hash"
"github.com/arr-ai/frozen/internal/pkg/tree"
"github.com/arr-ai/frozen/internal/pkg/value"
)
type mapEntry[K, V any] struct {
KeyValue[K, V]
}
func newMapEntry[K, V any](k K, v V) mapEntry[K, V] {
return mapEntry[K, V]{KeyValue: KeyValue[K, V]{Key: k, Value: v}}
}
func newMapKey[K, V any](k K) mapEntry[K, V] {
var v V
return mapEntry[K, V]{KeyValue: KeyValue[K, V]{Key: k, Value: v}}
}
// Equal implements value.Equaler for key-only comparison in the default path
// (Tree.Get, Tree.With, Tree.Without).
func (e mapEntry[K, V]) Equal(e2 mapEntry[K, V]) bool {
return value.Equal(e.Key, e2.Key)
}
// Hash implements hash.Hashable for key-only hashing in the default path.
func (e mapEntry[K, V]) Hash(seed uintptr) uintptr {
return hash.Any(e.Key, seed)
}
// mapEntryEqHash provides full entry equality (key + value) for Map.Equal and similar.
type mapEntryEqHash[K, V any] struct {
eqK func(K, K) bool
eqV func(V, V) bool
hash func(mapEntry[K, V]) tree.H128
}
func (m *mapEntryEqHash[K, V]) Equal(a, b mapEntry[K, V]) bool {
return m.eqK(a.Key, b.Key) && m.eqV(a.Value, b.Value)
}
func (m *mapEntryEqHash[K, V]) Hash(a mapEntry[K, V]) tree.H128 {
return m.hash(a)
}
func (m *mapEntryEqHash[K, V]) FullHash() bool { return false }
// mapKeyEqHash provides key-only equality for Map operations (With, Without, etc.).
type mapKeyEqHash[K, V any] struct {
eqK func(K, K) bool
hash func(mapEntry[K, V]) tree.H128
}
func (m *mapKeyEqHash[K, V]) Equal(a, b mapEntry[K, V]) bool {
return m.eqK(a.Key, b.Key)
}
func (m *mapKeyEqHash[K, V]) Hash(a mapEntry[K, V]) tree.H128 {
return m.hash(a)
}
func (m *mapKeyEqHash[K, V]) FullHash() bool { return false }
// mapEntryHashFunc returns a non-boxing H128 hash function for mapEntry[K, V].
// It hashes only the key, consistent with mapEntry.Hash, but avoids boxing the
// mapEntry struct through the Hashable interface and avoids boxing the key
// through hash.Any.
func mapEntryHashFunc[K, V any]() func(mapEntry[K, V]) tree.H128 {
kHash := tree.GetSeededHashFunc[K]()
return func(e mapEntry[K, V]) tree.H128 {
return tree.MakeH128(kHash(e.Key, 0), kHash(e.Key, 1))
}
}
var mapEntryEqHashCache sync.Map
func getMapEntryEqHash[K, V any]() *mapEntryEqHash[K, V] {
key := tree.TypeKeyOf[mapEntry[K, V]]()
if f, ok := mapEntryEqHashCache.Load(key); ok {
return f.(*mapEntryEqHash[K, V]) //nolint:forcetypeassert
}
ops := &mapEntryEqHash[K, V]{
eqK: value.EqualFuncFor[K](),
eqV: value.EqualFuncFor[V](),
hash: mapEntryHashFunc[K, V](),
}
mapEntryEqHashCache.Store(key, ops)
return ops
}
var mapKeyEqHashCache sync.Map
func getMapKeyEqHash[K, V any]() *mapKeyEqHash[K, V] {
key := tree.TypeKeyOf[mapEntry[K, V]]()
if f, ok := mapKeyEqHashCache.Load(key); ok {
return f.(*mapKeyEqHash[K, V]) //nolint:forcetypeassert
}
ops := &mapKeyEqHash[K, V]{
eqK: value.EqualFuncFor[K](),
hash: mapEntryHashFunc[K, V](),
}
mapKeyEqHashCache.Store(key, ops)
return ops
}