src/cx/tree.h

Sat, 17 Feb 2024 20:22:13 +0100

author
Mike Becker <universe@uap-core.de>
date
Sat, 17 Feb 2024 20:22:13 +0100
changeset 828
88fa3381206d
parent 827
13b40a598d16
child 830
c4dae6fe6d5b
permissions
-rw-r--r--

improve tree iterator struct and add signature for a function that can create an iterator

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

mercurial