Skip to content

Commit ba78b2b

Browse files
committed
add GetOrCompute
1 parent 4050894 commit ba78b2b

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

map.go

+47
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,53 @@ func (m *Map[K, V]) GetOrSet(key K, value V) (actual V, loaded bool) {
227227
return
228228
}
229229

230+
// GetOrCompute is similar to GetOrSet but the value to be set is obtained from a constructor
231+
// the value constructor is called only once
232+
func (m *Map[K, V]) GetOrCompute(key K, valueFn func() V) (actual V, loaded bool) {
233+
var (
234+
h = m.hasher(key)
235+
data = m.metadata.Load()
236+
existing = data.indexElement(h)
237+
)
238+
// try to get the element if present
239+
for elem := existing; elem != nil && elem.keyHash <= h; elem = elem.nextPtr.Load() {
240+
if elem.key == key && !elem.isDeleted() {
241+
actual, loaded = *elem.value.Load(), true
242+
return
243+
}
244+
}
245+
// Get() failed because element is absent
246+
// compute the value from the constructor and store it
247+
value := valueFn()
248+
actual, loaded = value, false
249+
250+
var (
251+
alloc *element[K, V]
252+
created = false
253+
valPtr = &value
254+
)
255+
if existing == nil || existing.keyHash > h {
256+
existing = m.listHead
257+
}
258+
if alloc, created = existing.inject(h, key, valPtr); alloc != nil {
259+
if created {
260+
m.numItems.Add(1)
261+
}
262+
} else {
263+
for existing = m.listHead; alloc == nil; alloc, created = existing.inject(h, key, valPtr) {
264+
}
265+
if created {
266+
m.numItems.Add(1)
267+
}
268+
}
269+
270+
count := data.addItemToIndex(alloc)
271+
if resizeNeeded(uintptr(len(data.index)), count) && m.resizing.CompareAndSwap(notResizing, resizingInProgress) {
272+
m.grow(0) // double in size
273+
}
274+
return
275+
}
276+
230277
// CompareAndSwap atomically updates a map entry given its key by comparing current value to `oldValue`
231278
// and setting it to `newValue` if the above comparison is successful
232279
// It returns a boolean indicating whether the CompareAndSwap was successful or not

0 commit comments

Comments
 (0)