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 |