src/cx/tree.h

Sun, 18 Feb 2024 12:24:04 +0100

author
Mike Becker <universe@uap-core.de>
date
Sun, 18 Feb 2024 12:24:04 +0100
changeset 830
c4dae6fe6d5b
parent 828
88fa3381206d
child 833
5c926801f052
permissions
-rw-r--r--

commit complicated stuff before simplifying it

relates to #371

     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  * When entering a node.
    49  *
    50  * When this is the first sibling, source is the parent, otherwise it is the previous child.
    51  */
    52 #define CX_TREE_ITERATOR_ENTER      0x1
    53 /**
    54  * When advancing to the next child.
    55  *
    56  * The visited node is the next child and the source is the previous child.
    57  * This pass is triggered after exiting the previous child and before entering the next child.
    58  */
    59 #define CX_TREE_ITERATOR_NEXT_CHILD 0x2
    60 /**
    61  * When exiting the node.
    62  *
    63  * The visited node is the node being exited and source is the previously entered node
    64  * (usually the last child of the exited node, unless it has no children, in which case it is the node itself).
    65  * When advancing to the next child in a list of siblings, the previous child is exited, first.
    66  */
    67 #define CX_TREE_ITERATOR_EXIT       0x4
    69 /**
    70  * Tree iterator.
    71  *
    72  * This iterator is not position-aware in a strict sense, as it does not assume a particular order of elements in the
    73  * tree. However, the iterator keeps track of the number of nodes it has passed in a counter variable.
    74  * Each node, regardless of the number of passes, is counted only once.
    75  *
    76  * @note Objects that are pointed to by an iterator are mutable through that iterator. However, if the
    77  * iterator is based on a collection and the underlying collection is mutated by other means than this iterator
    78  * (e.g. elements added or removed), the iterator becomes invalid (regardless of what cxIteratorValid() returns)
    79  * and MUST be re-obtained from the collection.
    80  *
    81  * @see CxIterator
    82  */
    83 typedef struct cx_tree_iterator_s {
    84     /**
    85      * The base properties of this iterator.
    86      */
    87     struct cx_iterator_base_s base;
    88     /**
    89      * The passes that are requested by this iterator.
    90      * A combination of the flags #CX_TREE_ITERATOR_ENTER, #CX_TREE_ITERATOR_NEXT_CHILD, #CX_TREE_ITERATOR_EXIT.
    91      *
    92      * Changing the value after beginning the iteration is unspecified.
    93      */
    94     uint8_t requested_passes;
    95     /**
    96      * The current pass.
    97      *
    98      * @see CX_TREE_ITERATOR_ENTER
    99      * @see CX_TREE_ITERATOR_NEXT_CHILD
   100      * @see CX_TREE_ITERATOR_EXIT
   101      */
   102     uint8_t current_pass;
   103     /**
   104      * Offset in the node struct for the children linked list.
   105      */
   106     off_t loc_children;
   107     /**
   108      * Offset in the node struct for the next pointer.
   109      */
   110     off_t loc_next;
   111     /**
   112      * The total number of distinct nodes that have been passed so far.
   113      */
   114     size_t counter;
   115     /**
   116      * The currently observed node.
   117      *
   118      * This is the same what cxIteratorCurrent() would return.
   119      */
   120     void *node;
   121     /**
   122      * The node where we came from.
   123      *
   124      * - When entering the root node, this is \c NULL.
   125      * - When entering another node, this is the node's parent.
   126      * - When advancing to the next child, this is the previous child.
   127      */
   128     void *source;
   129     /**
   130      * Internal stack.
   131      * Will be automatically freed once the iterator becomes invalid.
   132      *
   133      * If you want to discard the iterator before, you need to manually
   134      * call cxTreeIteratorDispose().
   135      */
   136     void **stack;
   137     /**
   138      * Internal capacity of the stack.
   139      */
   140     size_t stack_capacity;
   141     /**
   142      * Current depth.
   143      */
   144     size_t depth;
   145 } CxTreeIterator;
   147 /**
   148  * Releases internal memory of the given tree iterator.
   149  * @param iter the iterator
   150  */
   151 static inline void cxTreeIteratorDispose(CxTreeIterator *iter) {
   152     free(iter->stack);
   153 }
   155 /**
   156  * Links a node to a (new) parent.
   157  *
   158  * If the node has already a parent, it is unlinked, first.
   159  * If the parent has children already, the node is prepended to the list
   160  * of all currently existing children.
   161  *
   162  * @param parent the parent node
   163  * @param node the node that shall be linked
   164  * @param loc_parent offset in the node struct for the parent pointer
   165  * @param loc_children offset in the node struct for the children linked list
   166  * @param loc_prev offset in the node struct for the prev pointer
   167  * @param loc_next offset in the node struct for the next pointer
   168  * @see cx_tree_unlink()
   169  */
   170 __attribute__((__nonnull__))
   171 void cx_tree_link(
   172         void * restrict parent,
   173         void * restrict node,
   174         ptrdiff_t loc_parent,
   175         ptrdiff_t loc_children,
   176         ptrdiff_t loc_prev,
   177         ptrdiff_t loc_next
   178 );
   180 /**
   181  * Unlinks a node from its parent.
   182  *
   183  * If the node has no parent, this function does nothing.
   184  *
   185  * @param node the node that shall be unlinked from its parent
   186  * @param loc_parent offset in the node struct for the parent pointer
   187  * @param loc_children offset in the node struct for the children linked list
   188  * @param loc_prev offset in the node struct for the prev pointer
   189  * @param loc_next offset in the node struct for the next pointer
   190  * @see cx_tree_link()
   191  */
   192 __attribute__((__nonnull__))
   193 void cx_tree_unlink(
   194         void *node,
   195         ptrdiff_t loc_parent,
   196         ptrdiff_t loc_children,
   197         ptrdiff_t loc_prev,
   198         ptrdiff_t loc_next
   199 );
   201 /**
   202  * Function pointer for a search function.
   203  *
   204  * A function of this kind shall check if the specified \p node
   205  * contains the given \p data or if one of the children might contain
   206  * the data.
   207  *
   208  * The function should use the returned integer to indicate how close the
   209  * match is, where a negative number means that it does not match at all.
   210  *
   211  * For example if a tree stores file path information, a node that is
   212  * describing a parent directory of a filename that is searched, shall
   213  * return a positive number to indicate that a child node might contain the
   214  * searched item. On the other hand, if the node denotes a path that is not a
   215  * prefix of the searched filename, the function would return -1 to indicate
   216  * that * the search does not need to be continued in that branch.
   217  *
   218  * @param node the node that is currently investigated
   219  * @param data the data that is searched for
   220  *
   221  * @return 0 if the node contains the data,
   222  * positive if one of the children might contain the data,
   223  * negative if neither the node, nor the children contains the data
   224  */
   225 typedef int (*cx_tree_search_func)(void const *node, void const* data);
   228 /**
   229  * Searches for data in a tree.
   230  *
   231  * When the data cannot be found exactly, the search function might return a
   232  * closest result which might be a good starting point for adding a new node
   233  * to the tree.
   234  *
   235  * Depending on the tree structure it is not necessarily guaranteed that the
   236  * "closest" match is uniquely defined. This function will search for a node
   237  * with the best match according to the \p sfunc (meaning: the return value of
   238  * \p sfunc which is closest to zero). If that is also ambiguous, an arbitrary
   239  * node matching the criteria is returned.
   240  *
   241  * @param root the root node
   242  * @param data the data to search for
   243  * @param sfunc the search function
   244  * @param result where the result shall be stored
   245  * @param loc_children offset in the node struct for the children linked list
   246  * @param loc_next offset in the node struct for the next pointer
   247  * @return zero if the node was found exactly, positive if a node was found that
   248  * could contain the node (but doesn't right now), negative if the tree does not
   249  * contain any node that might be related to the searched data
   250  */
   251 __attribute__((__nonnull__))
   252 int cx_tree_search(
   253         void const *root,
   254         void const *data,
   255         cx_tree_search_func sfunc,
   256         void **result,
   257         ptrdiff_t loc_children,
   258         ptrdiff_t loc_next
   259 );
   261 /**
   262  * Creates an iterator for a tree with the specified root node.
   263  *
   264  * The \p passes argument is supposed to be a combination of the flags
   265  * #CX_TREE_ITERATOR_ENTER, #CX_TREE_ITERATOR_NEXT_CHILD, and #CX_TREE_ITERATOR_EXIT.
   266  * Alternatively, the integer 1 is equivalent to just specifying #CX_TREE_ITERATOR_ENTER
   267  * which will cause the iterator to pass every node only once (when entering the node).
   268  *
   269  * When #CX_TREE_ITERATOR_EXIT is set, the iterator will visit a parent node again,
   270  * when \em every of it's children has been visited (including the case when the node does not have any children).
   271  *
   272  * When #CX_TREE_ITERATOR_NEXT_CHILD is set, the iterator will visit a parent node again,
   273  * when advancing from one child to the next.
   274  *
   275  * @note A tree iterator needs to maintain a stack of visited nodes, which is allocated using stdlib malloc().
   276  * When the iterator becomes invalid, this memory is automatically released. However, if you wish to cancel the
   277  * iteration before the iterator becomes invalid by itself, you MUST call cxTreeIteratorDispose() manually to release
   278  * the memory.
   279  *
   280  * @remark At the moment, the returned iterator does not support cxIteratorFlagRemoval().
   281  *
   282  * @param root the root node
   283  * @param passes the passes this iterator shall perform
   284  * @param loc_children offset in the node struct for the children linked list
   285  * @param loc_next offset in the node struct for the next pointer
   286  * @return the new tree iterator
   287  * @see cxTreeIteratorDispose()
   288  */
   289 __attribute__((__nonnull__))
   290 CxTreeIterator cx_tree_iterator(
   291         void *root,
   292         int passes,
   293         ptrdiff_t loc_children,
   294         ptrdiff_t loc_next
   295 );
   297 #ifdef __cplusplus
   298 } // extern "C"
   299 #endif
   301 #endif //UCX_TREE_H

mercurial