add cxListClear and fix missing destructor invocations - #241 #246

Tue, 14 Mar 2023 20:25:24 +0100

author
Mike Becker <universe@uap-core.de>
date
Tue, 14 Mar 2023 20:25:24 +0100
changeset 664
af5bf4603a5d
parent 663
d50b5dc1e058
child 665
c4041b07165e

add cxListClear and fix missing destructor invocations - #241 #246

src/array_list.c file | annotate | diff | comparison | revisions
src/cx/list.h file | annotate | diff | comparison | revisions
src/linked_list.c file | annotate | diff | comparison | revisions
src/list.c file | annotate | diff | comparison | revisions
     1.1 --- a/src/array_list.c	Sun Mar 05 10:55:32 2023 +0100
     1.2 +++ b/src/array_list.c	Tue Mar 14 20:25:24 2023 +0100
     1.3 @@ -263,11 +263,20 @@
     1.4          struct cx_list_s *list,
     1.5          size_t index
     1.6  ) {
     1.7 +    cx_array_list *arl = (cx_array_list *) list;
     1.8 +
     1.9      // out-of-bounds check
    1.10      if (index >= list->size) {
    1.11          return 1;
    1.12      }
    1.13  
    1.14 +    // content destruction
    1.15 +    if (list->content_destructor_type != CX_DESTRUCTOR_NONE) {
    1.16 +        char *ptr = arl->data;
    1.17 +        ptr += index * list->itemsize;
    1.18 +        cx_list_invoke_destructor(list, ptr);
    1.19 +    }
    1.20 +
    1.21      // short-circuit removal of last element
    1.22      if (index == list->size - 1) {
    1.23          list->size--;
    1.24 @@ -275,7 +284,6 @@
    1.25      }
    1.26  
    1.27      // just move the elements starting at index to the left
    1.28 -    cx_array_list *arl = (cx_array_list *) list;
    1.29      int result = cx_array_copy(
    1.30              &arl->data,
    1.31              &list->size,
    1.32 @@ -293,6 +301,33 @@
    1.33      return result;
    1.34  }
    1.35  
    1.36 +static void cx_arl_clear(struct cx_list_s *list) {
    1.37 +    if (list->size == 0) return;
    1.38 +
    1.39 +    cx_array_list *arl = (cx_array_list *) list;
    1.40 +    char *ptr = arl->data;
    1.41 +
    1.42 +    switch (list->content_destructor_type) {
    1.43 +        case CX_DESTRUCTOR_SIMPLE: {
    1.44 +            for (size_t i = 0; i < list->size; i++) {
    1.45 +                list->simple_destructor(ptr);
    1.46 +                ptr += list->itemsize;
    1.47 +            }
    1.48 +            break;
    1.49 +        }
    1.50 +        case CX_DESTRUCTOR_ADVANCED: {
    1.51 +            for (size_t i = 0; i < list->size; i++) {
    1.52 +                list->advanced_destructor.func(list->advanced_destructor.data,
    1.53 +                                               ptr);
    1.54 +                ptr += list->itemsize;
    1.55 +            }
    1.56 +            break;
    1.57 +        }
    1.58 +        case CX_DESTRUCTOR_NONE:
    1.59 +            break; // nothing
    1.60 +    }
    1.61 +}
    1.62 +
    1.63  static int cx_arl_swap(
    1.64          struct cx_list_s *list,
    1.65          size_t i,
    1.66 @@ -451,6 +486,7 @@
    1.67          cx_arl_insert_array,
    1.68          cx_arl_insert_iter,
    1.69          cx_arl_remove,
    1.70 +        cx_arl_clear,
    1.71          cx_arl_swap,
    1.72          cx_arl_at,
    1.73          cx_arl_find,
     2.1 --- a/src/cx/list.h	Sun Mar 05 10:55:32 2023 +0100
     2.2 +++ b/src/cx/list.h	Tue Mar 14 20:25:24 2023 +0100
     2.3 @@ -164,6 +164,11 @@
     2.4      );
     2.5  
     2.6      /**
     2.7 +     * Member function for removing all elements.
     2.8 +     */
     2.9 +    void (*clear)(struct cx_list_s *list);
    2.10 +
    2.11 +    /**
    2.12       * Member function for swapping two elements.
    2.13       */
    2.14      int (*swap)(
    2.15 @@ -222,6 +227,21 @@
    2.16  typedef struct cx_list_s CxList;
    2.17  
    2.18  /**
    2.19 + * Invokes the destructor function for a specific element.
    2.20 + *
    2.21 + * Usually only used by list implementations. There should be no need
    2.22 + * to invoke this function manually.
    2.23 + *
    2.24 + * @param list the list
    2.25 + * @param elem the element
    2.26 + */
    2.27 +__attribute__((__nonnull__))
    2.28 +void cx_list_invoke_destructor(
    2.29 +        struct cx_list_s const *list,
    2.30 +        void *elem
    2.31 +);
    2.32 +
    2.33 +/**
    2.34   * Advises the list to store copies of the objects (default mode of operation).
    2.35   *
    2.36   * Retrieving objects from this list will yield pointers to the copies stored
    2.37 @@ -398,6 +418,10 @@
    2.38  
    2.39  /**
    2.40   * Removes the element at the specified index.
    2.41 + *
    2.42 + * If an element destructor function is specified, it is called before
    2.43 + * removing the element.
    2.44 + *
    2.45   * @param list the list
    2.46   * @param index the index of the element
    2.47   * @return zero on success, non-zero if the index is out of bounds
    2.48 @@ -411,6 +435,19 @@
    2.49  }
    2.50  
    2.51  /**
    2.52 + * Removes all elements from this list.
    2.53 + *
    2.54 + * If an element destructor function is specified, it is called for each
    2.55 + * element before removing them.
    2.56 + *
    2.57 + * @param list the list
    2.58 + */
    2.59 +__attribute__((__nonnull__))
    2.60 +static inline void cxListClear(CxList *list) {
    2.61 +    list->cl->clear(list);
    2.62 +}
    2.63 +
    2.64 +/**
    2.65   * Swaps two items in the list.
    2.66   *
    2.67   * Implementations should only allocate temporary memory for the swap, if
     3.1 --- a/src/linked_list.c	Sun Mar 05 10:55:32 2023 +0100
     3.2 +++ b/src/linked_list.c	Tue Mar 14 20:25:24 2023 +0100
     3.3 @@ -569,6 +569,11 @@
     3.4      // out-of-bounds check
     3.5      if (node == NULL) return 1;
     3.6  
     3.7 +    // element destruction
     3.8 +    if (list->content_destructor_type != CX_DESTRUCTOR_NONE) {
     3.9 +        cx_list_invoke_destructor(list, node->payload);
    3.10 +    }
    3.11 +
    3.12      // remove
    3.13      cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end,
    3.14                            CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node);
    3.15 @@ -582,6 +587,48 @@
    3.16      return 0;
    3.17  }
    3.18  
    3.19 +static void cx_ll_clear(struct cx_list_s *list) {
    3.20 +    if (list->size == 0) return;
    3.21 +
    3.22 +    cx_linked_list *ll = (cx_linked_list *) list;
    3.23 +    cx_linked_list_node *node = ll->begin;
    3.24 +
    3.25 +    // looks super redundant, but avoids repeatedly checking
    3.26 +    // the destructor type for each element
    3.27 +    switch (list->content_destructor_type) {
    3.28 +        case CX_DESTRUCTOR_SIMPLE: {
    3.29 +            while (node != NULL) {
    3.30 +                list->simple_destructor(node->payload);
    3.31 +                cx_linked_list_node *next = node->next;
    3.32 +                cxFree(list->allocator, node);
    3.33 +                node = next;
    3.34 +            }
    3.35 +            break;
    3.36 +        }
    3.37 +        case CX_DESTRUCTOR_ADVANCED: {
    3.38 +            while (node != NULL) {
    3.39 +                list->advanced_destructor.func(list->advanced_destructor.data,
    3.40 +                                               node->payload);
    3.41 +                cx_linked_list_node *next = node->next;
    3.42 +                cxFree(list->allocator, node);
    3.43 +                node = next;
    3.44 +            }
    3.45 +            break;
    3.46 +        }
    3.47 +        case CX_DESTRUCTOR_NONE: {
    3.48 +            while (node != NULL) {
    3.49 +                cx_linked_list_node *next = node->next;
    3.50 +                cxFree(list->allocator, node);
    3.51 +                node = next;
    3.52 +            }
    3.53 +            break;
    3.54 +        }
    3.55 +    }
    3.56 +
    3.57 +    ll->begin = ll->end = NULL;
    3.58 +    list->size = 0;
    3.59 +}
    3.60 +
    3.61  #ifndef CX_LINKED_LIST_SWAP_SBO_SIZE
    3.62  #define CX_LINKED_LIST_SWAP_SBO_SIZE 16
    3.63  #endif
    3.64 @@ -753,13 +800,17 @@
    3.65      if (itbase->remove) {
    3.66          itbase->remove = false;
    3.67          struct cx_mut_iterator_s *iter = it;
    3.68 +        struct cx_list_s *list = iter->src_handle;
    3.69          cx_linked_list *ll = iter->src_handle;
    3.70          cx_linked_list_node *node = iter->elem_handle;
    3.71          iter->elem_handle = node->next;
    3.72 +        if (list->content_destructor_type != CX_DESTRUCTOR_NONE) {
    3.73 +            cx_list_invoke_destructor(list, node->payload);
    3.74 +        }
    3.75          cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end,
    3.76                                CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node);
    3.77 -        ll->base.size--;
    3.78 -        cxFree(ll->base.allocator, node);
    3.79 +        list->size--;
    3.80 +        cxFree(list->allocator, node);
    3.81      } else {
    3.82          struct cx_iterator_s *iter = it;
    3.83          iter->index++;
    3.84 @@ -773,14 +824,18 @@
    3.85      if (itbase->remove) {
    3.86          itbase->remove = false;
    3.87          struct cx_mut_iterator_s *iter = it;
    3.88 +        struct cx_list_s *list = iter->src_handle;
    3.89          cx_linked_list *ll = iter->src_handle;
    3.90          cx_linked_list_node *node = iter->elem_handle;
    3.91          iter->elem_handle = node->prev;
    3.92          iter->index--;
    3.93 +        if (list->content_destructor_type != CX_DESTRUCTOR_NONE) {
    3.94 +            cx_list_invoke_destructor(list, node->payload);
    3.95 +        }
    3.96          cx_linked_list_remove((void **) &ll->begin, (void **) &ll->end,
    3.97                                CX_LL_LOC_PREV, CX_LL_LOC_NEXT, node);
    3.98 -        ll->base.size--;
    3.99 -        cxFree(ll->base.allocator, node);
   3.100 +        list->size--;
   3.101 +        cxFree(list->allocator, node);
   3.102      } else {
   3.103          struct cx_iterator_s *iter = it;
   3.104          iter->index--;
   3.105 @@ -861,6 +916,7 @@
   3.106          cx_ll_insert_array,
   3.107          cx_ll_insert_iter,
   3.108          cx_ll_remove,
   3.109 +        cx_ll_clear,
   3.110          cx_ll_swap,
   3.111          cx_ll_at,
   3.112          cx_ll_find,
     4.1 --- a/src/list.c	Sun Mar 05 10:55:32 2023 +0100
     4.2 +++ b/src/list.c	Tue Mar 14 20:25:24 2023 +0100
     4.3 @@ -95,6 +95,10 @@
     4.4      return list->climpl->remove(list, index);
     4.5  }
     4.6  
     4.7 +static void cx_pl_clear(struct cx_list_s *list) {
     4.8 +    list->climpl->clear(list);
     4.9 +}
    4.10 +
    4.11  static int cx_pl_swap(
    4.12          struct cx_list_s *list,
    4.13          size_t i,
    4.14 @@ -164,6 +168,7 @@
    4.15          cx_pl_insert_array,
    4.16          cx_pl_insert_iter,
    4.17          cx_pl_remove,
    4.18 +        cx_pl_clear,
    4.19          cx_pl_swap,
    4.20          cx_pl_at,
    4.21          cx_pl_find,
    4.22 @@ -192,6 +197,24 @@
    4.23  
    4.24  // </editor-fold>
    4.25  
    4.26 +void cx_list_invoke_destructor(
    4.27 +        CxList const *list,
    4.28 +        void *elem
    4.29 +) {
    4.30 +    switch (list->content_destructor_type) {
    4.31 +        case CX_DESTRUCTOR_SIMPLE: {
    4.32 +            list->simple_destructor(elem);
    4.33 +            break;
    4.34 +        }
    4.35 +        case CX_DESTRUCTOR_ADVANCED: {
    4.36 +            list->advanced_destructor.func(list->advanced_destructor.data, elem);
    4.37 +            break;
    4.38 +        }
    4.39 +        case CX_DESTRUCTOR_NONE:
    4.40 +            break; // nothing
    4.41 +    }
    4.42 +}
    4.43 +
    4.44  void cxListDestroy(CxList *list) {
    4.45      switch (list->content_destructor_type) {
    4.46          case CX_DESTRUCTOR_SIMPLE: {

mercurial