-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathatomic_float64.go
170 lines (136 loc) · 4.59 KB
/
atomic_float64.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
package metrics
import (
"math"
"sync/atomic"
"unsafe"
)
// AtomicFloat64Interface is an interface of an atomic float64 implementation
// It's an abstraction over (*AtomicFloat64) and (*AtomicFloat64Ptr)
type AtomicFloat64Interface interface {
// Get returns the current value
Get() float64
// Set sets a new value
Set(float64)
// Add adds the value to the current one (operator "plus")
Add(float64) float64
// GetFast is like Get but without atomicity
GetFast() float64
// SetFast is like Set but without atomicity
SetFast(float64)
// AddFast is like Add but without atomicity
AddFast(float64) float64
}
// NonAtomicFloat64 just an implementation of AtomicFloat64Interface without any atomicity
//
// Supposed to be used for debugging, only
type NonAtomicFloat64 float64
// Get returns the current value
func (f *NonAtomicFloat64) Get() float64 {
return (float64)(*f)
}
// Set sets a new value
func (f *NonAtomicFloat64) Set(n float64) {
*f = NonAtomicFloat64(n)
}
// Add adds the value to the current one (operator "plus")
func (f *NonAtomicFloat64) Add(a float64) float64 {
*f += NonAtomicFloat64(a)
return float64(*f)
}
// GetFast is the same as Get
func (f *NonAtomicFloat64) GetFast() float64 {
return f.Get()
}
// SetFast is the same as Set
func (f *NonAtomicFloat64) SetFast(n float64) {
f.Set(n)
}
// AddFast is the same as Add
func (f *NonAtomicFloat64) AddFast(n float64) float64 {
return f.Add(n)
}
// AtomicFloat64 is an implementation of atomic float64 using uint64 atomic instructions
// and `math.Float64frombits()`/`math.Float64bits()`
type AtomicFloat64 uint64
// Get returns the current value
func (f *AtomicFloat64) Get() float64 {
return math.Float64frombits(atomic.LoadUint64((*uint64)(f)))
}
// Set sets a new value
func (f *AtomicFloat64) Set(n float64) {
atomic.StoreUint64((*uint64)(f), math.Float64bits(n))
}
// Add adds the value to the current one (operator "plus")
func (f *AtomicFloat64) Add(a float64) float64 {
for {
// Get the old value
o := atomic.LoadUint64((*uint64)(f))
// Calculate the sum
s := math.Float64frombits(o) + a
// Get int64 representation of the sum to be able to use atomic operations
n := math.Float64bits(s)
// Swap the old value to the new one
// If not successful then somebody changes the value while our calculations above
// It means we need to recalculate the new value and try again (that's why it's in the loop)
if atomic.CompareAndSwapUint64((*uint64)(f), o, n) {
return s
}
}
}
// GetFast is like Get but without atomicity (faster, but unsafe)
func (f *AtomicFloat64) GetFast() float64 {
return math.Float64frombits(*(*uint64)(f))
}
// SetFast is like Set but without atomicity (faster, but unsafe)
func (f *AtomicFloat64) SetFast(n float64) {
*(*uint64)(f) = math.Float64bits(n)
}
// AddFast is like Add but without atomicity (faster, but unsafe)
func (f *AtomicFloat64) AddFast(n float64) float64 {
s := math.Float64frombits(*(*uint64)(f)) + n
*(*uint64)(f) = math.Float64bits(s)
return s
}
// AtomicFloat64Ptr is like AtomicFloat64 but stores the value in a pointer "*float64" (which in turn could be
// changed from the outside to point at some other variable).
type AtomicFloat64Ptr struct {
Pointer *float64
}
// Get returns the current value
func (f *AtomicFloat64Ptr) Get() float64 {
return math.Float64frombits(atomic.LoadUint64((*uint64)((unsafe.Pointer)(f.Pointer))))
}
// Set sets a new value
func (f *AtomicFloat64Ptr) Set(n float64) {
atomic.StoreUint64((*uint64)((unsafe.Pointer)(f.Pointer)), math.Float64bits(n))
}
// Add adds the value to the current one (operator "plus")
func (f *AtomicFloat64Ptr) Add(n float64) float64 {
for {
// Get the old value
a := atomic.LoadUint64((*uint64)((unsafe.Pointer)(f.Pointer)))
// Calculate the sum
s := math.Float64frombits(a) + n
// Get int64 representation of the sum to be able to use atomic operations
b := math.Float64bits(s)
// Swap the old value to the new one
// If not successful then somebody changes the value while our calculations above
// It means we need to recalculate the new value and try again (that's why it's in the loop)
if atomic.CompareAndSwapUint64((*uint64)((unsafe.Pointer)(f.Pointer)), a, b) {
return s
}
}
}
// GetFast is like Get but without atomicity (faster, but unsafe)
func (f *AtomicFloat64Ptr) GetFast() float64 {
return *f.Pointer
}
// SetFast is like Set but without atomicity (faster, but unsafe)
func (f *AtomicFloat64Ptr) SetFast(n float64) {
*f.Pointer = n
}
// AddFast is like Add but without atomicity (faster, but unsafe)
func (f *AtomicFloat64Ptr) AddFast(n float64) float64 {
*f.Pointer += n
return *f.Pointer
}