Created
October 4, 2010 13:19
-
-
Save jsimmons/609674 to your computer and use it in GitHub Desktop.
ringbuffer implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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