Fri, 12 Apr 2024 21:48:12 +0200
improves interface of cx_sprintf() variants
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
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
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28 /**
29 * \file tree.h
30 * \brief Interface for tree implementations.
31 * \author Mike Becker
32 * \author Olaf Wintermann
33 * \copyright 2-Clause BSD License
34 */
36 #ifndef UCX_TREE_H
37 #define UCX_TREE_H
39 #include "common.h"
41 #include "iterator.h"
43 #ifdef __cplusplus
44 extern "C" {
45 #endif
47 /**
48 * A depth-first tree iterator.
49 *
50 * This iterator is not position-aware in a strict sense, as it does not assume a particular order of elements in the
51 * tree. However, the iterator keeps track of the number of nodes it has passed in a counter variable.
52 * Each node, regardless of the number of passes, is counted only once.
53 *
54 * @note Objects that are pointed to by an iterator are mutable through that iterator. However, if the
55 * underlying data structure is mutated by other means than this iterator (e.g. elements added or removed),
56 * the iterator becomes invalid (regardless of what cxIteratorValid() returns).
57 *
58 * @see CxIterator
59 */
60 typedef struct cx_tree_iterator_s {
61 /**
62 * The base properties of this iterator.
63 */
64 struct cx_iterator_base_s base;
65 /**
66 * Indicates whether the subtree below the current node shall be skipped.
67 */
68 bool skip;
69 /**
70 * Set to true, when the iterator shall visit a node again
71 * when all it's children have been processed.
72 */
73 bool visit_on_exit;
74 /**
75 * True, if this iterator is currently leaving the node.
76 */
77 bool exiting;
78 /**
79 * Offset in the node struct for the children linked list.
80 */
81 ptrdiff_t loc_children;
82 /**
83 * Offset in the node struct for the next pointer.
84 */
85 ptrdiff_t loc_next;
86 /**
87 * The total number of distinct nodes that have been passed so far.
88 */
89 size_t counter;
90 /**
91 * The currently observed node.
92 *
93 * This is the same what cxIteratorCurrent() would return.
94 */
95 void *node;
96 /**
97 * Stores a copy of the next pointer of the visited node.
98 * Allows freeing a node on exit without corrupting the iteration.
99 */
100 void *next;
101 /**
102 * Internal stack.
103 * Will be automatically freed once the iterator becomes invalid.
104 *
105 * If you want to discard the iterator before, you need to manually
106 * call cxTreeIteratorDispose().
107 */
108 void **stack;
109 /**
110 * Internal capacity of the stack.
111 */
112 size_t stack_capacity;
113 union {
114 /**
115 * Internal stack size.
116 */
117 size_t stack_size;
118 /**
119 * The current depth in the tree.
120 */
121 size_t depth;
122 };
123 } CxTreeIterator;
125 /**
126 * An element in a visitor queue.
127 */
128 struct cx_tree_visitor_queue_s {
129 /**
130 * The tree node to visit.
131 */
132 void *node;
133 /**
134 * The depth of the node.
135 */
136 size_t depth;
137 /**
138 * The next element in the queue or \c NULL.
139 */
140 struct cx_tree_visitor_queue_s *next;
141 };
143 /**
144 * A breadth-first tree iterator.
145 *
146 * This iterator needs to maintain a visitor queue that will be automatically freed once the iterator becomes invalid.
147 * If you want to discard the iterator before, you MUST manually call cxTreeVisitorDispose().
148 *
149 * This iterator is not position-aware in a strict sense, as it does not assume a particular order of elements in the
150 * tree. However, the iterator keeps track of the number of nodes it has passed in a counter variable.
151 * Each node, regardless of the number of passes, is counted only once.
152 *
153 * @note Objects that are pointed to by an iterator are mutable through that iterator. However, if the
154 * underlying data structure is mutated by other means than this iterator (e.g. elements added or removed),
155 * the iterator becomes invalid (regardless of what cxIteratorValid() returns).
156 *
157 * @see CxIterator
158 */
159 typedef struct cx_tree_visitor_s {
160 /**
161 * The base properties of this iterator.
162 */
163 struct cx_iterator_base_s base;
164 /**
165 * Indicates whether the subtree below the current node shall be skipped.
166 */
167 bool skip;
168 /**
169 * Offset in the node struct for the children linked list.
170 */
171 ptrdiff_t loc_children;
172 /**
173 * Offset in the node struct for the next pointer.
174 */
175 ptrdiff_t loc_next;
176 /**
177 * The total number of distinct nodes that have been passed so far.
178 */
179 size_t counter;
180 /**
181 * The currently observed node.
182 *
183 * This is the same what cxIteratorCurrent() would return.
184 */
185 void *node;
186 /**
187 * The current depth in the tree.
188 */
189 size_t depth;
190 /**
191 * The next element in the visitor queue.
192 */
193 struct cx_tree_visitor_queue_s *queue_next;
194 /**
195 * The last element in the visitor queue.
196 */
197 struct cx_tree_visitor_queue_s *queue_last;
198 } CxTreeVisitor;
200 /**
201 * Releases internal memory of the given tree iterator.
202 * @param iter the iterator
203 */
204 __attribute__((__nonnull__))
205 static inline void cxTreeIteratorDispose(CxTreeIterator *iter) {
206 free(iter->stack);
207 iter->stack = NULL;
208 }
210 /**
211 * Releases internal memory of the given tree visitor.
212 * @param visitor the visitor
213 */
214 __attribute__((__nonnull__))
215 static inline void cxTreeVisitorDispose(CxTreeVisitor *visitor) {
216 struct cx_tree_visitor_queue_s *q = visitor->queue_next;
217 while (q != NULL) {
218 struct cx_tree_visitor_queue_s *next = q->next;
219 free(q);
220 q = next;
221 }
222 }
224 /**
225 * Advises the iterator to skip the subtree below the current node and
226 * also continues the current loop.
227 *
228 * @param iterator the iterator
229 */
230 #define cxTreeIteratorContinue(iterator) (iterator).skip = true; continue
232 /**
233 * Advises the visitor to skip the subtree below the current node and
234 * also continues the current loop.
235 *
236 * @param visitor the visitor
237 */
238 #define cxTreeVisitorContinue(visitor) cxTreeIteratorContinue(visitor)
240 /**
241 * Links a node to a (new) parent.
242 *
243 * If the node has already a parent, it is unlinked, first.
244 * If the parent has children already, the node is \em prepended to the list
245 * of all currently existing children.
246 *
247 * @param parent the parent node
248 * @param node the node that shall be linked
249 * @param loc_parent offset in the node struct for the parent pointer
250 * @param loc_children offset in the node struct for the children linked list
251 * @param loc_prev offset in the node struct for the prev pointer
252 * @param loc_next offset in the node struct for the next pointer
253 * @see cx_tree_unlink()
254 */
255 __attribute__((__nonnull__))
256 void cx_tree_link(
257 void * restrict parent,
258 void * restrict node,
259 ptrdiff_t loc_parent,
260 ptrdiff_t loc_children,
261 ptrdiff_t loc_prev,
262 ptrdiff_t loc_next
263 );
265 /**
266 * Unlinks a node from its parent.
267 *
268 * If the node has no parent, this function does nothing.
269 *
270 * @param node the node that shall be unlinked from its parent
271 * @param loc_parent offset in the node struct for the parent pointer
272 * @param loc_children offset in the node struct for the children linked list
273 * @param loc_prev offset in the node struct for the prev pointer
274 * @param loc_next offset in the node struct for the next pointer
275 * @see cx_tree_link()
276 */
277 __attribute__((__nonnull__))
278 void cx_tree_unlink(
279 void *node,
280 ptrdiff_t loc_parent,
281 ptrdiff_t loc_children,
282 ptrdiff_t loc_prev,
283 ptrdiff_t loc_next
284 );
286 /**
287 * Function pointer for a search function.
288 *
289 * A function of this kind shall check if the specified \p node
290 * contains the given \p data or if one of the children might contain
291 * the data.
292 *
293 * The function should use the returned integer to indicate how close the
294 * match is, where a negative number means that it does not match at all.
295 *
296 * For example if a tree stores file path information, a node that is
297 * describing a parent directory of a filename that is searched, shall
298 * return a positive number to indicate that a child node might contain the
299 * searched item. On the other hand, if the node denotes a path that is not a
300 * prefix of the searched filename, the function would return -1 to indicate
301 * that * the search does not need to be continued in that branch.
302 *
303 * @param node the node that is currently investigated
304 * @param data the data that is searched for
305 *
306 * @return 0 if the node contains the data,
307 * positive if one of the children might contain the data,
308 * negative if neither the node, nor the children contains the data
309 */
310 typedef int (*cx_tree_search_func)(void const *node, void const* data);
313 /**
314 * Searches for data in a tree.
315 *
316 * When the data cannot be found exactly, the search function might return a
317 * closest result which might be a good starting point for adding a new node
318 * to the tree.
319 *
320 * Depending on the tree structure it is not necessarily guaranteed that the
321 * "closest" match is uniquely defined. This function will search for a node
322 * with the best match according to the \p sfunc (meaning: the return value of
323 * \p sfunc which is closest to zero). If that is also ambiguous, an arbitrary
324 * node matching the criteria is returned.
325 *
326 * @param root the root node
327 * @param data the data to search for
328 * @param sfunc the search function
329 * @param result where the result shall be stored
330 * @param loc_children offset in the node struct for the children linked list
331 * @param loc_next offset in the node struct for the next pointer
332 * @return zero if the node was found exactly, positive if a node was found that
333 * could contain the node (but doesn't right now), negative if the tree does not
334 * contain any node that might be related to the searched data
335 */
336 __attribute__((__nonnull__))
337 int cx_tree_search(
338 void const *root,
339 void const *data,
340 cx_tree_search_func sfunc,
341 void **result,
342 ptrdiff_t loc_children,
343 ptrdiff_t loc_next
344 );
346 /**
347 * Creates a depth-first iterator for a tree with the specified root node.
348 *
349 * @note A tree iterator needs to maintain a stack of visited nodes, which is allocated using stdlib malloc().
350 * When the iterator becomes invalid, this memory is automatically released. However, if you wish to cancel the
351 * iteration before the iterator becomes invalid by itself, you MUST call cxTreeIteratorDispose() manually to release
352 * the memory.
353 *
354 * @remark The returned iterator does not support cxIteratorFlagRemoval().
355 *
356 * @param root the root node
357 * @param visit_on_exit set to true, when the iterator shall visit a node again after processing all children
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 iterator
361 * @see cxTreeIteratorDispose()
362 */
363 __attribute__((__nonnull__))
364 CxTreeIterator cx_tree_iterator(
365 void *root,
366 bool visit_on_exit,
367 ptrdiff_t loc_children,
368 ptrdiff_t loc_next
369 );
371 /**
372 * Creates a breadth-first iterator for a tree with the specified root node.
373 *
374 * @note A tree visitor needs to maintain a queue of to be visited nodes, which is allocated using stdlib malloc().
375 * When the visitor becomes invalid, this memory is automatically released. However, if you wish to cancel the
376 * iteration before the visitor becomes invalid by itself, you MUST call cxTreeVisitorDispose() manually to release
377 * the memory.
378 *
379 * @remark The returned iterator does not support cxIteratorFlagRemoval().
380 *
381 * @param root the root node
382 * @param loc_children offset in the node struct for the children linked list
383 * @param loc_next offset in the node struct for the next pointer
384 * @return the new tree visitor
385 * @see cxTreeVisitorDispose()
386 */
387 __attribute__((__nonnull__))
388 CxTreeVisitor cx_tree_visitor(
389 void *root,
390 ptrdiff_t loc_children,
391 ptrdiff_t loc_next
392 );
394 #ifdef __cplusplus
395 } // extern "C"
396 #endif
398 #endif //UCX_TREE_H