121 lines
3.1 KiB
C
121 lines
3.1 KiB
C
#ifndef QUEUE_H
|
|
#define QUEUE_H
|
|
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
//This was vibecoded #FML
|
|
|
|
typedef struct {
|
|
void *data;
|
|
size_t head;
|
|
size_t tail;
|
|
size_t count;
|
|
size_t capacity;
|
|
size_t stride; // Size of one element
|
|
bool is_dynamic;
|
|
} queue_t;
|
|
|
|
// Public API
|
|
void queue_init_static(queue_t *q, void *buffer, size_t capacity, size_t stride);
|
|
bool queue_init_dynamic(queue_t *q, size_t initial_capacity, size_t stride);
|
|
void queue_free(queue_t *q);
|
|
|
|
bool queue_push(queue_t *q, const void *val); // The "try_push" version
|
|
bool queue_pop(queue_t *q, void *out_val);
|
|
bool queue_peek(queue_t *q, void *out_val);
|
|
|
|
#define queue_is_empty(q) ((q)->count == 0)
|
|
#define queue_is_full(q) ((q)->count == (q)->capacity)
|
|
|
|
#ifdef QUEUE_IMPLEMENTATION
|
|
|
|
void queue_init_static(queue_t *q, void *buffer, size_t capacity, size_t stride) {
|
|
q->data = buffer;
|
|
q->head = 0;
|
|
q->tail = 0;
|
|
q->count = 0;
|
|
q->capacity = capacity;
|
|
q->stride = stride;
|
|
q->is_dynamic = false;
|
|
}
|
|
|
|
bool queue_init_dynamic(queue_t *q, size_t initial_capacity, size_t stride) {
|
|
q->capacity = (initial_capacity > 0) ? initial_capacity : 8;
|
|
q->stride = stride;
|
|
q->data = malloc(q->capacity * q->stride);
|
|
if (!q->data) return false;
|
|
|
|
q->head = 0;
|
|
q->tail = 0;
|
|
q->count = 0;
|
|
q->is_dynamic = true;
|
|
return true;
|
|
}
|
|
|
|
void queue_free(queue_t *q) {
|
|
if (q->is_dynamic && q->data) {
|
|
free(q->data);
|
|
}
|
|
q->data = NULL;
|
|
}
|
|
|
|
static bool _queue_grow(queue_t *q) {
|
|
size_t new_cap = q->capacity * 2;
|
|
void *new_data = malloc(new_cap * q->stride);
|
|
if (!new_data) return false;
|
|
|
|
// Copy data in order: from head to end, then from beginning to tail
|
|
for (size_t i = 0; i < q->count; ++i) {
|
|
size_t old_idx = (q->head + i) % q->capacity;
|
|
memcpy((char*)new_data + (i * q->stride),
|
|
(char*)q->data + (old_idx * q->stride),
|
|
q->stride);
|
|
}
|
|
|
|
if (q->is_dynamic) free(q->data);
|
|
|
|
q->data = new_data;
|
|
q->head = 0;
|
|
q->tail = q->count;
|
|
q->capacity = new_cap;
|
|
q->is_dynamic = true; // Even if it was static, it's dynamic now
|
|
return true;
|
|
}
|
|
|
|
bool queue_push(queue_t *q, const void *val) {
|
|
if (queue_is_full(q)) {
|
|
if (q->is_dynamic) {
|
|
if (!_queue_grow(q)) return false;
|
|
} else {
|
|
return false; // Static queue full
|
|
}
|
|
}
|
|
|
|
memcpy((char*)q->data + (q->tail * q->stride), val, q->stride);
|
|
q->tail = (q->tail + 1) % q->capacity;
|
|
q->count++;
|
|
return true;
|
|
}
|
|
|
|
bool queue_pop(queue_t *q, void *out_val) {
|
|
if (queue_is_empty(q)) return false;
|
|
|
|
if (out_val) {
|
|
memcpy(out_val, (char*)q->data + (q->head * q->stride), q->stride);
|
|
}
|
|
q->head = (q->head + 1) % q->capacity;
|
|
q->count--;
|
|
return true;
|
|
}
|
|
|
|
bool queue_peek(queue_t *q, void *out_val) {
|
|
if (queue_is_empty(q)) return false;
|
|
memcpy(out_val, (char*)q->data + (q->head * q->stride), q->stride);
|
|
return true;
|
|
}
|
|
|
|
#endif // QUEUE_IMPLEMENTATION
|
|
#endif // QUEUE_H
|