Fixed input event buffer issues

Queue doesn't properly act as a ring buffer had to roll my own.
I want to make a allocated ring buffer as well...
This commit is contained in:
2024-06-23 03:04:38 -04:00
parent ce1d31f0d4
commit 55b80da8e5
17 changed files with 390 additions and 139 deletions

View File

@ -0,0 +1,96 @@
package grime
import "core:mem"
RingBuffer :: struct($T: typeid) {
data: []T,
head: int,
tail: int,
len: int,
is_full: bool,
}
init :: proc(rb: ^RingBuffer($T), capacity: int, allocator := context.allocator) -> mem.Allocator_Error {
data, err := make([]T, capacity, allocator)
if err != nil {
return err
}
rb.data = data
rb.head = 0
rb.tail = 0
rb.len = 0
rb.is_full = false
return nil
}
destroy :: proc(rb: ^RingBuffer($T)) {
delete(rb.data)
rb^ = {}
}
len :: proc(rb: RingBuffer($T)) -> int {
return rb.len
}
cap :: proc(rb: RingBuffer($T)) -> int {
return len(rb.data)
}
is_empty :: proc(rb: RingBuffer($T)) -> bool {
return rb.len == 0
}
is_full :: proc(rb: RingBuffer($T)) -> bool {
return rb.is_full
}
push_back :: proc(rb: ^RingBuffer($T), value: T) {
if rb.is_full {
rb.data[rb.head] = value
rb.head = (rb.head + 1) % len(rb.data)
rb.tail = rb.head
} else {
rb.data[rb.tail] = value
rb.tail = (rb.tail + 1) % len(rb.data)
rb.len += 1
rb.is_full = rb.len == len(rb.data)
}
}
pop_front :: proc(rb: ^RingBuffer($T)) -> (T, bool) {
if rb.len == 0 {
return T{}, false
}
value := rb.data[rb.head]
rb.head = (rb.head + 1) % len(rb.data)
rb.len -= 1
rb.is_full = false
return value, true
}
get :: proc(rb: RingBuffer($T), index: int) -> (T, bool) {
if index < 0 || index >= rb.len {
return T{}, false
}
actual_index := (rb.head + index) % len(rb.data)
return rb.data[actual_index], true
}
RingBufferIterator :: struct($T: typeid) {
rb: ^RingBuffer(T),
current: int,
}
iterator :: proc(rb: ^RingBuffer($T)) -> RingBufferIterator(T) {
return RingBufferIterator(T){rb = rb, current = 0}
}
next :: proc(it: ^RingBufferIterator($T)) -> (T, bool) {
if it.current >= it.rb.len {
return T{}, false
}
value, _ := get(it.rb^, it.current)
it.current += 1
return value, true
}

View File

@ -186,15 +186,15 @@ array_back :: proc( self : Array($Type) ) -> Type {
return value
}
// array_push_back :: proc( using self : Array( $ Type)) -> b32 {
// if num == capacity {
// return false
// }
array_push_back :: proc( using self : Array( $ Type)) -> b32 {
if num == capacity {
return false
}
// data[ num ] = value
// num += 1
// return true
// }
data[ num ] = value
num += 1
return true
}
array_clear :: proc "contextless" ( using self : Array( $ Type ), zero_data : b32 = false ) {
if zero_data {

View File

@ -1 +0,0 @@
package grime

View File

@ -8,7 +8,7 @@ was I believe exclusively when I didn't set the base addresss of vmem
OR when I was attempting to use Casey's brute force replay feature with memory.
5-26-2024 Update:
TODO(Ed): There is a Raw_Map structure defined in base:runtime/core.odin
We can use the regulare dynamic
We can use the regulare dynamic
---------------------------------------------------------------------------------------------------------
This implementation uses two ZPL-Based Arrays to hold entires and the actual hash table.

View File

@ -148,6 +148,7 @@ is_power_of_two :: proc {
iterator :: proc {
iterator_queue,
iterator_ringbuf_fixed,
}
make :: proc {

View File

@ -1,7 +1,9 @@
package grime
import "base:runtime"
import "core:container/queue"
// Note(Ed): Fixed size queue DOES NOT act as a RING BUFFER
make_queue :: proc( $QueueType : typeid/Queue($Type), capacity := queue.DEFAULT_CAPACITY, allocator := context.allocator, fixed_cap : bool = false ) -> (result : Queue(Type), error : AllocatorError)
{
allocator := allocator
@ -19,7 +21,9 @@ make_queue :: proc( $QueueType : typeid/Queue($Type), capacity := queue.DEFAULT_
push_back_slice_queue :: proc( self : ^$QueueType / Queue($Type), slice : []Type ) -> ( error : AllocatorError )
{
if len(slice) == 0 do return
queue.push_back_elems( self, ..slice )
return
}

View File

@ -0,0 +1,168 @@
package grime
RingBufferFixed :: struct( $Type: typeid, $Size: u32 ) {
head : u32,
tail : u32,
num : u32,
items : [Size] Type,
}
ringbuf_fixed_clear :: #force_inline proc "contextless" ( using buffer : ^RingBufferFixed( $Type, $Size)) {
head = 0
tail = 0
num = 0
}
ringbuf_fixed_is_full :: #force_inline proc "contextless" ( using buffer : RingBufferFixed( $Type, $Size)) -> bool {
return num == Size
}
ringbuf_fixed_is_empty :: #force_inline proc "contextless" ( using buffer : RingBufferFixed( $Type, $Size)) -> bool {
return num == 0
}
ringbuf_fixed_peek_front_ref :: #force_inline proc "contextless" ( using buffer : ^RingBufferFixed( $Type, $Size)) -> ^Type {
assert(num > 0, "Attempted to peek an empty ring buffer")
return & items[ head ]
}
ringbuf_fixed_peek_front :: #force_inline proc "contextless" ( using buffer : RingBufferFixed( $Type, $Size)) -> Type {
assert(num > 0, "Attempted to peek an empty ring buffer")
return items[ head ]
}
ringbuf_fixed_peak_back :: #force_inline proc ( using buffer : RingBufferFixed( $Type, $Size)) -> Type {
assert(num > 0, "Attempted to peek an empty ring buffer")
buf_size := u32(Size)
index := (tail - 1 + buf_size) % buf_size
return items[ index ]
}
ringbuf_fixed_push :: #force_inline proc(using buffer: ^RingBufferFixed($Type, $Size), value: Type) {
if num == Size do head = (head + 1) % Size
else do num += 1
items[ tail ] = value
tail = (tail + 1) % Size
}
ringbuf_fixed_push_slice :: proc(buffer: ^RingBufferFixed($Type, $Size), slice: []Type) -> u32
{
size := u32(Size)
slice_size := u32(len(slice))
// assert( slice_size <= size, "Attempting to append a slice that is larger than the ring buffer!" )
if slice_size == 0 do return 0
items_to_add := min( slice_size, size)
items_added : u32 = 0
if items_to_add > Size - buffer.num
{
// Some or all existing items will be overwritten
overwrite_count := items_to_add - (Size - buffer.num)
buffer.head = (buffer.head + overwrite_count) % size
buffer.num = size
}
else
{
buffer.num += items_to_add
}
if items_to_add <= size
{
// Case 1: Slice fits entirely or partially in the buffer
space_to_end := size - buffer.tail
first_chunk := min(items_to_add, space_to_end)
// First copy: from tail to end of buffer
copy( buffer.items[ buffer.tail: ] , slice[ :first_chunk ] )
if first_chunk < items_to_add {
// Second copy: wrap around to start of buffer
second_chunk := items_to_add - first_chunk
copy( buffer.items[:], slice[ first_chunk : items_to_add ] )
}
buffer.tail = (buffer.tail + items_to_add) % Size
items_added = items_to_add
}
else
{
// Case 2: Slice is larger than buffer, only keep last Size elements
to_add := slice[ slice_size - size: ]
// First copy: from start of buffer to end
first_chunk := min(Size, u32(len(to_add)))
copy( buffer.items[:], to_add[ :first_chunk ] )
if first_chunk < Size
{
// Second copy: wrap around
copy( buffer.items[ first_chunk: ], to_add[ first_chunk: ] )
}
buffer.head = 0
buffer.tail = 0
buffer.num = Size
items_added = Size
}
return items_added
}
ringbuf_fixed_pop :: #force_inline proc "contextless" ( using buffer : ^RingBufferFixed( $Type, $Size )) -> Type {
assert(num > 0, "Attempted to pop an empty ring buffer")
value := items[ head ]
head = ( head + 1 ) % Size
num -= 1
return value
}
RingBufferFixedIterator :: struct( $Type : typeid) {
items : []Type,
head : u32,
tail : u32,
index : u32,
remaining : u32,
}
iterator_ringbuf_fixed :: proc(buffer: ^RingBufferFixed($Type, $Size)) -> RingBufferFixedIterator(Type)
{
iter := RingBufferFixedIterator(Type){
items = buffer.items[:],
head = buffer.head,
tail = buffer.tail,
remaining = buffer.num,
}
buff_size := u32(Size)
if buffer.num > 0 {
// Start from the last pushed item (one before tail)
iter.index = (buffer.tail - 1 + buff_size) % buff_size
} else {
iter.index = buffer.tail // This will not be used as remaining is 0
}
return iter
}
next_ringbuf_fixed_iterator :: proc(iter : ^RingBufferFixedIterator( $Type)) -> ^Type
{
using iter
if remaining == 0 {
return nil // If there are no items left to iterate over
}
buf_size := cast(u32) len(items)
result := &items[index]
// Decrement index and wrap around if necessary
index = (index - 1 + buf_size) % buf_size
remaining -= 1
return result
}

View File

@ -12,7 +12,7 @@ stack_clear :: #force_inline proc ( using stack : ^StackFixed( $Type, $Size)) {
}
stack_push :: #force_inline proc( using stack : ^ StackFixed( $ Type, $ Size ), value : Type ) {
assert( idx < len( items ), "Attempted to push on a full stack" )
assert( idx < u32(len( items )), "Attempted to push on a full stack" )
items[ idx ] = value
idx += 1