diff -r f49f8a7060aa -r f4e00bb3f3b2 src/tree.c --- a/src/tree.c Sat Oct 05 14:42:14 2024 +0200 +++ b/src/tree.c Sat Oct 05 19:05:47 2024 +0200 @@ -900,10 +900,48 @@ return visitor.depth; } -int cxTreeRemove(CxTree *tree, void *node) { +int cxTreeRemove( + CxTree *tree, + void *node, + cx_tree_relink_func relink_func +) { if (node == tree->root) return 1; + // determine the new parent + ptrdiff_t loc_parent = tree->loc_parent; + void *new_parent = tree_parent(node); + // first, unlink from the parent + cx_tree_unlink(node, cx_tree_node_layout(tree)); + + // then relink each child + ptrdiff_t loc_children = tree->loc_children; + ptrdiff_t loc_next = tree->loc_next; + void *child = tree_children(node); + while (child != NULL) { + // forcibly set the parent to NULL - we do not use the unlink function + // because that would unnecessarily modify the children linked list + tree_parent(child) = NULL; + + // update contents, if required + if (relink_func != NULL) { + relink_func(child, node, new_parent); + } + + // link to new parent + cx_tree_link(new_parent, child, cx_tree_node_layout(tree)); + + // proceed to next child + child = tree_next(child); + } + + // clear the linked list of the removed node + tree_children(node) = NULL; + ptrdiff_t loc_last_child = tree->loc_last_child; + if (loc_last_child >= 0) tree_last_child(node) = NULL; + + // the tree now has one member less + tree->size--; return 0; }