Fixed-size circular buffer (ring buffer) for FIFO operations with no runtime allocations after initialization
Structs
RingBuffer
typedef struct {
void **buf;
size_t capacity;
size_t count;
size_t head;
size_t tail;
void (*destroy)(void *data);
} RingBuffer;
Functions
rb_init
Initializes the ring buffer with a fixed capacity. The user is responsible for creating the initial RingBuffer structure and freeing memory with rb_destroy(). destroy is a deallocation function for the members of the buffer, pass NULL if the memory is stack-allocated. Returns 0 on success, -1 on error (NULL pointer or zero capacity).
int rb_init(RingBuffer *rb, size_t capacity, void (*destroy)(void *));
/* Usage */
RingBuffer *rb = malloc(sizeof(RingBuffer));
// Pass NULL for stack-allocated memory
rb_init(rb, 16, NULL);
// Pass free or a custom freeing function for heap allocated memory
rb_init(rb, 16, free);
rb_destroy
Calls the deallocation function on any remaining elements in the buffer and frees the internal buffer. Does not destroy the RingBuffer struct itself, that is left up to the user.
void rb_destroy(RingBuffer *rb);
rb_push
Adds an element to the back of the buffer. Returns 0 on success, -1 if the buffer is full.
int rb_push(RingBuffer *rb, void *data);
/* Usage */
int a = 1;
rb_push(rb, &a);
rb_pop
Removes the element at the front of the buffer and stores its data in data. Returns 0 on success, -1 if the buffer is empty. The caller is responsible for freeing the popped element if it was heap-allocated.
int rb_pop(RingBuffer *rb, void **data);
/* Usage */
// buffer: 1 2 3
void *data;
rb_pop(rb, &data);
assert(*(int *)data == 1);
// buffer: 2 3
rb_peek
Returns a void * to the front element of the buffer without removing it. Returns NULL if the buffer is empty.
void *rb_peek(RingBuffer *rb);
/* Usage */
// buffer: 1 2 3
int *t = (int *)rb_peek(rb);
assert(*t == 1);
// buffer: 1 2 3
rb_clear
Calls the deallocation function on all remaining elements and resets the buffer to empty. The buffer can be reused after clearing.
void rb_clear(RingBuffer *rb);
Macros
rb_count
Returns the number of elements currently in the buffer.
#define rb_count(rb) ((rb)->count)
rb_capacity
Returns the total capacity of the buffer.
#define rb_capacity(rb) ((rb)->capacity)
rb_is_empty
Returns true if the buffer has no elements.
#define rb_is_empty(rb) ((rb)->count == 0)
rb_is_full
Returns true if the buffer is at capacity.
#define rb_is_full(rb) ((rb)->count == (rb)->capacity)