v / vlib / datatypes / ringbuffer.v
124 lines · 109 sloc · 3.16 KB · b5f71dffe4085b668e1d3b12f71f7aa36ec0fc4a
Raw
1// Written by flopetautschnig (floscodes) (c) 2022
2
3module datatypes
4
5// RingBuffer represents a ring buffer also known as a circular buffer.
6pub struct RingBuffer[T] {
7mut:
8 reader int // index of the tail where data is going to be read
9 writer int // index of the head where data is going to be written
10 content []T
11}
12
13// new_ringbuffer creates an empty ring buffer of size `s`.
14pub fn new_ringbuffer[T](s int) RingBuffer[T] {
15 return RingBuffer[T]{
16 content: []T{len: s + 1, cap: s + 1}
17 } // increasing custom set size by one element in order to make ring flow possible, so that writer cannot equal reader before reader-index has been read.
18}
19
20// push adds an element to the ring buffer.
21pub fn (mut rb RingBuffer[T]) push(element T) ! {
22 if rb.is_full() {
23 return error('Buffer overflow')
24 } else {
25 rb.content[rb.writer] = element
26 rb.move_writer()
27 }
28}
29
30// pop returns the oldest element in the buffer.
31pub fn (mut rb RingBuffer[T]) pop() !T {
32 mut v := rb.content[rb.reader]
33 if rb.is_empty() {
34 return error('Buffer is empty')
35 } else {
36 rb.move_reader()
37 }
38 return v
39}
40
41// push_many pushes an array to the buffer.
42pub fn (mut rb RingBuffer[T]) push_many(elements []T) ! {
43 for v in elements {
44 rb.push(v) or { return err }
45 }
46}
47
48// pop_many returns `n` elements of the buffer starting with the oldest one.
49pub fn (mut rb RingBuffer[T]) pop_many(n u64) ![]T {
50 mut elements := []T{}
51 for _ in 0 .. n {
52 elements << rb.pop() or { return err }
53 }
54 return elements
55}
56
57// is_empty returns `true` if the ring buffer is empty, `false` otherwise.
58pub fn (rb RingBuffer[T]) is_empty() bool {
59 return rb.reader == rb.writer // if reader equals writer it means that no value to read has been written before. It follows that the buffer is empty.
60}
61
62// is_full returns `true` if the ring buffer is full, `false` otherwise.
63pub fn (rb RingBuffer[T]) is_full() bool {
64 if rb.writer + 1 == rb.reader {
65 return true
66 } else if rb.writer == rb.content.len - 1 && rb.reader == 0 {
67 return true
68 } else {
69 return false
70 }
71}
72
73// capacity returns the capacity of the ring buffer.
74pub fn (rb RingBuffer[T]) capacity() int {
75 return rb.content.cap - 1 // reduce by one because of the extra element explained in function `new_ringbuffer()`
76}
77
78// clear empties the ring buffer and all pushed elements.
79pub fn (mut rb RingBuffer[T]) clear() {
80 rb = RingBuffer[T]{
81 content: []T{len: rb.content.len, cap: rb.content.cap}
82 }
83}
84
85// occupied returns the occupied capacity of the buffer.
86pub fn (rb RingBuffer[T]) occupied() int {
87 mut reader := rb.reader
88 mut v := 0
89 if rb.is_empty() {
90 return v
91 }
92 for {
93 reader++
94 if reader > rb.content.len - 1 {
95 reader = 0
96 }
97 v++
98 if reader == rb.writer {
99 break
100 }
101 }
102 return v
103}
104
105// remaining returns the remaining capacity of the buffer.
106pub fn (rb RingBuffer[T]) remaining() int {
107 return rb.capacity() - rb.occupied()
108}
109
110// head an tail-pointer move methods
111// these methods are not public, they are just an eneasement for handling the pointer-movement process.
112fn (mut rb RingBuffer[T]) move_reader() {
113 rb.reader++
114 if rb.reader > rb.content.len - 1 {
115 rb.reader = 0
116 }
117}
118
119fn (mut rb RingBuffer[T]) move_writer() {
120 rb.writer++
121 if rb.writer > rb.content.len - 1 {
122 rb.writer = 0
123 }
124}
125