#include "IZ_list.h" bool IZ_ListFindFilterAlwaysTrue(IZ_ListNode** _node, u64 _index, IZ_List* _list) { return true; } /** * Initializes a list. * @param list - The list to initialize. */ void IZ_ListInitialize(IZ_List* list) { list->root = NULL; list->length = 0; list->iterator = NULL; } /** * Performs cleanup on a list. * @param list - The list to clean up. */ void IZ_ListTeardown(IZ_List* list) { while (list->root) { IZ_ListDeleteFirstNode(list, IZ_ListFindFilterAlwaysTrue); } list->iterator = NULL; list->length = 0; } /** * Appends a node to the end of the list. * @param list - The list to append to. * @param node_value - The value of the node to append. * @return Pointer to the newly created node. */ IZ_ListNode** IZ_ListAppendNode(IZ_List* list, void* node_value) { IZ_ListNode* new_node = SDL_malloc(sizeof(IZ_ListNode)); new_node->value = node_value; new_node->next = NULL; if (!(list->root)) { list->root = new_node; list->length += 1; return &list->root; } IZ_ListNode* last_node = list->root; while (last_node->next) { last_node = last_node->next; } last_node->next = new_node; list->length += 1; return &last_node->next; } /** * Inserts a node at the specified index in the list. * @param list - The list to append to. * @param node_value - The value of the node to insert. * @param index - The index to insert the node at. * @return Pointer to the newly created node. */ IZ_ListNode** IZ_ListInsertNodeAtIndex(IZ_List* list, void* node_value, u64 index) { if (index > list->length) { // we don't want to go out of bounds return NULL; } IZ_ListNode* new_node = SDL_malloc(sizeof(IZ_ListNode)); new_node->value = node_value; new_node->next = NULL; if (!(list->root)) { list->root = new_node; list->length += 1; return &list->root; } if (index == 0) { new_node->next = list->root; list->root = new_node; list->length += 1; return &list->root; } IZ_ListNode* last_node = list->root; for (u64 i = 0; i < index - 1; i += 1) { last_node = last_node->next; } new_node->next = last_node->next; last_node->next = new_node; list->length += 1; return &last_node->next; } /** * Deletes the first node in the list that matches the filter. * @param list - The list to delete from. * @param filter - The filter to use to find the node to delete. */ void IZ_ListDeleteFirstNode(IZ_List* list, IZ_ListFindPredicate filter) { if (!(list && list->root)) { // should we raise warnings here? return; } list->iterator = &list->root; IZ_ListNode* previous_node = NULL; u64 index = 0; do { if (!filter(list->iterator, index, list)) { previous_node = *list->iterator; list->iterator = &((*list->iterator)->next); index += 1; // we haven't found the node we're looking for, go to the next one continue; } 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 } SDL_free(*list->iterator); list->iterator = NULL; if (list->length > 0) { // avoid underflow list->length -= 1; } return; } while (*list->iterator); } /** * Finds the first node in the list that matches the filter. * @param list - The list to search. * @param filter - The filter to use to find the node. * @return Pointer to the node that matches the filter. */ IZ_ListNode** IZ_ListFindFirstNode(IZ_List* list, IZ_ListFindPredicate filter) { if (!(list && list->root)) { return NULL; } list->iterator = &list->root; u64 index = 0; do { if (filter(list->iterator, index, list)) { return list->iterator; } list->iterator = &((*list->iterator)->next); index += 1; } while (*list->iterator); return NULL; } void IZ_ListFilter(IZ_List* original_list, IZ_ListFindPredicate filter, IZ_List* out_filtered_list) { // we assume the new list is already initialized IZ_ListNode* node = original_list->root; u64 index; for (index = 0; node; index += 1) { if (!filter(&node, index, original_list)) { node = node->next; continue; } IZ_ListAppendNode(out_filtered_list, node->value); node = node->next; } } void IZ_ListSort(IZ_List* original_list, IZ_ListSortComparatorPredicate sort, IZ_List* out_sorted_list) { // we assume the new list is already initialized IZ_ListNode* original_node = original_list->root; u64 original_index; for (original_index = 0; original_node; original_index += 1) { if (!out_sorted_list->root) { IZ_ListAppendNode(out_sorted_list, original_node->value); original_node = original_node->next; continue; } IZ_ListNode* sorted_node = out_sorted_list->root; for (u64 sorted_index = 0; sorted_node; sorted_index += 1) { if (sort(&original_node, &sorted_node, original_index, original_list) < 0) { IZ_ListInsertNodeAtIndex(out_sorted_list, original_node->value, sorted_index); original_node = original_node->next; break; } sorted_node = sorted_node->next; } } }