|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "circ_buff.h"
|
|
|
|
|
|
|
|
// Defines the circular buffer structure
|
|
|
|
struct circ_buf_t {
|
|
|
|
char** buffer;
|
|
|
|
size_t head;
|
|
|
|
size_t tail;
|
|
|
|
size_t max; // of the buffer
|
|
|
|
bool full;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Private Functions
|
|
|
|
|
|
|
|
static void advance_pointer(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
if(cbuf->full) {
|
|
|
|
cbuf->tail = (cbuf->tail + 1) % cbuf->max;
|
|
|
|
}
|
|
|
|
|
|
|
|
cbuf->head = (cbuf->head + 1) % cbuf->max;
|
|
|
|
|
|
|
|
// We mark full because we will advance tail on the next time around
|
|
|
|
cbuf->full = (cbuf->head == cbuf->tail);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void retreat_pointer(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
cbuf->full = false;
|
|
|
|
cbuf->tail = (cbuf->tail + 1) % cbuf->max;
|
|
|
|
}
|
|
|
|
|
|
|
|
// APIs
|
|
|
|
|
|
|
|
cbuf_handle_t circ_buf_init(char** buffer, size_t size) {
|
|
|
|
assert(buffer && size);
|
|
|
|
|
|
|
|
cbuf_handle_t cbuf = malloc(sizeof(circ_buf_t));
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
cbuf->buffer = buffer;
|
|
|
|
cbuf->max = size;
|
|
|
|
circ_buf_reset(cbuf);
|
|
|
|
|
|
|
|
assert(circ_buf_empty(cbuf));
|
|
|
|
|
|
|
|
return cbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
void circ_buf_free(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
free(cbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
void circ_buf_reset(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
cbuf->head = 0;
|
|
|
|
cbuf->tail = 0;
|
|
|
|
cbuf->full = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t circ_buf_size(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
size_t size = cbuf->max;
|
|
|
|
|
|
|
|
if(!cbuf->full) {
|
|
|
|
if(cbuf->head >= cbuf->tail) {
|
|
|
|
size = (cbuf->head - cbuf->tail);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
size = (cbuf->max + cbuf->head - cbuf->tail);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t circ_buf_capacity(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
return cbuf->max;
|
|
|
|
}
|
|
|
|
|
|
|
|
void circ_buf_put(cbuf_handle_t cbuf, char* data) {
|
|
|
|
assert(cbuf && cbuf->buffer);
|
|
|
|
|
|
|
|
strcpy(cbuf->buffer[cbuf->head], data);
|
|
|
|
|
|
|
|
advance_pointer(cbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
int circ_buf_get(cbuf_handle_t cbuf, char* data) {
|
|
|
|
assert(cbuf && data && cbuf->buffer);
|
|
|
|
|
|
|
|
int r = -1;
|
|
|
|
|
|
|
|
if(!circ_buf_empty(cbuf)) {
|
|
|
|
strcpy(data, cbuf->buffer[cbuf->tail]);
|
|
|
|
retreat_pointer(cbuf);
|
|
|
|
|
|
|
|
r = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool circ_buf_empty(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
return (!cbuf->full && (cbuf->head == cbuf->tail));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool circ_buf_full(cbuf_handle_t cbuf) {
|
|
|
|
assert(cbuf);
|
|
|
|
|
|
|
|
return cbuf->full;
|
|
|
|
}
|