|
|
|
/* Circular buffer, using a counter to distinguish full from empty buffer. */
|
|
|
|
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#define DEBUG 0
|
|
|
|
#define debug_printf(fmt, ...) \
|
|
|
|
do { if (DEBUG) fprintf(stderr, fmt, __VA_ARGS__); } while (0)
|
|
|
|
|
|
|
|
#define CB_SIZE 42
|
|
|
|
|
|
|
|
/* Types */
|
|
|
|
|
|
|
|
struct elem {
|
|
|
|
int foo;
|
|
|
|
};
|
|
|
|
typedef struct elem elem_t;
|
|
|
|
|
|
|
|
struct cb {
|
|
|
|
int count;
|
|
|
|
int size;
|
|
|
|
int start;
|
|
|
|
int end;
|
|
|
|
|
|
|
|
elem_t *elems;
|
|
|
|
};
|
|
|
|
typedef struct cb cb_t;
|
|
|
|
|
|
|
|
|
|
|
|
/* Helpers */
|
|
|
|
|
|
|
|
void dienomem() {
|
|
|
|
fprintf(stderr, "ERROR: No memory?!\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Operations */
|
|
|
|
|
|
|
|
void cb_init(cb_t * cb, int size) {
|
|
|
|
cb->count = 0;
|
|
|
|
cb->size = size;
|
|
|
|
|
|
|
|
cb->start = 0;
|
|
|
|
|
|
|
|
cb->elems = malloc(sizeof(elem_t) * size);
|
|
|
|
if (!cb->elems)
|
|
|
|
dienomem();
|
|
|
|
}
|
|
|
|
|
|
|
|
void cb_free(cb_t * cb) {
|
|
|
|
free(cb->elems);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cb_is_full(cb_t * cb) {
|
|
|
|
return (cb->count == cb->size);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cb_is_empty(cb_t * cb) {
|
|
|
|
return (cb->count == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int cb_count(cb_t * cb) {
|
|
|
|
return cb->count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cb_write(cb_t * cb, elem_t * elem) {
|
|
|
|
int end = (cb->start + cb->count) % cb->size;
|
|
|
|
cb->elems[end] = *elem;
|
|
|
|
|
|
|
|
if (cb_is_full(cb))
|
|
|
|
/* We have just overwritten the first element of the buffer,
|
|
|
|
* therefore move the start. */
|
|
|
|
cb->start = (cb->start + 1) % cb->size;
|
|
|
|
else
|
|
|
|
cb->count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cb_read(cb_t * cb, elem_t * elem) {
|
|
|
|
if (!cb_is_empty(cb)) {
|
|
|
|
*elem = cb->elems[cb->start];
|
|
|
|
cb->start = (cb->start + 1) % cb->size;
|
|
|
|
cb->count--;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test it. */
|
|
|
|
|
|
|
|
int main(void) {
|
|
|
|
/* Initialize empty CB_SIZE-element circular buffer. */
|
|
|
|
cb_t *test_cb = malloc(sizeof(cb_t));
|
|
|
|
if (!test_cb)
|
|
|
|
dienomem();
|
|
|
|
cb_init(test_cb, CB_SIZE);
|
|
|
|
|
|
|
|
/* Should be empty. */
|
|
|
|
assert(cb_is_empty(test_cb) == true);
|
|
|
|
assert(cb_is_full(test_cb) == false);
|
|
|
|
|
|
|
|
/* Add one element. */
|
|
|
|
elem_t *one = malloc(sizeof(elem_t));
|
|
|
|
if (!one)
|
|
|
|
dienomem();
|
|
|
|
one->foo = 23;
|
|
|
|
cb_write(test_cb, one);
|
|
|
|
free(one);
|
|
|
|
assert(cb_is_empty(test_cb) == false);
|
|
|
|
|
|
|
|
/* Read the one element. */
|
|
|
|
elem_t *oneback = malloc(sizeof(elem_t));
|
|
|
|
if (!oneback)
|
|
|
|
dienomem();
|
|
|
|
cb_read(test_cb, oneback);
|
|
|
|
assert(oneback->foo == 23);
|
|
|
|
free(oneback);
|
|
|
|
assert(cb_is_empty(test_cb) == true);
|
|
|
|
|
|
|
|
/* Fill the buffer. */
|
|
|
|
elem_t *e = malloc(sizeof(elem_t));
|
|
|
|
if (!e)
|
|
|
|
dienomem();
|
|
|
|
for (int i = 1; i <= CB_SIZE; i++) {
|
|
|
|
e->foo = i;
|
|
|
|
cb_write(test_cb, e);
|
|
|
|
}
|
|
|
|
assert(cb_is_empty(test_cb) == false);
|
|
|
|
assert(cb_is_full(test_cb) == true);
|
|
|
|
assert(cb_count(test_cb) == CB_SIZE);
|
|
|
|
|
|
|
|
/* Add another element. */
|
|
|
|
e->foo = CB_SIZE + 1;
|
|
|
|
cb_write(test_cb, e);
|
|
|
|
assert(cb_is_empty(test_cb) == false);
|
|
|
|
assert(cb_is_full(test_cb) == true);
|
|
|
|
assert(cb_count(test_cb) == CB_SIZE);
|
|
|
|
|
|
|
|
/* Read all elements and check their values. */
|
|
|
|
for (int i = 2; i <= CB_SIZE + 1; i++) {
|
|
|
|
bool rc = cb_read(test_cb, e);
|
|
|
|
assert(rc == true);
|
|
|
|
debug_printf("e->foo == %d\n", e->foo);
|
|
|
|
assert(e->foo == i);
|
|
|
|
}
|
|
|
|
assert(cb_is_empty(test_cb) == true);
|
|
|
|
|
|
|
|
/* Should not be possible to read a value now. */
|
|
|
|
bool rc = cb_read(test_cb, e);
|
|
|
|
assert(rc == false);
|
|
|
|
assert(cb_is_empty(test_cb) == true);
|
|
|
|
assert(cb_count(test_cb) == 0);
|
|
|
|
|
|
|
|
/* Fill the buffer - twice. */
|
|
|
|
for (int i = 1; i <= CB_SIZE * 2; i++) {
|
|
|
|
e->foo = i;
|
|
|
|
cb_write(test_cb, e);
|
|
|
|
}
|
|
|
|
assert(cb_is_empty(test_cb) == false);
|
|
|
|
assert(cb_is_full(test_cb) == true);
|
|
|
|
assert(cb_count(test_cb) == CB_SIZE);
|
|
|
|
|
|
|
|
/* Read all elements and check their values. */
|
|
|
|
for (int i = CB_SIZE + 1; i <= CB_SIZE * 2; i++) {
|
|
|
|
bool rc = cb_read(test_cb, e);
|
|
|
|
assert(rc == true);
|
|
|
|
assert(e->foo == i);
|
|
|
|
}
|
|
|
|
assert(cb_is_empty(test_cb) == true);
|
|
|
|
|
|
|
|
/* Free buffer etc. */
|
|
|
|
free(e);
|
|
|
|
cb_free(test_cb);
|
|
|
|
free(test_cb);
|
|
|
|
}
|