src/ucx/cx/iterator.h

changeset 579
e10457d74fe1
parent 504
c094afcdfb27
equal deleted inserted replaced
578:eb48f716b31c 579:e10457d74fe1
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 /** 28 /**
29 * \file iterator.h 29 * @file iterator.h
30 * \brief Interface for iterator implementations. 30 * @brief Interface for iterator implementations.
31 * \author Mike Becker 31 * @author Mike Becker
32 * \author Olaf Wintermann 32 * @author Olaf Wintermann
33 * \version 3.0 33 * @copyright 2-Clause BSD License
34 * \copyright 2-Clause BSD License
35 */ 34 */
36 35
37 #ifndef UCX_ITERATOR_H 36 #ifndef UCX_ITERATOR_H
38 #define UCX_ITERATOR_H 37 #define UCX_ITERATOR_H
39 38
40 #include "common.h" 39 #include "common.h"
41 40
42 /** 41 #ifdef __cplusplus
43 * The base of mutating and non-mutating iterators. 42 extern "C" {
43 #endif
44
45 /**
46 * Common data for all iterators.
44 */ 47 */
45 struct cx_iterator_base_s { 48 struct cx_iterator_base_s {
46 /** 49 /**
47 * True iff the iterator points to valid data. 50 * True if the iterator points to valid data.
48 */ 51 */
49 __attribute__ ((__nonnull__)) 52 bool (*valid)(const void *);
50 bool (*valid)(void const *);
51 53
52 /** 54 /**
53 * Returns a pointer to the current element. 55 * Returns a pointer to the current element.
54 * 56 *
55 * When valid returns false, the behavior of this function is undefined. 57 * When valid returns false, the behavior of this function is undefined.
56 */ 58 */
57 __attribute__ ((__nonnull__)) 59 void *(*current)(const void *);
58 void *(*current)(void const *);
59 60
60 /** 61 /**
61 * Original implementation in case the function needs to be wrapped. 62 * Original implementation in case the function needs to be wrapped.
62 */ 63 */
63 __attribute__ ((__nonnull__)) 64 void *(*current_impl)(const void *);
64 void *(*current_impl)(void const *);
65 65
66 /** 66 /**
67 * Advances the iterator. 67 * Advances the iterator.
68 * 68 *
69 * When valid returns false, the behavior of this function is undefined. 69 * When valid returns false, the behavior of this function is undefined.
70 */ 70 */
71 __attribute__ ((__nonnull__))
72 void (*next)(void *); 71 void (*next)(void *);
73
74 /**
75 * Flag current element for removal, if possible.
76 *
77 * When valid returns false, the behavior of this function is undefined.
78 */
79 __attribute__ ((__nonnull__))
80 bool (*flag_removal)(void *);
81
82 /** 72 /**
83 * Indicates whether this iterator may remove elements. 73 * Indicates whether this iterator may remove elements.
84 */ 74 */
85 bool mutating; 75 bool mutating;
86
87 /** 76 /**
88 * Internal flag for removing the current element when advancing. 77 * Internal flag for removing the current element when advancing.
89 */ 78 */
90 bool remove; 79 bool remove;
91 }; 80 };
92 81
93 /** 82 /**
94 * Internal iterator struct - use CxMutIterator. 83 * Convenience type definition for the base structure of an iterator.
95 */ 84 * @see #CX_ITERATOR_BASE
96 struct cx_mut_iterator_s { 85 */
97 86 typedef struct cx_iterator_base_s CxIteratorBase;
98 /** 87
99 * The base properties of this iterator. 88 /**
100 */ 89 * Declares base attributes for an iterator.
101 struct cx_iterator_base_s base; 90 * Must be the first member of an iterator structure.
102 91 */
103 /** 92 #define CX_ITERATOR_BASE struct cx_iterator_base_s base
104 * Handle for the current element, if required. 93
94 /**
95 * Internal iterator struct - use CxIterator.
96 */
97 struct cx_iterator_s {
98 /**
99 * Inherited common data for all iterators.
100 */
101 CX_ITERATOR_BASE;
102
103 /**
104 * Handle for the current element.
105 */ 105 */
106 void *elem_handle; 106 void *elem_handle;
107 107
108 /** 108 /**
109 * Handle for the source collection, if any. 109 * Handle for the source collection, if any.
110 */ 110 */
111 void *src_handle; 111 union {
112
113 /**
114 * Field for storing a key-value pair.
115 * May be used by iterators that iterate over k/v-collections.
116 */
117 struct {
118 /** 112 /**
119 * A pointer to the key. 113 * Access for mutating iterators.
120 */ 114 */
121 void const *key; 115 void *m;
122 /** 116 /**
123 * A pointer to the value. 117 * Access for normal iterators.
124 */ 118 */
125 void *value; 119 const void *c;
126 } kv_data; 120 } src_handle;
127
128 /**
129 * Field for storing a slot number.
130 * May be used by iterators that iterate over multi-bucket collections.
131 */
132 size_t slot;
133 121
134 /** 122 /**
135 * If the iterator is position-aware, contains the index of the element in the underlying collection. 123 * If the iterator is position-aware, contains the index of the element in the underlying collection.
136 * Otherwise, this field is usually uninitialized. 124 * Otherwise, this field is usually uninitialized.
137 */ 125 */
138 size_t index; 126 size_t index;
127
128 /**
129 * The size of an individual element.
130 */
131 size_t elem_size;
132
133 /**
134 * May contain the total number of elements, if known.
135 * Shall be set to @c SIZE_MAX when the total number is unknown during iteration.
136 */
137 size_t elem_count;
139 }; 138 };
140 139
141 /** 140 /**
142 * Mutating iterator value type. 141 * Iterator type.
143 * 142 *
144 * An iterator points to a certain element in an (possibly unbounded) chain of elements.
145 * Iterators that are based on collections (which have a defined "first" element), are supposed
146 * to be "position-aware", which means that they keep track of the current index within the collection.
147 *
148 * @note Objects that are pointed to by an iterator are mutable through that iterator. However, if the
149 * iterator is based on a collection and the underlying collection is mutated by other means than this iterator
150 * (e.g. elements added or removed), the iterator becomes invalid (regardless of what cxIteratorValid() returns)
151 * and MUST be re-obtained from the collection.
152 *
153 * @see CxIterator
154 */
155 typedef struct cx_mut_iterator_s CxMutIterator;
156
157 /**
158 * Internal iterator struct - use CxIterator.
159 */
160 struct cx_iterator_s {
161
162 /**
163 * The base properties of this iterator.
164 */
165 struct cx_iterator_base_s base;
166
167 /**
168 * Handle for the current element, if required.
169 */
170 void *elem_handle;
171
172 /**
173 * Handle for the source collection, if any.
174 */
175 void const *src_handle;
176
177 /**
178 * Field for storing a key-value pair.
179 * May be used by iterators that iterate over k/v-collections.
180 */
181 struct {
182 /**
183 * A pointer to the key.
184 */
185 void const *key;
186 /**
187 * A pointer to the value.
188 */
189 void *value;
190 } kv_data;
191
192 /**
193 * Field for storing a slot number.
194 * May be used by iterators that iterate over multi-bucket collections.
195 */
196 size_t slot;
197
198 /**
199 * If the iterator is position-aware, contains the index of the element in the underlying collection.
200 * Otherwise, this field is usually uninitialized.
201 */
202 size_t index;
203 };
204
205 /**
206 * Iterator value type.
207 * An iterator points to a certain element in a (possibly unbounded) chain of elements. 143 * An iterator points to a certain element in a (possibly unbounded) chain of elements.
208 * Iterators that are based on collections (which have a defined "first" element), are supposed 144 * Iterators that are based on collections (which have a defined "first" element), are supposed
209 * to be "position-aware", which means that they keep track of the current index within the collection. 145 * to be "position-aware", which means that they keep track of the current index within the collection.
210 * 146 *
211 * @note Objects that are pointed to by an iterator are always mutable through that iterator. However, 147 * @note Objects that are pointed to by an iterator are always mutable through that iterator. However,
212 * this iterator cannot mutate the collection itself (add or remove elements) and any mutation of the 148 * any concurrent mutation of the collection other than by this iterator makes this iterator invalid,
213 * collection by other means makes this iterator invalid (regardless of what cxIteratorValid() returns). 149 * and it must not be used anymore.
214 *
215 * @see CxMutIterator
216 */ 150 */
217 typedef struct cx_iterator_s CxIterator; 151 typedef struct cx_iterator_s CxIterator;
218 152
219 /** 153 /**
220 * Checks if the iterator points to valid data. 154 * Checks if the iterator points to valid data.
221 * 155 *
222 * This is especially false for past-the-end iterators. 156 * @param iter the iterator
223 * 157 * @retval true if the iterator points to valid data
224 * @param iter the iterator 158 * @retval false if the iterator already moved past the end
225 * @return true iff the iterator points to valid data
226 */ 159 */
227 #define cxIteratorValid(iter) (iter).base.valid(&(iter)) 160 #define cxIteratorValid(iter) (iter).base.valid(&(iter))
228 161
229 /** 162 /**
230 * Returns a pointer to the current element. 163 * Returns a pointer to the current element.
231 * 164 *
232 * The behavior is undefined if this iterator is invalid. 165 * The behavior is undefined if this iterator is invalid.
233 * 166 *
234 * @param iter the iterator 167 * @param iter the iterator
235 * @return a pointer to the current element 168 * @return a pointer to the current element
169 * @see cxIteratorValid()
236 */ 170 */
237 #define cxIteratorCurrent(iter) (iter).base.current(&iter) 171 #define cxIteratorCurrent(iter) (iter).base.current(&iter)
238 172
239 /** 173 /**
240 * Advances the iterator to the next element. 174 * Advances the iterator to the next element.
242 * @param iter the iterator 176 * @param iter the iterator
243 */ 177 */
244 #define cxIteratorNext(iter) (iter).base.next(&iter) 178 #define cxIteratorNext(iter) (iter).base.next(&iter)
245 179
246 /** 180 /**
247 * Flags the current element for removal. 181 * Flags the current element for removal, if this iterator is mutating.
248 * 182 *
249 * @param iter the iterator 183 * Does nothing for non-mutating iterators.
250 * @return false if this iterator cannot remove the element 184 *
251 */ 185 * @param iter the iterator
252 #define cxIteratorFlagRemoval(iter) (iter).base.flag_removal(&iter) 186 */
187 #define cxIteratorFlagRemoval(iter) (iter).base.remove |= (iter).base.mutating
188
189 /**
190 * Obtains a reference to an arbitrary iterator.
191 *
192 * This is useful for APIs that expect some iterator as an argument.
193 *
194 * @param iter the iterator
195 * @return (@c struct @c cx_iterator_base_s*) a pointer to the iterator
196 */
197 #define cxIteratorRef(iter) &((iter).base)
253 198
254 /** 199 /**
255 * Loops over an iterator. 200 * Loops over an iterator.
201 *
256 * @param type the type of the elements 202 * @param type the type of the elements
257 * @param elem the name of the iteration variable 203 * @param elem the name of the iteration variable
258 * @param iter the iterator 204 * @param iter the iterator
259 */ 205 */
260 #define cx_foreach(type, elem, iter) \ 206 #define cx_foreach(type, elem, iter) \
261 for (type elem; cxIteratorValid(iter) && (elem = (type)cxIteratorCurrent(iter)) != NULL ; cxIteratorNext(iter)) 207 for (type elem; cxIteratorValid(iter) && (elem = (type)cxIteratorCurrent(iter)) != NULL ; cxIteratorNext(iter))
262 208
209
210 /**
211 * Creates an iterator for the specified plain array.
212 *
213 * The @p array can be @c NULL in which case the iterator will be immediately
214 * initialized such that #cxIteratorValid() returns @c false.
215 *
216 * This iterator yields the addresses of the array elements.
217 * If you want to iterator over an array of pointers, you can
218 * use cxIteratorPtr() to create an iterator which directly
219 * yields the stored pointers.
220 *
221 * @param array a pointer to the array (can be @c NULL)
222 * @param elem_size the size of one array element
223 * @param elem_count the number of elements in the array
224 * @return an iterator for the specified array
225 * @see cxIteratorPtr()
226 */
227 cx_attr_nodiscard
228 cx_attr_export
229 CxIterator cxIterator(
230 const void *array,
231 size_t elem_size,
232 size_t elem_count
233 );
234
235 /**
236 * Creates a mutating iterator for the specified plain array.
237 *
238 * While the iterator is in use, the array may only be altered by removing
239 * elements through #cxIteratorFlagRemoval(). Every other change to the array
240 * will bring this iterator to an undefined state.
241 *
242 * When @p remove_keeps_order is set to @c false, removing an element will only
243 * move the last element to the position of the removed element, instead of
244 * moving all subsequent elements by one. Usually, when the order of elements is
245 * not important, this parameter should be set to @c false.
246 *
247 * The @p array can be @c NULL in which case the iterator will be immediately
248 * initialized such that #cxIteratorValid() returns @c false.
249 *
250 *
251 * @param array a pointer to the array (can be @c NULL)
252 * @param elem_size the size of one array element
253 * @param elem_count the number of elements in the array
254 * @param remove_keeps_order @c true if the order of elements must be preserved
255 * when removing an element
256 * @return an iterator for the specified array
257 */
258 cx_attr_nodiscard
259 cx_attr_export
260 CxIterator cxMutIterator(
261 void *array,
262 size_t elem_size,
263 size_t elem_count,
264 bool remove_keeps_order
265 );
266
267 /**
268 * Creates an iterator for the specified plain pointer array.
269 *
270 * This iterator assumes that every element in the array is a pointer
271 * and yields exactly those pointers during iteration (while in contrast
272 * an iterator created with cxIterator() would return the addresses
273 * of those pointers within the array).
274 *
275 * @param array a pointer to the array (can be @c NULL)
276 * @param elem_count the number of elements in the array
277 * @return an iterator for the specified array
278 * @see cxIterator()
279 */
280 cx_attr_nodiscard
281 cx_attr_export
282 CxIterator cxIteratorPtr(
283 const void *array,
284 size_t elem_count
285 );
286
287 /**
288 * Creates a mutating iterator for the specified plain pointer array.
289 *
290 * This is the mutating variant of cxIteratorPtr(). See also
291 * cxMutIterator().
292 *
293 * @param array a pointer to the array (can be @c NULL)
294 * @param elem_count the number of elements in the array
295 * @param remove_keeps_order @c true if the order of elements must be preserved
296 * when removing an element
297 * @return an iterator for the specified array
298 * @see cxMutIterator()
299 * @see cxIteratorPtr()
300 */
301 cx_attr_nodiscard
302 cx_attr_export
303 CxIterator cxMutIteratorPtr(
304 void *array,
305 size_t elem_count,
306 bool remove_keeps_order
307 );
308
309 #ifdef __cplusplus
310 } // extern "C"
311 #endif
312
263 #endif // UCX_ITERATOR_H 313 #endif // UCX_ITERATOR_H

mercurial