-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathringbuffer.go
More file actions
157 lines (128 loc) · 3.15 KB
/
ringbuffer.go
File metadata and controls
157 lines (128 loc) · 3.15 KB
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
package easyringbuffer
import (
"errors"
"sync"
)
// Error messages for ring buffer operations.
var (
ErrRingBufferFull = errors.New("ring buffer is full")
ErrRingBufferEmpty = errors.New("ring buffer is empty")
)
// RingBuffer is a thread-safe ring buffer implementation.
type RingBuffer[T any] struct {
buffer []T
capacity int
size int
head int
tail int
mu sync.Mutex
}
// New creates a new ring buffer with the specified capacity.
func NewRingBuffer[T any](capacity int) *RingBuffer[T] {
if capacity <= 0 {
panic("capacity must be greater than 0")
}
return &RingBuffer[T]{
buffer: make([]T, capacity),
capacity: capacity,
}
}
// Enqueue adds an item to the ring buffer.
// Returns an error if the buffer is full.
func (rb *RingBuffer[T]) Enqueue(item T) error {
rb.mu.Lock()
defer rb.mu.Unlock()
if rb.size == rb.capacity {
return ErrRingBufferFull
}
rb.buffer[rb.tail] = item
rb.tail = (rb.tail + 1) % rb.capacity
rb.size++
return nil
}
// Dequeue removes and returns the oldest item from the ring buffer.
// Returns an error if the buffer is empty.
func (rb *RingBuffer[T]) Dequeue() (T, error) {
rb.mu.Lock()
defer rb.mu.Unlock()
var zeroValue T
if rb.size == 0 {
return zeroValue, ErrRingBufferEmpty
}
item := rb.buffer[rb.head]
// Optional: Clear the slot for garbage collection.
rb.buffer[rb.head] = zeroValue
rb.head = (rb.head + 1) % rb.capacity
rb.size--
return item, nil
}
// GetAll returns all items in the buffer in order from oldest to newest.
func (rb *RingBuffer[T]) GetAll() []T {
rb.mu.Lock()
defer rb.mu.Unlock()
result := make([]T, rb.size)
for i := 0; i < rb.size; i++ {
index := (rb.head + i) % rb.capacity
result[i] = rb.buffer[index]
}
return result
}
// GetLastN returns the last N items from the buffer.
func (rb *RingBuffer[T]) GetLastN(n int) []T {
rb.mu.Lock()
defer rb.mu.Unlock()
if n > rb.size {
n = rb.size
}
result := make([]T, n)
for i := 0; i < n; i++ {
index := (rb.tail - n + i + rb.capacity) % rb.capacity
result[i] = rb.buffer[index]
}
return result
}
// Peek returns the next item without removing it from the buffer.
// Returns an error if the buffer is empty.
func (rb *RingBuffer[T]) Peek() (T, error) {
rb.mu.Lock()
defer rb.mu.Unlock()
var zeroValue T
if rb.size == 0 {
return zeroValue, ErrRingBufferEmpty
}
return rb.buffer[rb.head], nil
}
// Len returns the current number of items in the buffer.
func (rb *RingBuffer[T]) Len() int {
rb.mu.Lock()
defer rb.mu.Unlock()
return rb.size
}
// Capacity returns the capacity of the ring buffer.
func (rb *RingBuffer[T]) Capacity() int {
return rb.capacity
}
// IsEmpty checks if the ring buffer is empty.
func (rb *RingBuffer[T]) IsEmpty() bool {
rb.mu.Lock()
defer rb.mu.Unlock()
return rb.size == 0
}
// IsFull checks if the ring buffer is full.
func (rb *RingBuffer[T]) IsFull() bool {
rb.mu.Lock()
defer rb.mu.Unlock()
return rb.size == rb.capacity
}
// Reset clears all items in the ring buffer.
func (rb *RingBuffer[T]) Reset() {
rb.mu.Lock()
defer rb.mu.Unlock()
var zeroValue T
for i := 0; i < rb.capacity; i++ {
rb.buffer[i] = zeroValue
}
rb.size = 0
rb.head = 0
rb.tail = 0
}