@@ -41,7 +41,7 @@ type Map[K comparable, V any] struct {
41
41
// Entries stored in read may be updated concurrently without mu, but updating
42
42
// a previously-expunged entry requires that the entry be copied to the dirty
43
43
// map and unexpunged with mu held.
44
- read Pointer [readOnly [K ]]
44
+ read atomic. Pointer [readOnly [K ]]
45
45
46
46
// dirty contains the portion of the map's contents that require mu to be
47
47
// held. To ensure that the dirty map can be promoted to the read map quickly,
@@ -102,18 +102,25 @@ func newEntry[V any](i V) *entry {
102
102
return & entry {p : unsafe .Pointer (& i )}
103
103
}
104
104
105
+ func (m * Map [K , V ]) loadReadOnly () readOnly [K ] {
106
+ if p := m .read .Load (); p != nil {
107
+ return * p
108
+ }
109
+ return readOnly [K ]{}
110
+ }
111
+
105
112
// Load returns the value stored in the map for a key, or nil if no
106
113
// value is present.
107
114
// The ok result indicates whether value was found in the map.
108
115
func (m * Map [K , V ]) Load (key K ) (value V , ok bool ) {
109
- read , _ := m .read . LoadValue ()
116
+ read := m .loadReadOnly ()
110
117
e , ok := read .m [key ]
111
118
if ! ok && read .amended {
112
119
m .mu .Lock ()
113
120
// Avoid reporting a spurious miss if m.dirty got promoted while we were
114
121
// blocked on m.mu. (If further loads of the same key will not miss, it's
115
122
// not worth copying the dirty map for this key.)
116
- read , _ = m .read . LoadValue ()
123
+ read = m .loadReadOnly ()
117
124
e , ok = read .m [key ]
118
125
if ! ok && read .amended {
119
126
e , ok = m .dirty [key ]
@@ -140,13 +147,13 @@ func entryLoad[V any](e *entry) (value V, ok bool) {
140
147
141
148
// Store sets the value for a key.
142
149
func (m * Map [K , V ]) Store (key K , value V ) {
143
- read , _ := m .read . LoadValue ()
150
+ read := m .loadReadOnly ()
144
151
if e , ok := read .m [key ]; ok && tryStore (e , & value ) {
145
152
return
146
153
}
147
154
148
155
m .mu .Lock ()
149
- read , _ = m .read . LoadValue ()
156
+ read = m .loadReadOnly ()
150
157
if e , ok := read .m [key ]; ok {
151
158
if e .unexpungeLocked () {
152
159
// The entry was previously expunged, which implies that there is a
@@ -204,7 +211,7 @@ func entryStoreLocked[V any](e *entry, i *V) {
204
211
// The loaded result is true if the value was loaded, false if stored.
205
212
func (m * Map [K , V ]) LoadOrStore (key K , value V ) (actual V , loaded bool ) {
206
213
// Avoid locking if it's a clean hit.
207
- read , _ := m .read . LoadValue ()
214
+ read := m .loadReadOnly ()
208
215
if e , ok := read .m [key ]; ok {
209
216
actual , loaded , ok := entryTryLoadOrStore (e , value )
210
217
if ok {
@@ -213,7 +220,7 @@ func (m *Map[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) {
213
220
}
214
221
215
222
m .mu .Lock ()
216
- read , _ = m .read . LoadValue ()
223
+ read = m .loadReadOnly ()
217
224
if e , ok := read .m [key ]; ok {
218
225
if e .unexpungeLocked () {
219
226
m .dirty [key ] = e
@@ -272,11 +279,11 @@ func entryTryLoadOrStore[V any](e *entry, i V) (actual V, loaded, ok bool) {
272
279
// LoadAndDelete deletes the value for a key, returning the previous value if any.
273
280
// The loaded result reports whether the key was present.
274
281
func (m * Map [K , V ]) LoadAndDelete (key K ) (value V , loaded bool ) {
275
- read , _ := m .read . LoadValue ()
282
+ read := m .loadReadOnly ()
276
283
e , ok := read .m [key ]
277
284
if ! ok && read .amended {
278
285
m .mu .Lock ()
279
- read , _ = m .read . LoadValue ()
286
+ read = m .loadReadOnly ()
280
287
e , ok = read .m [key ]
281
288
if ! ok && read .amended {
282
289
e , ok = m .dirty [key ]
@@ -327,14 +334,14 @@ func (m *Map[K, V]) Range(f func(key K, value V) bool) {
327
334
// present at the start of the call to Range.
328
335
// If read.amended is false, then read.m satisfies that property without
329
336
// requiring us to hold m.mu for a long time.
330
- read , _ := m .read . LoadValue ()
337
+ read := m .loadReadOnly ()
331
338
if read .amended {
332
339
// m.dirty contains keys not in read.m. Fortunately, Range is already O(N)
333
340
// (assuming the caller does not break out early), so a call to Range
334
341
// amortizes an entire copy of the map: we can promote the dirty copy
335
342
// immediately!
336
343
m .mu .Lock ()
337
- read , _ = m .read . LoadValue ()
344
+ read = m .loadReadOnly ()
338
345
if read .amended {
339
346
read = readOnly [K ]{m : m .dirty }
340
347
m .read .Store (& read )
@@ -370,7 +377,7 @@ func (m *Map[K, V]) dirtyLocked() {
370
377
return
371
378
}
372
379
373
- read , _ := m .read . LoadValue ()
380
+ read := m .loadReadOnly ()
374
381
m .dirty = make (map [K ]* entry , len (read .m ))
375
382
for k , e := range read .m {
376
383
if ! e .tryExpungeLocked () {
0 commit comments