float64_ext.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. // Copyright (c) 2020 Uber Technologies, Inc.
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE.
  20. package atomic
  21. import (
  22. "math"
  23. "strconv"
  24. )
  25. //go:generate bin/gen-atomicwrapper -name=Float64 -type=float64 -wrapped=Uint64 -pack=math.Float64bits -unpack=math.Float64frombits -swap -json -imports math -file=float64.go
  26. // Add atomically adds to the wrapped float64 and returns the new value.
  27. func (f *Float64) Add(delta float64) float64 {
  28. for {
  29. old := f.Load()
  30. new := old + delta
  31. if f.CAS(old, new) {
  32. return new
  33. }
  34. }
  35. }
  36. // Sub atomically subtracts from the wrapped float64 and returns the new value.
  37. func (f *Float64) Sub(delta float64) float64 {
  38. return f.Add(-delta)
  39. }
  40. // CAS is an atomic compare-and-swap for float64 values.
  41. //
  42. // Note: CAS handles NaN incorrectly. NaN != NaN using Go's inbuilt operators
  43. // but CAS allows a stored NaN to compare equal to a passed in NaN.
  44. // This avoids typical CAS loops from blocking forever, e.g.,
  45. //
  46. // for {
  47. // old := atom.Load()
  48. // new = f(old)
  49. // if atom.CAS(old, new) {
  50. // break
  51. // }
  52. // }
  53. //
  54. // If CAS did not match NaN to match, then the above would loop forever.
  55. func (f *Float64) CAS(old, new float64) (swapped bool) {
  56. return f.v.CAS(math.Float64bits(old), math.Float64bits(new))
  57. }
  58. // String encodes the wrapped value as a string.
  59. func (f *Float64) String() string {
  60. // 'g' is the behavior for floats with %v.
  61. return strconv.FormatFloat(f.Load(), 'g', -1, 64)
  62. }