1 # List Interface
2
3 The `list.h` header defines a common interface for all list implementations.
4
5 UCX already comes with two common list implementations ([linked list](linked_list.h.md) and [array list](array_list.h.md))
6 that should cover most use cases.
7 But if you feel the need to implement your own list, you will find the instructions [below](#implement-own-list-structures).
8
9 ```C
10 #include <cx/linked_list.h>
11
12 CxList *cxLinkedListCreate(const CxAllocator *allocator,
13 size_t elem_size);
14
15 #include <cx/array_list.h>
16
17 CxList *cxArrayListCreate(const CxAllocator *allocator,
18 size_t elem_size, size_t initial_capacity);
19 ```
20
21 The function `cxLinkedListCreate()` creates a new linked list with the specified `allocator` which stores elements of size `elem_size`.
22 The elements are supposed to be compared with the specified `comparator` (cf. [](#access-and-find)).
23
24 Array lists can be created with `cxArrayListCreate()` where the additional argument `initial_capacity` specifies for how many elements the underlying array shall be initially allocated.
25
26 If `CX_STORE_POINTERS` is used as `elem_size`, the actual element size will be `sizeof(void*)` and the list will behave slightly differently when accessing elements.
27 Lists that are storing pointers will always return the stored pointer directly, instead of returning a pointer into the list's memory, thus saving you from unnecessary dereferencing.
28 Conversely, when adding elements to the list, the pointers you specify (e.g., in `cxListAdd()` or `cxListInsert()`) are directly added to the list, instead of copying the contents pointed to by the argument.
29
30 > When you create a list which is storing pointers and do not specify a compare function, `cx_cmp_ptr` will be used by default.
31
32 > If you want to lazy-initialize lists, you can use the global `cxEmptyList` symbol as a placeholder instead of using a `NULL`-pointer.
33 > While you *must not* insert elements into that list, you can safely access this list or create iterators.
34 > This allows you to write clean code without checking for `NULL`-pointer everywhere.
35 > You still need to make sure that the placeholder is replaced with an actual list before inserting elements.
36
37 ## Example
38
39 In the following example we create a linked-list of regular expressions for filtering data.
40
41 ```C
42 #include <cx/linked_list.h>
43 #include <regex.h>
44
45 CxList *create_pattern_list(void) {
46 // create a linked list to store patterns
47 CxList *list = cxLinkedListCreate(NULL, sizeof(regex_t));
48
49 // automatically free the pattern when list gets destroyed
50 cxSetDestructor(list, regfree);
51
52 return list;
53 }
54
55 int add_pattern(CxList *list, const char *value) {
56 // compile pattern and add it to the list, if successful
57 regex_t regex;
58 if (regcomp(®ex, value, REG_EXTENDED|REG_NOSUB)) {
59 return 1;
60 } else {
61 // take address of local variable
62 // since we are not storing pointers in this list,
63 // we get a copy of the data directly in the list
64 cxListAdd(list, ®ex);
65 return 0;
66 }
67 }
68
69 bool matches_any(CxList *list, const char *text) {
70 CxIterator iter = cxListIterator(list);
71 cx_foreach(regex_t*, pat, iter) {
72 if (regexec(pat, text, 0, NULL, 0) == 0) {
73 return true;
74 }
75 }
76 return false;
77 }
78 ```
79
80 If in the above example the list was created with `CX_STORE_POINTERS` instead of `sizeof(regex_t)`,
81 the `add_pattern()` function would need to be changed as follows:
82
83 ```C
84 int add_pattern(CxList *list, const char *value) {
85 // allocate memory here, because now we are storing pointers
86 regex_t *regex = malloc(sizeof(regex_t));
87 if (!regex || regcomp(regex, value, REG_EXTENDED|REG_NOSUB)) {
88 return 1;
89 } else {
90 cxListAdd(list, regex);
91 return 0;
92 }
93 }
94 ```
95
96 Also, just registering `regfree()` as a destructor is not enough anymore because the `regex_t` structure also needs to be freed.
97 Therefore, we would need to wrap the calls to `regfree()` and `free()` into an own destructor, which we then register with the list.
98 However, it should be clear by now that using `CX_STORE_POINTERS` is a bad choice for this use case to begin with.
99
100 As a rule of thumb: if you allocate memory for an element that you immediately put into the list, consider storing the element directly.
101 And if you are getting pointers to already allocated memory from somewhere else, and you just want to organize those elements in a list, then consider using `CX_STORE_POINTERS`.
102
103 ## Insert
104
105 ```C
106 #include <cx/list.h>
107
108 int cxListAdd(CxList *list, const void *elem);
109
110 int cxListInsert(CxList *list, size_t index, const void *elem);
111
112 void *cxListEmplace(CxList *list);
113
114 void *cxListEmplaceAt(CxList *list, size_t index);
115
116 CxIterator cxListEmplaceArray(CxList *list, size_t n);
117
118 CxIterator cxListEmplaceArrayAt(CxList *list, size_t index, size_t n);
119
120 int cxListInsertSorted(CxList *list, const void *elem);
121
122 int cxListInsertUnique(CxList *list, const void *elem);
123
124 size_t cxListAddArray(CxList *list, const void *array, size_t n);
125
126 size_t cxListInsertArray(CxList *list, size_t index,
127 const void *array, size_t n);
128
129 size_t cxListInsertSortedArray(CxList *list,
130 const void *array, size_t n);
131
132 size_t cxListInsertUniqueArray(CxList *list,
133 const void *array, size_t n);
134
135 int cxListInsertAfter(CxIterator *iter, const void *elem);
136
137 int cxListInsertBefore(CxIterator *iter, const void *elem);
138 ```
139
140 The function `cxListAdd()` appends the element `elem` to the list and returns zero on success or non-zero when allocating the memory for the element fails.
141 Similarly, `cxListInsert()` adds the element at the specified `index`.
142
143 The functions `cxListEmplace()` and `cxListEmplaceAt()` behave like `cxListAdd()` and `cxListInsert()`,
144 except that they only allocate the memory and return a pointer to it, leaving it to the callee to copy the element data into it.
145 The same is true for `cxListEmplaceArray()` and `cxListEmplaceArrayAt()`, which allocate memory for `n` elements and return an iterator to the first element.
146 Be aware that when the list is storing pointers, the allocated memory will be for the pointer, not the actual element's data.
147
148 > If `cxListEmplaceArray()` or `cxListEmplaceArrayAt()` is unable to allocate memory for `n` elements,
149 > the iterator will iterate only over the elements that have been successfully allocated.
150 > The `elem_count` attribute of the iterator will be set to the number of successfully allocated elements.
151 > And the `index` attribute will count from zero to `elem_count - 1`.
152 > {style="note"}
153
154 The function `cxListInsertSorted()` inserts the element at the correct position so that the list remains sorted according to the list's compare function.
155 It is important that the list is already sorted before calling this function.
156 On the other hand, `cxListInsertUnique()` inserts the element only if it is not already in the list.
157 In this case it is strongly recommended that the list is already sorted but not required; the function will fall back to an inefficient algorithm when the list is not sorted.
158
159 When you are currently iterating through a list, you can insert elements before or after the current position of the iterator
160 with `cxListInsertBefore()` or `cxListInsertAfter()`, respectively.
161
162 If the list is storing pointers (cf. `cxCollectionStoresPointers()`), the pointer `elem` is directly added to the list.
163 Otherwise, the contents at the location pointed to by `elem` are copied to the list's memory with the element size specified during creation of the list.
164
165 On the other hand, the `array` argument for `cxListAddArray()`, `cxListInsertArray()`, `cxListInsertSortedArray()`, and `cxListInsertUniqueArray()`
166 must always point to an array of elements to be added (i.e., either an array of pointers or an array of actual elements).
167
168 The return values of the array-inserting functions are the number of elements that have been successfully _processed_.
169 Usually this is equivalent to the number of inserted elements, except for `cxListInsertUniqueArray()`,
170 where the actual number of inserted elements may be lower than the number of successfully processed elements.
171
172 > Implementations are required to optimize the insertion of a sorted array into a sorted list in linear time,
173 > while inserting each element separately via `cxListInsertSorted()` may take quadratic time.
174 >
175 > When used with sorted lists, the arrays passed to the functions must also be sorted according to the list's compare function.
176 > Only when `cxListInsertUniqueArray()` is used with a list that is not sorted, the array does not need to be sorted.
177 >
178 > The functions do not check if the passed arrays are sorted.
179 > {style="note"}
180
181 ## Access and Find
182
183 <link-summary>Functions for searching and accessing elements.</link-summary>
184
185 ```C
186 #include <cx/list.h>
187
188 void *cxListAt(const CxList *list, size_t index);
189
190 void *cxListFirst(const CxList *list);
191
192 void *cxListLast(const CxList *list);
193
194 int cxListSet(CxList *list, size_t index, const void *elem);
195
196 size_t cxListFind(const CxList *list, const void *elem);
197
198 size_t cxListFindRemove(CxList *list, const void *elem);
199
200 bool cxListContains(const CxList *list, const void *elem);
201
202 bool cxListIndexValid(const CxList *list, size_t index);
203
204 size_t cxListSize(const CxList *list);
205 ```
206
207 The function `cxListAt()` accesses the element at the specified `index`.
208 If the list is storing pointers (i.e. `cxCollectionStoresPointers()` returns `true`), the pointer at the specified index is directly returned.
209 Otherwise, a pointer to the element at the specified index is returned.
210 If the index is out-of-bounds, the function returns `NULL`.
211 The functions `cxListFirst()` and `cxListLast()` behave like `cxListAt()`,
212 accessing the first or the last valid index, respectively, and returning `NULL` when the list is empty.
213
214 The function `cxListSet()` allows you to modify elements at a specific index in the list.
215 This function replaces the element at the specified `index` with the value pointed to by `elem`.
216 If the list is storing values directly (not pointers), the contents at the memory location `elem` will be copied into the list.
217 If the list is storing pointers, the pointer value itself will be stored.
218 The function returns `0` on success and `1` if the index is out of bounds.
219
220 On the other hand, `cxListFind()` searches for the element pointed to by `elem` by comparing each element in the list with the list's compare function
221 and returns the first index when the element was found.
222 Otherwise, the function returns the list size.
223
224 The function `cxListFindRemove()` behaves like `cxListFind()`, except that it also removes the first occurrence of the element from the list.
225 This will _also_ call destructor functions, if specified, so take special care when you continue to use `elem`, or when the list is storing pointers and the element appears more than once in the list.
226
227 The function `cxListContains()` returns `true` if and only if `cxListFind()` returns a valid index.
228
229 With `cxListIndexValid()` you can check the index returned by `cxListFind()` or `cxListFindRemove()`,
230 which is more convenient than comparing the return value if the return value of `cxListSize()`.
231
232 ## Remove
233
234 ```C
235 #include <cx/list.h>
236
237 int cxListRemove(CxList *list, size_t index);
238
239 size_t cxListRemoveArray(CxList *list, size_t index, size_t num);
240
241 size_t cxListFindRemove(CxList *list, const void *elem);
242
243 int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf);
244
245 int cxListRemoveAndGetFirst(CxList *list, void *targetbuf);
246
247 int cxListPopFront(CxList *list, void *targetbuf);
248
249 int cxListRemoveAndLast(CxList *list, void *targetbuf);
250
251 int cxListPop(CxList *list, void *targetbuf);
252
253 size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num,
254 void *targetbuf);
255
256 void cxListClear(CxList *list);
257 ```
258
259 The function `cxListRemove()` removes the element at the specified index and returns zero,
260 or returns non-zero if the index is out-of-bounds.
261 The function `cxListRemoveArray()` removes `num` elements starting at `index` and returns the number of elements that have been removed.
262 For each removed element, the [destructor functions](collection.h.md#destructor-functions) are called.
263
264 The function `cxListFindRemove()` finds the first element within the list that is equivalent to the element pointed to by `elem` and removes it from the list.
265 This will _also_ call destructor functions, if specified, so take special care when you continue to use `elem`.
266
267 On the other hand, `cxListRemoveAndGet()` family of functions do not invoke the destructor functions
268 and instead copy the elements into the `targetbuf`, which must be large enough to hold the removed elements.
269
270 > Note that when the list was initialized with `CX_STORE_POINTERS`,
271 > the elements that will be copied to the `targetbuf` are the _pointers_.
272 > In contrast to other list functions, like `cxListAt()`, an automatic dereferencing does not happen here.
273 >{style="note"}
274
275 The function `cxListClear()` simply removes all elements from the list, invoking the destructor functions.
276 It behaves equivalently but is usually more efficient than calling `cxListRemove()` for every index.
277
278 ## Iterators
279
280 ```C
281 #include <cx/list.h>
282
283 CxIterator cxListIterator(const CxList *list);
284
285 CxIterator cxListBackwardsIterator(const CxList *list);
286
287 CxIterator cxListIteratorAt(const CxList *list, size_t index);
288
289 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index);
290 ```
291
292 The functions `cxListIterator()` and `cxListBackwardsIterator()` create iterators
293 that start and the first or the last element in the list and iterate through the entire list.
294
295 The functions `cxListIteratorAt()` and `cxListBackwardsIteratorAt()` start with the element at the specified index
296 and iterate until the end, or the beginning of the list, respectively.
297
298 Removing elements via an iterator will cause an invocation of the [destructor functions](collection.h.md#destructor-functions) for the removed element.
299
300 It is safe to specify an out-of-bounds index, or a `NULL` pointer, in which cases the returned iterator will behave like an iterator over an empty list.
301
302 ## Reorder
303
304 ```C
305 #include <cx/list.h>
306
307 int cxListSwap(CxList *list, size_t i, size_t j);
308
309 void cxListReverse(CxList *list);
310
311 void cxListSort(CxList *list);
312 ```
313
314 The function `cxListSwap()` swaps two elements specified by the indices `i` and `j`.
315 The return value is non-zero if one of the indices is out-of-bounds.
316
317 The function `cxListReverse()` reorders all elements so that they appear in exactly the opposite order after invoking this function.
318
319 The function `cxListSort()` sorts all elements with respect to the list's compare function,
320 unless the list is already sorted (cf. `cxCollectionSorted()`), in which case the function immediately returns.
321
322 Default UCX implementations of the list interface make use of [small buffer optimizations](install.md#small-buffer-optimizations) when swapping elements.
323
324 > An invocation of `cxListSort` sets the `sorted` flag of the [collection](collection.h.md).
325 > Implementations usually make use of this flag to optimize search operations, if possible.
326 > For example, the [array list](array_list.h.md) implementation will use binary search
327 > for `cxListFind()` and similar operations when the list is sorted.
328
329 ## Compare
330
331 ```C
332 #include <cx/list.h>
333
334 int cxListCompare(const CxList *list, const CxList *other);
335 ```
336
337 Arbitrary lists can be compared element-wise with `cxListCompare()`, as long as the compare functions of both lists are equivalent.
338
339 That means you can compare an UCX [array list](array_list.h.md) with a [linked list](linked_list.h.md),
340 and you could even compare lists that are storing pointers with lists that are not storing pointers.
341
342 However, the optimized list-internal compare implementation is only used when both the compare functions and the list classes are identical.
343 Otherwise, `cxListCompare()` will behave as if you were iterating through both lists and manually comparing the elements.
344
345 The return value of `cxListCompare()` is zero if the lists are element-wise equivalent.
346 If they are not, the non-zero return value equals the return value of the used compare function for the first pair of elements that are not equal.
347
348 ## Clone
349
350 ```C
351 #include <cx/allocator.h>
352
353 typedef void*(cx_clone_func)(
354 void *target, const void *source,
355 const CxAllocator *allocator,
356 void *data);
357
358 #include <cx/list.h>
359
360 int cxListClone(CxList *dst, const CxList *src,
361 cx_clone_func clone_func,
362 const CxAllocator *clone_allocator,
363 void *data);
364
365 int cxListCloneShallow(CxList *dst, const CxList *src);
366
367 int cxListDifference(CxList *dst,
368 const CxList *minuend, const CxList *subtrahend,
369 cx_clone_func clone_func,
370 const CxAllocator *clone_allocator,
371 void *data);
372
373 int cxListDifferenceShallow(CxList *dst,
374 const CxList *minuend, const CxList *subtrahend);
375
376 int cxListIntersection(CxList *dst,
377 const CxList *src, const CxList *other,
378 cx_clone_func clone_func,
379 const CxAllocator *clone_allocator,
380 void *data);
381
382 int cxListIntersectionShallow(CxList *dst,
383 const CxList *src, const CxList *other);
384
385 int cxListUnion(CxList *dst,
386 const CxList *src, const CxList *other,
387 cx_clone_func clone_func,
388 const CxAllocator *clone_allocator,
389 void *data);
390
391 int cxListUnionShallow(CxList *dst,
392 const CxList *src, const CxList *other);
393 ```
394
395 With `cxListClone()` you can create deep copies of the elements in a list and insert them into another list.
396 The destination list does not need to be empty, in which case the elements will be appended.
397 Depending on the concrete list implementation, `cxListClone()` tries to allocate enough memory up-front before trying
398 to insert anything.
399
400 The function `cxListDifference()` clones elements from the `minuend` that are _not_ contained in the `subtrahend`,
401 while `cxListIntersection()` only clones elements from the `src` that are _also_ contained in the `other` list.
402 And `cxListUnion()` clones elements from `src` first, and from `other` only when they are _not_ contained in `src`.
403
404 All three functions, for union, difference, and intersection, are optimized for sorted lists.
405 In that case they will take linear time instead of quadratic time for the operation.
406 Also, `cxListUnion()` makes sure that the elements from `src` and `other` are cloned interleaving,
407 so that the result of the union is still sorted.
408
409 However, when the `dst` list already contains elements, all functions will only append the result of the operation to that list.
410 That means the `dst` list is only guaranteed to be sorted when it was empty and the input lists are all sorted.
411
412 Refer to the documentation of the [clone-function callback](allocator.h.md#clone-function) to learn how to implement it.
413
414 The _simple_ versions of the above functions use an internal shallow clone function
415 which uses `memcpy()` to copy the elements.
416 If the destination map is storing pointers, this internal clone function uses the current default allocator to allocate the memory.
417
418 The functions return zero if and only if all clone operations were successful.
419
420 > It is perfectly possible to clone items into a list of a different type.
421 > For example, you can clone elements from a list that is just storing pointers (`CX_STORE_POINTERS`) to a list that
422 > allocates the memory for the objects (and vice versa).
423
424 > The lists passed to the above functions must all be different.
425 > Passing the same pointer for different list arguments may result in erroneous behavior.
426 >{style="warning"}
427
428 ## Reserve and Shrink
429
430 ```C
431 #include <cx/list.h>
432
433 int cxListReserve(CxList *list, size_t count);
434
435 int cxListShrink(CxList *list);
436 ```
437
438 If a list implementation allows overallocation, the function `cxListReserve()` can be used to reserve memory for a total of `count` elements.
439 On the other hand, you can use `cxListShrink()` to dispose of any overallocated memory and reduce the capacity to the actual number of currently stored elements.
440 Calling `cxListReserve()` with a `count` argument that is less than the current size of the list has no effect, and the function returns zero.
441
442 If allocating memory fails, `cxListReserve()` returns a non-zero value.
443 Since shrinking should never fail, `cxListShrink()` will usually always return zero,
444 but depending on the list (or allocator) implementation, the possibility for a non-zero return value is there.
445
446 List implementations that do not overallocate are advised to simply return zero.
447 That means, using those functions never does any harm and calls to them can be added whenever it seems appropriate.
448 Even if the currently used list implementation does not support overallocation, it may become extremely useful when the concrete implementation is exchanged later.
449
450 > The function `cxListReserve()` should not be confused with `cxListEmplaceArray()`.
451 > The former will only increase the capacity of a list which supports overallocation without changing the size.
452 > The latter will actually add real, uninitialized elements.
453 >{style="note"}
454
455 ## Dispose
456
457 ```C
458 #include <cx/list.h>
459
460 void cxListFree(CxList *list);
461 ```
462
463 No matter with which function a `CxList` has been created, you can _always_ deallocate the entire memory with a call to `cxListFree()`.
464
465 The effect is equivalent to invoking `cxListClear()` plus deallocating the memory for the list structure.
466 That means, for each element in the list, the [destructor functions](collection.h.md#destructor-functions) are called before deallocating the list.
467
468 When the list has been storing pointers, make sure that either another reference to the same memory exists in your program,
469 or any of the destructor functions deallocates the memory.
470 Otherwise, there is a risk of a memory leak.
471
472 ## Implement own List Structures
473
474 If you want to create your own list implementation, this is extremely easy.
475
476 You need to define a function for creating your list and assign a `cx_list_class` structure with the pointers to your implementation.
477 Then you call the `cx_list_init()` helper function to initialize the collection sture.
478 This also automatically adds support for `CX_STORE_POINTERS` to your list.
479
480 ```C
481 // define the class with pointers to your functions
482 static cx_list_class my_list_class = {
483 my_list_deallocate,
484 my_list_insert_element,
485 my_list_insert_array,
486 my_list_insert_sorted,
487 my_list_insert_unique,
488 my_list_insert_iter,
489 my_list_remove,
490 my_list_clear,
491 my_list_swap,
492 my_list_at,
493 my_list_find_remove,
494 my_list_sort,
495 my_list_compare,
496 my_list_reverse,
497 my_list_change_capacity,
498 my_list_iterator,
499 };
500
501 typedef struct {
502 struct cx_list_s base;
503 // your custom list data goes here
504 } my_list;
505
506 CxList *my_list_create(
507 const CxAllocator *allocator,
508 size_t elem_size
509 ) {
510 if (allocator == NULL) {
511 allocator = cxDefaultAllocator;
512 }
513
514 my_list *list = cxCalloc(allocator, 1, sizeof(my_list));
515 if (list == NULL) return NULL;
516 cx_list_init((CxList*)list, &my_list_class,
517 allocator, elem_size);
518
519 // initialize your custom list data here
520
521 return (CxList *) list;
522 }
523 ```
524
525 The required behavior for the implementations is described in the following table.
526 You can always look at the source code of the UCX implementations to get inspiration.
527
528 | Function | Description |
529 |-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
530 | `clear` | Invoke destructor functions on all elements and remove them from the list. |
531 | `deallocate` | Invoke destructor functions on all elements and deallocate the entire list memory. |
532 | `insert_element` | Insert or allocate a single element at the specified index. Return a pointer to the allocated element or `NULL` on failure. |
533 | `insert_array` | Insert or allocate an array of elements starting at the specified index. Return the number of successfully inserted or allocated elements. |
534 | `insert_sorted` | Insert an array of sorted elements into a sorted list. Return the number of elements processed (equals the number of elements inserted in this case). |
535 | `insert_unique` | Insert an array of sorted unique elements into a sorted list. Return the number of elements processed (not the number of elements inserted, which might be lower). |
536 | `insert_iter` | Insert a single element depending on the iterator position. The third argument to this function is zero when the element shall be inserted after the iterator position and non-zero if it shall be inserted before the iterator position. The implementation is also responsible for adjusting the iterator, respectively. |
537 | `remove` | Remove multiple elements starting at the specified index. If a target buffer is specified, copy the elements to that buffer. Otherwise, invoke the destructor functions for the elements. Return the number of elements actually removed. |
538 | `swap` | Swap two elements by index. Return zero on success or non-zero when any index was out-of-bounds. |
539 | `at` | Return a pointer to the element at the specified index or `NULL` when the index is out-of-bounds. |
540 | `find_remove` | Search for the specified element with the list's compare function and return the index if found. If the `remove` argument is true, invoke the destructor functions and remove the element. Return the list size if the element is not found. |
541 | `sort` | Sort all elements in the list with respect to the list's compare function. |
542 | `compare` | This function pointer can be `NULL`, in which case an unoptimized fallback is used. You can implement an optimized compare function that compares the list of another list of the same class. |
543 | `reverse` | Reorder all elements in the list so that they appear in exactly the opposite order. |
544 | `change_capacity` | When your list supports overallocation, the capacity shall be changed to the specified value. Return non-zero on error and zero on success. When the list does not support overallocation, this function pointer can be `NULL`. |
545 | `iterator` | Create an iterator starting at the specified index. The Boolean argument indicates whether iteration is supposed to traverse backwards. |
546
547 > If you initialize your list with `cx_list_init()`, you do not have to worry about making a
548 > difference between storing pointers and storing elements, because your implementation will
549 > be automatically wrapped.
550 > This means you only have to handle the one single case described above.
551
552 ### Default Class Function Implementations
553
554 If you are satisfied with some of the default implementations, you can use some pre-defined functions.
555 Note, however, that those are not optimized for any specific list structure
556 and just serve as a quick and convenient solution if performance does not matter for your use case.
557
558
559 | Default Function | Description |
560 |---------------------------------|-----------------------------------------------------------------------------------|
561 | `cx_list_default_insert_array` | Falls back to multiple calls of `insert_element`. |
562 | `cx_list_default_insert_sorted` | Uses linear search to find insertion points. |
563 | `cx_list_default_insert_unique` | Like `cx_default_insert_sorted` but skips elements that are already contained. |
564 | `cx_list_default_sort` | Copies all elements to an array, applies `qsort()`, and copies the elements back. |
565 | `cx_list_default_swap` | Uses a temporarily allocated buffer to perform a three-way-swap. |
566
567
568 <seealso>
569 <category ref="apidoc">
570 <a href="https://ucx.sourceforge.io/api/list_8h.html">list.h</a>
571 </category>
572 </seealso>
573