diff --git a/legacy/eina/src/include/eina_inline_list.x b/legacy/eina/src/include/eina_inline_list.x index 71feb4e2d7..d8e40125b5 100644 --- a/legacy/eina/src/include/eina_inline_list.x +++ b/legacy/eina/src/include/eina_inline_list.x @@ -47,7 +47,7 @@ eina_list_data(const Eina_List *list) return list->data; } -static inline int +static inline unsigned int eina_list_count(const Eina_List *list) { if (!list) return 0; diff --git a/legacy/eina/src/include/eina_list.h b/legacy/eina/src/include/eina_list.h index 9efd9d735c..9d07647756 100644 --- a/legacy/eina/src/include/eina_list.h +++ b/legacy/eina/src/include/eina_list.h @@ -22,6 +22,8 @@ #include #include "eina_types.h" +#include "eina_iterator.h" +#include "eina_accessor.h" /** * @defgroup List_Group List @@ -41,7 +43,7 @@ struct _Eina_List /** A linked list node */ struct _Eina_List_Accounting { Eina_List *last; - int count; + unsigned int count; }; @@ -60,16 +62,21 @@ EAPI Eina_List *eina_list_promote_list (Eina_List *list, Eina_List *move_list); EAPI void *eina_list_find(const Eina_List *list, const void *data); EAPI Eina_List *eina_list_find_list (const Eina_List *list, const void *data); EAPI Eina_List *eina_list_free (Eina_List *list); -EAPI void *eina_list_nth(const Eina_List *list, int n); -EAPI Eina_List *eina_list_nth_list (const Eina_List *list, int n); +EAPI void *eina_list_nth(const Eina_List *list, unsigned int n); +EAPI Eina_List *eina_list_nth_list (const Eina_List *list, unsigned int n); EAPI Eina_List *eina_list_reverse (Eina_List *list); -EAPI Eina_List *eina_list_sort (Eina_List *list, int size, int(*func)(void*,void*)); +EAPI Eina_List *eina_list_sort (Eina_List *list, unsigned int size, int(*func)(void*,void*)); static inline Eina_List *eina_list_last (const Eina_List *list); static inline Eina_List *eina_list_next (const Eina_List *list); static inline Eina_List *eina_list_prev (const Eina_List *list); static inline void *eina_list_data(const Eina_List *list); -static inline int eina_list_count(const Eina_List *list); +static inline unsigned int eina_list_count(const Eina_List *list); + +EAPI Eina_Iterator *eina_list_iterator_new(const Eina_List *list); +EAPI Eina_Accessor *eina_list_accessor_new(const Eina_List *list); + +#define EINA_LIST_ITER_NEXT(list, l, data) for (l = list, data = eina_list_data(l); l; l = eina_list_next(l), data = eina_list_data(l)) /** @} */ #include "eina_inline_list.x" diff --git a/legacy/eina/src/lib/eina_list.c b/legacy/eina/src/lib/eina_list.c index 553cf1e7ac..b1f700ca90 100644 --- a/legacy/eina/src/lib/eina_list.c +++ b/legacy/eina/src/lib/eina_list.c @@ -65,6 +65,27 @@ /*============================================================================* * Local * *============================================================================*/ +typedef struct _Eina_Iterator_List Eina_Iterator_List; +typedef struct _Eina_Accessor_List Eina_Accessor_List; + +struct _Eina_Iterator_List +{ + Eina_Iterator iterator; + + const Eina_List *head; + const Eina_List *current; +}; + +struct _Eina_Accessor_List +{ + Eina_Accessor accessor; + + const Eina_List *head; + const Eina_List *current; + + unsigned int index; +}; + static inline Eina_List_Accounting* _eina_list_mempool_accounting_new(__UNUSED__ Eina_List *list) { @@ -139,6 +160,108 @@ static Eina_Mempool2 _eina_list_accounting_mempool = }; #endif +static Eina_Bool +eina_list_iterator_next(Eina_Iterator_List *it, void **data) +{ + if (it->current == NULL) return EINA_FALSE; + if (data) *data = eina_list_data(it->current); + + it->current = eina_list_next(it->current); + + return EINA_TRUE; +} + +static Eina_List * +eina_list_iterator_get_container(Eina_Iterator_List *it) +{ + return (Eina_List *) it->head; +} + +static void +eina_list_iterator_free(Eina_Iterator_List *it) +{ + free(it); +} + +static Eina_Bool +eina_list_accessor_get_at(Eina_Accessor_List *it, unsigned int index, void **data) +{ + const Eina_List *over; + unsigned int middle; + unsigned int i; + + if (index > eina_list_count(it->head)) return EINA_FALSE; + + if (it->index == index) + { + over = it->current; + } + else if (index > it->index) + { + /* After current position. */ + middle = ((eina_list_count(it->head) - it->index) >> 1) + it->index; + + if (index > middle) + { + /* Go backward from the end. */ + for (i = eina_list_count(it->head) - 1, over = eina_list_last(it->head); + i > index && over != NULL; + --i, over = eina_list_prev(over)) + ; + } + else + { + /* Go forward from current. */ + for (i = it->index, over = it->current; + i < index && over != NULL; + ++i, over = eina_list_next(over)) + ; + } + } + else + { + /* Before current position. */ + middle = it->index >> 1; + + if (index > middle) + { + /* Go backward from current. */ + for (i = it->index, over = it->current; + i > index && over != NULL; + --i, over = eina_list_prev(over)) + ; + } + else + { + /* Go forward from start. */ + for (i = 0, over = it->head; + i < index && over != NULL; + ++i, over = eina_list_next(over)) + ; + } + } + + if (over == NULL) return EINA_FALSE; + + it->current = over; + it->index = index; + + if (data) *data = eina_list_data(it->current); + return EINA_TRUE; +} + +static Eina_List * +eina_list_accessor_get_container(Eina_Accessor_List *it) +{ + return (Eina_List *) it->head; +} + +static void +eina_list_accessor_free(Eina_Accessor_List *it) +{ + free(it); +} + /*============================================================================* * Global * *============================================================================*/ @@ -589,7 +712,7 @@ eina_list_promote_list(Eina_List *list, Eina_List *move_list) EAPI void * eina_list_find(const Eina_List *list, const void *data) { - if (eina_list_find_list(list, data)) return data; + if (eina_list_find_list(list, data)) return (void*) data; return NULL; } @@ -789,7 +912,7 @@ static inline void *eina_list_data(const Eina_List *list); * @endcode * @ingroup Eina_List_General_Group */ -static inline int eina_list_count(const Eina_List *list); +static inline unsigned int eina_list_count(const Eina_List *list); /** * Get the nth member's data pointer in a list @@ -814,10 +937,10 @@ static inline int eina_list_count(const Eina_List *list); * @ingroup Eina_List_Find_Group */ EAPI void * -eina_list_nth(const Eina_List *list, int n) +eina_list_nth(const Eina_List *list, unsigned int n) { Eina_List *l; - + l = eina_list_nth_list(list, n); return l ? l->data : NULL; } @@ -845,14 +968,13 @@ eina_list_nth(const Eina_List *list, int n) * @ingroup Eina_List_Find_Group */ EAPI Eina_List * -eina_list_nth_list(const Eina_List *list, int n) +eina_list_nth_list(const Eina_List *list, unsigned int n) { - int i; const Eina_List *l; + unsigned int i; /* check for non-existing nodes */ - if ((!list) || (n < 0) || - (n > (list->accounting->count - 1))) + if ((!list) || (n > (list->accounting->count - 1))) return NULL; /* if the node is in the 2nd half of the list, search from the end @@ -960,7 +1082,7 @@ eina_list_reverse(Eina_List *list) * @ingroup Eina_List_Ordering_Group */ EAPI Eina_List * -eina_list_sort(Eina_List *list, int size, int (*func)(void *, void *)) +eina_list_sort(Eina_List *list, unsigned int size, int (*func)(void *, void *)) { Eina_List* last; unsigned int list_number; @@ -970,7 +1092,7 @@ eina_list_sort(Eina_List *list, int size, int (*func)(void *, void *)) if (!list || !func) return NULL; /* if the caller specified an invalid size, sort the whole list */ - if ((size <= 0) || + if ((size == 0) || (size > list->accounting->count)) size = list->accounting->count; @@ -1060,3 +1182,53 @@ eina_list_sort(Eina_List *list, int size, int (*func)(void *, void *)) list->accounting->last = last; return list; } + +EAPI Eina_Iterator * +eina_list_iterator_new(const Eina_List *list) +{ + Eina_Iterator_List *it; + + if (!list) return NULL; + + eina_error_set(0); + it = calloc(1, sizeof (Eina_Iterator_List)); + if (!it) { + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + return NULL; + } + + it->head = list; + it->current = list; + + it->iterator.next = FUNC_ITERATOR_NEXT(eina_list_iterator_next); + it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(eina_list_iterator_get_container); + it->iterator.free = FUNC_ITERATOR_FREE(eina_list_iterator_free); + + return &it->iterator; +} + +EAPI Eina_Accessor * +eina_list_accessor_new(const Eina_List *list) +{ + Eina_Accessor_List *it; + + if (!list) return NULL; + + eina_error_set(0); + it = calloc(1, sizeof (Eina_Accessor_List)); + if (!it) { + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + return NULL; + } + + it->head = list; + it->current = list; + it->index = 0; + + it->accessor.get_at = FUNC_ACCESSOR_GET_AT(eina_list_accessor_get_at); + it->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(eina_list_accessor_get_container); + it->accessor.free = FUNC_ACCESSOR_FREE(eina_list_accessor_free); + + return &it->accessor; +} + diff --git a/legacy/eina/src/tests/eina_bench_array.c b/legacy/eina/src/tests/eina_bench_array.c index 2e73e031a5..390d266c96 100644 --- a/legacy/eina/src/tests/eina_bench_array.c +++ b/legacy/eina/src/tests/eina_bench_array.c @@ -233,6 +233,73 @@ eina_bench_list_4evas_render(int request) eina_list_shutdown(); } +static void +eina_bench_list_4evas_render_iterator(int request) +{ + Eina_List *list = NULL; + Eina_List *tmp; + Eina_Bench_Object *ebo; + Eina_Iterator *it; + int i; + int j; + + eina_list_init(); + + for (i = 0; i < 1000; ++i) + { + for (j = 0; j < request; ++j) + { + ebo = malloc(sizeof (Eina_Bench_Object)); + if (!ebo) continue ; + + ebo->keep = rand() < (RAND_MAX / 2) ? EINA_TRUE : EINA_FALSE; + + list = eina_list_prepend(list, ebo); + } + + if (i == 500) + { + while (list) + { + free(eina_list_data(list)); + list = eina_list_remove_list(list, list); + } + } + else + { + if (i % 30 == 0) + { + tmp = list; + while (tmp) + { + Eina_List *reminder = tmp; + + ebo = eina_list_data(reminder); + tmp = eina_list_next(tmp); + + if (ebo->keep == EINA_FALSE) + { + list = eina_list_remove_list(list, reminder); + free(ebo); + } + } + } + } + + it = eina_list_iterator_new(list); + eina_iterator_foreach(it, EINA_EACH(eina_iterator_ebo_rand), NULL); + eina_iterator_free(it); + } + + while (list) + { + free(eina_list_data(list)); + list = eina_list_remove_list(list, list); + } + + eina_list_shutdown(); +} + static void eina_bench_inlist_4evas_render(int request) { @@ -362,6 +429,7 @@ void eina_bench_array(Eina_Bench *bench) eina_bench_register(bench, "array-inline", EINA_BENCH(eina_bench_array_4evas_render_inline), 200, 4000, 100); eina_bench_register(bench, "array-iterator", EINA_BENCH(eina_bench_array_4evas_render_iterator), 200, 4000, 100); eina_bench_register(bench, "list", EINA_BENCH(eina_bench_list_4evas_render), 200, 4000, 100); + eina_bench_register(bench, "list-iterator", EINA_BENCH(eina_bench_list_4evas_render_iterator), 200, 4000, 100); eina_bench_register(bench, "inlist", EINA_BENCH(eina_bench_inlist_4evas_render), 200, 4000, 100); eina_bench_register(bench, "inlist-iterator", EINA_BENCH(eina_bench_inlist_4evas_render_iterator), 200, 4000, 100); } diff --git a/legacy/eina/src/tests/eina_test_accessor.c b/legacy/eina/src/tests/eina_test_accessor.c index 1df3aa56fa..c0656bf656 100644 --- a/legacy/eina/src/tests/eina_test_accessor.c +++ b/legacy/eina/src/tests/eina_test_accessor.c @@ -25,6 +25,7 @@ #include "eina_suite.h" #include "eina_array.h" #include "eina_inlist.h" +#include "eina_list.h" #include "eina_private.h" static Eina_Bool @@ -164,10 +165,75 @@ START_TEST(eina_accessor_inlist_simple) } END_TEST +static Eina_Bool +eina_iterator_list_data_check(__UNUSED__ const Eina_List *list, int *data, int *fdata) +{ + switch (*fdata) + { + case 0: fail_if(*data != 9); break; + case 1: fail_if(*data != 6); break; + } + + (*fdata)++; + + return EINA_TRUE; +} + +START_TEST(eina_accessor_list_simple) +{ + Eina_List *list = NULL; + Eina_Accessor *it; + int data[] = { 6, 9, 42, 1, 7, 1337, 81, 1664 }; + int *j; + int i = 0; + + eina_list_init(); + + list = eina_list_append(list, &data[0]); + fail_if(list == NULL); + + list = eina_list_prepend(list, &data[1]); + fail_if(list == NULL); + + list = eina_list_append(list, &data[2]); + fail_if(list == NULL); + + list = eina_list_append(list, &data[3]); + fail_if(list == NULL); + + list = eina_list_prepend(list, &data[4]); + fail_if(list == NULL); + + list = eina_list_append(list, &data[5]); + fail_if(list == NULL); + + list = eina_list_prepend(list, &data[6]); + fail_if(list == NULL); + + it = eina_list_accessor_new(list); + fail_if(!it); + + eina_accessor_over(it, EINA_EACH(eina_iterator_list_data_check), 2, 4, &i); + + fail_if(eina_accessor_data_get(it, 5, (void**) &j) != EINA_TRUE); + fail_if(*j != 1); + fail_if(eina_accessor_data_get(it, 3, (void**) &j) != EINA_TRUE); + fail_if(*j != 6); + fail_if(eina_accessor_data_get(it, 3, (void**) &j) != EINA_TRUE); + fail_if(*j != 6); + fail_if(eina_accessor_data_get(it, 1, (void**) &j) != EINA_TRUE); + fail_if(*j != 7); + fail_if(eina_accessor_data_get(it, 5, (void**) &j) != EINA_TRUE); + fail_if(*j != 1); + + eina_accessor_free(it); +} +END_TEST void eina_test_accessor(TCase *tc) { tcase_add_test(tc, eina_accessor_array_simple); tcase_add_test(tc, eina_accessor_inlist_simple); + tcase_add_test(tc, eina_accessor_list_simple); } diff --git a/legacy/eina/src/tests/eina_test_iterator.c b/legacy/eina/src/tests/eina_test_iterator.c index 4315969ce1..9392c56aff 100644 --- a/legacy/eina/src/tests/eina_test_iterator.c +++ b/legacy/eina/src/tests/eina_test_iterator.c @@ -26,6 +26,7 @@ #include "eina_array.h" #include "eina_hash.h" #include "eina_inlist.h" +#include "eina_list.h" #include "eina_private.h" static Eina_Bool @@ -212,10 +213,68 @@ START_TEST(eina_iterator_inlist_simple) } END_TEST +static Eina_Bool +eina_iterator_list_data_check(__UNUSED__ const Eina_List *list, int *data, int *fdata) +{ + switch (*fdata) + { + case 0: fail_if(*data != 81); break; + case 1: fail_if(*data != 7); break; + case 2: fail_if(*data != 9); break; + case 3: fail_if(*data != 6); break; + case 4: fail_if(*data != 42); break; + case 5: fail_if(*data != 1); break; + case 6: fail_if(*data != 1337); break; + } + + (*fdata)++; + + return EINA_TRUE; +} + +START_TEST(eina_iterator_list_simple) +{ + Eina_List *list = NULL; + Eina_Iterator *it; + int data[] = { 6, 9, 42, 1, 7, 1337, 81, 1664 }; + int i = 0; + + eina_list_init(); + + list = eina_list_append(list, &data[0]); + fail_if(list == NULL); + + list = eina_list_prepend(list, &data[1]); + fail_if(list == NULL); + + list = eina_list_append(list, &data[2]); + fail_if(list == NULL); + + list = eina_list_append(list, &data[3]); + fail_if(list == NULL); + + list = eina_list_prepend(list, &data[4]); + fail_if(list == NULL); + + list = eina_list_append(list, &data[5]); + fail_if(list == NULL); + + list = eina_list_prepend(list, &data[6]); + fail_if(list == NULL); + + it = eina_list_iterator_new(list); + fail_if(!it); + + eina_iterator_foreach(it, EINA_EACH(eina_iterator_list_data_check), &i); + eina_iterator_free(it); +} +END_TEST + void eina_test_iterator(TCase *tc) { tcase_add_test(tc, eina_iterator_array_simple); tcase_add_test(tc, eina_iterator_hash_simple); tcase_add_test(tc, eina_iterator_inlist_simple); + tcase_add_test(tc, eina_iterator_list_simple); }