1package io
2
3import (
4 "bytes"
5 "io"
6)
7
8// RingBuffer struct satisfies io.ReadWrite interface.
9//
10// ReadBuffer is a revolving buffer data structure, which can be used to store snapshots of data in a
11// revolving window.
12type RingBuffer struct {
13 slice []byte
14 start int
15 end int
16 size int
17}
18
19// NewRingBuffer method takes in a byte slice as an input and returns a RingBuffer.
20func NewRingBuffer(slice []byte) *RingBuffer {
21 ringBuf := RingBuffer{
22 slice: slice,
23 }
24 return &ringBuf
25}
26
27// Write method inserts the elements in a byte slice, and returns the number of bytes written along with any error.
28func (r *RingBuffer) Write(p []byte) (int, error) {
29 for _, b := range p {
30 // check if end points to invalid index, we need to circle back
31 if r.end == len(r.slice) {
32 r.end = 0
33 }
34 // check if start points to invalid index, we need to circle back
35 if r.start == len(r.slice) {
36 r.start = 0
37 }
38 // if ring buffer is filled, increment the start index
39 if r.size == len(r.slice) {
40 r.size--
41 r.start++
42 }
43
44 r.slice[r.end] = b
45 r.end++
46 r.size++
47 }
48 return len(p), nil
49}
50
51// Read copies the data on the ring buffer into the byte slice provided to the method.
52// Returns the read count along with any error encountered while reading.
53func (r *RingBuffer) Read(p []byte) (int, error) {
54 // readCount keeps track of the number of bytes read
55 var readCount int
56 for j := 0; j < len(p); j++ {
57 // if ring buffer is empty or completely read
58 // return EOF error.
59 if r.size == 0 {
60 return readCount, io.EOF
61 }
62
63 if r.start == len(r.slice) {
64 r.start = 0
65 }
66
67 p[j] = r.slice[r.start]
68 readCount++
69 // increment the start pointer for ring buffer
70 r.start++
71 // decrement the size of ring buffer
72 r.size--
73 }
74 return readCount, nil
75}
76
77// Len returns the number of unread bytes in the buffer.
78func (r *RingBuffer) Len() int {
79 return r.size
80}
81
82// Bytes returns a copy of the RingBuffer's bytes.
83func (r RingBuffer) Bytes() []byte {
84 var b bytes.Buffer
85 io.Copy(&b, &r)
86 return b.Bytes()
87}
88
89// Reset resets the ring buffer.
90func (r *RingBuffer) Reset() {
91 *r = RingBuffer{
92 slice: r.slice,
93 }
94}