Ringbuffer: introduce destroy_element
This commit is contained in:
parent
bda7eda76a
commit
269a45839c
2 changed files with 94 additions and 20 deletions
|
@ -1,37 +1,24 @@
|
||||||
#ifndef RINGBUFFER_C
|
#ifndef RINGBUFFER_C
|
||||||
#define RINGBUFFER_C
|
#define RINGBUFFER_C
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include "ringbuffer.h"
|
||||||
#include "../memory.c"
|
#include "../memory.c"
|
||||||
|
|
||||||
/*
|
struct ringbuffer* rbfr_create(const int capacity, void (*destroy_element)(void*)) {
|
||||||
* Data layout: ↓head
|
|
||||||
* [ 4, undef, undef, 1, 2, 3 ] (1 is first added etc.)
|
|
||||||
* So enqueue adds after 4 and dequeue removes 1.
|
|
||||||
*/
|
|
||||||
struct ringbuffer {
|
|
||||||
int head;
|
|
||||||
int size;
|
|
||||||
void** buffer;
|
|
||||||
int buffer_n;
|
|
||||||
};
|
|
||||||
|
|
||||||
void rbfr_clear(struct ringbuffer* this) {
|
|
||||||
this->size = 0;
|
|
||||||
this->head = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ringbuffer* rbfr_create(const int capacity) {
|
|
||||||
struct ringbuffer* const this = alloc(sizeof (struct ringbuffer));
|
struct ringbuffer* const this = alloc(sizeof (struct ringbuffer));
|
||||||
|
|
||||||
this->buffer = alloc(capacity * sizeof (void*));
|
this->buffer = alloc(capacity * sizeof (void*));
|
||||||
this->buffer_n = capacity;
|
this->buffer_n = capacity;
|
||||||
rbfr_clear(this);
|
this->size = 0;
|
||||||
|
this->head = 0;
|
||||||
|
|
||||||
|
this->destroy_element = destroy_element;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rbfr_destroy(struct ringbuffer* this) {
|
void rbfr_destroy(struct ringbuffer* this) {
|
||||||
|
rbfr_clear(this);
|
||||||
free(this->buffer);
|
free(this->buffer);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
@ -82,4 +69,11 @@ bool rbfr_dequeue(struct ringbuffer* this, void** element) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rbfr_clear(struct ringbuffer* this) {
|
||||||
|
void* element;
|
||||||
|
while (rbfr_dequeue(this, &element)) {
|
||||||
|
this->destroy_element(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif // RINGBUFFER_C
|
#endif // RINGBUFFER_C
|
||||||
|
|
80
kernel/util/ringbuffer.h
Normal file
80
kernel/util/ringbuffer.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
#ifndef RINGBUFFER_H
|
||||||
|
#define RINGBUFFER_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
// Data layout: ↓head
|
||||||
|
// buffer = [ 4, undef, undef, 1, 2, 3 ]
|
||||||
|
// where 1 is the oldest element and 4 the newest.
|
||||||
|
// Enqueue adds the element after 4 and dequeue removes 1.
|
||||||
|
struct ringbuffer {
|
||||||
|
int head;
|
||||||
|
int size;
|
||||||
|
void (*destroy_element)(void*);
|
||||||
|
int buffer_n;
|
||||||
|
void** buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate memory and initialize a circular queue with given capacity
|
||||||
|
*
|
||||||
|
* A ringbuffer, or circular queue, is like a regular queue, but if it's full when you add an
|
||||||
|
* element, it displaces the oldest element to make place. As such, adding elements never fails.
|
||||||
|
*
|
||||||
|
* Memory: this function allocates memory for the queue (free it with rbfr_destroy). The
|
||||||
|
* destroy_element function user has to provide must free an element's memory.
|
||||||
|
*
|
||||||
|
* @param capacity maximum amount of elements to accept without dropping oldest
|
||||||
|
* @param destroy_element function called when the queue has to drop an element, with the element
|
||||||
|
* passed as argument
|
||||||
|
* @return pointer to ringbuffer
|
||||||
|
*/
|
||||||
|
struct ringbuffer* rbfr_create(const int capacity, void (*destroy_element)(void*));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the queue's memory
|
||||||
|
*
|
||||||
|
* Memory: all elements still present are freed using the destroy_element function provided by user
|
||||||
|
* in rbfr_create.
|
||||||
|
*/
|
||||||
|
void rbfr_destroy(struct ringbuffer* this);
|
||||||
|
|
||||||
|
int rbfr_size(const struct ringbuffer* this);
|
||||||
|
|
||||||
|
int rbfr_capacity(const struct ringbuffer* this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add one element at the end
|
||||||
|
*
|
||||||
|
* If the queue is full (if size==capacity), the oldest element is removed to make place. As such,
|
||||||
|
* this operation does not fail if the queue is full.
|
||||||
|
*
|
||||||
|
* Memory: if an element has to be removed to make place, it is freed using the destroy_element
|
||||||
|
* function provided by user in rbfr_create.
|
||||||
|
*/
|
||||||
|
void rbfr_enqueue(struct ringbuffer* this, void* element);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return first element without removing it from the buffer
|
||||||
|
*
|
||||||
|
* Memory: do not free the element's memory, it still lives in the ringbuffer.
|
||||||
|
*/
|
||||||
|
bool rbfr_peek(const struct ringbuffer* this, void** element);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove first element and return it
|
||||||
|
*
|
||||||
|
* Memory: user is responsible for freeing the element's memory.
|
||||||
|
*/
|
||||||
|
bool rbfr_dequeue(struct ringbuffer* this, void** element);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all elements
|
||||||
|
*
|
||||||
|
* Memory: this function destroys elements using the destroy_element function provided by user in
|
||||||
|
* rbfr_create.
|
||||||
|
*/
|
||||||
|
void rbfr_clear(struct ringbuffer* this);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // RINGBUFFER_H
|
Loading…
Reference in a new issue