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

universe@816 1 /*
universe@816 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
universe@816 3 *
universe@816 4 * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved.
universe@816 5 *
universe@816 6 * Redistribution and use in source and binary forms, with or without
universe@816 7 * modification, are permitted provided that the following conditions are met:
universe@816 8 *
universe@816 9 * 1. Redistributions of source code must retain the above copyright
universe@816 10 * notice, this list of conditions and the following disclaimer.
universe@816 11 *
universe@816 12 * 2. Redistributions in binary form must reproduce the above copyright
universe@816 13 * notice, this list of conditions and the following disclaimer in the
universe@816 14 * documentation and/or other materials provided with the distribution.
universe@816 15 *
universe@816 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
universe@816 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
universe@816 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
universe@816 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
universe@816 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
universe@816 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
universe@816 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
universe@816 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
universe@816 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
universe@816 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
universe@816 26 * POSSIBILITY OF SUCH DAMAGE.
universe@816 27 */
universe@816 28 /**
universe@816 29 * \file tree.h
universe@816 30 * \brief Interface for tree implementations.
universe@816 31 * \author Mike Becker
universe@816 32 * \author Olaf Wintermann
universe@816 33 * \copyright 2-Clause BSD License
universe@816 34 */
universe@816 35
universe@816 36 #ifndef UCX_TREE_H
universe@816 37 #define UCX_TREE_H
universe@816 38
universe@816 39 #include "common.h"
universe@816 40
universe@827 41 #include "iterator.h"
universe@827 42
universe@816 43 #ifdef __cplusplus
universe@816 44 extern "C" {
universe@816 45 #endif
universe@816 46
universe@827 47 /**
universe@827 48 * When entering a node.
universe@827 49 */
universe@827 50 #define CX_TREE_ITERATOR_ENTER 0x1
universe@827 51 /**
universe@827 52 * When advancing to the next child.
universe@827 53 */
universe@827 54 #define CX_TREE_ITERATOR_NEXT_CHILD 0x2
universe@827 55 /**
universe@827 56 * When exiting the node.
universe@827 57 */
universe@827 58 #define CX_TREE_ITERATOR_EXIT 0x4
universe@827 59
universe@827 60 /**
universe@827 61 * Tree iterator.
universe@827 62 *
universe@827 63 * This iterator is not position-aware in a strict sense, as it does not assume a particular order of elements in the
universe@827 64 * tree. However, the iterator keeps track of the number of nodes it has passed in a counter variable.
universe@827 65 * Each node, regardless of the number of passes, is counted only once.
universe@827 66 *
universe@827 67 * @note Objects that are pointed to by an iterator are mutable through that iterator. However, if the
universe@827 68 * iterator is based on a collection and the underlying collection is mutated by other means than this iterator
universe@827 69 * (e.g. elements added or removed), the iterator becomes invalid (regardless of what cxIteratorValid() returns)
universe@827 70 * and MUST be re-obtained from the collection.
universe@827 71 *
universe@827 72 * @see CxIterator
universe@827 73 */
universe@827 74 typedef struct cx_tree_iterator_s {
universe@827 75 /**
universe@827 76 * The base properties of this iterator.
universe@827 77 */
universe@827 78 struct cx_iterator_base_s base;
universe@827 79 /**
universe@827 80 * The passes that are requested by this iterator.
universe@827 81 * A combination of the flags #CX_TREE_ITERATOR_ENTER, #CX_TREE_ITERATOR_NEXT_CHILD, #CX_TREE_ITERATOR_EXIT.
universe@827 82 *
universe@827 83 * Changing the value after beginning the iteration is unspecified.
universe@827 84 */
universe@827 85 uint8_t requested_passes;
universe@827 86 /**
universe@827 87 * The current pass.
universe@827 88 *
universe@827 89 * @see CX_TREE_ITERATOR_ENTER
universe@827 90 * @see CX_TREE_ITERATOR_NEXT_CHILD
universe@827 91 * @see CX_TREE_ITERATOR_EXIT
universe@827 92 */
universe@827 93 uint8_t current_pass;
universe@827 94 /**
universe@827 95 * Offset in the node struct for the children linked list.
universe@827 96 */
universe@827 97 off_t loc_children;
universe@827 98 /**
universe@827 99 * Offset in the node struct for the next pointer.
universe@827 100 */
universe@827 101 off_t loc_next;
universe@827 102 /**
universe@827 103 * The total number of distinct nodes that have been passed so far.
universe@827 104 */
universe@827 105 size_t counter;
universe@827 106 /**
universe@827 107 * The currently observed node.
universe@827 108 *
universe@827 109 * This is the same what cxIteratorCurrent() would return.
universe@827 110 */
universe@827 111 void *node;
universe@827 112 /**
universe@827 113 * The node where we came from.
universe@827 114 *
universe@827 115 * - When entering the root node, this is \c NULL.
universe@827 116 * - When entering another node, this is the node's parent.
universe@827 117 * - When advancing to the next child, this is the previous child.
universe@827 118 */
universe@827 119 void *source;
universe@827 120 /**
universe@827 121 * Internal stack.
universe@827 122 * Will be automatically freed once the iterator becomes invalid.
universe@827 123 *
universe@827 124 * If you want to discard the iterator before, you need to manually
universe@827 125 * call cxTreeIteratorDispose().
universe@827 126 */
universe@827 127 void **stack;
universe@828 128 /**
universe@828 129 * Internal capacity of the stack.
universe@828 130 */
universe@828 131 size_t stack_capacity;
universe@828 132 /**
universe@828 133 * Current depth.
universe@828 134 */
universe@828 135 size_t depth;
universe@827 136 } CxTreeIterator;
universe@827 137
universe@827 138 /**
universe@827 139 * Releases internal memory of the given tree iterator.
universe@827 140 * @param iter the iterator
universe@827 141 */
universe@827 142 static inline void cxTreeIteratorDispose(CxTreeIterator *iter) {
universe@827 143 free(iter->stack);
universe@827 144 }
universe@816 145
universe@822 146 /**
universe@822 147 * Links a node to a (new) parent.
universe@822 148 *
universe@822 149 * If the node has already a parent, it is unlinked, first.
universe@826 150 * If the parent has children already, the node is prepended to the list
universe@826 151 * of all currently existing children.
universe@822 152 *
universe@822 153 * @param parent the parent node
universe@822 154 * @param node the node that shall be linked
universe@822 155 * @param loc_parent offset in the node struct for the parent pointer
universe@822 156 * @param loc_children offset in the node struct for the children linked list
universe@822 157 * @param loc_prev offset in the node struct for the prev pointer
universe@822 158 * @param loc_next offset in the node struct for the next pointer
universe@822 159 * @see cx_tree_unlink()
universe@822 160 */
universe@816 161 __attribute__((__nonnull__))
universe@816 162 void cx_tree_link(
universe@816 163 void * restrict parent,
universe@816 164 void * restrict node,
universe@816 165 ptrdiff_t loc_parent,
universe@816 166 ptrdiff_t loc_children,
universe@816 167 ptrdiff_t loc_prev,
universe@816 168 ptrdiff_t loc_next
universe@816 169 );
universe@816 170
universe@822 171 /**
universe@822 172 * Unlinks a node from its parent.
universe@822 173 *
universe@822 174 * If the node has no parent, this function does nothing.
universe@822 175 *
universe@822 176 * @param node the node that shall be unlinked from its parent
universe@822 177 * @param loc_parent offset in the node struct for the parent pointer
universe@822 178 * @param loc_children offset in the node struct for the children linked list
universe@822 179 * @param loc_prev offset in the node struct for the prev pointer
universe@822 180 * @param loc_next offset in the node struct for the next pointer
universe@822 181 * @see cx_tree_link()
universe@822 182 */
universe@816 183 __attribute__((__nonnull__))
universe@816 184 void cx_tree_unlink(
universe@816 185 void *node,
universe@816 186 ptrdiff_t loc_parent,
universe@816 187 ptrdiff_t loc_children,
universe@816 188 ptrdiff_t loc_prev,
universe@816 189 ptrdiff_t loc_next
universe@816 190 );
universe@816 191
universe@823 192 /**
universe@823 193 * Function pointer for a search function.
universe@823 194 *
universe@823 195 * A function of this kind shall check if the specified \p node
universe@823 196 * contains the given \p data or if one of the children might contain
universe@823 197 * the data.
universe@823 198 *
universe@826 199 * The function should use the returned integer to indicate how close the
universe@826 200 * match is, where a negative number means that it does not match at all.
universe@826 201 *
universe@823 202 * For example if a tree stores file path information, a node that is
universe@823 203 * describing a parent directory of a filename that is searched, shall
universe@826 204 * return a positive number to indicate that a child node might contain the
universe@826 205 * searched item. On the other hand, if the node denotes a path that is not a
universe@826 206 * prefix of the searched filename, the function would return -1 to indicate
universe@826 207 * that * the search does not need to be continued in that branch.
universe@823 208 *
universe@823 209 * @param node the node that is currently investigated
universe@823 210 * @param data the data that is searched for
universe@823 211 *
universe@823 212 * @return 0 if the node contains the data,
universe@826 213 * positive if one of the children might contain the data,
universe@826 214 * negative if neither the node, nor the children contains the data
universe@823 215 */
universe@824 216 typedef int (*cx_tree_search_func)(void const *node, void const* data);
universe@823 217
universe@826 218
universe@826 219 /**
universe@826 220 * Searches for data in a tree.
universe@826 221 *
universe@826 222 * When the data cannot be found exactly, the search function might return a
universe@826 223 * closest result which might be a good starting point for adding a new node
universe@826 224 * to the tree.
universe@826 225 *
universe@826 226 * Depending on the tree structure it is not necessarily guaranteed that the
universe@826 227 * "closest" match is uniquely defined. This function will search for a node
universe@826 228 * with the best match according to the \p sfunc (meaning: the return value of
universe@826 229 * \p sfunc which is closest to zero). If that is also ambiguous, an arbitrary
universe@826 230 * node matching the criteria is returned.
universe@826 231 *
universe@826 232 * @param root the root node
universe@826 233 * @param data the data to search for
universe@826 234 * @param sfunc the search function
universe@826 235 * @param result where the result shall be stored
universe@826 236 * @param loc_children offset in the node struct for the children linked list
universe@826 237 * @param loc_next offset in the node struct for the next pointer
universe@826 238 * @return zero if the node was found exactly, positive if a node was found that
universe@826 239 * could contain the node (but doesn't right now), negative if the tree does not
universe@826 240 * contain any node that might be related to the searched data
universe@826 241 */
universe@826 242 __attribute__((__nonnull__))
universe@826 243 int cx_tree_search(
universe@826 244 void const *root,
universe@826 245 void const *data,
universe@826 246 cx_tree_search_func sfunc,
universe@826 247 void **result,
universe@826 248 ptrdiff_t loc_children,
universe@826 249 ptrdiff_t loc_next
universe@826 250 );
universe@826 251
universe@828 252 /**
universe@828 253 * Creates an iterator for a tree with the specified root node.
universe@828 254 *
universe@828 255 * The \p passes argument is supposed to be a combination of the flags
universe@828 256 * #CX_TREE_ITERATOR_ENTER, #CX_TREE_ITERATOR_NEXT_CHILD, and #CX_TREE_ITERATOR_EXIT.
universe@828 257 * Alternatively, the integer 1 is equivalent to just specifying #CX_TREE_ITERATOR_ENTER
universe@828 258 * which will cause the iterator to pass every node only once (when entering the node).
universe@828 259 *
universe@828 260 * When #CX_TREE_ITERATOR_EXIT is set, the iterator will visit a parent node again,
universe@828 261 * when \em every of it's children has been visited (including the case when the node does not have any children).
universe@828 262 *
universe@828 263 * When #CX_TREE_ITERATOR_NEXT_CHILD is set, the iterator will visit a parent node again,
universe@828 264 * when advancing from one child to the next.
universe@828 265 *
universe@828 266 * @note A tree iterator needs to maintain a stack of visited nodes, which is allocated using stdlib malloc().
universe@828 267 * When the iterator becomes invalid, this memory is automatically released. However, if you wish to cancel the
universe@828 268 * iteration before the iterator becomes invalid by itself, you MUST call cxTreeIteratorDispose() manually to release
universe@828 269 * the memory.
universe@828 270 *
universe@828 271 * @remark At the moment, the returned iterator does not support cxIteratorFlagRemoval().
universe@828 272 *
universe@828 273 * @param root the root node
universe@828 274 * @param passes the passes this iterator shall perform
universe@828 275 * @param loc_children offset in the node struct for the children linked list
universe@828 276 * @param loc_next offset in the node struct for the next pointer
universe@828 277 * @return the new tree iterator
universe@828 278 * @see cxTreeIteratorDispose()
universe@828 279 */
universe@828 280 __attribute__((__nonnull__))
universe@828 281 CxTreeIterator cx_tree_iterate(
universe@828 282 void const *root,
universe@828 283 int passes,
universe@828 284 ptrdiff_t loc_children,
universe@828 285 ptrdiff_t loc_next
universe@828 286 );
universe@828 287
universe@816 288 #ifdef __cplusplus
universe@816 289 } // extern "C"
universe@816 290 #endif
universe@816 291
universe@816 292 #endif //UCX_TREE_H

mercurial