-
Notifications
You must be signed in to change notification settings - Fork 814
/
ring.go
106 lines (94 loc) · 2.27 KB
/
ring.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
/*
* Copyright 2021 CloudWeGo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package utils
import (
"errors"
"sync"
)
// ErrRingFull means the ring is full.
var ErrRingFull = errors.New("ring is full")
// Ring implements a fixed size ring buffer to manage data
type Ring struct {
l sync.Mutex
arr []interface{}
size int
tail int
head int
}
// NewRing creates a ringbuffer with fixed size.
func NewRing(size int) *Ring {
if size <= 0 {
// When size is an invalid number, we still return an instance
// with zero-size to reduce error checks of the callers.
size = 0
}
return &Ring{
arr: make([]interface{}, size+1),
size: size,
}
}
// Push appends item to the ring.
func (r *Ring) Push(i interface{}) error {
r.l.Lock()
defer r.l.Unlock()
if r.isFull() {
return ErrRingFull
}
r.arr[r.head] = i
r.head = r.inc()
return nil
}
// Pop returns the last item and removes it from the ring.
func (r *Ring) Pop() interface{} {
r.l.Lock()
defer r.l.Unlock()
if r.isEmpty() {
return nil
}
c := r.arr[r.tail]
r.arr[r.tail] = nil
r.tail = r.dec()
return c
}
// Dump dumps the data in the ring.
func (r *Ring) Dump() interface{} {
r.l.Lock()
defer r.l.Unlock()
m := struct {
Array []interface{} `json:"array"`
Len int `json:"len"`
Cap int `json:"cap"`
}{}
m.Cap = r.size + 1
m.Len = (r.head - r.tail + r.size + 1) / (r.size + 1)
m.Array = make([]interface{}, 0, m.Len)
for i := 0; i < m.Len; i++ {
m.Array = append(m.Array, r.arr[(r.tail+i)%(r.size+1)])
}
return m
}
func (r *Ring) inc() int {
return (r.head + 1) % (r.size + 1)
}
func (r *Ring) dec() int {
return (r.tail + 1) % (r.size + 1)
}
func (r *Ring) isEmpty() bool {
return r.tail == r.head
}
func (r *Ring) isFull() bool {
return r.inc() == r.tail
}