109 lines
3.6 KiB
C
109 lines
3.6 KiB
C
// vim:fileencoding=utf-8:foldmethod=marker
|
|
|
|
#include "queue.h"
|
|
#include "../array/array.h"
|
|
#include "../../common/assert/assert.h"
|
|
#include "../../common/misc/misc_utils.h"
|
|
#include <string.h>
|
|
|
|
void queuePush(WpQueue *queue, void *item, u64 item_size) {
|
|
wpDebugAssert(queue != NULL, "`queue` should not be NULL");
|
|
wpRuntimeAssert(item_size == wpArrayItemSize(queue->items), "Invalid type");
|
|
|
|
u64 capacity = wpArrayCapacity(queue->items);
|
|
if (queue->count >= capacity) { return; }
|
|
|
|
u64 index = (queue->back)++;
|
|
arraySet(queue->items, index, item, item_size);
|
|
++(queue->count);
|
|
|
|
if (queue->back >= capacity) {
|
|
queue->back = 0;
|
|
}
|
|
}
|
|
|
|
WpQueue *queuePushAlloc(const WpAllocator *allocator, WpQueue *queue, void *item, u64 item_size) {
|
|
wpDebugAssert(allocator != NULL && queue != NULL && item != NULL,
|
|
"`allocator`, `queue` and `item` should not be NULL");
|
|
wpRuntimeAssert(item_size == wpArrayItemSize(queue->items), "Invalid type");
|
|
|
|
WpQueue *output = queue;
|
|
|
|
u64 capacity = wpArrayCapacity(queue->items);
|
|
|
|
// NOTE (Abdelrahman): Extracted into variable to fix MSVC error
|
|
b8 queue_full = queue->count >= capacity;
|
|
if (queue_full) {
|
|
u64 new_capacity = wpMiscUtilsU64RoundUpPow2(capacity * 2);
|
|
u64 array_size = arrayCalcAllocSize(new_capacity, item_size);
|
|
u64 alloc_size = sizeof(WpQueue) + array_size;
|
|
void *buffer = wpMemAllocatorAlloc(allocator, alloc_size);
|
|
if (!buffer) {
|
|
goto RETURN_QUEUE_PUSH_ALLOC;
|
|
}
|
|
|
|
memset((void *)buffer, 0, alloc_size);
|
|
|
|
output = (WpQueue *)buffer;
|
|
output->items = arrayFromPreallocatedBuffer((void *)(output + 1), array_size, WP_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);
|
|
|
|
/**
|
|
* NOTE (Abdelrahman): Since this is a ring buffer, the elements at the beginning of the array
|
|
* aren't always the ones at the front of the queue. When that's the case, the memcpy above
|
|
* will only copy a subset of the elements. This is why we need to copy the remaining ones.
|
|
*
|
|
* Example: Take a queue that looks like this with a capacity of 5 elements
|
|
*
|
|
* 0 1 | 2 3 4
|
|
* ---------------|-----------------------
|
|
* | * | * | * | * | * |
|
|
* ---------------|-----------------------
|
|
* |
|
|
* queue_front = 2
|
|
* queue_back = 2
|
|
*
|
|
* In this case, the first memcpy will only copy elements 2-4. The memcpy below will be
|
|
* responsible for copying elements 0-1.
|
|
*/
|
|
b8 items_left_to_copy = back_count > 0;
|
|
if (items_left_to_copy) {
|
|
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;
|
|
}
|
|
|
|
queuePush(output, item, item_size);
|
|
|
|
RETURN_QUEUE_PUSH_ALLOC:
|
|
return output;
|
|
}
|
|
|
|
void *queuePop(WpQueue *queue, u64 item_size) {
|
|
wpDebugAssert(queue != NULL, "`queue` should not be NULL");
|
|
wpRuntimeAssert(item_size == wpArrayItemSize(queue->items), "Invalid type");
|
|
|
|
if (queue->count == 0) { return NULL; }
|
|
|
|
u64 index = (queue->front)++;
|
|
--(queue->count);
|
|
|
|
u64 capacity = wpArrayCapacity(queue->items);
|
|
if (queue->front >= capacity) {
|
|
queue->front = 0;
|
|
}
|
|
|
|
return arrayGet(queue->items, index, item_size);
|
|
}
|