| 14 |
15 |
| 15 #include <cx/array_list.h> |
16 #include <cx/array_list.h> |
| 16 |
17 |
| 17 CxList *cxArrayListCreate(const CxAllocator *allocator, |
18 CxList *cxArrayListCreate(const CxAllocator *allocator, |
| 18 size_t elem_size, size_t initial_capacity); |
19 size_t elem_size, size_t initial_capacity); |
| |
20 |
| |
21 #include <cx/kv_list.h> |
| |
22 |
| |
23 CxList *cxKvListCreate(const CxAllocator *allocator, |
| |
24 size_t elem_size); |
| |
25 |
| |
26 CxMap *cxKvListCreateAsMap(const CxAllocator *allocator, |
| |
27 size_t elem_size); |
| 19 ``` |
28 ``` |
| 20 |
29 |
| 21 The function `cxLinkedListCreate()` creates a new linked list with the specified `allocator` which stores elements of size `elem_size`. |
30 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 |
31 |
| 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. |
32 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. |
| |
33 |
| |
34 The key/value list implements both the list and the [map](map.h.md) interfaces and allows access to the elements via a key. |
| |
35 Depending on the perspective, you can see a key/value list as an associative list or as an _ordered_ map. |
| 25 |
36 |
| 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. |
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. |
| 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. |
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. |
| 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. |
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. |
| 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 |
40 |
| 32 > If you want to lazy-initialize lists, you can use the global `cxEmptyList` symbol as a placeholder instead of using a `NULL`-pointer. |
41 > 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. |
42 > 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. |
43 > 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. |
44 > You still need to make sure that the placeholder is replaced with an actual list before inserting elements. |
| 149 > the iterator will iterate only over the elements that have been successfully allocated. |
159 > 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. |
160 > 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`. |
161 > And the `index` attribute will count from zero to `elem_count - 1`. |
| 152 > {style="note"} |
162 > {style="note"} |
| 153 |
163 |
| |
164 If the list is storing pointers (cf. `cxCollectionStoresPointers()`), the pointer `elem` is directly added to the list. |
| |
165 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. |
| |
166 |
| |
167 When you are currently iterating through a list, you can insert elements before or after the current position of the iterator |
| |
168 with `cxListInsertBefore()` or `cxListInsertAfter()`, respectively. |
| |
169 |
| 154 The function `cxListInsertSorted()` inserts the element at the correct position so that the list remains sorted according to the list's compare function. |
170 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. |
171 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. |
172 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. |
173 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 |
174 |
| 159 When you are currently iterating through a list, you can insert elements before or after the current position of the iterator |
175 > Inserting sorted or unique elements requires a [comparator function](collection.h.md#comparator-functions). |
| 160 with `cxListInsertBefore()` or `cxListInsertAfter()`, respectively. |
176 > If you haven't set one specifically, the list is using `cx_cmp_ptr` for pointer lists and |
| 161 |
177 > a `memcmp()`-based solution for non-pointer lists by default. |
| 162 If the list is storing pointers (cf. `cxCollectionStoresPointers()`), the pointer `elem` is directly added to the list. |
178 > They might be enough to determine uniqueness, but are usually not capable of determining a reasonable sort order. |
| 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. |
179 > |
| 164 |
180 > It is strongly recommended to set a comparator function (e.g., one of those defined in [compare.h](compare.h.md)) |
| 165 On the other hand, the `array` argument for `cxListAddArray()`, `cxListInsertArray()`, `cxListInsertSortedArray()`, and `cxListInsertUniqueArray()` |
181 > with `cxSetCompareFunc()` after creating the list, when you intend to use functions that need to compare elements. |
| |
182 > {style="note"} |
| |
183 |
| |
184 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). |
185 must always point to an array of elements to be added (i.e., either an array of pointers or an array of actual elements). |
| |
186 Here, no auto-magic is implemented, depending on `cxCollectionStoresPointers()`. |
| 167 |
187 |
| 168 The return values of the array-inserting functions are the number of elements that have been successfully _processed_. |
188 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()`, |
189 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. |
190 where the actual number of inserted elements may be lower than the number of successfully processed elements. |
| 171 |
191 |
| 172 > Implementations are required to optimize the insertion of a sorted array into a sorted list in linear time, |
192 > 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. |
193 > while inserting each element separately via `cxListInsertSorted()` may take quadratic time. |
| 174 > |
194 > |
| 175 > When used with sorted lists, the arrays passed to the functions must also be sorted according to the list's compare function. |
195 > When the `list` is sorted, the `array` 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. |
196 > As a special case, `cxListInsertUniqueArray()` also works with lists that are not sorted, in which case the `array` also does not need to be sorted. |
| 177 > |
197 > However, it is strongly recommended to work with sorted arrays to avoid bugs that are caused by a failed assumption. |
| 178 > The functions do not check if the passed arrays are sorted. |
198 > Plus, the functions do not check if the passed arrays are sorted! |
| 179 > {style="note"} |
199 > {style="note"} |
| 180 |
200 |
| 181 ## Access and Find |
201 ## Access and Find |
| 182 |
202 |
| 183 <link-summary>Functions for searching and accessing elements.</link-summary> |
203 Functions for searching and accessing elements. |
| 184 |
204 |
| 185 ```C |
205 ```C |
| 186 #include <cx/list.h> |
206 #include <cx/list.h> |
| 187 |
207 |
| 188 void *cxListAt(const CxList *list, size_t index); |
208 void *cxListAt(const CxList *list, size_t index); |
| 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. |
245 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 |
246 |
| 227 The function `cxListContains()` returns `true` if and only if `cxListFind()` returns a valid index. |
247 The function `cxListContains()` returns `true` if and only if `cxListFind()` returns a valid index. |
| 228 |
248 |
| 229 With `cxListIndexValid()` you can check the index returned by `cxListFind()` or `cxListFindRemove()`, |
249 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()`. |
250 which is more convenient than comparing the return value with the return value of `cxListSize()`. |
| |
251 |
| |
252 > The functions `cxListFind()`, `cxListFindRemove()`, and `cxListContains()` use the collections |
| |
253 > [comparator function](collection.h.md#comparator-functions). |
| |
254 > If you haven't set one specifically, the list is using `cx_cmp_ptr` for pointer lists and |
| |
255 > a `memcmp()`-based solution for non-pointer lists by default. |
| |
256 > {style="note"} |
| 231 |
257 |
| 232 ## Remove |
258 ## Remove |
| 233 |
259 |
| 234 ```C |
260 ```C |
| 235 #include <cx/list.h> |
261 #include <cx/list.h> |
| 261 The function `cxListRemoveArray()` removes `num` elements starting at `index` and returns the number of elements that have been removed. |
287 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. |
288 For each removed element, the [destructor functions](collection.h.md#destructor-functions) are called. |
| 263 |
289 |
| 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. |
290 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`. |
291 This will _also_ call destructor functions, if specified, so take special care when you continue to use `elem`. |
| |
292 This function needs a valid [comparator function](collection.h.md#comparator-functions). |
| 266 |
293 |
| 267 On the other hand, `cxListRemoveAndGet()` family of functions do not invoke the destructor functions |
294 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. |
295 and instead copy the elements into the `targetbuf`, which must be large enough to hold the removed elements. |
| 269 |
296 |
| 270 > Note that when the list was initialized with `CX_STORE_POINTERS`, |
297 > Note that when the list was initialized with `CX_STORE_POINTERS`, |
| 324 > An invocation of `cxListSort` sets the `sorted` flag of the [collection](collection.h.md). |
351 > 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. |
352 > 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 |
353 > 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. |
354 > for `cxListFind()` and similar operations when the list is sorted. |
| 328 |
355 |
| |
356 > The function `cxListSort()` uses the collections [comparator function](collection.h.md#comparator-functions). |
| |
357 > If you haven't set one specifically, the list is using `cx_cmp_ptr` for pointer lists and |
| |
358 > a `memcmp()`-based solution for non-pointer lists by default, which do not provide a reasonable order of the elements. |
| |
359 > |
| |
360 > It is strongly recommended to set a comparator function (e.g., one of those defined in [compare.h](compare.h.md)) |
| |
361 > with `cxSetCompareFunc()` after creating the list, when you intend to use functions that need to compare elements. |
| |
362 > {style="note"} |
| |
363 |
| 329 ## Compare |
364 ## Compare |
| 330 |
365 |
| 331 ```C |
366 ```C |
| 332 #include <cx/list.h> |
367 #include <cx/list.h> |
| 333 |
368 |
| 334 int cxListCompare(const CxList *list, const CxList *other); |
369 int cxListCompare(const CxList *list, const CxList *other); |
| 335 ``` |
370 ``` |
| 336 |
371 |
| 337 Arbitrary lists can be compared element-wise with `cxListCompare()`, as long as the compare functions of both lists are equivalent. |
372 Arbitrary lists can be compared element-wise with `cxListCompare()`, |
| |
373 as long as the [comparator functions](collection.h.md#comparator-functions) of both lists are equivalent. |
| 338 |
374 |
| 339 That means you can compare an UCX [array list](array_list.h.md) with a [linked list](linked_list.h.md), |
375 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. |
376 and you could even compare lists that are storing pointers with lists that are not storing pointers. |
| 341 |
377 |
| 342 However, the optimized list-internal compare implementation is only used when both the compare functions and the list classes are identical. |
378 However, the optimized list-internal compare implementation is only used when they are identical for both lists. |
| 343 Otherwise, `cxListCompare()` will behave as if you were iterating through both lists and manually comparing the elements. |
379 Otherwise, `cxListCompare()` will behave as if you were iterating through both lists and manually comparing the elements. |
| |
380 |
| |
381 > Since the [key/value list](kv_list.h.md) is based on a [linked list](linked_list.h.md), |
| |
382 > they share the same optimized implementation for `compare`. |
| |
383 > That means comparing a key/value list with a normal linked list is as efficient as comparing two linked lists. |
| 344 |
384 |
| 345 The return value of `cxListCompare()` is zero if the lists are element-wise equivalent. |
385 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. |
386 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 |
387 |
| 348 ## Clone |
388 ## Clone |