117 size_t depth; |
117 size_t depth; |
118 }; |
118 }; |
119 } CxTreeIterator; |
119 } CxTreeIterator; |
120 |
120 |
121 /** |
121 /** |
|
122 * An element in a visitor queue. |
|
123 */ |
|
124 struct cx_tree_visitor_queue_s { |
|
125 /** |
|
126 * The tree node to visit. |
|
127 */ |
|
128 void *node; |
|
129 /** |
|
130 * The depth of the node. |
|
131 */ |
|
132 size_t depth; |
|
133 /** |
|
134 * The next element in the queue or \c NULL. |
|
135 */ |
|
136 struct cx_tree_visitor_queue_s *next; |
|
137 }; |
|
138 |
|
139 /** |
|
140 * A breadth-first tree iterator. |
|
141 * |
|
142 * This iterator needs to maintain a visitor queue that will be automatically freed once the iterator becomes invalid. |
|
143 * If you want to discard the iterator before, you MUST manually call cxTreeVisitorDispose(). |
|
144 * |
|
145 * This iterator is not position-aware in a strict sense, as it does not assume a particular order of elements in the |
|
146 * tree. However, the iterator keeps track of the number of nodes it has passed in a counter variable. |
|
147 * Each node, regardless of the number of passes, is counted only once. |
|
148 * |
|
149 * @note Objects that are pointed to by an iterator are mutable through that iterator. However, if the |
|
150 * underlying data structure is mutated by other means than this iterator (e.g. elements added or removed), |
|
151 * the iterator becomes invalid (regardless of what cxIteratorValid() returns). |
|
152 * |
|
153 * @see CxIterator |
|
154 */ |
|
155 typedef struct cx_tree_visitor_s { |
|
156 /** |
|
157 * The base properties of this iterator. |
|
158 */ |
|
159 struct cx_iterator_base_s base; |
|
160 /** |
|
161 * Offset in the node struct for the children linked list. |
|
162 */ |
|
163 ptrdiff_t loc_children; |
|
164 /** |
|
165 * Offset in the node struct for the next pointer. |
|
166 */ |
|
167 ptrdiff_t loc_next; |
|
168 /** |
|
169 * The total number of distinct nodes that have been passed so far. |
|
170 */ |
|
171 size_t counter; |
|
172 /** |
|
173 * The currently observed node. |
|
174 * |
|
175 * This is the same what cxIteratorCurrent() would return. |
|
176 */ |
|
177 void *node; |
|
178 /** |
|
179 * The current depth in the tree. |
|
180 */ |
|
181 size_t depth; |
|
182 /** |
|
183 * The next element in the visitor queue. |
|
184 */ |
|
185 struct cx_tree_visitor_queue_s *queue_next; |
|
186 /** |
|
187 * The last element in the visitor queue. |
|
188 */ |
|
189 struct cx_tree_visitor_queue_s *queue_last; |
|
190 } CxTreeVisitor; |
|
191 |
|
192 /** |
122 * Releases internal memory of the given tree iterator. |
193 * Releases internal memory of the given tree iterator. |
123 * @param iter the iterator |
194 * @param iter the iterator |
124 */ |
195 */ |
|
196 __attribute__((__nonnull__)) |
125 static inline void cxTreeIteratorDispose(CxTreeIterator *iter) { |
197 static inline void cxTreeIteratorDispose(CxTreeIterator *iter) { |
126 free(iter->stack); |
198 free(iter->stack); |
127 iter->stack = NULL; |
199 iter->stack = NULL; |
128 } |
200 } |
129 |
201 |
130 /** |
202 /** |
|
203 * Releases internal memory of the given tree visitor. |
|
204 * @param visitor the visitor |
|
205 */ |
|
206 __attribute__((__nonnull__)) |
|
207 static inline void cxTreeVisitorDispose(CxTreeVisitor *visitor) { |
|
208 struct cx_tree_visitor_queue_s *q = visitor->queue_next; |
|
209 while (q != NULL) { |
|
210 struct cx_tree_visitor_queue_s *next = q->next; |
|
211 free(q); |
|
212 q = next; |
|
213 } |
|
214 } |
|
215 |
|
216 /** |
131 * Links a node to a (new) parent. |
217 * Links a node to a (new) parent. |
132 * |
218 * |
133 * If the node has already a parent, it is unlinked, first. |
219 * If the node has already a parent, it is unlinked, first. |
134 * If the parent has children already, the node is prepended to the list |
220 * If the parent has children already, the node is \em prepended to the list |
135 * of all currently existing children. |
221 * of all currently existing children. |
136 * |
222 * |
137 * @param parent the parent node |
223 * @param parent the parent node |
138 * @param node the node that shall be linked |
224 * @param node the node that shall be linked |
139 * @param loc_parent offset in the node struct for the parent pointer |
225 * @param loc_parent offset in the node struct for the parent pointer |
232 ptrdiff_t loc_children, |
318 ptrdiff_t loc_children, |
233 ptrdiff_t loc_next |
319 ptrdiff_t loc_next |
234 ); |
320 ); |
235 |
321 |
236 /** |
322 /** |
237 * Creates an iterator for a tree with the specified root node. |
323 * Creates a depth-first iterator for a tree with the specified root node. |
238 * |
324 * |
239 * @note A tree iterator needs to maintain a stack of visited nodes, which is allocated using stdlib malloc(). |
325 * @note A tree iterator needs to maintain a stack of visited nodes, which is allocated using stdlib malloc(). |
240 * When the iterator becomes invalid, this memory is automatically released. However, if you wish to cancel the |
326 * When the iterator becomes invalid, this memory is automatically released. However, if you wish to cancel the |
241 * iteration before the iterator becomes invalid by itself, you MUST call cxTreeIteratorDispose() manually to release |
327 * iteration before the iterator becomes invalid by itself, you MUST call cxTreeIteratorDispose() manually to release |
242 * the memory. |
328 * the memory. |
243 * |
329 * |
244 * @remark At the moment, the returned iterator does not support cxIteratorFlagRemoval(). |
330 * @remark The returned iterator does not support cxIteratorFlagRemoval(). |
245 * |
331 * |
246 * @param root the root node |
332 * @param root the root node |
247 * @param visit_on_exit set to true, when the iterator shall visit a node again after processing all children |
333 * @param visit_on_exit set to true, when the iterator shall visit a node again after processing all children |
248 * @param loc_children offset in the node struct for the children linked list |
334 * @param loc_children offset in the node struct for the children linked list |
249 * @param loc_next offset in the node struct for the next pointer |
335 * @param loc_next offset in the node struct for the next pointer |
256 bool visit_on_exit, |
342 bool visit_on_exit, |
257 ptrdiff_t loc_children, |
343 ptrdiff_t loc_children, |
258 ptrdiff_t loc_next |
344 ptrdiff_t loc_next |
259 ); |
345 ); |
260 |
346 |
|
347 /** |
|
348 * Creates a breadth-first iterator for a tree with the specified root node. |
|
349 * |
|
350 * @note A tree visitor needs to maintain a queue of to be visited nodes, which is allocated using stdlib malloc(). |
|
351 * When the visitor becomes invalid, this memory is automatically released. However, if you wish to cancel the |
|
352 * iteration before the visitor becomes invalid by itself, you MUST call cxTreeVisitorDispose() manually to release |
|
353 * the memory. |
|
354 * |
|
355 * @remark The returned iterator does not support cxIteratorFlagRemoval(). |
|
356 * |
|
357 * @param root the root node |
|
358 * @param loc_children offset in the node struct for the children linked list |
|
359 * @param loc_next offset in the node struct for the next pointer |
|
360 * @return the new tree visitor |
|
361 * @see cxTreeVisitorDispose() |
|
362 */ |
|
363 __attribute__((__nonnull__)) |
|
364 CxTreeVisitor cx_tree_visitor( |
|
365 void *root, |
|
366 ptrdiff_t loc_children, |
|
367 ptrdiff_t loc_next |
|
368 ); |
|
369 |
261 #ifdef __cplusplus |
370 #ifdef __cplusplus |
262 } // extern "C" |
371 } // extern "C" |
263 #endif |
372 #endif |
264 |
373 |
265 #endif //UCX_TREE_H |
374 #endif //UCX_TREE_H |