src/cx/tree.h

Thu, 23 May 2024 19:29:14 +0200

author
Mike Becker <universe@uap-core.de>
date
Thu, 23 May 2024 19:29:14 +0200
changeset 853
d4baf4dd55c3
parent 848
6456036bbb37
child 854
fe0d69d72bcd
permissions
-rw-r--r--

simplify iterator structures

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

mercurial