ucx/list.c

changeset 1040
473d8cb58a6c
parent 1016
ccde46662db7
--- a/ucx/list.c	Wed Dec 31 12:37:09 2025 +0100
+++ b/ucx/list.c	Wed Dec 31 16:40:12 2025 +0100
@@ -31,6 +31,12 @@
 #include <string.h>
 #include <assert.h>
 
+// we don't want to include the full array_list.h.
+// therefore, we only forward declare the one function we want to use
+CX_EXPORT void cx_array_qsort_c(void *array, size_t nmemb, size_t size,
+        cx_compare_func2 fn, void *context);
+
+
 int cx_list_compare_wrapper(const void *l, const void *r, void *c) {
     CxList *list = c;
     const void *left;
@@ -57,33 +63,33 @@
 
 // <editor-fold desc="empty list implementation">
 
-static void cx_emptyl_noop(cx_attr_unused CxList *list) {
+static void cx_emptyl_noop(CX_UNUSED CxList *list) {
     // this is a noop, but MUST be implemented
 }
 
 static void *cx_emptyl_at(
-        cx_attr_unused const struct cx_list_s *list,
-        cx_attr_unused size_t index
+        CX_UNUSED const struct cx_list_s *list,
+        CX_UNUSED size_t index
 ) {
     return NULL;
 }
 
 static size_t cx_emptyl_find_remove(
-        cx_attr_unused struct cx_list_s *list,
-        cx_attr_unused const void *elem,
-        cx_attr_unused bool remove
+        CX_UNUSED struct cx_list_s *list,
+        CX_UNUSED const void *elem,
+        CX_UNUSED bool remove
 ) {
     return 0;
 }
 
-static bool cx_emptyl_iter_valid(cx_attr_unused const void *iter) {
+static bool cx_emptyl_iter_valid(CX_UNUSED const void *iter) {
     return false;
 }
 
 static CxIterator cx_emptyl_iterator(
         const struct cx_list_s *list,
         size_t index,
-        cx_attr_unused bool backwards
+        CX_UNUSED bool backwards
 ) {
     CxIterator iter = {0};
     iter.src_handle = (void*) list;
@@ -141,8 +147,7 @@
     const char *src = data;
     size_t i = 0;
     for (; i < n; i++) {
-        if (NULL == list->cl->insert_element(list, index + i, src)
-        ) {
+        if (NULL == list->cl->insert_element(list, index + i, src)) {
             return i; // LCOV_EXCL_LINE
         }
         if (src != NULL) {
@@ -283,12 +288,6 @@
     return cx_list_default_insert_sorted_impl(list, sorted_data, n, false);
 }
 
-// TODO: remove this hack once we have a solution for qsort() / qsort_s()
-static _Thread_local CxList *cx_hack_for_qsort_list;
-static int cx_hack_cmp_for_qsort(const void *l, const void *r) {
-    return cx_list_compare_wrapper(l, r, cx_hack_for_qsort_list);
-}
-
 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;
@@ -304,9 +303,7 @@
     }
 
     // qsort
-    // TODO: qsort_s() is not as nice as we thought
-    cx_hack_for_qsort_list = list;
-    qsort(tmp, list_size, elem_size, cx_hack_cmp_for_qsort);
+    cx_array_qsort_c(tmp, list_size, elem_size, cx_list_compare_wrapper, list);
 
     // copy elements back
     loc = tmp;
@@ -341,6 +338,13 @@
     return 0;
 }
 
+static int cx_list_cmpfunc2_safe_memcmp(const void *a, const void *b, void *c) {
+    // it is not safe to store a pointer to the size in the list
+    // because the entire list structure might get reallocated
+    size_t elem_size = (size_t)(uintptr_t)c;
+    return memcmp(a, b, elem_size);
+}
+
 void cx_list_init(
     struct cx_list_s *list,
     struct cx_list_class_s *cl,
@@ -354,8 +358,8 @@
     if (elem_size > 0) {
         list->collection.elem_size = elem_size;
         list->collection.simple_cmp = NULL;
-        list->collection.advanced_cmp = cx_acmp_memcmp;
-        list->collection.cmp_data = &list->collection.elem_size;
+        list->collection.advanced_cmp = cx_list_cmpfunc2_safe_memcmp;
+        list->collection.cmp_data = (void*)(uintptr_t)list->collection.elem_size;
         list->collection.store_pointer = false;
     } else {
         list->collection.elem_size = sizeof(void *);

mercurial