You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

179 lines
3.6 KiB
C

/* 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);
}