| 8 |
8 |
| 9 UCX already comes with two common list implementations ([linked list](linked_list.h.md) and [array list](array_list.h.md)) |
9 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. |
10 that should cover most use cases. |
| 11 But if you feel the need to implement an own list, you will find instructions [below](#implement-own-list-structures). |
11 But if you feel the need to implement an own list, you will find instructions [below](#implement-own-list-structures). |
| 12 |
12 |
| |
13 ```C |
| |
14 #include <cx/linked_list.h> |
| |
15 |
| |
16 CxList *cxLinkedListCreate(const CxAllocator *allocator, |
| |
17 cx_compare_func comparator, size_t elem_size); |
| |
18 |
| |
19 CxList *cxLinkedListCreateSimple(size_t elem_size); |
| |
20 |
| |
21 #include <cx/array_list.h> |
| |
22 |
| |
23 CxList *cxArrayListCreate(const CxAllocator *allocator, |
| |
24 cx_compare_func comparator, size_t elem_size, |
| |
25 size_t initial_capacity); |
| |
26 |
| |
27 CxList *cxArrayListCreateSimple(size_t elem_size, |
| |
28 size_t initial_capacity); |
| |
29 ``` |
| |
30 |
| |
31 The function `cxLinkedListCreate()` creates a new linked list with the specified `allocator` which stores elements of size `elem_size`. |
| |
32 The elements are supposed to be compared with the specified `comparator` (cf. [](#access-and-find)). |
| |
33 The function `cxLinkedListCreateSimple()` will use the stdlib default allocator and does not specify a compare function. |
| |
34 |
| |
35 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. |
| |
36 |
| |
37 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. |
| |
38 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. |
| |
39 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. |
| |
40 |
| |
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. |
| |
42 |
| 13 ## Example |
43 ## Example |
| 14 |
44 |
| 15 <warning> |
45 <warning> |
| 16 TODO: add example how to work with lists |
46 TODO: add example how to work with lists |
| 17 </warning> |
47 </warning> |
| 18 |
48 |
| 19 > If you want to lazy-initialize lists, you can use the global `cxEmptyList` symbol as a placeholder instead of using a `NULL`-pointer. |
49 > If you want to lazy-initialize lists, you can use the global `cxEmptyList` symbol as a placeholder instead of using a `NULL`-pointer. |
| 20 > While you *must not* insert items into that list, you can safely access this list or create iterators. |
50 > While you *must not* insert elements into that list, you can safely access this list or create iterators. |
| 21 > This allows you to write clean code without checking for `NULL`-pointer everywhere. |
51 > This allows you to write clean code without checking for `NULL`-pointer everywhere. |
| 22 > You still need to make sure that the placeholder is replaced with an actual list before inserting items. |
52 > You still need to make sure that the placeholder is replaced with an actual list before inserting elements. |
| 23 |
53 |
| 24 ## Insert |
54 ## Insert |
| 25 |
55 |
| 26 ```C |
56 ```C |
| |
57 #include <cx/list.h> |
| |
58 |
| 27 int cxListAdd(CxList *list, const void *elem); |
59 int cxListAdd(CxList *list, const void *elem); |
| 28 |
60 |
| |
61 int cxListInsert(CxList *list, size_t index, const void *elem); |
| |
62 |
| |
63 int cxListInsertSorted(CxList *list, const void *elem); |
| |
64 |
| 29 size_t cxListAddArray(CxList *list, const void *array, size_t n); |
65 size_t cxListAddArray(CxList *list, const void *array, size_t n); |
| 30 |
|
| 31 int cxListInsert(CxList *list, size_t index, const void *elem); |
|
| 32 |
|
| 33 int cxListInsertSorted(CxList *list, const void *elem); |
|
| 34 |
66 |
| 35 size_t cxListInsertArray(CxList *list, size_t index, |
67 size_t cxListInsertArray(CxList *list, size_t index, |
| 36 const void *array, size_t n); |
68 const void *array, size_t n); |
| 37 |
69 |
| 38 size_t cxListInsertSortedArray(CxList *list, |
70 size_t cxListInsertSortedArray(CxList *list, |
| 41 int cxListInsertAfter(CxIterator *iter, const void *elem); |
73 int cxListInsertAfter(CxIterator *iter, const void *elem); |
| 42 |
74 |
| 43 int cxListInsertBefore(CxIterator *iter, const void *elem); |
75 int cxListInsertBefore(CxIterator *iter, const void *elem); |
| 44 ``` |
76 ``` |
| 45 |
77 |
| 46 <warning> |
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. |
| 47 TODO: add documentation |
79 Similarly, `cxListInsert()` adds the element at the specified `index`, |
| 48 </warning> |
80 and `cxListInsertSorted()` adds the element at the correct position so that the list remains sorted according to the list's compare function. |
| |
81 |
| |
82 When you are currently iterating through a list, you can insert items before or after the current position of the iterator |
| |
83 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. |
| |
85 |
| |
86 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. |
| |
88 |
| |
89 On the other hand the `array` argument for `cxListAddArray()`, `cxListInsertArray()`, and `cxListInsertSortedArray()` |
| |
90 must always point to an array of elements to be added (i.e. either an array of pointers, or an array of actual elements). |
| |
91 |
| |
92 A special requirement for `cxListInsertSortedArray()` is, that the `array` must already be sorted. |
| |
93 |
| |
94 > Implementations are required to optimize the insertion of a sorted array into a sorted list in linear time, |
| |
95 > while inserting each element separately via `cxListInsertSorted()` may take quadratic time. |
| |
96 |
| |
97 > The functions `cxListInsertSorted()` and `cxListInsertSortedArray()` do neither check if the list is already sorted, nor do they actively sort the list. |
| |
98 > {style="note"} |
| 49 |
99 |
| 50 ## Access and Find |
100 ## Access and Find |
| 51 |
101 |
| 52 ```C |
102 <link-summary>Functions for searching and accessing elements.</link-summary> |
| |
103 |
| |
104 ```C |
| |
105 #include <cx/list.h> |
| |
106 |
| |
107 void *cxListAt(const CxList *list, size_t index); |
| |
108 |
| |
109 size_t cxListFind(const CxList *list, const void *elem); |
| |
110 |
| |
111 size_t cxListFindRemove(CxList *list, const void *elem); |
| |
112 |
| |
113 bool cxListIndexValid(const CxList *list, size_t index); |
| |
114 |
| 53 size_t cxListSize(const CxList *list); |
115 size_t cxListSize(const CxList *list); |
| 54 |
116 ``` |
| 55 void *cxListAt(const CxList *list, size_t index); |
117 |
| 56 |
118 The function `cxListAt()` accesses the element at the specified `index`. |
| 57 size_t cxListFind(const CxList *list, const void *elem); |
119 If the list is storing pointers (i.e. `cxCollectionStoresPointers()` returns `true`), the pointer at the specified index is directly returned. |
| 58 |
120 Otherwise, a pointer to element at the specified index is returned. |
| 59 size_t cxListFindRemove(CxList *list, const void *elem); |
121 If the index is out-of-bounds, the function returns `NULL`. |
| 60 |
122 |
| 61 bool cxListIndexValid(const CxList *list, size_t index); |
123 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, |
| 62 ``` |
124 and returns the first index when the element was found. |
| 63 |
125 Otherwise, the function returns the list size. |
| 64 <warning> |
126 |
| 65 TODO: add documentation |
127 The function `cxListFindRemove()` behaves like `cxListFind()`, except that it also removes the first occurrence of the element from the list. |
| 66 </warning> |
128 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. |
| |
129 |
| |
130 With `cxListIndexValid()` you can check the index returned by `cxListFind()` or `cxListFindRemove()`, |
| |
131 which is more convenient than comparing the return value if the return value of `cxListSize()`. |
| 67 |
132 |
| 68 ## Remove |
133 ## Remove |
| 69 |
134 |
| 70 ```C |
135 ```C |
| |
136 #include <cx/list.h> |
| |
137 |
| 71 int cxListRemove(CxList *list, size_t index); |
138 int cxListRemove(CxList *list, size_t index); |
| 72 |
139 |
| |
140 size_t cxListRemoveArray(CxList *list, size_t index, size_t num); |
| |
141 |
| 73 int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf); |
142 int cxListRemoveAndGet(CxList *list, size_t index, void *targetbuf); |
| 74 |
|
| 75 size_t cxListRemoveArray(CxList *list, size_t index, size_t num); |
|
| 76 |
143 |
| 77 size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num, |
144 size_t cxListRemoveArrayAndGet(CxList *list, size_t index, size_t num, |
| 78 void *targetbuf); |
145 void *targetbuf); |
| |
146 |
| |
147 size_t cxListFindRemove(CxList *list, const void *elem); |
| 79 |
148 |
| 80 void cxListClear(CxList *list); |
149 void cxListClear(CxList *list); |
| 81 ``` |
150 ``` |
| 82 |
151 |
| 83 <warning> |
152 The function `cxListRemove()` removes the element at the specified index and returns zero, |
| 84 TODO: add documentation |
153 or returns non-zero if the index is out-of-bounds. |
| 85 </warning> |
154 The function `cxListRemoveArray()` removes `num` elements starting at `index` and returns the number of elements that have been removed. |
| |
155 For each removed element, the [destructor functions](collection.h.md#destructor-functions) are called. |
| |
156 |
| |
157 On the other hand, `cxListRemoveAndGet()` and `cxListRemoveArrayAndGet()` do not invoke the destructor functions |
| |
158 and instead copy the elements into the `targetbuf`, which must be large enough to hold the removed elements. |
| |
159 |
| |
160 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. |
| |
161 This will _also_ call destructor functions, if specified, so take special care when you continue to use `elem`. |
| |
162 |
| |
163 The function `cxListClear()` simply removes all elements from the list, invoking the destructor functions. |
| |
164 It behaves equivalently, but is usually more efficient than calling `cxListRemove()` for every index. |
| 86 |
165 |
| 87 ## Iterators |
166 ## Iterators |
| 88 |
167 |
| 89 ```C |
168 ```C |
| |
169 #include <cx/list.h> |
| |
170 |
| 90 CxIterator cxListIterator(const CxList *list); |
171 CxIterator cxListIterator(const CxList *list); |
| 91 |
172 |
| |
173 CxIterator cxListBackwardsIterator(const CxList *list); |
| |
174 |
| |
175 CxIterator cxListIteratorAt(const CxList *list, size_t index); |
| |
176 |
| |
177 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index); |
| |
178 |
| 92 CxIterator cxListMutIterator(CxList *list); |
179 CxIterator cxListMutIterator(CxList *list); |
| 93 |
180 |
| 94 CxIterator cxListBackwardsIterator(const CxList *list); |
|
| 95 |
|
| 96 CxIterator cxListMutBackwardsIterator(CxList *list); |
181 CxIterator cxListMutBackwardsIterator(CxList *list); |
| 97 |
182 |
| 98 CxIterator cxListIteratorAt(const CxList *list, size_t index); |
|
| 99 |
|
| 100 CxIterator cxListBackwardsIteratorAt(const CxList *list, size_t index); |
|
| 101 |
|
| 102 CxIterator cxListMutIteratorAt(CxList *list, size_t index); |
183 CxIterator cxListMutIteratorAt(CxList *list, size_t index); |
| 103 |
184 |
| 104 CxIterator cxListMutBackwardsIteratorAt(CxList *list, size_t index); |
185 CxIterator cxListMutBackwardsIteratorAt(CxList *list, size_t index); |
| 105 ``` |
186 ``` |
| 106 |
187 |
| 107 <warning> |
188 The functions `cxListIterator()` and `cxListBackwardsIterator()` create iterators |
| 108 TODO: add documentation |
189 that start and the first or the last element in the list and iterate through the entire list. |
| 109 </warning> |
190 |
| |
191 The functions `cxListIteratorAt()` and `cxListBackwardsIteratorAt()` start with the element at the specified index |
| |
192 and iterate until the end, or the beginning of the list, respectively. |
| |
193 |
| |
194 The functions with `Mut` in are equivalently, except that they create a [mutating iterator](iterator.h.md#mutating-iterators). |
| |
195 Removing elements via a mutating iterator will cause an invocation of the [destructor functions](collection.h.md#destructor-functions) for the removed element. |
| |
196 |
| |
197 If is safe to specify an out-of-bounds index in which case an iterator is returned for which `cxIteratorValid()` returns `false`, immediately. |
| 110 |
198 |
| 111 ## Reorder |
199 ## Reorder |
| 112 |
200 |
| 113 ```C |
201 ```C |
| |
202 #include <cx/list.h> |
| |
203 |
| 114 int cxListSwap(CxList *list, size_t i, size_t j); |
204 int cxListSwap(CxList *list, size_t i, size_t j); |
| 115 |
205 |
| |
206 void cxListReverse(CxList *list); |
| |
207 |
| 116 void cxListSort(CxList *list); |
208 void cxListSort(CxList *list); |
| 117 |
209 ``` |
| 118 void cxListReverse(CxList *list); |
210 |
| 119 ``` |
211 The function `cxListSwap()` swaps two elements specified by the indices `i` and `j`. |
| 120 |
212 The return value is non-zero if one of the indices is out-of-bounds. |
| 121 <warning> |
213 |
| 122 TODO: add documentation |
214 The function `cxListReverse()` reorders all elements, so that they appear in exactly the opposite order after invoking this function. |
| 123 </warning> |
215 |
| |
216 The function `cxListSort()` sorts all elements with respect to the list's compare function, |
| |
217 unless the list is already sorted (cf. `cxCollectionSorted()`), in which case the function immediately returns. |
| |
218 |
| |
219 Default UCX implementations of the list interface make use of [small buffer optimizations](install.md#small-buffer-optimizations) when swapping elements. |
| |
220 |
| |
221 > An invocation of `cxListSort` sets the `sorted` flag of the [collection](collection.h.md). |
| |
222 > Implementations usually make use of this flag to optimize search operations, if possible. |
| |
223 > For example the [array list](array_list.h.md) implementation will use binary search |
| |
224 > for `cxListFind()` and similar operations, when the list is sorted. |
| 124 |
225 |
| 125 ## Compare |
226 ## Compare |
| 126 |
227 |
| 127 ```C |
228 ```C |
| |
229 #include <cx/list.h> |
| |
230 |
| 128 int cxListCompare(const CxList *list, const CxList *other); |
231 int cxListCompare(const CxList *list, const CxList *other); |
| 129 ``` |
232 ``` |
| 130 |
233 |
| 131 Arbitrary lists can be compared item-wise with `cxListCompare()`, as long as the compare functions of both lists are equivalent. |
234 Arbitrary lists can be compared element-wise with `cxListCompare()`, as long as the compare functions of both lists are equivalent. |
| 132 |
235 |
| 133 That means, you can compare an UCX [array list](array_list.h.md) with a [linked list](linked_list.h.md), |
236 That means, you can compare an UCX [array list](array_list.h.md) with a [linked list](linked_list.h.md), |
| 134 and you could even compare lists that are storing pointers with lists that are not storing pointers. |
237 and you could even compare lists that are storing pointers with lists that are not storing pointers. |
| 135 |
238 |
| 136 However, the optimized list-internal compare implementation is only used, when both the compare functions and the list classes are identical. |
239 However, the optimized list-internal compare implementation is only used, when both the compare functions and the list classes are identical. |
| 137 Otherwise, `cxListCompare()` will behave as if you were iterating through both lists and manually comparing the items. |
240 Otherwise, `cxListCompare()` will behave as if you were iterating through both lists and manually comparing the elements. |
| 138 |
241 |
| 139 The return value of `cxListCompare()` is zero, if the lists are item-wise equivalent. |
242 The return value of `cxListCompare()` is zero, if the lists are element-wise equivalent. |
| 140 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. |
243 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. |
| 141 |
244 |
| 142 ## Dispose |
245 ## Dispose |
| 143 |
246 |
| 144 ```C |
247 ```C |
| |
248 #include <cx/list.h> |
| |
249 |
| 145 void cxListFree(CxList *list); |
250 void cxListFree(CxList *list); |
| 146 ``` |
251 ``` |
| 147 |
252 |
| 148 No matter with which function a `CxList` has been created, you can _always_ deallocate the entire memory with a call to `cxListFree()`. |
253 No matter with which function a `CxList` has been created, you can _always_ deallocate the entire memory with a call to `cxListFree()`. |
| 149 |
254 |
| 150 The effect is equivalent to invoking `cxListClear()` plus deallocating the memory for the list structure. |
255 The effect is equivalent to invoking `cxListClear()` plus deallocating the memory for the list structure. |
| 151 That means, for each item in the list, the destructor functions defined by `cxDefineDestructor()` or `cxDefineAdvancedDestructor()` are called, |
256 That means, for each element in the list, the [destructor functions](collection.h.md#destructor-functions) are called before deallocating the list. |
| 152 before deallocating the list. |
|
| 153 |
257 |
| 154 When the list has been storing pointers, make sure that either another reference to the same memory exist in your program, |
258 When the list has been storing pointers, make sure that either another reference to the same memory exist in your program, |
| 155 or any of the destructor functions deallocates the memory. |
259 or any of the destructor functions deallocates the memory. |
| 156 Otherwise, there is a risk of a memory leak. |
260 Otherwise, there is a risk of a memory leak. |
| 157 |
261 |