-
Notifications
You must be signed in to change notification settings - Fork 0
/
counter.go
140 lines (120 loc) · 2.84 KB
/
counter.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
package gounter
import (
"math"
"sync"
"sync/atomic"
)
// Counter supports increasing and decreasing counter internal value.
// Only responsible for counting, without any additional content.
//
// Decrement to a negative number is allowed,
// but once it is less than 0, `Get()` will get 0.
// However, it is still a negative number.
// You can continue to `Add()` or `Sub()`.
//
// Copying is prohibited. Please acquire new object.
type Counter struct {
noCopy noCopy
bits uint64
}
// counterPool is a pool for counter.
var counterPool = &sync.Pool{
New: func() any {
return &Counter{}
},
}
// AcquireCounter return a Counter Pointer.
func AcquireCounter() *Counter {
return counterPool.Get().(*Counter)
}
// ReleaseCounter releases a Counter Pointer.
func ReleaseCounter(c *Counter) {
if c == nil {
return
}
c.reset()
counterPool.Put(c)
}
// reset Counter to release.
func (c *Counter) reset() {
atomic.StoreUint64(&c.bits, 0)
}
// Get returns a number.
// When the counter value is negative, it returns 0.
func (c *Counter) Get() float64 {
val := c.Real()
if val < 0 {
return 0
}
return val
}
// Real returns a number in counter.
func (c *Counter) Real() float64 {
bits := atomic.LoadUint64(&c.bits)
val := math.Float64frombits(bits)
return val
}
// Inc increases the counter by 1.
// Counter always returns true.
func (c *Counter) Inc() bool {
return c.Add(1)
}
// Dec decreases the counter by 1.
// Counter always returns true.
func (c *Counter) Dec() bool {
return c.Add(-1)
}
// Set sets the value of the counter to the given value using atomic operations.
func (c *Counter) Set(value float64) bool {
for {
oldBits := atomic.LoadUint64(&c.bits)
newBits := math.Float64bits(value)
if atomic.CompareAndSwapUint64(&c.bits, oldBits, newBits) {
return true
}
}
}
// Add increases the counter number.
// Decreasing use negative number.
// Counter always returns true.
func (c *Counter) Add(delta float64) bool {
for {
oldBits := atomic.LoadUint64(&c.bits)
newVal := math.Float64frombits(oldBits) + delta
newBits := math.Float64bits(newVal)
if atomic.CompareAndSwapUint64(&c.bits, oldBits, newBits) {
return true
}
}
}
// Sub decreases the counter number.
// Counter always returns true.
func (c *Counter) Sub(delta float64) bool {
return c.Add(delta * -1)
}
// Reset resets this Counter.
func (c *Counter) Reset() {
c.reset()
}
// CopyTo copies a Counter to other Counter.
// If same Counter, do not change everything.
func (c *Counter) CopyTo(d interface{}) (ok bool, err error) {
dst, can := d.(*Counter)
if !can {
err = ErrDifferentCounterType
return
}
// fix c to c can not return
if c == dst {
err = ErrSameCounterPointer
return
}
for {
oldVal1 := atomic.LoadUint64(&dst.bits)
val1 := atomic.LoadUint64(&c.bits)
if atomic.CompareAndSwapUint64(&dst.bits, oldVal1, val1) {
ok = true
return
}
}
}