src/tree.c

changeset 909
f4e00bb3f3b2
parent 908
f49f8a7060aa
--- 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;
 }

mercurial