Last active
June 20, 2019 04:11
-
-
Save floooh/3eb289cf298e855078b81cad6ac7626d to your computer and use it in GitHub Desktop.
simple circular-queue / ringbuffer in C
This file contains hidden or 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
#define MAX_SLOTS (256) | |
typedef struct { | |
uint32_t head; // next slot to enqeue | |
uint32_t tail; // next slot to dequeue | |
uint32_t num; // number of slots in ring buffer (plus 1 for empty/full detection) | |
uint32_t buf[MAX_SLOTS]; // items could be index-handles | |
} ring_t; | |
// wrapped index into buf (private helper) | |
static void _ring_wrap(const ring_t* rb, uint32_t i) { | |
return i % rb->num; | |
} | |
// initialize a ring_t struct | |
void ring_init(ring_t* rb, uint32_t num_slots) { | |
assert(rb && (num_slots > 0) && (num_slots < MAX_SLOTS)); | |
memset(rb, 0, sizeof(ring_t)); | |
// one slot reserved to detect full vs empty | |
rb->num = num_slots + 1; | |
} | |
// return true if ring buffer is full | |
bool ring_full(const ring_t* rb) { | |
assert(rb && (rb->num > 0)); | |
return _ring_wrap(rb, rb->head + 1) == rb->tail; | |
} | |
// return true if ring buffer is empty | |
bool ring_empty(const ring_t* rb) { | |
assert(rb && (rb->num > 0)); | |
return rb->head == rb->tail; | |
} | |
// return number of items in ring buffer | |
uint32_t ring_count(const ring_t* rb) { | |
assert(rb && (rb->num > 0)); | |
uint32_t count; | |
if (rb->head >= rb->tail) { | |
count = rb->head - rb->tail; | |
} | |
else { | |
count = (rb->head + rb->num) - rb->tail; | |
} | |
assert(count < rb->num); | |
return count; | |
} | |
// enqueue a new item at the front (assumes not full) | |
bool ring_enqueue(ring_t* rb, uint32_t val) { | |
assert(rb && (rb->num > 0)); | |
assert(!ring_full(rb)); | |
assert(rb->head < rb->num); | |
rb->buf[rb->head] = val; | |
rb->head = _ring_wrap(rb, rb->head + 1); | |
} | |
// dequeue item from the back (assumes not empty) | |
uint32_t ring_dequeue(ring_t* rb) { | |
assert(rb && (rb->num > 0)); | |
assert(!ring_empty(rb)); | |
assert(rb->tail < rb->num); | |
uint32_t val = rb->buf[rb->tail]; | |
rb->tail = _ring_wrap(rb, rb->tail + 1); | |
return val; | |
} | |
// return item at relative index (for iterating over content) | |
uint32_t ring_peek(const ring_t* rb, uint32_t index) { | |
assert(rb && (rb->num > 0)); | |
assert(index < ring_count(rb)); | |
uint32_t rb_index = _ring_wrap(rb, rb->tail + index); | |
return rb->buf[rb_index]; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment