docs/Writerside/topics/list.h.md

changeset 1639
5c3e6477aab4
parent 1618
ef7cab6eb131
equal deleted inserted replaced
1638:14ae6a039af7 1639:5c3e6477aab4
2 2
3 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.
4 4
5 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))
6 that should cover most use cases. 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). 7 A more advanced use case is implemented as a [key/value list](kv_list.h.md).
8 If you feel the need to implement your own list, you will find the instructions [below](#implement-own-list-structures).
8 9
9 ```C 10 ```C
10 #include <cx/linked_list.h> 11 #include <cx/linked_list.h>
11 12
12 CxList *cxLinkedListCreate(const CxAllocator *allocator, 13 CxList *cxLinkedListCreate(const CxAllocator *allocator,
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.
42 #include <cx/linked_list.h> 51 #include <cx/linked_list.h>
43 #include <regex.h> 52 #include <regex.h>
44 53
45 CxList *create_pattern_list(void) { 54 CxList *create_pattern_list(void) {
46 // create a linked list to store patterns 55 // create a linked list to store patterns
56 // NULL means, the cxDefaultAllocator will be used
47 CxList *list = cxLinkedListCreate(NULL, sizeof(regex_t)); 57 CxList *list = cxLinkedListCreate(NULL, sizeof(regex_t));
48 58
49 // automatically free the pattern when list gets destroyed 59 // automatically free the pattern when list gets destroyed
50 cxSetDestructor(list, regfree); 60 cxSetDestructor(list, regfree);
51 61
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

mercurial