diff --git a/legacy/eina/ChangeLog b/legacy/eina/ChangeLog index 97447a327a..f3c3478f9a 100644 --- a/legacy/eina/ChangeLog +++ b/legacy/eina/ChangeLog @@ -41,3 +41,7 @@ 2011-04-06 Gustavo Sverzut Barbieri * Add Simple XML parser API. + +2011-05-11 Cedric Bail + + * Add eina_inlist_sort. diff --git a/legacy/eina/src/include/eina_inlist.h b/legacy/eina/src/include/eina_inlist.h index 793d2d6cca..ed67785617 100644 --- a/legacy/eina/src/include/eina_inlist.h +++ b/legacy/eina/src/include/eina_inlist.h @@ -361,6 +361,53 @@ EAPI Eina_Iterator *eina_inlist_iterator_new(const Eina_Inlist *in_list) EINA_MA */ EAPI Eina_Accessor *eina_inlist_accessor_new(const Eina_Inlist *in_list) EINA_MALLOC EINA_WARN_UNUSED_RESULT; +/** + * @brief Sort a list according to the ordering func will return. + * + * @param list The list handle to sort. + * @param func A function pointer that can handle comparing the list data + * nodes. + * @return the new head of list. + * + * This function sorts all the elements of @p list. @p func is used to + * compare two elements of @p list. If @p list or @p func are @c NULL, + * this function returns @c NULL. + * + * @note @b in-place: this will change the given list, so you should + * now point to the new list head that is returned by this function. + * + * @note worst case is O(n * log2(n)) comparisons (calls to func()), + * O(n) comparisons average case. That means that for 1,000,000 list + * elements, sort will usually do 1,000,000 comparisons, but may do up + * to 20,000,000. + * + * Example: + * @code + * typedef struct _Sort_Ex Sort_Ex; + * struct _Sort_Ex + * { + * INLIST; + * const char *text; + * }; + * + * int + * sort_cb(const Inlist *l1, const Inlist *l2) + * { + * const Sort_Ex *x1; + * const Sort_Ex *x2; + * + * x1 = EINA_INLIST_CONTAINER_GET(l1, Sort_Ex); + * x2 = EINA_INLIST_CONTAINER_GET(l2, Sort_Ex); + * + * return(strcmp(x1->text, x2->text)); + * } + * extern Eina_Inlist *list; + * + * list = eina_inlist_sort(list, sort_cb); + * @endcode + */ +EAPI Eina_Inlist *eina_inlist_sort(Eina_Inlist *head, Eina_Compare_Cb func); + /* This two macros are helpers for the _FOREACH ones, don't use them */ #define _EINA_INLIST_OFFSET(ref) ((char *)&(ref)->__in_list - (char *)(ref)) #define _EINA_INLIST_CONTAINER(ref, ptr) (void *)((char *)(ptr) - \ diff --git a/legacy/eina/src/lib/eina_inlist.c b/legacy/eina/src/lib/eina_inlist.c index 9fdd95bbe2..90a0580072 100644 --- a/legacy/eina/src/lib/eina_inlist.c +++ b/legacy/eina/src/lib/eina_inlist.c @@ -42,6 +42,8 @@ * @cond LOCAL */ +#define EINA_INLIST_SORT_STACK_SIZE 32 + typedef struct _Eina_Iterator_Inlist Eina_Iterator_Inlist; typedef struct _Eina_Accessor_Inlist Eina_Accessor_Inlist; @@ -141,6 +143,41 @@ eina_inlist_accessor_free(Eina_Accessor_Inlist *it) { free(it); } +static Eina_Inlist * +eina_inlist_sort_merge(Eina_Inlist *a, Eina_Inlist *b, Eina_Compare_Cb func) +{ + Eina_Inlist *first, *last; + + if (func(a, b) < 0) + a = (last = first = a)->next; + else + b = (last = first = b)->next; + + while (a && b) + if (func(a, b) < 0) + a = (last = last->next = a)->next; + else + b = (last = last->next = b)->next; + + last->next = a ? a : b; + + return first; +} + +static Eina_Inlist * +eina_inlist_sort_rebuild_prev(Eina_Inlist *list) +{ + Eina_Inlist *prev = NULL; + + for (; list; list = list->next) + { + list->prev = prev; + prev = list; + } + + return prev; +} + /** * @endcond */ @@ -385,6 +422,61 @@ eina_inlist_count(const Eina_Inlist *list) return i; } +EAPI Eina_Inlist * +eina_inlist_sort(Eina_Inlist *head, Eina_Compare_Cb func) +{ + unsigned int i = 0; + unsigned int n = 0; + Eina_Inlist *tail = head; + Eina_Inlist *unsort = NULL; + Eina_Inlist *stack[EINA_INLIST_SORT_STACK_SIZE]; + + EINA_SAFETY_ON_NULL_RETURN_VAL(head, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(func, head); + + while (tail) + { + unsigned int idx, tmp; + + Eina_Inlist *a = tail; + Eina_Inlist *b = tail->next; + + if (!b) + { + stack[i++] = a; + break; + } + + tail = b->next; + + if (func(a, b) < 0) + ((stack[i++] = a)->next = b)->next = 0; + else + ((stack[i++] = b)->next = a)->next = 0; + + tmp = n++; + for (idx = n ^ tmp; idx &= idx - 1; i--) + stack[i - 2] = eina_inlist_sort_merge(stack[i - 2], stack[i - 1], func); + } + + while (i-- > 1) + stack[i - 1] = eina_inlist_sort_merge(stack[i - 1], stack[i], func); + + head = stack[0]; + tail = eina_inlist_sort_rebuild_prev(head); + + if (unsort) + { + tail->next = unsort; + unsort->prev = tail; + } + + head->last = tail; + + return head; + +} + EAPI Eina_Iterator * eina_inlist_iterator_new(const Eina_Inlist *list) {