github.com/haraldrudell/parl@v0.4.176/atomic-counter.go (about)

     1  /*
     2  © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package parl
     7  
     8  import (
     9  	"math"
    10  	"sync/atomic"
    11  )
    12  
    13  // AtomicCounter is a uint64 thread-safe counter
    14  //   - [atomic.Uint64] added:
    15  //   - Inc Dec delegating to Add
    16  //   - Inc2 Dec2: preventing wrap-around CompareAndSwap mechanic
    17  //   - Set sets particular value
    18  //   - Value returns current value
    19  type AtomicCounter atomic.Uint64
    20  
    21  // Inc increments with wrap-around. Thread-Safe
    22  //   - value is new value
    23  func (a *AtomicCounter) Inc() (value uint64) { return (*atomic.Uint64)(a).Add(1) }
    24  
    25  // Inc2 is increment without wrap-around. Thread-Safe
    26  //   - at math.MaxUint64, increments are ineffective
    27  func (a *AtomicCounter) Inc2() (value uint64, didInc bool) {
    28  	for {
    29  		var beforeValue = (*atomic.Uint64)(a).Load()
    30  		if beforeValue == math.MaxUint64 {
    31  			return // at max
    32  		} else if didInc = (*atomic.Uint64)(a).CompareAndSwap(beforeValue, beforeValue+1); didInc {
    33  			return // inc successful return
    34  		}
    35  	}
    36  }
    37  
    38  // Dec is decrement with wrap-around. Thread-Safe
    39  func (a *AtomicCounter) Dec() (value uint64) { return (*atomic.Uint64)(a).Add(math.MaxUint64) }
    40  
    41  // Dec2 is decrement with no wrap-around. Thread-Safe
    42  //   - at 0, decrements are ineffective
    43  func (a *AtomicCounter) Dec2() (value uint64, didDec bool) {
    44  	for {
    45  		var beforeValue = (*atomic.Uint64)(a).Load()
    46  		if beforeValue == 0 {
    47  			return // no dec return
    48  		} else if didDec = (*atomic.Uint64)(a).CompareAndSwap(beforeValue, beforeValue-1); didDec {
    49  			return // dec successful return
    50  		}
    51  	}
    52  }
    53  
    54  // Add is add with wrap-around. Thread-Safe
    55  func (a *AtomicCounter) Add(value uint64) (newValue uint64) { return (*atomic.Uint64)(a).Add(value) }
    56  
    57  // Set sets a new aggregate value. Thread-Safe
    58  func (a *AtomicCounter) Set(value uint64) (oldValue uint64) { return (*atomic.Uint64)(a).Swap(value) }
    59  
    60  // Value returns current counter-value
    61  func (a *AtomicCounter) Value() (value uint64) { return (*atomic.Uint64)(a).Load() }