summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hollerbach <mail@marcel-hollerbach.de>2020-01-10 16:35:57 +0100
committerMarcel Hollerbach <mail@marcel-hollerbach.de>2020-02-19 16:34:05 +0100
commit74491e8781d87b4321470bea5414a3a750a695e8 (patch)
tree725384661c6ec8d602ac8cbb4d9ffe712b24febb
parentc9c540b9df90f5b2867da3b5c4dcb69310f89623 (diff)
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
-rw-r--r--src/lib/eina/eina_iterator.c59
-rw-r--r--src/lib/eina/eina_iterator.h18
-rw-r--r--src/lib/eina/eina_types.h12
-rw-r--r--src/tests/eina/eina_test_iterator.c44
4 files changed, 133 insertions, 0 deletions
diff --git a/src/lib/eina/eina_iterator.c b/src/lib/eina/eina_iterator.c
index 1043a9c6e0..26d05f4045 100644
--- a/src/lib/eina/eina_iterator.c
+++ b/src/lib/eina/eina_iterator.c
@@ -429,3 +429,62 @@ eina_iterator_filter_new(Eina_Iterator *iterator, Eina_Each_Cb filter, Eina_Free
429 429
430 return &it->iterator; 430 return &it->iterator;
431} 431}
432
433typedef struct {
434 Eina_Iterator iterator;
435
436 void *data;
437 Eina_Iterator *original;
438 Eina_Process_Cb cb;
439 Eina_Free_Cb free;
440} Eina_Iterator_Processor;
441
442static Eina_Bool
443eina_iterator_process_next(Eina_Iterator_Processor *it, void **data)
444{
445 if (!eina_iterator_next(it->original, data))
446 return EINA_FALSE;
447
448 *data = it->cb(it->original, *data, it->data);
449
450 return EINA_TRUE;
451}
452
453static void*
454eina_iterator_process_get_container(Eina_Iterator_Processor *it)
455{
456 return it->original;
457}
458
459static void
460eina_iterator_process_free(Eina_Iterator_Processor *it)
461{
462 if (it->free)
463 it->free(it->data);
464 eina_iterator_free(it->original);
465 free(it);
466}
467
468EAPI Eina_Iterator*
469eina_iterator_processed_new(Eina_Iterator *iterator, Eina_Process_Cb process, Eina_Free_Cb free_cb, void *data)
470{
471 Eina_Iterator_Processor *it;
472
473 EINA_SAFETY_ON_NULL_RETURN_VAL(iterator, NULL);
474 EINA_SAFETY_ON_NULL_RETURN_VAL(process, NULL);
475
476 it = calloc(1, sizeof(Eina_Iterator_Processor));
477 it->data = data;
478 it->cb = process;
479 it->free = free_cb;
480 it->original = iterator;
481
482 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
483
484 it->iterator.version = EINA_ITERATOR_VERSION;
485 it->iterator.next = FUNC_ITERATOR_NEXT(eina_iterator_process_next);
486 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(eina_iterator_process_get_container);
487 it->iterator.free = FUNC_ITERATOR_FREE(eina_iterator_process_free);
488
489 return &it->iterator;
490}
diff --git a/src/lib/eina/eina_iterator.h b/src/lib/eina/eina_iterator.h
index cb254c7e8e..21194d59c3 100644
--- a/src/lib/eina/eina_iterator.h
+++ b/src/lib/eina/eina_iterator.h
@@ -365,6 +365,24 @@ EAPI Eina_Iterator* eina_iterator_filter_new(Eina_Iterator *original, Eina_Each_
365 */ 365 */
366EAPI Eina_Iterator *eina_multi_iterator_internal_new(Eina_Iterator *it, ...) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT; 366EAPI Eina_Iterator *eina_multi_iterator_internal_new(Eina_Iterator *it, ...) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
367 367
368
369/**
370 * @brief Calls the process method on each node of iterator, producing new "processed"
371 * nodes and returning a new iterator which contains them.
372 *
373 * @param[in] original Iterator containing the nodes to process.
374 * @param[in] process Method to call on each node.
375 * @param[in] free_cb Method called when all nodes have been processed. It receives "data" as a parameter.
376 * @param[in] data Additional data passed to the process method.
377 *
378 * Processes every node in the input iterator and returns a new iterator containing
379 * the processed nodes. This is akin to a Map function:
380 * @see https://en.wikipedia.org/wiki/Map_(higher-order_function)
381 *
382 * @since 1.24
383 */
384EAPI Eina_Iterator* eina_iterator_processed_new(Eina_Iterator *iterator, Eina_Process_Cb process, Eina_Free_Cb free_cb, void *fdata) EINA_WARN_UNUSED_RESULT;
385
368/** 386/**
369 * @def eina_multi_iterator_new 387 * @def eina_multi_iterator_new
370 * @brief Creates an Eina_Iterator that iterates through a series 388 * @brief Creates an Eina_Iterator that iterates through a series
diff --git a/src/lib/eina/eina_types.h b/src/lib/eina/eina_types.h
index c049baf4dd..ad797d3d91 100644
--- a/src/lib/eina/eina_types.h
+++ b/src/lib/eina/eina_types.h
@@ -540,6 +540,18 @@ typedef int (*Eina_Random_Cb)(const int min, const int max);
540#define EINA_RANDOM_CB(function) ((Eina_Random_Cb)function) 540#define EINA_RANDOM_CB(function) ((Eina_Random_Cb)function)
541 541
542/** 542/**
543 * @typedef Eina_Process_Cb
544 * Method that processes some data and returns new data.
545 * It's meant to be used as a callback to process all nodes inside a container (See eina_iterator_processed_new, for example.)
546 */
547typedef void* (*Eina_Process_Cb)(const void *container, void *data, void *fdata);
548
549/**
550 * @def EINA_PROCESS_CB
551 * Macro to cast to Eina_Process.
552 */
553#define EINA_PROCESS_CB(Function) ((Eina_Process_Cb)Function)
554/**
543 * @typedef Eina_Each_Cb 555 * @typedef Eina_Each_Cb
544 * A callback type used when iterating over a container. 556 * A callback type used when iterating over a container.
545 */ 557 */
diff --git a/src/tests/eina/eina_test_iterator.c b/src/tests/eina/eina_test_iterator.c
index 28fe0dfc5b..8eb37f2488 100644
--- a/src/tests/eina/eina_test_iterator.c
+++ b/src/tests/eina/eina_test_iterator.c
@@ -654,6 +654,49 @@ EFL_START_TEST(eina_iterator_multi)
654} 654}
655EFL_END_TEST 655EFL_END_TEST
656 656
657static void*
658_return_x(const void *container EINA_UNUSED, void *data, void *fdata)
659{
660 Eina_Rectangle *rect = data;
661 ck_assert_int_eq(*((int*)fdata), 1337);
662
663 return &rect->x;
664}
665
666static void
667_free_cb(void *data)
668{
669 int *free_data = data;
670
671 *free_data = 0;
672}
673
674EFL_START_TEST(eina_iterator_process)
675{
676 Eina_Inarray *rects = eina_inarray_new(sizeof(Eina_Rectangle), 5);
677 Eina_Rectangle rect_arr[] = {{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}, {12, 13, 14, 15}, {16, 17, 18, 19}};
678 Eina_Iterator *it;
679 int free = 1337;
680 int *a, i = 0;
681
682 eina_inarray_push(rects, &rect_arr[0]);
683 eina_inarray_push(rects, &rect_arr[1]);
684 eina_inarray_push(rects, &rect_arr[2]);
685 eina_inarray_push(rects, &rect_arr[3]);
686 eina_inarray_push(rects, &rect_arr[4]);
687
688 it = eina_iterator_processed_new(eina_inarray_iterator_new(rects), _return_x, _free_cb, &free);
689 EINA_ITERATOR_FOREACH(it, a)
690 {
691 ck_assert_int_eq(*a, i*4);
692 i++;
693 }
694 ck_assert_int_eq(i, 5);
695 eina_iterator_free(it);
696 ck_assert_int_eq(free, 0);
697}
698EFL_END_TEST
699
657void 700void
658eina_test_iterator(TCase *tc) 701eina_test_iterator(TCase *tc)
659{ 702{
@@ -667,4 +710,5 @@ eina_test_iterator(TCase *tc)
667 tcase_add_test(tc, eina_iterator_filter_free); 710 tcase_add_test(tc, eina_iterator_filter_free);
668 tcase_add_test(tc, eina_iterator_carray_length); 711 tcase_add_test(tc, eina_iterator_carray_length);
669 tcase_add_test(tc, eina_iterator_multi); 712 tcase_add_test(tc, eina_iterator_multi);
713 tcase_add_test(tc, eina_iterator_process);
670} 714}