Skip to content

Instantly share code, notes, and snippets.

@jsimmons
Created October 4, 2010 13:19
Show Gist options
  • Save jsimmons/609674 to your computer and use it in GitHub Desktop.
Save jsimmons/609674 to your computer and use it in GitHub Desktop.
ringbuffer implementation
#include "ring-buffer.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
RingBuffer *rb_new(size_t size)
{
RingBuffer *buf = malloc(sizeof(*buf));
assert(buf != NULL);
buf->data = malloc(size);
assert(buf->data != NULL);
buf->size = size;
buf->head = buf->fill = 0;
return buf;
}
static inline void advance_tail(RingBuffer *buf, size_t bytes)
{
buf->fill += bytes;
}
void rb_write(RingBuffer *buf, const char *from, size_t bytes)
{
assert(bytes <= rb_remain(buf));
char *tail = buf->data + ((buf->head + buf->fill) % buf->size);
char *write_end = buf->data + ((buf->head + buf->fill + bytes) % buf->size);
if(tail <= write_end)
{
memcpy(tail, from, bytes);
}
else
{
char *end = buf->data + buf->size;
size_t first_write = end - tail;
memcpy(tail, from, first_write);
size_t second_write = bytes - first_write;
memcpy(buf->data, from + first_write, second_write);
}
advance_tail(buf, bytes);
}
char *rb_write_pointer(RingBuffer *buf, size_t *writable)
{
if(rb_is_full(buf))
{
*writable = 0;
return NULL;
}
char *head = buf->data + buf->head;
char *tail = buf->data + ((buf->head + buf->fill) % buf->size);
if(tail < head)
{
*writable = head - tail;
}
else
{
char *end = buf->data + buf->size;
*writable = end - tail;
}
return tail;
}
void rb_write_commit(RingBuffer *buf, size_t bytes)
{
assert(bytes <= rb_remain(buf));
advance_tail(buf, bytes);
}
static inline void advance_head(RingBuffer *buf, size_t bytes)
{
buf->head = (buf->head + bytes) % buf->size;
buf->fill -= bytes;
}
void rb_read(RingBuffer *buf, char *to, size_t bytes)
{
assert(bytes <= rb_used(buf));
char *head = buf->data + buf->head;
char *end_read = buf->data + ((buf->head + bytes) % buf->size);
if(end_read <= head)
{
char *end = buf->data + buf->size;
size_t first_read = end - head;
memcpy(to, head, first_read);
size_t second_read = bytes - first_read;
memcpy(to + first_read, buf->data, second_read);
}
else
{
memcpy(to, head, bytes);
}
advance_head(buf, bytes);
}
const char *rb_read_pointer(RingBuffer *buf, size_t offset, size_t *readable)
{
if(rb_is_empty(buf))
{
*readable = 0;
return NULL;
}
char *head = buf->data + buf->head + offset;
char *tail = buf->data + ((buf->head + offset + buf->fill) % buf->size);
if(tail <= head)
{
char *end = buf->data + buf->size;
*readable = end - head;
}
else
{
*readable = tail - head;
}
return head;
}
void rb_read_commit(RingBuffer *buf, size_t bytes)
{
assert(rb_used(buf) >= bytes);
advance_head(buf, bytes);
}
void rb_stream(RingBuffer *from, RingBuffer *to, size_t bytes)
{
assert(rb_used(from) <= bytes);
assert(rb_remain(to) >= bytes);
size_t copied = 0;
while(copied < bytes)
{
size_t can_read;
const char *from_ptr = rb_read_pointer(from, copied, &can_read);
size_t copied_this_read = 0;
while(copied_this_read < can_read)
{
size_t can_write;
char *to_ptr = rb_write_pointer(to, &can_write);
size_t write = (can_read > can_write) ? can_write : can_read;
memcpy(to_ptr, from_ptr, write);
copied_this_read += write;
}
copied += copied_this_read;
}
advance_tail(to, copied);
}
void rb_free(RingBuffer *buf)
{
if(buf != NULL)
{
free(buf->data);
free(buf);
}
}
#ifndef RIRC_RING_BUFFER_H
#define RIRC_RING_BUFFER_H
#include <stdbool.h>
#include <stddef.h>
typedef struct
{
char *data;
size_t size;
size_t head;
size_t fill;
} RingBuffer;
RingBuffer *rb_new(size_t size);
static inline bool rb_is_empty(RingBuffer *buf)
{
return buf->fill == 0;
}
static inline bool rb_is_full(RingBuffer *buf)
{
return buf->fill == buf->size;
}
static inline size_t rb_size(RingBuffer *buf)
{
return buf->size;
}
static inline size_t rb_used(RingBuffer *buf)
{
return buf->fill;
}
static inline size_t rb_remain(RingBuffer *buf)
{
return buf->size - buf->fill;
}
static inline void rb_empty(RingBuffer *buf)
{
buf->head = buf->fill = 0;
}
void rb_write(RingBuffer *buf, const char *from, size_t bytes);
char *rb_write_pointer(RingBuffer *buf, size_t *writable);
void rb_write_commit(RingBuffer *buf, size_t bytes);
void rb_read(RingBuffer *buf, char *to, size_t bytes);
const char *rb_read_pointer(RingBuffer *buf, size_t offset, size_t *readable);
void rb_read_commit(RingBuffer *buf, size_t bytes);
void rb_stream(RingBuffer *from, RingBuffer *to, size_t bytes);
void rb_free(RingBuffer *buf);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment