diff --git a/sandbox/base/main.c b/sandbox/base/main.c index 30d03f2..9b57f35 100644 --- a/sandbox/base/main.c +++ b/sandbox/base/main.c @@ -12,8 +12,10 @@ extern int memory_test(void); extern int btree_test(void); +extern int queue_test(void); int main(int argc, const char **argv) { - btree_test(); + queue_test(); + return 0; } diff --git a/sandbox/base/queue_test.c b/sandbox/base/queue_test.c new file mode 100644 index 0000000..6543be5 --- /dev/null +++ b/sandbox/base/queue_test.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NR_QUEUE_ITEMS 32 + +struct q_item { + queue_entry_t base; + unsigned int key; +}; + +static struct q_item *find(queue_t *q, unsigned int key) +{ + queue_foreach (struct q_item, item, q, base) { + if (item->key == key) { + return item; + } + } + + return NULL; +} + +int queue_test(void) +{ + queue_t q = {}; + struct q_item *items = calloc(NR_QUEUE_ITEMS, sizeof *items); + + for (int i = 0; i < NR_QUEUE_ITEMS; i++) { + items[i].key = i; + printf(" - item %d: %u\n", i, items[i].key); + } + + for (int i = 0; i < NR_QUEUE_ITEMS; i++) { + printf("#######################\n"); + printf("inserting items #%d: %u\n", i, items[i].key); + + queue_push_back(&q, &items[i].base); + printf("#######################\n"); + + for (int ii = 0; ii < NR_QUEUE_ITEMS; ii++) { + struct q_item *n = find(&q, items[ii].key); + + if (ii <= i) { + assert(n && n->key == items[ii].key); + } else { + assert(!n); + } + } + } + + printf("in-order traversal:\n"); + queue_foreach (struct q_item, item, &q, base) { + printf(" - %u\n", item->key); + } + + printf("reverse-order traversal:\n"); + queue_foreach_r (struct q_item, item, &q, base) { + printf(" - %u\n", item->key); + } + + for (int i = 0; i < NR_QUEUE_ITEMS; i++) { + printf("#######################\n"); + printf("deleting node #%d: %u\n", i, items[i].key); + printf("#######################\n"); + + queue_delete(&q, &items[i].base); + + for (int ii = 0; ii < NR_QUEUE_ITEMS; ii++) { + struct q_item *n = find(&q, items[ii].key); + + if (ii <= i) { + assert(!n); + } else { + assert(n && n->key == items[ii].key); + } + } + } + + free(items); + return 0; +} diff --git a/sandbox/queue/include/socks/queue.h b/sandbox/queue/include/socks/queue.h index e887ebc..713b444 100644 --- a/sandbox/queue/include/socks/queue.h +++ b/sandbox/queue/include/socks/queue.h @@ -1,14 +1,48 @@ #ifndef SOCKS_QUEUE_H_ #define SOCKS_QUEUE_H_ +#include + +#define QUEUE_CONTAINER(t, m, v) ((void *)((v) ? (uintptr_t)(v) - (offsetof(t, m)) : 0)) + +#define queue_foreach(iter_type, iter_name, queue_name, node_member) \ + for (iter_type *iter_name = QUEUE_CONTAINER(iter_type, node_member, queue_first(queue_name)); \ + iter_name; \ + iter_name = QUEUE_CONTAINER(iter_type, node_member, queue_next(&((iter_name)->node_member)))) + +#define queue_foreach_r(iter_type, iter_name, queue_name, node_member) \ + for (iter_type *iter_name = QUEUE_CONTAINER(iter_type, node_member, queue_last(queue_name)); \ + iter_name; \ + iter_name = QUEUE_CONTAINER(iter_type, node_member, queue_prev(&((iter_name)->node_member)))) + typedef struct queue_entry { - struct queue_entry *q_next; - struct queue_entry *q_prev; + struct queue_entry *qe_next; + struct queue_entry *qe_prev; } queue_entry_t; typedef struct queue { queue_entry_t *q_first; queue_entry_t *q_last; + unsigned int q_length; } queue_t; +static inline void queue_init(queue_t *q) { memset(q, 0x00, sizeof *q); } +static inline unsigned int queue_length(queue_t *q) { return q->q_length; } + +static inline queue_entry_t *queue_first(queue_t *q) { return q->q_first; } +static inline queue_entry_t *queue_last(queue_t *q) { return q->q_last; } +static inline queue_entry_t *queue_next(queue_entry_t *entry) { return entry->qe_next; } +static inline queue_entry_t *queue_prev(queue_entry_t *entry) { return entry->qe_prev; } + +extern void queue_insert_before(queue_t *q, queue_entry_t *entry, queue_entry_t *before); +extern void queue_insert_after(queue_t *q, queue_entry_t *entry, queue_entry_t *after); + +extern void queue_push_front(queue_t *q, queue_entry_t *entry); +extern void queue_push_back(queue_t *q, queue_entry_t *entry); + +extern queue_entry_t *queue_pop_front(queue_t *q); +extern queue_entry_t *queue_pop_back(queue_t *q); + +extern void queue_delete(queue_t *q, queue_entry_t *entry); + #endif diff --git a/sandbox/queue/queue.c b/sandbox/queue/queue.c index e69de29..1229da8 100644 --- a/sandbox/queue/queue.c +++ b/sandbox/queue/queue.c @@ -0,0 +1,104 @@ +#include + +void queue_insert_before(queue_t *q, queue_entry_t *entry, queue_entry_t *before) +{ + queue_entry_t *x = before->qe_prev; + if (x) { + x->qe_next = entry; + } else { + q->q_first = entry; + } + + entry->qe_prev = x; + + before->qe_prev = entry; + entry->qe_next = before; +} + +void queue_insert_after(queue_t *q, queue_entry_t *entry, queue_entry_t *after) +{ + queue_entry_t *x = after->qe_next; + if (x) { + x->qe_prev = entry; + } else { + q->q_last = entry; + } + + entry->qe_prev = x; + + after->qe_next = entry; + entry->qe_prev = after; + q->q_length++; +} + +void queue_push_front(queue_t *q, queue_entry_t *entry) +{ + if (q->q_first) { + q->q_first->qe_prev = entry; + } + + entry->qe_next = q->q_first; + entry->qe_prev = NULL; + + q->q_first = entry; + + if (!q->q_last) { + q->q_last = entry; + } + + q->q_length++; +} + +void queue_push_back(queue_t *q, queue_entry_t *entry) +{ + if (q->q_last) { + q->q_last->qe_next = entry; + } + + entry->qe_prev = q->q_last; + entry->qe_next = NULL; + + q->q_last = entry; + + if (!q->q_first) { + q->q_first = entry; + } + + q->q_length++; +} + +queue_entry_t *queue_pop_front(queue_t *q) +{ + queue_entry_t *x = q->q_first; + queue_delete(q, x); + return x; +} + +queue_entry_t *queue_pop_back(queue_t *q) +{ + queue_entry_t *x = q->q_last; + queue_delete(q, x); + return x; +} + +void queue_delete(queue_t *q, queue_entry_t *entry) +{ + if (entry == q->q_first) { + q->q_first = q->q_first->qe_next; + } + + if (entry == q->q_last) { + q->q_last = q->q_last->qe_prev; + } + + if (entry->qe_next) { + entry->qe_next->qe_prev = entry->qe_prev; + } + + if (entry->qe_prev) { + entry->qe_prev->qe_next = entry->qe_next; + } + + entry->qe_next = entry->qe_prev = NULL; + q->q_length--; +}