From bfabb435e5c5bf313005c4636747fce59eb4ca6f Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Mon, 12 Jun 2023 08:52:15 -0700 Subject: Add list library. --- list/include/list.h | 118 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 104 insertions(+), 14 deletions(-) (limited to 'list/include') diff --git a/list/include/list.h b/list/include/list.h index 945de28..facf820 100644 --- a/list/include/list.h +++ b/list/include/list.h @@ -1,21 +1,111 @@ -/// A doubly linked list. -/// -/// This list does not hold user data. Instead, the list can be used as an -/// intrusive list or as part as a more complex data structure. +/// Doubly-linked list. #pragma once +#include #include +#include + +#define DEF_LIST(type) \ + typedef struct type##_node { \ + type val; \ + struct type##_node* prev; \ + struct type##_node* next; \ + } type##_node; \ + typedef struct type##_list { \ + type##_node* head; \ + } type##_list; + +static inline void* alloc(size_t size) { + void* ptr = calloc(1, size); + assert(ptr); + return ptr; +} + +/// Create a new empty list. +#define make_list(type) \ + (type##_list) { 0 } + +/// Delete the list. +#define del_list(list) \ + for (__typeof__(list.head) node = list.head; node;) { \ + __typeof__(node) cur = node; \ + node = node->next; \ + free(cur); \ + } \ + list.head = 0; -typedef struct list list; +/// Prepend a value to the list. +#define list_push(list, value) \ + { \ + __typeof__(list.head) node = alloc(sizeof(*list.head)); \ + node->val = value; \ + node->next = list.head; \ + if (list.head) { \ + list.head->prev = node; \ + } \ + list.head = node; \ + } -typedef struct list { - list* prev; - list* next; -} list; +/// Delete the first occurrence of the value from the list. +#define list_remove(list, search_value) \ + for (__typeof__(list.head) iter = list.head; iter; iter = iter->next) { \ + if (iter->val == (search_value)) { \ + del_node(list, iter); \ + break; \ + } \ + } -/// Create a new list from an array of `size` items. -void list_make(list* list, size_t size); +/// Delete the node that contains the value at the given address from the +/// list. +#define list_remove_ptr(list, value_ptr) \ + for (__typeof__(list.head) iter = list.head; iter; iter = iter->next) { \ + if (&iter->val == value_ptr) { \ + del_node(list, iter); \ + break; \ + } \ + } -/// Iterates over all the items in the list. -#define list_foreach(LIST, iter) \ - for (struct list* iter = LIST; iter; iter = iter->next) +/// Delete the list node. +#define del_node(list, node) \ + { \ + assert(node); \ + if (node->prev) { \ + node->prev->next = node->next; \ + } \ + if (node->next) { \ + node->next->prev = node->prev; \ + } \ + if (list.head == node) { \ + list.head = 0; \ + } \ + free(node); \ + node = 0; \ + } + +/// Iterate over all the items in the list. +/// +/// Use 'value' to refer to the address of the current node's value during +/// iteration. +#define list_foreach(list, body) \ + { \ + __typeof__(list.head) node = list.head; \ + while (node) { \ + const __typeof__(node->val)* value = &node->val; \ + body; \ + node = node->next; \ + } \ + } + +/// Iterate over all the items in the list. +/// +/// Use 'value' to refer to the address of the current node's value during +/// iteration. +#define list_foreach_mut(list, body) \ + { \ + __typeof__(list.head) node = list.head; \ + while (node) { \ + __typeof__(node->val)* value = &node->val; \ + body; \ + node = node->next; \ + } \ + } -- cgit v1.2.3