docs/Writerside/topics/list.h.md

changeset 1351
4407229bd944
parent 1344
8afaeb395b3c
equal deleted inserted replaced
1350:189756516eaa 1351:4407229bd944
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

mercurial