// vim:fileencoding=utf-8:foldmethod=marker #include "./dbl_list.h" #include "../mem/allocator/mem_allocator.h" #include "../../common/assert/assert.h" #include "../../common/aliases/aliases.h" #include "../../common/platform/platform.h" #include wapp_intern GenericList _node_to_list(GenericNode *node, u64 item_size); wapp_intern inline void _dbl_list_validate(const GenericList *list, u64 item_size); wapp_intern inline void _dbl_list_node_validate(const GenericList *list, const GenericNode *node, u64 item_size); GenericList *_dbl_list_alloc(const Allocator *allocator, u64 item_size) { wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL"); GenericList *list = wapp_mem_allocator_alloc(allocator, sizeof(GenericList)); if (!list) { goto DBL_LIST_ALLOC_RETURN; } memset((void *)list, 0, sizeof(GenericList)); list->magic = WAPP_DBL_LIST_MAGIC; list->item_size = item_size; DBL_LIST_ALLOC_RETURN: return list; } GenericNode *_dbl_list_node_alloc(const Allocator *allocator, u64 item_size) { wapp_debug_assert(allocator != NULL, "`allocator` should not be NULL"); GenericNode *node = wapp_mem_allocator_alloc(allocator, sizeof(GenericNode)); if (!node) { goto DBL_LIST_NODE_ALLOC_RETURN; } memset((void *)node, 0, sizeof(GenericNode)); node->magic = WAPP_DBL_NODE_MAGIC; node->item_size = item_size; DBL_LIST_NODE_ALLOC_RETURN: return node; } GenericNode *_dbl_list_get(const GenericList *list, u64 index, u64 item_size) { wapp_debug_assert(list != NULL, "`list` should not be NULL"); _dbl_list_validate(list, item_size); wapp_runtime_assert(index < list->node_count, "`index` is out of bounds"); GenericNode *output = NULL; GenericNode *current = list->first; for (u64 i = 1; i <= index; ++i) { current = current->next; } output = current; return output; } void _dbl_list_push_front(GenericList *list, GenericNode *node, u64 item_size) { wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); _dbl_list_validate(list, item_size); _dbl_list_node_validate(list, node, item_size); GenericList node_list = _node_to_list(node, item_size); if (list->node_count == 0) { *list = node_list; return; } list->node_count += node_list.node_count; GenericNode *first = list->first; if (first) { first->prev = node_list.last; } list->first = node_list.first; node_list.last->next = first; } void _dbl_list_push_back(GenericList *list, GenericNode *node, u64 item_size) { wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); _dbl_list_validate(list, item_size); _dbl_list_node_validate(list, node, item_size); GenericList node_list = _node_to_list(node, item_size); if (list->node_count == 0) { *list = node_list; return; } list->node_count += node_list.node_count; GenericNode *last = list->last; if (last) { last->next = node_list.first; } list->last = node_list.last; node_list.first->prev = last; } void _dbl_list_insert(GenericList *list, GenericNode *node, u64 index, u64 item_size) { wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL"); _dbl_list_validate(list, item_size); _dbl_list_node_validate(list, node, item_size); if (index == 0) { _dbl_list_push_front(list, node, item_size); return; } else if (index == list->node_count) { _dbl_list_push_back(list, node, item_size); return; } GenericNode *dst_node = _dbl_list_get(list, index, item_size); if (!dst_node) { return; } GenericList node_list = _node_to_list(node, item_size); list->node_count += node_list.node_count; GenericNode *prev = dst_node->prev; dst_node->prev = node_list.last; prev->next = node_list.first; node_list.first->prev = prev; node_list.last->next = dst_node; } GenericNode *_dbl_list_pop_front(GenericList *list, u64 item_size) { wapp_debug_assert(list != NULL, "`list` should not be NULL"); _dbl_list_validate(list, item_size); GenericNode *output = NULL; if (list->node_count == 0) { goto RETURN_I32_LIST_POP_FRONT; } output = list->first; if (list->node_count == 1) { *list = (GenericList){.magic = WAPP_DBL_LIST_MAGIC, .item_size = item_size}; goto RETURN_I32_LIST_POP_FRONT; } --(list->node_count); list->first = output->next; output->prev = output->next = NULL; RETURN_I32_LIST_POP_FRONT: return output; } GenericNode *_dbl_list_pop_back(GenericList *list, u64 item_size) { wapp_debug_assert(list != NULL, "`list` should not be NULL"); _dbl_list_validate(list, item_size); GenericNode *output = NULL; if (list->node_count == 0) { goto RETURN_I32_LIST_POP_BACK; } output = list->last; if (list->node_count == 1) { *list = (GenericList){.magic = WAPP_DBL_LIST_MAGIC, .item_size = item_size}; goto RETURN_I32_LIST_POP_BACK; } --(list->node_count); list->last = output->prev; output->prev = output->next = NULL; RETURN_I32_LIST_POP_BACK: return output; } GenericNode *_dbl_list_remove(GenericList *list, u64 index, u64 item_size) { wapp_debug_assert(list != NULL, "`list` should not be NULL"); _dbl_list_validate(list, item_size); GenericNode *output = NULL; if (index == 0) { output = _dbl_list_pop_front(list, item_size); goto RETURN_I32_LIST_REMOVE; } else if (index == list->node_count) { output = _dbl_list_pop_back(list, item_size); goto RETURN_I32_LIST_REMOVE; } output = _dbl_list_get(list, index, item_size); if (!output) { goto RETURN_I32_LIST_REMOVE; } output->prev->next = output->next; output->next->prev = output->prev; --(list->node_count); output->prev = output->next = NULL; RETURN_I32_LIST_REMOVE: return output; } void _dbl_list_empty(GenericList *list, u64 item_size) { wapp_debug_assert(list != NULL, "`list` should not be NULL"); _dbl_list_validate(list, item_size); u64 count = list->node_count; for (u64 i = 0; i < count; ++i) { _dbl_list_pop_back(list, item_size); } } wapp_intern GenericList _node_to_list(GenericNode *node, u64 item_size) { GenericList output = { .magic = WAPP_DBL_LIST_MAGIC, .first = node, .last = node, .node_count = 1, .item_size = item_size, }; while (output.first->prev != NULL) { output.first = output.first->prev; ++(output.node_count); } while (output.last->next != NULL) { output.last = output.last->next; ++(output.node_count); } return output; } wapp_intern inline void _dbl_list_validate(const GenericList *list, u64 item_size) { wapp_runtime_assert(list->magic == WAPP_DBL_LIST_MAGIC, "`list` isn't a valid wapp list type"); wapp_runtime_assert(list->item_size == item_size, "Invalid item provided"); } wapp_intern inline void _dbl_list_node_validate(const GenericList *list, const GenericNode *node, u64 item_size) { wapp_runtime_assert(node->magic == WAPP_DBL_NODE_MAGIC, "`node` isn't a valid wapp node type"); wapp_runtime_assert(list->item_size == node->item_size, "Mismatched `list` and `node` types"); wapp_runtime_assert(node->item_size == item_size, "Invalid item provided"); }