add bounding parameter to cx_tree_add_iter()

Sun, 29 Sep 2024 13:32:33 +0200

author
Mike Becker <universe@uap-core.de>
date
Sun, 29 Sep 2024 13:32:33 +0200
changeset 893
0a2b328f5b91
parent 892
6ebf6fdfbc2c
child 894
89cd8dfdc3c2

add bounding parameter to cx_tree_add_iter()

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 Sep 29 13:10:52 2024 +0200
+++ b/src/cx/tree.h	Sun Sep 29 13:32:33 2024 +0200
@@ -512,6 +512,7 @@
  * Refer to the documentation of #cx_tree_add() for more details.
  *
  * @param iter a pointer to an arbitrary iterator
+ * @param num the maximum number of elements to obtain from the iterator
  * @param sfunc a search function
  * @param cfunc a node creation function
  * @param cdata optional additional data
@@ -526,9 +527,10 @@
  * @return the number of nodes created and added
  * @see cx_tree_add()
  */
-__attribute__((__nonnull__(1, 2, 3, 5, 6)))
+__attribute__((__nonnull__(1, 3, 4, 6, 7)))
 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,
--- a/src/tree.c	Sun Sep 29 13:10:52 2024 +0200
+++ b/src/tree.c	Sun Sep 29 13:32:33 2024 +0200
@@ -541,6 +541,7 @@
 
 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,
@@ -562,7 +563,7 @@
     void *current_node = root;
     const void *elem;
 
-    for (void **eptr;
+    for (void **eptr; processed < num &&
          iter->valid(iter) && (eptr = iter->current(iter)) != NULL;
          iter->next(iter)) {
         elem = *eptr;
@@ -659,7 +660,7 @@
 
     // otherwise, create iterator and hand over to other function
     CxIterator iter = cxIterator(src, elem_size, num);
-    return cx_tree_add_iter(cxIteratorRef(iter), sfunc,
+    return cx_tree_add_iter(cxIteratorRef(iter), num, sfunc,
                             cfunc, cdata, failed, root,
                             loc_parent, loc_children, loc_last_child,
                             loc_prev, loc_next);
--- a/tests/test_tree.c	Sun Sep 29 13:10:52 2024 +0200
+++ b/tests/test_tree.c	Sun Sep 29 13:32:33 2024 +0200
@@ -1221,6 +1221,7 @@
         CxIterator iter = cxIterator(NULL, sizeof(void *), 0);
         processed = cx_tree_add_iter(
                 cxIteratorRef(iter),
+                10, // deliberately specify more than the iter has
                 tree_node_file_search,
                 create_tree_node_file, alloc,
                 &failed, &root, tree_node_file_layout
@@ -1300,6 +1301,71 @@
     cx_testing_allocator_destroy(&talloc);
 }
 
+CX_TEST(test_tree_add_many_but_not_all) {
+    CxTestingAllocator talloc;
+    cx_testing_allocator_init(&talloc);
+    CxAllocator *alloc = &talloc.base;
+
+    tree_node_file root = {0};
+    root.path = "/";
+    tree_node_file usr = {0};
+    usr.path = "/usr/";
+    cx_tree_link(&root, &usr, tree_node_file_layout);
+    tree_node_file home = {0};
+    home.path = "/home/";
+    cx_tree_link(&root, &home, tree_node_file_layout);
+    tree_node_file lib = {0};
+    lib.path = "/usr/lib/";
+    cx_tree_link(&usr, &lib, tree_node_file_layout);
+
+    CX_TEST_DO {
+        void *failed;
+
+        const char *paths[] = {
+                "/home/foo/",
+                "/home/foo/bar",
+                "/usr/lib64/",
+                "/usr/lib/foo.so"
+        };
+        // create iterator for 4 elements, but choose to insert only 3 of them
+        CxIterator iter = cxIterator(paths, sizeof(const char*), 4);
+        size_t processed = cx_tree_add_iter(
+                cxIteratorRef(iter), 3,
+                tree_node_file_search,
+                create_tree_node_file, alloc,
+                &failed, &root, tree_node_file_layout
+        );
+
+        CX_TEST_ASSERT(cxIteratorValid(iter));
+        CX_TEST_ASSERT(cxIteratorCurrent(iter) == &paths[3]);
+
+        CX_TEST_ASSERT(failed == NULL);
+        CX_TEST_ASSERT(processed == 3);
+        CX_TEST_ASSERT(talloc.alloc_total == 3);
+
+        CX_TEST_ASSERT(home.children == home.last_child);
+        tree_node_file *foo = home.children;
+        CX_TEST_ASSERT(foo != NULL && foo->path == paths[0]);
+        CX_TEST_ASSERT(foo->children == foo->last_child);
+        tree_node_file *bar = foo->children;
+        CX_TEST_ASSERT(bar != NULL && bar->path == paths[1]);
+        CX_TEST_ASSERT(usr.children != usr.last_child);
+        tree_node_file *lib64 = usr.last_child;
+        CX_TEST_ASSERT(lib64 != NULL);
+        CX_TEST_ASSERT(lib64->path == paths[2]);
+        CX_TEST_ASSERT(lib64->prev == &lib);
+        CX_TEST_ASSERT(lib64->parent == &usr);
+        CX_TEST_ASSERT(lib.children == NULL);
+
+        cxFree(alloc, foo);
+        cxFree(alloc, bar);
+        cxFree(alloc, lib64);
+
+        CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
+    }
+    cx_testing_allocator_destroy(&talloc);
+}
+
 CX_TEST(test_tree_add_many_with_dupl_and_no_match) {
     CxTestingAllocator talloc;
     cx_testing_allocator_init(&talloc);
@@ -1494,6 +1560,7 @@
     cx_test_register(suite, test_tree_add_duplicate_root);
     cx_test_register(suite, test_tree_add_zero);
     cx_test_register(suite, test_tree_add_many);
+    cx_test_register(suite, test_tree_add_many_but_not_all);
     cx_test_register(suite, test_tree_add_many_with_dupl_and_no_match);
     cx_test_register(suite, test_tree_add_create_from_array);
 

mercurial