src/list.c

Mon, 20 Mar 2023 19:09:08 +0100

author
Mike Becker <universe@uap-core.de>
date
Mon, 20 Mar 2023 19:09:08 +0100
changeset 666
b5dd654deb3b
parent 664
af5bf4603a5d
child 677
b09aae58bba4
permissions
-rw-r--r--

add unit test for cxListClear + fix destructor functions not always invoked with the correct pointer

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  *   1. Redistributions of source code must retain the above copyright
    10  *      notice, this list of conditions and the following disclaimer.
    11  *
    12  *   2. Redistributions in binary form must reproduce the above copyright
    13  *      notice, this list of conditions and the following disclaimer in the
    14  *      documentation and/or other materials provided with the distribution.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26  * POSSIBILITY OF SUCH DAMAGE.
    27  */
    29 #include "cx/list.h"
    31 #include <string.h>
    33 // <editor-fold desc="Store Pointers Functionality">
    35 static _Thread_local CxListComparator cx_pl_cmpfunc_impl;
    37 static int cx_pl_cmpfunc(
    38         void const *l,
    39         void const *r
    40 ) {
    41     void *const *lptr = l;
    42     void *const *rptr = r;
    43     void const *left = lptr == NULL ? NULL : *lptr;
    44     void const *right = rptr == NULL ? NULL : *rptr;
    45     return cx_pl_cmpfunc_impl(left, right);
    46 }
    48 static void cx_pl_hack_cmpfunc(struct cx_list_s const *list) {
    49     // cast away const - this is the hacky thing
    50     struct cx_list_s *l = (struct cx_list_s *) list;
    51     cx_pl_cmpfunc_impl = l->cmpfunc;
    52     l->cmpfunc = cx_pl_cmpfunc;
    53 }
    55 static void cx_pl_unhack_cmpfunc(struct cx_list_s const *list) {
    56     // cast away const - this is the hacky thing
    57     struct cx_list_s *l = (struct cx_list_s *) list;
    58     l->cmpfunc = cx_pl_cmpfunc_impl;
    59 }
    61 static void cx_pl_destructor(struct cx_list_s *list) {
    62     list->climpl->destructor(list);
    63 }
    65 static int cx_pl_insert_element(
    66         struct cx_list_s *list,
    67         size_t index,
    68         void const *element
    69 ) {
    70     return list->climpl->insert_element(list, index, &element);
    71 }
    73 static size_t cx_pl_insert_array(
    74         struct cx_list_s *list,
    75         size_t index,
    76         void const *array,
    77         size_t n
    78 ) {
    79     return list->climpl->insert_array(list, index, array, n);
    80 }
    82 static int cx_pl_insert_iter(
    83         struct cx_mut_iterator_s *iter,
    84         void const *elem,
    85         int prepend
    86 ) {
    87     struct cx_list_s *list = iter->src_handle;
    88     return list->climpl->insert_iter(iter, &elem, prepend);
    89 }
    91 static int cx_pl_remove(
    92         struct cx_list_s *list,
    93         size_t index
    94 ) {
    95     return list->climpl->remove(list, index);
    96 }
    98 static void cx_pl_clear(struct cx_list_s *list) {
    99     list->climpl->clear(list);
   100 }
   102 static int cx_pl_swap(
   103         struct cx_list_s *list,
   104         size_t i,
   105         size_t j
   106 ) {
   107     return list->climpl->swap(list, i, j);
   108 }
   110 static void *cx_pl_at(
   111         struct cx_list_s const *list,
   112         size_t index
   113 ) {
   114     void **ptr = list->climpl->at(list, index);
   115     return ptr == NULL ? NULL : *ptr;
   116 }
   118 static size_t cx_pl_find(
   119         struct cx_list_s const *list,
   120         void const *elem
   121 ) {
   122     cx_pl_hack_cmpfunc(list);
   123     size_t ret = list->climpl->find(list, &elem);
   124     cx_pl_unhack_cmpfunc(list);
   125     return ret;
   126 }
   128 static void cx_pl_sort(struct cx_list_s *list) {
   129     cx_pl_hack_cmpfunc(list);
   130     list->climpl->sort(list);
   131     cx_pl_unhack_cmpfunc(list);
   132 }
   134 static int cx_pl_compare(
   135         struct cx_list_s const *list,
   136         struct cx_list_s const *other
   137 ) {
   138     cx_pl_hack_cmpfunc(list);
   139     int ret = list->climpl->compare(list, other);
   140     cx_pl_unhack_cmpfunc(list);
   141     return ret;
   142 }
   144 static void cx_pl_reverse(struct cx_list_s *list) {
   145     list->climpl->reverse(list);
   146 }
   148 static void *cx_pl_iter_current(void const *it) {
   149     struct cx_iterator_s const *iter = it;
   150     void **ptr = iter->base.current_impl(it);
   151     return ptr == NULL ? NULL : *ptr;
   152 }
   154 static struct cx_iterator_s cx_pl_iterator(
   155         struct cx_list_s const *list,
   156         size_t index,
   157         bool backwards
   158 ) {
   159     struct cx_iterator_s iter = list->climpl->iterator(list, index, backwards);
   160     iter.base.current_impl = iter.base.current;
   161     iter.base.current = cx_pl_iter_current;
   162     return iter;
   163 }
   165 static cx_list_class cx_pointer_list_class = {
   166         cx_pl_destructor,
   167         cx_pl_insert_element,
   168         cx_pl_insert_array,
   169         cx_pl_insert_iter,
   170         cx_pl_remove,
   171         cx_pl_clear,
   172         cx_pl_swap,
   173         cx_pl_at,
   174         cx_pl_find,
   175         cx_pl_sort,
   176         cx_pl_compare,
   177         cx_pl_reverse,
   178         cx_pl_iterator,
   179 };
   181 void cxListStoreObjects(CxList *list) {
   182     if (list->climpl != NULL) {
   183         list->cl = list->climpl;
   184         list->climpl = NULL;
   185     }
   186 }
   188 void cxListStorePointers(CxList *list) {
   189     list->itemsize = sizeof(void *);
   190     list->climpl = list->cl;
   191     list->cl = &cx_pointer_list_class;
   192 }
   194 bool cxListIsStoringPointers(CxList const *list) {
   195     return list->climpl != NULL;
   196 }
   198 // </editor-fold>
   200 void cx_list_invoke_destructor(
   201         CxList const *list,
   202         void *elem
   203 ) {
   204     switch (list->content_destructor_type) {
   205         case CX_DESTRUCTOR_SIMPLE: {
   206             cx_list_invoke_simple_destructor(list, elem);
   207             break;
   208         }
   209         case CX_DESTRUCTOR_ADVANCED: {
   210             cx_list_invoke_advanced_destructor(list, elem);
   211             break;
   212         }
   213         case CX_DESTRUCTOR_NONE:
   214             break; // nothing
   215     }
   216 }
   218 void cx_list_invoke_simple_destructor(
   219         CxList const *list,
   220         void *elem
   221 ) {
   222     if (cxListIsStoringPointers(list)) {
   223         elem = *((void **) elem);
   224     }
   225     list->simple_destructor(elem);
   226 }
   228 void cx_list_invoke_advanced_destructor(
   229         CxList const *list,
   230         void *elem
   231 ) {
   232     if (cxListIsStoringPointers(list)) {
   233         elem = *((void **) elem);
   234     }
   235     list->advanced_destructor.func(list->advanced_destructor.data, elem);
   236 }
   238 void cxListDestroy(CxList *list) {
   239     switch (list->content_destructor_type) {
   240         case CX_DESTRUCTOR_SIMPLE: {
   241             CxIterator iter = cxListIterator(list);
   242             cx_foreach(void*, elem, iter) {
   243                 // already correctly resolved pointer - immediately invoke dtor
   244                 list->simple_destructor(elem);
   245             }
   246             break;
   247         }
   248         case CX_DESTRUCTOR_ADVANCED: {
   249             CxIterator iter = cxListIterator(list);
   250             cx_foreach(void*, elem, iter) {
   251                 // already correctly resolved pointer - immediately invoke dtor
   252                 list->advanced_destructor.func(list->advanced_destructor.data, elem);
   253             }
   254             break;
   255         }
   256         case CX_DESTRUCTOR_NONE:
   257             break; // nothing
   258     }
   260     list->cl->destructor(list);
   261     cxFree(list->allocator, list);
   262 }
   264 int cxListCompare(
   265         CxList const *list,
   266         CxList const *other
   267 ) {
   268     if (list->cl->compare == other->cl->compare) {
   269         // same compare function, lists are compatible
   270         return list->cl->compare(list, other);
   271     } else {
   272         // different compare functions, use iterator
   273         if (list->size == other->size) {
   274             CxIterator left = cxListIterator(list);
   275             CxIterator right = cxListIterator(other);
   276             for (size_t i = 0; i < list->size; i++) {
   277                 void *leftValue = cxIteratorCurrent(left);
   278                 void *rightValue = cxIteratorCurrent(right);
   279                 int d = list->cmpfunc(leftValue, rightValue);
   280                 if (d != 0) {
   281                     return d;
   282                 }
   283                 cxIteratorNext(left);
   284                 cxIteratorNext(right);
   285             }
   286             return 0;
   287         } else {
   288             return list->size < other->size ? -1 : 1;
   289         }
   290     }
   291 }
   293 CxMutIterator cxListMutIteratorAt(
   294         CxList *list,
   295         size_t index
   296 ) {
   297     CxIterator it = list->cl->iterator(list, index, false);
   298     it.base.mutating = true;
   300     // we know the iterators share the same memory layout
   301     CxMutIterator iter;
   302     memcpy(&iter, &it, sizeof(CxMutIterator));
   303     return iter;
   304 }
   306 CxMutIterator cxListMutBackwardsIteratorAt(
   307         CxList *list,
   308         size_t index
   309 ) {
   310     CxIterator it = list->cl->iterator(list, index, true);
   311     it.base.mutating = true;
   313     // we know the iterators share the same memory layout
   314     CxMutIterator iter;
   315     memcpy(&iter, &it, sizeof(CxMutIterator));
   316     return iter;
   317 }

mercurial