From 10186202adda6a4b48c0034def50694a536fe656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 8 Sep 2026 23:45:14 +0200 Subject: [PATCH] Add single/double linked list macros --- src/base_core.h | 168 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 113 ++++++++++++++++++++++++++++++++ 2 files changed, 281 insertions(+) diff --git a/src/base_core.h b/src/base_core.h index 4899410..9b1e962 100644 --- a/src/base_core.h +++ b/src/base_core.h @@ -410,3 +410,171 @@ static INLINE void allocator_free_all(Allocator *allocator) #define ASAN_UNPOISON_MEMORY_REGION(addr, size) \ ((void)(addr), (void)(size)) #endif + + +// linked lists + +/* + SList - singly linked lists + "list" struct must have a "*first" and "**last" member to entrys + "first"/"last" structs must have a "*next" member +*/ + +/** + * Initialize a list + * + * @param list struct pointer with a *first and a **last member to an entry struct + */ +#define SListInit(list) \ +do { \ + (list)->first = NULL; \ + (list)->last = &(list)->first; \ +} while (0) + +/** + * Adds entry to the head of a list + * + * @param list struct pointer with a *first and a **last member to an entry struct + * @param entry struct pointer with a *next member to an entry struct + */ +#define SListAddFirst(list, entry) \ +do { \ + (entry)->next = (list)->first; \ + if ((entry)->next == NULL) { \ + (list)->last = &(entry)->next; \ + } \ + (list)->first = (entry); \ +} while (0) + +/** + * Adds entry to the tail of a list + * + * @param list struct pointer with a *first and a **last member to an entry struct + * @param entry struct pointer with a *next member to an entry struct + */ +#define SListAddLast(list, entry) \ +do { \ + (entry)->next = NULL; \ + *(list)->last = (entry); \ + (list)->last = &(entry)->next; \ +} while (0) + +/** + * Remove head from list, list MUST not be empty + * + * @param entry struct pointer with a *next member to an entry struct + */ +#define SListRemoveFirst(list) \ +do { \ + (list)->first = (list)->first->next; \ + if ((list)->first == NULL) { \ + (list)->last = &(list)->first; \ + } \ +} while (0) + +#define SListIsEmpty(list) ((list)->first == NULL) + +/* + DList - doubly linked lists + "list" struct must have a "*first" and "*last" member to entrys + "first"/"last" structs must have a "*next" and a "*prev" member +*/ + +/** + * Initialize a list + * + * @param list struct pointer with a *first and a *last member to an entry struct + */ +#define DListInit(list) \ +do { \ + (list)->first = NULL; \ + (list)->last = NULL; \ +} while (0) + +/** + * Adds entry to the head of a list + * + * @param list struct pointer with a *first and a *last member to an entry struct + * @param entry struct pointer with a *next and *prev member to an entry struct + */ +#define DListAddFirst(list, entry) \ +do { \ + (entry)->next = (list)->first; \ + (entry)->prev = NULL; \ + if ((list)->first != NULL) { \ + (list)->first->prev = (entry); \ + } else { \ + (list)->last = (entry); \ + } \ + (list)->first = (entry); \ +} while (0) +/** + * Adds entry to the tail of a list + * + * @param list struct pointer with a *first and a *last member to an entry struct + * @param entry struct pointer with a *next and *prev member to an entry struct + */ +#define DListAddLast(list, entry) \ +do { \ + (entry)->prev = (list)->last; \ + (entry)->next = NULL; \ + if ((list)->last != NULL) { \ + (list)->last->next = (entry); \ + } else { \ + (list)->first = (entry); \ + } \ + (list)->last = (entry); \ +} while (0) + +/** + * Remove first entry from list, list MUST not be empty + * + * @param entry struct pointer with a *next and *prev member to an entry struct + */ +#define DListRemoveFirst(list) \ +do { \ + (list)->first = (list)->first->next; \ + if ((list)->first != NULL) { \ + (list)->first->prev = NULL; \ + } else { \ + (list)->last = NULL; \ + } \ +} while (0) + +/** + * Remove last entry from list, list MUST not be empty + * + * @param entry struct pointer with a *next and *prev member to an entry struct + */ +#define DListRemoveLast(list) \ +do { \ + (list)->last = (list)->last->prev; \ + if ((list)->last != NULL) { \ + (list)->last->next = NULL; \ + } else { \ + (list)->first = NULL; \ + } \ +} while (0) + +/** + * Remove last entry from list, entry must be in the list + * + * @param entry struct pointer with a *next and *prev member to an entry struct + */ +#define DListRemove(list, entry) \ +do { \ + if ((entry)->next != NULL) { \ + (entry)->next->prev = (entry)->prev; \ + } else { \ + (list)->last = (entry)->prev; \ + } \ + if ((entry)->prev != NULL) { \ + (entry)->prev->next = (entry)->next; \ + } else { \ + (list)->first = (entry)->next; \ + } \ + (entry)->next = NULL; \ + (entry)->prev = NULL; \ +} while (0) + +#define DListIsEmpty(list) ((list)->first == NULL) diff --git a/src/main.c b/src/main.c index 3294857..14fc202 100644 --- a/src/main.c +++ b/src/main.c @@ -515,6 +515,8 @@ void print_runes(Str str) void string_test_utf8(void) { + TRACEF("\n"); + Str str1 = S("Test 1ø2 ☺"); TRACEF("str1:\n"); @@ -537,6 +539,8 @@ void string_test_utf8(void) void string_test_hex(void) { + TRACEF("\n"); + MArena arena; U8 data[4096]; marena_init(&arena, data, sizeof data); @@ -557,8 +561,115 @@ void string_test_hex(void) Str str2_decoded = str_hex_decode_alloc(&allocator, str2_encoded); printf("str2_decoded: '%.*s'\n", str2_decoded.len, str2_decoded.str); +} +typedef struct StrSLNode StrSLNode; +struct StrSLNode { + Str str; + StrSLNode *next; +}; +typedef struct StrSList StrSList; +struct StrSList { + StrSLNode *first; + StrSLNode **last; +}; + +void string_test_slist(void) +{ + TRACEF("\n"); + + Str str1 = S("one"); + Str str2 = S("two"); + Str str3 = S("three"); + StrSList strlist = {}; + StrSLNode n1 = {str1, NULL}; + StrSLNode n2 = {str2, NULL}; + StrSLNode n3 = {str3, NULL}; + + SListInit(&strlist); + SListAddFirst(&strlist, &n1); + SListAddFirst(&strlist, &n2); + SListAddFirst(&strlist, &n3); + TRACEF("List test first\n"); + + for (StrSLNode *n = strlist.first; n != NULL; n = n->next) { + printf("Node: %.*s\n", n->str.len, n->str.str); + } + TRACEF("List test first done\n"); + SListInit(&strlist); + SListAddLast(&strlist, &n1); + SListAddLast(&strlist, &n2); + SListAddLast(&strlist, &n3); + SListRemoveFirst(&strlist); + TRACEF("List test last\n"); + + for (StrSLNode *n = strlist.first; n != NULL; n = n->next) { + printf("Node: %.*s\n", n->str.len, n->str.str); + } + TRACEF("List test last done\n"); + +} +typedef struct StrDLNode StrDLNode; +struct StrDLNode { + Str str; + StrDLNode *next; + StrDLNode *prev; +}; + +typedef struct StrDList StrDList; +struct StrDList { + StrDLNode *first; + StrDLNode *last; +}; + +void string_test_dlist(void) +{ + TRACEF("\n"); + + Str str1 = S("one"); + Str str2 = S("two"); + Str str3 = S("three"); + Str str4 = S("four"); + StrDList strlist = {}; + StrDLNode n1 = {str1, NULL, NULL}; + StrDLNode n2 = {str2, NULL, NULL}; + StrDLNode n3 = {str3, NULL, NULL}; + StrDLNode n4 = {str4, NULL, NULL}; + + DListInit(&strlist); + DListAddFirst(&strlist, &n1); + DListAddFirst(&strlist, &n2); + DListAddFirst(&strlist, &n3); + TRACEF("List test first\n"); + + for (StrDLNode *n = strlist.first; n != NULL; n = n->next) { + printf("Node: %.*s\n", n->str.len, n->str.str); + } + TRACEF("List test first done\n"); + + DListInit(&strlist); + DListAddLast(&strlist, &n2); + DListAddLast(&strlist, &n3); + DListAddLast(&strlist, &n4); + DListAddFirst(&strlist, &n1); + + TRACEF("List test full\n"); + + for (StrDLNode *n = strlist.first; n != NULL; n = n->next) { + printf("Node: %.*s\n", n->str.len, n->str.str); + } + TRACEF("List test full done\n"); + + DListRemove(&strlist, &n1); + DListRemoveFirst(&strlist); + DListRemoveLast(&strlist); + TRACEF("List test tail removed\n"); + + for (StrDLNode *n = strlist.first; n != NULL; n = n->next) { + printf("Node: %.*s\n", n->str.len, n->str.str); + } + TRACEF("List test tail removed done\n"); } @@ -580,6 +691,8 @@ int main(int argc, char *argv[]) string_test_join(); string_test_utf8(); string_test_hex(); + string_test_slist(); + string_test_dlist(); }