# HG changeset patch # User Mike Becker # Date 1727609553 -7200 # Node ID 0a2b328f5b91dbc46ec279bacb75d28c3a5dfaa2 # Parent 6ebf6fdfbc2cc796735649b0c5ada5ca09510c53 add bounding parameter to cx_tree_add_iter() diff -r 6ebf6fdfbc2c -r 0a2b328f5b91 src/cx/tree.h --- 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, diff -r 6ebf6fdfbc2c -r 0a2b328f5b91 src/tree.c --- 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); diff -r 6ebf6fdfbc2c -r 0a2b328f5b91 tests/test_tree.c --- 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);