210 lines
4.8 KiB
Plaintext
210 lines
4.8 KiB
Plaintext
Circle_Buffer :: struct (T: Type) {
|
|
allocated: s64;
|
|
data: *T;
|
|
|
|
allocator: Allocator;
|
|
|
|
offset: s64;
|
|
total_count: s64;
|
|
}
|
|
|
|
resize :: (cb: *Circle_Buffer, item_count: s64) {
|
|
buffer_has_memory := cb.data;
|
|
cb_copy := cb.*;
|
|
|
|
remember_allocators(cb);
|
|
|
|
array := NewArray(item_count, cb.T,, cb.allocator);
|
|
|
|
cb.allocated = array.count;
|
|
cb.data = array.data;
|
|
|
|
cb.offset = 0;
|
|
cb.total_count = 0;
|
|
|
|
// add back original and delete
|
|
if buffer_has_memory {
|
|
for item: cb_copy {
|
|
insert(cb, item);
|
|
}
|
|
|
|
delete(*cb_copy);
|
|
}
|
|
}
|
|
|
|
initialized :: (cb: *Circle_Buffer) -> bool {
|
|
return (cb.data && cb.allocated);
|
|
}
|
|
|
|
reset :: (using cb: *Circle_Buffer, $overwrite:=false) {
|
|
offset = 0;
|
|
total_count = 0;
|
|
|
|
if overwrite {
|
|
memset(cb.data, 0, cb.allocated * size_of(cb.T));
|
|
}
|
|
}
|
|
|
|
delete :: (cb: *Circle_Buffer) {
|
|
free(cb.data,, cb.allocator);
|
|
cb.allocated = 0;
|
|
cb.data = null;
|
|
cb.offset = 0;
|
|
cb.total_count = 0;
|
|
}
|
|
|
|
// This version of insert returns the original item from the slot to
|
|
// be inserted into. This is useful for when resources need to be freed before
|
|
// a slot should be overwritten
|
|
insert :: (cb: *Circle_Buffer, item: cb.T) -> cb.T {
|
|
original_item := cb.data[cb.offset];
|
|
|
|
cb.data[cb.offset] = item;
|
|
cb.offset = (cb.offset + 1) % cb.allocated;
|
|
|
|
cb.total_count += 1;
|
|
|
|
return original_item;
|
|
}
|
|
|
|
insert :: (cb: *Circle_Buffer, items: []cb.T) {
|
|
for item: items { insert(cb, item); }
|
|
}
|
|
|
|
// The newest get_count items, oldest first. Clamped to the items actually stored, since the slots
|
|
// past them hold nothing yet.
|
|
get :: (cb: *Circle_Buffer, get_count: s64) -> []cb.T {
|
|
get_count = min(get_count, count(cb.*));
|
|
|
|
return flatten_circle_buffer(cb, get_count);
|
|
}
|
|
|
|
flatten_circle_buffer :: (src: *Circle_Buffer, count: s64) -> []src.T {
|
|
assert(count <= src.allocated);
|
|
assert(src.offset < src.allocated);
|
|
|
|
// View buffer as Array_View:
|
|
src_array : []src.T = {src.allocated, src.data};
|
|
return flatten_circle_buffer(src_array, src.offset, count);
|
|
}
|
|
|
|
flatten_circle_buffer :: inline (src: []$T, offset: s64, count: s64) -> []T {
|
|
start := offset - count;
|
|
|
|
result := NewArray(count, T);
|
|
|
|
if start >= 0 { // just copy buffer:
|
|
for 0..count-1 {
|
|
result[it] = src[it + start];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
remainder := -start;
|
|
src_start := src.count - remainder;
|
|
|
|
// copy from end-remainder to src_buffer end
|
|
copy1_count := remainder;
|
|
for 0..copy1_count-1 {
|
|
result[it] = src[it + src_start];
|
|
}
|
|
|
|
// copy from 0 -> offset (the end bit)
|
|
copy2_count := offset;
|
|
for 0..copy2_count-1 {
|
|
result[it + copy1_count] = src[it];
|
|
}
|
|
|
|
assert(copy1_count + copy2_count == count);
|
|
return result;
|
|
}
|
|
|
|
operator *[] :: (cb: Circle_Buffer, index: int) -> *cb.T {
|
|
cb_index : int;
|
|
if cb.total_count > cb.allocated {
|
|
assert(index < cb.allocated, "Array index out of bounds!");
|
|
cb_index = (cb.offset + index) % cb.allocated;
|
|
} else {
|
|
assert(index < cb.total_count, "Array index out of bounds!");
|
|
cb_index = (index);
|
|
}
|
|
result := *cb.data[cb_index];
|
|
|
|
return result;
|
|
}
|
|
|
|
count :: (cb: Circle_Buffer) -> int {
|
|
if cb.total_count <= cb.allocated {
|
|
return cb.total_count;
|
|
}
|
|
|
|
return cb.allocated;
|
|
}
|
|
|
|
// This needs a for_expansion & operator *[]
|
|
for_expansion :: (src: *$T/Circle_Buffer, body: Code, flags: For_Flags) #expand {
|
|
REVERSE :: cast(bool) (flags & .REVERSE);
|
|
DO_POINTER :: cast(bool) (flags & .POINTER);
|
|
|
|
`it_index: int;
|
|
#if DO_POINTER { `it: *src.T; }
|
|
else { `it: src.T; }
|
|
|
|
#if REVERSE it_index = count(src.*);
|
|
else it_index = -1;
|
|
|
|
case1 := src.total_count <= src.allocated;
|
|
if case1 {
|
|
for <=REVERSE i: 0..src.total_count-1 {
|
|
#if REVERSE it_index -= 1;
|
|
else it_index += 1;
|
|
|
|
#if DO_POINTER it = *src.data[i];
|
|
else it = src.data[i];
|
|
#insert body;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Section 1 | Section 2
|
|
// mem_block: [-------------|------------------]<src.allocated
|
|
// offset: ^
|
|
|
|
#if REVERSE {
|
|
// Section 1
|
|
for < i: 0..src.offset-1 {
|
|
it_index -= 1;
|
|
#if DO_POINTER it = *src.data[i];
|
|
else it = src.data[i];
|
|
#insert body;
|
|
}
|
|
// Section 2
|
|
for < i: src.offset..src.allocated-1 {
|
|
it_index -= 1;
|
|
#if DO_POINTER it = *src.data[i];
|
|
else it = src.data[i];
|
|
#insert body;
|
|
}
|
|
}
|
|
|
|
#if !REVERSE {
|
|
// Section 2 (pointers after offset)
|
|
for i: src.offset..src.allocated-1 {
|
|
it_index += 1;
|
|
#if DO_POINTER it = *src.data[i];
|
|
else it = src.data[i];
|
|
#insert body;
|
|
}
|
|
|
|
// Section 1
|
|
for i: 0..src.offset-1 {
|
|
it_index += 1;
|
|
#if DO_POINTER it = *src.data[i];
|
|
else it = src.data[i];
|
|
#insert body;
|
|
}
|
|
}
|
|
}
|
|
|