--- a/src/ucx/linked_list.c Mon Feb 10 17:44:51 2025 +0100 +++ b/src/ucx/linked_list.c Sun Mar 02 18:10:52 2025 +0100 @@ -27,7 +27,7 @@ */ #include "cx/linked_list.h" -#include "cx/utils.h" +#include "cx/compare.h" #include <string.h> #include <assert.h> @@ -40,7 +40,7 @@ #define ll_data(node) (((char*)(node))+loc_data) void *cx_linked_list_at( - void const *start, + const void *start, size_t start_index, ptrdiff_t loc_advance, size_t index @@ -48,7 +48,7 @@ assert(start != NULL); assert(loc_advance >= 0); size_t i = start_index; - void const *cur = start; + const void *cur = start; while (i != index && cur != NULL) { cur = ll_advance(cur); i < index ? i++ : i--; @@ -56,47 +56,51 @@ return (void *) cur; } -ssize_t cx_linked_list_find( - void const *start, +void *cx_linked_list_find( + const void *start, ptrdiff_t loc_advance, ptrdiff_t loc_data, cx_compare_func cmp_func, - void const *elem + const void *elem, + size_t *found_index ) { assert(start != NULL); assert(loc_advance >= 0); assert(loc_data >= 0); assert(cmp_func); - void const *node = start; - ssize_t index = 0; + void *node = (void*) start; + size_t index = 0; do { void *current = ll_data(node); if (cmp_func(current, elem) == 0) { - return index; + if (found_index != NULL) { + *found_index = index; + } + return node; } node = ll_advance(node); index++; } while (node != NULL); - return -1; + return NULL; } void *cx_linked_list_first( - void const *node, + const void *node, ptrdiff_t loc_prev ) { return cx_linked_list_last(node, loc_prev); } void *cx_linked_list_last( - void const *node, + const void *node, ptrdiff_t loc_next ) { assert(node != NULL); assert(loc_next >= 0); - void const *cur = node; - void const *last; + const void *cur = node; + const void *last; do { last = cur; } while ((cur = ll_next(cur)) != NULL); @@ -105,16 +109,16 @@ } void *cx_linked_list_prev( - void const *begin, + const void *begin, ptrdiff_t loc_next, - void const *node + const void *node ) { assert(begin != NULL); assert(node != NULL); assert(loc_next >= 0); if (begin == node) return NULL; - void const *cur = begin; - void const *next; + const void *cur = begin; + const void *next; while (1) { next = ll_next(cur); if (next == node) return (void *) cur; @@ -227,19 +231,111 @@ } } -void cx_linked_list_remove( +void cx_linked_list_insert_sorted( + void **begin, + void **end, + ptrdiff_t loc_prev, + ptrdiff_t loc_next, + void *new_node, + cx_compare_func cmp_func +) { + assert(ll_next(new_node) == NULL); + cx_linked_list_insert_sorted_chain( + begin, end, loc_prev, loc_next, new_node, cmp_func); +} + +void cx_linked_list_insert_sorted_chain( void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, - void *node + void *insert_begin, + cx_compare_func cmp_func +) { + assert(begin != NULL); + assert(loc_next >= 0); + assert(insert_begin != NULL); + + // track currently observed nodes + void *dest_prev = NULL; + void *dest = *begin; + void *src = insert_begin; + + // special case: list is empty + if (dest == NULL) { + *begin = src; + if (end != NULL) { + *end = cx_linked_list_last(src, loc_next); + } + return; + } + + // search the list for insertion points + while (dest != NULL && src != NULL) { + // compare current list node with source node + // if less or equal, skip + if (cmp_func(dest, src) <= 0) { + dest_prev = dest; + dest = ll_next(dest); + continue; + } + + // determine chain of elements that can be inserted + void *end_of_chain = src; + void *next_in_chain = ll_next(src); + while (next_in_chain != NULL) { + // once we become larger than the list elem, break + if (cmp_func(dest, next_in_chain) <= 0) { + break; + } + // otherwise, we can insert one more + end_of_chain = next_in_chain; + next_in_chain = ll_next(next_in_chain); + } + + // insert the elements + if (dest_prev == NULL) { + // new begin + *begin = src; + } else { + cx_linked_list_link(dest_prev, src, loc_prev, loc_next); + } + cx_linked_list_link(end_of_chain, dest, loc_prev, loc_next); + + // continue with next + src = next_in_chain; + dest_prev = dest; + dest = ll_next(dest); + } + + // insert remaining items + if (src != NULL) { + cx_linked_list_link(dest_prev, src, loc_prev, loc_next); + } + + // determine new end of list, if requested + if (end != NULL) { + *end = cx_linked_list_last( + dest != NULL ? dest : dest_prev, loc_next); + } +} + +size_t cx_linked_list_remove_chain( + void **begin, + void **end, + ptrdiff_t loc_prev, + ptrdiff_t loc_next, + void *node, + size_t num ) { assert(node != NULL); assert(loc_next >= 0); assert(loc_prev >= 0 || begin != NULL); + // easy exit + if (num == 0) return 0; + // find adjacent nodes - void *next = ll_next(node); void *prev; if (loc_prev >= 0) { prev = ll_prev(node); @@ -247,6 +343,12 @@ prev = cx_linked_list_prev(*begin, loc_next, node); } + void *next = ll_next(node); + size_t removed = 1; + for (; removed < num && next != NULL ; removed++) { + next = ll_next(next); + } + // update next pointer of prev node, or set begin if (prev == NULL) { if (begin != NULL) { @@ -264,10 +366,12 @@ } else if (loc_prev >= 0) { ll_prev(next) = prev; } + + return removed; } size_t cx_linked_list_size( - void const *node, + const void *node, ptrdiff_t loc_next ) { assert(loc_next >= 0); @@ -327,13 +431,13 @@ // Update pointer if (loc_prev >= 0) ll_prev(sorted[0]) = NULL; - cx_for_n (i, length - 1) { + for (size_t i = 0 ; i < length - 1; i++) { cx_linked_list_link(sorted[i], sorted[i + 1], loc_prev, loc_next); } ll_next(sorted[length - 1]) = NULL; *begin = sorted[0]; - *end = sorted[length-1]; + *end = sorted[length - 1]; if (sorted != sbo) { free(sorted); } @@ -405,17 +509,17 @@ } int cx_linked_list_compare( - void const *begin_left, - void const *begin_right, + const void *begin_left, + const void *begin_right, ptrdiff_t loc_advance, ptrdiff_t loc_data, cx_compare_func cmp_func ) { - void const *left = begin_left, *right = begin_right; + const void *left = begin_left, *right = begin_right; while (left != NULL && right != NULL) { - void const *left_data = ll_data(left); - void const *right_data = ll_data(right); + const void *left_data = ll_data(left); + const void *right_data = ll_data(right); int result = cmp_func(left_data, right_data); if (result != 0) return result; left = ll_advance(left); @@ -460,8 +564,6 @@ // HIGH LEVEL LINKED LIST IMPLEMENTATION -bool CX_DISABLE_LINKED_LIST_SWAP_SBO = false; - typedef struct cx_linked_list_node cx_linked_list_node; struct cx_linked_list_node { cx_linked_list_node *prev; @@ -480,34 +582,38 @@ } cx_linked_list; static cx_linked_list_node *cx_ll_node_at( - cx_linked_list const *list, + const cx_linked_list *list, size_t index ) { - if (index >= list->base.size) { + if (index >= list->base.collection.size) { return NULL; - } else if (index > list->base.size / 2) { - return cx_linked_list_at(list->end, list->base.size - 1, CX_LL_LOC_PREV, index); + } else if (index > list->base.collection.size / 2) { + return cx_linked_list_at(list->end, list->base.collection.size - 1, CX_LL_LOC_PREV, index); } else { return cx_linked_list_at(list->begin, 0, CX_LL_LOC_NEXT, index); } } +static cx_linked_list_node *cx_ll_malloc_node(const struct cx_list_s *list) { + return cxMalloc(list->collection.allocator, + sizeof(cx_linked_list_node) + list->collection.elem_size); +} + static int cx_ll_insert_at( struct cx_list_s *list, cx_linked_list_node *node, - void const *elem + const void *elem ) { // create the new new_node - cx_linked_list_node *new_node = cxMalloc(list->allocator, - sizeof(cx_linked_list_node) + list->item_size); + cx_linked_list_node *new_node = cx_ll_malloc_node(list); // sortir if failed if (new_node == NULL) return 1; // initialize new new_node new_node->prev = new_node->next = NULL; - memcpy(new_node->payload, elem, list->item_size); + memcpy(new_node->payload, elem, list->collection.elem_size); // insert cx_linked_list *ll = (cx_linked_list *) list; @@ -518,26 +624,24 @@ ); // increase the size and return - list->size++; + list->collection.size++; return 0; } static size_t cx_ll_insert_array( struct cx_list_s *list, size_t index, - void const *array, + const void *array, size_t n ) { // out-of bounds and corner case check - if (index > list->size || n == 0) return 0; + if (index > list->collection.size || n == 0) return 0; // find position efficiently cx_linked_list_node *node = index == 0 ? NULL : cx_ll_node_at((cx_linked_list *) list, index - 1); // perform first insert - if (0 != cx_ll_insert_at(list, node, array)) { - return 1; - } + if (0 != cx_ll_insert_at(list, node, array)) return 1; // is there more? if (n == 1) return 1; @@ -545,13 +649,11 @@ // we now know exactly where we are node = node == NULL ? ((cx_linked_list *) list)->begin : node->next; - // we can add the remaining nodes and immedately advance to the inserted node - char const *source = array; + // we can add the remaining nodes and immediately advance to the inserted node + const char *source = array; for (size_t i = 1; i < n; i++) { - source += list->item_size; - if (0 != cx_ll_insert_at(list, node, source)) { - return i; - } + source += list->collection.elem_size; + if (0 != cx_ll_insert_at(list, node, source)) return i; node = node->next; } return n; @@ -560,67 +662,151 @@ static int cx_ll_insert_element( struct cx_list_s *list, size_t index, - void const *element + const void *element ) { return 1 != cx_ll_insert_array(list, index, element, 1); } -static int cx_ll_remove( +static _Thread_local cx_compare_func cx_ll_insert_sorted_cmp_func; + +static int cx_ll_insert_sorted_cmp_helper(const void *l, const void *r) { + const cx_linked_list_node *left = l; + const cx_linked_list_node *right = r; + return cx_ll_insert_sorted_cmp_func(left->payload, right->payload); +} + +static size_t cx_ll_insert_sorted( struct cx_list_s *list, - size_t index + const void *array, + size_t n +) { + // special case + if (n == 0) return 0; + + // create a new chain of nodes + cx_linked_list_node *chain = cx_ll_malloc_node(list); + if (chain == NULL) return 0; + + memcpy(chain->payload, array, list->collection.elem_size); + chain->prev = NULL; + chain->next = NULL; + + // add all elements from the array to that chain + cx_linked_list_node *prev = chain; + const char *src = array; + size_t inserted = 1; + for (; inserted < n; inserted++) { + cx_linked_list_node *next = cx_ll_malloc_node(list); + if (next == NULL) break; + src += list->collection.elem_size; + memcpy(next->payload, src, list->collection.elem_size); + prev->next = next; + next->prev = prev; + prev = next; + } + prev->next = NULL; + + // invoke the low level function + cx_linked_list *ll = (cx_linked_list *) list; + cx_ll_insert_sorted_cmp_func = list->collection.cmpfunc; + cx_linked_list_insert_sorted_chain( + (void **) &ll->begin, + (void **) &ll->end, + CX_LL_LOC_PREV, + CX_LL_LOC_NEXT, + chain, + cx_ll_insert_sorted_cmp_helper + ); + + // adjust the list metadata + list->collection.size += inserted; + + return inserted; +} + +static size_t cx_ll_remove( + struct cx_list_s *list, + size_t index, + size_t num, + void *targetbuf ) { cx_linked_list *ll = (cx_linked_list *) list; cx_linked_list_node *node = cx_ll_node_at(ll, index); // out-of-bounds check - if (node == NULL) return 1; - - // element destruction - cx_invoke_destructor(list, node->payload); + if (node == NULL) return 0; // remove - cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, - CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); + size_t removed = cx_linked_list_remove_chain( + (void **) &ll->begin, + (void **) &ll->end, + CX_LL_LOC_PREV, + CX_LL_LOC_NEXT, + node, + num + ); // adjust size - list->size--; + list->collection.size -= removed; + + // copy or destroy the removed chain + if (targetbuf == NULL) { + cx_linked_list_node *n = node; + for (size_t i = 0; i < removed; i++) { + // element destruction + cx_invoke_destructor(list, n->payload); - // free and return - cxFree(list->allocator, node); + // free the node and advance + void *next = n->next; + cxFree(list->collection.allocator, n); + n = next; + } + } else { + char *dest = targetbuf; + cx_linked_list_node *n = node; + for (size_t i = 0; i < removed; i++) { + // copy payload + memcpy(dest, n->payload, list->collection.elem_size); - return 0; + // advance target buffer + dest += list->collection.elem_size; + + // free the node and advance + void *next = n->next; + cxFree(list->collection.allocator, n); + n = next; + } + } + + return removed; } static void cx_ll_clear(struct cx_list_s *list) { - if (list->size == 0) return; + if (list->collection.size == 0) return; cx_linked_list *ll = (cx_linked_list *) list; cx_linked_list_node *node = ll->begin; while (node != NULL) { cx_invoke_destructor(list, node->payload); cx_linked_list_node *next = node->next; - cxFree(list->allocator, node); + cxFree(list->collection.allocator, node); node = next; } ll->begin = ll->end = NULL; - list->size = 0; + list->collection.size = 0; } -#ifndef CX_LINKED_LIST_SWAP_SBO_SIZE -#define CX_LINKED_LIST_SWAP_SBO_SIZE 128 -#endif - static int cx_ll_swap( struct cx_list_s *list, size_t i, size_t j ) { - if (i >= list->size || j >= list->size) return 1; + if (i >= list->collection.size || j >= list->collection.size) return 1; if (i == j) return 0; // perform an optimized search that finds both elements in one run cx_linked_list *ll = (cx_linked_list *) list; - size_t mid = list->size / 2; + size_t mid = list->collection.size / 2; size_t left, right; if (i < j) { left = i; @@ -629,10 +815,11 @@ left = j; right = i; } - cx_linked_list_node *nleft, *nright; + cx_linked_list_node *nleft = NULL, *nright = NULL; if (left < mid && right < mid) { // case 1: both items left from mid nleft = cx_ll_node_at(ll, left); + assert(nleft != NULL); nright = nleft; for (size_t c = left; c < right; c++) { nright = nright->next; @@ -640,6 +827,7 @@ } else if (left >= mid && right >= mid) { // case 2: both items right from mid nright = cx_ll_node_at(ll, right); + assert(nright != NULL); nleft = nright; for (size_t c = right; c > left; c--) { nleft = nleft->prev; @@ -650,7 +838,7 @@ // chose the closest to begin / end size_t closest; size_t other; - size_t diff2boundary = list->size - right - 1; + size_t diff2boundary = list->collection.size - right - 1; if (left <= diff2boundary) { closest = left; other = right; @@ -686,48 +874,40 @@ } } - if (list->item_size > CX_LINKED_LIST_SWAP_SBO_SIZE || CX_DISABLE_LINKED_LIST_SWAP_SBO) { - cx_linked_list_node *prev = nleft->prev; - cx_linked_list_node *next = nright->next; - cx_linked_list_node *midstart = nleft->next; - cx_linked_list_node *midend = nright->prev; + cx_linked_list_node *prev = nleft->prev; + cx_linked_list_node *next = nright->next; + cx_linked_list_node *midstart = nleft->next; + cx_linked_list_node *midend = nright->prev; - if (prev == NULL) { - ll->begin = nright; - } else { - prev->next = nright; - } - nright->prev = prev; - if (midstart == nright) { - // special case: both nodes are adjacent - nright->next = nleft; - nleft->prev = nright; - } else { - // likely case: a chain is between the two nodes - nright->next = midstart; - midstart->prev = nright; - midend->next = nleft; - nleft->prev = midend; - } - nleft->next = next; - if (next == NULL) { - ll->end = nleft; - } else { - next->prev = nleft; - } + if (prev == NULL) { + ll->begin = nright; + } else { + prev->next = nright; + } + nright->prev = prev; + if (midstart == nright) { + // special case: both nodes are adjacent + nright->next = nleft; + nleft->prev = nright; } else { - // swap payloads to avoid relinking - char buf[CX_LINKED_LIST_SWAP_SBO_SIZE]; - memcpy(buf, nleft->payload, list->item_size); - memcpy(nleft->payload, nright->payload, list->item_size); - memcpy(nright->payload, buf, list->item_size); + // likely case: a chain is between the two nodes + nright->next = midstart; + midstart->prev = nright; + midend->next = nleft; + nleft->prev = midend; + } + nleft->next = next; + if (next == NULL) { + ll->end = nleft; + } else { + next->prev = nleft; } return 0; } static void *cx_ll_at( - struct cx_list_s const *list, + const struct cx_list_s *list, size_t index ) { cx_linked_list *ll = (cx_linked_list *) list; @@ -735,20 +915,39 @@ return node == NULL ? NULL : node->payload; } -static ssize_t cx_ll_find( - struct cx_list_s const *list, - void const *elem +static size_t cx_ll_find_remove( + struct cx_list_s *list, + const void *elem, + bool remove ) { - return cx_linked_list_find(((cx_linked_list *) list)->begin, - CX_LL_LOC_NEXT, CX_LL_LOC_DATA, - list->cmpfunc, elem); + if (list->collection.size == 0) return 0; + + size_t index; + cx_linked_list *ll = ((cx_linked_list *) list); + cx_linked_list_node *node = cx_linked_list_find( + ll->begin, + CX_LL_LOC_NEXT, CX_LL_LOC_DATA, + list->collection.cmpfunc, elem, + &index + ); + if (node == NULL) { + return list->collection.size; + } + if (remove) { + cx_invoke_destructor(list, node->payload); + cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, + CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); + list->collection.size--; + cxFree(list->collection.allocator, node); + } + return index; } static void cx_ll_sort(struct cx_list_s *list) { cx_linked_list *ll = (cx_linked_list *) list; cx_linked_list_sort((void **) &ll->begin, (void **) &ll->end, CX_LL_LOC_PREV, CX_LL_LOC_NEXT, CX_LL_LOC_DATA, - list->cmpfunc); + list->collection.cmpfunc); } static void cx_ll_reverse(struct cx_list_s *list) { @@ -757,37 +956,35 @@ } static int cx_ll_compare( - struct cx_list_s const *list, - struct cx_list_s const *other + const struct cx_list_s *list, + const struct cx_list_s *other ) { cx_linked_list *left = (cx_linked_list *) list; cx_linked_list *right = (cx_linked_list *) other; return cx_linked_list_compare(left->begin, right->begin, CX_LL_LOC_NEXT, CX_LL_LOC_DATA, - list->cmpfunc); + list->collection.cmpfunc); } -static bool cx_ll_iter_valid(void const *it) { - struct cx_iterator_s const *iter = it; +static bool cx_ll_iter_valid(const void *it) { + const struct cx_iterator_s *iter = it; return iter->elem_handle != NULL; } static void cx_ll_iter_next(void *it) { - struct cx_iterator_base_s *itbase = it; - if (itbase->remove) { - itbase->remove = false; - struct cx_mut_iterator_s *iter = it; - struct cx_list_s *list = iter->src_handle; - cx_linked_list *ll = iter->src_handle; + struct cx_iterator_s *iter = it; + if (iter->base.remove) { + iter->base.remove = false; + struct cx_list_s *list = iter->src_handle.m; + cx_linked_list *ll = iter->src_handle.m; cx_linked_list_node *node = iter->elem_handle; iter->elem_handle = node->next; cx_invoke_destructor(list, node->payload); cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); - list->size--; - cxFree(list->allocator, node); + list->collection.size--; + cxFree(list->collection.allocator, node); } else { - struct cx_iterator_s *iter = it; iter->index++; cx_linked_list_node *node = iter->elem_handle; iter->elem_handle = node->next; @@ -795,78 +992,75 @@ } static void cx_ll_iter_prev(void *it) { - struct cx_iterator_base_s *itbase = it; - if (itbase->remove) { - itbase->remove = false; - struct cx_mut_iterator_s *iter = it; - struct cx_list_s *list = iter->src_handle; - cx_linked_list *ll = iter->src_handle; + struct cx_iterator_s *iter = it; + if (iter->base.remove) { + iter->base.remove = false; + struct cx_list_s *list = iter->src_handle.m; + cx_linked_list *ll = iter->src_handle.m; cx_linked_list_node *node = iter->elem_handle; iter->elem_handle = node->prev; iter->index--; cx_invoke_destructor(list, node->payload); cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end, CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node); - list->size--; - cxFree(list->allocator, node); + list->collection.size--; + cxFree(list->collection.allocator, node); } else { - struct cx_iterator_s *iter = it; iter->index--; cx_linked_list_node *node = iter->elem_handle; iter->elem_handle = node->prev; } } -static void *cx_ll_iter_current(void const *it) { - struct cx_iterator_s const *iter = it; +static void *cx_ll_iter_current(const void *it) { + const struct cx_iterator_s *iter = it; cx_linked_list_node *node = iter->elem_handle; return node->payload; } -static bool cx_ll_iter_flag_rm(void *it) { - struct cx_iterator_base_s *iter = it; - if (iter->mutating) { - iter->remove = true; - return true; - } else { - return false; - } -} - static CxIterator cx_ll_iterator( - struct cx_list_s const *list, + const struct cx_list_s *list, size_t index, bool backwards ) { CxIterator iter; iter.index = index; - iter.src_handle = list; - iter.elem_handle = cx_ll_node_at((cx_linked_list const *) list, index); + iter.src_handle.c = list; + iter.elem_handle = cx_ll_node_at((const cx_linked_list *) list, index); + iter.elem_size = list->collection.elem_size; + iter.elem_count = list->collection.size; iter.base.valid = cx_ll_iter_valid; iter.base.current = cx_ll_iter_current; iter.base.next = backwards ? cx_ll_iter_prev : cx_ll_iter_next; - iter.base.flag_removal = cx_ll_iter_flag_rm; iter.base.mutating = false; iter.base.remove = false; return iter; } static int cx_ll_insert_iter( - CxMutIterator *iter, - void const *elem, + CxIterator *iter, + const void *elem, int prepend ) { - struct cx_list_s *list = iter->src_handle; + struct cx_list_s *list = iter->src_handle.m; cx_linked_list_node *node = iter->elem_handle; if (node != NULL) { assert(prepend >= 0 && prepend <= 1); cx_linked_list_node *choice[2] = {node, node->prev}; int result = cx_ll_insert_at(list, choice[prepend], elem); - iter->index += prepend * (0 == result); + if (result == 0) { + iter->elem_count++; + if (prepend) { + iter->index++; + } + } return result; } else { - int result = cx_ll_insert_element(list, list->size, elem); - iter->index = list->size; + int result = cx_ll_insert_element(list, list->collection.size, elem); + if (result == 0) { + iter->elem_count++; + iter->index = list->collection.size; + } return result; } } @@ -878,23 +1072,24 @@ while (node) { cx_invoke_destructor(list, node->payload); void *next = node->next; - cxFree(list->allocator, node); + cxFree(list->collection.allocator, node); node = next; } - cxFree(list->allocator, list); + cxFree(list->collection.allocator, list); } static cx_list_class cx_linked_list_class = { cx_ll_destructor, cx_ll_insert_element, cx_ll_insert_array, + cx_ll_insert_sorted, cx_ll_insert_iter, cx_ll_remove, cx_ll_clear, cx_ll_swap, cx_ll_at, - cx_ll_find, + cx_ll_find_remove, cx_ll_sort, cx_ll_compare, cx_ll_reverse, @@ -902,9 +1097,9 @@ }; CxList *cxLinkedListCreate( - CxAllocator const *allocator, + const CxAllocator *allocator, cx_compare_func comparator, - size_t item_size + size_t elem_size ) { if (allocator == NULL) { allocator = cxDefaultAllocator; @@ -912,16 +1107,8 @@ cx_linked_list *list = cxCalloc(allocator, 1, sizeof(cx_linked_list)); if (list == NULL) return NULL; - - list->base.cl = &cx_linked_list_class; - list->base.allocator = allocator; - list->base.cmpfunc = comparator; - - if (item_size > 0) { - list->base.item_size = item_size; - } else { - cxListStorePointers((CxList *) list); - } + cx_list_init((CxList*)list, &cx_linked_list_class, + allocator, comparator, elem_size); return (CxList *) list; }