eina_iterator: add new api to have a filtered iterator

Summary:
the new iterator represents the order from the elements of the original
iterator, elements where the filter callback return false will be
skipped.

The container of this iterator is the original iterator.

Test Plan: Just run `make check` there is a testcase

Reviewers: cedric, jpeg, raster, herdsman

Differential Revision: https://phab.enlightenment.org/D4417
This commit is contained in:
Marcel Hollerbach 2016-11-20 15:24:26 +01:00
parent 36862e13ec
commit c34e4b6312
3 changed files with 137 additions and 0 deletions

View File

@ -228,3 +228,62 @@ eina_carray_iterator_new(void** array)
return &it->iterator;
}
typedef struct {
Eina_Iterator iterator;
void *data;
Eina_Iterator *original;
Eina_Each_Cb cb;
} Eina_Iterator_Filter;
static Eina_Bool
eina_iterator_filter_next(Eina_Iterator_Filter *it, void **data)
{
do
{
if (!eina_iterator_next(it->original , data))
return EINA_FALSE;
}
while (!it->cb(it->original, *data, it->data));
return EINA_TRUE;
}
static void*
eina_iterator_filter_get_container(Eina_Iterator_Filter *it)
{
return it->original;
}
static void
eina_iterator_filter_free(Eina_Iterator_Filter *it)
{
eina_iterator_free(it->original);
free(it);
}
EAPI Eina_Iterator*
eina_iterator_filter_new(Eina_Iterator *iterator, Eina_Each_Cb filter, void *data)
{
Eina_Iterator_Filter *it;
EINA_SAFETY_ON_NULL_RETURN_VAL(iterator, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(filter, NULL);
it = calloc(1, sizeof(Eina_Iterator_Filter));
it->original = iterator;
it->data = data;
it->cb = filter;
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
it->iterator.version = EINA_ITERATOR_VERSION;
it->iterator.next = FUNC_ITERATOR_NEXT(eina_iterator_filter_next);
it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
eina_iterator_filter_get_container);
it->iterator.free = FUNC_ITERATOR_FREE(eina_iterator_filter_free);
return &it->iterator;
}

View File

@ -300,6 +300,20 @@ EAPI Eina_Bool eina_iterator_unlock(Eina_Iterator *iterator) EINA_ARG_NONNULL(1)
*/
EAPI Eina_Iterator* eina_carray_iterator_new(void** array) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
/**
* @brief Creates a new iterator which which iterates throuw all elements with are accepted by the filter callback
*
* @param original the iterator the use as original set
* @param filter if the callback returns true the element from the original set is taken into the the new set.
* @param data the data which is passed to the filter callback
*
* The iterator is filtered while it is beeing iterated.
* The original iterator you pass in here is is then owned and will be freed once the the new iterator is freed.
*
* @since 1.19
*/
EAPI Eina_Iterator* eina_iterator_filter_new(Eina_Iterator *original, Eina_Each_Cb filter, void *data) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
/**
* @def EINA_ITERATOR_FOREACH
* @brief Macro to iterate over all elements easily.

View File

@ -26,6 +26,69 @@
#include "eina_suite.h"
struct Number{
int number;
};
static Eina_Bool
_filter(const void *it EINA_UNUSED, void *data, void *fdata)
{
struct Number *numb = data;
ck_assert_ptr_eq(fdata, (void*)1);
return numb->number % 2;
}
START_TEST(eina_iterator_filter_simple)
{
Eina_Iterator *it, *filtered;
Eina_Array *ea;
eina_init();
ea = eina_array_new(11);
fail_if(!ea);
for(int i = 0; i <= 10; i++)
{
struct Number *number;
number = calloc(1, sizeof(struct Number));
number->number = i;
eina_array_push(ea, number);
}
it = eina_array_iterator_new(ea);
filtered = eina_iterator_filter_new(it, _filter, (void*)1);
for(int i = 1; i <= 10; i+=2)
{
struct Number *numb;
Eina_Bool ret;
ret = eina_iterator_next(filtered, (void**)&numb);
fail_if(!ret);
ck_assert_int_eq(numb->number, i);
}
{
struct Number *numb;
Eina_Bool ret;
ret = eina_iterator_next(filtered, (void**)&numb);
fail_if(ret);
}
eina_iterator_free(it);
eina_array_free(ea);
eina_shutdown();
}
END_TEST
static Eina_Bool
eina_iterator_array_check(EINA_UNUSED const Eina_Array *array,
int *data, int *fdata)
@ -529,4 +592,5 @@ eina_test_iterator(TCase *tc)
tcase_add_test(tc, eina_iterator_list_simple);
tcase_add_test(tc, eina_reverse_iterator_list_simple);
tcase_add_test(tc, eina_iterator_rbtree_simple);
tcase_add_test(tc, eina_iterator_filter_simple);
}