mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
125 lines
3.1 KiB
V
125 lines
3.1 KiB
V
|
// Written by flopetautschnig (floscodes) (c) 2022
|
||
|
|
||
|
module datatypes
|
||
|
|
||
|
// RingBuffer - public struct that represents the ringbuffer
|
||
|
pub struct RingBuffer<T> {
|
||
|
mut:
|
||
|
reader int // index of the tail where data is going to be read
|
||
|
writer int // index of the head where data is going to be written
|
||
|
content []T
|
||
|
}
|
||
|
|
||
|
// new_ringbuffer - creates an empty ringbuffer
|
||
|
pub fn new_ringbuffer<T>(s int) RingBuffer<T> {
|
||
|
return RingBuffer<T>{
|
||
|
content: []T{len: s + 1, cap: s + 1}
|
||
|
} // 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.
|
||
|
}
|
||
|
|
||
|
// push - adds an element to the ringbuffer
|
||
|
pub fn (mut rb RingBuffer<T>) push(element T) ? {
|
||
|
if rb.is_full() {
|
||
|
return error('Buffer overflow')
|
||
|
} else {
|
||
|
rb.content[rb.writer] = element
|
||
|
rb.move_writer()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// pop - returns the oldest element of the buffer
|
||
|
pub fn (mut rb RingBuffer<T>) pop() ?T {
|
||
|
mut v := rb.content[rb.reader]
|
||
|
if rb.is_empty() {
|
||
|
return error('Buffer is empty')
|
||
|
} else {
|
||
|
rb.move_reader()
|
||
|
}
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
// push_many - pushes an array to the buffer
|
||
|
pub fn (mut rb RingBuffer<T>) push_many(elements []T) ? {
|
||
|
for v in elements {
|
||
|
rb.push(v) or { return err }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// pop_many - returns a given number(n) of elements of the buffer starting with the oldest one
|
||
|
pub fn (mut rb RingBuffer<T>) pop_many(n u64) ?[]T {
|
||
|
mut elements := []T{}
|
||
|
for _ in 0 .. n {
|
||
|
elements << rb.pop() or { return err }
|
||
|
}
|
||
|
return elements
|
||
|
}
|
||
|
|
||
|
// is_empty - checks if the ringbuffer is empty
|
||
|
pub fn (rb RingBuffer<T>) is_empty() bool {
|
||
|
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.
|
||
|
}
|
||
|
|
||
|
// is_full - checks if the ringbuffer is full
|
||
|
pub fn (rb RingBuffer<T>) is_full() bool {
|
||
|
if rb.writer + 1 == rb.reader {
|
||
|
return true
|
||
|
} else if rb.writer == rb.content.len - 1 && rb.reader == 0 {
|
||
|
return true
|
||
|
} else {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// capacity - returns the capacity of the ringbuffer
|
||
|
pub fn (rb RingBuffer<T>) capacity() int {
|
||
|
return rb.content.cap - 1 // reduce by one because of the extra element explained in function `new_ringbuffer()`
|
||
|
}
|
||
|
|
||
|
// clear - emptys the ringbuffer and all pushed elements
|
||
|
pub fn (mut rb RingBuffer<T>) clear() {
|
||
|
rb = RingBuffer<T>{
|
||
|
content: []T{len: rb.content.len, cap: rb.content.cap}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// occupied - returns occupied capacity of the buffer.
|
||
|
pub fn (rb RingBuffer<T>) occupied() int {
|
||
|
mut reader := rb.reader
|
||
|
mut v := 0
|
||
|
if rb.is_empty() {
|
||
|
return v
|
||
|
}
|
||
|
for {
|
||
|
reader++
|
||
|
if reader > rb.content.len - 1 {
|
||
|
reader = 0
|
||
|
}
|
||
|
v++
|
||
|
if reader == rb.writer {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
return v
|
||
|
}
|
||
|
|
||
|
// remaining - returns remaining capacity of the buffer
|
||
|
pub fn (rb RingBuffer<T>) remaining() int {
|
||
|
return rb.capacity() - rb.occupied()
|
||
|
}
|
||
|
|
||
|
// head an tail-pointer move methods
|
||
|
// these methods are not public, they are just an eneasement for handling the pointer-movement process.
|
||
|
fn (mut rb RingBuffer<T>) move_reader() {
|
||
|
rb.reader++
|
||
|
if rb.reader > rb.content.len - 1 {
|
||
|
rb.reader = 0
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn (mut rb RingBuffer<T>) move_writer() {
|
||
|
rb.writer++
|
||
|
if rb.writer > rb.content.len - 1 {
|
||
|
rb.writer = 0
|
||
|
}
|
||
|
}
|