eina: introduce eina_iterator_process

this brings a functional-map function to the iterator implementations.
https://en.wikipedia.org/wiki/Map_(higher-order_function)

Reviewed-by: Cedric BAIL <cedric.bail@free.fr>
Differential Revision: https://phab.enlightenment.org/D11062
This commit is contained in:
Marcel Hollerbach 2020-01-10 16:35:57 +01:00
parent c9c540b9df
commit 74491e8781
4 changed files with 133 additions and 0 deletions

View File

@ -429,3 +429,62 @@ eina_iterator_filter_new(Eina_Iterator *iterator, Eina_Each_Cb filter, Eina_Free
return &it->iterator;
}
typedef struct {
Eina_Iterator iterator;
void *data;
Eina_Iterator *original;
Eina_Process_Cb cb;
Eina_Free_Cb free;
} Eina_Iterator_Processor;
static Eina_Bool
eina_iterator_process_next(Eina_Iterator_Processor *it, void **data)
{
if (!eina_iterator_next(it->original, data))
return EINA_FALSE;
*data = it->cb(it->original, *data, it->data);
return EINA_TRUE;
}
static void*
eina_iterator_process_get_container(Eina_Iterator_Processor *it)
{
return it->original;
}
static void
eina_iterator_process_free(Eina_Iterator_Processor *it)
{
if (it->free)
it->free(it->data);
eina_iterator_free(it->original);
free(it);
}
EAPI Eina_Iterator*
eina_iterator_processed_new(Eina_Iterator *iterator, Eina_Process_Cb process, Eina_Free_Cb free_cb, void *data)
{
Eina_Iterator_Processor *it;
EINA_SAFETY_ON_NULL_RETURN_VAL(iterator, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(process, NULL);
it = calloc(1, sizeof(Eina_Iterator_Processor));
it->data = data;
it->cb = process;
it->free = free_cb;
it->original = iterator;
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
it->iterator.version = EINA_ITERATOR_VERSION;
it->iterator.next = FUNC_ITERATOR_NEXT(eina_iterator_process_next);
it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(eina_iterator_process_get_container);
it->iterator.free = FUNC_ITERATOR_FREE(eina_iterator_process_free);
return &it->iterator;
}

View File

@ -365,6 +365,24 @@ EAPI Eina_Iterator* eina_iterator_filter_new(Eina_Iterator *original, Eina_Each_
*/
EAPI Eina_Iterator *eina_multi_iterator_internal_new(Eina_Iterator *it, ...) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
/**
* @brief Calls the process method on each node of iterator, producing new "processed"
* nodes and returning a new iterator which contains them.
*
* @param[in] original Iterator containing the nodes to process.
* @param[in] process Method to call on each node.
* @param[in] free_cb Method called when all nodes have been processed. It receives "data" as a parameter.
* @param[in] data Additional data passed to the process method.
*
* Processes every node in the input iterator and returns a new iterator containing
* the processed nodes. This is akin to a Map function:
* @see https://en.wikipedia.org/wiki/Map_(higher-order_function)
*
* @since 1.24
*/
EAPI Eina_Iterator* eina_iterator_processed_new(Eina_Iterator *iterator, Eina_Process_Cb process, Eina_Free_Cb free_cb, void *fdata) EINA_WARN_UNUSED_RESULT;
/**
* @def eina_multi_iterator_new
* @brief Creates an Eina_Iterator that iterates through a series

View File

@ -539,6 +539,18 @@ typedef int (*Eina_Random_Cb)(const int min, const int max);
*/
#define EINA_RANDOM_CB(function) ((Eina_Random_Cb)function)
/**
* @typedef Eina_Process_Cb
* Method that processes some data and returns new data.
* It's meant to be used as a callback to process all nodes inside a container (See eina_iterator_processed_new, for example.)
*/
typedef void* (*Eina_Process_Cb)(const void *container, void *data, void *fdata);
/**
* @def EINA_PROCESS_CB
* Macro to cast to Eina_Process.
*/
#define EINA_PROCESS_CB(Function) ((Eina_Process_Cb)Function)
/**
* @typedef Eina_Each_Cb
* A callback type used when iterating over a container.

View File

@ -654,6 +654,49 @@ EFL_START_TEST(eina_iterator_multi)
}
EFL_END_TEST
static void*
_return_x(const void *container EINA_UNUSED, void *data, void *fdata)
{
Eina_Rectangle *rect = data;
ck_assert_int_eq(*((int*)fdata), 1337);
return &rect->x;
}
static void
_free_cb(void *data)
{
int *free_data = data;
*free_data = 0;
}
EFL_START_TEST(eina_iterator_process)
{
Eina_Inarray *rects = eina_inarray_new(sizeof(Eina_Rectangle), 5);
Eina_Rectangle rect_arr[] = {{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}, {12, 13, 14, 15}, {16, 17, 18, 19}};
Eina_Iterator *it;
int free = 1337;
int *a, i = 0;
eina_inarray_push(rects, &rect_arr[0]);
eina_inarray_push(rects, &rect_arr[1]);
eina_inarray_push(rects, &rect_arr[2]);
eina_inarray_push(rects, &rect_arr[3]);
eina_inarray_push(rects, &rect_arr[4]);
it = eina_iterator_processed_new(eina_inarray_iterator_new(rects), _return_x, _free_cb, &free);
EINA_ITERATOR_FOREACH(it, a)
{
ck_assert_int_eq(*a, i*4);
i++;
}
ck_assert_int_eq(i, 5);
eina_iterator_free(it);
ck_assert_int_eq(free, 0);
}
EFL_END_TEST
void
eina_test_iterator(TCase *tc)
{
@ -667,4 +710,5 @@ eina_test_iterator(TCase *tc)
tcase_add_test(tc, eina_iterator_filter_free);
tcase_add_test(tc, eina_iterator_carray_length);
tcase_add_test(tc, eina_iterator_multi);
tcase_add_test(tc, eina_iterator_process);
}