Sun, 26 Sep 2021 15:43:41 +0200
add cx_tree_add_child_node tests
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "cx/linked_list.h" #include <stdint.h> #include <string.h> /* LOW LEVEL LINKED LIST FUNCTIONS */ #define CX_LL_PTR(cur, off) ((void**)(((char*)cur)+off)) void *cx_linked_list_last(void **begin, void **end, ptrdiff_t loc_next) { if (end != NULL) { return *end; } else { if (begin == NULL || *begin == NULL) return NULL; void *cur = *begin; void *last; do { last = cur; } while ((cur = *CX_LL_PTR(cur, loc_next)) != NULL); return last; } } int cx_linked_list_add(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node) { void *last = cx_linked_list_last(begin, end, loc_next); if (last == NULL) { if (begin == NULL) { // no current list and no begin ptr to write to - we don't find something to append to return 1; } else { // start fresh list *begin = new_node; } } else { // if there is a last node, update its next pointer void **next = CX_LL_PTR(last, loc_next); *next = new_node; } // if there is an end pointer, update it if (end != NULL) { *end = cx_linked_list_last(&new_node, NULL, loc_next); } // if the nodes use a prev pointer, update it if (loc_prev >= 0) { void **prev = CX_LL_PTR(new_node, loc_prev); *prev = last; } return 0; } /* HIGH LEVEL LINKED LIST IMPLEMENTATION */ struct cx_linked_list_node { void *prev; void *next; char payload[]; }; typedef struct { void *begin; void *end; ptrdiff_t loc_prev; ptrdiff_t loc_next; } cx_linked_list; int cx_ll_add(cx_list *list, void *elem) { cx_linked_list *listdata = (cx_linked_list *) list->listdata; CxAllocator allocator = list->allocator; struct cx_linked_list_node *node = cxMalloc(allocator, sizeof(struct cx_linked_list_node) + list->itemsize); if (node == NULL) return 1; node->next = NULL; memcpy(node->payload, elem, list->itemsize); int ret = cx_linked_list_add( &listdata->begin, &listdata->end, offsetof(struct cx_linked_list_node, prev), offsetof(struct cx_linked_list_node, next), node ); if (ret == 0) { list->size++; return 0; } else { return ret; } } int cx_ll_insert(cx_list *list, size_t index, void *elem) { cx_linked_list *listdata = (cx_linked_list *) list->listdata; // TODO: implement using low level API return 1; } void *cx_ll_remove(cx_list *list, size_t index) { cx_linked_list *listdata = (cx_linked_list *) list->listdata; // TODO: implement using low level API return NULL; } size_t cx_ll_find(cx_list *list, void *elem) { cx_linked_list *listdata = (cx_linked_list *) list->listdata; // TODO: implement using low level API return 0; } void *cx_ll_last(cx_list *list) { cx_linked_list *listdata = (cx_linked_list *) list->listdata; struct cx_linked_list_node *last = cx_linked_list_last( NULL, &listdata->end, offsetof(struct cx_linked_list_node, next)); return &last->payload; } cx_list_class cx_linked_list_class = { cx_ll_add, cx_ll_insert, cx_ll_remove, cx_ll_find, cx_ll_last }; CxList cxLinkedListCreate(CxAllocator allocator, CxListComparator comparator, size_t item_size) { CxList list = cxMalloc(allocator, sizeof(cx_list_s) + sizeof(cx_linked_list)); if (list == NULL) return NULL; list->cl = &cx_linked_list_class; list->data.allocator = allocator; list->data.cmpfunc = comparator; list->data.itemsize = item_size; list->data.capacity = SIZE_MAX; cx_linked_list *ll = (cx_linked_list *) list->data.listdata; ll->begin = NULL; ll->loc_prev = offsetof(struct cx_linked_list_node, prev); ll->loc_next = offsetof(struct cx_linked_list_node, next); cxLinkedListRecalculateSize(list); return list; } void cxLinkedListDestroy(CxList list) { // TODO: free contents cxFree(list->data.allocator, list); } size_t cxLinkedListRecalculateSize(CxList list) { cx_linked_list *ll = (cx_linked_list *) list->data.listdata; if (ll->begin == NULL) { list->data.size = 0; ll->end = NULL; return 0; } else { void *cur = ll->begin; void *last; size_t size; do { last = cur; size++; } while ((cur = *CX_LL_PTR(cur, ll->loc_next)) != NULL); ll->end = last; list->data.size = size; return size; } }