| 1 | // Written by flopetautschnig (floscodes) (c) 2022 |
| 2 | |
| 3 | module datatypes |
| 4 | |
| 5 | // RingBuffer represents a ring buffer also known as a circular buffer. |
| 6 | pub struct RingBuffer[T] { |
| 7 | mut: |
| 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`. |
| 14 | pub 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. |
| 21 | pub 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. |
| 31 | pub 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. |
| 42 | pub 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. |
| 49 | pub 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. |
| 58 | pub 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. |
| 63 | pub 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. |
| 74 | pub 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. |
| 79 | pub 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. |
| 86 | pub 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. |
| 106 | pub 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. |
| 112 | fn (mut rb RingBuffer[T]) move_reader() { |
| 113 | rb.reader++ |
| 114 | if rb.reader > rb.content.len - 1 { |
| 115 | rb.reader = 0 |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | fn (mut rb RingBuffer[T]) move_writer() { |
| 120 | rb.writer++ |
| 121 | if rb.writer > rb.content.len - 1 { |
| 122 | rb.writer = 0 |
| 123 | } |
| 124 | } |
| 125 | |