Update queue implementation to use ring buffer
This commit is contained in:
@@ -3,24 +3,83 @@
|
||||
#include "queue.h"
|
||||
#include "../array/array.h"
|
||||
#include "../../common/assert/assert.h"
|
||||
#include "../../common/misc/misc_utils.h"
|
||||
#include <string.h>
|
||||
|
||||
void _queue_pop_front(GenericQueue *queue, void *output, u64 item_size) {
|
||||
wapp_debug_assert(queue != NULL && output != NULL, "`queue` and `output` should not be NULL");
|
||||
void _queue_push(GenericQueue *queue, void *item, u64 item_size) {
|
||||
wapp_debug_assert(queue != NULL, "`queue` should not be NULL");
|
||||
wapp_runtime_assert(item_size == wapp_array_item_size(queue->items), "Invalid type");
|
||||
|
||||
memcpy(output, queue->items, item_size);
|
||||
u64 capacity = wapp_array_capacity(queue->items);
|
||||
if (queue->count >= capacity) { return; }
|
||||
|
||||
// NOTE (Abdelrahman): Uses a while loop instead of a for loop to get rid of
|
||||
// MSVC Spectre mitigation warnings
|
||||
u64 new_count = wapp_array_count(queue->items) - 1;
|
||||
u64 index = 0;
|
||||
b8 running = index < new_count;
|
||||
while (running) {
|
||||
_array_set(queue->items, index, _array_get(queue->items, index + 1, item_size), item_size);
|
||||
++index;
|
||||
running = index < new_count;
|
||||
u64 index = (queue->back)++;
|
||||
_array_set(queue->items, index, item, item_size);
|
||||
++(queue->count);
|
||||
|
||||
if (queue->back >= capacity) {
|
||||
queue->back = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GenericQueue *_queue_push_alloc(const Allocator *allocator, GenericQueue *queue, void *item, u64 item_size) {
|
||||
wapp_debug_assert(allocator != NULL && queue != NULL && item != NULL,
|
||||
"`allocator`, `queue` and `item` should not be NULL");
|
||||
wapp_runtime_assert(item_size == wapp_array_item_size(queue->items), "Invalid type");
|
||||
|
||||
GenericQueue *output = queue;
|
||||
|
||||
u64 capacity = wapp_array_capacity(queue->items);
|
||||
if (queue->count >= capacity) {
|
||||
u64 new_capacity = wapp_misc_utils_u64_round_up_pow2(capacity * 2);
|
||||
u64 array_size = _array_calc_alloc_size(new_capacity, item_size);
|
||||
u64 alloc_size = sizeof(GenericQueue) + array_size;
|
||||
void *buffer = wapp_mem_allocator_alloc(allocator, alloc_size);
|
||||
if (!buffer) {
|
||||
goto RETURN_QUEUE_PUSH_ALLOC;
|
||||
}
|
||||
|
||||
memset((void *)buffer, 0, alloc_size);
|
||||
|
||||
output = (GenericQueue *)buffer;
|
||||
output->items = _array_from_preallocated_buffer((void *)(output + 1), array_size, ARRAY_INIT_FILLED, item_size);
|
||||
|
||||
// NOTE (Abdelrahman): When the queue is full, the front and back indices should
|
||||
// always be the same
|
||||
u64 front_count = capacity - queue->front;
|
||||
u64 back_count = queue->back;
|
||||
void *copy_boundary = (void *)((uptr)(queue->items) + (queue->front * item_size));
|
||||
|
||||
memcpy(output->items, copy_boundary, front_count * item_size);
|
||||
if (back_count > 0) {
|
||||
void *back_copy_dst = (void *)((uptr)(output->items) + (front_count * item_size));
|
||||
memcpy(back_copy_dst, queue->items, back_count * item_size);
|
||||
}
|
||||
|
||||
output->front = 0;
|
||||
output->back = front_count + back_count;
|
||||
output->count = queue->count;
|
||||
}
|
||||
|
||||
wapp_array_set_count(queue->items, new_count);
|
||||
_queue_push(output, item, item_size);
|
||||
|
||||
RETURN_QUEUE_PUSH_ALLOC:
|
||||
return output;
|
||||
}
|
||||
|
||||
void *_queue_pop(GenericQueue *queue, u64 item_size) {
|
||||
wapp_debug_assert(queue != NULL, "`queue` should not be NULL");
|
||||
wapp_runtime_assert(item_size == wapp_array_item_size(queue->items), "Invalid type");
|
||||
|
||||
if (queue->count == 0) { return NULL; }
|
||||
|
||||
u64 index = (queue->front)++;
|
||||
--(queue->count);
|
||||
|
||||
u64 capacity = wapp_array_capacity(queue->items);
|
||||
if (queue->front >= capacity) {
|
||||
queue->front = 0;
|
||||
}
|
||||
|
||||
return _array_get(queue->items, index, item_size);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user