/* Circular buffer, using a counter to distinguish full from empty buffer. */ #include #include #include #include #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(int argc, char *argv[]) { /* 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); }