ucx/cx/linked_list.h

changeset 431
bb7da585debc
parent 324
ce13a778654a
child 440
7c4b9cba09ca
equal deleted inserted replaced
169:fe49cff3c571 431:bb7da585debc
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 const CxAllocator *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 __attribute__((__nonnull__))
108 void *cx_linked_list_at(
109 const void *start,
110 size_t start_index,
111 ptrdiff_t loc_advance,
112 size_t index
113 );
114
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 __attribute__((__nonnull__))
126 ssize_t cx_linked_list_find(
127 const void *start,
128 ptrdiff_t loc_advance,
129 ptrdiff_t loc_data,
130 cx_compare_func cmp_func,
131 const void *elem
132 );
133
134 /**
135 * Finds the node containing an element within a linked list.
136 *
137 * @param result a pointer to the memory where the node pointer (or \c NULL if the element
138 * could not be found) shall be stored to
139 * @param start a pointer to the start node
140 * @param loc_advance the location of the pointer to advance
141 * @param loc_data the location of the \c data pointer within your node struct
142 * @param cmp_func a compare function to compare \p elem against the node data
143 * @param elem a pointer to the element to find
144 * @return the index of the element or a negative value if it could not be found
145 */
146 __attribute__((__nonnull__))
147 ssize_t cx_linked_list_find_node(
148 void **result,
149 const void *start,
150 ptrdiff_t loc_advance,
151 ptrdiff_t loc_data,
152 cx_compare_func cmp_func,
153 const void *elem
154 );
155
156 /**
157 * Finds the first node in a linked list.
158 *
159 * The function starts with the pointer denoted by \p node and traverses the list
160 * along a prev pointer whose location within the node struct is
161 * denoted by \p loc_prev.
162 *
163 * @param node a pointer to a node in the list
164 * @param loc_prev the location of the \c prev pointer
165 * @return a pointer to the first node
166 */
167 __attribute__((__nonnull__))
168 void *cx_linked_list_first(
169 const void *node,
170 ptrdiff_t loc_prev
171 );
172
173 /**
174 * Finds the last node in a linked list.
175 *
176 * The function starts with the pointer denoted by \p node and traverses the list
177 * along a next pointer whose location within the node struct is
178 * denoted by \p loc_next.
179 *
180 * @param node a pointer to a node in the list
181 * @param loc_next the location of the \c next pointer
182 * @return a pointer to the last node
183 */
184 __attribute__((__nonnull__))
185 void *cx_linked_list_last(
186 const void *node,
187 ptrdiff_t loc_next
188 );
189
190 /**
191 * Finds the predecessor of a node in case it is not linked.
192 *
193 * \remark If \p node is not contained in the list starting with \p begin, the behavior is undefined.
194 *
195 * @param begin the node where to start the search
196 * @param loc_next the location of the \c next pointer
197 * @param node the successor of the node to find
198 * @return the node or \c NULL if \p node has no predecessor
199 */
200 __attribute__((__nonnull__))
201 void *cx_linked_list_prev(
202 const void *begin,
203 ptrdiff_t loc_next,
204 const void *node
205 );
206
207 /**
208 * Adds a new node to a linked list.
209 * The node must not be part of any list already.
210 *
211 * \remark One of the pointers \p begin or \p end may be \c NULL, but not both.
212 *
213 * @param begin a pointer to the begin node pointer (if your list has one)
214 * @param end a pointer to the end node pointer (if your list has one)
215 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
216 * @param loc_next the location of a \c next pointer within your node struct (required)
217 * @param new_node a pointer to the node that shall be appended
218 */
219 __attribute__((__nonnull__(5)))
220 void cx_linked_list_add(
221 void **begin,
222 void **end,
223 ptrdiff_t loc_prev,
224 ptrdiff_t loc_next,
225 void *new_node
226 );
227
228 /**
229 * Prepends a new node to a linked list.
230 * The node must not be part of any list already.
231 *
232 * \remark One of the pointers \p begin or \p end may be \c NULL, but not both.
233 *
234 * @param begin a pointer to the begin node pointer (if your list has one)
235 * @param end a pointer to the end node pointer (if your list has one)
236 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
237 * @param loc_next the location of a \c next pointer within your node struct (required)
238 * @param new_node a pointer to the node that shall be prepended
239 */
240 __attribute__((__nonnull__(5)))
241 void cx_linked_list_prepend(
242 void **begin,
243 void **end,
244 ptrdiff_t loc_prev,
245 ptrdiff_t loc_next,
246 void *new_node
247 );
248
249 /**
250 * Links two nodes.
251 *
252 * @param left the new predecessor of \p right
253 * @param right the new successor of \p left
254 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
255 * @param loc_next the location of a \c next pointer within your node struct (required)
256 */
257 __attribute__((__nonnull__))
258 void cx_linked_list_link(
259 void *left,
260 void *right,
261 ptrdiff_t loc_prev,
262 ptrdiff_t loc_next
263 );
264
265 /**
266 * Unlinks two nodes.
267 *
268 * If right is not the successor of left, the behavior is undefined.
269 *
270 * @param left the predecessor of \p right
271 * @param right the successor of \p left
272 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
273 * @param loc_next the location of a \c next pointer within your node struct (required)
274 */
275 __attribute__((__nonnull__))
276 void cx_linked_list_unlink(
277 void *left,
278 void *right,
279 ptrdiff_t loc_prev,
280 ptrdiff_t loc_next
281 );
282
283 /**
284 * Inserts a new node after a given node of a linked list.
285 * The new node must not be part of any list already.
286 *
287 * \note If you specify \c NULL as the \p node to insert after, this function needs either the \p begin or
288 * the \p end pointer to determine the start of the list. Then the new node will be prepended to the list.
289 *
290 * @param begin a pointer to the begin node pointer (if your list has one)
291 * @param end a pointer to the end node pointer (if your list has one)
292 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
293 * @param loc_next the location of a \c next pointer within your node struct (required)
294 * @param node the node after which to insert (\c NULL if you want to prepend the node to the list)
295 * @param new_node a pointer to the node that shall be inserted
296 */
297 __attribute__((__nonnull__(6)))
298 void cx_linked_list_insert(
299 void **begin,
300 void **end,
301 ptrdiff_t loc_prev,
302 ptrdiff_t loc_next,
303 void *node,
304 void *new_node
305 );
306
307 /**
308 * Inserts a chain of nodes after a given node of a linked list.
309 * The chain must not be part of any list already.
310 *
311 * If you do not explicitly specify the end of the chain, it will be determined by traversing
312 * the \c next pointer.
313 *
314 * \note If you specify \c NULL as the \p node to insert after, this function needs either the \p begin or
315 * the \p end pointer to determine the start of the list. If only the \p end pointer is specified, you also need
316 * to provide a valid \p loc_prev location.
317 * Then the chain will be prepended to the list.
318 *
319 * @param begin a pointer to the begin node pointer (if your list has one)
320 * @param end a pointer to the end node pointer (if your list has one)
321 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
322 * @param loc_next the location of a \c next pointer within your node struct (required)
323 * @param node the node after which to insert (\c NULL to prepend the chain to the list)
324 * @param insert_begin a pointer to the first node of the chain that shall be inserted
325 * @param insert_end a pointer to the last node of the chain (or NULL if the last node shall be determined)
326 */
327 __attribute__((__nonnull__(6)))
328 void cx_linked_list_insert_chain(
329 void **begin,
330 void **end,
331 ptrdiff_t loc_prev,
332 ptrdiff_t loc_next,
333 void *node,
334 void *insert_begin,
335 void *insert_end
336 );
337
338 /**
339 * Inserts a node into a sorted linked list.
340 * The new node must not be part of any list already.
341 *
342 * If the list starting with the node pointed to by \p begin is not sorted
343 * already, the behavior is undefined.
344 *
345 * @param begin a pointer to the begin node pointer (required)
346 * @param end a pointer to the end node pointer (if your list has one)
347 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
348 * @param loc_next the location of a \c next pointer within your node struct (required)
349 * @param new_node a pointer to the node that shall be inserted
350 * @param cmp_func a compare function that will receive the node pointers
351 */
352 __attribute__((__nonnull__(1, 5, 6)))
353 void cx_linked_list_insert_sorted(
354 void **begin,
355 void **end,
356 ptrdiff_t loc_prev,
357 ptrdiff_t loc_next,
358 void *new_node,
359 cx_compare_func cmp_func
360 );
361
362 /**
363 * Inserts a chain of nodes into a sorted linked list.
364 * The chain must not be part of any list already.
365 *
366 * If either the list starting with the node pointed to by \p begin or the list
367 * starting with \p insert_begin is not sorted, the behavior is undefined.
368 *
369 * \attention In contrast to cx_linked_list_insert_chain(), the source chain
370 * will be broken and inserted into the target list so that the resulting list
371 * will be sorted according to \p cmp_func. That means, each node in the source
372 * chain may be re-linked with nodes from the target list.
373 *
374 * @param begin a pointer to the begin node pointer (required)
375 * @param end a pointer to the end node pointer (if your list has one)
376 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
377 * @param loc_next the location of a \c next pointer within your node struct (required)
378 * @param insert_begin a pointer to the first node of the chain that shall be inserted
379 * @param cmp_func a compare function that will receive the node pointers
380 */
381 __attribute__((__nonnull__(1, 5, 6)))
382 void cx_linked_list_insert_sorted_chain(
383 void **begin,
384 void **end,
385 ptrdiff_t loc_prev,
386 ptrdiff_t loc_next,
387 void *insert_begin,
388 cx_compare_func cmp_func
389 );
390
391 /**
392 * Removes a node from the linked list.
393 *
394 * If the node to remove is the begin (resp. end) node of the list and if \p begin (resp. \p end)
395 * addresses are provided, the pointers are adjusted accordingly.
396 *
397 * The following combinations of arguments are valid (more arguments are optional):
398 * \li \p loc_next and \p loc_prev (ancestor node is determined by using the prev pointer, overall O(1) performance)
399 * \li \p loc_next and \p begin (ancestor node is determined by list traversal, overall O(n) performance)
400 *
401 * \remark The \c next and \c prev pointers of the removed node are not cleared by this function and may still be used
402 * to traverse to a former adjacent node in the list.
403 *
404 * @param begin a pointer to the begin node pointer (optional)
405 * @param end a pointer to the end node pointer (optional)
406 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
407 * @param loc_next the location of a \c next pointer within your node struct (required)
408 * @param node the node to remove
409 */
410 __attribute__((__nonnull__(5)))
411 void cx_linked_list_remove(
412 void **begin,
413 void **end,
414 ptrdiff_t loc_prev,
415 ptrdiff_t loc_next,
416 void *node
417 );
418
419
420 /**
421 * Determines the size of a linked list starting with \p node.
422 * @param node the first node
423 * @param loc_next the location of the \c next pointer within the node struct
424 * @return the size of the list or zero if \p node is \c NULL
425 */
426 size_t cx_linked_list_size(
427 const void *node,
428 ptrdiff_t loc_next
429 );
430
431 /**
432 * Sorts a linked list based on a comparison function.
433 *
434 * This function can work with linked lists of the following structure:
435 * \code
436 * typedef struct node node;
437 * struct node {
438 * node* prev;
439 * node* next;
440 * my_payload data;
441 * }
442 * \endcode
443 *
444 * @note This is a recursive function with at most logarithmic recursion depth.
445 *
446 * @param begin a pointer to the begin node pointer (required)
447 * @param end a pointer to the end node pointer (optional)
448 * @param loc_prev the location of a \c prev pointer within your node struct (negative if not present)
449 * @param loc_next the location of a \c next pointer within your node struct (required)
450 * @param loc_data the location of the \c data pointer within your node struct
451 * @param cmp_func the compare function defining the sort order
452 */
453 __attribute__((__nonnull__(1, 6)))
454 void cx_linked_list_sort(
455 void **begin,
456 void **end,
457 ptrdiff_t loc_prev,
458 ptrdiff_t loc_next,
459 ptrdiff_t loc_data,
460 cx_compare_func cmp_func
461 );
462
463
464 /**
465 * Compares two lists element wise.
466 *
467 * \note Both list must have the same structure.
468 *
469 * @param begin_left the begin of the left list (\c NULL denotes an empty list)
470 * @param begin_right the begin of the right list (\c NULL denotes an empty list)
471 * @param loc_advance the location of the pointer to advance
472 * @param loc_data the location of the \c data pointer within your node struct
473 * @param cmp_func the function to compare the elements
474 * @return the first non-zero result of invoking \p cmp_func or: negative if the left list is smaller than the
475 * right list, positive if the left list is larger than the right list, zero if both lists are equal.
476 */
477 __attribute__((__nonnull__(5)))
478 int cx_linked_list_compare(
479 const void *begin_left,
480 const void *begin_right,
481 ptrdiff_t loc_advance,
482 ptrdiff_t loc_data,
483 cx_compare_func cmp_func
484 );
485
486 /**
487 * Reverses the order of the nodes in a linked list.
488 *
489 * @param begin a pointer to the begin node pointer (required)
490 * @param end a pointer to the end node pointer (optional)
491 * @param loc_prev the location of a \c prev pointer within your node struct (negative if your struct does not have one)
492 * @param loc_next the location of a \c next pointer within your node struct (required)
493 */
494 __attribute__((__nonnull__(1)))
495 void cx_linked_list_reverse(
496 void **begin,
497 void **end,
498 ptrdiff_t loc_prev,
499 ptrdiff_t loc_next
500 );
501
502 #ifdef __cplusplus
503 } // extern "C"
504 #endif
505
506 #endif // UCX_LINKED_LIST_H

mercurial