#pragma once #include #ifndef QUEUE_ASSERT void __flight_assert(bool cond, const char *file, int line, const char *cond_string); #define QUEUE_ASSERT(condition) __flight_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) // oldest to newest #define QUEUE_ITER(q_ptr, cur_header) for (QueueElementHeader *cur_header = (q_ptr)->next; cur_header != NULL; cur_header = cur_header->next) 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); void *queue_most_recent_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; cur = (QueueElementHeader*)((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; } void *queue_most_recent_element(Queue *q) { if (q->next == NULL) return NULL; else { QueueElementHeader *cur = q->next; while (cur->next != NULL) cur = cur->next; return (void *)cur->data; } } #undef QUEUE_ELEM_ITER #endif