src/cx/tree.h

Mon, 19 Feb 2024 22:08:09 +0100

author
Mike Becker <universe@uap-core.de>
date
Mon, 19 Feb 2024 22:08:09 +0100
changeset 835
13068743197f
parent 833
5c926801f052
child 840
4f02995ce44e
permissions
-rw-r--r--

set tree iterator stack pointer to NULL on dispose to avoid accidental double-frees

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

mercurial