github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/syncutil/atomic.go (about)

     1  // Copyright 2017 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package syncutil
    12  
    13  import (
    14  	"math"
    15  	"sync/atomic"
    16  )
    17  
    18  // AtomicFloat64 mimics the atomic types in the sync/atomic standard library,
    19  // but for the float64 type. If you'd like to implement additional methods,
    20  // consider checking out the expvar Float type for guidance:
    21  // https://golang.org/src/expvar/expvar.go?s=2188:2222#L69
    22  type AtomicFloat64 uint64
    23  
    24  // StoreFloat64 atomically stores a float64 value into the provided address.
    25  func StoreFloat64(addr *AtomicFloat64, val float64) {
    26  	atomic.StoreUint64((*uint64)(addr), math.Float64bits(val))
    27  }
    28  
    29  // LoadFloat64 atomically loads tha float64 value from the provided address.
    30  func LoadFloat64(addr *AtomicFloat64) (val float64) {
    31  	return math.Float64frombits(atomic.LoadUint64((*uint64)(addr)))
    32  }
    33  
    34  func AddFloat64(addr *AtomicFloat64, add float64) (val float64) {
    35  	for {
    36  		oldFloat := LoadFloat64(addr)
    37  		oldInt := math.Float64bits(oldFloat)
    38  		newFloat := oldFloat + add
    39  		newInt := math.Float64bits(newFloat)
    40  		if atomic.CompareAndSwapUint64((*uint64)(addr), oldInt, newInt) {
    41  			return
    42  		}
    43  	}
    44  }
    45  
    46  func StoreFloat64IfHigher(addr *AtomicFloat64, new float64) (val float64) {
    47  	for {
    48  		oldFloat := LoadFloat64(addr)
    49  		if oldFloat > new {
    50  			return
    51  		}
    52  		oldInt := math.Float64bits(oldFloat)
    53  		newInt := math.Float64bits(new)
    54  		if atomic.CompareAndSwapUint64((*uint64)(addr), oldInt, newInt) {
    55  			return
    56  		}
    57  	}
    58  }
    59  
    60  // AtomicBool mimics an atomic boolean.
    61  type AtomicBool uint32
    62  
    63  // Set atomically sets the boolean.
    64  func (b *AtomicBool) Set(v bool) {
    65  	s := uint32(0)
    66  	if v {
    67  		s = 1
    68  	}
    69  	atomic.StoreUint32((*uint32)(b), s)
    70  }
    71  
    72  // Get atomically gets the boolean.
    73  func (b *AtomicBool) Get() bool {
    74  	return atomic.LoadUint32((*uint32)(b)) != 0
    75  }
    76  
    77  // Swap atomically swaps the value.
    78  func (b *AtomicBool) Swap(v bool) bool {
    79  	wanted := uint32(0)
    80  	if v {
    81  		wanted = 1
    82  	}
    83  	return atomic.SwapUint32((*uint32)(b), wanted) != 0
    84  }
    85  
    86  // AtomicString gives you atomic-style APIs for string.
    87  type AtomicString struct {
    88  	s atomic.Value
    89  }
    90  
    91  // Set atomically sets str as new value.
    92  func (s *AtomicString) Set(val string) {
    93  	s.s.Store(val)
    94  }
    95  
    96  // Get atomically returns the current value.
    97  func (s *AtomicString) Get() string {
    98  	val := s.s.Load()
    99  	if val == nil {
   100  		return ""
   101  	}
   102  	return val.(string)
   103  }