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  }