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

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 665
c4041b07165e
child 667
2f88a7c13a28

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

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
tests/test_list.cpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/array_list.c	Mon Mar 20 18:05:12 2023 +0100
     1.2 +++ b/src/array_list.c	Mon Mar 20 19:09:08 2023 +0100
     1.3 @@ -310,15 +310,14 @@
     1.4      switch (list->content_destructor_type) {
     1.5          case CX_DESTRUCTOR_SIMPLE: {
     1.6              for (size_t i = 0; i < list->size; i++) {
     1.7 -                list->simple_destructor(ptr);
     1.8 +                cx_list_invoke_simple_destructor(list, ptr);
     1.9                  ptr += list->itemsize;
    1.10              }
    1.11              break;
    1.12          }
    1.13          case CX_DESTRUCTOR_ADVANCED: {
    1.14              for (size_t i = 0; i < list->size; i++) {
    1.15 -                list->advanced_destructor.func(list->advanced_destructor.data,
    1.16 -                                               ptr);
    1.17 +                cx_list_invoke_advanced_destructor(list, ptr);
    1.18                  ptr += list->itemsize;
    1.19              }
    1.20              break;
    1.21 @@ -326,6 +325,9 @@
    1.22          case CX_DESTRUCTOR_NONE:
    1.23              break; // nothing
    1.24      }
    1.25 +
    1.26 +    memset(arl->data, 0, list->size * list->itemsize);
    1.27 +    list->size = 0;
    1.28  }
    1.29  
    1.30  static int cx_arl_swap(
     2.1 --- a/src/cx/list.h	Mon Mar 20 18:05:12 2023 +0100
     2.2 +++ b/src/cx/list.h	Mon Mar 20 19:09:08 2023 +0100
     2.3 @@ -227,7 +227,7 @@
     2.4  typedef struct cx_list_s CxList;
     2.5  
     2.6  /**
     2.7 - * Invokes the destructor function for a specific element.
     2.8 + * Invokes the configured destructor function for a specific element.
     2.9   *
    2.10   * Usually only used by list implementations. There should be no need
    2.11   * to invoke this function manually.
    2.12 @@ -242,6 +242,36 @@
    2.13  );
    2.14  
    2.15  /**
    2.16 + * Invokes the simple destructor function for a specific element.
    2.17 + *
    2.18 + * Usually only used by list implementations. There should be no need
    2.19 + * to invoke this function manually.
    2.20 + *
    2.21 + * @param list the list
    2.22 + * @param elem the element
    2.23 + */
    2.24 +__attribute__((__nonnull__))
    2.25 +void cx_list_invoke_simple_destructor(
    2.26 +        struct cx_list_s const *list,
    2.27 +        void *elem
    2.28 +);
    2.29 +
    2.30 +/**
    2.31 + * Invokes the advanced destructor function for a specific element.
    2.32 + *
    2.33 + * Usually only used by list implementations. There should be no need
    2.34 + * to invoke this function manually.
    2.35 + *
    2.36 + * @param list the list
    2.37 + * @param elem the element
    2.38 + */
    2.39 +__attribute__((__nonnull__))
    2.40 +void cx_list_invoke_advanced_destructor(
    2.41 +        struct cx_list_s const *list,
    2.42 +        void *elem
    2.43 +);
    2.44 +
    2.45 +/**
    2.46   * Advises the list to store copies of the objects (default mode of operation).
    2.47   *
    2.48   * Retrieving objects from this list will yield pointers to the copies stored
    2.49 @@ -276,7 +306,7 @@
    2.50   * @see cxListStorePointers()
    2.51   */
    2.52  __attribute__((__nonnull__))
    2.53 -bool cxListIsStoringPointers(CxList *list);
    2.54 +bool cxListIsStoringPointers(CxList const *list);
    2.55  
    2.56  /**
    2.57   * Adds an item to the end of the list.
     3.1 --- a/src/linked_list.c	Mon Mar 20 18:05:12 2023 +0100
     3.2 +++ b/src/linked_list.c	Mon Mar 20 19:09:08 2023 +0100
     3.3 @@ -598,7 +598,7 @@
     3.4      switch (list->content_destructor_type) {
     3.5          case CX_DESTRUCTOR_SIMPLE: {
     3.6              while (node != NULL) {
     3.7 -                list->simple_destructor(node->payload);
     3.8 +                cx_list_invoke_simple_destructor(list, node->payload);
     3.9                  cx_linked_list_node *next = node->next;
    3.10                  cxFree(list->allocator, node);
    3.11                  node = next;
    3.12 @@ -607,8 +607,7 @@
    3.13          }
    3.14          case CX_DESTRUCTOR_ADVANCED: {
    3.15              while (node != NULL) {
    3.16 -                list->advanced_destructor.func(list->advanced_destructor.data,
    3.17 -                                               node->payload);
    3.18 +                cx_list_invoke_advanced_destructor(list, node->payload);
    3.19                  cx_linked_list_node *next = node->next;
    3.20                  cxFree(list->allocator, node);
    3.21                  node = next;
     4.1 --- a/src/list.c	Mon Mar 20 18:05:12 2023 +0100
     4.2 +++ b/src/list.c	Mon Mar 20 19:09:08 2023 +0100
     4.3 @@ -191,7 +191,7 @@
     4.4      list->cl = &cx_pointer_list_class;
     4.5  }
     4.6  
     4.7 -bool cxListIsStoringPointers(CxList *list) {
     4.8 +bool cxListIsStoringPointers(CxList const *list) {
     4.9      return list->climpl != NULL;
    4.10  }
    4.11  
    4.12 @@ -203,11 +203,11 @@
    4.13  ) {
    4.14      switch (list->content_destructor_type) {
    4.15          case CX_DESTRUCTOR_SIMPLE: {
    4.16 -            list->simple_destructor(elem);
    4.17 +            cx_list_invoke_simple_destructor(list, elem);
    4.18              break;
    4.19          }
    4.20          case CX_DESTRUCTOR_ADVANCED: {
    4.21 -            list->advanced_destructor.func(list->advanced_destructor.data, elem);
    4.22 +            cx_list_invoke_advanced_destructor(list, elem);
    4.23              break;
    4.24          }
    4.25          case CX_DESTRUCTOR_NONE:
    4.26 @@ -215,11 +215,32 @@
    4.27      }
    4.28  }
    4.29  
    4.30 +void cx_list_invoke_simple_destructor(
    4.31 +        CxList const *list,
    4.32 +        void *elem
    4.33 +) {
    4.34 +    if (cxListIsStoringPointers(list)) {
    4.35 +        elem = *((void **) elem);
    4.36 +    }
    4.37 +    list->simple_destructor(elem);
    4.38 +}
    4.39 +
    4.40 +void cx_list_invoke_advanced_destructor(
    4.41 +        CxList const *list,
    4.42 +        void *elem
    4.43 +) {
    4.44 +    if (cxListIsStoringPointers(list)) {
    4.45 +        elem = *((void **) elem);
    4.46 +    }
    4.47 +    list->advanced_destructor.func(list->advanced_destructor.data, elem);
    4.48 +}
    4.49 +
    4.50  void cxListDestroy(CxList *list) {
    4.51      switch (list->content_destructor_type) {
    4.52          case CX_DESTRUCTOR_SIMPLE: {
    4.53              CxIterator iter = cxListIterator(list);
    4.54              cx_foreach(void*, elem, iter) {
    4.55 +                // already correctly resolved pointer - immediately invoke dtor
    4.56                  list->simple_destructor(elem);
    4.57              }
    4.58              break;
    4.59 @@ -227,6 +248,7 @@
    4.60          case CX_DESTRUCTOR_ADVANCED: {
    4.61              CxIterator iter = cxListIterator(list);
    4.62              cx_foreach(void*, elem, iter) {
    4.63 +                // already correctly resolved pointer - immediately invoke dtor
    4.64                  list->advanced_destructor.func(list->advanced_destructor.data, elem);
    4.65              }
    4.66              break;
     5.1 --- a/tests/test_list.cpp	Mon Mar 20 18:05:12 2023 +0100
     5.2 +++ b/tests/test_list.cpp	Mon Mar 20 19:09:08 2023 +0100
     5.3 @@ -38,6 +38,19 @@
     5.4  #include <unordered_set>
     5.5  #include <algorithm>
     5.6  
     5.7 +struct testdatastruct {
     5.8 +    int x;
     5.9 +    void *ptr;
    5.10 +};
    5.11 +
    5.12 +static void free_testdatastruct(
    5.13 +        void *a,
    5.14 +        void *s
    5.15 +) {
    5.16 +    auto al = reinterpret_cast<CxTestingAllocator *>(a);
    5.17 +    cxFree(al, reinterpret_cast<testdatastruct *>(s)->ptr);
    5.18 +}
    5.19 +
    5.20  struct node {
    5.21      node *next = nullptr;
    5.22      node *prev = nullptr;
    5.23 @@ -697,6 +710,21 @@
    5.24          EXPECT_NE(cxListRemove(list, testdata_len), 0);
    5.25      }
    5.26  
    5.27 +    void verifyClear(CxList *list) {
    5.28 +        // use the testing allocator for testing the destructor function
    5.29 +        list->content_destructor_type = CX_DESTRUCTOR_ADVANCED;
    5.30 +        list->advanced_destructor.func = free_testdatastruct;
    5.31 +        list->advanced_destructor.data = &testingAllocator;
    5.32 +
    5.33 +        testdatastruct s[10];
    5.34 +        for (auto &t: s) {
    5.35 +            t.ptr = cxMalloc(&testingAllocator, 16);
    5.36 +            cxListAdd(list, &t);
    5.37 +        }
    5.38 +
    5.39 +        cxListClear(list);
    5.40 +    }
    5.41 +
    5.42      static void verifySwap(CxList *list) {
    5.43          ASSERT_EQ(list->size, 0);
    5.44  
    5.45 @@ -997,6 +1025,20 @@
    5.46      verifyRemove(arrayListFromTestData());
    5.47  }
    5.48  
    5.49 +TEST_F(LinkedList, cxListClear) {
    5.50 +    verifyClear(autofree(cxLinkedListCreateSimple(sizeof(testdatastruct))));
    5.51 +}
    5.52 +
    5.53 +TEST_F(PointerLinkedList, cxListClear) {
    5.54 +    auto l = cxLinkedListCreateSimple(sizeof(testdatastruct));
    5.55 +    cxListStorePointers(l);
    5.56 +    verifyClear(autofree(l));
    5.57 +}
    5.58 +
    5.59 +TEST_F(ArrayList, cxListClear) {
    5.60 +    verifyClear(autofree(cxArrayListCreateSimple(sizeof(testdatastruct), 8)));
    5.61 +}
    5.62 +
    5.63  TEST_F(LinkedList, cxListSwap) {
    5.64      verifySwap(autofree(cxLinkedListCreate(&testingAllocator, cx_cmp_int, sizeof(int))));
    5.65  }

mercurial