src/cx/linked_list.h

Mon, 18 Dec 2023 18:22:53 +0100

author
Mike Becker <universe@uap-core.de>
date
Mon, 18 Dec 2023 18:22:53 +0100
changeset 764
ccbdbd088455
parent 763
741a2040fa33
child 807
c8d692131b1e
permissions
-rw-r--r--

add cxListFindRemove and cx_linked_list_find_node

resolves #339

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  *   1. Redistributions of source code must retain the above copyright
    10  *      notice, this list of conditions and the following disclaimer.
    11  *
    12  *   2. Redistributions in binary form must reproduce the above copyright
    13  *      notice, this list of conditions and the following disclaimer in the
    14  *      documentation and/or other materials provided with the distribution.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26  * POSSIBILITY OF SUCH DAMAGE.
    27  */
    28 /**
    29  * \file linked_list.h
    30  * \brief Linked list implementation.
    31  * \details Also provides several low-level functions for custom linked list implementations.
    32  * \author Mike Becker
    33  * \author Olaf Wintermann
    34  * \copyright 2-Clause BSD License
    35  */
    37 #ifndef UCX_LINKED_LIST_H
    38 #define UCX_LINKED_LIST_H
    40 #include "common.h"
    41 #include "list.h"
    43 #ifdef __cplusplus
    44 extern "C" {
    45 #endif
    47 /**
    48  * Set this flag to true, if you want to disable the use of SBO for
    49  * linked list swap operations.
    50  */
    51 extern bool CX_DISABLE_LINKED_LIST_SWAP_SBO;
    53 /**
    54  * Allocates a linked list for storing elements with \p item_size bytes each.
    55  *
    56  * If \p item_size is CX_STORE_POINTERS, the created list will be created as if
    57  * cxListStorePointers() was called immediately after creation and the compare
    58  * function will be automatically set to cx_cmp_ptr(), if none is given.
    59  *
    60  * @param allocator the allocator for allocating the list nodes
    61  * (if \c NULL the cxDefaultAllocator will be used)
    62  * @param comparator the comparator for the elements
    63  * (if \c NULL, and the list is not storing pointers, sort and find
    64  * functions will not work)
    65  * @param item_size the size of each element in bytes
    66  * @return the created list
    67  */
    68 CxList *cxLinkedListCreate(
    69         CxAllocator const *allocator,
    70         cx_compare_func comparator,
    71         size_t item_size
    72 );
    74 /**
    75  * Allocates a linked list for storing elements with \p item_size bytes each.
    76  *
    77  * The list will use cxDefaultAllocator and no comparator function. If you want
    78  * to call functions that need a comparator, you must either set one immediately
    79  * after list creation or use cxLinkedListCreate().
    80  *
    81  * If \p item_size is CX_STORE_POINTERS, the created list will be created as if
    82  * cxListStorePointers() was called immediately after creation and the compare
    83  * function will be automatically set to cx_cmp_ptr().
    84  *
    85  * @param item_size the size of each element in bytes
    86  * @return the created list
    87  */
    88 #define cxLinkedListCreateSimple(item_size) \
    89     cxLinkedListCreate(NULL, NULL, item_size)
    91 /**
    92  * Finds the node at a certain index.
    93  *
    94  * This function can be used to start at an arbitrary position within the list.
    95  * If the search index is large than the start index, \p loc_advance must denote
    96  * the location of some sort of \c next pointer (i.e. a pointer to the next node).
    97  * But it is also possible that the search index is smaller than the start index
    98  * (e.g. in cases where traversing a list backwards is faster) in which case
    99  * \p loc_advance must denote the location of some sort of \c prev pointer
   100  * (i.e. a pointer to the previous node).
   101  *
   102  * @param start a pointer to the start node
   103  * @param start_index the start index
   104  * @param loc_advance the location of the pointer to advance
   105  * @param index the search index
   106  * @return the node found at the specified index
   107  */
   108 void *cx_linked_list_at(
   109         void const *start,
   110         size_t start_index,
   111         ptrdiff_t loc_advance,
   112         size_t index
   113 ) __attribute__((__nonnull__));
   115 /**
   116  * Finds the index of an element within a linked list.
   117  *
   118  * @param start a pointer to the start node
   119  * @param loc_advance the location of the pointer to advance
   120  * @param loc_data the location of the \c data pointer within your node struct
   121  * @param cmp_func a compare function to compare \p elem against the node data
   122  * @param elem a pointer to the element to find
   123  * @return the index of the element or a negative value if it could not be found
   124  */
   125 ssize_t cx_linked_list_find(
   126         void const *start,
   127         ptrdiff_t loc_advance,
   128         ptrdiff_t loc_data,
   129         cx_compare_func cmp_func,
   130         void const *elem
   131 ) __attribute__((__nonnull__));
   133 /**
   134  * Finds the node containing an element within a linked list.
   135  *
   136  * @param result a pointer to the memory where the node pointer (or \c NULL if the element
   137  * could not be found) shall be stored to
   138  * @param start a pointer to the start node
   139  * @param loc_advance the location of the pointer to advance
   140  * @param loc_data the location of the \c data pointer within your node struct
   141  * @param cmp_func a compare function to compare \p elem against the node data
   142  * @param elem a pointer to the element to find
   143  * @return the index of the element or a negative value if it could not be found
   144  */
   145 ssize_t cx_linked_list_find_node(
   146         void **result,
   147         void const *start,
   148         ptrdiff_t loc_advance,
   149         ptrdiff_t loc_data,
   150         cx_compare_func cmp_func,
   151         void const *elem
   152 ) __attribute__((__nonnull__));
   154 /**
   155  * Finds the first node in a linked list.
   156  *
   157  * The function starts with the pointer denoted by \p node and traverses the list
   158  * along a prev pointer whose location within the node struct is
   159  * denoted by \p loc_prev.
   160  *
   161  * @param node a pointer to a node in the list
   162  * @param loc_prev the location of the \c prev pointer
   163  * @return a pointer to the first node
   164  */
   165 void *cx_linked_list_first(
   166         void const *node,
   167         ptrdiff_t loc_prev
   168 ) __attribute__((__nonnull__));
   170 /**
   171  * Finds the last node in a linked list.
   172  *
   173  * The function starts with the pointer denoted by \p node and traverses the list
   174  * along a next pointer whose location within the node struct is
   175  * denoted by \p loc_next.
   176  *
   177  * @param node a pointer to a node in the list
   178  * @param loc_next the location of the \c next pointer
   179  * @return a pointer to the last node
   180  */
   181 void *cx_linked_list_last(
   182         void const *node,
   183         ptrdiff_t loc_next
   184 ) __attribute__((__nonnull__));
   186 /**
   187  * Finds the predecessor of a node in case it is not linked.
   188  *
   189  * \remark If \p node is not contained in the list starting with \p begin, the behavior is undefined.
   190  *
   191  * @param begin the node where to start the search
   192  * @param loc_next the location of the \c next pointer
   193  * @param node the successor of the node to find
   194  * @return the node or \c NULL if \p node has no predecessor
   195  */
   196 void *cx_linked_list_prev(
   197         void const *begin,
   198         ptrdiff_t loc_next,
   199         void const *node
   200 ) __attribute__((__nonnull__));
   202 /**
   203  * Adds a new node to a linked list.
   204  * The node must not be part of any list already.
   205  *
   206  * \remark One of the pointers \p begin or \p end may be \c NULL, but not both.
   207  *
   208  * @param begin a pointer to the begin node pointer (if your list has one)
   209  * @param end a pointer to the end node pointer (if your list has one)
   210  * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
   211  * @param loc_next the location of a \c next pointer within your node struct (required)
   212  * @param new_node a pointer to the node that shall be appended
   213  */
   214 void cx_linked_list_add(
   215         void **begin,
   216         void **end,
   217         ptrdiff_t loc_prev,
   218         ptrdiff_t loc_next,
   219         void *new_node
   220 ) __attribute__((__nonnull__(5)));
   222 /**
   223  * Prepends a new node to a linked list.
   224  * The node must not be part of any list already.
   225  *
   226  * \remark One of the pointers \p begin or \p end may be \c NULL, but not both.
   227  *
   228  * @param begin a pointer to the begin node pointer (if your list has one)
   229  * @param end a pointer to the end node pointer (if your list has one)
   230  * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
   231  * @param loc_next the location of a \c next pointer within your node struct (required)
   232  * @param new_node a pointer to the node that shall be prepended
   233  */
   234 void cx_linked_list_prepend(
   235         void **begin,
   236         void **end,
   237         ptrdiff_t loc_prev,
   238         ptrdiff_t loc_next,
   239         void *new_node
   240 ) __attribute__((__nonnull__(5)));
   242 /**
   243  * Links two nodes.
   244  *
   245  * @param left the new predecessor of \p right
   246  * @param right the new successor of \p left
   247  * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
   248  * @param loc_next the location of a \c next pointer within your node struct (required)
   249  */
   250 void cx_linked_list_link(
   251         void *left,
   252         void *right,
   253         ptrdiff_t loc_prev,
   254         ptrdiff_t loc_next
   255 ) __attribute__((__nonnull__));
   257 /**
   258  * Unlinks two nodes.
   259  *
   260  * If right is not the successor of left, the behavior is undefined.
   261  *
   262  * @param left the predecessor of \p right
   263  * @param right the successor of \p left
   264  * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
   265  * @param loc_next the location of a \c next pointer within your node struct (required)
   266  */
   267 void cx_linked_list_unlink(
   268         void *left,
   269         void *right,
   270         ptrdiff_t loc_prev,
   271         ptrdiff_t loc_next
   272 ) __attribute__((__nonnull__));
   274 /**
   275  * Inserts a new node after a given node of a linked list.
   276  * The new node must not be part of any list already.
   277  *
   278  * \note If you specify \c NULL as the \p node to insert after, this function needs either the \p begin or
   279  * the \p end pointer to determine the start of the list. Then the new node will be prepended to the list.
   280  *
   281  * @param begin a pointer to the begin node pointer (if your list has one)
   282  * @param end a pointer to the end node pointer (if your list has one)
   283  * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
   284  * @param loc_next the location of a \c next pointer within your node struct (required)
   285  * @param node the node after which to insert (\c NULL if you want to prepend the node to the list)
   286  * @param new_node a pointer to the node that shall be prepended
   287  */
   288 void cx_linked_list_insert(
   289         void **begin,
   290         void **end,
   291         ptrdiff_t loc_prev,
   292         ptrdiff_t loc_next,
   293         void *node,
   294         void *new_node
   295 ) __attribute__((__nonnull__(6)));
   297 /**
   298  * Inserts a chain of nodes after a given node of a linked list.
   299  * The chain must not be part of any list already.
   300  *
   301  * If you do not explicitly specify the end of the chain, it will be determined by traversing
   302  * the \c next pointer.
   303  *
   304  * \note If you specify \c NULL as the \p node to insert after, this function needs either the \p begin or
   305  * the \p end pointer to determine the start of the list. If only the \p end pointer is specified, you also need
   306  * to provide a valid \p loc_prev location.
   307  * Then the chain will be prepended to the list.
   308  *
   309  * @param begin a pointer to the begin node pointer (if your list has one)
   310  * @param end a pointer to the end node pointer (if your list has one)
   311  * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
   312  * @param loc_next the location of a \c next pointer within your node struct (required)
   313  * @param node the node after which to insert (\c NULL to prepend the chain to the list)
   314  * @param insert_begin a pointer to the first node of the chain that shall be inserted
   315  * @param insert_end a pointer to the last node of the chain (or NULL if the last node shall be determined)
   316  */
   317 void cx_linked_list_insert_chain(
   318         void **begin,
   319         void **end,
   320         ptrdiff_t loc_prev,
   321         ptrdiff_t loc_next,
   322         void *node,
   323         void *insert_begin,
   324         void *insert_end
   325 ) __attribute__((__nonnull__(6)));
   327 /**
   328  * Removes a node from the linked list.
   329  *
   330  * If the node to remove is the begin (resp. end) node of the list and if \p begin (resp. \p end)
   331  * addresses are provided, the pointers are adjusted accordingly.
   332  *
   333  * The following combinations of arguments are valid (more arguments are optional):
   334  * \li \p loc_next and \p loc_prev (ancestor node is determined by using the prev pointer, overall O(1) performance)
   335  * \li \p loc_next and \p begin (ancestor node is determined by list traversal, overall O(n) performance)
   336  *
   337  * \remark The \c next and \c prev pointers of the removed node are not cleared by this function and may still be used
   338  * to traverse to a former adjacent node in the list.
   339  *
   340  * @param begin a pointer to the begin node pointer (optional)
   341  * @param end a pointer to the end node pointer (optional)
   342  * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
   343  * @param loc_next the location of a \c next pointer within your node struct (required)
   344  * @param node the node to remove
   345  */
   346 void cx_linked_list_remove(
   347         void **begin,
   348         void **end,
   349         ptrdiff_t loc_prev,
   350         ptrdiff_t loc_next,
   351         void *node
   352 ) __attribute__((__nonnull__(5)));
   355 /**
   356  * Determines the size of a linked list starting with \p node.
   357  * @param node the first node
   358  * @param loc_next the location of the \c next pointer within the node struct
   359  * @return the size of the list or zero if \p node is \c NULL
   360  */
   361 size_t cx_linked_list_size(
   362         void const *node,
   363         ptrdiff_t loc_next
   364 );
   366 /**
   367  * Sorts a linked list based on a comparison function.
   368  *
   369  * This function can work with linked lists of the following structure:
   370  * \code
   371  * typedef struct node node;
   372  * struct node {
   373  *   node* prev;
   374  *   node* next;
   375  *   my_payload data;
   376  * }
   377  * \endcode
   378  *
   379  * @note This is a recursive function with at most logarithmic recursion depth.
   380  *
   381  * @param begin a pointer to the begin node pointer (required)
   382  * @param end a pointer to the end node pointer (optional)
   383  * @param loc_prev the location of a \c prev pointer within your node struct (negative if not present)
   384  * @param loc_next the location of a \c next pointer within your node struct (required)
   385  * @param loc_data the location of the \c data pointer within your node struct
   386  * @param cmp_func the compare function defining the sort order
   387  */
   388 void cx_linked_list_sort(
   389         void **begin,
   390         void **end,
   391         ptrdiff_t loc_prev,
   392         ptrdiff_t loc_next,
   393         ptrdiff_t loc_data,
   394         cx_compare_func cmp_func
   395 ) __attribute__((__nonnull__(1, 6)));
   398 /**
   399  * Compares two lists element wise.
   400  *
   401  * \note Both list must have the same structure.
   402  *
   403  * @param begin_left the begin of the left list (\c NULL denotes an empty list)
   404  * @param begin_right the begin of the right list  (\c NULL denotes an empty list)
   405  * @param loc_advance the location of the pointer to advance
   406  * @param loc_data the location of the \c data pointer within your node struct
   407  * @param cmp_func the function to compare the elements
   408  * @return the first non-zero result of invoking \p cmp_func or: negative if the left list is smaller than the
   409  * right list, positive if the left list is larger than the right list, zero if both lists are equal.
   410  */
   411 int cx_linked_list_compare(
   412         void const *begin_left,
   413         void const *begin_right,
   414         ptrdiff_t loc_advance,
   415         ptrdiff_t loc_data,
   416         cx_compare_func cmp_func
   417 ) __attribute__((__nonnull__(5)));
   419 /**
   420  * Reverses the order of the nodes in a linked list.
   421  *
   422  * @param begin a pointer to the begin node pointer (required)
   423  * @param end a pointer to the end node pointer (optional)
   424  * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
   425  * @param loc_next the location of a \c next pointer within your node struct (required)
   426  */
   427 void cx_linked_list_reverse(
   428         void **begin,
   429         void **end,
   430         ptrdiff_t loc_prev,
   431         ptrdiff_t loc_next
   432 ) __attribute__((__nonnull__(1)));
   434 #ifdef __cplusplus
   435 } // extern "C"
   436 #endif
   438 #endif // UCX_LINKED_LIST_H

mercurial