-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfastmap.go
More file actions
69 lines (57 loc) · 1.58 KB
/
fastmap.go
File metadata and controls
69 lines (57 loc) · 1.58 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
//go:build go1.19
// +build go1.19
package di
import (
"reflect"
"sync"
"sync/atomic"
"unsafe"
)
// typeKey: address of reflect.Type – estable mientras el proceso viva.
// func typeKey(t reflect.Type) uintptr { return uintptr(unsafe.Pointer(t)) }
// typeKey devuelve la dirección interna (*rtype) de un reflect.Type.
// Go garantiza que dicho puntero no cambia en tiempo de ejecución.
func typeKey(t reflect.Type) uintptr {
// La representación de una interface{} en memoria es [2]uintptr:
// [0] = puntero al descriptor de tipo (itab/itab*), [1] = datos.
return uintptr((*[2]uintptr)(unsafe.Pointer(&t))[1])
}
type entry struct{ v interface{} }
// safeMap = mapa inmutable con copia-en-escritura.
// - Lecturas: 1 atomic + lookup => ~4-8 ns.
// - Escrituras: copia bajo mutex; los lectores nunca se bloquean.
type safeMap struct {
data atomic.Value // map[uintptr]entry
mu sync.Mutex // serializa Stores
}
func newSafeMap() *safeMap {
m := &safeMap{}
m.data.Store(make(map[uintptr]entry))
return m
}
func (m *safeMap) Load(k uintptr) (e entry, ok bool) {
e, ok = m.data.Load().(map[uintptr]entry)[k]
return
}
func (m *safeMap) Store(k uintptr, e entry) {
m.mu.Lock()
old := m.data.Load().(map[uintptr]entry)
if prev, ok := old[k]; ok && prev == e {
m.mu.Unlock()
return // sin trabajo
}
clone := make(map[uintptr]entry, len(old)+1)
for k0, v := range old {
clone[k0] = v
}
clone[k] = e
m.data.Store(clone)
m.mu.Unlock()
}
func (m *safeMap) Range(fn func(entry) bool) {
for _, v := range m.data.Load().(map[uintptr]entry) {
if !fn(v) {
return
}
}
}