2020-01-29 14:45:48 +01:00
|
|
|
#ifndef RINGBUFFER_C
|
|
|
|
#define RINGBUFFER_C
|
|
|
|
|
2020-02-01 22:47:51 +01:00
|
|
|
#include "ringbuffer.h"
|
2020-01-31 06:20:56 +01:00
|
|
|
#include "../memory.c"
|
2020-01-29 14:45:48 +01:00
|
|
|
|
2020-02-01 23:13:50 +01:00
|
|
|
#define ERROR(msg) \
|
|
|
|
do { \
|
|
|
|
/* TODO Do something error-ish */ \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
#define ASSERT_NONNULL_ARG(argument) { \
|
|
|
|
if (argument == NULL) { \
|
|
|
|
ERROR(__func__ " got NULL for argument '" #argument "'"); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct ringbuffer* rbfr_create(const int capacity, void (*const destroy_element)(void*)) {
|
|
|
|
ASSERT_NONNULL_ARG(destroy_element);
|
|
|
|
|
2020-01-29 14:45:48 +01:00
|
|
|
struct ringbuffer* const this = alloc(sizeof (struct ringbuffer));
|
|
|
|
|
|
|
|
this->buffer = alloc(capacity * sizeof (void*));
|
|
|
|
this->buffer_n = capacity;
|
2020-02-01 22:47:51 +01:00
|
|
|
this->size = 0;
|
|
|
|
this->head = 0;
|
|
|
|
|
|
|
|
this->destroy_element = destroy_element;
|
2020-01-29 14:45:48 +01:00
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2020-02-01 23:13:50 +01:00
|
|
|
void rbfr_destroy(struct ringbuffer* const this) {
|
|
|
|
ASSERT_NONNULL_ARG(this);
|
|
|
|
|
2020-02-01 22:47:51 +01:00
|
|
|
rbfr_clear(this);
|
2020-02-01 23:13:50 +01:00
|
|
|
|
2020-01-29 14:45:48 +01:00
|
|
|
free(this->buffer);
|
2020-02-01 23:13:50 +01:00
|
|
|
this->buffer = NULL;
|
|
|
|
|
2020-01-29 14:45:48 +01:00
|
|
|
free(this);
|
|
|
|
}
|
|
|
|
|
2020-02-01 23:13:50 +01:00
|
|
|
int rbfr_size(const struct ringbuffer* const this) {
|
|
|
|
ASSERT_NONNULL_ARG(this);
|
|
|
|
|
2020-01-29 14:45:48 +01:00
|
|
|
return this->size;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rbfr_capacity(const struct ringbuffer* this) {
|
2020-02-01 23:13:50 +01:00
|
|
|
ASSERT_NONNULL_ARG(this);
|
2020-01-29 14:45:48 +01:00
|
|
|
return this->buffer_n;
|
|
|
|
}
|
|
|
|
|
2020-02-01 23:13:50 +01:00
|
|
|
void rbfr_enqueue(struct ringbuffer* this, void* const element) {
|
|
|
|
ASSERT_NONNULL_ARG(this);
|
|
|
|
|
2020-01-29 14:45:48 +01:00
|
|
|
if (this->buffer_n == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int index = this->head + this->size;
|
|
|
|
if (index >= this->buffer_n) {
|
|
|
|
index -= this->buffer_n;
|
|
|
|
}
|
|
|
|
this->buffer[index] = element;
|
|
|
|
if (this->size < this->buffer_n) {
|
|
|
|
this->size++;
|
|
|
|
} else {
|
|
|
|
this->head++;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-02-01 23:13:50 +01:00
|
|
|
bool rbfr_peek(const struct ringbuffer *const this, void** element) {
|
|
|
|
ASSERT_NONNULL_ARG(this);
|
|
|
|
ASSERT_NONNULL_ARG(element);
|
|
|
|
|
2020-01-29 14:45:48 +01:00
|
|
|
if (this->size == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
*element = this->buffer[this->head];
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-02-01 23:13:50 +01:00
|
|
|
bool rbfr_dequeue(struct ringbuffer *const this, void** element) {
|
|
|
|
ASSERT_NONNULL_ARG(this);
|
|
|
|
ASSERT_NONNULL_ARG(element);
|
|
|
|
|
2020-01-29 14:45:48 +01:00
|
|
|
if (!rbfr_peek(this, element)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
this->size--;
|
|
|
|
this->head++;
|
|
|
|
if (this->head >= this->buffer_n) {
|
|
|
|
this->head = 0;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-02-01 22:47:51 +01:00
|
|
|
void rbfr_clear(struct ringbuffer* this) {
|
2020-02-01 23:13:50 +01:00
|
|
|
ASSERT_NONNULL_ARG(this);
|
|
|
|
|
2020-02-01 22:47:51 +01:00
|
|
|
void* element;
|
|
|
|
while (rbfr_dequeue(this, &element)) {
|
|
|
|
this->destroy_element(element);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-29 14:45:48 +01:00
|
|
|
#endif // RINGBUFFER_C
|