You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
2.8 KiB
C

#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