Add generic circular buffer
Add a circular buffer implementation, to factorize multiple specific queues implementation.
This commit is contained in:
parent
7475550ae8
commit
b38292cd69
3 changed files with 126 additions and 0 deletions
|
@ -154,6 +154,9 @@ executable('scrcpy', src,
|
||||||
### TESTS
|
### TESTS
|
||||||
|
|
||||||
tests = [
|
tests = [
|
||||||
|
['test_cbuf', [
|
||||||
|
'tests/test_cbuf.c',
|
||||||
|
]],
|
||||||
['test_control_event_queue', [
|
['test_control_event_queue', [
|
||||||
'tests/test_control_event_queue.c',
|
'tests/test_control_event_queue.c',
|
||||||
'src/control_event.c'
|
'src/control_event.c'
|
||||||
|
|
50
app/src/cbuf.h
Normal file
50
app/src/cbuf.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
// generic circular buffer (bounded queue) implementation
|
||||||
|
#ifndef CBUF_H
|
||||||
|
#define CBUF_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// To define a circular buffer type of 20 ints:
|
||||||
|
// typedef CBUF(int, 20) my_cbuf_t;
|
||||||
|
//
|
||||||
|
// data has length CAP + 1 to distinguish empty vs full.
|
||||||
|
#define CBUF(TYPE, CAP) { \
|
||||||
|
TYPE data[(CAP) + 1]; \
|
||||||
|
size_t head; \
|
||||||
|
size_t tail; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define cbuf_size_(PCBUF) \
|
||||||
|
(sizeof((PCBUF)->data) / sizeof(*(PCBUF)->data))
|
||||||
|
|
||||||
|
#define cbuf_is_empty(PCBUF) \
|
||||||
|
((PCBUF)->head == (PCBUF)->tail)
|
||||||
|
|
||||||
|
#define cbuf_is_full(PCBUF) \
|
||||||
|
(((PCBUF)->head + 1) % cbuf_size_(PCBUF) == (PCBUF)->tail)
|
||||||
|
|
||||||
|
#define cbuf_init(PCBUF) \
|
||||||
|
(void) ((PCBUF)->head = (PCBUF)->tail = 0)
|
||||||
|
|
||||||
|
#define cbuf_push(PCBUF, ITEM) \
|
||||||
|
({ \
|
||||||
|
bool ok = !cbuf_is_full(PCBUF); \
|
||||||
|
if (ok) { \
|
||||||
|
(PCBUF)->data[(PCBUF)->head] = (ITEM); \
|
||||||
|
(PCBUF)->head = ((PCBUF)->head + 1) % cbuf_size_(PCBUF); \
|
||||||
|
} \
|
||||||
|
ok; \
|
||||||
|
}) \
|
||||||
|
|
||||||
|
#define cbuf_take(PCBUF, PITEM) \
|
||||||
|
({ \
|
||||||
|
bool ok = !cbuf_is_empty(PCBUF); \
|
||||||
|
if (ok) { \
|
||||||
|
*(PITEM) = (PCBUF)->data[(PCBUF)->tail]; \
|
||||||
|
(PCBUF)->tail = ((PCBUF)->tail + 1) % cbuf_size_(PCBUF); \
|
||||||
|
} \
|
||||||
|
ok; \
|
||||||
|
})
|
||||||
|
|
||||||
|
#endif
|
73
app/tests/test_cbuf.c
Normal file
73
app/tests/test_cbuf.c
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cbuf.h"
|
||||||
|
|
||||||
|
struct int_queue CBUF(int, 32);
|
||||||
|
|
||||||
|
static void test_cbuf_empty(void) {
|
||||||
|
struct int_queue queue;
|
||||||
|
cbuf_init(&queue);
|
||||||
|
|
||||||
|
assert(cbuf_is_empty(&queue));
|
||||||
|
|
||||||
|
bool push_ok = cbuf_push(&queue, 42);
|
||||||
|
assert(push_ok);
|
||||||
|
assert(!cbuf_is_empty(&queue));
|
||||||
|
|
||||||
|
int item;
|
||||||
|
bool take_ok = cbuf_take(&queue, &item);
|
||||||
|
assert(take_ok);
|
||||||
|
assert(cbuf_is_empty(&queue));
|
||||||
|
|
||||||
|
bool take_empty_ok = cbuf_take(&queue, &item);
|
||||||
|
assert(!take_empty_ok); // the queue is empty
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_cbuf_full(void) {
|
||||||
|
struct int_queue queue;
|
||||||
|
cbuf_init(&queue);
|
||||||
|
|
||||||
|
assert(!cbuf_is_full(&queue));
|
||||||
|
|
||||||
|
// fill the queue
|
||||||
|
for (int i = 0; i < 32; ++i) {
|
||||||
|
bool ok = cbuf_push(&queue, i);
|
||||||
|
assert(ok);
|
||||||
|
}
|
||||||
|
bool ok = cbuf_push(&queue, 42);
|
||||||
|
assert(!ok); // the queue if full
|
||||||
|
|
||||||
|
int item;
|
||||||
|
bool take_ok = cbuf_take(&queue, &item);
|
||||||
|
assert(take_ok);
|
||||||
|
assert(!cbuf_is_full(&queue));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_cbuf_push_take(void) {
|
||||||
|
struct int_queue queue;
|
||||||
|
cbuf_init(&queue);
|
||||||
|
|
||||||
|
bool push1_ok = cbuf_push(&queue, 42);
|
||||||
|
assert(push1_ok);
|
||||||
|
|
||||||
|
bool push2_ok = cbuf_push(&queue, 35);
|
||||||
|
assert(push2_ok);
|
||||||
|
|
||||||
|
int item;
|
||||||
|
|
||||||
|
bool take1_ok = cbuf_take(&queue, &item);
|
||||||
|
assert(take1_ok);
|
||||||
|
assert(item == 42);
|
||||||
|
|
||||||
|
bool take2_ok = cbuf_take(&queue, &item);
|
||||||
|
assert(take2_ok);
|
||||||
|
assert(item == 35);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
test_cbuf_empty();
|
||||||
|
test_cbuf_full();
|
||||||
|
test_cbuf_push_take();
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue