I searched the net for over two days to make a circular list that could be used for different data types. I use c language, so I mean I am looking for some code that can manage buffers with char, short, int, signed, or unsigned definitions. what I have found more useful is these 2 links
The problem I have is that I am working on embedded boards with an external ram and since I do have not enough memory inside the processor chip, I have to use external memory, and in this case, malloc function would not work correctly.
So I am looking for some code or enhancing the embedded artistry code to be flexible to different data types.
What I had done with no good result was to change this code into two parts. one for char type and one for short type.
struct circular_buf_t {
uint8_t *buffer;
size_t head;
size_t tail;
size_t max; // of the buffer
bool full;
};
struct circular_buf_short_t {
void *buffer;
size_t head;
size_t tail;
size_t max; // of the buffer
bool full;
};
cbuf_handle_t circular_buf_init(uint8_t *buffer, size_t size) {
cbuf_handle_t cbuf = malloc(sizeof(circular_buf_t));
cbuf->buffer = buffer;
cbuf->max = size;
circular_buf_reset(cbuf);
return cbuf;
}
cbuf_handle_short_t circular_buf_short_init(uint16_t *buffer, size_t size) {
cbuf_handle_short_t cbuf = malloc(sizeof(cbuf_handle_short_t));
circular_buf_short_reset(cbuf);
cbuf->buffer = buffer;
cbuf->max = size;
return cbuf;
}
int circular_buf_try_put(cbuf_handle_t me, uint8_t data) {
int r = -1;
if (!circular_buf_full(me)) {
me->buffer[me->head] = data;
advance_head_pointer(me);
r = 0;
}
return r;
}
int circular_buf_short_try_put(cbuf_handle_short_t me, uint16_t data) {
int r = -1;
if (!circular_buf_short_full(me)) {
me->buffer[me->head] = data;
advance_head_pointer_short(me);
r = 0;
}
return r;
}
For your purpose, you could use a generic circular buffer structure that you initialize with an array of the type needed (eg: 8, 16 or 32 bit integers) along with the element size and element count.
The ancillary functions work the same for all types, and the get and put functions handle the specific type with a test.
If you know the type of element for a given buffer, you can use the specific get/put function.
Here is a sample implementation:
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct circular_buf_t {
void *buffer;
size_t head; // you can make these uint16_t to save memory
size_t tail;
size_t element_count; // number of elements in the buffer
uint8_t element_size;
bool full;
} circular_buf_t;
circular_buf_t *circular_buf_reset(circular_buf_t *cbuf) {
cbuf->head = cbuf->tail = 0;
cbuf->full = false;
return cbuf;
}
circular_buf_t *circular_buf_init(void *buffer, size_t element_size, size_t element_count) {
if (element_size == 1 || element_size == 2 || element_size == 4) {
circular_buf_t *cbuf = malloc(sizeof(*cbuf));
cbuf->buffer = buffer;
cbuf->element_count = element_count;
cbuf->element_size = (uint8_t)element_size;
return circular_buf_reset(cbuf);
} else {
return NULL;
}
}
bool circular_buf_full(circular_buf_t *me) {
return me->full;
}
bool circular_buf_empty(circular_buf_t *me) {
return me->head == me->tail && !me->full;
}
int circular_buf_advance_head_pointer(circular_buf_t *me) {
if (++me->head == me->element_count)
me->head = 0;
me->full = (me->head == me->tail);
return 0;
}
int circular_buf_advance_tail_pointer(circular_buf_t *me) {
if (++me->tail == me->element_count)
me->tail = 0;
me->full = 0;
return 0;
}
int circular_buf_try_put(circular_buf_t *me, int32_t data) {
if (circular_buf_full(me)) {
return -1;
} else {
switch (me->element_size) {
case 1: ((uint8_t *)me->buffer)[me->head] = (uint8_t)data; break;
case 2: ((uint16_t *)me->buffer)[me->head] = (uint16_t)data; break;
case 4: ((int32_t *)me->buffer)[me->head] = data; break;
}
return circular_buf_advance_head_pointer(me);
}
}
int circular_buf_try_put8(circular_buf_t *me, uint8_t data) {
if (circular_buf_full(me) || me->element_size != sizeof(data)) {
return -1;
} else {
((uint8_t *)me->buffer)[me->head] = data;
return circular_buf_advance_head_pointer(me);
}
}
int circular_buf_try_put16(circular_buf_t *me, uint16_t data) {
if (circular_buf_full(me) || me->element_size != sizeof(data)) {
return -1;
} else {
((uint16_t *)me->buffer)[me->head] = data;
return circular_buf_advance_head_pointer(me);
}
}
int circular_buf_try_put32(circular_buf_t *me, int32_t data) {
if (circular_buf_full(me) || me->element_size != sizeof(data)) {
return -1;
} else {
((int32_t *)me->buffer)[me->head] = data;
return circular_buf_advance_head_pointer(me);
}
}
int32_t circular_buf_get(circular_buf_t *me) {
int32_t res = -1;
if (!circular_buf_empty(me)) {
switch (me->element_size) {
case 1: res = ((uint8_t *)me->buffer)[me->head]; break;
case 2: res = ((uint16_t *)me->buffer)[me->head]; break;
case 4: res = ((int32_t *)me->buffer)[me->head]; break;
}
circular_buf_advance_tail_pointer(me);
}
return res;
}
int32_t circular_buf_try_get8(circular_buf_t *me) {
int32_t res = -1;
if (!circular_buf_empty(me) && me->element_size == 1) {
res = ((uint8_t *)me->buffer)[me->tail];
circular_buf_advance_tail_pointer(me);
}
return res;
}
int32_t circular_buf_try_get16(circular_buf_t *me) {
int32_t res = -1;
if (!circular_buf_empty(me) && me->element_size == 2) {
res = ((uint16_t *)me->buffer)[me->tail];
circular_buf_advance_tail_pointer(me);
}
return res;
}
int32_t circular_buf_try_get32(circular_buf_t *me) {
int32_t res = -1;
if (!circular_buf_empty(me) && me->element_size == 4) {
res = ((int32_t *)me->buffer)[me->tail];
circular_buf_advance_tail_pointer(me);
}
return res;
}