docs/Writerside/topics/list.h.md

changeset 1240
c5924c781372
parent 1239
b4b1f15d1866
equal deleted inserted replaced
1239:b4b1f15d1866 1240:c5924c781372
1 # List Interface 1 # List Interface
2
3 <warning>
4 Outdated Section - will be updated soon!
5 </warning>
6 2
7 The `list.h` header defines a common interface for all list implementations. 3 The `list.h` header defines a common interface for all list implementations.
8 4
9 UCX already comes with two common list implementations ([linked list](linked_list.h.md) and [array list](array_list.h.md)) 5 UCX already comes with two common list implementations ([linked list](linked_list.h.md) and [array list](array_list.h.md))
10 that should cover most use cases. 6 that should cover most use cases.
40 36
41 > When you create a list which is storing pointers and do not specify a compare function, `cx_cmp_ptr` will be used by default. 37 > When you create a list which is storing pointers and do not specify a compare function, `cx_cmp_ptr` will be used by default.
42 38
43 ## Example 39 ## Example
44 40
45 <warning> 41 In the following example we create a linked-list of regular expressions for filtering data.
46 TODO: add example how to work with lists 42
47 </warning> 43 ```C
44 #include <cx/linked_list.h>
45 #include <regex.h>
46
47 CxList *create_pattern_list(void) {
48 // create a linked list to store patterns
49 CxList *list = cxLinkedListCreateSimple(sizeof(regex_t));
50
51 // automatically free the pattern when list gets destroyed
52 cxDefineDestructor(list, regfree);
53
54 return list;
55 }
56
57 int add_pattern(CxList *list, const char *value) {
58 // compile pattern and add it to the list, if successful
59 regex_t regex;
60 if (regcomp(&regex, value, REG_EXTENDED|REG_NOSUB)) {
61 return 1;
62 } else {
63 // take address of local variable
64 // since we are not storing pointers in this list,
65 // we get a copy of the data directly in the list
66 cxListAdd(list, &regex);
67 return 0;
68 }
69 }
70
71 bool matches_any(CxList *list, const char *text) {
72 CxIterator iter = cxListIterator(list);
73 cx_foreach(regex_t*, pat, iter) {
74 if (regexec(pat, text, 0, NULL, 0) == 0) {
75 return true;
76 }
77 }
78 return false;
79 }
80 ```
81
82 If in the above example the list was created with `CX_STORE_POINTERS` instead of `sizeof(regex_t)`,
83 the `add_pattern()` function would need to be changed as follows:
84
85 ```C
86 int add_pattern(CxList *list, const char *value) {
87 // allocate memory here, because now we are storing pointers
88 regex_t *regex = malloc(sizeof(regex_t));
89 if (!regex || regcomp(regex, value, REG_EXTENDED|REG_NOSUB)) {
90 return 1;
91 } else {
92 cxListAdd(list, regex);
93 return 0;
94 }
95 }
96 ```
97
98 Also, just registering `regfree()` as destructor is not sufficient anymore, because the `regex_t` structure also needs to be freed.
99 Therefore, we would need to wrap the calls to `regfree()` and `free()` into an own destructor, which we then register with the list.
100 However, it should be clear by now that using `CX_STORE_POINTERS` is a bad choice for this use case to begin with.
101
102 As a rule of thumb: if you allocate memory for an element that you immediately put into the list, consider storing the element directly.
103 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`.
48 104
49 > If you want to lazy-initialize lists, you can use the global `cxEmptyList` symbol as a placeholder instead of using a `NULL`-pointer. 105 > If you want to lazy-initialize lists, you can use the global `cxEmptyList` symbol as a placeholder instead of using a `NULL`-pointer.
50 > While you *must not* insert elements into that list, you can safely access this list or create iterators. 106 > While you *must not* insert elements into that list, you can safely access this list or create iterators.
51 > This allows you to write clean code without checking for `NULL`-pointer everywhere. 107 > This allows you to write clean code without checking for `NULL`-pointer everywhere.
52 > You still need to make sure that the placeholder is replaced with an actual list before inserting elements. 108 > You still need to make sure that the placeholder is replaced with an actual list before inserting elements.
77 133
78 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. 134 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.
79 Similarly, `cxListInsert()` adds the element at the specified `index`, 135 Similarly, `cxListInsert()` adds the element at the specified `index`,
80 and `cxListInsertSorted()` adds the element at the correct position so that the list remains sorted according to the list's compare function. 136 and `cxListInsertSorted()` adds the element at the correct position so that the list remains sorted according to the list's compare function.
81 137
82 When you are currently iterating through a list, you can insert items before or after the current position of the iterator 138 When you are currently iterating through a list, you can insert elements before or after the current position of the iterator
83 with `cxListInsertBefore()` or `cxListInsertAfter()`, respectively. 139 with `cxListInsertBefore()` or `cxListInsertAfter()`, respectively.
84 This _should_ be done with [mutating iterators](iterator.h.md#mutating-iterators) only, but is also defined for normal iterators. 140 This _should_ be done with [mutating iterators](iterator.h.md#mutating-iterators) only, but is also defined for normal iterators.
85 141
86 If the list is storing pointers (cf. `cxCollectionStoresPointers()`), the pointer `elem` is directly added to the list. 142 If the list is storing pointers (cf. `cxCollectionStoresPointers()`), the pointer `elem` is directly added to the list.
87 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. 143 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.
259 or any of the destructor functions deallocates the memory. 315 or any of the destructor functions deallocates the memory.
260 Otherwise, there is a risk of a memory leak. 316 Otherwise, there is a risk of a memory leak.
261 317
262 ## Implement own List Structures 318 ## Implement own List Structures
263 319
264 <warning> 320 If you want to create your own list implementation, this is extremely easy.
265 TODO: add documentation 321
266 </warning> 322 You just need to define a function for creating your list and assign a `cx_list_class` structure with the pointers to your implementation.
323 Then you call the `cx_list_init()` helper function to initialize the collection sture.
324 This also automatically adds support for `CX_STORE_POINTERS` to your list.
325
326 ```C
327 // define the class with pointers to your functions
328 static cx_list_class my_list_class = {
329 my_list_destructor,
330 my_list_insert_element,
331 my_list_insert_array,
332 my_list_insert_sorted,
333 my_list_insert_iter,
334 my_list_remove,
335 my_list_clear,
336 my_list_swap,
337 my_list_at,
338 my_list_find_remove,
339 my_list_sort,
340 my_list_compare,
341 my_list_reverse,
342 my_list_iterator,
343 };
344
345 typedef struct {
346 struct cx_list_s base;
347 // your custom list data goes here
348 } my_list;
349
350 CxList *my_list_create(
351 const CxAllocator *allocator,
352 cx_compare_func cmpfun,
353 size_t elem_size
354 ) {
355 if (allocator == NULL) {
356 allocator = cxDefaultAllocator;
357 }
358
359 my_list *list = cxCalloc(allocator, 1, sizeof(my_list));
360 if (list == NULL) return NULL;
361 cx_list_init((CxList*)list, &my_list_class,
362 allocator, cmpfun, elem_size);
363
364 // initialize your custom list data here
365
366 return (CxList *) list;
367 }
368 ```
369
370 The required behavior for the implementations is described in the following table.
371 You can always look at the source code of the UCX implementations to get inspiration.
372
373 | Function | Description |
374 |------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
375 | `clear` | Invoke destructor functions on all elements and remove them from the list. |
376 | `destructor` | Invoke destructor functions on all elements and deallocate the entire list memory. |
377 | `insert_element` | Insert a single element at the specified index. Return zero on success and non-zero on failure. |
378 | `insert_array` | Insert an array of elements starting at the specified index. Return the number of elements inserted. |
379 | `insert_sorted` | Insert an array of sorted elements into a sorted list. Return the number of elements inserted. |
380 | `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. |
381 | `remove` | Removes a 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. |
382 | `swap` | Swap two elements by index. Return zero on success or non-zero when any index was out-of-bounds. |
383 | `at` | Return a pointer to the element at the specified index or `NULL` when the index is out-of-bounds. |
384 | `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. |
385 | `sort` | Sort all elements in the list with respect to the list's compare function. |
386 | `compare` | Only function pointer that may 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. |
387 | `reverse` | Reorders all elements in the list so that they appear in exactly the opposite order. |
388 | `iterator` | Creates an iterator starting at the specified index. The Boolean argument indicates whether iteration is supposed to traverse backwards. |
389
390 > If you initialize your list with `cx_list_init()` you do not have to worry about making a
391 > difference between storing pointers and storing elements, because your implementation will
392 > be automatically wrapped.
393 > This means, you only have to handle the one single case described above.
394
395 ### Default Class Function Implementations
396
397 If you are satisfied with some of the default implementations, you can use some pre-defined functions.
398 Note, however, that those are not optimized for any specific list structure
399 and just serve as a quick and convenient solution if performance does not matter for your use case.
400
401
402 | Default Function | Description |
403 |---------------------------------|-----------------------------------------------------------------------------------|
404 | `cx_list_default_insert_array` | Falls back to multiple calls of `insert_element`. |
405 | `cx_list_default_insert_sorted` | Uses linear search to find insertion points. |
406 | `cx_list_default_sort` | Copies all elements to an array, applies `qsort()`, and copies the elements back. |
407 | `cx_list_default_swap` | Uses a temporarily allocated buffer to perform a three-way-swap. |
408
267 409
268 <seealso> 410 <seealso>
269 <category ref="apidoc"> 411 <category ref="apidoc">
270 <a href="https://ucx.sourceforge.io/api/list_8h.html">list.h</a> 412 <a href="https://ucx.sourceforge.io/api/list_8h.html">list.h</a>
271 </category> 413 </category>

mercurial