diff --git a/include/ucore/htable.h b/include/ucore/htable.h index 29d935e..5c73563 100644 --- a/include/ucore/htable.h +++ b/include/ucore/htable.h @@ -48,7 +48,7 @@ struct UHTable { int uc_htable_init(struct UHTable *table, size_t buckets); /** - * Frees resources of the hash table. + * Free resources of the hash table. * @param table hash table to free (does not free @table itself */ void uc_htable_destroy(struct UHTable *table); @@ -201,6 +201,15 @@ void uc_htable_clear(struct UHTable *table); */ void uc_htable_insert(struct UHTable *table, struct UHNode *node, size_t hash); +/** Remove a node. + * If the node pointer is not part of the table, + * no action is taken + * + * @param table table to remove from. + * @param node node to remove. + */ +void uc_htable_remove(struct UHTable *table, struct UHNode *node); + /** Resize the hash table. This changes the number of buckets, and re-inserts * all nodes. * diff --git a/src/htable.c b/src/htable.c index fbc2c4e..3fab8e6 100644 --- a/src/htable.c +++ b/src/htable.c @@ -113,6 +113,22 @@ void uc_htable_insert(struct UHTable *table, struct UHNode *node, size_t hash) table->cnt_elements++; } +void uc_htable_remove(struct UHTable *table, struct UHNode *node) +{ + struct UHNode **it = &table->buckets[uc_htable_bucket(table, node->hash)]; + + while (*it) { + + if (*it == node) { + *it = (*it)->next; + table->cnt_elements--; + break; + } + + it = &(*it)->next; + } +} + int uc_htable_resize(struct UHTable *table, size_t buckets) { struct UHTable tmp_table; diff --git a/test/test_htable.c b/test/test_htable.c index ad3814c..523a34e 100644 --- a/test/test_htable.c +++ b/test/test_htable.c @@ -163,6 +163,49 @@ START_TEST (test_htable_has_node) END_TEST +START_TEST (test_htable_remove) + struct MyString str1 = {"One", {0,NULL}}; + struct MyString str2 = {"One", {0,NULL}}; + struct MyString str3 = {"Other", {0,NULL}}; + + struct UHTable table; + int rc; + + 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); + + uc_htable_remove(&table, &str2.node); + ck_assert_int_eq(uc_htable_count(&table), 2); + + //this one should still be here + fail_if(my_find(&table, "One", hash_str("One")) != &str1); + // + //thisone should be gone + rc = uc_htable_has_node(&table, &str2.node); + ck_assert_int_eq(rc, 0); + + + uc_htable_remove(&table, &str1.node); + ck_assert_int_eq(uc_htable_count(&table), 1); + + //now this one should be gone + rc = uc_htable_has_node(&table, &str1.node); + ck_assert_int_eq(rc, 0); + + //double removal should be ok + uc_htable_remove(&table, &str1.node); + ck_assert_int_eq(uc_htable_count(&table), 1); + + //this one should still be here + fail_if(my_find(&table, "Other", hash_str("Other")) != &str3); + +END_TEST + Suite *htable_suite(void) { Suite *s = suite_create("htable"); @@ -173,6 +216,7 @@ Suite *htable_suite(void) tcase_add_test(tc, test_htable_resize); tcase_add_test(tc, test_htable_fail_init_resize); tcase_add_test(tc, test_htable_has_node); + tcase_add_test(tc, test_htable_remove); suite_add_tcase(s, tc);