150 lines
4.5 KiB
C
150 lines
4.5 KiB
C
#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);
|
|
}
|