Tue, 14 Mar 2023 20:25:24 +0100
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: {