Source file
src/sync/map_reference_test.go
Documentation: sync
1
2
3
4
5 package sync_test
6
7 import (
8 "sync"
9 "sync/atomic"
10 )
11
12
13
14
15 type mapInterface interface {
16 Load(any) (any, bool)
17 Store(key, value any)
18 LoadOrStore(key, value any) (actual any, loaded bool)
19 LoadAndDelete(key any) (value any, loaded bool)
20 Delete(any)
21 Swap(key, value any) (previous any, loaded bool)
22 CompareAndSwap(key, old, new any) (swapped bool)
23 CompareAndDelete(key, old any) (deleted bool)
24 Range(func(key, value any) (shouldContinue bool))
25 }
26
27 var (
28 _ mapInterface = &RWMutexMap{}
29 _ mapInterface = &DeepCopyMap{}
30 )
31
32
33 type RWMutexMap struct {
34 mu sync.RWMutex
35 dirty map[any]any
36 }
37
38 func (m *RWMutexMap) Load(key any) (value any, ok bool) {
39 m.mu.RLock()
40 value, ok = m.dirty[key]
41 m.mu.RUnlock()
42 return
43 }
44
45 func (m *RWMutexMap) Store(key, value any) {
46 m.mu.Lock()
47 if m.dirty == nil {
48 m.dirty = make(map[any]any)
49 }
50 m.dirty[key] = value
51 m.mu.Unlock()
52 }
53
54 func (m *RWMutexMap) LoadOrStore(key, value any) (actual any, loaded bool) {
55 m.mu.Lock()
56 actual, loaded = m.dirty[key]
57 if !loaded {
58 actual = value
59 if m.dirty == nil {
60 m.dirty = make(map[any]any)
61 }
62 m.dirty[key] = value
63 }
64 m.mu.Unlock()
65 return actual, loaded
66 }
67
68 func (m *RWMutexMap) Swap(key, value any) (previous any, loaded bool) {
69 m.mu.Lock()
70 if m.dirty == nil {
71 m.dirty = make(map[any]any)
72 }
73
74 previous, loaded = m.dirty[key]
75 m.dirty[key] = value
76 m.mu.Unlock()
77 return
78 }
79
80 func (m *RWMutexMap) LoadAndDelete(key any) (value any, loaded bool) {
81 m.mu.Lock()
82 value, loaded = m.dirty[key]
83 if !loaded {
84 m.mu.Unlock()
85 return nil, false
86 }
87 delete(m.dirty, key)
88 m.mu.Unlock()
89 return value, loaded
90 }
91
92 func (m *RWMutexMap) Delete(key any) {
93 m.mu.Lock()
94 delete(m.dirty, key)
95 m.mu.Unlock()
96 }
97
98 func (m *RWMutexMap) CompareAndSwap(key, old, new any) (swapped bool) {
99 m.mu.Lock()
100 defer m.mu.Unlock()
101 if m.dirty == nil {
102 return false
103 }
104
105 value, loaded := m.dirty[key]
106 if loaded && value == old {
107 m.dirty[key] = new
108 return true
109 }
110 return false
111 }
112
113 func (m *RWMutexMap) CompareAndDelete(key, old any) (deleted bool) {
114 m.mu.Lock()
115 defer m.mu.Unlock()
116 if m.dirty == nil {
117 return false
118 }
119
120 value, loaded := m.dirty[key]
121 if loaded && value == old {
122 delete(m.dirty, key)
123 return true
124 }
125 return false
126 }
127
128 func (m *RWMutexMap) Range(f func(key, value any) (shouldContinue bool)) {
129 m.mu.RLock()
130 keys := make([]any, 0, len(m.dirty))
131 for k := range m.dirty {
132 keys = append(keys, k)
133 }
134 m.mu.RUnlock()
135
136 for _, k := range keys {
137 v, ok := m.Load(k)
138 if !ok {
139 continue
140 }
141 if !f(k, v) {
142 break
143 }
144 }
145 }
146
147
148
149
150 type DeepCopyMap struct {
151 mu sync.Mutex
152 clean atomic.Value
153 }
154
155 func (m *DeepCopyMap) Load(key any) (value any, ok bool) {
156 clean, _ := m.clean.Load().(map[any]any)
157 value, ok = clean[key]
158 return value, ok
159 }
160
161 func (m *DeepCopyMap) Store(key, value any) {
162 m.mu.Lock()
163 dirty := m.dirty()
164 dirty[key] = value
165 m.clean.Store(dirty)
166 m.mu.Unlock()
167 }
168
169 func (m *DeepCopyMap) LoadOrStore(key, value any) (actual any, loaded bool) {
170 clean, _ := m.clean.Load().(map[any]any)
171 actual, loaded = clean[key]
172 if loaded {
173 return actual, loaded
174 }
175
176 m.mu.Lock()
177
178 clean, _ = m.clean.Load().(map[any]any)
179 actual, loaded = clean[key]
180 if !loaded {
181 dirty := m.dirty()
182 dirty[key] = value
183 actual = value
184 m.clean.Store(dirty)
185 }
186 m.mu.Unlock()
187 return actual, loaded
188 }
189
190 func (m *DeepCopyMap) Swap(key, value any) (previous any, loaded bool) {
191 m.mu.Lock()
192 dirty := m.dirty()
193 previous, loaded = dirty[key]
194 dirty[key] = value
195 m.clean.Store(dirty)
196 m.mu.Unlock()
197 return
198 }
199
200 func (m *DeepCopyMap) LoadAndDelete(key any) (value any, loaded bool) {
201 m.mu.Lock()
202 dirty := m.dirty()
203 value, loaded = dirty[key]
204 delete(dirty, key)
205 m.clean.Store(dirty)
206 m.mu.Unlock()
207 return
208 }
209
210 func (m *DeepCopyMap) Delete(key any) {
211 m.mu.Lock()
212 dirty := m.dirty()
213 delete(dirty, key)
214 m.clean.Store(dirty)
215 m.mu.Unlock()
216 }
217
218 func (m *DeepCopyMap) CompareAndSwap(key, old, new any) (swapped bool) {
219 clean, _ := m.clean.Load().(map[any]any)
220 if previous, ok := clean[key]; !ok || previous != old {
221 return false
222 }
223
224 m.mu.Lock()
225 defer m.mu.Unlock()
226 dirty := m.dirty()
227 value, loaded := dirty[key]
228 if loaded && value == old {
229 dirty[key] = new
230 m.clean.Store(dirty)
231 return true
232 }
233 return false
234 }
235
236 func (m *DeepCopyMap) CompareAndDelete(key, old any) (deleted bool) {
237 clean, _ := m.clean.Load().(map[any]any)
238 if previous, ok := clean[key]; !ok || previous != old {
239 return false
240 }
241
242 m.mu.Lock()
243 defer m.mu.Unlock()
244
245 dirty := m.dirty()
246 value, loaded := dirty[key]
247 if loaded && value == old {
248 delete(dirty, key)
249 m.clean.Store(dirty)
250 return true
251 }
252 return false
253 }
254
255 func (m *DeepCopyMap) Range(f func(key, value any) (shouldContinue bool)) {
256 clean, _ := m.clean.Load().(map[any]any)
257 for k, v := range clean {
258 if !f(k, v) {
259 break
260 }
261 }
262 }
263
264 func (m *DeepCopyMap) dirty() map[any]any {
265 clean, _ := m.clean.Load().(map[any]any)
266 dirty := make(map[any]any, len(clean)+1)
267 for k, v := range clean {
268 dirty[k] = v
269 }
270 return dirty
271 }
272
View as plain text