-
Notifications
You must be signed in to change notification settings - Fork 15
/
ringbuffer.go
125 lines (103 loc) · 2.52 KB
/
ringbuffer.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
// Copyright (c) Berk D. Demir and the runitor contributors.
// SPDX-License-Identifier: 0BSD
package internal
import (
"errors"
"io"
)
// ErrReadOnly is the error returned by Write to indicate the ring
// buffer is in read only mode and will not accept further writes.
var ErrReadOnly = errors.New("read only")
// RingBuffer implements io.ReadWriter interface to a []byte backed ring
// buffer (aka circular buffer).
//
// Can be written to repeatedly until read from.
// At first read, ring buffer becomes read only, refusing further writes with
// ErrReadOnly error.
type RingBuffer struct {
buf []byte
idx int
unread int
readonly bool
}
// Len returns the length of the ring buffer.
func (r *RingBuffer) Len() int {
return len(r.buf)
}
// Cap returns the capacity of the ring buffer.
func (r *RingBuffer) Cap() int {
return cap(r.buf)
}
// Wrapped returns true if the ring buffer overwrote at least one byte.
func (r *RingBuffer) Wrapped() bool {
return r.Len() == r.Cap() && r.idx > 0
}
func (r *RingBuffer) Write(p []byte) (n int, err error) {
if r.readonly {
return 0, ErrReadOnly
}
return r.write(p), nil
}
func (r *RingBuffer) write(p []byte) (n int) {
// grow slice by write size, up to capacity.
if r.Len() != r.Cap() {
newlen := r.idx + len(p)
if newlen > r.Cap() {
newlen = r.Cap()
}
r.buf = r.buf[:newlen]
}
// If source is larger than the capacity of the ring buffer, we'll
// need to overwrite unobservable data. Optimize this by only writing
// last `r.Cap()` bytes from source.
if len(p) > r.Cap() {
// jump over what would be overwritten and count as written
n = len(p) - r.Cap()
r.idx = (r.idx + n) % r.Cap()
}
for n < len(p) {
cn := copy(r.buf[r.idx:], p[n:])
n += cn
r.idx = (r.idx + cn) % r.Cap()
}
return
}
func (r *RingBuffer) Read(p []byte) (n int, err error) {
if !r.readonly {
r.readonly = true
r.unread = r.Len()
if !r.Wrapped() {
r.idx = 0
}
}
if r.unread == 0 {
if len(p) == 0 {
return 0, nil
}
return 0, io.EOF
}
return r.read(p), nil
}
func (r *RingBuffer) read(p []byte) (n int) {
goal := len(p)
if goal > r.unread {
goal = r.unread
}
for n < goal {
from := r.idx
to := from + r.unread
if to > r.Len() {
to = r.Len()
}
cn := copy(p[n:], r.buf[from:to])
n += cn
r.unread -= cn
r.idx = (r.idx + cn) % r.Cap()
}
return
}
// NewRingBuffer allocates a new RingBuffer and the backing byte array with
// specified capacity.
func NewRingBuffer(cap int) *RingBuffer {
return &RingBuffer{buf: make([]byte, 0, cap)}
}