docs/Writerside/topics/iterator.h.md

changeset 1215
790ff923f375
parent 1190
a7b913d5d589
child 1216
151c1b7d5d50
equal deleted inserted replaced
1214:ee4e33284f0c 1215:790ff923f375
1 # Iterators 1 # Iterators
2 2
3 <warning> 3 Iterators generalize the iteration over elements of an arbitrary collection.
4 Outdated Section - will be updated soon! 4 This allows iteration over arrays, lists, maps, trees, etc. in a unified way.
5 </warning>
6 5
7 In UCX 3 a new feature has been introduced to write own iterators, that work with the `cx_foreach` macro. 6 Creating an iterator is as simple as creating a `CxIterator` struct and setting the fields in a meaningful way.
8 In previous UCX releases there were different hard-coded foreach macros for lists and maps that were not customizable. 7 The UCX collections provide various functions to create such iterators.
9 Now, creating an iterator is as simple as creating a `CxIterator` struct and setting the fields in a meaningful way.
10 8
11 You do not always need all fields in the iterator structure, depending on your use case. 9 If the predefined fields are insufficient (or introduce too much bloat) for your use case,
12 Sometimes you only need the `index` (for example when iterating over simple lists), and other times you will need the 10 you can alternatively create your own iterator structure
13 `slot` and `kv_data` fields (for example when iterating over maps).
14
15 If the predefined fields are insufficient for your use case, you can alternatively create your own iterator structure
16 and place the `CX_ITERATOR_BASE` macro as first member of that structure. 11 and place the `CX_ITERATOR_BASE` macro as first member of that structure.
17 12
13 ```C
14 #include <cx/iterator.h>
15
16 struct my_fancy_iterator_s {
17 CX_ITERATOR_BASE; // the base members used by cx_foreach()
18 // ... custom fields ...
19 };
20 ```
21
22 ## Overview
23
24
25
26 ## Using an Iterator
27
28 The following macros work with arbitrary structures using `CX_ITERATOR_BASE`
29 and invoke the respective function pointers `valid`, `current`, or `next`.
30 ```C
31 cxIteratorValid(iter)
32 cxIteratorCurrent(iter)
33 cxIteratorNext(iter)
34 ```
35
36 You may use them for manual iterator, but usually you do not need them.
37 Every iterator can be used with the `cx_foreach` macro.
38
39 ```C
40 #include <cx/iterator.h>
41
42 // some custom array and its size
43 MyData *array = // ...
44 size_t size = // ...
45
46 CxIterator iter = cxIterator(array, sizeof(MyData), size);
47 cx_foreach(MyData*, elem, iter) {
48 // .. do something with elem ..
49 }
50 ```
51
52 The macro takes three arguments:
53 1. the pointer-type of a pointer to an element,
54 2. the name of the variable you want to use for accessing the element,
55 3. and the iterator.
56
57 > An iterator does not necessarily need to iterate over the elements of a collections.
58 > Map iterators, for example, can iterator over the key/value pairs,
59 > but they can also iterate over just the values or just the keys.
60 >
61 > You should read the documentation of the function creating the iterator to learn
62 > what exactly the iterator is iterating over.
63
64 ## Mutating Iterators
65
18 Usually an iterator is not mutating the collection it is iterating over. 66 Usually an iterator is not mutating the collection it is iterating over.
19 In some programming languages it is even disallowed to change the collection while iterating with foreach.
20 But sometimes it is desirable to remove an element from the collection while iterating over it. 67 But sometimes it is desirable to remove an element from the collection while iterating over it.
68
21 For this purpose, most collections allow the creation of a _mutating_ iterator. 69 For this purpose, most collections allow the creation of a _mutating_ iterator.
22 The only differences are, that the `mutating` flag is `true` and the `src_handle` is not const. 70 On mutating iterators the `mutating` flag in the base structure is set to `true`,
23 On mutating iterators it is allowed to call the `cxFlagForRemoval()` function, which instructs the iterator to remove 71 and it is allowed to call the `cxFlagForRemoval()` function, which instructs the iterator to remove
24 the current element from the collection on the next call to `cxIteratorNext()` and clear the flag afterward. 72 the current element from the collection on the next call to `cxIteratorNext()` and clear the flag afterward.
25 If you are implementing your own iterator, it is up to you to implement this behavior. 73 If you are implementing your own iterator, it is up to you to implement this behavior.
26 74
27 <!-- 75 ## Passing Iterators to Functions
28 ## Undocumented Symbols (TODO) 76
29 ### cxIterator 77 To eliminate the need of memory management for iterators, the structures are usually used by value.
30 ### cxIteratorPtr 78 This does not come with additional costs, because iteration is implemented entirely by macros.
31 ### cxMutIterator 79
32 ### cxMutIteratorPtr 80 However, sometimes it is necessary to pass an iterator to another function.
33 --> 81 To make that possible in a generalized way, such functions should accept a `CxIteratorBase*` pointer
82 which can be obtained with the `cxIteratorRef()` macro on the calling site.
83
84 In the following example, elements from a list are inserted into a tree:
85
86 ```C
87 CxList *list = // ...
88 CxTree *tree = // ...
89
90 CxIterator iter = cxListIterator(list);
91 cxTreeInsertIter(tree, cxIteratorRef(iter), cxListSize(list));
92 ```
93
94 > This is the reason, why `CX_ITERATOR_BASE` must be the first member of any iterator structure.
95 > Otherwise, the address taken by `cxIteratorRef()` would not equal the address of the iterator.
96 {style="note"}
97
98 ## Custom Iterators
99
100 The base structure is defined as follows:
101 ```C
102 struct cx_iterator_base_s {
103 bool (*valid)(const void *);
104 void *(*current)(const void *);
105 void *(*current_impl)(const void *);
106 void (*next)(void *);
107 bool mutating;
108 bool remove;
109 };
110
111 typedef struct cx_iterator_base_s CxIteratorBase;
112 ```
113
114 The `valid` function indicates whether the iterator is currently pointing to an element in the collection.
115 The `current` function is supposed to return that element,
116 and the `next` function shall advance the iterator to the next element.
117 The booleans `mutating` and `remove` are used for [mutating iterators](#mutating-iterators) as explained above.
118
119 Iterators may be wrapped in which case the original implementation can be stored in `current_impl` and
120 called by a wrapper implementation pointed to by `current`.
121 This can be useful when you want to support the `store_pointer` field of the [](collection.h.md) API.
122
123 A specialized, simple, and fast iterator over an array of a certain type,
124 that does not support mutation, can be implemented as follows:
125 ```C
126 #include <cx/iterator.h>
127
128 typedef struct my_foo_s {
129 // ... your data ...
130 } MyFoo;
131
132 typedef struct my_foo_iterator_s {
133 CX_ITERATOR_BASE;
134 MyFoo *array;
135 size_t index;
136 size_t elem_count;
137 } MyFooIterator;
138
139 static bool my_foo_iter_valid(const void *it) {
140 const MyFooIterator *iter = it;
141 return iter->index < iter->elem_count;
142 }
143
144 static void *my_foo_iter_current(const void *it) {
145 const MyFooIterator *iter = it;
146 return &iter->array[iter->index];
147 }
148
149 static void my_foo_iter_next(void *it) {
150 MyFooIterator *iter = it;
151 iter->index++;
152 }
153
154 MyFooIterator myFooIterator(MyFoo *array, size_t elem_count) {
155 MyFooIterator iter;
156
157 // base fields
158 iter.base.valid = my_foo_iter_valid;
159 iter.base.current = my_foo_iter_current;
160 iter.base.next = my_foo_iter_next;
161 iter.base.remove = false;
162 iter.base.mutating = false;
163
164 // custom fields
165 iter.index = 0;
166 iter.elem_count = elem_count;
167
168 return iter;
169 }
170 ```
171
172 > Note, that the behavior of `current` is undefined when `valid` returns `false`.
173 > That means, on the one hand, `current` does not need to check for validity of the iterator,
174 > but on the other hand it is forbidden to invoke `current` when `valid` would return `false`.
175 {style="note"}
176
177 > If performance matters in your application, it is recommended that you indeed create specialized iterators
178 > for your collections. The default UCX implementations trade some of the performance for generality.
34 179
35 <seealso> 180 <seealso>
36 <category ref="apidoc"> 181 <category ref="apidoc">
37 <a href="https://ucx.sourceforge.io/api/iterator_8h.html">iterator.h</a> 182 <a href="https://ucx.sourceforge.io/api/iterator_8h.html">iterator.h</a>
38 </category> 183 </category>

mercurial