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:
96
code/grime/.ring_buffer.odin
Normal file
96
code/grime/.ring_buffer.odin
Normal 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
|
||||
}
|
@ -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 {
|
||||
|
@ -1 +0,0 @@
|
||||
package grime
|
@ -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.
|
||||
|
@ -148,6 +148,7 @@ is_power_of_two :: proc {
|
||||
|
||||
iterator :: proc {
|
||||
iterator_queue,
|
||||
iterator_ringbuf_fixed,
|
||||
}
|
||||
|
||||
make :: proc {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
168
code/grime/ring_buffer_fixed.odin
Normal file
168
code/grime/ring_buffer_fixed.odin
Normal 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
|
||||
}
|
@ -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
|
||||
|
Reference in New Issue
Block a user