github.com/haraldrudell/parl@v0.4.176/pmaps/thread-safe-map2.go (about) 1 /* 2 © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package pmaps 7 8 import ( 9 "github.com/haraldrudell/parl/perrors" 10 "github.com/haraldrudell/parl/pmaps/pmaps2" 11 ) 12 13 // threadSafeMap is a private promotable field 14 // that does not promote any public identifiers 15 // - native Go map functions: Get Put Delete Length Range 16 // - convenience methods: clone Clear 17 // - order methods: List 18 type threadSafeMap[K comparable, V any] struct { 19 tsm pmaps2.ThreadSafeMap[K, V] 20 } 21 22 // newThreadSafeMap returns a thread-safe Go map 23 func newThreadSafeMap[K comparable, V any]() (m *threadSafeMap[K, V]) { 24 return &threadSafeMap[K, V]{tsm: *pmaps2.NewThreadSafeMap[K, V]()} 25 } 26 27 // GetOrCreate returns an item from the map if it exists otherwise creates it. 28 // - newV or makeV are invoked in the critical section, ie. these functions 29 // may not access the map or deadlock 30 // - if a key is mapped, its value is returned 31 // - otherwise, if newV and makeV are both nil, nil is returned. 32 // - otherwise, if newV is present, it is invoked to return a pointer ot a value. 33 // A nil return value from newV causes panic. A new mapping is created using 34 // the value pointed to by the newV return value. 35 // - otherwise, a mapping is created using whatever makeV returns 36 // - newV and makeV may not access the map. 37 // The map’s write lock is held during their execution 38 // - GetOrCreate is an atomic, thread-safe operation 39 // - value insert is O(log n) 40 func (m *threadSafeMap[K, V]) GetOrCreate( 41 key K, 42 newV func() (value *V), 43 makeV func() (value V), 44 ) (value V, hasValue bool) { 45 defer m.tsm.Lock()() 46 47 // try existing mapping 48 if value, hasValue = m.tsm.Get(key); hasValue { 49 return // mapping exists return 50 } 51 52 // create using newV 53 if newV != nil { 54 pt := newV() 55 if pt == nil { 56 panic(perrors.NewPF("newV returned nil")) 57 } 58 value = *pt 59 m.tsm.Put(key, value) 60 hasValue = true 61 return // created using newV return 62 } 63 64 // create using makeV 65 if makeV != nil { 66 value = makeV() 67 m.tsm.Put(key, value) 68 hasValue = true 69 return // created using makeV return 70 } 71 72 return // no key, no newV or makeV: nil return 73 } 74 75 func (m *threadSafeMap[K, V]) clone() (clone *threadSafeMap[K, V]) { 76 return &threadSafeMap[K, V]{tsm: *m.tsm.Clone()} 77 } 78 func (m *threadSafeMap[K, V]) Get(key K) (value V, ok bool) { 79 defer m.tsm.RLock()() 80 81 return m.tsm.Get(key) 82 } 83 84 func (m *threadSafeMap[K, V]) Put(key K, value V) { 85 defer m.tsm.Lock()() 86 87 m.tsm.Put(key, value) 88 } 89 90 func (m *threadSafeMap[K, V]) Delete(key K, useZeroValue ...bool) { 91 defer m.tsm.Lock()() 92 93 m.tsm.Delete(key, useZeroValue...) 94 } 95 96 func (m *threadSafeMap[K, V]) Length() (length int) { 97 defer m.tsm.RLock()() 98 99 return m.tsm.Length() 100 } 101 102 func (m *threadSafeMap[K, V]) Range(rangeFunc func(key K, value V) (keepGoing bool)) (rangedAll bool) { 103 defer m.tsm.RLock()() 104 105 return m.tsm.Range(rangeFunc) 106 } 107 108 // Clear empties the map 109 func (m *threadSafeMap[K, V]) Clear(useRange ...bool) { 110 defer m.tsm.Lock()() 111 112 m.tsm.Clear(useRange...) 113 } 114 115 // List provides the mapped values, undefined ordering 116 // - O(n) 117 func (m *threadSafeMap[K, V]) List(n ...int) (list []V) { 118 119 // get n 120 var n0 int 121 if len(n) > 0 { 122 n0 = n[0] 123 } 124 defer m.tsm.RLock()() 125 126 return m.tsm.List(n0) 127 }