#include #include #include #include "circbuf.h" // --- Circbuf data structure ---- /** Offset in void* buffer */ #define PV_OFFS(pvBuf, elem_size, index) ((uint8_t*)(pvBuf) + ((elem_size)*(index))) /** * @brief Write data to a CircBuf slot * @param cb : circbuf * @param index : slot index * @param source : data source */ static inline void write_buffer(CircBuf *cb, circbuf_size_t index, const void *source) { memcpy(PV_OFFS(cb->buf, cb->elem_size, index), source, cb->elem_size); } /** * @brief Copy data from a CircBuf slot to a buffer * @param cb : circbuf * @param index : slot index * @param dest : destination buffer */ static inline void read_buffer(const CircBuf *cb, circbuf_size_t index, void *dest) { memcpy(dest, PV_OFFS(cb->buf, cb->elem_size, index), cb->elem_size); } /** Get index of the front position (for write) */ static inline circbuf_size_t front_writepos(const CircBuf *cb) { return (cb->back + cb->num_used) % cb->cap; } void cbuf_init(CircBuf *cb, void *buf, circbuf_size_t capacity, circbuf_size_t elem_size) { // allocate the buffer cb->buf = buf; // set capacity, clear state cb->elem_size = elem_size; cb->cap = capacity; cbuf_clear(cb); } /** Check if cbuf is full */ bool cbuf_full(const CircBuf *cb) { if (cb == NULL) { return false; } return cb->num_used == cb->cap; } /** Check if cbuf is empty */ bool cbuf_empty(const CircBuf *cb) { if (cb == NULL) { return true; } return cb->num_used == 0; } /** Get the max capacity of the buffer */ circbuf_size_t cbuf_capacity(const CircBuf *cb) { return cb->cap; } /** Get the current number of items in the buffer */ circbuf_size_t cbuf_count(const CircBuf *cb) { return cb->num_used; } /** Push one element to the front_writepos */ bool cbuf_push(CircBuf *cb, const void *source) { if (cb == NULL || source == NULL || cb->num_used == cb->cap) { return false; } write_buffer(cb, front_writepos(cb), source); // increment cb->num_used++; return true; } /** Pop one element from the front_writepos */ bool cbuf_pop(CircBuf *cb, void *dest) { if (cb == NULL || dest == NULL || cb->num_used == 0) { return false; } cb->num_used--; circbuf_size_t f = front_writepos(cb); read_buffer(cb, f, dest); #ifdef CIRCBUF_ZERO_FREE_SLOTS memset(PV_OFFS(cb->buf, cb->elem_size, f), 0, cb->elem_size); #endif return true; } /** Peek at the front_writepos element */ bool cbuf_peek(const CircBuf *cb, void *dest) { if (cb == NULL || dest == NULL || cb->num_used == 0) { return false; } circbuf_size_t f = (cb->back + cb->num_used - 1) % cb->cap; read_buffer(cb, f, dest); return true; } void * cbuf_ptr(const CircBuf *cb) { if (cb == NULL || cb->num_used == 0) { return NULL; } circbuf_size_t f = (cb->back + cb->num_used - 1) % cb->cap; return PV_OFFS(cb->buf, cb->elem_size, f); } /** Peek at the nth element (counted from back) */ bool cbuf_nth(const CircBuf *cb, circbuf_size_t num, void *dest) { if (cb == NULL || dest == NULL || num > cb->num_used) { return false; } circbuf_size_t index = (cb->back + num) % cb->cap; read_buffer(cb, index, dest); return true; } void *cbuf_ptr_nth(const CircBuf *cb, circbuf_size_t num) { if (cb == NULL || num > cb->num_used) { return NULL; } circbuf_size_t index = (cb->back + num) % cb->cap; return PV_OFFS(cb->buf, cb->elem_size, index); } /** Push one element to the back */ bool cbuf_push_back(CircBuf *cb, const void *source) { if (cb == NULL || source == NULL || cb->num_used == cb->cap) { return false; } // move lr back if (cb->back == 0) { cb->back = cb->cap - 1; // wrap to the end } else { cb->back--; } cb->num_used++; write_buffer(cb, cb->back, source); return true; } /** Pop one element from the back */ bool cbuf_pop_back(CircBuf *cb, void *dest) { if (cb == NULL || dest == NULL || cb->num_used == 0) { return false; } read_buffer(cb, cb->back, dest); #ifdef CIRCBUF_ZERO_FREE_SLOTS memset(PV_OFFS(cb->buf, cb->elem_size, cb->back), 0, cb->elem_size); #endif // increment cb->back++; if (cb->back == cb->cap) { cb->back = 0; } cb->num_used--; return true; } /** Pop one element from the back */ bool cbuf_peek_back(const CircBuf *cb, void *dest) { if (cb == NULL || dest == NULL || cb->num_used == 0) { return false; } read_buffer(cb, cb->back, dest); return true; } void* cbuf_ptr_back(const CircBuf *cb) { if (cb == NULL || cb->num_used == 0) { return NULL; } return PV_OFFS(cb->buf, cb->elem_size, cb->back); } /** Clear a cbuf */ void cbuf_clear(CircBuf *cb) { if (cb == NULL) { return; } cb->num_used = 0; cb->back = 0; #ifdef CIRCBUF_ZERO_FREE_SLOTS memset(PV_OFFS(cb->buf, cb->elem_size, 0), 0, cb->cap * cb->elem_size); #endif }