src/cx/tree.h

Fri, 12 Apr 2024 21:48:12 +0200

author
Mike Becker <universe@uap-core.de>
date
Fri, 12 Apr 2024 21:48:12 +0200
changeset 849
edb9f875b7f9
parent 848
6456036bbb37
permissions
-rw-r--r--

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

mercurial