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 |