Implemented queue type
This commit is contained in:
parent
184e7d8514
commit
99f78f16c5
2
Makefile
2
Makefile
|
@ -12,7 +12,7 @@ CPPFLAGS += $(shell pkg-config --cflags $(DEPS))
|
|||
LDLIBS += $(shell pkg-config --libs $(DEPS))
|
||||
INTERP ?=
|
||||
MAIN = main
|
||||
OBJS = main.o events.o processing.o graph.o config.o event_code_names.o hash_table.o module_registry.o event_predicate.o nodes/getchar.o nodes/print.o nodes/evdev.o nodes/tee.o nodes/router.o nodes/modifiers.o nodes/modify_predicate.o nodes/uinput.o nodes/assign.o nodes/differentiate.o nodes/scale.o
|
||||
OBJS = main.o events.o processing.o graph.o config.o event_code_names.o hash_table.o queue.o module_registry.o event_predicate.o nodes/getchar.o nodes/print.o nodes/evdev.o nodes/tee.o nodes/router.o nodes/modifiers.o nodes/modify_predicate.o nodes/uinput.o nodes/assign.o nodes/differentiate.o nodes/scale.o
|
||||
|
||||
all: $(MAIN)
|
||||
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "queue.h"
|
||||
|
||||
void
|
||||
queue_deinit_with_destructor(Queue * q, void (*value_destructor)(QueueValue value, void * destructor_closure), void * destructor_closure)
|
||||
{
|
||||
if (q->values) {
|
||||
if (value_destructor) {
|
||||
QUEUE_FOREACH_INDEX(i, q) {
|
||||
value_destructor(q->values[i], destructor_closure);
|
||||
}
|
||||
}
|
||||
free(q->values);
|
||||
q->values = NULL;
|
||||
}
|
||||
q->capacity = 0;
|
||||
q->after_tail_idx = 0;
|
||||
q->head_idx = 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
queue_grow(Queue * queue)
|
||||
{
|
||||
size_t old_capacity = queue->capacity;
|
||||
size_t new_capacity = old_capacity + (old_capacity >> 1) + 2;
|
||||
QueueValue *values = queue->values;
|
||||
if (values) {
|
||||
values = T_REALLOC(values, new_capacity, QueueValue);
|
||||
if (!values) {
|
||||
return false;
|
||||
}
|
||||
if (queue->head_idx > queue->after_tail_idx) {
|
||||
size_t old_head_idx = queue->head_idx;
|
||||
size_t head_shift = new_capacity - old_capacity;
|
||||
size_t shifted_count = old_capacity - old_head_idx;
|
||||
QueueValue *old_head_ptr = &values[old_head_idx];
|
||||
memmove(old_head_ptr + head_shift, old_head_ptr, shifted_count * sizeof(QueueValue));
|
||||
queue->head_idx = old_head_idx + head_shift;
|
||||
}
|
||||
} else {
|
||||
values = T_ALLOC(new_capacity, QueueValue);
|
||||
if (!values) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
queue->values = values;
|
||||
queue->capacity = new_capacity;
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t
|
||||
queue_put(Queue * queue, QueueValue value)
|
||||
{
|
||||
if (queue_is_full(queue)) {
|
||||
if (!queue_grow(queue)) {
|
||||
return -1;
|
||||
}
|
||||
assert(!queue_is_full(queue));
|
||||
}
|
||||
size_t capacity = queue->capacity;
|
||||
assert(capacity > 0);
|
||||
size_t index = queue->after_tail_idx;
|
||||
queue->values[index] = value;
|
||||
queue->after_tail_idx = (index + 1) % capacity;
|
||||
return index;
|
||||
}
|
||||
|
||||
bool
|
||||
queue_try_pop(Queue * queue, QueueValue * ret)
|
||||
{
|
||||
if (!queue_try_peek(queue, ret)) {
|
||||
return false;
|
||||
}
|
||||
queue->head_idx = (queue->head_idx + 1) % queue->capacity;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
queue_try_peek(const Queue * queue, QueueValue * ret)
|
||||
{
|
||||
if (queue_is_empty(queue)) {
|
||||
return false;
|
||||
}
|
||||
assert(queue->capacity > 0);
|
||||
if (ret) {
|
||||
*ret = queue->values[queue->head_idx];
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
#ifndef QUEUE_H_
|
||||
#define QUEUE_H_
|
||||
|
||||
#include "defs.h"
|
||||
|
||||
typedef union {
|
||||
void *as_ptr;
|
||||
intptr_t as_intptr_t;
|
||||
intptr_t as_signed;
|
||||
uintptr_t as_uintptr_t;
|
||||
uintptr_t as_unsigned;
|
||||
uint8_t as_bytes[sizeof(void*)];
|
||||
} QueueValue;
|
||||
|
||||
#define ZERO_QUEUE_VALUE ((QueueValue) {.as_ptr = NULL})
|
||||
|
||||
typedef struct {
|
||||
// Always keep one unused slot to distinguish empty and full queue
|
||||
size_t capacity;
|
||||
size_t after_tail_idx;
|
||||
size_t head_idx;
|
||||
QueueValue *values;
|
||||
} Queue;
|
||||
|
||||
#define EMPTY_QUEUE ((Queue) {.capacity = 0, .after_tail_idx = 0, .head_idx = 0, .values = NULL})
|
||||
|
||||
void queue_deinit_with_destructor(Queue * queue, void (*value_destructor)(QueueValue value, void * destructor_closure), void * destructor_closure);
|
||||
ssize_t queue_put(Queue * queue, QueueValue value);
|
||||
bool queue_try_pop(Queue * queue, QueueValue * ret);
|
||||
bool queue_try_peek(const Queue * queue, QueueValue * ret);
|
||||
|
||||
__attribute__((unused)) inline static size_t
|
||||
queue_length(const Queue * queue)
|
||||
{
|
||||
ssize_t n = queue->after_tail_idx - queue->head_idx;
|
||||
if (n < 0) {
|
||||
n += queue->capacity;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
__attribute__((unused)) inline static bool
|
||||
queue_is_empty(const Queue * queue)
|
||||
{
|
||||
return queue->head_idx == queue->after_tail_idx;
|
||||
}
|
||||
|
||||
__attribute__((unused)) inline static bool
|
||||
queue_is_full(const Queue * queue)
|
||||
{
|
||||
size_t capacity = queue->capacity;
|
||||
if (!capacity) {
|
||||
return true;
|
||||
}
|
||||
return (queue->after_tail_idx + 1) % capacity == queue->head_idx;
|
||||
}
|
||||
|
||||
__attribute__((unused)) inline static void
|
||||
queue_deinit(Queue * queue)
|
||||
{
|
||||
queue_deinit_with_destructor(queue, NULL, NULL);
|
||||
}
|
||||
|
||||
__attribute__((unused)) inline static QueueValue
|
||||
queue_pop(Queue * queue)
|
||||
{
|
||||
QueueValue value = ZERO_QUEUE_VALUE;
|
||||
queue_try_pop(queue, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
__attribute__((unused)) inline static QueueValue
|
||||
queue_peek(const Queue * queue)
|
||||
{
|
||||
QueueValue value = ZERO_QUEUE_VALUE;
|
||||
queue_try_peek(queue, &value);
|
||||
return value;
|
||||
}
|
||||
|
||||
// As long as head and tail indices are correct, division by zero should not happen
|
||||
#define QUEUE_FOREACH_INDEX(i, q) for (size_t i = (q)->head_idx; i != (q)->after_tail_idx; i = (i + 1) % (q)->capacity)
|
||||
|
||||
#endif /* end of include guard: QUEUE_H_ */
|
Loading…
Reference in New Issue