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