github.com/cilium/cilium@v1.16.2/pkg/lock/map.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright Authors of Cilium 3 4 package lock 5 6 import "sync" 7 8 // Map is a thin generic wrapper around sync.Map. The sync.Map description from 9 // the standard library follows (and is also propagated to the corresponding 10 // methods) for users' convenience: 11 // 12 // Map is like a Go map[interface{}]interface{} but is safe for concurrent use 13 // by multiple goroutines without additional locking or coordination. 14 // Loads, stores, and deletes run in amortized constant time. 15 // 16 // The Map type is specialized. Most code should use a plain Go map instead, 17 // with separate locking or coordination, for better type safety and to make it 18 // easier to maintain other invariants along with the map content. 19 // 20 // The Map type is optimized for two common use cases: (1) when the entry for a given 21 // key is only ever written once but read many times, as in caches that only grow, 22 // or (2) when multiple goroutines read, write, and overwrite entries for disjoint 23 // sets of keys. In these two cases, use of a Map may significantly reduce lock 24 // contention compared to a Go map paired with a separate Mutex or RWMutex. 25 // 26 // The zero Map is empty and ready for use. A Map must not be copied after first use. 27 type Map[K comparable, V any] sync.Map 28 29 // MapCmpValues is an extension of Map, which additionally wraps the two extra 30 // methods requiring values to be also of comparable type. 31 type MapCmpValues[K, V comparable] Map[K, V] 32 33 // Load returns the value stored in the map for a key, or the zero value if no 34 // value is present. The ok result indicates whether value was found in the map. 35 func (m *Map[K, V]) Load(key K) (value V, ok bool) { 36 val, ok := (*sync.Map)(m).Load(key) 37 return m.convert(val, ok) 38 } 39 40 // LoadOrStore returns the existing value for the key if present. 41 // Otherwise, it stores and returns the given value. 42 // The loaded result is true if the value was loaded, false if stored. 43 func (m *Map[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) { 44 val, loaded := (*sync.Map)(m).LoadOrStore(key, value) 45 return val.(V), loaded 46 } 47 48 // LoadAndDelete deletes the value for a key, returning the previous value if any 49 // (zero value otherwise). The loaded result reports whether the key was present. 50 func (m *Map[K, V]) LoadAndDelete(key K) (value V, loaded bool) { 51 val, loaded := (*sync.Map)(m).LoadAndDelete(key) 52 return m.convert(val, loaded) 53 } 54 55 // Store sets the value for a key. 56 func (m *Map[K, V]) Store(key K, value V) { 57 (*sync.Map)(m).Store(key, value) 58 } 59 60 // Swap swaps the value for a key and returns the previous value if any (zero 61 // value otherwise). The loaded result reports whether the key was present. 62 func (m *Map[K, V]) Swap(key K, value V) (previous V, loaded bool) { 63 val, loaded := (*sync.Map)(m).Swap(key, value) 64 return m.convert(val, loaded) 65 } 66 67 // Delete deletes the value for a key. 68 func (m *Map[K, V]) Delete(key K) { 69 (*sync.Map)(m).Delete(key) 70 } 71 72 // Range calls f sequentially for each key and value present in the map. 73 // If f returns false, range stops the iteration. 74 // 75 // Range does not necessarily correspond to any consistent snapshot of the Map's 76 // contents: no key will be visited more than once, but if the value for any key 77 // is stored or deleted concurrently (including by f), Range may reflect any 78 // mapping for that key from any point during the Range call. Range does not 79 // block other methods on the receiver; even f itself may call any method on m. 80 // 81 // Range may be O(N) with the number of elements in the map even if f returns 82 // false after a constant number of calls. 83 func (m *Map[K, V]) Range(f func(key K, value V) bool) { 84 (*sync.Map)(m).Range(func(key, value any) bool { 85 return f(key.(K), value.(V)) 86 }) 87 } 88 89 // CompareAndDelete deletes the entry for key if its value is equal to old. 90 // If there is no current value for key in the map, CompareAndDelete returns false 91 // (even if the old value is the nil interface value). 92 func (m *MapCmpValues[K, V]) CompareAndDelete(key K, old V) (deleted bool) { 93 return (*sync.Map)(m).CompareAndDelete(key, old) 94 } 95 96 // CompareAndSwap swaps the old and new values for key if the value stored in 97 // the map is equal to old. 98 func (m *MapCmpValues[K, V]) CompareAndSwap(key K, old, new V) bool { 99 return (*sync.Map)(m).CompareAndSwap(key, old, new) 100 } 101 102 func (m *Map[K, V]) convert(value any, ok bool) (V, bool) { 103 if !ok { 104 return *new(V), false 105 } 106 107 return value.(V), true 108 }