universe@816: /* universe@816: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. universe@816: * universe@816: * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved. universe@816: * universe@816: * Redistribution and use in source and binary forms, with or without universe@816: * modification, are permitted provided that the following conditions are met: universe@816: * universe@816: * 1. Redistributions of source code must retain the above copyright universe@816: * notice, this list of conditions and the following disclaimer. universe@816: * universe@816: * 2. Redistributions in binary form must reproduce the above copyright universe@816: * notice, this list of conditions and the following disclaimer in the universe@816: * documentation and/or other materials provided with the distribution. universe@816: * universe@816: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" universe@816: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE universe@816: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE universe@816: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE universe@816: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR universe@816: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF universe@816: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS universe@816: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN universe@816: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) universe@816: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE universe@816: * POSSIBILITY OF SUCH DAMAGE. universe@816: */ universe@816: /** universe@816: * \file tree.h universe@816: * \brief Interface for tree implementations. universe@816: * \author Mike Becker universe@816: * \author Olaf Wintermann universe@816: * \copyright 2-Clause BSD License universe@816: */ universe@816: universe@816: #ifndef UCX_TREE_H universe@816: #define UCX_TREE_H universe@816: universe@816: #include "common.h" universe@816: universe@827: #include "iterator.h" universe@827: universe@816: #ifdef __cplusplus universe@816: extern "C" { universe@816: #endif universe@816: universe@827: /** universe@827: * When entering a node. universe@827: */ universe@827: #define CX_TREE_ITERATOR_ENTER 0x1 universe@827: /** universe@827: * When advancing to the next child. universe@827: */ universe@827: #define CX_TREE_ITERATOR_NEXT_CHILD 0x2 universe@827: /** universe@827: * When exiting the node. universe@827: */ universe@827: #define CX_TREE_ITERATOR_EXIT 0x4 universe@827: universe@827: /** universe@827: * Tree iterator. universe@827: * universe@827: * This iterator is not position-aware in a strict sense, as it does not assume a particular order of elements in the universe@827: * tree. However, the iterator keeps track of the number of nodes it has passed in a counter variable. universe@827: * Each node, regardless of the number of passes, is counted only once. universe@827: * universe@827: * @note Objects that are pointed to by an iterator are mutable through that iterator. However, if the universe@827: * iterator is based on a collection and the underlying collection is mutated by other means than this iterator universe@827: * (e.g. elements added or removed), the iterator becomes invalid (regardless of what cxIteratorValid() returns) universe@827: * and MUST be re-obtained from the collection. universe@827: * universe@827: * @see CxIterator universe@827: */ universe@827: typedef struct cx_tree_iterator_s { universe@827: /** universe@827: * The base properties of this iterator. universe@827: */ universe@827: struct cx_iterator_base_s base; universe@827: /** universe@827: * The passes that are requested by this iterator. universe@827: * A combination of the flags #CX_TREE_ITERATOR_ENTER, #CX_TREE_ITERATOR_NEXT_CHILD, #CX_TREE_ITERATOR_EXIT. universe@827: * universe@827: * Changing the value after beginning the iteration is unspecified. universe@827: */ universe@827: uint8_t requested_passes; universe@827: /** universe@827: * The current pass. universe@827: * universe@827: * @see CX_TREE_ITERATOR_ENTER universe@827: * @see CX_TREE_ITERATOR_NEXT_CHILD universe@827: * @see CX_TREE_ITERATOR_EXIT universe@827: */ universe@827: uint8_t current_pass; universe@827: /** universe@827: * Offset in the node struct for the children linked list. universe@827: */ universe@827: off_t loc_children; universe@827: /** universe@827: * Offset in the node struct for the next pointer. universe@827: */ universe@827: off_t loc_next; universe@827: /** universe@827: * The total number of distinct nodes that have been passed so far. universe@827: */ universe@827: size_t counter; universe@827: /** universe@827: * The currently observed node. universe@827: * universe@827: * This is the same what cxIteratorCurrent() would return. universe@827: */ universe@827: void *node; universe@827: /** universe@827: * The node where we came from. universe@827: * universe@827: * - When entering the root node, this is \c NULL. universe@827: * - When entering another node, this is the node's parent. universe@827: * - When advancing to the next child, this is the previous child. universe@827: */ universe@827: void *source; universe@827: /** universe@827: * Internal stack. universe@827: * Will be automatically freed once the iterator becomes invalid. universe@827: * universe@827: * If you want to discard the iterator before, you need to manually universe@827: * call cxTreeIteratorDispose(). universe@827: */ universe@827: void **stack; universe@828: /** universe@828: * Internal capacity of the stack. universe@828: */ universe@828: size_t stack_capacity; universe@828: /** universe@828: * Current depth. universe@828: */ universe@828: size_t depth; universe@827: } CxTreeIterator; universe@827: universe@827: /** universe@827: * Releases internal memory of the given tree iterator. universe@827: * @param iter the iterator universe@827: */ universe@827: static inline void cxTreeIteratorDispose(CxTreeIterator *iter) { universe@827: free(iter->stack); universe@827: } universe@816: universe@822: /** universe@822: * Links a node to a (new) parent. universe@822: * universe@822: * If the node has already a parent, it is unlinked, first. universe@826: * If the parent has children already, the node is prepended to the list universe@826: * of all currently existing children. universe@822: * universe@822: * @param parent the parent node universe@822: * @param node the node that shall be linked universe@822: * @param loc_parent offset in the node struct for the parent pointer universe@822: * @param loc_children offset in the node struct for the children linked list universe@822: * @param loc_prev offset in the node struct for the prev pointer universe@822: * @param loc_next offset in the node struct for the next pointer universe@822: * @see cx_tree_unlink() universe@822: */ universe@816: __attribute__((__nonnull__)) universe@816: void cx_tree_link( universe@816: void * restrict parent, universe@816: void * restrict node, universe@816: ptrdiff_t loc_parent, universe@816: ptrdiff_t loc_children, universe@816: ptrdiff_t loc_prev, universe@816: ptrdiff_t loc_next universe@816: ); universe@816: universe@822: /** universe@822: * Unlinks a node from its parent. universe@822: * universe@822: * If the node has no parent, this function does nothing. universe@822: * universe@822: * @param node the node that shall be unlinked from its parent universe@822: * @param loc_parent offset in the node struct for the parent pointer universe@822: * @param loc_children offset in the node struct for the children linked list universe@822: * @param loc_prev offset in the node struct for the prev pointer universe@822: * @param loc_next offset in the node struct for the next pointer universe@822: * @see cx_tree_link() universe@822: */ universe@816: __attribute__((__nonnull__)) universe@816: void cx_tree_unlink( universe@816: void *node, universe@816: ptrdiff_t loc_parent, universe@816: ptrdiff_t loc_children, universe@816: ptrdiff_t loc_prev, universe@816: ptrdiff_t loc_next universe@816: ); universe@816: universe@823: /** universe@823: * Function pointer for a search function. universe@823: * universe@823: * A function of this kind shall check if the specified \p node universe@823: * contains the given \p data or if one of the children might contain universe@823: * the data. universe@823: * universe@826: * The function should use the returned integer to indicate how close the universe@826: * match is, where a negative number means that it does not match at all. universe@826: * universe@823: * For example if a tree stores file path information, a node that is universe@823: * describing a parent directory of a filename that is searched, shall universe@826: * return a positive number to indicate that a child node might contain the universe@826: * searched item. On the other hand, if the node denotes a path that is not a universe@826: * prefix of the searched filename, the function would return -1 to indicate universe@826: * that * the search does not need to be continued in that branch. universe@823: * universe@823: * @param node the node that is currently investigated universe@823: * @param data the data that is searched for universe@823: * universe@823: * @return 0 if the node contains the data, universe@826: * positive if one of the children might contain the data, universe@826: * negative if neither the node, nor the children contains the data universe@823: */ universe@824: typedef int (*cx_tree_search_func)(void const *node, void const* data); universe@823: universe@826: universe@826: /** universe@826: * Searches for data in a tree. universe@826: * universe@826: * When the data cannot be found exactly, the search function might return a universe@826: * closest result which might be a good starting point for adding a new node universe@826: * to the tree. universe@826: * universe@826: * Depending on the tree structure it is not necessarily guaranteed that the universe@826: * "closest" match is uniquely defined. This function will search for a node universe@826: * with the best match according to the \p sfunc (meaning: the return value of universe@826: * \p sfunc which is closest to zero). If that is also ambiguous, an arbitrary universe@826: * node matching the criteria is returned. universe@826: * universe@826: * @param root the root node universe@826: * @param data the data to search for universe@826: * @param sfunc the search function universe@826: * @param result where the result shall be stored universe@826: * @param loc_children offset in the node struct for the children linked list universe@826: * @param loc_next offset in the node struct for the next pointer universe@826: * @return zero if the node was found exactly, positive if a node was found that universe@826: * could contain the node (but doesn't right now), negative if the tree does not universe@826: * contain any node that might be related to the searched data universe@826: */ universe@826: __attribute__((__nonnull__)) universe@826: int cx_tree_search( universe@826: void const *root, universe@826: void const *data, universe@826: cx_tree_search_func sfunc, universe@826: void **result, universe@826: ptrdiff_t loc_children, universe@826: ptrdiff_t loc_next universe@826: ); universe@826: universe@828: /** universe@828: * Creates an iterator for a tree with the specified root node. universe@828: * universe@828: * The \p passes argument is supposed to be a combination of the flags universe@828: * #CX_TREE_ITERATOR_ENTER, #CX_TREE_ITERATOR_NEXT_CHILD, and #CX_TREE_ITERATOR_EXIT. universe@828: * Alternatively, the integer 1 is equivalent to just specifying #CX_TREE_ITERATOR_ENTER universe@828: * which will cause the iterator to pass every node only once (when entering the node). universe@828: * universe@828: * When #CX_TREE_ITERATOR_EXIT is set, the iterator will visit a parent node again, universe@828: * when \em every of it's children has been visited (including the case when the node does not have any children). universe@828: * universe@828: * When #CX_TREE_ITERATOR_NEXT_CHILD is set, the iterator will visit a parent node again, universe@828: * when advancing from one child to the next. universe@828: * universe@828: * @note A tree iterator needs to maintain a stack of visited nodes, which is allocated using stdlib malloc(). universe@828: * When the iterator becomes invalid, this memory is automatically released. However, if you wish to cancel the universe@828: * iteration before the iterator becomes invalid by itself, you MUST call cxTreeIteratorDispose() manually to release universe@828: * the memory. universe@828: * universe@828: * @remark At the moment, the returned iterator does not support cxIteratorFlagRemoval(). universe@828: * universe@828: * @param root the root node universe@828: * @param passes the passes this iterator shall perform universe@828: * @param loc_children offset in the node struct for the children linked list universe@828: * @param loc_next offset in the node struct for the next pointer universe@828: * @return the new tree iterator universe@828: * @see cxTreeIteratorDispose() universe@828: */ universe@828: __attribute__((__nonnull__)) universe@828: CxTreeIterator cx_tree_iterate( universe@828: void const *root, universe@828: int passes, universe@828: ptrdiff_t loc_children, universe@828: ptrdiff_t loc_next universe@828: ); universe@828: universe@816: #ifdef __cplusplus universe@816: } // extern "C" universe@816: #endif universe@816: universe@816: #endif //UCX_TREE_H