diff --git a/src/packages/game/data/IZ_list.c b/src/packages/game/data/IZ_list.c index 66da775..d6b868c 100644 --- a/src/packages/game/data/IZ_list.c +++ b/src/packages/game/data/IZ_list.c @@ -15,8 +15,8 @@ void IZ_ListInitialize(IZ_List* list) { * @param list - The list to clean up. */ void IZ_ListTeardown(IZ_List* list) { - while (list->root) { - IZ_ListDeleteNode(list, &list->root); + while (list->length > 0) { + IZ_ListDeleteNode(list->root); } IZ_free(list); } @@ -30,61 +30,51 @@ IZ_ListNode** IZ_ListAppendNode(IZ_List* list, void* node_value) { IZ_ListNode* new_node = IZ_malloc(sizeof(IZ_ListNode)); new_node->value = node_value; new_node->next = NULL; - list->length += 1; + new_node->list = list; + new_node->list->length += 1; if (!(list->root)) { - list->root = new_node; - return &list->root; + new_node->previous = NULL; + new_node->list->root = new_node; + return &new_node->list->root; } - IZ_ListNode *last_node = list->root; + IZ_ListNode *last_node = new_node->list->root; while (last_node->next) { last_node = last_node->next; } + new_node->previous = last_node; last_node->next = new_node; return &last_node->next; } /** * Deletes the first node in the list that matches the filter. - * @param list - The list to delete from. * @param node - The node to delete. */ -void IZ_ListDeleteNode(IZ_List* list, IZ_ListNode** node) { - if (!(list && list->root && node)) { +void IZ_ListDeleteNode(IZ_ListNode* node) { + if (!node) { // should we raise warnings here? return; } - // FIXME Teardown having problems here - list->iterator = &list->root; - IZ_ListNode** previous_node = NULL; - do { - if (list->iterator != node) { - previous_node = list->iterator; - list->iterator = &((*list->iterator)->next); - // we haven't found the node we're looking for, go to the next one - continue; + if (node->previous) { + node->previous->next = node->next; + } else { + if (node->next) { + node->next->previous = NULL; } - - if (previous_node) { - // this is not the first node in the list - (*previous_node)->next = (*list->iterator)->next; - } else { - // this is the first node, set it as new root - list->root = (*list->iterator)->next; - // if there is only one item in the list, root, gets set to NULL + if (node->list) { + node->list->root = node->next; } + } - IZ_free(*list->iterator); - list->iterator = NULL; - if (list->length > 0) { - // avoid underflow - list->length -= 1; - } - return; - } while (*list->iterator); + if (node->list && node->list->length > 0) { + node->list->length -= 1; + } + + IZ_free(node); } /** diff --git a/src/packages/game/data/IZ_list.h b/src/packages/game/data/IZ_list.h index cb5d8db..1671a19 100644 --- a/src/packages/game/data/IZ_list.h +++ b/src/packages/game/data/IZ_list.h @@ -4,10 +4,15 @@ #include "../../common/IZ_common.h" #include "../../stdinc/IZ_stdlib.h" +struct IZ_List; + /** * A node in a linked list. */ typedef struct IZ_ListNode { + struct IZ_List* list; + + struct IZ_ListNode* previous; /** * The value of the node. */ @@ -21,7 +26,7 @@ typedef struct IZ_ListNode { /** * A singly-linked list. */ -typedef struct { +typedef struct IZ_List { /** * The first node in the list. */ @@ -57,7 +62,7 @@ IZ_ListNode** IZ_ListAppendNode(IZ_List*, void*); /** * Deletes the first node in the list that matches the filter. */ -void IZ_ListDeleteNode(IZ_List*, IZ_ListNode**); +void IZ_ListDeleteNode(IZ_ListNode*); /** * Finds the first node in the list that matches the filter. diff --git a/src/packages/game/data/data.test.c b/src/packages/game/data/data.test.c index 8ce0cca..36b2d5c 100644 --- a/src/packages/game/data/data.test.c +++ b/src/packages/game/data/data.test.c @@ -22,6 +22,7 @@ spec("data") { after_each() { IZ_ListTeardown(&list); + mock_reset(IZ_free); } it("sets root to NULL") { @@ -77,10 +78,13 @@ spec("data") { IZ_ListInitialize(&list2); static u64 existing_value = 69420u; static IZ_ListNode existing_node = { + .list = NULL, + .previous = NULL, .value = &existing_value, .next = NULL, }; list2.root = &existing_node; + existing_node.list = &list2; list2.length = 1; } @@ -171,7 +175,7 @@ spec("data") { it("removes first node satisfying the filter condition") { IZ_ListNode** existing_node = IZ_ListFindFirstNode(&list, NodeExists); - IZ_ListDeleteNode(&list, existing_node); + IZ_ListDeleteNode(*existing_node); check( mock_is_called(IZ_free),