eina: add eina_inlist_sort (merge sort based on eina_list code).

SVN revision: 58540
This commit is contained in:
Cedric BAIL 2011-04-11 09:55:27 +00:00
parent 733cfc629b
commit ca83ca2ff4
3 changed files with 143 additions and 0 deletions

View File

@ -41,3 +41,7 @@
2011-04-06 Gustavo Sverzut Barbieri
* Add Simple XML parser API.
2011-05-11 Cedric Bail
* Add eina_inlist_sort.

View File

@ -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) - \

View File

@ -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)
{