diff --git a/include/igloo/list.h b/include/igloo/list.h index 0405ba4..bd81a90 100644 --- a/include/igloo/list.h +++ b/include/igloo/list.h @@ -79,6 +79,12 @@ igloo_ro_t igloo_list_pop(igloo_list_t *list); /* Merge the content of the list elements into the list list. The list elements is not changed. */ int igloo_list_merge(igloo_list_t *list, igloo_list_t *elements); +/* Remove a single element from the list. + * Note: This is not very efficient as the list is first searched for the element + * and then reorganized so there is no gap. + */ +int igloo_list_remove(igloo_list_t *list, igloo_ro_t element); + /* Creates a new iterator that can be used to walk the list. * The memory pointed to by storage of size storage_length is used to store the iterator's internal * values. It must be allocated (e.g. on stack) untill igloo_list_iterator_end() is called. diff --git a/include/igloo/ro.h b/include/igloo/ro.h index 01a428c..cedc44b 100644 --- a/include/igloo/ro.h +++ b/include/igloo/ro.h @@ -273,6 +273,8 @@ int igloo_RO_IS_VALID_raw(igloo_ro_t object, const igloo_ro_type_t * int igloo_RO_HAS_TYPE_raw(igloo_ro_t object, const igloo_ro_type_t *type); #define igloo_RO_HAS_TYPE(x,type) igloo_RO_HAS_TYPE_raw((x), (type)) +#define igloo_RO_IS_SAME(a,b) (igloo_RO__GETBASE((a)) == igloo_RO__GETBASE((b))) + /* Create a new refobject * The type argument gives the type for the new object, * the name for the object is given by name, and diff --git a/src/list.c b/src/list.c index b782bab..d8a7e4c 100644 --- a/src/list.c +++ b/src/list.c @@ -394,6 +394,25 @@ int igloo_list_merge(igloo_list_t *list, igloo_list_t *eleme return 0; } +int igloo_list_remove(igloo_list_t *list, igloo_ro_t element) +{ + size_t i; + + if (!igloo_RO_IS_VALID(list, igloo_list_t) || igloo_RO_IS_NULL(element)) + return -1; + + for (i = list->offset; i < list->fill; i++) { + if (igloo_RO_IS_SAME(list->elements[i], element)) { + igloo_ro_unref(list->elements[i]); + memmove(list->elements + i, list->elements + i + 1, (list->fill - i - 1)*sizeof(*list->elements)); + list->fill--; + return 0; + } + } + + return -1; +} + igloo_list_iterator_t * igloo_list_iterator_start(igloo_list_t *list, void *storage, size_t storage_length) { igloo_list_iterator_t *iterator; diff --git a/src/tests/ctest_list.c b/src/tests/ctest_list.c index ceddfe5..9e9dffe 100644 --- a/src/tests/ctest_list.c +++ b/src/tests/ctest_list.c @@ -550,6 +550,43 @@ static void test_list_policy_fixed_pipe_merge(void) { ctest_test("un-referenced dstlist", igloo_ro_unref(dstlist) == 0); } +static void test_list_remove(void) { + igloo_list_t *list; + igloo_ro_base_t *element; + igloo_ro_base_t *second_element = NULL; + size_t i; + size_t count = 0; + + list = igloo_ro_new(igloo_list_t); + ctest_test("list created", !igloo_RO_IS_NULL(list)); + + for (i = 0; i < 4; i++) { + element = igloo_ro_new(igloo_ro_base_t); + ctest_test("test object created", !igloo_RO_IS_NULL(element)); + ctest_test("test object pushed", igloo_list_push(list, element) == 0); + + if (i == 1) { + second_element = element; + ctest_test("referenced 2nd test object", igloo_ro_ref(second_element) == 0); + } + + ctest_test("un-referenced test object", igloo_ro_unref(element) == 0); + } + + ctest_test("2nd element was removed", igloo_list_remove(list, second_element) == 0); + + igloo_list_foreach(list, igloo_ro_base_t, ret, { + ctest_test("Returned element is valid", igloo_RO_IS_VALID(ret, igloo_ro_base_t)); + ctest_test("Returned element is not same as 2nd element", !igloo_RO_IS_SAME(ret, second_element)); + count++; + }); + + ctest_test("Number of returned elements is correct", count == 3); + + ctest_test("un-referenced 2nd test object", igloo_ro_unref(second_element) == 0); + ctest_test("un-referenced list", igloo_ro_unref(list) == 0); +} + int main (void) { ctest_init(); @@ -578,6 +615,8 @@ int main (void) test_list_policy_fixed_pipe_unshift(); test_list_policy_fixed_pipe_merge(); + test_list_remove(); + ctest_fin(); return 0;