diff --git a/legacy/eina/src/include/eina_list.h b/legacy/eina/src/include/eina_list.h index 1b1cce2c64..e61e5e6cbc 100644 --- a/legacy/eina/src/include/eina_list.h +++ b/legacy/eina/src/include/eina_list.h @@ -96,6 +96,9 @@ 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, unsigned int size, Eina_Compare_Cb func); +EAPI Eina_List *eina_list_merge (Eina_List *left, Eina_List *right); +EAPI Eina_List *eina_list_sorted_merge(Eina_List *left, Eina_List *right, Eina_Compare_Cb func); + static inline Eina_List *eina_list_last (const Eina_List *list); static inline Eina_List *eina_list_next (const Eina_List *list); diff --git a/legacy/eina/src/lib/eina_list.c b/legacy/eina/src/lib/eina_list.c index ab0dce1b94..c6ca44334a 100644 --- a/legacy/eina/src/lib/eina_list.c +++ b/legacy/eina/src/lib/eina_list.c @@ -1217,11 +1217,6 @@ eina_list_reverse(Eina_List *list) * extern Eina_List *list; * * list = eina_list_sort(list, eina_list_count(list), sort_cb); - * if (eina_error_get()) - * { - * fprintf(stderr, "ERROR: Memory is low. List Sorting failed.\n"); - * exit(-1); - * } * @endcode */ EAPI Eina_List * @@ -1291,6 +1286,147 @@ eina_list_sort(Eina_List *list, unsigned int size, Eina_Compare_Cb func) return list; } +/** + * @brief Merge two list. + * + * @param left Head list to merge. + * @param right Tail list to merge. + * @return A new merged list. + * + * This function put right at the end of left and return the head. + * + * Both left and right does not exist anymore after the merge. + * + */ +EAPI Eina_List * +eina_list_merge(Eina_List *left, Eina_List *right) +{ + if (!left) return right; + if (!right) return left; + + left->accounting->last->next = right; + right->prev = left->accounting->last; + + left->accounting->last = right->accounting->last; + left->accounting->count += right->accounting->count; + + _eina_list_mempool_accounting_free(right->accounting); + + while (right) + { + right->accounting = left->accounting; + right = right->next; + } + + return left; +} + +/** + * @brief Merge two sorted list according to the ordering func will return. + * + * @param left First list to merge. + * @param right Second list to merge. + * @param func A function pointer that can handle comparing the list data + * nodes. + * @return A new sorted list. + * + * This function compare the head of @p left and @p right, and choose the + * smallest one to be head of the returned list. It will continue this process + * for all entry of both list. + * + * Both left and right does not exist anymore after the merge. + * If @p func is NULL, it will return NULL. + * + * Example: + * @code + * int + * sort_cb(void *d1, void *d2) + * { + * const char *txt = NULL; + * const char *txt2 = NULL; + * + * if(!d1) return(1); + * if(!d2) return(-1); + * + * return(strcmp((const char*)d1, (const char*)d2)); + * } + * extern Eina_List *sorted1; + * extern Eina_List *sorted2; + * + * list = eina_list_sorted_merge(sorted1, sorted2, sort_cb); + * @endcode + */ +EAPI Eina_List * +eina_list_sorted_merge(Eina_List *left, Eina_List *right, Eina_Compare_Cb func) +{ + Eina_List *ret; + Eina_List *current; + + if (!left) return right; + if (!right) return left; + if (!func) return NULL; + + if (func(left->data, right->data) < 0) + { + ret = left; + current = left; + left = left->next; + ret->accounting->count += right->accounting->count; + + _eina_list_mempool_accounting_free(right->accounting); + } + else + { + ret = right; + current = right; + right = right->next; + ret->accounting->count += left->accounting->count; + + _eina_list_mempool_accounting_free(left->accounting); + } + + while (left && right) + { + if (func(left->data, right->data) < 0) + { + current->next = left; + left->prev = current; + left = left->next; + } + else + { + current->next = right; + right->prev = current; + right = right->next; + } + + current = current->next; + current->accounting = ret->accounting; + } + + if (left) + { + current->next = left; + left->prev = current; + } + + if (right) + { + current->next = right; + right->prev = current; + } + + while (current->next) + { + current->accounting = ret->accounting; + current = current->next; + } + + ret->accounting->last = current; + + return ret; +} + /** * @brief Returned a new iterator asociated to a list. * diff --git a/legacy/eina/src/tests/eina_test_list.c b/legacy/eina/src/tests/eina_test_list.c index e6a65658c9..190ef8affd 100644 --- a/legacy/eina/src/tests/eina_test_list.c +++ b/legacy/eina/src/tests/eina_test_list.c @@ -188,8 +188,78 @@ START_TEST(eina_test_simple) } END_TEST +START_TEST(eina_test_merge) +{ + Eina_List *l1; + Eina_List *l2; + Eina_List *l3; + Eina_List *l4; + Eina_List *l5; + int data[] = { 6, 9, 42, 1, 7, 9, 81, 1664, 1337, 3, 21, 10, 0, 5, 2008 }; + int *prev; + int *current; + int i; + + eina_list_init(); + + l1 = eina_list_append(NULL, &data[0]); + l1 = eina_list_append(l1, &data[1]); + l1 = eina_list_append(l1, &data[2]); + + l2 = eina_list_append(NULL, &data[3]); + l2 = eina_list_append(l2, &data[4]); + l2 = eina_list_append(l2, &data[5]); + + l3 = eina_list_append(NULL, &data[6]); + l3 = eina_list_append(l3, &data[7]); + l3 = eina_list_append(l3, &data[8]); + + l4 = eina_list_append(NULL, &data[9]); + l4 = eina_list_append(l4, &data[10]); + l4 = eina_list_append(l4, &data[11]); + + l5 = eina_list_append(NULL, &data[12]); + l5 = eina_list_append(l5, &data[13]); + l5 = eina_list_append(l5, &data[14]); + + l1 = eina_list_merge(l1, l2); + fail_if(l1 == NULL); + fail_if(eina_list_count(l1) != 6); + for (i = 0; i < 6; ++i) + fail_if(eina_list_nth(l1, i) != &data[i]); + + l1 = eina_list_sort(l1, -1, eina_int_cmp); + l3 = eina_list_sort(l3, -1, eina_int_cmp); + l4 = eina_list_sort(l4, -1, eina_int_cmp); + l5 = eina_list_sort(l5, -1, eina_int_cmp); + + l1 = eina_list_sorted_merge(l1, l3, eina_int_cmp); + fail_if(l1 == NULL); + fail_if(eina_list_count(l1) != 9); + + l1 = eina_list_sorted_merge(l1, l4, eina_int_cmp); + fail_if(l1 == NULL); + fail_if(eina_list_count(l1) != 12); + + l1 = eina_list_sorted_merge(l1, l5, eina_int_cmp); + fail_if(l1 == NULL); + fail_if(eina_list_count(l1) != 15); + + prev = eina_list_data_get(l1); + for (i = 1; i < eina_list_count(l1); ++i) + { + current = eina_list_nth(l1, i); + fail_if (*prev > *current); + prev = current; + } + + eina_list_shutdown(); +} +END_TEST + void eina_test_list(TCase *tc) { tcase_add_test(tc, eina_test_simple); + tcase_add_test(tc, eina_test_merge); }