add stupid default implementation for high level insertion sort

Sun, 01 Sep 2024 14:48:43 +0200

author
Mike Becker <universe@uap-core.de>
date
Sun, 01 Sep 2024 14:48:43 +0200
changeset 876
f4ce7df9cff0
parent 875
ee84ac776cbc
child 877
608b14deea18

add stupid default implementation for high level insertion sort

relates to #418

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.c file | annotate | diff | comparison | revisions
--- a/src/array_list.c	Thu Aug 29 21:30:52 2024 +0200
+++ b/src/array_list.c	Sun Sep 01 14:48:43 2024 +0200
@@ -521,6 +521,7 @@
         cx_arl_destructor,
         cx_arl_insert_element,
         cx_arl_insert_array,
+        cx_list_default_insert_sorted,
         cx_arl_insert_iter,
         cx_arl_remove,
         cx_arl_clear,
--- a/src/cx/list.h	Thu Aug 29 21:30:52 2024 +0200
+++ b/src/cx/list.h	Sun Sep 01 14:48:43 2024 +0200
@@ -98,6 +98,17 @@
     );
 
     /**
+     * Member function for inserting sorted elements into a sorted list.
+     *
+     * @see cx_list_default_insert_sorted()
+     */
+    size_t (*insert_sorted)(
+            struct cx_list_s *list,
+            void const *sorted_data,
+            size_t n
+    );
+
+    /**
      * Member function for inserting an element relative to an iterator position.
      */
     int (*insert_iter)(
@@ -200,6 +211,29 @@
 );
 
 /**
+ * Default implementation of a sorted insert.
+ *
+ * This function uses the array insert function to insert consecutive groups
+ * of sorted data.
+ *
+ * The source data \em must already be sorted wrt. the list's compare function.
+ *
+ * Use this in your own list class if you do not want to implement an optimized
+ * version for your list.
+ *
+ * @param list the list
+ * @param sorted_data a pointer to the array of pre-sorted data to insert
+ * @param n the number of elements to insert
+ * @return the number of elements actually inserted
+ */
+__attribute__((__nonnull__))
+size_t cx_list_default_insert_sorted(
+        struct cx_list_s *list,
+        void const *sorted_data,
+        size_t n
+);
+
+/**
  * Default unoptimized sort implementation.
  *
  * This function will copy all data to an array, sort the array with standard
@@ -345,6 +379,22 @@
 }
 
 /**
+ * Inserts an item into a sorted list.
+ *
+ * @param list the list
+ * @param elem a pointer to the element to add
+ * @return zero on success, non-zero on memory allocation failure
+ */
+__attribute__((__nonnull__))
+static inline int cxListInsertSorted(
+        CxList *list,
+        void const *elem
+) {
+    void const *data = list->collection.store_pointer ? &elem : elem;
+    return list->cl->insert_sorted(list, data, 1) == 0;
+}
+
+/**
  * Inserts multiple items to the list at the specified index.
  * If \p index equals the list size, this is effectively cxListAddArray().
  *
@@ -374,6 +424,32 @@
 }
 
 /**
+ * Inserts a sorted array into a sorted list.
+ *
+ * This method is usually more efficient than inserting each element separately,
+ * because consecutive chunks of sorted data are inserted in one pass.
+ *
+ * If there is not enough memory to add all elements, the returned value is
+ * less than \p n.
+ *
+ * If this list is storing pointers instead of objects \p array is expected to
+ * be an array of pointers.
+ *
+ * @param list the list
+ * @param array a pointer to the elements to add
+ * @param n the number of elements to add
+ * @return the number of added elements
+ */
+__attribute__((__nonnull__))
+static inline size_t cxListInsertSortedArray(
+        CxList *list,
+        void const *array,
+        size_t n
+) {
+    return list->cl->insert_sorted(list, array, n);
+}
+
+/**
  * Inserts an element after the current location of the specified iterator.
  *
  * The used iterator remains operational, but all other active iterators should
--- a/src/linked_list.c	Thu Aug 29 21:30:52 2024 +0200
+++ b/src/linked_list.c	Sun Sep 01 14:48:43 2024 +0200
@@ -927,6 +927,7 @@
         cx_ll_destructor,
         cx_ll_insert_element,
         cx_ll_insert_array,
+        cx_list_default_insert_sorted,
         cx_ll_insert_iter,
         cx_ll_remove,
         cx_ll_clear,
--- a/src/list.c	Thu Aug 29 21:30:52 2024 +0200
+++ b/src/list.c	Sun Sep 01 14:48:43 2024 +0200
@@ -79,6 +79,17 @@
     return list->climpl->insert_array(list, index, array, n);
 }
 
+static size_t cx_pl_insert_sorted(
+        struct cx_list_s *list,
+        void const *array,
+        size_t n
+) {
+    cx_pl_hack_cmpfunc(list);
+    size_t result = list->climpl->insert_sorted(list, array, n);
+    cx_pl_unhack_cmpfunc(list);
+    return result;
+}
+
 static int cx_pl_insert_iter(
         struct cx_iterator_s *iter,
         void const *elem,
@@ -167,6 +178,7 @@
         cx_pl_destructor,
         cx_pl_insert_element,
         cx_pl_insert_array,
+        cx_pl_insert_sorted,
         cx_pl_insert_iter,
         cx_pl_remove,
         cx_pl_clear,
@@ -239,6 +251,7 @@
         NULL,
         NULL,
         NULL,
+        NULL,
         cx_emptyl_noop,
         NULL,
         cx_emptyl_at,
@@ -290,6 +303,21 @@
     return i;
 }
 
+size_t cx_list_default_insert_sorted(
+        struct cx_list_s *list,
+        void const *sorted_data,
+        size_t n
+) {
+    size_t elem_size = list->collection.elem_size;
+    cx_compare_func cmp = list->collection.cmpfunc;
+    char const *src = sorted_data;
+
+    size_t r = cx_list_default_insert_array(list, 0, src, n);
+    cx_list_default_sort(list);
+
+    return r;
+}
+
 void cx_list_default_sort(struct cx_list_s *list) {
     size_t elem_size = list->collection.elem_size;
     size_t list_size = list->collection.size;
--- a/tests/test_list.c	Thu Aug 29 21:30:52 2024 +0200
+++ b/tests/test_list.c	Sun Sep 01 14:48:43 2024 +0200
@@ -962,6 +962,7 @@
     cx_list_class const *cl = list->climpl == NULL ? list->cl : list->climpl;
     memcpy(defaulted_cl, cl, sizeof(cx_list_class));
     defaulted_cl->insert_array = cx_list_default_insert_array;
+    defaulted_cl->insert_sorted = cx_list_default_insert_sorted;
     defaulted_cl->sort = cx_list_default_sort;
     defaulted_cl->swap = cx_list_default_swap;
     defaulted_cl->compare = NULL;
@@ -1099,6 +1100,54 @@
     CX_TEST_ASSERT(*(int *) cxListAt(list, 9) == 42);
 })
 
+roll_out_test_combos_with_defaulted_funcs(insert_sorted, {
+    int d1 = 50;
+    int d2 = 80;
+    int d3 = 60;
+    int d4 = 40;
+    int d5 = 70;
+    int d6a[6] = array_init(52, 54, 56, 62, 64, 75);
+    int d7a[6] = array_init(51, 57, 58, 65, 77, 78);
+    int d8 = 90;
+    int *d6ptr[6];
+    int *d7ptr[6];
+    cx_for_n(i, 6)
+    {
+        d6ptr[i] = &d6a[i];
+        d7ptr[i] = &d7a[i];
+    }
+    size_t inserted;
+    int expected[18] = array_init(
+            40, 50, 51, 52, 54, 56, 57, 58, 60,
+            62, 64, 65, 70, 75, 77, 78, 80, 90
+    );
+
+    CX_TEST_ASSERT(0 == cxListInsertSorted(list, &d1));
+    CX_TEST_ASSERT(0 == cxListInsertSorted(list, &d2));
+    CX_TEST_ASSERT(0 == cxListInsertSorted(list, &d3));
+    CX_TEST_ASSERT(0 == cxListInsertSorted(list, &d4));
+    CX_TEST_ASSERT(0 == cxListInsertSorted(list, &d5));
+    if (isptrlist) {
+        inserted = cxListInsertSortedArray(list, d6ptr, 6);
+    } else {
+        inserted = cxListInsertSortedArray(list, d6a, 6);
+    }
+    CX_TEST_ASSERT(inserted == 6);
+    if (isptrlist) {
+        inserted = cxListInsertSortedArray(list, d7ptr, 6);
+    } else {
+        inserted = cxListInsertSortedArray(list, d7a, 6);
+    }
+    CX_TEST_ASSERT(inserted == 6);
+    CX_TEST_ASSERT(0 == cxListInsertSorted(list, &d8));
+
+    CX_TEST_ASSERT(cxListSize(list) == 18);
+    cx_for_n(i, 18)
+    {
+        CX_TEST_ASSERT(*(int *) cxListAt(list, i) == expected[i]);
+    }
+})
+
 roll_out_test_combos(remove, {
     const size_t testdata_len = 32;
     int *testdata = int_test_data_added_to_list(list, isptrlist, testdata_len);
@@ -1499,6 +1548,8 @@
     cx_test_register(suite, test_list_parl_insert);
     cx_test_register(suite, test_list_arl_insert_array);
     cx_test_register(suite, test_list_parl_insert_array);
+    cx_test_register(suite, test_list_arl_insert_sorted);
+    cx_test_register(suite, test_list_parl_insert_sorted);
     cx_test_register(suite, test_list_arl_remove);
     cx_test_register(suite, test_list_parl_remove);
     cx_test_register(suite, test_list_arl_find_remove);
@@ -1542,6 +1593,8 @@
 
     cx_test_register(suite, test_list_arlm_insert_array);
     cx_test_register(suite, test_list_parlm_insert_array);
+    cx_test_register(suite, test_list_arlm_insert_sorted);
+    cx_test_register(suite, test_list_parlm_insert_sorted);
     cx_test_register(suite, test_list_arlm_swap);
     cx_test_register(suite, test_list_parlm_swap);
     cx_test_register(suite, test_list_arlm_sort);
@@ -1589,6 +1642,8 @@
     cx_test_register(suite, test_list_pll_insert);
     cx_test_register(suite, test_list_ll_insert_array);
     cx_test_register(suite, test_list_pll_insert_array);
+    cx_test_register(suite, test_list_ll_insert_sorted);
+    cx_test_register(suite, test_list_pll_insert_sorted);
     cx_test_register(suite, test_list_ll_remove);
     cx_test_register(suite, test_list_pll_remove);
     cx_test_register(suite, test_list_ll_find_remove);
@@ -1632,6 +1687,8 @@
 
     cx_test_register(suite, test_list_llm_insert_array);
     cx_test_register(suite, test_list_pllm_insert_array);
+    cx_test_register(suite, test_list_llm_insert_sorted);
+    cx_test_register(suite, test_list_pllm_insert_sorted);
     cx_test_register(suite, test_list_llm_swap);
     cx_test_register(suite, test_list_pllm_swap);
     cx_test_register(suite, test_list_llm_sort);

mercurial