ucx/tree.c

changeset 1040
473d8cb58a6c
parent 1016
ccde46662db7
--- a/ucx/tree.c	Wed Dec 31 12:37:09 2025 +0100
+++ b/ucx/tree.c	Wed Dec 31 16:40:12 2025 +0100
@@ -29,6 +29,7 @@
 #include "cx/tree.h"
 
 #include <assert.h>
+#include <string.h>
 
 #define CX_TREE_PTR(cur, off) (*(void**)(((char*)(cur))+(off)))
 #define tree_parent(node) CX_TREE_PTR(node, loc_parent)
@@ -37,36 +38,14 @@
 #define tree_prev(node) CX_TREE_PTR(node, loc_prev)
 #define tree_next(node) CX_TREE_PTR(node, loc_next)
 
-#define cx_tree_ptr_locations \
-    loc_parent, loc_children, loc_last_child, loc_prev, loc_next
-
-#define cx_tree_node_layout(tree) \
+#define tree_layout(tree) \
     (tree)->loc_parent,\
     (tree)->loc_children,\
     (tree)->loc_last_child,\
     (tree)->loc_prev,  \
     (tree)->loc_next
 
-static void cx_tree_zero_pointers(
-        void *node,
-        ptrdiff_t loc_parent,
-        ptrdiff_t loc_children,
-        ptrdiff_t loc_last_child,
-        ptrdiff_t loc_prev,
-        ptrdiff_t loc_next
-) {
-    tree_parent(node) = NULL;
-    if (loc_prev >= 0) {
-        tree_prev(node) = NULL;
-    }
-    tree_next(node) = NULL;
-    tree_children(node) = NULL;
-    if (loc_last_child >= 0) {
-        tree_last_child(node) = NULL;
-    }
-}
-
-void cx_tree_link(
+void cx_tree_add(
         void *parent,
         void *node,
         ptrdiff_t loc_parent,
@@ -82,7 +61,8 @@
     void *current_parent = tree_parent(node);
     if (current_parent == parent) return;
     if (current_parent != NULL) {
-        cx_tree_unlink(node, cx_tree_ptr_locations);
+        cx_tree_remove(node, loc_parent, loc_children,
+            loc_last_child, loc_prev, loc_next);
     }
 
     if (tree_children(parent) == NULL) {
@@ -128,7 +108,7 @@
     }
 }
 
-void cx_tree_unlink(
+void cx_tree_remove(
         void *node,
         ptrdiff_t loc_parent,
         ptrdiff_t loc_children,
@@ -175,21 +155,20 @@
     }
 }
 
-int cx_tree_search(
-        const void *root,
-        size_t depth,
-        const void *node,
-        cx_tree_search_func sfunc,
-        void **result,
-        ptrdiff_t loc_children,
-        ptrdiff_t loc_next
-) {
+int cx_tree_search(const void *root, size_t max_depth,
+        const void *data, cx_tree_search_func sfunc, void **result,
+        ptrdiff_t loc_children, ptrdiff_t loc_next) {
     // help avoiding bugs due to uninitialized memory
     assert(result != NULL);
     *result = NULL;
 
+    // NULL root? exit!
+    if (root == NULL) {
+        return -1;
+    }
+
     // remember return value for best match
-    int ret = sfunc(root, node);
+    int ret = sfunc(root, data);
     if (ret < 0) {
         // not contained, exit
         return -1;
@@ -201,13 +180,13 @@
     }
 
     // when depth is one, we are already done
-    if (depth == 1) {
+    if (max_depth == 1) {
         return ret;
     }
 
     // special case: indefinite depth
-    if (depth == 0) {
-        depth = SIZE_MAX;
+    if (max_depth == 0) {
+        max_depth = SIZE_MAX;
     }
 
     // create an iterator
@@ -221,7 +200,7 @@
     // loop through the remaining tree
     cx_foreach(void *, elem, iter) {
         // investigate the current node
-        int ret_elem = sfunc(elem, node);
+        int ret_elem = sfunc(elem, data);
         if (ret_elem == 0) {
             // if found, exit the search
             *result = elem;
@@ -237,47 +216,30 @@
         }
 
         // when we reached the max depth, skip the subtree
-        if (iter.depth == depth) {
+        if (iter.depth == max_depth) {
             cxTreeIteratorContinue(iter);
         }
     }
 
-    // dispose the iterator as we might have exited the loop early
+    // dispose of the iterator as we might have exited the loop early
     cxTreeIteratorDispose(&iter);
 
     assert(ret < 0 || *result != NULL);
     return ret;
 }
 
-int cx_tree_search_data(
-        const void *root,
-        size_t depth,
-        const void *data,
-        cx_tree_search_data_func sfunc,
-        void **result,
-        ptrdiff_t loc_children,
-        ptrdiff_t loc_next
-) {
-    // it is basically the same implementation
-    return cx_tree_search(
-            root, depth, data,
-            (cx_tree_search_func) sfunc,
-            result,
-            loc_children, loc_next);
-}
-
 static bool cx_tree_iter_valid(const void *it) {
-    const struct cx_tree_iterator_s *iter = it;
+    const CxTreeIterator *iter = it;
     return iter->node != NULL;
 }
 
 static void *cx_tree_iter_current(const void *it) {
-    const struct cx_tree_iterator_s *iter = it;
+    const CxTreeIterator *iter = it;
     return iter->node;
 }
 
 static void cx_tree_iter_next(void *it) {
-    struct cx_tree_iterator_s *iter = it;
+    CxTreeIterator *iter = it;
     ptrdiff_t const loc_next = iter->loc_next;
     ptrdiff_t const loc_children = iter->loc_children;
     // protect us from misuse
@@ -350,16 +312,16 @@
         }
     } else {
         // node has children, push the first child onto the stack and enter it
-        if (iter->stack_size >= iter->stack_capacity) {
+        if (iter->depth >= iter->stack_capacity) {
             const size_t newcap = iter->stack_capacity + 8;
-            if (cxReallocArrayDefault(&iter->stack, newcap, sizeof(void*))) {
+            if (cxReallocateArrayDefault(&iter->stack, newcap, sizeof(void*))) {
                 // we cannot return an error in this function
                 abort(); // LCOV_EXCL_LINE
             }
             iter->stack_capacity = newcap;
         }
-        iter->stack[iter->stack_size] = children;
-        iter->stack_size++;
+        iter->stack[iter->depth] = children;
+        iter->depth++;
         iter->node = children;
         iter->counter++;
     }
@@ -371,55 +333,56 @@
         ptrdiff_t loc_children,
         ptrdiff_t loc_next
 ) {
-    CxTreeIterator iter;
-    iter.loc_children = loc_children;
-    iter.loc_next = loc_next;
-    iter.visit_on_exit = visit_on_exit;
+    CxTreeIterator ret;
+    ret.use_dfs = true;
+    ret.loc_children = loc_children;
+    ret.loc_next = loc_next;
+    ret.visit_on_exit = visit_on_exit;
 
     // initialize members
-    iter.node_next = NULL;
-    iter.exiting = false;
-    iter.skip = false;
+    ret.node_next = NULL;
+    ret.exiting = false;
+    ret.skip = false;
 
     // assign base iterator functions
-    iter.base.allow_remove = false;
-    iter.base.remove = false;
-    iter.base.current_impl = NULL;
-    iter.base.valid = cx_tree_iter_valid;
-    iter.base.next = cx_tree_iter_next;
-    iter.base.current = cx_tree_iter_current;
+    ret.base.allow_remove = false;
+    ret.base.remove = false;
+    ret.base.current_impl = NULL;
+    ret.base.valid = cx_tree_iter_valid;
+    ret.base.next = cx_tree_iter_next;
+    ret.base.current = cx_tree_iter_current;
 
     // visit the root node
-    iter.node = root;
+    ret.node = root;
     if (root != NULL) {
-        iter.stack_capacity = 16;
-        iter.stack = cxMallocDefault(sizeof(void *) * 16);
-        iter.stack[0] = root;
-        iter.counter = 1;
-        iter.depth = 1;
+        ret.stack_capacity = 16;
+        ret.stack = cxMallocDefault(sizeof(void *) * 16);
+        ret.stack[0] = root;
+        ret.counter = 1;
+        ret.depth = 1;
     } else {
-        iter.stack_capacity = 0;
-        iter.stack = NULL;
-        iter.counter = 0;
-        iter.depth = 0;
+        ret.stack_capacity = 0;
+        ret.stack = NULL;
+        ret.counter = 0;
+        ret.depth = 0;
     }
 
-    return iter;
+    return ret;
 }
 
 static bool cx_tree_visitor_valid(const void *it) {
-    const struct cx_tree_visitor_s *iter = it;
+    const CxTreeIterator *iter = it;
     return iter->node != NULL;
 }
 
 static void *cx_tree_visitor_current(const void *it) {
-    const struct cx_tree_visitor_s *iter = it;
+    const CxTreeIterator *iter = it;
     return iter->node;
 }
 
-cx_attr_nonnull
+CX_NONNULL
 static void cx_tree_visitor_enqueue_siblings(
-        struct cx_tree_visitor_s *iter, void *node, ptrdiff_t loc_next) {
+        CxTreeIterator *iter, void *node, ptrdiff_t loc_next) {
     node = tree_next(node);
     while (node != NULL) {
         struct cx_tree_visitor_queue_s *q;
@@ -434,7 +397,7 @@
 }
 
 static void cx_tree_visitor_next(void *it) {
-    struct cx_tree_visitor_s *iter = it;
+    CxTreeIterator *iter = it;
     // protect us from misuse
     if (!iter->base.valid(iter)) return;
 
@@ -488,358 +451,98 @@
     iter->counter++;
 }
 
-CxTreeVisitor cx_tree_visitor(
+CxTreeIterator cx_tree_visitor(
         void *root,
         ptrdiff_t loc_children,
         ptrdiff_t loc_next
 ) {
-    CxTreeVisitor iter;
-    iter.loc_children = loc_children;
-    iter.loc_next = loc_next;
+    CxTreeIterator ret;
+    ret.visit_on_exit = false;
+    ret.exiting = false;
+    ret.use_dfs = false;
+    ret.loc_children = loc_children;
+    ret.loc_next = loc_next;
 
     // initialize members
-    iter.skip = false;
-    iter.queue_next = NULL;
-    iter.queue_last = NULL;
+    ret.skip = false;
+    ret.queue_next = NULL;
+    ret.queue_last = NULL;
 
     // assign base iterator functions
-    iter.base.allow_remove = false;
-    iter.base.remove = false;
-    iter.base.current_impl = NULL;
-    iter.base.valid = cx_tree_visitor_valid;
-    iter.base.next = cx_tree_visitor_next;
-    iter.base.current = cx_tree_visitor_current;
+    ret.base.allow_remove = false;
+    ret.base.remove = false;
+    ret.base.current_impl = NULL;
+    ret.base.valid = cx_tree_visitor_valid;
+    ret.base.next = cx_tree_visitor_next;
+    ret.base.current = cx_tree_visitor_current;
 
     // visit the root node
-    iter.node = root;
+    ret.node = root;
     if (root != NULL) {
-        iter.counter = 1;
-        iter.depth = 1;
+        ret.counter = 1;
+        ret.depth = 1;
     } else {
-        iter.counter = 0;
-        iter.depth = 0;
+        ret.counter = 0;
+        ret.depth = 0;
     }
 
-    return iter;
-}
-
-static void cx_tree_add_link_duplicate(
-        void *original, void *duplicate,
-        ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
-        ptrdiff_t loc_prev, ptrdiff_t loc_next
-) {
-    void *shared_parent = tree_parent(original);
-    if (shared_parent == NULL) {
-        cx_tree_link(original, duplicate, cx_tree_ptr_locations);
-    } else {
-        cx_tree_link(shared_parent, duplicate, cx_tree_ptr_locations);
-    }
-}
-
-static void cx_tree_add_link_new(
-        void *parent, void *node, cx_tree_search_func sfunc,
-        ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
-        ptrdiff_t loc_prev, ptrdiff_t loc_next
-) {
-    // check the current children one by one,
-    // if they could be children of the new node
-    void *child = tree_children(parent);
-    while (child != NULL) {
-        void *next = tree_next(child);
-
-        if (sfunc(node, child) > 0) {
-            // the sibling could be a child -> re-link
-            cx_tree_link(node, child, cx_tree_ptr_locations);
-        }
-
-        child = next;
-    }
-
-    // add new node as new child
-    cx_tree_link(parent, node, cx_tree_ptr_locations);
-}
-
-int cx_tree_add(
-        const void *src,
-        cx_tree_search_func sfunc,
-        cx_tree_node_create_func cfunc,
-        void *cdata,
-        void **cnode,
-        void *root,
-        ptrdiff_t loc_parent,
-        ptrdiff_t loc_children,
-        ptrdiff_t loc_last_child,
-        ptrdiff_t loc_prev,
-        ptrdiff_t loc_next
-) {
-    *cnode = cfunc(src, cdata);
-    if (*cnode == NULL) return 1;  // LCOV_EXCL_LINE
-    cx_tree_zero_pointers(*cnode, cx_tree_ptr_locations);
-
-    void *match = NULL;
-    int result = cx_tree_search(
-            root,
-            0,
-            *cnode,
-            sfunc,
-            &match,
-            loc_children,
-            loc_next
-    );
-
-    if (result < 0) {
-        // node does not fit into the tree - return non-zero value
-        return 1;
-    } else if (result == 0) {
-        // data already found in the tree, link duplicate
-        cx_tree_add_link_duplicate(match, *cnode, cx_tree_ptr_locations);
-    } else {
-        // closest match found, add new node
-        cx_tree_add_link_new(match, *cnode, sfunc, cx_tree_ptr_locations);
-    }
-
-    return 0;
+    return ret;
 }
 
-unsigned int cx_tree_add_look_around_depth = 3;
-
-size_t cx_tree_add_iter(
-        struct cx_iterator_base_s *iter,
-        size_t num,
-        cx_tree_search_func sfunc,
-        cx_tree_node_create_func cfunc,
-        void *cdata,
-        void **failed,
-        void *root,
-        ptrdiff_t loc_parent,
-        ptrdiff_t loc_children,
-        ptrdiff_t loc_last_child,
-        ptrdiff_t loc_prev,
-        ptrdiff_t loc_next
-) {
-    // erase the failed pointer
-    *failed = NULL;
-
-    // iter not valid? cancel...
-    if (!iter->valid(iter)) return 0;
-
-    size_t processed = 0;
-    void *current_node = root;
-    const void *elem;
-
-    for (void **eptr; processed < num &&
-         iter->valid(iter) && (eptr = iter->current(iter)) != NULL;
-         iter->next(iter)) {
-        elem = *eptr;
-
-        // create the new node
-        void *new_node = cfunc(elem, cdata);
-        if (new_node == NULL) return processed;  // LCOV_EXCL_LINE
-        cx_tree_zero_pointers(new_node, cx_tree_ptr_locations);
-
-        // start searching from current node
-        void *match;
-        int result;
-        unsigned int look_around_retries = cx_tree_add_look_around_depth;
-        cx_tree_add_look_around_retry:
-        result = cx_tree_search(
-                current_node,
-                0,
-                new_node,
-                sfunc,
-                &match,
-                loc_children,
-                loc_next
-        );
-
-        if (result < 0) {
-            // traverse upwards and try to find better parents
-            void *parent = tree_parent(current_node);
-            if (parent != NULL) {
-                if (look_around_retries > 0) {
-                    look_around_retries--;
-                    current_node = parent;
-                } else {
-                    // look around retries exhausted, start from the root
-                    current_node = root;
-                }
-                goto cx_tree_add_look_around_retry;
-            } else {
-                // no parents. so we failed
-                *failed = new_node;
-                return processed;
-            }
-        } else if (result == 0) {
-            // data already found in the tree, link duplicate
-            cx_tree_add_link_duplicate(match, new_node, cx_tree_ptr_locations);
-            // but stick with the original match, in case we needed a new root
-            current_node = match;
-        } else {
-            // closest match found, add new node as child
-            cx_tree_add_link_new(match, new_node, sfunc,
-                                 cx_tree_ptr_locations);
-            current_node = match;
-        }
-
-        processed++;
+size_t cx_tree_size(void *root, ptrdiff_t loc_children, ptrdiff_t loc_next) {
+    CxTreeIterator iter = cx_tree_iterator(root, false, loc_children, loc_next);
+    while (cxIteratorValid(iter)) {
+        cxIteratorNext(iter);
     }
-    return processed;
+    return iter.counter;
 }
 
-size_t cx_tree_add_array(
-        const void *src,
-        size_t num,
-        size_t elem_size,
-        cx_tree_search_func sfunc,
-        cx_tree_node_create_func cfunc,
-        void *cdata,
-        void **failed,
-        void *root,
-        ptrdiff_t loc_parent,
-        ptrdiff_t loc_children,
-        ptrdiff_t loc_last_child,
-        ptrdiff_t loc_prev,
-        ptrdiff_t loc_next
-) {
-    // erase failed pointer
-    *failed = NULL;
-
-    // super special case: zero elements
-    if (num == 0) {
-        return 0;
+size_t cx_tree_depth(void *root, ptrdiff_t loc_children, ptrdiff_t loc_next) {
+    CxTreeIterator iter = cx_tree_iterator(root, false, loc_children, loc_next);
+    size_t depth = 0;
+    while (cxIteratorValid(iter)) {
+        if (iter.depth > depth) {
+            depth = iter.depth;
+        }
+        cxIteratorNext(iter);
     }
-
-    // special case: one element does not need an iterator
-    if (num == 1) {
-        void *node;
-        if (0 == cx_tree_add(
-                src, sfunc, cfunc, cdata, &node, root,
-                loc_parent, loc_children, loc_last_child,
-                loc_prev, loc_next)) {
-            return 1;
-        } else {
-            *failed = node;
-            return 0;
-        }
-    }
-
-    // otherwise, create iterator and hand over to other function
-    CxIterator iter = cxIterator(src, elem_size, num);
-    return cx_tree_add_iter(cxIteratorRef(iter), num, sfunc,
-                            cfunc, cdata, failed, root,
-                            loc_parent, loc_children, loc_last_child,
-                            loc_prev, loc_next);
+    return depth;
 }
 
-static int cx_tree_default_insert_element(
-        CxTree *tree,
-        const void *data
-) {
-    void *node;
-    if (tree->root == NULL) {
-        node = tree->node_create(data, tree);
-        if (node == NULL) return 1;  // LCOV_EXCL_LINE
-        cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
-        tree->root = node;
-        tree->collection.size = 1;
-        return 0;
-    }
-    int result = cx_tree_add(data, tree->search, tree->node_create,
-                tree, &node, tree->root, cx_tree_node_layout(tree));
-    if (0 == result) {
-        tree->collection.size++;
-    } else {
-        cxFree(tree->collection.allocator, node);
-    }
-    return result;
-}
+CxTree *cxTreeCreate(const CxAllocator *allocator,
+        size_t node_size, size_t elem_size, void *root, ptrdiff_t loc_data,
+        ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
+        ptrdiff_t loc_prev, ptrdiff_t loc_next) {
 
-static size_t cx_tree_default_insert_many(
-        CxTree *tree,
-        CxIteratorBase *iter,
-        size_t n
-) {
-    size_t ins = 0;
-    if (!iter->valid(iter)) return 0;
-    if (tree->root == NULL) {
-        // use the first element from the iter to create the root node
-        void **eptr = iter->current(iter);
-        void *node = tree->node_create(*eptr, tree);
-        if (node == NULL) return 0;  // LCOV_EXCL_LINE
-        cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
-        tree->root = node;
-        ins = 1;
-        iter->next(iter);
-    }
-    void *failed;
-    ins += cx_tree_add_iter(iter, n, tree->search, tree->node_create,
-                                  tree, &failed, tree->root, cx_tree_node_layout(tree));
-    tree->collection.size += ins;
-    if (ins < n) {
-        cxFree(tree->collection.allocator, failed);
-    }
-    return ins;
-}
-
-static void *cx_tree_default_find(
-        CxTree *tree,
-        const void *subtree,
-        const void *data,
-        size_t depth
-) {
-    if (tree->root == NULL) return NULL;  // LCOV_EXCL_LINE
-
-    void *found;
-    if (0 == cx_tree_search_data(
-            subtree,
-            depth,
-            data,
-            tree->search_data,
-            &found,
-            tree->loc_children,
-            tree->loc_next
-    )) {
-        return found;
-    } else {
-        return NULL;
-    }
-}
-
-static cx_tree_class cx_tree_default_class = {
-        cx_tree_default_insert_element,
-        cx_tree_default_insert_many,
-        cx_tree_default_find
-};
-
-CxTree *cxTreeCreate(const CxAllocator *allocator,
-        cx_tree_node_create_func create_func,
-        cx_tree_search_func search_func,
-        cx_tree_search_data_func search_data_func,
-        ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
-        ptrdiff_t loc_prev, ptrdiff_t loc_next
-) {
     if (allocator == NULL) {
         allocator = cxDefaultAllocator;
     }
-    assert(create_func != NULL);
-    assert(search_func != NULL);
-    assert(search_data_func != NULL);
 
     CxTree *tree = cxZalloc(allocator, sizeof(CxTree));
     if (tree == NULL) return NULL;  // LCOV_EXCL_LINE
+    tree->collection.allocator = allocator;
 
-    tree->cl = &cx_tree_default_class;
-    tree->collection.allocator = allocator;
-    tree->node_create = create_func;
-    tree->search = search_func;
-    tree->search_data = search_data_func;
-    tree->collection.advanced_destructor = (cx_destructor_func2) cxFree;
-    tree->collection.destructor_data = (void *) allocator;
+    if (elem_size == CX_STORE_POINTERS) {
+        tree->collection.store_pointer = true;
+        tree->collection.elem_size = sizeof(void*);
+    } else {
+        tree->collection.elem_size = elem_size;
+    }
+
+    tree->root = root;
+    tree->node_size = node_size;
     tree->loc_parent = loc_parent;
     tree->loc_children = loc_children;
     tree->loc_last_child = loc_last_child;
     tree->loc_prev = loc_prev;
     tree->loc_next = loc_next;
+    tree->loc_data = loc_data;
+
+    if (root == NULL) {
+        cxSetAdvancedDestructor(tree, cxFree, (void*)allocator);
+    } else {
+        tree->collection.size = cx_tree_size(root, loc_children, loc_next);
+    }
 
     return tree;
 }
@@ -852,97 +555,120 @@
     cxFree(tree->collection.allocator, tree);
 }
 
-CxTree *cxTreeCreateWrapped(const CxAllocator *allocator, void *root,
-        ptrdiff_t loc_parent, ptrdiff_t loc_children, ptrdiff_t loc_last_child,
-        ptrdiff_t loc_prev, ptrdiff_t loc_next) {
-    if (allocator == NULL) {
-        allocator = cxDefaultAllocator;
-    }
-    assert(root != NULL);
-
-    CxTree *tree = cxZalloc(allocator, sizeof(CxTree));
-    if (tree == NULL) return NULL;  // LCOV_EXCL_LINE
-
-    tree->cl = &cx_tree_default_class;
-    // set the allocator anyway, just in case...
-    tree->collection.allocator = allocator;
-    tree->loc_parent = loc_parent;
-    tree->loc_children = loc_children;
-    tree->loc_last_child = loc_last_child;
-    tree->loc_prev = loc_prev;
-    tree->loc_next = loc_next;
-    tree->root = root;
-    tree->collection.size = cxTreeSubtreeSize(tree, root);
-    return tree;
-}
-
 void cxTreeSetParent(CxTree *tree, void *parent, void *child) {
     size_t loc_parent = tree->loc_parent;
     if (tree_parent(child) == NULL) {
         tree->collection.size++;
     }
-    cx_tree_link(parent, child, cx_tree_node_layout(tree));
+    cx_tree_add(parent, child, tree_layout(tree));
 }
 
-void cxTreeAddChildNode(CxTree *tree, void *parent, void *child) {
-    cx_tree_link(parent, child, cx_tree_node_layout(tree));
+void cxTreeAddNode(CxTree *tree, void *parent, void *child) {
+    cx_tree_add(parent, child, tree_layout(tree));
     tree->collection.size++;
 }
 
-int cxTreeAddChild(CxTree *tree, void *parent, const void *data) {
-    void *node = tree->node_create(data, tree);
-    if (node == NULL) return 1; // LCOV_EXCL_LINE
-    cx_tree_zero_pointers(node, cx_tree_node_layout(tree));
-    cx_tree_link(parent, node, cx_tree_node_layout(tree));
+void *cxTreeCreateNode(CxTree *tree, void *parent) {
+    void *node = cxZalloc(tree->collection.allocator, tree->node_size);
+    if (node == NULL) return NULL; // LCOV_EXCL_LINE
+    cx_tree_add(parent, node, tree_layout(tree));
     tree->collection.size++;
-    return 0;
+    return node;
 }
 
-int cxTreeInsert(CxTree *tree, const void *data) {
-    return tree->cl->insert_element(tree, data);
+void *cxTreeAddData(CxTree *tree, void *parent, const void *data) {
+    if (tree->loc_data < 0) return NULL;
+
+    void *node = cxTreeCreateNode(tree, parent);
+    if (node == NULL) return NULL; // LCOV_EXCL_LINE
+
+    char *dst = node;
+    dst += tree->loc_data;
+    const void *src = cxCollectionStoresPointers(tree) ? (const void*)&data : data;
+    memcpy(dst, src, tree->collection.elem_size);
+
+    return node;
+}
+
+void *cxTreeCreateRoot(CxTree *tree) {
+    if (tree->root != NULL) {
+        return tree->root;
+    }
+
+    void *node = cxZalloc(tree->collection.allocator, tree->node_size);
+    if (node == NULL) return NULL; // LCOV_EXCL_LINE
+    tree->root = node;
+    tree->collection.size = 1;
+    return node;
 }
 
-size_t cxTreeInsertIter(CxTree *tree, CxIteratorBase *iter, size_t n) {
-    return tree->cl->insert_many(tree, iter, n);
+void *cxTreeCreateRootData(CxTree *tree, const void *data) {
+    if (tree->loc_data < 0) return NULL;
+
+    void *node = cxTreeCreateRoot(tree);
+    if (node == NULL) return NULL; // LCOV_EXCL_LINE
+
+    char *dst = node;
+    dst += tree->loc_data;
+    const void *src = cxCollectionStoresPointers(tree) ? (const void*)&data : data;
+    memcpy(dst, src, tree->collection.elem_size);
+
+    return node;
+}
+
+void *cxTreeSetRoot(CxTree *tree, void *new_root) {
+    void *old_root = tree->root;
+    tree->root = new_root;
+    return old_root;
 }
 
-size_t cxTreeInsertArray(CxTree *tree, const void *data, size_t elem_size, size_t n) {
-    if (n == 0) return 0;
-    if (n == 1) return 0 == cxTreeInsert(tree, data) ? 1 : 0;
-    CxIterator iter = cxIterator(data, elem_size, n);
-    return cxTreeInsertIter(tree, cxIteratorRef(iter), n);
+void *cxTreeFindInSubtree(CxTree *tree, const void *data,
+        void *subtree_root, size_t max_depth, bool use_dfs) {
+    if (tree->loc_data < 0 || subtree_root == NULL) {
+        return NULL;
+    }
+
+    CxTreeIterator iter = use_dfs
+        ? cx_tree_iterator(subtree_root, false, tree->loc_children, tree->loc_next)
+        : cx_tree_visitor(subtree_root, tree->loc_children, tree->loc_next);
+
+    cx_foreach(char*, node, iter) {
+        char *node_data = node + tree->loc_data;
+        if (cxCollectionStoresPointers(tree)) {
+            node_data = *(void**)node_data;
+        }
+        if (cx_invoke_compare_func(tree, node_data, data) == 0) {
+            cxTreeIteratorDispose(&iter);
+            return node;
+        }
+        if (iter.depth == max_depth) {
+            cxTreeIteratorContinue(iter);
+        }
+    }
+    return NULL;
 }
 
-void *cxTreeFind( CxTree *tree, const void *data) {
-    return tree->cl->find(tree, tree->root, data, 0);
-}
-
-void *cxTreeFindInSubtree(CxTree *tree, const void *data, void *subtree_root, size_t max_depth) {
-    return tree->cl->find(tree, subtree_root, data, max_depth);
+void *cxTreeFindFastInSubtree(CxTree *tree, const void *data,
+        cx_tree_search_func sfunc, void *root, size_t max_depth) {
+    void *result;
+    int ret = cx_tree_search(root, max_depth, data, sfunc, &result,
+        tree->loc_children, tree->loc_next);
+    if (ret == 0) {
+        return result;
+    } else {
+        return NULL;
+    }
 }
 
 size_t cxTreeSubtreeSize(CxTree *tree, void *subtree_root) {
-    CxTreeVisitor visitor = cx_tree_visitor(
-            subtree_root,
-            tree->loc_children,
-            tree->loc_next
-    );
-    while (cxIteratorValid(visitor)) {
-        cxIteratorNext(visitor);
+    if (subtree_root == tree->root) {
+        return tree->collection.size;
     }
-    return visitor.counter;
+    return cx_tree_size(subtree_root, tree->loc_children, tree->loc_next);
 }
 
 size_t cxTreeSubtreeDepth(CxTree *tree, void *subtree_root) {
-    CxTreeVisitor visitor = cx_tree_visitor(
-            subtree_root,
-            tree->loc_children,
-            tree->loc_next
-    );
-    while (cxIteratorValid(visitor)) {
-        cxIteratorNext(visitor);
-    }
-    return visitor.depth;
+    return cx_tree_depth(subtree_root, tree->loc_children, tree->loc_next);
 }
 
 size_t cxTreeSize(CxTree *tree) {
@@ -950,13 +676,7 @@
 }
 
 size_t cxTreeDepth(CxTree *tree) {
-    CxTreeVisitor visitor = cx_tree_visitor(
-            tree->root, tree->loc_children, tree->loc_next
-    );
-    while (cxIteratorValid(visitor)) {
-        cxIteratorNext(visitor);
-    }
-    return visitor.depth;
+    return cx_tree_depth(tree->root, tree->loc_children, tree->loc_next);
 }
 
 int cxTreeRemoveNode(
@@ -971,7 +691,7 @@
     void *new_parent = tree_parent(node);
 
     // first, unlink from the parent
-    cx_tree_unlink(node, cx_tree_node_layout(tree));
+    cx_tree_remove(node, tree_layout(tree));
 
     // then relink each child
     ptrdiff_t loc_children = tree->loc_children;
@@ -988,7 +708,7 @@
         }
 
         // link to new parent
-        cx_tree_link(new_parent, child, cx_tree_node_layout(tree));
+        cx_tree_add(new_parent, child, tree_layout(tree));
 
         // proceed to next child
         child = tree_next(child);
@@ -1012,7 +732,7 @@
         return;
     }
     size_t subtree_size = cxTreeSubtreeSize(tree, node);
-    cx_tree_unlink(node, cx_tree_node_layout(tree));
+    cx_tree_remove(node, tree_layout(tree));
     tree->collection.size -= subtree_size;
 }
 
@@ -1023,7 +743,7 @@
 ) {
     int result = cxTreeRemoveNode(tree, node, relink_func);
     if (result == 0) {
-        cx_invoke_destructor(tree, node);
+        cx_invoke_destructor_raw(tree, node);
         return 0;
     } else {
         return result;
@@ -1031,14 +751,15 @@
 }
 
 void cxTreeDestroySubtree(CxTree *tree, void *node) {
-    cx_tree_unlink(node, cx_tree_node_layout(tree));
+    cx_tree_remove(node, tree_layout(tree));
     CxTreeIterator iter = cx_tree_iterator(
             node, true,
             tree->loc_children, tree->loc_next
     );
     cx_foreach(void *, child, iter) {
         if (iter.exiting) {
-            cx_invoke_destructor(tree, child);
+            // always call the destructors with the node!
+            cx_invoke_destructor_raw(tree, child);
         }
     }
     tree->collection.size -= iter.counter;
@@ -1048,18 +769,18 @@
 }
 
 void cxTreeIteratorDispose(CxTreeIterator *iter) {
-    cxFreeDefault(iter->stack);
-    iter->stack = NULL;
-}
-
-void cxTreeVisitorDispose(CxTreeVisitor *visitor) {
-    struct cx_tree_visitor_queue_s *q = visitor->queue_next;
-    while (q != NULL) {
-        struct cx_tree_visitor_queue_s *next = q->next;
-        cxFreeDefault(q);
-        q = next;
+    if (iter->use_dfs) {
+        cxFreeDefault(iter->stack);
+        iter->stack = NULL;
+    } else {
+        struct cx_tree_visitor_queue_s *q = iter->queue_next;
+        while (q != NULL) {
+            struct cx_tree_visitor_queue_s *next = q->next;
+            cxFreeDefault(q);
+            q = next;
+        }
+        iter->queue_next = iter->queue_last = NULL;
     }
-    visitor->queue_next = visitor->queue_last = NULL;
 }
 
 CxTreeIterator cxTreeIterateSubtree(CxTree *tree, void *node, bool visit_on_exit) {
@@ -1069,7 +790,7 @@
     );
 }
 
-CxTreeVisitor cxTreeVisitSubtree(CxTree *tree, void *node) {
+CxTreeIterator cxTreeVisitSubtree(CxTree *tree, void *node) {
     return cx_tree_visitor(
             node, tree->loc_children, tree->loc_next
     );
@@ -1079,6 +800,6 @@
     return cxTreeIterateSubtree(tree, tree->root, visit_on_exit);
 }
 
-CxTreeVisitor cxTreeVisit(CxTree *tree) {
+CxTreeIterator cxTreeVisit(CxTree *tree) {
     return cxTreeVisitSubtree(tree, tree->root);
 }

mercurial