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