add cx_linked_list_find()

Mon, 20 Dec 2021 13:01:38 +0100

author
Mike Becker <universe@uap-core.de>
date
Mon, 20 Dec 2021 13:01:38 +0100
changeset 480
e3be53a3354f
parent 479
a29bdd703e02
child 481
eef025d82a34

add cx_linked_list_find()

src/cx/linked_list.h file | annotate | diff | comparison | revisions
src/linked_list.c file | annotate | diff | comparison | revisions
--- a/src/cx/linked_list.h	Mon Dec 20 12:10:48 2021 +0100
+++ b/src/cx/linked_list.h	Mon Dec 20 13:01:38 2021 +0100
@@ -98,6 +98,22 @@
 __attribute__((__nonnull__));
 
 /**
+ * Finds the index of an element within a linked list.
+ *
+ * @param start a pointer to the start node
+ * @param loc_advance the location of the pointer to advance
+ * @param loc_data the location of the \c data pointer within your node struct
+ * @param follow_ptr \c false if the pointer denoted by \p loc_data shall be passed to the \p cmp_func.
+ * If \c true, the data at \p loc_data is assumed to be a pointer, dereferenced, and then passed to \p cmp_func.
+ * @param cmp_func a compare function to compare \p elem against the node data
+ * @param elem a pointer to the element to find
+ * @return the index of the element or a past-one index if the element could not be found
+ */
+size_t cx_linked_list_find(void *start, ptrdiff_t loc_advance, ptrdiff_t loc_data, int follow_ptr,
+                           CxListComparator cmp_func, void *elem)
+__attribute__((__nonnull__));
+
+/**
  * Finds the first node in a linked list.
  *
  * The function starts with the pointer denoted by \p node and traverses the list
@@ -226,7 +242,7 @@
  * @param loc_next the location of a \c next pointer within your node struct (required)
  * @param loc_data the location of the \c data pointer within your node struct
  * @param follow_ptr \c false if the pointer denoted by \p loc_data shall be passed to the \p cmp_func.
- * If \c true, the data at \p loc_data is dereferenced, assuming to be a pointer, and then passed to \p cmp_func.
+ * If \c true, the data at \p loc_data is assumed to be a pointer, dereferenced, and then passed to \p cmp_func.
  * @param cmp_func the compare function defining the sort order
  */
 void cx_linked_list_sort(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next,
--- a/src/linked_list.c	Mon Dec 20 12:10:48 2021 +0100
+++ b/src/linked_list.c	Mon Dec 20 13:01:38 2021 +0100
@@ -34,6 +34,10 @@
 /* LOW LEVEL LINKED LIST FUNCTIONS */
 
 #define CX_LL_PTR(cur, off) (*(void**)(((char*)cur)+off))
+#define ll_prev(node) CX_LL_PTR(node, loc_prev)
+#define ll_next(node) CX_LL_PTR(node, loc_next)
+#define ll_advance(node) CX_LL_PTR(node, loc_advance)
+#define ll_data(node) (follow_ptr?CX_LL_PTR(node, loc_data):(((char*)node)+loc_data))
 
 void *cx_linked_list_at(void *start, size_t start_index, ptrdiff_t loc_advance, size_t index) {
     assert(start != NULL);
@@ -41,12 +45,32 @@
     size_t i = start_index;
     void *cur = start;
     while (i != index && cur != NULL) {
-        cur = CX_LL_PTR(cur, loc_advance);
+        cur = ll_advance(cur);
         i < index ? i++ : i--;
     }
     return cur;
 }
 
+size_t cx_linked_list_find(void *start, ptrdiff_t loc_advance, ptrdiff_t loc_data, int follow_ptr,
+                           CxListComparator cmp_func, void *elem) {
+    assert(start != NULL);
+    assert(loc_advance >= 0);
+    assert(loc_data >= 0);
+    assert(cmp_func);
+
+    void *node = start;
+    size_t index = 0;
+    do {
+        void *current = ll_data(node);
+        if (cmp_func(current, elem) == 0) {
+            return index;
+        }
+        node = ll_advance(node);
+        index++;
+    } while (node != NULL);
+    return index;
+}
+
 void *cx_linked_list_first(void *node, ptrdiff_t loc_prev) {
     return cx_linked_list_last(node, loc_prev);
 }
@@ -59,7 +83,7 @@
     void *last;
     do {
         last = cur;
-    } while ((cur = CX_LL_PTR(cur, loc_next)) != NULL);
+    } while ((cur = ll_next(cur)) != NULL);
 
     return last;
 }
@@ -72,7 +96,7 @@
     void *cur = begin;
     void *next;
     while (1) {
-        next = CX_LL_PTR(cur, loc_next);
+        next = ll_next(cur);
         if (next == node) return cur;
         cur = next;
     }
@@ -81,7 +105,7 @@
 void cx_linked_list_add(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node) {
     assert(new_node != NULL);
     assert(loc_next >= 0);
-    assert(CX_LL_PTR(new_node, loc_next) == NULL);
+    assert(ll_next(new_node) == NULL);
     void *last;
     if (end == NULL) {
         assert(begin != NULL);
@@ -95,7 +119,7 @@
         }
     } else {
         // if there is a last node, update its next pointer
-        CX_LL_PTR(last, loc_next) = new_node;
+        ll_next(last) = new_node;
     }
 
     // if there is an end pointer, update it
@@ -105,15 +129,15 @@
 
     // if the nodes use a prev pointer, update it
     if (loc_prev >= 0) {
-        assert(CX_LL_PTR(new_node, loc_prev) == NULL);
-        CX_LL_PTR(new_node, loc_prev) = last;
+        assert(ll_prev(new_node) == NULL);
+        ll_prev(new_node) = last;
     }
 }
 
 void cx_linked_list_prepend(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next, void *new_node) {
     assert(new_node != NULL);
     assert(loc_next >= 0);
-    assert(CX_LL_PTR(new_node, loc_next) == NULL);
+    assert(ll_next(new_node) == NULL);
     void *first;
     if (begin == NULL) {
         assert(end != NULL);
@@ -127,14 +151,14 @@
             *end = new_node;
         }
     } else {
-        CX_LL_PTR(new_node, loc_next) = first;
+        ll_next(new_node) = first;
         if (loc_prev >= 0) {
-            CX_LL_PTR(first, loc_prev) = new_node;
+            ll_prev(first) = new_node;
         }
     }
 
     if (begin != NULL) {
-        assert(loc_prev < 0 || CX_LL_PTR(new_node, loc_prev) == NULL);
+        assert(loc_prev < 0 || ll_prev(new_node) == NULL);
         *begin = new_node;
     }
 }
@@ -145,10 +169,10 @@
     assert(loc_prev >= 0 || begin != NULL);
 
     // find adjacent nodes
-    void *next = CX_LL_PTR(node, loc_next);
+    void *next = ll_next(node);
     void *prev;
     if (loc_prev >= 0) {
-        prev = CX_LL_PTR(node, loc_prev);
+        prev = ll_prev(node);
     } else {
         prev = cx_linked_list_prev(*begin, loc_next, node);
     }
@@ -159,7 +183,7 @@
             *begin = next;
         }
     } else {
-        CX_LL_PTR(prev, loc_next) = next;
+        ll_next(prev) = next;
     }
 
     // update prev pointer of next node, or set end
@@ -168,7 +192,7 @@
             *end = prev;
         }
     } else if (loc_prev >= 0) {
-        CX_LL_PTR(next, loc_prev) = prev;
+        ll_prev(next) = prev;
     }
 }
 
@@ -176,16 +200,12 @@
     assert(loc_next >= 0);
     size_t size = 0;
     while (node != NULL) {
-        node = CX_LL_PTR(node, loc_next);
+        node = ll_next(node);
         size++;
     }
     return size;
 }
 
-#define ll_prev(node) CX_LL_PTR(node, loc_prev)
-#define ll_next(node) CX_LL_PTR(node, loc_next)
-#define ll_data(node) (follow_ptr?CX_LL_PTR(node, loc_data):(((char*)node)+loc_data))
-
 static void *cx_linked_list_sort_merge(ptrdiff_t loc_prev, ptrdiff_t loc_next,
                                        ptrdiff_t loc_data, int follow_ptr,
                                        size_t length, void *ls, void *le, void *re,
@@ -290,9 +310,6 @@
     }
 }
 
-#undef ll_next
-#undef ll_data
-
 void cx_linked_list_reverse(void **begin, void **end, ptrdiff_t loc_prev, ptrdiff_t loc_next) {
     assert(begin != NULL);
     assert(loc_next >= 0);
@@ -301,11 +318,11 @@
     void *prev = NULL;
     void *cur = *begin;
     while (cur != NULL) {
-        void *next = CX_LL_PTR(cur, loc_next);
+        void *next = ll_next(cur);
 
-        CX_LL_PTR(cur, loc_next) = prev;
+        ll_next(cur) = prev;
         if (loc_prev >= 0) {
-            CX_LL_PTR(cur, loc_prev) = next;
+            ll_prev(cur) = next;
         }
 
         prev = cur;
@@ -446,35 +463,15 @@
 }
 
 static size_t cx_ll_find(cx_list_s *list, void *elem) {
-    CxListComparator cmp = list->cmpfunc;
-    cx_linked_list *ll = (cx_linked_list *) list;
-
-    size_t index;
-    cx_linked_list_node *node = ll->begin;
-    for (index = 0; index < list->size; index++) {
-        void *current = node->payload;
-        if (cmp(current, elem) == 0) {
-            return index;
-        }
-        node = node->next;
-    }
-    return index;
+    return cx_linked_list_find(((cx_linked_list *) list)->begin,
+                               CX_LL_LOC_NEXT, CX_LL_LOC_DATA,
+                               0, list->cmpfunc, elem);
 }
 
 static size_t cx_pll_find(cx_list_s *list, void *elem) {
-    CxListComparator cmp = list->cmpfunc;
-    cx_linked_list *ll = (cx_linked_list *) list;
-
-    size_t index;
-    cx_linked_list_node *node = ll->begin;
-    for (index = 0; index < list->size; index++) {
-        void *current = *(void **) node->payload;
-        if (cmp(current, elem) == 0) {
-            return index;
-        }
-        node = node->next;
-    }
-    return index;
+    return cx_linked_list_find(((cx_linked_list *) list)->begin,
+                               CX_LL_LOC_NEXT, CX_LL_LOC_DATA,
+                               1, list->cmpfunc, elem);
 }
 
 static void cx_ll_sort(cx_list_s *list) {

mercurial