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() }