For my purposes I just needed a simple FIFO buffer, but implementations I saw either wasted a byte of buffer space, required extra fields or were not very performant. This implementation provides full and empty conditions, a count (if you need it, I did not test it, just fair warning). You can add/remove bytes efficiently even if your buffer is not a power of 2 size.
#ifndef __REVRING_H__
#define __REVRING_H__
#include <stdint.h>
/** @brief Ring buffer that decrements indices as data is stored. */
struct revring_s {
unsigned head;
unsigned tail;
unsigned buffer_size;
uint8_t buffer[];
};
/** @brief Initialize reverse ring buffer. */
void revring_init(struct revring_s* rr, unsigned buffer_size);
static unsigned revring_empty(const struct revring_s* rr);
static unsigned revring_full(const struct revring_s* rr);
static unsigned revring_count(const struct revring_s* rr);
void revring_add_byte(struct revring_s* rr, uint8_t byte);
uint8_t revring_remove_byte(struct revring_s* rr);
static inline unsigned revring_empty(const struct revring_s* rr){
return rr->head == rr->tail;
}
static inline unsigned revring_full(const struct revring_s* rr){
return rr->head == 0;
}
static inline unsigned revring_count(const struct revring_s* rr){
unsigned ret = rr->buffer_size;
if(rr->head){
ret += rr->tail;
ret -= rr->head;
ret %= rr->buffer_size;
}
return ret;
}
#endif
#include <assert.h>
#include "revring.h"
void revring_init(struct revring_s* rr, unsigned buffer_size){
rr->head = buffer_size;
rr->tail = buffer_size;
rr->buffer_size = buffer_size;
}
void revring_add_byte(struct revring_s* rr, uint8_t byte){
assert(!revring_full(rr));
register unsigned idx = rr->head;
--idx;
rr->buffer[idx] = byte;
if(0 == idx)
idx = rr->buffer_size;
if(rr->tail == idx)
idx = 0;
rr->head = idx;
}
uint8_t revring_remove_byte(struct revring_s* rr){
assert(!revring_empty(rr));
register unsigned idx = rr->tail;
--idx;
const uint8_t* ret = rr->buffer + idx;
if(0 == idx)
idx = rr->buffer_size;
/* If full, then point head to where tail is currently. */
if(revring_full(rr))
rr->head = rr->tail;
rr->tail = idx;
return *ret;
}