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 an own list, you will find instructions [below](#implement-own-list-structures). |
7 But if you feel the need to implement your own list, you will find the instructions [below](#implement-own-list-structures). |
8 |
8 |
9 ```C |
9 ```C |
10 #include <cx/linked_list.h> |
10 #include <cx/linked_list.h> |
11 |
11 |
12 CxList *cxLinkedListCreate(const CxAllocator *allocator, |
12 CxList *cxLinkedListCreate(const CxAllocator *allocator, |
30 |
30 |
31 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. |
31 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 |
32 |
33 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. |
33 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. |
34 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. |
34 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. |
35 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. |
35 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. |
36 |
36 |
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. |
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. |
38 |
38 |
39 > If you want to lazy-initialize lists, you can use the global `cxEmptyList` symbol as a placeholder instead of using a `NULL`-pointer. |
39 > If you want to lazy-initialize lists, you can use the global `cxEmptyList` symbol as a placeholder instead of using a `NULL`-pointer. |
40 > While you *must not* insert elements into that list, you can safely access this list or create iterators. |
40 > While you *must not* insert elements into that list, you can safely access this list or create iterators. |
98 return 0; |
98 return 0; |
99 } |
99 } |
100 } |
100 } |
101 ``` |
101 ``` |
102 |
102 |
103 Also, just registering `regfree()` as destructor is not sufficient anymore, because the `regex_t` structure also needs to be freed. |
103 Also, just registering `regfree()` as destructor is not enough anymore, because the `regex_t` structure also needs to be freed. |
104 Therefore, we would need to wrap the calls to `regfree()` and `free()` into an own destructor, which we then register with the list. |
104 Therefore, we would need to wrap the calls to `regfree()` and `free()` into an own destructor, which we then register with the list. |
105 However, it should be clear by now that using `CX_STORE_POINTERS` is a bad choice for this use case to begin with. |
105 However, it should be clear by now that using `CX_STORE_POINTERS` is a bad choice for this use case to begin with. |
106 |
106 |
107 As a rule of thumb: if you allocate memory for an element that you immediately put into the list, consider storing the element directly. |
107 As a rule of thumb: if you allocate memory for an element that you immediately put into the list, consider storing the element directly. |
108 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`. |
108 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`. |
149 This _should_ be done with [mutating iterators](iterator.h.md#mutating-iterators) only, but is also defined for normal iterators. |
149 This _should_ be done with [mutating iterators](iterator.h.md#mutating-iterators) only, but is also defined for normal iterators. |
150 |
150 |
151 If the list is storing pointers (cf. `cxCollectionStoresPointers()`), the pointer `elem` is directly added to the list. |
151 If the list is storing pointers (cf. `cxCollectionStoresPointers()`), the pointer `elem` is directly added to the list. |
152 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. |
152 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. |
153 |
153 |
154 On the other hand the `array` argument for `cxListAddArray()`, `cxListInsertArray()`, and `cxListInsertSortedArray()` |
154 On the other hand, the `array` argument for `cxListAddArray()`, `cxListInsertArray()`, and `cxListInsertSortedArray()` |
155 must always point to an array of elements to be added (i.e. either an array of pointers, or an array of actual elements). |
155 must always point to an array of elements to be added (i.e., either an array of pointers or an array of actual elements). |
156 |
156 |
157 A special requirement for `cxListInsertSortedArray()` is, that the `array` must already be sorted. |
157 A special requirement for `cxListInsertSortedArray()` is, that the `array` must already be sorted. |
158 |
158 |
159 > Implementations are required to optimize the insertion of a sorted array into a sorted list in linear time, |
159 > Implementations are required to optimize the insertion of a sorted array into a sorted list in linear time, |
160 > while inserting each element separately via `cxListInsertSorted()` may take quadratic time. |
160 > while inserting each element separately via `cxListInsertSorted()` may take quadratic time. |
188 size_t cxListSize(const CxList *list); |
188 size_t cxListSize(const CxList *list); |
189 ``` |
189 ``` |
190 |
190 |
191 The function `cxListAt()` accesses the element at the specified `index`. |
191 The function `cxListAt()` accesses the element at the specified `index`. |
192 If the list is storing pointers (i.e. `cxCollectionStoresPointers()` returns `true`), the pointer at the specified index is directly returned. |
192 If the list is storing pointers (i.e. `cxCollectionStoresPointers()` returns `true`), the pointer at the specified index is directly returned. |
193 Otherwise, a pointer to element at the specified index is returned. |
193 Otherwise, a pointer to the element at the specified index is returned. |
194 If the index is out-of-bounds, the function returns `NULL`. |
194 If the index is out-of-bounds, the function returns `NULL`. |
195 The functions `cxListFirst()` and `cxListLast()` behave like `cxListAt()`, |
195 The functions `cxListFirst()` and `cxListLast()` behave like `cxListAt()`, |
196 accessing the first or the last valid index, respectively, and returning `NULL` when the list is empty. |
196 accessing the first or the last valid index, respectively, and returning `NULL` when the list is empty. |
197 |
197 |
198 The function `cxListSet()` allows you to modify elements at a specific index in the list. |
198 The function `cxListSet()` allows you to modify elements at a specific index in the list. |
199 This function replaces the element at the specified `index` with the value pointed to by `elem`. |
199 This function replaces the element at the specified `index` with the value pointed to by `elem`. |
200 If the list is storing values directly (not pointers), the contents at the memory location `elem` will be copied into the list. |
200 If the list is storing values directly (not pointers), the contents at the memory location `elem` will be copied into the list. |
201 If the list is storing pointers, the pointer value itself will be stored. |
201 If the list is storing pointers, the pointer value itself will be stored. |
202 The function returns `0` on success and `1` if the index is out of bounds. |
202 The function returns `0` on success and `1` if the index is out of bounds. |
203 |
203 |
204 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, |
204 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, |
205 and returns the first index when the element was found. |
205 and returns the first index when the element was found. |
206 Otherwise, the function returns the list size. |
206 Otherwise, the function returns the list size. |
207 |
207 |
208 The function `cxListFindRemove()` behaves like `cxListFind()`, except that it also removes the first occurrence of the element from the list. |
208 The function `cxListFindRemove()` behaves like `cxListFind()`, except that it also removes the first occurrence of the element from the list. |
209 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. |
209 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. |
314 |
314 |
315 Default UCX implementations of the list interface make use of [small buffer optimizations](install.md#small-buffer-optimizations) when swapping elements. |
315 Default UCX implementations of the list interface make use of [small buffer optimizations](install.md#small-buffer-optimizations) when swapping elements. |
316 |
316 |
317 > An invocation of `cxListSort` sets the `sorted` flag of the [collection](collection.h.md). |
317 > An invocation of `cxListSort` sets the `sorted` flag of the [collection](collection.h.md). |
318 > Implementations usually make use of this flag to optimize search operations, if possible. |
318 > Implementations usually make use of this flag to optimize search operations, if possible. |
319 > For example the [array list](array_list.h.md) implementation will use binary search |
319 > For example, the [array list](array_list.h.md) implementation will use binary search |
320 > for `cxListFind()` and similar operations, when the list is sorted. |
320 > for `cxListFind()` and similar operations, when the list is sorted. |
321 |
321 |
322 ## Compare |
322 ## Compare |
323 |
323 |
324 ```C |
324 ```C |
327 int cxListCompare(const CxList *list, const CxList *other); |
327 int cxListCompare(const CxList *list, const CxList *other); |
328 ``` |
328 ``` |
329 |
329 |
330 Arbitrary lists can be compared element-wise with `cxListCompare()`, as long as the compare functions of both lists are equivalent. |
330 Arbitrary lists can be compared element-wise with `cxListCompare()`, as long as the compare functions of both lists are equivalent. |
331 |
331 |
332 That means, you can compare an UCX [array list](array_list.h.md) with a [linked list](linked_list.h.md), |
332 That means you can compare an UCX [array list](array_list.h.md) with a [linked list](linked_list.h.md), |
333 and you could even compare lists that are storing pointers with lists that are not storing pointers. |
333 and you could even compare lists that are storing pointers with lists that are not storing pointers. |
334 |
334 |
335 However, the optimized list-internal compare implementation is only used, when both the compare functions and the list classes are identical. |
335 However, the optimized list-internal compare implementation is only used when both the compare functions and the list classes are identical. |
336 Otherwise, `cxListCompare()` will behave as if you were iterating through both lists and manually comparing the elements. |
336 Otherwise, `cxListCompare()` will behave as if you were iterating through both lists and manually comparing the elements. |
337 |
337 |
338 The return value of `cxListCompare()` is zero, if the lists are element-wise equivalent. |
338 The return value of `cxListCompare()` is zero, if the lists are element-wise equivalent. |
339 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. |
339 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. |
340 |
340 |
349 No matter with which function a `CxList` has been created, you can _always_ deallocate the entire memory with a call to `cxListFree()`. |
349 No matter with which function a `CxList` has been created, you can _always_ deallocate the entire memory with a call to `cxListFree()`. |
350 |
350 |
351 The effect is equivalent to invoking `cxListClear()` plus deallocating the memory for the list structure. |
351 The effect is equivalent to invoking `cxListClear()` plus deallocating the memory for the list structure. |
352 That means, for each element in the list, the [destructor functions](collection.h.md#destructor-functions) are called before deallocating the list. |
352 That means, for each element in the list, the [destructor functions](collection.h.md#destructor-functions) are called before deallocating the list. |
353 |
353 |
354 When the list has been storing pointers, make sure that either another reference to the same memory exist in your program, |
354 When the list has been storing pointers, make sure that either another reference to the same memory exists in your program, |
355 or any of the destructor functions deallocates the memory. |
355 or any of the destructor functions deallocates the memory. |
356 Otherwise, there is a risk of a memory leak. |
356 Otherwise, there is a risk of a memory leak. |
357 |
357 |
358 ## Implement own List Structures |
358 ## Implement own List Structures |
359 |
359 |
360 If you want to create your own list implementation, this is extremely easy. |
360 If you want to create your own list implementation, this is extremely easy. |
361 |
361 |
362 You just need to define a function for creating your list and assign a `cx_list_class` structure with the pointers to your implementation. |
362 You need to define a function for creating your list and assign a `cx_list_class` structure with the pointers to your implementation. |
363 Then you call the `cx_list_init()` helper function to initialize the collection sture. |
363 Then you call the `cx_list_init()` helper function to initialize the collection sture. |
364 This also automatically adds support for `CX_STORE_POINTERS` to your list. |
364 This also automatically adds support for `CX_STORE_POINTERS` to your list. |
365 |
365 |
366 ```C |
366 ```C |
367 // define the class with pointers to your functions |
367 // define the class with pointers to your functions |
428 | `iterator` | Creates an iterator starting at the specified index. The Boolean argument indicates whether iteration is supposed to traverse backwards. | |
428 | `iterator` | Creates an iterator starting at the specified index. The Boolean argument indicates whether iteration is supposed to traverse backwards. | |
429 |
429 |
430 > If you initialize your list with `cx_list_init()` you do not have to worry about making a |
430 > If you initialize your list with `cx_list_init()` you do not have to worry about making a |
431 > difference between storing pointers and storing elements, because your implementation will |
431 > difference between storing pointers and storing elements, because your implementation will |
432 > be automatically wrapped. |
432 > be automatically wrapped. |
433 > This means, you only have to handle the one single case described above. |
433 > This means you only have to handle the one single case described above. |
434 |
434 |
435 ### Default Class Function Implementations |
435 ### Default Class Function Implementations |
436 |
436 |
437 If you are satisfied with some of the default implementations, you can use some pre-defined functions. |
437 If you are satisfied with some of the default implementations, you can use some pre-defined functions. |
438 Note, however, that those are not optimized for any specific list structure |
438 Note, however, that those are not optimized for any specific list structure |