Fri, 19 Dec 2025 17:53:18 +0100
update ucx
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
1 | /* |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
3 | * |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
4 | * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved. |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
5 | * |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
6 | * Redistribution and use in source and binary forms, with or without |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
7 | * modification, are permitted provided that the following conditions are met: |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
8 | * |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
9 | * 1. Redistributions of source code must retain the above copyright |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
10 | * notice, this list of conditions and the following disclaimer. |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
11 | * |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
12 | * 2. Redistributions in binary form must reproduce the above copyright |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
13 | * notice, this list of conditions and the following disclaimer in the |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
14 | * documentation and/or other materials provided with the distribution. |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
15 | * |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
26 | * POSSIBILITY OF SUCH DAMAGE. |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
27 | */ |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
28 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
29 | #include "cx/tree.h" |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
30 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
31 | #include <assert.h> |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
32 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
33 | #define CX_TREE_PTR(cur, off) (*(void**)(((char*)(cur))+(off))) |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
34 | #define tree_parent(node) CX_TREE_PTR(node, loc_parent) |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
35 | #define tree_children(node) CX_TREE_PTR(node, loc_children) |
| 852 | 36 | #define tree_last_child(node) CX_TREE_PTR(node, loc_last_child) |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
37 | #define tree_prev(node) CX_TREE_PTR(node, loc_prev) |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
38 | #define tree_next(node) CX_TREE_PTR(node, loc_next) |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
39 | |
| 852 | 40 | #define cx_tree_ptr_locations \ |
| 41 | loc_parent, loc_children, loc_last_child, loc_prev, loc_next | |
| 42 | ||
| 43 | #define cx_tree_node_layout(tree) \ | |
| 44 | (tree)->loc_parent,\ | |
| 45 | (tree)->loc_children,\ | |
| 46 | (tree)->loc_last_child,\ | |
| 47 | (tree)->loc_prev, \ | |
| 48 | (tree)->loc_next | |
| 49 | ||
| 50 | static void cx_tree_zero_pointers( | |
| 51 | void *node, | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
52 | ptrdiff_t loc_parent, |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
53 | ptrdiff_t loc_children, |
| 852 | 54 | ptrdiff_t loc_last_child, |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
55 | ptrdiff_t loc_prev, |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
56 | ptrdiff_t loc_next |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
57 | ) { |
| 852 | 58 | tree_parent(node) = NULL; |
| 59 | if (loc_prev >= 0) { | |
| 60 | tree_prev(node) = NULL; | |
| 61 | } | |
| 62 | tree_next(node) = NULL; | |
| 63 | tree_children(node) = NULL; | |
| 64 | if (loc_last_child >= 0) { | |
| 65 | tree_last_child(node) = NULL; | |
| 66 | } | |
| 67 | } | |
| 68 | ||
| 69 | void cx_tree_link( | |
| 70 | void *parent, | |
| 71 | void *node, | |
| 72 | ptrdiff_t loc_parent, | |
| 73 | ptrdiff_t loc_children, | |
| 74 | ptrdiff_t loc_last_child, | |
| 75 | ptrdiff_t loc_prev, | |
| 76 | ptrdiff_t loc_next | |
| 77 | ) { | |
| 78 | assert(loc_parent >= 0); | |
| 79 | assert(loc_children >= 0); | |
| 80 | assert(loc_next >= 0); | |
| 81 | ||
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
82 | void *current_parent = tree_parent(node); |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
83 | if (current_parent == parent) return; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
84 | if (current_parent != NULL) { |
| 852 | 85 | cx_tree_unlink(node, cx_tree_ptr_locations); |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
86 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
87 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
88 | if (tree_children(parent) == NULL) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
89 | tree_children(parent) = node; |
| 852 | 90 | if (loc_last_child >= 0) { |
| 91 | tree_last_child(parent) = node; | |
| 92 | } | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
93 | } else { |
| 852 | 94 | void *child; |
| 95 | if (loc_last_child >= 0) { | |
| 96 | child = tree_last_child(parent); | |
| 97 | tree_last_child(parent) = node; | |
| 98 | } else { | |
| 99 | child = tree_children(parent); | |
| 100 | void *next; | |
| 101 | while ((next = tree_next(child)) != NULL) { | |
| 102 | child = next; | |
| 103 | } | |
| 104 | } | |
| 105 | if (loc_prev >= 0) { | |
| 106 | tree_prev(node) = child; | |
| 107 | } | |
| 108 | tree_next(child) = node; | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
109 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
110 | tree_parent(node) = parent; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
111 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
112 | |
| 852 | 113 | static void *cx_tree_node_prev( |
| 114 | ptrdiff_t loc_parent, | |
| 115 | ptrdiff_t loc_children, | |
| 116 | ptrdiff_t loc_next, | |
| 117 | const void *node | |
| 118 | ) { | |
| 119 | void *parent = tree_parent(node); | |
| 120 | void *begin = tree_children(parent); | |
| 121 | if (begin == node) return NULL; | |
| 122 | const void *cur = begin; | |
| 123 | const void *next; | |
| 124 | while (1) { | |
| 125 | next = tree_next(cur); | |
| 126 | if (next == node) return (void *) cur; | |
| 127 | cur = next; | |
| 128 | } | |
| 129 | } | |
| 130 | ||
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
131 | void cx_tree_unlink( |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
132 | void *node, |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
133 | ptrdiff_t loc_parent, |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
134 | ptrdiff_t loc_children, |
| 852 | 135 | ptrdiff_t loc_last_child, |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
136 | ptrdiff_t loc_prev, |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
137 | ptrdiff_t loc_next |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
138 | ) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
139 | if (tree_parent(node) == NULL) return; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
140 | |
| 852 | 141 | assert(loc_children >= 0); |
| 142 | assert(loc_next >= 0); | |
| 143 | assert(loc_parent >= 0); | |
| 144 | void *left; | |
| 145 | if (loc_prev >= 0) { | |
| 146 | left = tree_prev(node); | |
| 147 | } else { | |
| 148 | left = cx_tree_node_prev(loc_parent, loc_children, loc_next, node); | |
| 149 | } | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
150 | void *right = tree_next(node); |
| 852 | 151 | void *parent = tree_parent(node); |
| 152 | assert(left == NULL || tree_children(parent) != node); | |
| 153 | assert(right == NULL || loc_last_child < 0 || | |
| 154 | tree_last_child(parent) != node); | |
| 155 | ||
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
156 | if (left == NULL) { |
| 852 | 157 | tree_children(parent) = right; |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
158 | } else { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
159 | tree_next(left) = right; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
160 | } |
| 852 | 161 | if (right == NULL) { |
| 162 | if (loc_last_child >= 0) { | |
| 163 | tree_last_child(parent) = left; | |
| 164 | } | |
| 165 | } else { | |
| 166 | if (loc_prev >= 0) { | |
| 167 | tree_prev(right) = left; | |
| 168 | } | |
| 169 | } | |
| 170 | ||
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
171 | tree_parent(node) = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
172 | tree_next(node) = NULL; |
| 852 | 173 | if (loc_prev >= 0) { |
| 174 | tree_prev(node) = NULL; | |
| 175 | } | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
176 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
177 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
178 | int cx_tree_search( |
| 852 | 179 | const void *root, |
| 180 | size_t depth, | |
| 181 | const void *node, | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
182 | cx_tree_search_func sfunc, |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
183 | void **result, |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
184 | ptrdiff_t loc_children, |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
185 | ptrdiff_t loc_next |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
186 | ) { |
| 852 | 187 | // help avoiding bugs due to uninitialized memory |
| 188 | assert(result != NULL); | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
189 | *result = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
190 | |
| 852 | 191 | // remember return value for best match |
| 192 | int ret = sfunc(root, node); | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
193 | if (ret < 0) { |
| 852 | 194 | // not contained, exit |
| 195 | return -1; | |
| 196 | } | |
| 197 | *result = (void*) root; | |
| 198 | // if root is already exact match, exit | |
| 199 | if (ret == 0) { | |
| 200 | return 0; | |
| 201 | } | |
| 202 | ||
| 203 | // when depth is one, we are already done | |
| 204 | if (depth == 1) { | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
205 | return ret; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
206 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
207 | |
| 852 | 208 | // special case: indefinite depth |
| 209 | if (depth == 0) { | |
| 210 | depth = SIZE_MAX; | |
| 211 | } | |
| 212 | ||
| 213 | // create an iterator | |
| 214 | CxTreeIterator iter = cx_tree_iterator( | |
| 215 | (void*) root, false, loc_children, loc_next | |
| 216 | ); | |
| 217 | ||
| 218 | // skip root, we already handled it | |
| 219 | cxIteratorNext(iter); | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
220 | |
| 852 | 221 | // loop through the remaining tree |
| 222 | cx_foreach(void *, elem, iter) { | |
| 223 | // investigate the current node | |
| 224 | int ret_elem = sfunc(elem, node); | |
| 225 | if (ret_elem == 0) { | |
| 226 | // if found, exit the search | |
| 886 | 227 | *result = elem; |
| 852 | 228 | ret = 0; |
| 229 | break; | |
| 230 | } else if (ret_elem > 0 && ret_elem < ret) { | |
| 231 | // new distance is better | |
| 232 | *result = elem; | |
| 233 | ret = ret_elem; | |
| 886 | 234 | } else if (ret_elem < 0 || ret_elem > ret) { |
| 852 | 235 | // not contained or distance is worse, skip entire subtree |
| 236 | cxTreeIteratorContinue(iter); | |
| 237 | } | |
| 238 | ||
| 239 | // when we reached the max depth, skip the subtree | |
| 240 | if (iter.depth == depth) { | |
| 241 | cxTreeIteratorContinue(iter); | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
242 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
243 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
244 | |
| 852 | 245 | // dispose the iterator as we might have exited the loop early |
| 246 | cxTreeIteratorDispose(&iter); | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
247 | |
| 852 | 248 | assert(ret < 0 || *result != NULL); |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
249 | return ret; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
250 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
251 | |
| 852 | 252 | int cx_tree_search_data( |
| 253 | const void *root, | |
| 254 | size_t depth, | |
| 255 | const void *data, | |
| 256 | cx_tree_search_data_func sfunc, | |
| 257 | void **result, | |
| 258 | ptrdiff_t loc_children, | |
| 259 | ptrdiff_t loc_next | |
| 260 | ) { | |
| 261 | // it is basically the same implementation | |
| 262 | return cx_tree_search( | |
| 263 | root, depth, data, | |
| 264 | (cx_tree_search_func) sfunc, | |
| 265 | result, | |
| 266 | loc_children, loc_next); | |
| 267 | } | |
| 268 | ||
| 269 | static bool cx_tree_iter_valid(const void *it) { | |
| 270 | const struct cx_tree_iterator_s *iter = it; | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
271 | return iter->node != NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
272 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
273 | |
| 852 | 274 | static void *cx_tree_iter_current(const void *it) { |
| 275 | const struct cx_tree_iterator_s *iter = it; | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
276 | return iter->node; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
277 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
278 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
279 | static void cx_tree_iter_next(void *it) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
280 | struct cx_tree_iterator_s *iter = it; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
281 | ptrdiff_t const loc_next = iter->loc_next; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
282 | ptrdiff_t const loc_children = iter->loc_children; |
| 852 | 283 | // protect us from misuse |
| 284 | if (!iter->base.valid(iter)) return; | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
285 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
286 | void *children; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
287 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
288 | // check if we are currently exiting or entering nodes |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
289 | if (iter->exiting) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
290 | children = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
291 | // skipping on exit is pointless, just clear the flag |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
292 | iter->skip = false; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
293 | } else { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
294 | if (iter->skip) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
295 | // skip flag is set, pretend that there are no children |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
296 | iter->skip = false; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
297 | children = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
298 | } else { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
299 | // try to enter the children (if any) |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
300 | children = tree_children(iter->node); |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
301 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
302 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
303 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
304 | if (children == NULL) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
305 | // search for the next node |
| 886 | 306 | void *next = NULL; |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
307 | cx_tree_iter_search_next: |
| 886 | 308 | // check if there is a sibling, but only if we are not a (subtree-)root |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
309 | if (iter->exiting) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
310 | next = iter->node_next; |
| 886 | 311 | } else if (iter->depth > 1) { |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
312 | next = tree_next(iter->node); |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
313 | iter->node_next = next; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
314 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
315 | if (next == NULL) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
316 | // no sibling, we are done with this node and exit |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
317 | if (iter->visit_on_exit && !iter->exiting) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
318 | // iter is supposed to visit the node again |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
319 | iter->exiting = true; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
320 | } else { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
321 | iter->exiting = false; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
322 | if (iter->depth == 1) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
323 | // there is no parent - we have iterated the entire tree |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
324 | // invalidate the iterator and free the node stack |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
325 | iter->node = iter->node_next = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
326 | iter->stack_capacity = iter->depth = 0; |
| 886 | 327 | cxFreeDefault(iter->stack); |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
328 | iter->stack = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
329 | } else { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
330 | // the parent node can be obtained from the top of stack |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
331 | // this way we can avoid the loc_parent in the iterator |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
332 | iter->depth--; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
333 | iter->node = iter->stack[iter->depth - 1]; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
334 | // retry with the parent node to find a sibling |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
335 | goto cx_tree_iter_search_next; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
336 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
337 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
338 | } else { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
339 | if (iter->visit_on_exit && !iter->exiting) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
340 | // iter is supposed to visit the node again |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
341 | iter->exiting = true; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
342 | } else { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
343 | iter->exiting = false; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
344 | // move to the sibling |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
345 | iter->counter++; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
346 | iter->node = next; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
347 | // new top of stack is the sibling |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
348 | iter->stack[iter->depth - 1] = next; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
349 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
350 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
351 | } else { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
352 | // node has children, push the first child onto the stack and enter it |
| 891 | 353 | if (iter->stack_size >= iter->stack_capacity) { |
| 354 | const size_t newcap = iter->stack_capacity + 8; | |
| 355 | if (cxReallocArrayDefault(&iter->stack, newcap, sizeof(void*))) { | |
| 356 | // we cannot return an error in this function | |
| 357 | abort(); // LCOV_EXCL_LINE | |
| 358 | } | |
| 359 | iter->stack_capacity = newcap; | |
| 360 | } | |
| 361 | iter->stack[iter->stack_size] = children; | |
| 362 | iter->stack_size++; | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
363 | iter->node = children; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
364 | iter->counter++; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
365 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
366 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
367 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
368 | CxTreeIterator cx_tree_iterator( |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
369 | void *root, |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
370 | bool visit_on_exit, |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
371 | ptrdiff_t loc_children, |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
372 | ptrdiff_t loc_next |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
373 | ) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
374 | CxTreeIterator iter; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
375 | iter.loc_children = loc_children; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
376 | iter.loc_next = loc_next; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
377 | iter.visit_on_exit = visit_on_exit; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
378 | |
| 852 | 379 | // initialize members |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
380 | iter.node_next = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
381 | iter.exiting = false; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
382 | iter.skip = false; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
383 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
384 | // assign base iterator functions |
| 889 | 385 | iter.base.allow_remove = false; |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
386 | iter.base.remove = false; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
387 | iter.base.current_impl = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
388 | iter.base.valid = cx_tree_iter_valid; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
389 | iter.base.next = cx_tree_iter_next; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
390 | iter.base.current = cx_tree_iter_current; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
391 | |
| 852 | 392 | // visit the root node |
| 393 | iter.node = root; | |
| 394 | if (root != NULL) { | |
| 395 | iter.stack_capacity = 16; | |
| 886 | 396 | iter.stack = cxMallocDefault(sizeof(void *) * 16); |
| 852 | 397 | iter.stack[0] = root; |
| 398 | iter.counter = 1; | |
| 399 | iter.depth = 1; | |
| 400 | } else { | |
| 401 | iter.stack_capacity = 0; | |
| 402 | iter.stack = NULL; | |
| 403 | iter.counter = 0; | |
| 404 | iter.depth = 0; | |
| 405 | } | |
| 406 | ||
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
407 | return iter; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
408 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
409 | |
| 852 | 410 | static bool cx_tree_visitor_valid(const void *it) { |
| 411 | const struct cx_tree_visitor_s *iter = it; | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
412 | return iter->node != NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
413 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
414 | |
| 852 | 415 | static void *cx_tree_visitor_current(const void *it) { |
| 416 | const struct cx_tree_visitor_s *iter = it; | |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
417 | return iter->node; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
418 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
419 | |
| 852 | 420 | cx_attr_nonnull |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
421 | static void cx_tree_visitor_enqueue_siblings( |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
422 | struct cx_tree_visitor_s *iter, void *node, ptrdiff_t loc_next) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
423 | node = tree_next(node); |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
424 | while (node != NULL) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
425 | struct cx_tree_visitor_queue_s *q; |
| 886 | 426 | q = cxMallocDefault(sizeof(struct cx_tree_visitor_queue_s)); |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
427 | q->depth = iter->queue_last->depth; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
428 | q->node = node; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
429 | iter->queue_last->next = q; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
430 | iter->queue_last = q; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
431 | node = tree_next(node); |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
432 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
433 | iter->queue_last->next = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
434 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
435 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
436 | static void cx_tree_visitor_next(void *it) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
437 | struct cx_tree_visitor_s *iter = it; |
| 852 | 438 | // protect us from misuse |
| 439 | if (!iter->base.valid(iter)) return; | |
| 440 | ||
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
441 | ptrdiff_t const loc_next = iter->loc_next; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
442 | ptrdiff_t const loc_children = iter->loc_children; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
443 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
444 | // add the children of the current node to the queue |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
445 | // unless the skip flag is set |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
446 | void *children; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
447 | if (iter->skip) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
448 | iter->skip = false; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
449 | children = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
450 | } else { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
451 | children = tree_children(iter->node); |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
452 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
453 | if (children != NULL) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
454 | struct cx_tree_visitor_queue_s *q; |
| 886 | 455 | q = cxMallocDefault(sizeof(struct cx_tree_visitor_queue_s)); |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
456 | q->depth = iter->depth + 1; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
457 | q->node = children; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
458 | if (iter->queue_last == NULL) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
459 | assert(iter->queue_next == NULL); |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
460 | iter->queue_next = q; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
461 | } else { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
462 | iter->queue_last->next = q; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
463 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
464 | iter->queue_last = q; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
465 | cx_tree_visitor_enqueue_siblings(iter, children, loc_next); |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
466 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
467 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
468 | // check if there is a next node |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
469 | if (iter->queue_next == NULL) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
470 | iter->node = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
471 | return; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
472 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
473 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
474 | // dequeue the next node |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
475 | iter->node = iter->queue_next->node; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
476 | iter->depth = iter->queue_next->depth; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
477 | { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
478 | struct cx_tree_visitor_queue_s *q = iter->queue_next; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
479 | iter->queue_next = q->next; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
480 | if (iter->queue_next == NULL) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
481 | assert(iter->queue_last == q); |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
482 | iter->queue_last = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
483 | } |
| 886 | 484 | cxFreeDefault(q); |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
485 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
486 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
487 | // increment the node counter |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
488 | iter->counter++; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
489 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
490 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
491 | CxTreeVisitor cx_tree_visitor( |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
492 | void *root, |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
493 | ptrdiff_t loc_children, |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
494 | ptrdiff_t loc_next |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
495 | ) { |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
496 | CxTreeVisitor iter; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
497 | iter.loc_children = loc_children; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
498 | iter.loc_next = loc_next; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
499 | |
| 852 | 500 | // initialize members |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
501 | iter.skip = false; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
502 | iter.queue_next = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
503 | iter.queue_last = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
504 | |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
505 | // assign base iterator functions |
| 889 | 506 | iter.base.allow_remove = false; |
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
507 | iter.base.remove = false; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
508 | iter.base.current_impl = NULL; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
509 | iter.base.valid = cx_tree_visitor_valid; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
510 | iter.base.next = cx_tree_visitor_next; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
511 | iter.base.current = cx_tree_visitor_current; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
512 | |
| 852 | 513 | // visit the root node |
| 514 | iter.node = root; | |
| 515 | if (root != NULL) { | |
| 516 | iter.counter = 1; | |
| 517 | iter.depth = 1; | |
| 518 | } else { | |
| 519 | iter.counter = 0; | |
| 520 | iter.depth = 0; | |
| 521 | } | |
| 522 | ||
|
816
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
523 | return iter; |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
524 | } |
|
839fefbdedc7
compatibility with UCX 3.1 plus several minor code fixes
Mike Becker <universe@uap-core.de>
parents:
diff
changeset
|
525 | |
| 852 | 526 | static void cx_tree_add_link_duplicate( |
| 527 | void *original, void *duplicate, | |
| 528 | ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, | |
| 529 | ptrdiff_t loc_prev, ptrdiff_t loc_next | |
| 530 | ) { | |
| 531 | void *shared_parent = tree_parent(original); | |
| 532 | if (shared_parent == NULL) { | |
| 533 | cx_tree_link(original, duplicate, cx_tree_ptr_locations); | |
| 534 | } else { | |
| 535 | cx_tree_link(shared_parent, duplicate, cx_tree_ptr_locations); | |
| 536 | } | |
| 537 | } | |
| 538 | ||
| 539 | static void cx_tree_add_link_new( | |
| 540 | void *parent, void *node, cx_tree_search_func sfunc, | |
| 541 | ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, | |
| 542 | ptrdiff_t loc_prev, ptrdiff_t loc_next | |
| 543 | ) { | |
| 544 | // check the current children one by one, | |
| 545 | // if they could be children of the new node | |
| 546 | void *child = tree_children(parent); | |
| 547 | while (child != NULL) { | |
| 548 | void *next = tree_next(child); | |
| 549 | ||
| 550 | if (sfunc(node, child) > 0) { | |
| 551 | // the sibling could be a child -> re-link | |
| 552 | cx_tree_link(node, child, cx_tree_ptr_locations); | |
| 553 | } | |
| 554 | ||
| 555 | child = next; | |
| 556 | } | |
| 557 | ||
| 558 | // add new node as new child | |
| 559 | cx_tree_link(parent, node, cx_tree_ptr_locations); | |
| 560 | } | |
| 561 | ||
| 562 | int cx_tree_add( | |
| 563 | const void *src, | |
| 564 | cx_tree_search_func sfunc, | |
| 565 | cx_tree_node_create_func cfunc, | |
| 566 | void *cdata, | |
| 567 | void **cnode, | |
| 568 | void *root, | |
| 569 | ptrdiff_t loc_parent, | |
| 570 | ptrdiff_t loc_children, | |
| 571 | ptrdiff_t loc_last_child, | |
| 572 | ptrdiff_t loc_prev, | |
| 573 | ptrdiff_t loc_next | |
| 574 | ) { | |
| 575 | *cnode = cfunc(src, cdata); | |
| 891 | 576 | if (*cnode == NULL) return 1; // LCOV_EXCL_LINE |
| 852 | 577 | cx_tree_zero_pointers(*cnode, cx_tree_ptr_locations); |
| 578 | ||
| 579 | void *match = NULL; | |
| 580 | int result = cx_tree_search( | |
| 581 | root, | |
| 582 | 0, | |
| 583 | *cnode, | |
| 584 | sfunc, | |
| 585 | &match, | |
| 586 | loc_children, | |
| 587 | loc_next | |
| 588 | ); | |
| 589 | ||
| 590 | if (result < 0) { | |
| 591 | // node does not fit into the tree - return non-zero value | |
| 592 | return 1; | |
| 593 | } else if (result == 0) { | |
| 594 | // data already found in the tree, link duplicate | |
| 595 | cx_tree_add_link_duplicate(match, *cnode, cx_tree_ptr_locations); | |
| 596 | } else { | |
| 597 | // closest match found, add new node | |
| 598 | cx_tree_add_link_new(match, *cnode, sfunc, cx_tree_ptr_locations); | |
| 599 | } | |
| 600 | ||
| 601 | return 0; | |
| 602 | } | |
| 603 | ||
| 604 | unsigned int cx_tree_add_look_around_depth = 3; | |
| 605 | ||
| 606 | size_t cx_tree_add_iter( | |
| 607 | struct cx_iterator_base_s *iter, | |
| 608 | size_t num, | |
| 609 | cx_tree_search_func sfunc, | |
| 610 | cx_tree_node_create_func cfunc, | |
| 611 | void *cdata, | |
| 612 | void **failed, | |
| 613 | void *root, | |
| 614 | ptrdiff_t loc_parent, | |
| 615 | ptrdiff_t loc_children, | |
| 616 | ptrdiff_t loc_last_child, | |
| 617 | ptrdiff_t loc_prev, | |
| 618 | ptrdiff_t loc_next | |
| 619 | ) { | |
| 620 | // erase the failed pointer | |
| 621 | *failed = NULL; | |
| 622 | ||
| 623 | // iter not valid? cancel... | |
| 624 | if (!iter->valid(iter)) return 0; | |
| 625 | ||
| 626 | size_t processed = 0; | |
| 627 | void *current_node = root; | |
| 628 | const void *elem; | |
| 629 | ||
| 630 | for (void **eptr; processed < num && | |
| 631 | iter->valid(iter) && (eptr = iter->current(iter)) != NULL; | |
| 632 | iter->next(iter)) { | |
| 633 | elem = *eptr; | |
| 634 | ||
| 635 | // create the new node | |
| 636 | void *new_node = cfunc(elem, cdata); | |
| 891 | 637 | if (new_node == NULL) return processed; // LCOV_EXCL_LINE |
| 852 | 638 | cx_tree_zero_pointers(new_node, cx_tree_ptr_locations); |
| 639 | ||
| 640 | // start searching from current node | |
| 641 | void *match; | |
| 642 | int result; | |
| 643 | unsigned int look_around_retries = cx_tree_add_look_around_depth; | |
| 644 | cx_tree_add_look_around_retry: | |
| 645 | result = cx_tree_search( | |
| 646 | current_node, | |
| 647 | 0, | |
| 648 | new_node, | |
| 649 | sfunc, | |
| 650 | &match, | |
| 651 | loc_children, | |
| 652 | loc_next | |
| 653 | ); | |
| 654 | ||
| 655 | if (result < 0) { | |
| 656 | // traverse upwards and try to find better parents | |
| 657 | void *parent = tree_parent(current_node); | |
| 658 | if (parent != NULL) { | |
| 659 | if (look_around_retries > 0) { | |
| 660 | look_around_retries--; | |
| 661 | current_node = parent; | |
| 662 | } else { | |
| 663 | // look around retries exhausted, start from the root | |
| 664 | current_node = root; | |
| 665 | } | |
| 666 | goto cx_tree_add_look_around_retry; | |
| 667 | } else { | |
| 668 | // no parents. so we failed | |
| 669 | *failed = new_node; | |
| 670 | return processed; | |
| 671 | } | |
| 672 | } else if (result == 0) { | |
| 673 | // data already found in the tree, link duplicate | |
| 674 | cx_tree_add_link_duplicate(match, new_node, cx_tree_ptr_locations); | |
| 675 | // but stick with the original match, in case we needed a new root | |
| 676 | current_node = match; | |
| 677 | } else { | |
| 678 | // closest match found, add new node as child | |
| 679 | cx_tree_add_link_new(match, new_node, sfunc, | |
| 680 | cx_tree_ptr_locations); | |
| 681 | current_node = match; | |
| 682 | } | |
| 683 | ||
| 684 | processed++; | |
| 685 | } | |
| 686 | return processed; | |
| 687 | } | |
| 688 | ||
| 689 | size_t cx_tree_add_array( | |
| 690 | const void *src, | |
| 691 | size_t num, | |
| 692 | size_t elem_size, | |
| 693 | cx_tree_search_func sfunc, | |
| 694 | cx_tree_node_create_func cfunc, | |
| 695 | void *cdata, | |
| 696 | void **failed, | |
| 697 | void *root, | |
| 698 | ptrdiff_t loc_parent, | |
| 699 | ptrdiff_t loc_children, | |
| 700 | ptrdiff_t loc_last_child, | |
| 701 | ptrdiff_t loc_prev, | |
| 702 | ptrdiff_t loc_next | |
| 703 | ) { | |
| 704 | // erase failed pointer | |
| 705 | *failed = NULL; | |
| 706 | ||
| 707 | // super special case: zero elements | |
| 708 | if (num == 0) { | |
| 709 | return 0; | |
| 710 | } | |
| 711 | ||
| 712 | // special case: one element does not need an iterator | |
| 713 | if (num == 1) { | |
| 714 | void *node; | |
| 715 | if (0 == cx_tree_add( | |
| 716 | src, sfunc, cfunc, cdata, &node, root, | |
| 717 | loc_parent, loc_children, loc_last_child, | |
| 718 | loc_prev, loc_next)) { | |
| 719 | return 1; | |
| 720 | } else { | |
| 721 | *failed = node; | |
| 722 | return 0; | |
| 723 | } | |
| 724 | } | |
| 725 | ||
| 726 | // otherwise, create iterator and hand over to other function | |
| 891 | 727 | CxIterator iter = cxIterator(src, elem_size, num); |
| 852 | 728 | return cx_tree_add_iter(cxIteratorRef(iter), num, sfunc, |
| 729 | cfunc, cdata, failed, root, | |
| 730 | loc_parent, loc_children, loc_last_child, | |
| 731 | loc_prev, loc_next); | |
| 732 | } | |
| 733 | ||
| 734 | static int cx_tree_default_insert_element( | |
| 735 | CxTree *tree, | |
| 736 | const void *data | |
| 737 | ) { | |
| 738 | void *node; | |
| 739 | if (tree->root == NULL) { | |
| 740 | node = tree->node_create(data, tree); | |
| 891 | 741 | if (node == NULL) return 1; // LCOV_EXCL_LINE |
| 852 | 742 | cx_tree_zero_pointers(node, cx_tree_node_layout(tree)); |
| 743 | tree->root = node; | |
| 891 | 744 | tree->collection.size = 1; |
| 852 | 745 | return 0; |
| 746 | } | |
| 747 | int result = cx_tree_add(data, tree->search, tree->node_create, | |
| 748 | tree, &node, tree->root, cx_tree_node_layout(tree)); | |
| 749 | if (0 == result) { | |
| 891 | 750 | tree->collection.size++; |
| 852 | 751 | } else { |
| 891 | 752 | cxFree(tree->collection.allocator, node); |
| 852 | 753 | } |
| 754 | return result; | |
| 755 | } | |
| 756 | ||
| 757 | static size_t cx_tree_default_insert_many( | |
| 758 | CxTree *tree, | |
|
854
1c8401ece69e
update ucx to version 3.1
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
852
diff
changeset
|
759 | CxIteratorBase *iter, |
| 852 | 760 | size_t n |
| 761 | ) { | |
| 762 | size_t ins = 0; | |
| 763 | if (!iter->valid(iter)) return 0; | |
| 764 | if (tree->root == NULL) { | |
| 765 | // use the first element from the iter to create the root node | |
| 766 | void **eptr = iter->current(iter); | |
| 767 | void *node = tree->node_create(*eptr, tree); | |
| 891 | 768 | if (node == NULL) return 0; // LCOV_EXCL_LINE |
| 852 | 769 | cx_tree_zero_pointers(node, cx_tree_node_layout(tree)); |
| 770 | tree->root = node; | |
| 771 | ins = 1; | |
| 772 | iter->next(iter); | |
| 773 | } | |
| 774 | void *failed; | |
| 775 | ins += cx_tree_add_iter(iter, n, tree->search, tree->node_create, | |
| 776 | tree, &failed, tree->root, cx_tree_node_layout(tree)); | |
| 891 | 777 | tree->collection.size += ins; |
| 852 | 778 | if (ins < n) { |
| 891 | 779 | cxFree(tree->collection.allocator, failed); |
| 852 | 780 | } |
| 781 | return ins; | |
| 782 | } | |
| 783 | ||
| 784 | static void *cx_tree_default_find( | |
| 785 | CxTree *tree, | |
| 786 | const void *subtree, | |
| 787 | const void *data, | |
| 788 | size_t depth | |
| 789 | ) { | |
| 891 | 790 | if (tree->root == NULL) return NULL; // LCOV_EXCL_LINE |
| 852 | 791 | |
| 792 | void *found; | |
| 793 | if (0 == cx_tree_search_data( | |
| 794 | subtree, | |
| 795 | depth, | |
| 796 | data, | |
| 797 | tree->search_data, | |
| 798 | &found, | |
| 799 | tree->loc_children, | |
| 800 | tree->loc_next | |
| 801 | )) { | |
| 802 | return found; | |
| 803 | } else { | |
| 804 | return NULL; | |
| 805 | } | |
| 806 | } | |
| 807 | ||
| 808 | static cx_tree_class cx_tree_default_class = { | |
| 809 | cx_tree_default_insert_element, | |
| 810 | cx_tree_default_insert_many, | |
| 811 | cx_tree_default_find | |
| 812 | }; | |
| 813 | ||
| 889 | 814 | CxTree *cxTreeCreate(const CxAllocator *allocator, |
| 852 | 815 | cx_tree_node_create_func create_func, |
| 816 | cx_tree_search_func search_func, | |
| 817 | cx_tree_search_data_func search_data_func, | |
| 889 | 818 | ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, |
| 819 | ptrdiff_t loc_prev, ptrdiff_t loc_next | |
| 852 | 820 | ) { |
| 821 | if (allocator == NULL) { | |
| 822 | allocator = cxDefaultAllocator; | |
| 823 | } | |
| 824 | assert(create_func != NULL); | |
| 825 | assert(search_func != NULL); | |
| 826 | assert(search_data_func != NULL); | |
| 827 | ||
| 891 | 828 | CxTree *tree = cxZalloc(allocator, sizeof(CxTree)); |
| 829 | if (tree == NULL) return NULL; // LCOV_EXCL_LINE | |
| 852 | 830 | |
| 831 | tree->cl = &cx_tree_default_class; | |
| 891 | 832 | tree->collection.allocator = allocator; |
| 852 | 833 | tree->node_create = create_func; |
| 834 | tree->search = search_func; | |
| 835 | tree->search_data = search_data_func; | |
| 891 | 836 | tree->collection.advanced_destructor = (cx_destructor_func2) cxFree; |
| 837 | tree->collection.destructor_data = (void *) allocator; | |
| 852 | 838 | tree->loc_parent = loc_parent; |
| 839 | tree->loc_children = loc_children; | |
| 840 | tree->loc_last_child = loc_last_child; | |
| 841 | tree->loc_prev = loc_prev; | |
| 842 | tree->loc_next = loc_next; | |
| 843 | ||
| 844 | return tree; | |
| 845 | } | |
| 846 | ||
| 847 | void cxTreeFree(CxTree *tree) { | |
| 848 | if (tree == NULL) return; | |
| 849 | if (tree->root != NULL) { | |
| 850 | cxTreeClear(tree); | |
| 851 | } | |
| 891 | 852 | cxFree(tree->collection.allocator, tree); |
| 852 | 853 | } |
| 854 | ||
| 889 | 855 | CxTree *cxTreeCreateWrapped(const CxAllocator *allocator, void *root, |
| 856 | ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child, | |
| 857 | ptrdiff_t loc_prev, ptrdiff_t loc_next) { | |
| 852 | 858 | if (allocator == NULL) { |
| 859 | allocator = cxDefaultAllocator; | |
| 860 | } | |
| 861 | assert(root != NULL); | |
| 862 | ||
| 891 | 863 | CxTree *tree = cxZalloc(allocator, sizeof(CxTree)); |
| 864 | if (tree == NULL) return NULL; // LCOV_EXCL_LINE | |
| 852 | 865 | |
| 866 | tree->cl = &cx_tree_default_class; | |
| 867 | // set the allocator anyway, just in case... | |
| 891 | 868 | tree->collection.allocator = allocator; |
| 852 | 869 | tree->loc_parent = loc_parent; |
| 870 | tree->loc_children = loc_children; | |
| 871 | tree->loc_last_child = loc_last_child; | |
| 872 | tree->loc_prev = loc_prev; | |
| 873 | tree->loc_next = loc_next; | |
| 874 | tree->root = root; | |
| 891 | 875 | tree->collection.size = cxTreeSubtreeSize(tree, root); |
| 852 | 876 | return tree; |
| 877 | } | |
| 878 | ||
| 889 | 879 | void cxTreeSetParent(CxTree *tree, void *parent, void *child) { |
| 852 | 880 | size_t loc_parent = tree->loc_parent; |
| 881 | if (tree_parent(child) == NULL) { | |
| 891 | 882 | tree->collection.size++; |
| 852 | 883 | } |
| 884 | cx_tree_link(parent, child, cx_tree_node_layout(tree)); | |
| 885 | } | |
| 886 | ||
| 889 | 887 | void cxTreeAddChildNode(CxTree *tree, void *parent, void *child) { |
| 852 | 888 | cx_tree_link(parent, child, cx_tree_node_layout(tree)); |
| 891 | 889 | tree->collection.size++; |
| 852 | 890 | } |
| 891 | ||
| 889 | 892 | int cxTreeAddChild(CxTree *tree, void *parent, const void *data) { |
| 852 | 893 | void *node = tree->node_create(data, tree); |
| 891 | 894 | if (node == NULL) return 1; // LCOV_EXCL_LINE |
| 852 | 895 | cx_tree_zero_pointers(node, cx_tree_node_layout(tree)); |
| 896 | cx_tree_link(parent, node, cx_tree_node_layout(tree)); | |
| 891 | 897 | tree->collection.size++; |
| 852 | 898 | return 0; |
| 899 | } | |
| 900 | ||
| 889 | 901 | int cxTreeInsert(CxTree *tree, const void *data) { |
| 902 | return tree->cl->insert_element(tree, data); | |
| 903 | } | |
| 904 | ||
| 905 | size_t cxTreeInsertIter(CxTree *tree, CxIteratorBase *iter, size_t n) { | |
| 906 | return tree->cl->insert_many(tree, iter, n); | |
| 907 | } | |
| 908 | ||
| 909 | size_t cxTreeInsertArray(CxTree *tree, const void *data, size_t elem_size, size_t n) { | |
| 910 | if (n == 0) return 0; | |
| 911 | if (n == 1) return 0 == cxTreeInsert(tree, data) ? 1 : 0; | |
| 891 | 912 | CxIterator iter = cxIterator(data, elem_size, n); |
| 889 | 913 | return cxTreeInsertIter(tree, cxIteratorRef(iter), n); |
| 914 | } | |
| 915 | ||
| 916 | void *cxTreeFind( CxTree *tree, const void *data) { | |
| 917 | return tree->cl->find(tree, tree->root, data, 0); | |
| 918 | } | |
| 919 | ||
| 920 | void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root, size_t max_depth) { | |
| 921 | return tree->cl->find(tree, subtree_root, data, max_depth); | |
| 922 | } | |
| 923 | ||
| 852 | 924 | size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root) { |
| 925 | CxTreeVisitor visitor = cx_tree_visitor( | |
| 926 | subtree_root, | |
| 927 | tree->loc_children, | |
| 928 | tree->loc_next | |
| 929 | ); | |
| 930 | while (cxIteratorValid(visitor)) { | |
| 931 | cxIteratorNext(visitor); | |
| 932 | } | |
| 933 | return visitor.counter; | |
| 934 | } | |
| 935 | ||
| 936 | size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root) { | |
| 937 | CxTreeVisitor visitor = cx_tree_visitor( | |
| 938 | subtree_root, | |
| 939 | tree->loc_children, | |
| 940 | tree->loc_next | |
| 941 | ); | |
| 942 | while (cxIteratorValid(visitor)) { | |
| 943 | cxIteratorNext(visitor); | |
| 944 | } | |
| 945 | return visitor.depth; | |
| 946 | } | |
| 947 | ||
| 889 | 948 | size_t cxTreeSize(CxTree *tree) { |
| 891 | 949 | return tree->collection.size; |
| 889 | 950 | } |
| 951 | ||
| 852 | 952 | size_t cxTreeDepth(CxTree *tree) { |
| 953 | CxTreeVisitor visitor = cx_tree_visitor( | |
| 954 | tree->root, tree->loc_children, tree->loc_next | |
| 955 | ); | |
| 956 | while (cxIteratorValid(visitor)) { | |
| 957 | cxIteratorNext(visitor); | |
| 958 | } | |
| 959 | return visitor.depth; | |
| 960 | } | |
| 961 | ||
| 962 | int cxTreeRemoveNode( | |
| 963 | CxTree *tree, | |
| 964 | void *node, | |
| 965 | cx_tree_relink_func relink_func | |
| 966 | ) { | |
| 967 | if (node == tree->root) return 1; | |
| 968 | ||
| 969 | // determine the new parent | |
| 970 | ptrdiff_t loc_parent = tree->loc_parent; | |
| 971 | void *new_parent = tree_parent(node); | |
| 972 | ||
| 973 | // first, unlink from the parent | |
| 974 | cx_tree_unlink(node, cx_tree_node_layout(tree)); | |
| 975 | ||
| 976 | // then relink each child | |
| 977 | ptrdiff_t loc_children = tree->loc_children; | |
| 978 | ptrdiff_t loc_next = tree->loc_next; | |
| 979 | void *child = tree_children(node); | |
| 980 | while (child != NULL) { | |
| 981 | // forcibly set the parent to NULL - we do not use the unlink function | |
| 982 | // because that would unnecessarily modify the children linked list | |
| 983 | tree_parent(child) = NULL; | |
| 984 | ||
| 985 | // update contents, if required | |
| 986 | if (relink_func != NULL) { | |
| 987 | relink_func(child, node, new_parent); | |
| 988 | } | |
| 989 | ||
| 990 | // link to new parent | |
| 991 | cx_tree_link(new_parent, child, cx_tree_node_layout(tree)); | |
| 992 | ||
| 993 | // proceed to next child | |
| 994 | child = tree_next(child); | |
| 995 | } | |
| 996 | ||
| 997 | // clear the linked list of the removed node | |
| 998 | tree_children(node) = NULL; | |
| 999 | ptrdiff_t loc_last_child = tree->loc_last_child; | |
| 1000 | if (loc_last_child >= 0) tree_last_child(node) = NULL; | |
| 1001 | ||
| 1002 | // the tree now has one member less | |
| 891 | 1003 | tree->collection.size--; |
| 852 | 1004 | |
| 1005 | return 0; | |
| 1006 | } | |
| 1007 | ||
| 1008 | void cxTreeRemoveSubtree(CxTree *tree, void *node) { | |
| 1009 | if (node == tree->root) { | |
| 1010 | tree->root = NULL; | |
| 891 | 1011 | tree->collection.size = 0; |
| 852 | 1012 | return; |
| 1013 | } | |
| 1014 | size_t subtree_size = cxTreeSubtreeSize(tree, node); | |
| 1015 | cx_tree_unlink(node, cx_tree_node_layout(tree)); | |
| 891 | 1016 | tree->collection.size -= subtree_size; |
| 852 | 1017 | } |
| 1018 | ||
| 1019 | int cxTreeDestroyNode( | |
| 1020 | CxTree *tree, | |
| 1021 | void *node, | |
| 1022 | cx_tree_relink_func relink_func | |
| 1023 | ) { | |
| 1024 | int result = cxTreeRemoveNode(tree, node, relink_func); | |
| 1025 | if (result == 0) { | |
| 891 | 1026 | cx_invoke_destructor(tree, node); |
| 852 | 1027 | return 0; |
| 1028 | } else { | |
| 1029 | return result; | |
| 1030 | } | |
| 1031 | } | |
| 1032 | ||
| 1033 | void cxTreeDestroySubtree(CxTree *tree, void *node) { | |
| 1034 | cx_tree_unlink(node, cx_tree_node_layout(tree)); | |
| 1035 | CxTreeIterator iter = cx_tree_iterator( | |
| 1036 | node, true, | |
| 1037 | tree->loc_children, tree->loc_next | |
| 1038 | ); | |
| 1039 | cx_foreach(void *, child, iter) { | |
| 1040 | if (iter.exiting) { | |
| 891 | 1041 | cx_invoke_destructor(tree, child); |
| 852 | 1042 | } |
| 1043 | } | |
| 891 | 1044 | tree->collection.size -= iter.counter; |
| 852 | 1045 | if (node == tree->root) { |
| 1046 | tree->root = NULL; | |
| 1047 | } | |
| 1048 | } | |
| 889 | 1049 | |
| 1050 | void cxTreeIteratorDispose(CxTreeIterator *iter) { | |
| 1051 | cxFreeDefault(iter->stack); | |
| 1052 | iter->stack = NULL; | |
| 1053 | } | |
| 1054 | ||
| 1055 | void cxTreeVisitorDispose(CxTreeVisitor *visitor) { | |
| 1056 | struct cx_tree_visitor_queue_s *q = visitor->queue_next; | |
| 1057 | while (q != NULL) { | |
| 1058 | struct cx_tree_visitor_queue_s *next = q->next; | |
| 1059 | cxFreeDefault(q); | |
| 1060 | q = next; | |
| 1061 | } | |
| 891 | 1062 | visitor->queue_next = visitor->queue_last = NULL; |
| 889 | 1063 | } |
| 1064 | ||
| 1065 | CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool visit_on_exit) { | |
| 1066 | return cx_tree_iterator( | |
| 1067 | node, visit_on_exit, | |
| 1068 | tree->loc_children, tree->loc_next | |
| 1069 | ); | |
| 1070 | } | |
| 1071 | ||
| 1072 | CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node) { | |
| 1073 | return cx_tree_visitor( | |
| 1074 | node, tree->loc_children, tree->loc_next | |
| 1075 | ); | |
| 1076 | } | |
| 1077 | ||
| 1078 | CxTreeIterator cxTreeIterate(CxTree *tree, bool visit_on_exit) { | |
| 1079 | return cxTreeIterateSubtree(tree, tree->root, visit_on_exit); | |
| 1080 | } | |
| 1081 | ||
| 1082 | CxTreeVisitor cxTreeVisit(CxTree *tree) { | |
| 1083 | return cxTreeVisitSubtree(tree, tree->root); | |
| 1084 | } |