Add FOREACH_SAFE macros + tests

This commit is contained in:
Nils O. Selåsdal
2013-10-24 22:13:16 +02:00
parent 45ecb3c1e0
commit 0acb4789b0
2 changed files with 104 additions and 1 deletions
+30
View File
@@ -168,6 +168,21 @@ void uc_htable_swap(struct UHTable *a, struct UHTable *b);
(node_iter) != NULL;\ (node_iter) != NULL;\
(node_iter) = uc_htable_next_hash((node_iter))) (node_iter) = uc_htable_next_hash((node_iter)))
/**
* "Safe" variant of UC_HTABLE_FOREACH_HASH, the iterated node
* (or any previously iterated nodes) can be freed while iterating
*
* @param table the struct UHTable*
* @param node_iter struct UHNode* for the current node being iterated
* @param next_iter struct UHNode* for the next node, required by the
* iteration, next_iter must not be altered while iterating.
* @param hash size_t hash for the node(s) to iterate over
*/
#define UC_HTABLE_FOREACH_HASH_SAFE(table, node_iter, next_iter, hash)\
for ((node_iter) = uc_htable_first_hash((table), (hash));\
(node_iter) != NULL && (((next_iter) = (node_iter->next)), 1);\
(node_iter) = (next))
/** /**
* Iterate over all nodes in a table * Iterate over all nodes in a table
* The table must not be changed while iterating. * The table must not be changed while iterating.
@@ -180,6 +195,21 @@ void uc_htable_swap(struct UHTable *a, struct UHTable *b);
(node_iter) != NULL;\ (node_iter) != NULL;\
(node_iter) = uc_htable_next((table), (node_iter))) (node_iter) = uc_htable_next((table), (node_iter)))
/**
* "Safe" variant of UC_HTABLE_FOREACH, the iterated node
* (or any previously iterated nodes) can be freed while iterating
*
* @param table the struct UHTable*
* @param node_iter struct UHNode* for the current node being iterated
* @param next_iter struct UHNode* for the next node, required by the
* iteration, next_iter must not be altered while iterating.
*/
#define UC_HTABLE_FOREACH_SAFE(table, node_iter, next_iter)\
for ((node_iter) = uc_htable_first((table));\
(node_iter) != NULL &&\
((next_iter) = uc_htable_next((table), (node_iter)), 1);\
(node_iter) = (next))
/** /**
* Check if the given node pointer exists in the hash table * Check if the given node pointer exists in the hash table
+73
View File
@@ -218,6 +218,43 @@ START_TEST (test_htable_remove)
END_TEST END_TEST
START_TEST (test_htable_remove_foreach)
struct MyString str1 = {"One", {0,NULL}};
struct MyString str2 = {"One", {0,NULL}};
struct MyString str3 = {"Other", {0,NULL}};
struct UHTable table;
struct UHNode *it;
struct UHNode *next;
int rc;
int removed = 0;
rc = uc_htable_init(&table, 1);
ck_assert_int_eq(rc, 0);
uc_htable_insert(&table, &str1.node, hash_str(str1.str));
uc_htable_insert(&table, &str2.node, hash_str(str2.str));
uc_htable_insert(&table, &str3.node, hash_str(str3.str));
ck_assert_int_eq(uc_htable_count(&table), 3);
fail_if(my_find(&table, "One", hash_str("One")) == NULL);
UC_HTABLE_FOREACH_HASH_SAFE(&table, it, next, hash_str("One")) {
uc_htable_remove(&table, it);
removed++;
}
ck_assert_int_eq(removed, 2);
fail_if(my_find(&table, "One", hash_str("One")) != NULL);
fail_if(my_find(&table, "Other", hash_str("Other")) != &str3);
ck_assert_int_eq(uc_htable_count(&table), 1);
uc_htable_destroy(&table);
END_TEST
START_TEST (test_htable_clear) START_TEST (test_htable_clear)
struct MyString str1 = {"One", {0,NULL}}; struct MyString str1 = {"One", {0,NULL}};
@@ -282,6 +319,40 @@ START_TEST (test_htable_foreach)
END_TEST END_TEST
START_TEST (test_htable_foreach_safe)
struct MyString str1 = {"One", {0,NULL}};
struct MyString str2 = {"One", {0,NULL}};
struct MyString str3 = {"Other",{0,NULL}};
struct UHTable table;
struct UHNode *it;
struct UHNode *next;
int rc;
rc = uc_htable_init(&table, 1000);
ck_assert_int_eq(rc, 0);
uc_htable_insert(&table, &str1.node, hash_str(str1.str));
uc_htable_insert(&table, &str2.node, hash_str(str2.str));
uc_htable_insert(&table, &str3.node, hash_str(str3.str));
fail_if(my_find(&table, "Other", hash_str("Other")) != &str3);
ck_assert_int_eq(uc_htable_count(&table), 3);
UC_HTABLE_FOREACH_SAFE(&table, it, next) {
uc_htable_remove(&table, it);
}
fail_if(my_find(&table, "One", hash_str("One")) != NULL);
fail_if(my_find(&table, "Other", hash_str("Other")) != NULL);
ck_assert_int_eq(uc_htable_count(&table), 0);
uc_htable_destroy(&table);
END_TEST
Suite *htable_suite(void) Suite *htable_suite(void)
{ {
Suite *s = suite_create("htable"); Suite *s = suite_create("htable");
@@ -293,8 +364,10 @@ Suite *htable_suite(void)
tcase_add_test(tc, test_htable_fail_init_resize); tcase_add_test(tc, test_htable_fail_init_resize);
tcase_add_test(tc, test_htable_has_node); tcase_add_test(tc, test_htable_has_node);
tcase_add_test(tc, test_htable_remove); tcase_add_test(tc, test_htable_remove);
tcase_add_test(tc, test_htable_remove_foreach);
tcase_add_test(tc, test_htable_clear); tcase_add_test(tc, test_htable_clear);
tcase_add_test(tc, test_htable_foreach); tcase_add_test(tc, test_htable_foreach);
tcase_add_test(tc, test_htable_foreach_safe);
suite_add_tcase(s, tc); suite_add_tcase(s, tc);