From 57e2d5775d9571506773ec135662c6c788103669 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Fri, 25 Oct 2013 17:23:32 +0200 Subject: [PATCH] utils llist: Added sdb_llist_iter_remove_current(). This function may be used to remove the current (the one returned by the last sdb_llist_iter_get_next() call) iterator value from the list. Note, that this function is not safe if another iterator is used in parallel at the same time. --- src/include/utils/llist.h | 17 ++++++++++++++++- src/utils/llist.c | 24 ++++++++++++++++++++++++ t/utils/llist_test.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/src/include/utils/llist.h b/src/include/utils/llist.h index 104c9e4..2742139 100644 --- a/src/include/utils/llist.h +++ b/src/include/utils/llist.h @@ -173,7 +173,8 @@ sdb_llist_remove(sdb_llist_t *list, sdb_object_t * sdb_llist_shift(sdb_llist_t *list); -/* sdb_llist_get_iter, sdb_llist_iter_has_next, sdb_llist_iter_get_next: +/* + * sdb_llist_get_iter, sdb_llist_iter_has_next, sdb_llist_iter_get_next: * Iterate through the list, element by element. * * sdb_llist_iter_get_next returns NULL if there is no next element. @@ -188,6 +189,20 @@ sdb_llist_iter_has_next(sdb_llist_iter_t *iter); sdb_object_t * sdb_llist_iter_get_next(sdb_llist_iter_t *iter); +/* + * sdb_llist_iter_remove_current: + * Remove the current object from the list, that is, the object which was + * returned by the last call to sdb_llist_iter_get_next(). + * + * This operation is not safe if another iterator is in use at the same time. + * + * Returns: + * - 0 on success + * - a negative value else + */ +int +sdb_llist_iter_remove_current(sdb_llist_iter_t *iter); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/utils/llist.c b/src/utils/llist.c index 0af9c8c..0a4665d 100644 --- a/src/utils/llist.c +++ b/src/utils/llist.c @@ -434,5 +434,29 @@ sdb_llist_iter_get_next(sdb_llist_iter_t *iter) return obj; } /* sdb_llist_iter_get_next */ +int +sdb_llist_iter_remove_current(sdb_llist_iter_t *iter) +{ + sdb_llist_elem_t *elem; + + if ((! iter) || (! iter->list)) + return -1; + + pthread_rwlock_wrlock(&iter->list->lock); + + if (! iter->elem) /* reached end of list */ + elem = iter->list->tail; + else + elem = iter->elem->prev; + if (elem) + sdb_llist_remove_elem(iter->list, elem); + + pthread_rwlock_unlock(&iter->list->lock); + + if (! elem) + return -1; + return 0; +} /* sdb_llist_iter_remove */ + /* vim: set tw=78 sw=4 ts=4 noexpandtab : */ diff --git a/t/utils/llist_test.c b/t/utils/llist_test.c index 638d2fb..ede8200 100644 --- a/t/utils/llist_test.c +++ b/t/utils/llist_test.c @@ -233,6 +233,41 @@ START_TEST(test_sdb_llist_iter) } END_TEST +START_TEST(test_sdb_llist_iter_remove) +{ + sdb_llist_iter_t *iter; + sdb_object_t *check; + size_t i; + + populate(); + + iter = sdb_llist_get_iter(list); + fail_unless(iter != NULL, + "sdb_llist_get_iter() did not return an iterator"); + + i = 0; + while (sdb_llist_iter_has_next(iter)) { + check = sdb_llist_iter_get_next(iter); + fail_unless(check == &golden_data[i], + "sdb_llist_iter_get_next() = %p; expected: %p", + check, &golden_data[i]); + + sdb_llist_iter_remove_current(iter); + ++i; + } + sdb_llist_iter_destroy(iter); + + fail_unless(i == (size_t)SDB_STATIC_ARRAY_LEN(golden_data), + "iterated for %zu steps; expected: %i", + i, SDB_STATIC_ARRAY_LEN(golden_data)); + + /* all elements should be removed */ + check = sdb_llist_shift(list); + fail_unless(check == NULL, + "sdb_llist_shift() = %p; expected: NULL", check); +} +END_TEST + Suite * util_llist_suite(void) { @@ -249,6 +284,7 @@ util_llist_suite(void) tcase_add_test(tc, test_sdb_llist_search); tcase_add_test(tc, test_sdb_llist_shift); tcase_add_test(tc, test_sdb_llist_iter); + tcase_add_test(tc, test_sdb_llist_iter_remove); suite_add_tcase(s, tc); return s; -- 2.30.2