change cx_tree_link() from prepending to appending children - fixes #391 default tip

Sun, 07 Jul 2024 14:56:44 +0200

author
Mike Becker <universe@uap-core.de>
date
Sun, 07 Jul 2024 14:56:44 +0200
changeset 862
387414a7afd8
parent 861
bab51b32fcb1

change cx_tree_link() from prepending to appending children - fixes #391

src/cx/tree.h file | annotate | diff | comparison | revisions
src/tree.c file | annotate | diff | comparison | revisions
tests/test_tree.c file | annotate | diff | comparison | revisions
--- a/src/cx/tree.h	Sun Jul 07 14:20:28 2024 +0200
+++ b/src/cx/tree.h	Sun Jul 07 14:56:44 2024 +0200
@@ -249,23 +249,26 @@
  * Links a node to a (new) parent.
  *
  * If the node has already a parent, it is unlinked, first.
- * If the parent has children already, the node is \em prepended to the list
+ * If the parent has children already, the node is \em appended to the list
  * of all currently existing children.
  *
  * @param parent the parent node
  * @param node the node that shall be linked
  * @param loc_parent offset in the node struct for the parent pointer
  * @param loc_children offset in the node struct for the children linked list
+ * @param loc_last_child optional offset in the node struct for the pointer to
+ * the last child in the linked list (negative if there is no such pointer)
  * @param loc_prev offset in the node struct for the prev pointer
  * @param loc_next offset in the node struct for the next pointer
  * @see cx_tree_unlink()
  */
 __attribute__((__nonnull__))
 void cx_tree_link(
-        void * restrict parent,
-        void * restrict node,
+        void *restrict parent,
+        void *restrict node,
         ptrdiff_t loc_parent,
         ptrdiff_t loc_children,
+        ptrdiff_t loc_last_child,
         ptrdiff_t loc_prev,
         ptrdiff_t loc_next
 );
@@ -278,6 +281,8 @@
  * @param node the node that shall be unlinked from its parent
  * @param loc_parent offset in the node struct for the parent pointer
  * @param loc_children offset in the node struct for the children linked list
+ * @param loc_last_child optional offset in the node struct for the pointer to
+ * the last child in the linked list (negative if there is no such pointer)
  * @param loc_prev offset in the node struct for the prev pointer
  * @param loc_next offset in the node struct for the next pointer
  * @see cx_tree_link()
@@ -287,6 +292,7 @@
         void *node,
         ptrdiff_t loc_parent,
         ptrdiff_t loc_children,
+        ptrdiff_t loc_last_child,
         ptrdiff_t loc_prev,
         ptrdiff_t loc_next
 );
--- a/src/tree.c	Sun Jul 07 14:20:28 2024 +0200
+++ b/src/tree.c	Sun Jul 07 14:56:44 2024 +0200
@@ -36,6 +36,7 @@
 #define CX_TREE_PTR(cur, off) (*(void**)(((char*)(cur))+(off)))
 #define tree_parent(node) CX_TREE_PTR(node, loc_parent)
 #define tree_children(node) CX_TREE_PTR(node, loc_children)
+#define tree_last_child(node) CX_TREE_PTR(node, loc_last_child)
 #define tree_prev(node) CX_TREE_PTR(node, loc_prev)
 #define tree_next(node) CX_TREE_PTR(node, loc_next)
 
@@ -44,23 +45,37 @@
         void *restrict node,
         ptrdiff_t loc_parent,
         ptrdiff_t loc_children,
+        ptrdiff_t loc_last_child,
         ptrdiff_t loc_prev,
         ptrdiff_t loc_next
 ) {
     void *current_parent = tree_parent(node);
     if (current_parent == parent) return;
     if (current_parent != NULL) {
-        cx_tree_unlink(node, loc_parent, loc_children,
+        cx_tree_unlink(node, loc_parent, loc_children, loc_last_child,
                        loc_prev, loc_next);
     }
 
     if (tree_children(parent) == NULL) {
         tree_children(parent) = node;
+        if (loc_last_child >= 0) {
+            tree_last_child(parent) = node;
+        }
     } else {
-        void *children = tree_children(parent);
-        tree_prev(children) = node;
-        tree_next(node) = children;
-        tree_children(parent) = node;
+        if (loc_last_child >= 0) {
+            void *child = tree_last_child(parent);
+            tree_prev(node) = child;
+            tree_next(child) = node;
+            tree_last_child(parent) = node;
+        } else {
+            void *child = tree_children(parent);
+            void *next;
+            while ((next = tree_next(child)) != NULL) {
+                child = next;
+            }
+            tree_prev(node) = child;
+            tree_next(child) = node;
+        }
     }
     tree_parent(node) = parent;
 }
@@ -69,6 +84,7 @@
         void *node,
         ptrdiff_t loc_parent,
         ptrdiff_t loc_children,
+        ptrdiff_t loc_last_child,
         ptrdiff_t loc_prev,
         ptrdiff_t loc_next
 ) {
@@ -76,13 +92,24 @@
 
     void *left = tree_prev(node);
     void *right = tree_next(node);
-    assert(left == NULL || tree_children(tree_parent(node)) != node);
+    void *parent = tree_parent(node);
+    assert(left == NULL || tree_children(parent) != node);
+    assert(right == NULL || loc_last_child < 0 ||
+           tree_last_child(parent) != node);
+
     if (left == NULL) {
-        tree_children(tree_parent(node)) = right;
+        tree_children(parent) = right;
     } else {
         tree_next(left) = right;
     }
-    if (right != NULL) tree_prev(right) = left;
+    if (right == NULL) {
+        if (loc_last_child >= 0) {
+            tree_last_child(parent) = left;
+        }
+    } else {
+        tree_prev(right) = left;
+    }
+
     tree_parent(node) = NULL;
     tree_prev(node) = NULL;
     tree_next(node) = NULL;
--- a/tests/test_tree.c	Sun Jul 07 14:20:28 2024 +0200
+++ b/tests/test_tree.c	Sun Jul 07 14:56:44 2024 +0200
@@ -40,11 +40,24 @@
     int data;
 } tree_node;
 
+typedef struct tree_node2 {
+    struct tree_node2 *parent;
+    struct tree_node2 *next;
+    struct tree_node2 *prev;
+    struct tree_node2 *children;
+    struct tree_node2 *last_child;
+    int data;
+} tree_node2;
+
 #define tree_node_layout \
-    offsetof(tree_node, parent), offsetof(tree_node, children), \
+    offsetof(tree_node, parent), offsetof(tree_node, children), -1, \
     offsetof(tree_node, prev), offsetof(tree_node, next)
+#define tree_node2_layout \
+    offsetof(tree_node2, parent), offsetof(tree_node2, children),\
+    offsetof(tree_node2, last_child), \
+    offsetof(tree_node2, prev), offsetof(tree_node2, next)
 
-#define tree_child_list offsetof(tree_node, children),offsetof(tree_node, next)
+#define tree_children(type) offsetof(type, children), offsetof(type, next)
 
 CX_TEST(test_tree_link_new_child) {
     tree_node parent = {0};
@@ -76,7 +89,7 @@
         CX_TEST_ASSERT(parent.next == NULL);
         CX_TEST_ASSERT(parent.prev == NULL);
         CX_TEST_ASSERT(parent.parent == NULL);
-        CX_TEST_ASSERT(parent.children == &child3);
+        CX_TEST_ASSERT(parent.children == &child1);
 
         CX_TEST_ASSERT(child1.parent == &parent);
         CX_TEST_ASSERT(child2.parent == &parent);
@@ -85,12 +98,12 @@
         CX_TEST_ASSERT(child2.children == NULL);
         CX_TEST_ASSERT(child3.children == NULL);
 
-        CX_TEST_ASSERT(child3.prev == NULL);
-        CX_TEST_ASSERT(child3.next == &child2);
-        CX_TEST_ASSERT(child2.prev == &child3);
-        CX_TEST_ASSERT(child2.next == &child1);
-        CX_TEST_ASSERT(child1.prev == &child2);
-        CX_TEST_ASSERT(child1.next == NULL);
+        CX_TEST_ASSERT(child1.prev == NULL);
+        CX_TEST_ASSERT(child1.next == &child2);
+        CX_TEST_ASSERT(child2.prev == &child1);
+        CX_TEST_ASSERT(child2.next == &child3);
+        CX_TEST_ASSERT(child3.prev == &child2);
+        CX_TEST_ASSERT(child3.next == NULL);
     }
 }
 
@@ -109,7 +122,7 @@
         CX_TEST_ASSERT(parent.next == NULL);
         CX_TEST_ASSERT(parent.prev == NULL);
         CX_TEST_ASSERT(parent.parent == NULL);
-        CX_TEST_ASSERT(parent.children == &child3);
+        CX_TEST_ASSERT(parent.children == &child1);
 
         CX_TEST_ASSERT(child1.parent == &parent);
         CX_TEST_ASSERT(child2.parent == &child3);
@@ -118,10 +131,10 @@
         CX_TEST_ASSERT(child2.children == NULL);
         CX_TEST_ASSERT(child3.children == &child2);
 
-        CX_TEST_ASSERT(child3.prev == NULL);
-        CX_TEST_ASSERT(child3.next == &child1);
-        CX_TEST_ASSERT(child1.prev == &child3);
-        CX_TEST_ASSERT(child1.next == NULL);
+        CX_TEST_ASSERT(child1.prev == NULL);
+        CX_TEST_ASSERT(child1.next == &child3);
+        CX_TEST_ASSERT(child3.prev == &child1);
+        CX_TEST_ASSERT(child3.next == NULL);
 
         CX_TEST_ASSERT(child2.prev == NULL);
         CX_TEST_ASSERT(child2.next == NULL);
@@ -161,6 +174,155 @@
         CX_TEST_ASSERT(child2.children == NULL);
         CX_TEST_ASSERT(child2.prev == NULL);
         CX_TEST_ASSERT(child2.next == NULL);
+
+        // unlink last child from parent
+        cx_tree_unlink(&child1, tree_node_layout);
+        CX_TEST_ASSERT(parent.next == NULL);
+        CX_TEST_ASSERT(parent.prev == NULL);
+        CX_TEST_ASSERT(parent.parent == NULL);
+        CX_TEST_ASSERT(parent.children == NULL);
+        CX_TEST_ASSERT(child1.parent == NULL);
+    }
+}
+
+CX_TEST(test_tree2_link_new_child) {
+    tree_node2 parent = {0};
+    tree_node2 child = {0};
+
+    CX_TEST_DO {
+        cx_tree_link(&parent, &child, tree_node2_layout);
+        CX_TEST_ASSERT(parent.next == NULL);
+        CX_TEST_ASSERT(parent.prev == NULL);
+        CX_TEST_ASSERT(parent.parent == NULL);
+        CX_TEST_ASSERT(parent.children == &child);
+        CX_TEST_ASSERT(parent.last_child == &child);
+        CX_TEST_ASSERT(child.parent == &parent);
+        CX_TEST_ASSERT(child.next == NULL);
+        CX_TEST_ASSERT(child.prev == NULL);
+        CX_TEST_ASSERT(child.children == NULL);
+        CX_TEST_ASSERT(child.last_child == NULL);
+    }
+}
+
+CX_TEST(test_tree2_link_add_child) {
+    tree_node2 parent = {0};
+    tree_node2 child1 = {0};
+    tree_node2 child2 = {0};
+    tree_node2 child3 = {0};
+
+    CX_TEST_DO {
+        cx_tree_link(&parent, &child1, tree_node2_layout);
+        cx_tree_link(&parent, &child2, tree_node2_layout);
+        cx_tree_link(&parent, &child3, tree_node2_layout);
+        CX_TEST_ASSERT(parent.next == NULL);
+        CX_TEST_ASSERT(parent.prev == NULL);
+        CX_TEST_ASSERT(parent.parent == NULL);
+        CX_TEST_ASSERT(parent.children == &child1);
+        CX_TEST_ASSERT(parent.last_child == &child3);
+
+        CX_TEST_ASSERT(child1.parent == &parent);
+        CX_TEST_ASSERT(child2.parent == &parent);
+        CX_TEST_ASSERT(child3.parent == &parent);
+        CX_TEST_ASSERT(child1.children == NULL);
+        CX_TEST_ASSERT(child2.children == NULL);
+        CX_TEST_ASSERT(child3.children == NULL);
+        CX_TEST_ASSERT(child1.last_child == NULL);
+        CX_TEST_ASSERT(child2.last_child == NULL);
+        CX_TEST_ASSERT(child3.last_child == NULL);
+
+        CX_TEST_ASSERT(child1.prev == NULL);
+        CX_TEST_ASSERT(child1.next == &child2);
+        CX_TEST_ASSERT(child2.prev == &child1);
+        CX_TEST_ASSERT(child2.next == &child3);
+        CX_TEST_ASSERT(child3.prev == &child2);
+        CX_TEST_ASSERT(child3.next == NULL);
+    }
+}
+
+CX_TEST(test_tree2_link_move_to_other_parent) {
+    tree_node2 parent = {0};
+    tree_node2 child1 = {0};
+    tree_node2 child2 = {0};
+    tree_node2 child3 = {0};
+    cx_tree_link(&parent, &child1, tree_node2_layout);
+    cx_tree_link(&parent, &child2, tree_node2_layout);
+    cx_tree_link(&parent, &child3, tree_node2_layout);
+
+    CX_TEST_DO {
+        cx_tree_link(&child3, &child2, tree_node2_layout);
+
+        CX_TEST_ASSERT(parent.next == NULL);
+        CX_TEST_ASSERT(parent.prev == NULL);
+        CX_TEST_ASSERT(parent.parent == NULL);
+        CX_TEST_ASSERT(parent.children == &child1);
+        CX_TEST_ASSERT(parent.last_child == &child3);
+
+        CX_TEST_ASSERT(child1.parent == &parent);
+        CX_TEST_ASSERT(child2.parent == &child3);
+        CX_TEST_ASSERT(child3.parent == &parent);
+        CX_TEST_ASSERT(child1.children == NULL);
+        CX_TEST_ASSERT(child2.children == NULL);
+        CX_TEST_ASSERT(child3.children == &child2);
+        CX_TEST_ASSERT(child1.last_child == NULL);
+        CX_TEST_ASSERT(child2.last_child == NULL);
+        CX_TEST_ASSERT(child3.last_child == &child2);
+
+        CX_TEST_ASSERT(child1.prev == NULL);
+        CX_TEST_ASSERT(child1.next == &child3);
+        CX_TEST_ASSERT(child3.prev == &child1);
+        CX_TEST_ASSERT(child3.next == NULL);
+
+        CX_TEST_ASSERT(child2.prev == NULL);
+        CX_TEST_ASSERT(child2.next == NULL);
+    }
+}
+
+CX_TEST(test_tree2_unlink) {
+    tree_node2 parent = {0};
+    tree_node2 child1 = {0};
+    tree_node2 child2 = {0};
+    tree_node2 child3 = {0};
+    cx_tree_link(&parent, &child1, tree_node2_layout);
+    cx_tree_link(&parent, &child3, tree_node2_layout);
+    cx_tree_link(&child3, &child2, tree_node2_layout);
+
+    CX_TEST_DO {
+        cx_tree_unlink(&child3, tree_node2_layout);
+
+        CX_TEST_ASSERT(parent.next == NULL);
+        CX_TEST_ASSERT(parent.prev == NULL);
+        CX_TEST_ASSERT(parent.parent == NULL);
+        CX_TEST_ASSERT(parent.children == &child1);
+        CX_TEST_ASSERT(parent.last_child == &child1);
+
+        CX_TEST_ASSERT(child1.parent == &parent);
+        CX_TEST_ASSERT(child1.children == NULL);
+        CX_TEST_ASSERT(child1.last_child == NULL);
+        CX_TEST_ASSERT(child1.prev == NULL);
+        CX_TEST_ASSERT(child1.next == NULL);
+
+        // child 3 is unlinked
+        CX_TEST_ASSERT(child3.parent == NULL);
+        CX_TEST_ASSERT(child3.prev == NULL);
+        CX_TEST_ASSERT(child3.next == NULL);
+
+        // child 2 is still child of the unlinked child 3
+        CX_TEST_ASSERT(child3.children == &child2);
+        CX_TEST_ASSERT(child3.last_child == &child2);
+        CX_TEST_ASSERT(child2.parent == &child3);
+        CX_TEST_ASSERT(child2.children == NULL);
+        CX_TEST_ASSERT(child2.last_child == NULL);
+        CX_TEST_ASSERT(child2.prev == NULL);
+        CX_TEST_ASSERT(child2.next == NULL);
+
+        // unlink last child from parent
+        cx_tree_unlink(&child1, tree_node2_layout);
+        CX_TEST_ASSERT(parent.next == NULL);
+        CX_TEST_ASSERT(parent.prev == NULL);
+        CX_TEST_ASSERT(parent.parent == NULL);
+        CX_TEST_ASSERT(parent.children == NULL);
+        CX_TEST_ASSERT(parent.last_child == NULL);
+        CX_TEST_ASSERT(child1.parent == NULL);
     }
 }
 
@@ -215,38 +377,38 @@
         for (unsigned i = 0 ; i <= 10 ; i++) {
             s = testdata[i];
             r = cx_tree_search(&root, &s, test_tree_search_function,
-                               (void **) &n, tree_child_list);
+                               (void **) &n, tree_children(tree_node));
             CX_TEST_ASSERT(r == 0);
             CX_TEST_ASSERT(n == testnodes[i]);
         }
 
         s = -5;
         r = cx_tree_search(&root, &s, test_tree_search_function,
-                           (void **) &n, tree_child_list);
+                           (void **) &n, tree_children(tree_node));
         CX_TEST_ASSERT(r < 0);
         CX_TEST_ASSERT(n == NULL);
 
         s = 26;
         r = cx_tree_search(&root, &s, test_tree_search_function,
-                           (void **) &n, tree_child_list);
+                           (void **) &n, tree_children(tree_node));
         CX_TEST_ASSERT(r > 0);
         CX_TEST_ASSERT(n == &ba);
 
         s = 35;
         r = cx_tree_search(&root, &s, test_tree_search_function,
-                           (void **) &n, tree_child_list);
+                           (void **) &n, tree_children(tree_node));
         CX_TEST_ASSERT(r > 0);
         CX_TEST_ASSERT(n == &cb);
 
         s = 38;
         r = cx_tree_search(&root, &s, test_tree_search_function,
-                           (void **) &n, tree_child_list);
+                           (void **) &n, tree_children(tree_node));
         CX_TEST_ASSERT(r > 0);
         CX_TEST_ASSERT(n == &cba);
 
         s = 42;
         r = cx_tree_search(&root, &s, test_tree_search_function,
-                           (void **) &n, tree_child_list);
+                           (void **) &n, tree_children(tree_node));
         CX_TEST_ASSERT(r > 0);
         CX_TEST_ASSERT(n == &cc);
     }
@@ -255,7 +417,7 @@
 CX_TEST(test_tree_iterator_create_and_dispose) {
     tree_node root;
     CX_TEST_DO {
-        CxTreeIterator iter = cx_tree_iterator(&root, false, tree_child_list);
+        CxTreeIterator iter = cx_tree_iterator(&root, false, tree_children(tree_node));
         CX_TEST_ASSERT(!iter.visit_on_exit);
         CX_TEST_ASSERT(!iter.exiting);
         CX_TEST_ASSERT(iter.counter == 1);
@@ -288,9 +450,9 @@
 
     tree_node* expected_order[] = {
             &root,
-            &c, &cc,&cb, &cba,&ca,
+            &a, &aa, &ab,
             &b, &ba,
-            &a, &ab, &aa,
+            &c, &ca, &cb, &cba, &cc,
     };
     tree_node* actual_order[16]; // reserve more space in case s.t. goes wrong
 
@@ -305,7 +467,7 @@
     cx_tree_link(&c, &cc, tree_node_layout);
     cx_tree_link(&cb, &cba, tree_node_layout);
     CX_TEST_DO {
-        CxTreeIterator iter = cx_tree_iterator(&root, false, tree_child_list);
+        CxTreeIterator iter = cx_tree_iterator(&root, false, tree_children(tree_node));
         unsigned chk = 0;
         cx_foreach(tree_node*, node, iter) {
             CX_TEST_ASSERT(node->data == 0);
@@ -358,7 +520,7 @@
     cx_tree_link(&c, &cc, tree_node_layout);
     cx_tree_link(&cb, &cba, tree_node_layout);
     CX_TEST_DO {
-        CxTreeIterator iter = cx_tree_iterator(&root, true, tree_child_list);
+        CxTreeIterator iter = cx_tree_iterator(&root, true, tree_children(tree_node));
         unsigned chk = 0;
         cx_foreach(tree_node*, node, iter) {
             CX_TEST_ASSERT(iter.exiting || node->data == 0);
@@ -393,10 +555,7 @@
 }
 
 typedef struct test_xml_node {
-    struct test_xml_node *parent;
-    struct test_xml_node *next;
-    struct test_xml_node *prev;
-    struct test_xml_node *children;
+    struct tree_node base;
     char const* name;
 } test_xml_node;
 
@@ -431,18 +590,18 @@
     target_dependencies.name = "dependencies";
     target_feature_dependencies.name = "dependencies";
 
-    cx_tree_link(&project, &target, tree_node_layout);
-    cx_tree_link(&project, &dependency2, tree_node_layout);
+    cx_tree_link(&project, &config, tree_node_layout);
     cx_tree_link(&project, &dependency1, tree_node_layout);
-    cx_tree_link(&project, &config, tree_node_layout);
-    cx_tree_link(&config, &var3, tree_node_layout);
+    cx_tree_link(&project, &dependency2, tree_node_layout);
+    cx_tree_link(&project, &target, tree_node_layout);
+    cx_tree_link(&config, &var1, tree_node_layout);
     cx_tree_link(&config, &var2, tree_node_layout);
-    cx_tree_link(&config, &var1, tree_node_layout);
+    cx_tree_link(&config, &var3, tree_node_layout);
     cx_tree_link(&dependency1, &dependency1make, tree_node_layout);
+    cx_tree_link(&dependency2, &dependency2lang, tree_node_layout);
     cx_tree_link(&dependency2, &dependency2make, tree_node_layout);
-    cx_tree_link(&dependency2, &dependency2lang, tree_node_layout);
+    cx_tree_link(&target, &target_feature, tree_node_layout);
     cx_tree_link(&target, &target_dependencies, tree_node_layout);
-    cx_tree_link(&target, &target_feature, tree_node_layout);
     cx_tree_link(&target_feature, &target_feature_dependencies, tree_node_layout);
 
     char const *expected =
@@ -451,7 +610,7 @@
             "<target><feature><dependencies></dependencies></feature><dependencies></dependencies></target></project>";
     char *actual = malloc(512);
     CX_TEST_DO {
-        CxTreeIterator iter = cx_tree_iterator(&project, true, tree_child_list);
+        CxTreeIterator iter = cx_tree_iterator(&project, true, tree_children(tree_node));
         size_t i = 0;
         cx_foreach(test_xml_node*, node, iter) {
             size_t len = strlen(node->name);
@@ -497,7 +656,7 @@
         cx_tree_link(c, cc, tree_node_layout);
         cx_tree_link(cb, cba, tree_node_layout);
 
-        CxTreeIterator iter = cx_tree_iterator(root, true, tree_child_list);
+        CxTreeIterator iter = cx_tree_iterator(root, true, tree_children(tree_node));
         cx_foreach(tree_node *, node, iter) {
             if (iter.exiting) {
                 cxFree(alloc,node);
@@ -514,7 +673,7 @@
     tree_node child;
     cx_tree_link(&root, &child, tree_node_layout);
     CX_TEST_DO {
-        CxTreeVisitor iter = cx_tree_visitor(&root, tree_child_list);
+        CxTreeVisitor iter = cx_tree_visitor(&root, tree_children(tree_node));
         CX_TEST_ASSERT(iter.counter == 1);
         CX_TEST_ASSERT(iter.node == &root);
         CX_TEST_ASSERT(!iter.base.mutating);
@@ -545,8 +704,8 @@
 
     tree_node* expected_order[] = {
             &root,
-            &c, &b, &a,
-            &cc, &cb, &ca, &ba, &ab, &aa,
+            &a, &b, &c,
+            &aa, &ab, &ba, &ca, &cb, &cc,
             &cba
     };
     tree_node* actual_order[16]; // reserve more space in case s.t. goes wrong
@@ -562,7 +721,7 @@
     cx_tree_link(&c, &cc, tree_node_layout);
     cx_tree_link(&cb, &cba, tree_node_layout);
     CX_TEST_DO {
-        CxTreeVisitor iter = cx_tree_visitor(&root, tree_child_list);
+        CxTreeVisitor iter = cx_tree_visitor(&root, tree_children(tree_node));
         unsigned chk = 0;
         cx_foreach(tree_node*, node, iter) {
             CX_TEST_ASSERT(node->data == 0);
@@ -595,7 +754,7 @@
     tree_node root = {0};
 
     CX_TEST_DO {
-        CxTreeVisitor iter = cx_tree_visitor(&root, tree_child_list);
+        CxTreeVisitor iter = cx_tree_visitor(&root, tree_children(tree_node));
         unsigned chk = 0;
         cx_foreach(tree_node*, node, iter) {
             CX_TEST_ASSERT(node == iter.node);
@@ -624,7 +783,7 @@
     cx_tree_link(&b, &c, tree_node_layout);
 
     CX_TEST_DO {
-        CxTreeVisitor iter = cx_tree_visitor(&root, tree_child_list);
+        CxTreeVisitor iter = cx_tree_visitor(&root, tree_children(tree_node));
         unsigned chk = 0;
         cx_foreach(tree_node*, node, iter) {
             CX_TEST_ASSERT(node == iter.node);
@@ -659,8 +818,8 @@
 
     tree_node* expected_order[] = {
             &root,
-            &c, &b, &a,
-            &ba, &ab, &aa
+            &a, &b, &c,
+            &aa, &ab, &ba
     };
     tree_node* actual_order[16]; // reserve more space in case s.t. goes wrong
 
@@ -675,7 +834,7 @@
     cx_tree_link(&c, &cc, tree_node_layout);
     cx_tree_link(&cb, &cba, tree_node_layout);
     CX_TEST_DO {
-        CxTreeVisitor iter = cx_tree_visitor(&root, tree_child_list);
+        CxTreeVisitor iter = cx_tree_visitor(&root, tree_children(tree_node));
         unsigned chk = 0;
         cx_foreach(tree_node*, node, iter) {
             CX_TEST_ASSERT(node->data == 0);
@@ -722,11 +881,11 @@
     tree_node cc = {0};
     tree_node cba = {0};
 
-    tree_node* expected_order[] = {
+    tree_node *expected_order[] = {
             &root,
+            &a, &aa, &ab,
+            &b, &ba,
             &c,
-            &b, &ba,
-            &a, &ab, &aa,
     };
     tree_node* actual_order[16]; // reserve more space in case s.t. goes wrong
 
@@ -741,7 +900,7 @@
     cx_tree_link(&c, &cc, tree_node_layout);
     cx_tree_link(&cb, &cba, tree_node_layout);
     CX_TEST_DO {
-        CxTreeIterator iter = cx_tree_iterator(&root, false, tree_child_list);
+        CxTreeIterator iter = cx_tree_iterator(&root, false, tree_children(tree_node));
         unsigned chk = 0;
         cx_foreach(tree_node*, node, iter) {
             CX_TEST_ASSERT(node->data == 0);
@@ -799,7 +958,7 @@
     cx_tree_link(&c, &cc, tree_node_layout);
     cx_tree_link(&cb, &cba, tree_node_layout);
     CX_TEST_DO {
-        CxTreeIterator iter = cx_tree_iterator(&root, true, tree_child_list);
+        CxTreeIterator iter = cx_tree_iterator(&root, true, tree_children(tree_node));
         unsigned chk = 0;
         cx_foreach(tree_node*, node, iter) {
             CX_TEST_ASSERT(iter.exiting || node->data == 0);
@@ -841,6 +1000,10 @@
     cx_test_register(suite, test_tree_link_add_child);
     cx_test_register(suite, test_tree_link_move_to_other_parent);
     cx_test_register(suite, test_tree_unlink);
+    cx_test_register(suite, test_tree2_link_new_child);
+    cx_test_register(suite, test_tree2_link_add_child);
+    cx_test_register(suite, test_tree2_link_move_to_other_parent);
+    cx_test_register(suite, test_tree2_unlink);
     cx_test_register(suite, test_tree_search);
     cx_test_register(suite, test_tree_iterator_create_and_dispose);
     cx_test_register(suite, test_tree_iterator_basic_only_enter);

mercurial