UNIXworkcode

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 */ 36 37 #ifndef UCX_LINKED_LIST_H 38 #define UCX_LINKED_LIST_H 39 40 #include "common.h" 41 #include "list.h" 42 43 #ifdef __cplusplus 44 extern "C" { 45 #endif 46 47 /** 48 * The maximum item size that uses SBO swap instead of relinking. 49 */ 50 extern unsigned cx_linked_list_swap_sbo_size; 51 52 /** 53 * Allocates a linked list for storing elements with \p elem_size bytes each. 54 * 55 * If \p elem_size is CX_STORE_POINTERS, the created list will be created as if 56 * cxListStorePointers() was called immediately after creation and the compare 57 * function will be automatically set to cx_cmp_ptr(), if none is given. 58 * 59 * @param allocator the allocator for allocating the list nodes 60 * (if \c NULL the cxDefaultAllocator will be used) 61 * @param comparator the comparator for the elements 62 * (if \c NULL, and the list is not storing pointers, sort and find 63 * functions will not work) 64 * @param elem_size the size of each element in bytes 65 * @return the created list 66 */ 67 CxList *cxLinkedListCreate( 68 CxAllocator const *allocator, 69 cx_compare_func comparator, 70 size_t elem_size 71 ); 72 73 /** 74 * Allocates a linked list for storing elements with \p elem_size bytes each. 75 * 76 * The list will use cxDefaultAllocator and no comparator function. If you want 77 * to call functions that need a comparator, you must either set one immediately 78 * after list creation or use cxLinkedListCreate(). 79 * 80 * If \p elem_size is CX_STORE_POINTERS, the created list will be created as if 81 * cxListStorePointers() was called immediately after creation and the compare 82 * function will be automatically set to cx_cmp_ptr(). 83 * 84 * @param elem_size the size of each element in bytes 85 * @return the created list 86 */ 87 #define cxLinkedListCreateSimple(elem_size) \ 88 cxLinkedListCreate(NULL, NULL, elem_size) 89 90 /** 91 * Finds the node at a certain index. 92 * 93 * This function can be used to start at an arbitrary position within the list. 94 * If the search index is large than the start index, \p loc_advance must denote 95 * the location of some sort of \c next pointer (i.e. a pointer to the next node). 96 * But it is also possible that the search index is smaller than the start index 97 * (e.g. in cases where traversing a list backwards is faster) in which case 98 * \p loc_advance must denote the location of some sort of \c prev pointer 99 * (i.e. a pointer to the previous node). 100 * 101 * @param start a pointer to the start node 102 * @param start_index the start index 103 * @param loc_advance the location of the pointer to advance 104 * @param index the search index 105 * @return the node found at the specified index 106 */ 107 void *cx_linked_list_at( 108 void const *start, 109 size_t start_index, 110 ptrdiff_t loc_advance, 111 size_t index 112 ) __attribute__((__nonnull__)); 113 114 /** 115 * Finds the index of an element within a linked list. 116 * 117 * @param start a pointer to the start node 118 * @param loc_advance the location of the pointer to advance 119 * @param loc_data the location of the \c data pointer within your node struct 120 * @param cmp_func a compare function to compare \p elem against the node data 121 * @param elem a pointer to the element to find 122 * @return the index of the element or a negative value if it could not be found 123 */ 124 ssize_t cx_linked_list_find( 125 void const *start, 126 ptrdiff_t loc_advance, 127 ptrdiff_t loc_data, 128 cx_compare_func cmp_func, 129 void const *elem 130 ) __attribute__((__nonnull__)); 131 132 /** 133 * Finds the node containing an element within a linked list. 134 * 135 * @param result a pointer to the memory where the node pointer (or \c NULL if the element 136 * could not be found) shall be stored to 137 * @param start a pointer to the start node 138 * @param loc_advance the location of the pointer to advance 139 * @param loc_data the location of the \c data pointer within your node struct 140 * @param cmp_func a compare function to compare \p elem against the node data 141 * @param elem a pointer to the element to find 142 * @return the index of the element or a negative value if it could not be found 143 */ 144 ssize_t cx_linked_list_find_node( 145 void **result, 146 void const *start, 147 ptrdiff_t loc_advance, 148 ptrdiff_t loc_data, 149 cx_compare_func cmp_func, 150 void const *elem 151 ) __attribute__((__nonnull__)); 152 153 /** 154 * Finds the first node in a linked list. 155 * 156 * The function starts with the pointer denoted by \p node and traverses the list 157 * along a prev pointer whose location within the node struct is 158 * denoted by \p loc_prev. 159 * 160 * @param node a pointer to a node in the list 161 * @param loc_prev the location of the \c prev pointer 162 * @return a pointer to the first node 163 */ 164 void *cx_linked_list_first( 165 void const *node, 166 ptrdiff_t loc_prev 167 ) __attribute__((__nonnull__)); 168 169 /** 170 * Finds the last node in a linked list. 171 * 172 * The function starts with the pointer denoted by \p node and traverses the list 173 * along a next pointer whose location within the node struct is 174 * denoted by \p loc_next. 175 * 176 * @param node a pointer to a node in the list 177 * @param loc_next the location of the \c next pointer 178 * @return a pointer to the last node 179 */ 180 void *cx_linked_list_last( 181 void const *node, 182 ptrdiff_t loc_next 183 ) __attribute__((__nonnull__)); 184 185 /** 186 * Finds the predecessor of a node in case it is not linked. 187 * 188 * \remark If \p node is not contained in the list starting with \p begin, the behavior is undefined. 189 * 190 * @param begin the node where to start the search 191 * @param loc_next the location of the \c next pointer 192 * @param node the successor of the node to find 193 * @return the node or \c NULL if \p node has no predecessor 194 */ 195 void *cx_linked_list_prev( 196 void const *begin, 197 ptrdiff_t loc_next, 198 void const *node 199 ) __attribute__((__nonnull__)); 200 201 /** 202 * Adds a new node to a linked list. 203 * The node must not be part of any list already. 204 * 205 * \remark One of the pointers \p begin or \p end may be \c NULL, but not both. 206 * 207 * @param begin a pointer to the begin node pointer (if your list has one) 208 * @param end a pointer to the end node pointer (if your list has one) 209 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one) 210 * @param loc_next the location of a \c next pointer within your node struct (required) 211 * @param new_node a pointer to the node that shall be appended 212 */ 213 void cx_linked_list_add( 214 void **begin, 215 void **end, 216 ptrdiff_t loc_prev, 217 ptrdiff_t loc_next, 218 void *new_node 219 ) __attribute__((__nonnull__(5))); 220 221 /** 222 * Prepends a new node to a linked list. 223 * The node must not be part of any list already. 224 * 225 * \remark One of the pointers \p begin or \p end may be \c NULL, but not both. 226 * 227 * @param begin a pointer to the begin node pointer (if your list has one) 228 * @param end a pointer to the end node pointer (if your list has one) 229 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one) 230 * @param loc_next the location of a \c next pointer within your node struct (required) 231 * @param new_node a pointer to the node that shall be prepended 232 */ 233 void cx_linked_list_prepend( 234 void **begin, 235 void **end, 236 ptrdiff_t loc_prev, 237 ptrdiff_t loc_next, 238 void *new_node 239 ) __attribute__((__nonnull__(5))); 240 241 /** 242 * Links two nodes. 243 * 244 * @param left the new predecessor of \p right 245 * @param right the new successor of \p left 246 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one) 247 * @param loc_next the location of a \c next pointer within your node struct (required) 248 */ 249 void cx_linked_list_link( 250 void *left, 251 void *right, 252 ptrdiff_t loc_prev, 253 ptrdiff_t loc_next 254 ) __attribute__((__nonnull__)); 255 256 /** 257 * Unlinks two nodes. 258 * 259 * If right is not the successor of left, the behavior is undefined. 260 * 261 * @param left the predecessor of \p right 262 * @param right the successor of \p left 263 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one) 264 * @param loc_next the location of a \c next pointer within your node struct (required) 265 */ 266 void cx_linked_list_unlink( 267 void *left, 268 void *right, 269 ptrdiff_t loc_prev, 270 ptrdiff_t loc_next 271 ) __attribute__((__nonnull__)); 272 273 /** 274 * Inserts a new node after a given node of a linked list. 275 * The new node must not be part of any list already. 276 * 277 * \note If you specify \c NULL as the \p node to insert after, this function needs either the \p begin or 278 * the \p end pointer to determine the start of the list. Then the new node will be prepended to the list. 279 * 280 * @param begin a pointer to the begin node pointer (if your list has one) 281 * @param end a pointer to the end node pointer (if your list has one) 282 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one) 283 * @param loc_next the location of a \c next pointer within your node struct (required) 284 * @param node the node after which to insert (\c NULL if you want to prepend the node to the list) 285 * @param new_node a pointer to the node that shall be prepended 286 */ 287 void cx_linked_list_insert( 288 void **begin, 289 void **end, 290 ptrdiff_t loc_prev, 291 ptrdiff_t loc_next, 292 void *node, 293 void *new_node 294 ) __attribute__((__nonnull__(6))); 295 296 /** 297 * Inserts a chain of nodes after a given node of a linked list. 298 * The chain must not be part of any list already. 299 * 300 * If you do not explicitly specify the end of the chain, it will be determined by traversing 301 * the \c next pointer. 302 * 303 * \note If you specify \c NULL as the \p node to insert after, this function needs either the \p begin or 304 * the \p end pointer to determine the start of the list. If only the \p end pointer is specified, you also need 305 * to provide a valid \p loc_prev location. 306 * Then the chain will be prepended to the list. 307 * 308 * @param begin a pointer to the begin node pointer (if your list has one) 309 * @param end a pointer to the end node pointer (if your list has one) 310 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one) 311 * @param loc_next the location of a \c next pointer within your node struct (required) 312 * @param node the node after which to insert (\c NULL to prepend the chain to the list) 313 * @param insert_begin a pointer to the first node of the chain that shall be inserted 314 * @param insert_end a pointer to the last node of the chain (or NULL if the last node shall be determined) 315 */ 316 void cx_linked_list_insert_chain( 317 void **begin, 318 void **end, 319 ptrdiff_t loc_prev, 320 ptrdiff_t loc_next, 321 void *node, 322 void *insert_begin, 323 void *insert_end 324 ) __attribute__((__nonnull__(6))); 325 326 /** 327 * Removes a node from the linked list. 328 * 329 * If the node to remove is the begin (resp. end) node of the list and if \p begin (resp. \p end) 330 * addresses are provided, the pointers are adjusted accordingly. 331 * 332 * The following combinations of arguments are valid (more arguments are optional): 333 * \li \p loc_next and \p loc_prev (ancestor node is determined by using the prev pointer, overall O(1) performance) 334 * \li \p loc_next and \p begin (ancestor node is determined by list traversal, overall O(n) performance) 335 * 336 * \remark The \c next and \c prev pointers of the removed node are not cleared by this function and may still be used 337 * to traverse to a former adjacent node in the list. 338 * 339 * @param begin a pointer to the begin node pointer (optional) 340 * @param end a pointer to the end node pointer (optional) 341 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one) 342 * @param loc_next the location of a \c next pointer within your node struct (required) 343 * @param node the node to remove 344 */ 345 void cx_linked_list_remove( 346 void **begin, 347 void **end, 348 ptrdiff_t loc_prev, 349 ptrdiff_t loc_next, 350 void *node 351 ) __attribute__((__nonnull__(5))); 352 353 354 /** 355 * Determines the size of a linked list starting with \p node. 356 * @param node the first node 357 * @param loc_next the location of the \c next pointer within the node struct 358 * @return the size of the list or zero if \p node is \c NULL 359 */ 360 size_t cx_linked_list_size( 361 void const *node, 362 ptrdiff_t loc_next 363 ); 364 365 /** 366 * Sorts a linked list based on a comparison function. 367 * 368 * This function can work with linked lists of the following structure: 369 * \code 370 * typedef struct node node; 371 * struct node { 372 * node* prev; 373 * node* next; 374 * my_payload data; 375 * } 376 * \endcode 377 * 378 * @note This is a recursive function with at most logarithmic recursion depth. 379 * 380 * @param begin a pointer to the begin node pointer (required) 381 * @param end a pointer to the end node pointer (optional) 382 * @param loc_prev the location of a \c prev pointer within your node struct (negative if not present) 383 * @param loc_next the location of a \c next pointer within your node struct (required) 384 * @param loc_data the location of the \c data pointer within your node struct 385 * @param cmp_func the compare function defining the sort order 386 */ 387 void cx_linked_list_sort( 388 void **begin, 389 void **end, 390 ptrdiff_t loc_prev, 391 ptrdiff_t loc_next, 392 ptrdiff_t loc_data, 393 cx_compare_func cmp_func 394 ) __attribute__((__nonnull__(1, 6))); 395 396 397 /** 398 * Compares two lists element wise. 399 * 400 * \note Both list must have the same structure. 401 * 402 * @param begin_left the begin of the left list (\c NULL denotes an empty list) 403 * @param begin_right the begin of the right list (\c NULL denotes an empty list) 404 * @param loc_advance the location of the pointer to advance 405 * @param loc_data the location of the \c data pointer within your node struct 406 * @param cmp_func the function to compare the elements 407 * @return the first non-zero result of invoking \p cmp_func or: negative if the left list is smaller than the 408 * right list, positive if the left list is larger than the right list, zero if both lists are equal. 409 */ 410 int cx_linked_list_compare( 411 void const *begin_left, 412 void const *begin_right, 413 ptrdiff_t loc_advance, 414 ptrdiff_t loc_data, 415 cx_compare_func cmp_func 416 ) __attribute__((__nonnull__(5))); 417 418 /** 419 * Reverses the order of the nodes in a linked list. 420 * 421 * @param begin a pointer to the begin node pointer (required) 422 * @param end a pointer to the end node pointer (optional) 423 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one) 424 * @param loc_next the location of a \c next pointer within your node struct (required) 425 */ 426 void cx_linked_list_reverse( 427 void **begin, 428 void **end, 429 ptrdiff_t loc_prev, 430 ptrdiff_t loc_next 431 ) __attribute__((__nonnull__(1))); 432 433 #ifdef __cplusplus 434 } // extern "C" 435 #endif 436 437 #endif // UCX_LINKED_LIST_H 438