1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

datatypes: adding ringbuffer (#15818)

This commit is contained in:
flopetautschnig 2022-09-21 18:42:59 +02:00 committed by GitHub
parent 09411128af
commit 391ac12fe2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 189 additions and 0 deletions

124
vlib/datatypes/ringbuffer.v Normal file
View File

@ -0,0 +1,124 @@
// 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
}
}

View File

@ -0,0 +1,65 @@
import datatypes
fn test_push_and_pop() {
mut r := datatypes.new_ringbuffer<int>(2)
r.push(3) or { panic(err) }
r.push(4) or { panic(err) }
mut oldest_value := r.pop() or { 0 }
assert oldest_value == 3
r.push(5) or { panic(err) }
oldest_value = r.pop() or { 0 }
assert oldest_value == 4
}
fn test_clear_and_empty() {
mut r := datatypes.new_ringbuffer<int>(4)
r.push(3) or { panic(err) }
r.push(4) or { panic(err) }
oldest_value := r.pop() or { 0 }
assert oldest_value == 3
r.clear()
assert r.is_empty() == true
}
fn test_capacity_and_is_full() {
mut r := datatypes.new_ringbuffer<int>(4)
assert r.capacity() == 4
r.push(3) or { panic(err) }
r.push(4) or { panic(err) }
r.push(5) or { panic(err) }
r.push(6) or { panic(err) }
assert r.is_full() == true
}
fn test_occupied_and_remaining() {
mut r := datatypes.new_ringbuffer<int>(4)
r.push(3) or { panic(err) }
r.push(4) or { panic(err) }
assert r.occupied() == r.remaining()
}
fn test_push_and_pop_many() {
mut r := datatypes.new_ringbuffer<int>(4)
a := [1, 2, 3, 4]
r.push_many(a) or { panic(err) }
assert r.is_full() == true
b := r.pop_many(4) or { panic(err) }
assert a == b
}