Refactor opus queue into generic datastructure
parent
8ae4d90f1b
commit
6c0211436e
@ -0,0 +1,112 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef QUEUE_ASSERT
|
||||||
|
void __assert(bool cond, const char* file, int line, const char* cond_string);
|
||||||
|
#define QUEUE_ASSERT(condition) __assert(condition, __FILE__, __LINE__, #condition)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct QueueElementHeader {
|
||||||
|
bool exists;
|
||||||
|
struct QueueElementHeader* next;
|
||||||
|
char data[];
|
||||||
|
} QueueElementHeader;
|
||||||
|
|
||||||
|
typedef struct Queue {
|
||||||
|
char* data;
|
||||||
|
size_t data_length; // must be a multiple of sizeof(QueueElementHeader) + element_size
|
||||||
|
size_t element_size;
|
||||||
|
QueueElementHeader* next;
|
||||||
|
} Queue;
|
||||||
|
|
||||||
|
#define QUEUE_SIZE_FOR_ELEMENTS(element_size, max_elements) ((sizeof(QueueElementHeader) + element_size) * max_elements)
|
||||||
|
|
||||||
|
void queue_init(Queue* q, size_t element_size, char* data, size_t data_length);
|
||||||
|
void queue_clear(Queue* q);
|
||||||
|
void* queue_push_element(Queue* q);
|
||||||
|
size_t queue_num_elements(Queue* q);
|
||||||
|
void* queue_pop_element(Queue* q);
|
||||||
|
|
||||||
|
#ifdef QUEUE_IMPL
|
||||||
|
|
||||||
|
void queue_init(Queue* q, size_t element_size, char* data, size_t data_length)
|
||||||
|
{
|
||||||
|
q->data = data;
|
||||||
|
q->data_length = data_length;
|
||||||
|
q->element_size = element_size;
|
||||||
|
QUEUE_ASSERT(data_length % (sizeof(QueueElementHeader) + element_size) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void queue_clear(Queue* q)
|
||||||
|
{
|
||||||
|
QUEUE_ASSERT(q->data != NULL);
|
||||||
|
for (size_t i = 0; i < q->data_length; i++)
|
||||||
|
{
|
||||||
|
q->data[i] = 0;
|
||||||
|
}
|
||||||
|
q->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define QUEUE_ELEM_ITER(cur) for(QueueElementHeader *cur = (QueueElementHeader*)q->data; (char*)cur < q->data + q->data_length; (char*)cur += (sizeof(QueueElementHeader) + q->element_size))
|
||||||
|
|
||||||
|
// you push an element, get the return value, cast it to your type, and fill it with data. It's that easy!
|
||||||
|
// if it's null the queue is out of space
|
||||||
|
void* queue_push_element(Queue* q)
|
||||||
|
{
|
||||||
|
QUEUE_ASSERT(q->data != NULL);
|
||||||
|
QueueElementHeader* to_return = NULL;
|
||||||
|
QUEUE_ELEM_ITER(cur)
|
||||||
|
{
|
||||||
|
if (!cur->exists)
|
||||||
|
{
|
||||||
|
to_return = cur;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no free packet found in the buffer
|
||||||
|
if (to_return == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
to_return->exists = true;
|
||||||
|
to_return->next = NULL; // very important.
|
||||||
|
for (size_t i = 0; i < q->element_size; i++)
|
||||||
|
to_return->data[i] = 0;
|
||||||
|
|
||||||
|
// add to the end of the linked list chain
|
||||||
|
if (q->next != NULL)
|
||||||
|
{
|
||||||
|
QueueElementHeader* cur = q->next;
|
||||||
|
while (cur->next != NULL) cur = cur->next;
|
||||||
|
cur->next = to_return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
q->next = to_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void*)to_return->data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t queue_num_elements(Queue* q)
|
||||||
|
{
|
||||||
|
QUEUE_ASSERT(q->data != NULL);
|
||||||
|
size_t to_return = 0;
|
||||||
|
QUEUE_ELEM_ITER(cur)
|
||||||
|
if (cur->exists) to_return++;
|
||||||
|
return to_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns null if the queue is empty
|
||||||
|
void* queue_pop_element(Queue* q)
|
||||||
|
{
|
||||||
|
QUEUE_ASSERT(q->data != NULL);
|
||||||
|
QueueElementHeader* to_return = q->next;
|
||||||
|
if (q->next != NULL) q->next = q->next->next;
|
||||||
|
if (to_return != NULL) to_return->exists = false; // jank!
|
||||||
|
return to_return == NULL ? NULL : (void*)to_return->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef QUEUE_ELEM_ITER
|
||||||
|
#endif
|
Loading…
Reference in New Issue