UNIXworkcode

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 */ 35 36 #ifndef UCX_TREE_H 37 #define UCX_TREE_H 38 39 #include "common.h" 40 41 #include "iterator.h" 42 43 #ifdef __cplusplus 44 extern "C" { 45 #endif 46 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 * Base members. 63 */ 64 CX_ITERATOR_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 *node_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; 124 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 }; 142 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 * Base members. 162 */ 163 CX_ITERATOR_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; 199 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 } 209 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 } 223 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 231 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) 239 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 ); 264 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 ); 285 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); 311 312 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 ); 345 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 ); 370 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 ); 393 394 #ifdef __cplusplus 395 } // extern "C" 396 #endif 397 398 #endif //UCX_TREE_H 399