-
Notifications
You must be signed in to change notification settings - Fork 1
/
cache.go
122 lines (102 loc) · 2.85 KB
/
cache.go
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package gg
import (
r "reflect"
"sync"
)
// Type-inferring shortcut for creating a `Cache` of the given type.
func CacheOf[
Key comparable,
Val any,
Ptr Initer1Ptr[Val, Key],
]() *Cache[Key, Val, Ptr] {
return new(Cache[Key, Val, Ptr])
}
// Concurrency-safe cache. See the method reference.
type Cache[
Key comparable,
Val any,
Ptr Initer1Ptr[Val, Key],
] struct {
Map map[Key]Ptr
Lock sync.RWMutex
}
/*
Shortcut for using `.Ptr` and dereferencing the result. May be invalid if the
resulting value is non-copyable, for example when it contains a mutex.
*/
func (self *Cache[Key, Val, Ptr]) Get(key Key) Val { return *self.Ptr(key) }
/*
Returns the cached value for the given key. If the value did not previously
exist, idempotently initializes it by calling `.Init` (by pointer) and caches
the result. For any given key, the value is initialized exactly once, even if
multiple goroutines are trying to access it simultaneously.
*/
func (self *Cache[Key, Val, Ptr]) Ptr(key Key) Ptr {
ptr := self.get(key)
if ptr != nil {
return ptr
}
defer Lock(&self.Lock).Unlock()
ptr = self.Map[key]
if ptr != nil {
return ptr
}
ptr = new(Val)
ptr.Init(key)
MapInit(&self.Map)[key] = ptr
return ptr
}
func (self *Cache[Key, _, Ptr]) get(key Key) Ptr {
defer Lock(self.Lock.RLocker()).Unlock()
return self.Map[key]
}
// Deletes the value for the given key.
func (self *Cache[Key, _, _]) Del(key Key) {
defer Lock(&self.Lock).Unlock()
delete(self.Map, key)
}
// Type-inferring shortcut for creating a `TypeCache` of the given type.
func TypeCacheOf[Val any, Ptr Initer1Ptr[Val, r.Type]]() *TypeCache[Val, Ptr] {
return new(TypeCache[Val, Ptr])
}
/*
Tool for storing information derived from `reflect.Type` that can be generated
once and then cached. Used internally. All methods are concurrency-safe.
*/
type TypeCache[Val any, Ptr Initer1Ptr[Val, r.Type]] struct {
Map map[r.Type]Ptr
Lock sync.RWMutex
}
/*
Shortcut for using `.Ptr` and dereferencing the result. May be invalid if the
resulting value is non-copyable, for example when it contains a mutex.
*/
func (self *TypeCache[Val, Ptr]) Get(key r.Type) Val { return *self.Ptr(key) }
/*
Returns the cached value for the given key. If the value did not previously
exist, idempotently initializes it by calling `.Init` (by pointer) and caches
the result. For any given key, the value is initialized exactly once, even if
multiple goroutines are trying to access it simultaneously.
*/
func (self *TypeCache[Val, Ptr]) Ptr(key r.Type) Ptr {
ptr := self.get(key)
if ptr != nil {
return ptr
}
defer Lock(&self.Lock).Unlock()
ptr = self.Map[key]
if ptr != nil {
return ptr
}
ptr = new(Val)
ptr.Init(key)
if self.Map == nil {
self.Map = map[r.Type]Ptr{}
}
self.Map[key] = ptr
return ptr
}
func (self *TypeCache[Val, Ptr]) get(key r.Type) Ptr {
defer Lock(self.Lock.RLocker()).Unlock()
return self.Map[key]
}