src/cx/tree.h

Mon, 26 Feb 2024 21:07:23 +0100

author
Mike Becker <universe@uap-core.de>
date
Mon, 26 Feb 2024 21:07:23 +0100
changeset 840
4f02995ce44e
parent 835
13068743197f
child 845
2615317311b7
permissions
-rw-r--r--

allow freeing tree nodes on exit - fixes #377

     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  * 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      * Set to true, when the iterator shall visit a node again
    67      * when all it's children have been processed.
    68      */
    69     bool visit_on_exit;
    70     /**
    71      * True, if this iterator is currently leaving the node.
    72      */
    73     bool exiting;
    74     /**
    75      * Offset in the node struct for the children linked list.
    76      */
    77     off_t loc_children;
    78     /**
    79      * Offset in the node struct for the next pointer.
    80      */
    81     off_t loc_next;
    82     /**
    83      * The total number of distinct nodes that have been passed so far.
    84      */
    85     size_t counter;
    86     /**
    87      * The currently observed node.
    88      *
    89      * This is the same what cxIteratorCurrent() would return.
    90      */
    91     void *node;
    92     /**
    93      * Stores a copy of the next pointer of the visited node.
    94      * Allows freeing a node on exit without corrupting the iteration.
    95      */
    96     void *next;
    97     /**
    98      * Internal stack.
    99      * Will be automatically freed once the iterator becomes invalid.
   100      *
   101      * If you want to discard the iterator before, you need to manually
   102      * call cxTreeIteratorDispose().
   103      */
   104     void **stack;
   105     /**
   106      * Internal capacity of the stack.
   107      */
   108     size_t stack_capacity;
   109     union {
   110         /**
   111          * Internal stack size.
   112          */
   113         size_t stack_size;
   114         /**
   115          * The current depth in the tree.
   116          */
   117         size_t depth;
   118     };
   119 } CxTreeIterator;
   121 /**
   122  * Releases internal memory of the given tree iterator.
   123  * @param iter the iterator
   124  */
   125 static inline void cxTreeIteratorDispose(CxTreeIterator *iter) {
   126     free(iter->stack);
   127     iter->stack = NULL;
   128 }
   130 /**
   131  * Links a node to a (new) parent.
   132  *
   133  * 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
   135  * of all currently existing children.
   136  *
   137  * @param parent the parent node
   138  * @param node the node that shall be linked
   139  * @param loc_parent offset in the node struct for the parent pointer
   140  * @param loc_children offset in the node struct for the children linked list
   141  * @param loc_prev offset in the node struct for the prev pointer
   142  * @param loc_next offset in the node struct for the next pointer
   143  * @see cx_tree_unlink()
   144  */
   145 __attribute__((__nonnull__))
   146 void cx_tree_link(
   147         void * restrict parent,
   148         void * restrict node,
   149         ptrdiff_t loc_parent,
   150         ptrdiff_t loc_children,
   151         ptrdiff_t loc_prev,
   152         ptrdiff_t loc_next
   153 );
   155 /**
   156  * Unlinks a node from its parent.
   157  *
   158  * If the node has no parent, this function does nothing.
   159  *
   160  * @param node the node that shall be unlinked from its parent
   161  * @param loc_parent offset in the node struct for the parent pointer
   162  * @param loc_children offset in the node struct for the children linked list
   163  * @param loc_prev offset in the node struct for the prev pointer
   164  * @param loc_next offset in the node struct for the next pointer
   165  * @see cx_tree_link()
   166  */
   167 __attribute__((__nonnull__))
   168 void cx_tree_unlink(
   169         void *node,
   170         ptrdiff_t loc_parent,
   171         ptrdiff_t loc_children,
   172         ptrdiff_t loc_prev,
   173         ptrdiff_t loc_next
   174 );
   176 /**
   177  * Function pointer for a search function.
   178  *
   179  * A function of this kind shall check if the specified \p node
   180  * contains the given \p data or if one of the children might contain
   181  * the data.
   182  *
   183  * The function should use the returned integer to indicate how close the
   184  * match is, where a negative number means that it does not match at all.
   185  *
   186  * For example if a tree stores file path information, a node that is
   187  * describing a parent directory of a filename that is searched, shall
   188  * return a positive number to indicate that a child node might contain the
   189  * searched item. On the other hand, if the node denotes a path that is not a
   190  * prefix of the searched filename, the function would return -1 to indicate
   191  * that * the search does not need to be continued in that branch.
   192  *
   193  * @param node the node that is currently investigated
   194  * @param data the data that is searched for
   195  *
   196  * @return 0 if the node contains the data,
   197  * positive if one of the children might contain the data,
   198  * negative if neither the node, nor the children contains the data
   199  */
   200 typedef int (*cx_tree_search_func)(void const *node, void const* data);
   203 /**
   204  * Searches for data in a tree.
   205  *
   206  * When the data cannot be found exactly, the search function might return a
   207  * closest result which might be a good starting point for adding a new node
   208  * to the tree.
   209  *
   210  * Depending on the tree structure it is not necessarily guaranteed that the
   211  * "closest" match is uniquely defined. This function will search for a node
   212  * with the best match according to the \p sfunc (meaning: the return value of
   213  * \p sfunc which is closest to zero). If that is also ambiguous, an arbitrary
   214  * node matching the criteria is returned.
   215  *
   216  * @param root the root node
   217  * @param data the data to search for
   218  * @param sfunc the search function
   219  * @param result where the result shall be stored
   220  * @param loc_children offset in the node struct for the children linked list
   221  * @param loc_next offset in the node struct for the next pointer
   222  * @return zero if the node was found exactly, positive if a node was found that
   223  * could contain the node (but doesn't right now), negative if the tree does not
   224  * contain any node that might be related to the searched data
   225  */
   226 __attribute__((__nonnull__))
   227 int cx_tree_search(
   228         void const *root,
   229         void const *data,
   230         cx_tree_search_func sfunc,
   231         void **result,
   232         ptrdiff_t loc_children,
   233         ptrdiff_t loc_next
   234 );
   236 /**
   237  * Creates an iterator for a tree with the specified root node.
   238  *
   239  * @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
   241  * iteration before the iterator becomes invalid by itself, you MUST call cxTreeIteratorDispose() manually to release
   242  * the memory.
   243  *
   244  * @remark At the moment, the returned iterator does not support cxIteratorFlagRemoval().
   245  *
   246  * @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
   248  * @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
   250  * @return the new tree iterator
   251  * @see cxTreeIteratorDispose()
   252  */
   253 __attribute__((__nonnull__))
   254 CxTreeIterator cx_tree_iterator(
   255         void *root,
   256         bool visit_on_exit,
   257         ptrdiff_t loc_children,
   258         ptrdiff_t loc_next
   259 );
   261 #ifdef __cplusplus
   262 } // extern "C"
   263 #endif
   265 #endif //UCX_TREE_H

mercurial