File syn_ringbuf.c¶
File List > src > syntropic > util > syn_ringbuf.c
Go to the documentation of this file
#include "syn_ringbuf.h"
#include "../common/syn_barrier.h"
#include "../util/syn_assert.h"
#include <string.h>
/* ── Helpers ────────────────────────────────────────────────────────────── */
static inline size_t advance(size_t idx, size_t size)
{
size_t next = idx + 1;
return (next >= size) ? 0 : next;
}
/* ── API ────────────────────────────────────────────────────────────────── */
void syn_ringbuf_init(SYN_RingBuf *rb, uint8_t *buf, size_t size)
{
SYN_ASSERT(rb != NULL);
SYN_ASSERT(buf != NULL);
SYN_ASSERT(size > 1); /* need at least 2 bytes (1 usable + 1 sentinel) */
if (rb == NULL || buf == NULL || size <= 1) {
return;
}
rb->buf = buf;
rb->size = size;
SYN_STORE_RELEASE(&rb->head, 0);
SYN_STORE_RELEASE(&rb->tail, 0);
}
void syn_ringbuf_reset(SYN_RingBuf *rb)
{
SYN_ASSERT(rb != NULL);
if (rb == NULL) {
return;
}
SYN_STORE_RELEASE(&rb->head, 0);
SYN_STORE_RELEASE(&rb->tail, 0);
}
bool syn_ringbuf_put(SYN_RingBuf *rb, uint8_t byte)
{
SYN_ASSERT(rb != NULL);
if (rb == NULL || rb->buf == NULL || rb->size <= 1) {
return false;
}
size_t head = SYN_LOAD_ACQUIRE(&rb->head);
size_t tail = SYN_LOAD_ACQUIRE(&rb->tail);
size_t next_head = advance(head, rb->size);
if (next_head == tail) {
return false; /* full */
}
rb->buf[head] = byte;
SYN_STORE_RELEASE(&rb->head, next_head);
return true;
}
bool syn_ringbuf_get(SYN_RingBuf *rb, uint8_t *byte)
{
SYN_ASSERT(rb != NULL);
SYN_ASSERT(byte != NULL);
if (rb == NULL || rb->buf == NULL || byte == NULL || rb->size <= 1) {
return false;
}
size_t head = SYN_LOAD_ACQUIRE(&rb->head);
size_t tail = SYN_LOAD_ACQUIRE(&rb->tail);
if (head == tail) {
return false; /* empty */
}
*byte = rb->buf[tail];
SYN_STORE_RELEASE(&rb->tail, advance(tail, rb->size));
return true;
}
bool syn_ringbuf_peek(const SYN_RingBuf *rb, uint8_t *byte)
{
SYN_ASSERT(rb != NULL);
SYN_ASSERT(byte != NULL);
if (rb == NULL || rb->buf == NULL || byte == NULL || rb->size <= 1) {
return false;
}
size_t head = SYN_LOAD_ACQUIRE(&rb->head);
size_t tail = SYN_LOAD_ACQUIRE(&rb->tail);
if (head == tail) {
return false;
}
*byte = rb->buf[tail];
return true;
}
bool syn_ringbuf_full(const SYN_RingBuf *rb)
{
SYN_ASSERT(rb != NULL);
if (rb == NULL || rb->size <= 1) {
return false;
}
size_t head = SYN_LOAD_ACQUIRE(&rb->head);
size_t tail = SYN_LOAD_ACQUIRE(&rb->tail);
return advance(head, rb->size) == tail;
}
bool syn_ringbuf_empty(const SYN_RingBuf *rb)
{
SYN_ASSERT(rb != NULL);
if (rb == NULL) {
return true;
}
size_t head = SYN_LOAD_ACQUIRE(&rb->head);
size_t tail = SYN_LOAD_ACQUIRE(&rb->tail);
return head == tail;
}
size_t syn_ringbuf_count(const SYN_RingBuf *rb)
{
SYN_ASSERT(rb != NULL);
if (rb == NULL || rb->size <= 1) {
return 0;
}
size_t h = SYN_LOAD_ACQUIRE(&rb->head);
size_t t = SYN_LOAD_ACQUIRE(&rb->tail);
if (h >= t) {
return h - t;
}
return rb->size - t + h;
}
size_t syn_ringbuf_free(const SYN_RingBuf *rb)
{
SYN_ASSERT(rb != NULL);
if (rb == NULL || rb->size <= 1) {
return 0;
}
/* Capacity is size - 1 (one slot reserved as sentinel). */
return (rb->size - 1) - syn_ringbuf_count(rb);
}
size_t syn_ringbuf_write(SYN_RingBuf *rb, const uint8_t *data, size_t len)
{
SYN_ASSERT(rb != NULL);
SYN_ASSERT(data != NULL || len == 0);
if (rb == NULL || (data == NULL && len > 0)) {
return 0;
}
size_t avail = syn_ringbuf_free(rb);
if (len > avail) {
len = avail;
}
if (len == 0) {
return 0;
}
size_t head = SYN_LOAD_ACQUIRE(&rb->head);
/* Bytes from head to end of backing array */
size_t to_end = rb->size - head;
if (len <= to_end) {
/* No wrap needed */
memcpy(&rb->buf[head], data, len);
} else {
/* Two-part copy across the wrap boundary */
memcpy(&rb->buf[head], data, to_end);
memcpy(&rb->buf[0], data + to_end, len - to_end);
}
size_t new_head = head + len;
SYN_STORE_RELEASE(&rb->head, (new_head >= rb->size) ? new_head - rb->size : new_head);
return len;
}
size_t syn_ringbuf_read(SYN_RingBuf *rb, uint8_t *data, size_t len)
{
SYN_ASSERT(rb != NULL);
SYN_ASSERT(data != NULL || len == 0);
if (rb == NULL || (data == NULL && len > 0)) {
return 0;
}
size_t peeked = syn_ringbuf_peek_n(rb, data, len);
if (peeked > 0) {
size_t tail = SYN_LOAD_ACQUIRE(&rb->tail);
size_t new_tail = tail + peeked;
SYN_STORE_RELEASE(&rb->tail, (new_tail >= rb->size) ? new_tail - rb->size : new_tail);
}
return peeked;
}
size_t syn_ringbuf_peek_n(const SYN_RingBuf *rb, uint8_t *data, size_t len)
{
SYN_ASSERT(rb != NULL);
SYN_ASSERT(data != NULL || len == 0);
if (rb == NULL || (data == NULL && len > 0)) {
return 0;
}
size_t avail = syn_ringbuf_count(rb);
if (len > avail) {
len = avail;
}
if (len == 0) {
return 0;
}
size_t tail = SYN_LOAD_ACQUIRE(&rb->tail);
/* Bytes from tail to end of backing array */
size_t to_end = rb->size - tail;
if (len <= to_end) {
/* No wrap needed */
memcpy(data, &rb->buf[tail], len);
} else {
/* Two-part copy across the wrap boundary */
memcpy(data, &rb->buf[tail], to_end);
memcpy(data + to_end, &rb->buf[0], len - to_end);
}
/* Tail is NOT advanced — this is a peek, not a consume */
return len;
}