Tue, 16 Jan 2024 23:43:27 +0100
improve program flow - relates to #353
/* * 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/list.h" #include <string.h> // <editor-fold desc="Store Pointers Functionality"> static _Thread_local cx_compare_func cx_pl_cmpfunc_impl; static int cx_pl_cmpfunc( void const *l, void const *r ) { void *const *lptr = l; void *const *rptr = r; void const *left = lptr == NULL ? NULL : *lptr; void const *right = rptr == NULL ? NULL : *rptr; return cx_pl_cmpfunc_impl(left, right); } static void cx_pl_hack_cmpfunc(struct cx_list_s const *list) { // cast away const - this is the hacky thing struct cx_list_s *l = (struct cx_list_s *) list; cx_pl_cmpfunc_impl = l->cmpfunc; l->cmpfunc = cx_pl_cmpfunc; } static void cx_pl_unhack_cmpfunc(struct cx_list_s const *list) { // cast away const - this is the hacky thing struct cx_list_s *l = (struct cx_list_s *) list; l->cmpfunc = cx_pl_cmpfunc_impl; } static void cx_pl_destructor(struct cx_list_s *list) { list->climpl->destructor(list); } static int cx_pl_insert_element( struct cx_list_s *list, size_t index, void const *element ) { return list->climpl->insert_element(list, index, &element); } static size_t cx_pl_insert_array( struct cx_list_s *list, size_t index, void const *array, size_t n ) { return list->climpl->insert_array(list, index, array, n); } static int cx_pl_insert_iter( struct cx_mut_iterator_s *iter, void const *elem, int prepend ) { struct cx_list_s *list = iter->src_handle; return list->climpl->insert_iter(iter, &elem, prepend); } static int cx_pl_remove( struct cx_list_s *list, size_t index ) { return list->climpl->remove(list, index); } static void cx_pl_clear(struct cx_list_s *list) { list->climpl->clear(list); } static int cx_pl_swap( struct cx_list_s *list, size_t i, size_t j ) { return list->climpl->swap(list, i, j); } static void *cx_pl_at( struct cx_list_s const *list, size_t index ) { void **ptr = list->climpl->at(list, index); return ptr == NULL ? NULL : *ptr; } static ssize_t cx_pl_find_remove( struct cx_list_s *list, void const *elem, bool remove ) { cx_pl_hack_cmpfunc(list); ssize_t ret = list->climpl->find_remove(list, &elem, remove); cx_pl_unhack_cmpfunc(list); return ret; } static void cx_pl_sort(struct cx_list_s *list) { cx_pl_hack_cmpfunc(list); list->climpl->sort(list); cx_pl_unhack_cmpfunc(list); } static int cx_pl_compare( struct cx_list_s const *list, struct cx_list_s const *other ) { cx_pl_hack_cmpfunc(list); int ret = list->climpl->compare(list, other); cx_pl_unhack_cmpfunc(list); return ret; } static void cx_pl_reverse(struct cx_list_s *list) { list->climpl->reverse(list); } static void *cx_pl_iter_current(void const *it) { struct cx_iterator_s const *iter = it; void **ptr = iter->base.current_impl(it); return ptr == NULL ? NULL : *ptr; } static struct cx_iterator_s cx_pl_iterator( struct cx_list_s const *list, size_t index, bool backwards ) { struct cx_iterator_s iter = list->climpl->iterator(list, index, backwards); iter.base.current_impl = iter.base.current; iter.base.current = cx_pl_iter_current; return iter; } static cx_list_class cx_pointer_list_class = { cx_pl_destructor, cx_pl_insert_element, cx_pl_insert_array, cx_pl_insert_iter, cx_pl_remove, cx_pl_clear, cx_pl_swap, cx_pl_at, cx_pl_find_remove, cx_pl_sort, cx_pl_compare, cx_pl_reverse, cx_pl_iterator, }; void cxListStoreObjects(CxList *list) { list->store_pointer = false; if (list->climpl != NULL) { list->cl = list->climpl; list->climpl = NULL; } } void cxListStorePointers(CxList *list) { list->item_size = sizeof(void *); list->store_pointer = true; list->climpl = list->cl; list->cl = &cx_pointer_list_class; } // </editor-fold> // <editor-fold desc="empty list implementation"> static void cx_emptyl_noop(__attribute__((__unused__)) CxList *list) { // this is a noop, but MUST be implemented } static void *cx_emptyl_at( __attribute__((__unused__)) struct cx_list_s const *list, __attribute__((__unused__)) size_t index ) { return NULL; } static ssize_t cx_emptyl_find_remove( __attribute__((__unused__)) struct cx_list_s *list, __attribute__((__unused__)) void const *elem, __attribute__((__unused__)) bool remove ) { return -1; } static int cx_emptyl_compare( __attribute__((__unused__)) struct cx_list_s const *list, struct cx_list_s const *other ) { if (other->size == 0) return 0; return -1; } static bool cx_emptyl_iter_valid(__attribute__((__unused__)) void const *iter) { return false; } static CxIterator cx_emptyl_iterator( struct cx_list_s const *list, size_t index, __attribute__((__unused__)) bool backwards ) { CxIterator iter = {0}; iter.src_handle = list; iter.index = index; iter.base.valid = cx_emptyl_iter_valid; return iter; } static cx_list_class cx_empty_list_class = { cx_emptyl_noop, NULL, NULL, NULL, NULL, cx_emptyl_noop, NULL, cx_emptyl_at, cx_emptyl_find_remove, cx_emptyl_noop, cx_emptyl_compare, cx_emptyl_noop, cx_emptyl_iterator, }; CxList cx_empty_list = { NULL, NULL, 0, 0, NULL, NULL, NULL, false, &cx_empty_list_class, NULL }; CxList *const cxEmptyList = &cx_empty_list; // </editor-fold> void cxListDestroy(CxList *list) { list->cl->destructor(list); } int cxListCompare( CxList const *list, CxList const *other ) { if ( // if one is storing pointers but the other is not (list->store_pointer ^ other->store_pointer) || // if one class is wrapped but the other is not ((list->climpl == NULL) ^ (other->climpl == NULL)) || // if the resolved compare functions are not the same ((list->climpl != NULL ? list->climpl->compare : list->cl->compare) != (other->climpl != NULL ? other->climpl->compare : other->cl->compare)) ) { // lists are definitely different - cannot use internal compare function if (list->size == other->size) { CxIterator left = list->cl->iterator(list, 0, false); CxIterator right = other->cl->iterator(other, 0, false); for (size_t i = 0; i < list->size; i++) { void *leftValue = cxIteratorCurrent(left); void *rightValue = cxIteratorCurrent(right); int d = list->cmpfunc(leftValue, rightValue); if (d != 0) { return d; } cxIteratorNext(left); cxIteratorNext(right); } return 0; } else { return list->size < other->size ? -1 : 1; } } else { // lists are compatible return list->cl->compare(list, other); } } CxMutIterator cxListMutIteratorAt( CxList *list, size_t index ) { CxIterator it = list->cl->iterator(list, index, false); it.base.mutating = true; // we know the iterators share the same memory layout CxMutIterator iter; memcpy(&iter, &it, sizeof(CxMutIterator)); return iter; } CxMutIterator cxListMutBackwardsIteratorAt( CxList *list, size_t index ) { CxIterator it = list->cl->iterator(list, index, true); it.base.mutating = true; // we know the iterators share the same memory layout CxMutIterator iter; memcpy(&iter, &it, sizeof(CxMutIterator)); return iter; }