github.com/haraldrudell/parl@v0.4.176/internal/cyclebreaker/atomic-max.go (about) 1 /* 2 © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package cyclebreaker 7 8 import ( 9 "sync/atomic" 10 11 "github.com/haraldrudell/parl/ints" 12 "golang.org/x/exp/constraints" 13 ) 14 15 type AtomicMax[T constraints.Integer] struct { 16 value uint64 17 hasValue atomic.Bool 18 } 19 20 func NewAtomicMax[T constraints.Integer](value T) (atomicMax *AtomicMax[T]) { 21 m := AtomicMax[T]{} 22 m.value = uint64(value) // set initial threshold 23 return &m 24 } 25 26 func (max *AtomicMax[T]) Value(value T) (isNewMax bool) { 27 28 // check if value is a new max 29 valueU64, err := ints.Unsigned[uint64](value, "") 30 if err != nil { 31 panic(err) // value out of range, ie. negative 32 } 33 maxU64p := (*uint64)(&max.value) 34 current := atomic.LoadUint64(maxU64p) 35 if isNewMax = valueU64 > current; !isNewMax { 36 return // not a new max return 37 } 38 max.hasValue.Store(true) 39 40 // store the new max 41 for { 42 43 // try to write value to *max 44 if atomic.CompareAndSwapUint64(maxU64p, current, valueU64) { 45 return // new max written return 46 } 47 if current = atomic.LoadUint64(maxU64p); current >= valueU64 { 48 return // no longer a need to write return 49 } 50 } 51 } 52 53 func (max *AtomicMax[T]) Max() (value T, hasValue bool) { 54 value = T(atomic.LoadUint64((*uint64)(&max.value))) 55 hasValue = max.hasValue.Load() 56 return 57 } 58 59 func (max *AtomicMax[T]) Max1() (value T) { 60 return T(atomic.LoadUint64((*uint64)(&max.value))) 61 }