src/tree.c

changeset 930
6540096c17b7
parent 921
5a7aa9cf9c3a
equal deleted inserted replaced
929:192a440b99df 930:6540096c17b7
170 } 170 }
171 } 171 }
172 172
173 int cx_tree_search( 173 int cx_tree_search(
174 const void *root, 174 const void *root,
175 size_t depth,
175 const void *node, 176 const void *node,
176 cx_tree_search_func sfunc, 177 cx_tree_search_func sfunc,
177 void **result, 178 void **result,
178 ptrdiff_t loc_children, 179 ptrdiff_t loc_children,
179 ptrdiff_t loc_next 180 ptrdiff_t loc_next
180 ) { 181 ) {
181 int ret; 182 // help avoiding bugs due to uninitialized memory
183 assert(result != NULL);
182 *result = NULL; 184 *result = NULL;
183 185
184 // shortcut: compare root before doing anything else 186 // remember return value for best match
185 ret = sfunc(root, node); 187 int ret = sfunc(root, node);
186 if (ret < 0) { 188 if (ret < 0) {
189 // not contained, exit
190 return -1;
191 }
192 *result = (void*) root;
193 // if root is already exact match, exit
194 if (ret == 0) {
195 return 0;
196 }
197
198 // when depth is one, we are already done
199 if (depth == 1) {
187 return ret; 200 return ret;
188 } else if (ret == 0 || tree_children(root) == NULL) { 201 }
189 *result = (void*)root; 202
190 return ret; 203 // special case: indefinite depth
191 } 204 if (depth == 0) {
192 205 depth = SIZE_MAX;
193 // create a working stack 206 }
194 CX_ARRAY_DECLARE(const void *, work); 207
195 cx_array_initialize(work, 32); 208 // create an iterator
196 209 CxTreeIterator iter = cx_tree_iterator(
197 // add the children of root to the working stack 210 (void*) root, false, loc_children, loc_next
198 { 211 );
199 void *c = tree_children(root); 212
200 while (c != NULL) { 213 // skip root, we already handled it
201 cx_array_simple_add(work, c); 214 cxIteratorNext(iter);
202 c = tree_next(c); 215
203 } 216 // loop through the remaining tree
204 } 217 cx_foreach(void *, elem, iter) {
205 218 // investigate the current node
206 // remember a candidate for adding the data 219 int ret_elem = sfunc(elem, node);
207 // also remember the exact return code from sfunc 220 if (ret_elem == 0) {
208 void *candidate = (void *) root;
209 int ret_candidate = ret;
210
211 // process the working stack
212 while (work_size > 0) {
213 // pop element
214 const void *elem = work[--work_size];
215
216 // apply the search function
217 ret = sfunc(elem, node);
218
219 if (ret == 0) {
220 // if found, exit the search 221 // if found, exit the search
221 *result = (void *) elem; 222 *result = (void *) elem;
222 work_size = 0; 223 ret = 0;
223 break; 224 break;
224 } else if (ret > 0) { 225 } else if (ret_elem > 0 && ret_elem < ret) {
225 // if children might contain the data, add them to the stack 226 // new distance is better
226 void *c = tree_children(elem); 227 *result = elem;
227 while (c != NULL) { 228 ret = ret_elem;
228 cx_array_simple_add(work, c); 229 } else {
229 c = tree_next(c); 230 // not contained or distance is worse, skip entire subtree
230 } 231 cxTreeIteratorContinue(iter);
231 232 }
232 // remember this node in case no child is suitable 233
233 if (ret < ret_candidate) { 234 // when we reached the max depth, skip the subtree
234 candidate = (void *) elem; 235 if (iter.depth == depth) {
235 ret_candidate = ret; 236 cxTreeIteratorContinue(iter);
236 } 237 }
237 } 238 }
238 } 239
239 240 // dispose the iterator as we might have exited the loop early
240 // not found, but was there a candidate? 241 cxTreeIteratorDispose(&iter);
241 if (ret != 0 && candidate != NULL) { 242
242 ret = ret_candidate; 243 assert(ret < 0 || *result != NULL);
243 *result = candidate;
244 }
245
246 // free the working queue and return
247 free(work);
248 return ret; 244 return ret;
249 } 245 }
250 246
251 int cx_tree_search_data( 247 int cx_tree_search_data(
252 const void *root, 248 const void *root,
249 size_t depth,
253 const void *data, 250 const void *data,
254 cx_tree_search_data_func sfunc, 251 cx_tree_search_data_func sfunc,
255 void **result, 252 void **result,
256 ptrdiff_t loc_children, 253 ptrdiff_t loc_children,
257 ptrdiff_t loc_next 254 ptrdiff_t loc_next
258 ) { 255 ) {
259 // it is basically the same implementation 256 // it is basically the same implementation
260 return cx_tree_search( 257 return cx_tree_search(
261 root, data, 258 root, depth, data,
262 (cx_tree_search_func) sfunc, 259 (cx_tree_search_func) sfunc,
263 result, 260 result,
264 loc_children, loc_next); 261 loc_children, loc_next);
265 } 262 }
266 263
566 cx_tree_zero_pointers(*cnode, cx_tree_ptr_locations); 563 cx_tree_zero_pointers(*cnode, cx_tree_ptr_locations);
567 564
568 void *match = NULL; 565 void *match = NULL;
569 int result = cx_tree_search( 566 int result = cx_tree_search(
570 root, 567 root,
568 0,
571 *cnode, 569 *cnode,
572 sfunc, 570 sfunc,
573 &match, 571 &match,
574 loc_children, 572 loc_children,
575 loc_next 573 loc_next
630 int result; 628 int result;
631 unsigned int look_around_retries = cx_tree_add_look_around_depth; 629 unsigned int look_around_retries = cx_tree_add_look_around_depth;
632 cx_tree_add_look_around_retry: 630 cx_tree_add_look_around_retry:
633 result = cx_tree_search( 631 result = cx_tree_search(
634 current_node, 632 current_node,
633 0,
635 new_node, 634 new_node,
636 sfunc, 635 sfunc,
637 &match, 636 &match,
638 loc_children, 637 loc_children,
639 loc_next 638 loc_next
769 } 768 }
770 769
771 static void *cx_tree_default_find( 770 static void *cx_tree_default_find(
772 CxTree *tree, 771 CxTree *tree,
773 const void *subtree, 772 const void *subtree,
774 const void *data 773 const void *data,
774 size_t depth
775 ) { 775 ) {
776 if (tree->root == NULL) return NULL; 776 if (tree->root == NULL) return NULL;
777 777
778 void *found; 778 void *found;
779 if (0 == cx_tree_search_data( 779 if (0 == cx_tree_search_data(
780 subtree, 780 subtree,
781 depth,
781 data, 782 data,
782 tree->search_data, 783 tree->search_data,
783 &found, 784 &found,
784 tree->loc_children, 785 tree->loc_children,
785 tree->loc_next 786 tree->loc_next

mercurial