Files

150 lines
4.5 KiB
C
Raw Permalink Normal View History

#include "ringbuf.h"
#include <stdlib.h>
#include <string.h>
#include <stdatomic.h>
struct crt_ringbuf {
uint8_t* buffer;
size_t capacity;
size_t head;
size_t tail;
atomic_size_t count;
};
crt_ringbuf_t* crt_ringbuf_create(size_t capacity) {
crt_ringbuf_t* rb = calloc(1, sizeof(crt_ringbuf_t));
if (!rb) return NULL;
rb->buffer = malloc(capacity);
if (!rb->buffer) {
free(rb);
return NULL;
}
rb->capacity = capacity;
rb->head = 0;
rb->tail = 0;
atomic_init(&rb->count, 0);
return rb;
}
void crt_ringbuf_destroy(crt_ringbuf_t* rb) {
if (!rb) return;
free(rb->buffer);
free(rb);
}
bool crt_ringbuf_push(crt_ringbuf_t* rb, const void* data, size_t len) {
if (!rb || !data || len == 0) return false;
if (len + sizeof(size_t) > rb->capacity) return false;
size_t current = atomic_load(&rb->count);
if (current >= rb->capacity - len - sizeof(size_t)) return false;
size_t head = rb->head;
size_t needed = len + sizeof(size_t);
if (head + needed <= rb->capacity) {
memcpy(rb->buffer + head, &len, sizeof(size_t));
memcpy(rb->buffer + head + sizeof(size_t), data, len);
rb->head = (head + needed) % rb->capacity;
} else {
size_t first_part = rb->capacity - head;
if (first_part >= sizeof(size_t)) {
memcpy(rb->buffer + head, &len, sizeof(size_t));
memcpy(rb->buffer + head + sizeof(size_t), data, first_part - sizeof(size_t));
memcpy(rb->buffer, (uint8_t*)data + first_part - sizeof(size_t), len - (first_part - sizeof(size_t)));
} else {
memcpy(rb->buffer + head, &len, first_part);
memcpy(rb->buffer, (uint8_t*)&len + first_part, sizeof(size_t) - first_part);
memcpy(rb->buffer + sizeof(size_t) - first_part, data, len);
}
rb->head = needed - first_part;
}
atomic_fetch_add(&rb->count, needed);
return true;
}
bool crt_ringbuf_pop(crt_ringbuf_t* rb, void* out, size_t* len) {
if (!rb || !out || !len) return false;
if (atomic_load(&rb->count) == 0) return false;
size_t tail = rb->tail;
size_t stored_len;
if (tail + sizeof(size_t) <= rb->capacity) {
memcpy(&stored_len, rb->buffer + tail, sizeof(size_t));
} else {
size_t first_part = rb->capacity - tail;
memcpy(&stored_len, rb->buffer + tail, first_part);
memcpy((uint8_t*)&stored_len + first_part, rb->buffer, sizeof(size_t) - first_part);
}
size_t total_size = stored_len + sizeof(size_t);
if (tail + total_size <= rb->capacity) {
memcpy(out, rb->buffer + tail + sizeof(size_t), stored_len);
} else {
size_t first_part = rb->capacity - tail - sizeof(size_t);
memcpy(out, rb->buffer + tail + sizeof(size_t), first_part);
memcpy((uint8_t*)out + first_part, rb->buffer, stored_len - first_part);
}
rb->tail = (tail + total_size) % rb->capacity;
atomic_fetch_sub(&rb->count, total_size);
*len = stored_len;
return true;
}
bool crt_ringbuf_peek(crt_ringbuf_t* rb, void* out, size_t* len) {
if (!rb || !out || !len) return false;
if (atomic_load(&rb->count) == 0) return false;
size_t tail = rb->tail;
size_t stored_len;
if (tail + sizeof(size_t) <= rb->capacity) {
memcpy(&stored_len, rb->buffer + tail, sizeof(size_t));
} else {
size_t first_part = rb->capacity - tail;
memcpy(&stored_len, rb->buffer + tail, first_part);
memcpy((uint8_t*)&stored_len + first_part, rb->buffer, sizeof(size_t) - first_part);
}
size_t total_size = stored_len + sizeof(size_t);
if (tail + total_size <= rb->capacity) {
memcpy(out, rb->buffer + tail + sizeof(size_t), stored_len);
} else {
size_t first_part = rb->capacity - tail - sizeof(size_t);
memcpy(out, rb->buffer + tail + sizeof(size_t), first_part);
memcpy((uint8_t*)out + first_part, rb->buffer, stored_len - first_part);
}
*len = stored_len;
return true;
}
size_t crt_ringbuf_count(crt_ringbuf_t* rb) {
return rb ? atomic_load(&rb->count) : 0;
}
size_t crt_ringbuf_capacity(crt_ringbuf_t* rb) {
return rb ? rb->capacity : 0;
}
bool crt_ringbuf_empty(crt_ringbuf_t* rb) {
return rb ? atomic_load(&rb->count) == 0 : true;
}
bool crt_ringbuf_full(crt_ringbuf_t* rb) {
return rb ? atomic_load(&rb->count) >= rb->capacity : true;
}
void crt_ringbuf_clear(crt_ringbuf_t* rb) {
if (!rb) return;
rb->head = 0;
rb->tail = 0;
atomic_store(&rb->count, 0);
}