parent
30e6030197
commit
cde3148eca
|
@ -89,3 +89,7 @@
|
||||||
2011-05-24 Vincent Torri
|
2011-05-24 Vincent Torri
|
||||||
|
|
||||||
* Implement eina_sched_prio_drop() on Windows
|
* Implement eina_sched_prio_drop() on Windows
|
||||||
|
|
||||||
|
2011-05-24 Cedric Bail
|
||||||
|
|
||||||
|
* Add eina_inlist_sorted_insert.
|
||||||
|
|
|
@ -361,6 +361,29 @@ 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;
|
EAPI Eina_Accessor *eina_inlist_accessor_new(const Eina_Inlist *in_list) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Insert a new node into a sorted list.
|
||||||
|
*
|
||||||
|
* @param list The given linked list, @b must be sorted.
|
||||||
|
* @param item list node to insert, must not be NULL.
|
||||||
|
* @param func The function called for the sort.
|
||||||
|
* @return A list pointer.
|
||||||
|
*
|
||||||
|
* This function inserts item into a linked list assuming it was
|
||||||
|
* sorted and the result will be sorted. If @p list is @c NULLL, item
|
||||||
|
* is returned. On success, a new list pointer that should be
|
||||||
|
* used in place of the one given to this function is
|
||||||
|
* returned. Otherwise, the old pointer is returned. See eina_error_get().
|
||||||
|
*
|
||||||
|
* @note O(log2(n)) comparisons (calls to @p func) average/worst case
|
||||||
|
* performance as it uses eina_list_search_sorted_near_list() and thus
|
||||||
|
* is bounded to that. As said in eina_list_search_sorted_near_list(),
|
||||||
|
* lists do not have O(1) access time, so walking to the correct node
|
||||||
|
* can be costly, consider worst case to be almost O(n) pointer
|
||||||
|
* dereference (list walk).
|
||||||
|
*/
|
||||||
|
EAPI Eina_Inlist *eina_inlist_sorted_insert(Eina_Inlist *list, Eina_Inlist *item, Eina_Compare_Cb func) EINA_ARG_NONNULL(2, 3) EINA_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sort a list according to the ordering func will return.
|
* @brief Sort a list according to the ordering func will return.
|
||||||
*
|
*
|
||||||
|
|
|
@ -422,6 +422,141 @@ eina_inlist_count(const Eina_Inlist *list)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define EINA_INLIST_JUMP_SIZE 256
|
||||||
|
|
||||||
|
EAPI Eina_Inlist *
|
||||||
|
eina_inlist_sorted_insert(Eina_Inlist *list,
|
||||||
|
Eina_Inlist *item,
|
||||||
|
Eina_Compare_Cb func)
|
||||||
|
{
|
||||||
|
Eina_Inlist *ct = NULL;
|
||||||
|
Eina_Inlist *jump_table[EINA_INLIST_JUMP_SIZE];
|
||||||
|
int cmp = 0;
|
||||||
|
int inf, sup;
|
||||||
|
int cur = 0;
|
||||||
|
int count = 0;
|
||||||
|
unsigned short jump_limit = 0;
|
||||||
|
int jump_div = 1;
|
||||||
|
int jump_count = 1;
|
||||||
|
|
||||||
|
if (!list) return eina_inlist_append(NULL, item);
|
||||||
|
|
||||||
|
if (!list->next)
|
||||||
|
{
|
||||||
|
cmp = func(list, item);
|
||||||
|
|
||||||
|
if (cmp < 0)
|
||||||
|
return eina_inlist_append(list, item);
|
||||||
|
return eina_inlist_prepend(list, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* prepare a jump table to avoid doing unecessary rewalk
|
||||||
|
* of the inlist as much as possible.
|
||||||
|
*/
|
||||||
|
for (ct = list->next; ct; ct = ct->next, jump_count++, count++)
|
||||||
|
{
|
||||||
|
if (jump_count == jump_div)
|
||||||
|
{
|
||||||
|
if (jump_limit == EINA_INLIST_JUMP_SIZE)
|
||||||
|
{
|
||||||
|
unsigned short i, j;
|
||||||
|
|
||||||
|
/* compress the jump table */
|
||||||
|
jump_div *= 2;
|
||||||
|
jump_limit /= 2;
|
||||||
|
|
||||||
|
for (i = 2, j = 1;
|
||||||
|
i < EINA_INLIST_JUMP_SIZE;
|
||||||
|
i += 2, j++)
|
||||||
|
jump_table[j] = jump_table[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
jump_table[jump_limit] = ct;
|
||||||
|
jump_limit++;
|
||||||
|
jump_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* now do a dychotomic search directly inside the jump_table.
|
||||||
|
*/
|
||||||
|
inf = 0;
|
||||||
|
sup = jump_limit - 1;
|
||||||
|
cur = 0;
|
||||||
|
ct = jump_table[cur];
|
||||||
|
|
||||||
|
while (inf <= sup)
|
||||||
|
{
|
||||||
|
cur = inf + ((sup - inf) >> 1);
|
||||||
|
ct = jump_table[cur];
|
||||||
|
|
||||||
|
cmp = func(ct, item);
|
||||||
|
if (cmp == 0)
|
||||||
|
break ;
|
||||||
|
else if (cmp < 0)
|
||||||
|
inf = cur + 1;
|
||||||
|
else if (cmp > 0)
|
||||||
|
{
|
||||||
|
if (cur > 0)
|
||||||
|
sup = cur - 1;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If at the beginning of the table and cmp < 0,
|
||||||
|
* insert just after the head */
|
||||||
|
if (cur == 0 && cmp < 0)
|
||||||
|
return eina_inlist_append_relative(list, item, list->next);
|
||||||
|
|
||||||
|
/* If at the end of the table and cmp >= 0,
|
||||||
|
* just append the item to the list */
|
||||||
|
if (cmp >= 0 && ct == list->last)
|
||||||
|
return eina_inlist_append(list, item);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now do a dychotomic search between two entries inside the jump_table
|
||||||
|
*/
|
||||||
|
cur *= jump_div;
|
||||||
|
inf = cur;
|
||||||
|
sup = inf + jump_div;
|
||||||
|
|
||||||
|
if (sup > count - 1) sup = count - 1;
|
||||||
|
|
||||||
|
while (inf <= sup)
|
||||||
|
{
|
||||||
|
int tmp = cur;
|
||||||
|
|
||||||
|
cur = inf + ((sup - inf) >> 1);
|
||||||
|
if (tmp < cur)
|
||||||
|
for (; tmp != cur; tmp++, ct = ct->next);
|
||||||
|
else if (tmp > cur)
|
||||||
|
for (; tmp != cur; tmp--, ct = ct->prev);
|
||||||
|
|
||||||
|
cmp = func(ct, item);
|
||||||
|
if (cmp == 0)
|
||||||
|
break ;
|
||||||
|
else if (cmp < 0)
|
||||||
|
inf = cur + 1;
|
||||||
|
else if (cmp > 0)
|
||||||
|
{
|
||||||
|
if (cur > 0)
|
||||||
|
sup = cur - 1;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmp < 0)
|
||||||
|
return eina_inlist_append_relative(list, item, ct);
|
||||||
|
return eina_inlist_prepend_relative(list, item, ct);
|
||||||
|
}
|
||||||
|
|
||||||
EAPI Eina_Inlist *
|
EAPI Eina_Inlist *
|
||||||
eina_inlist_sort(Eina_Inlist *head, Eina_Compare_Cb func)
|
eina_inlist_sort(Eina_Inlist *head, Eina_Compare_Cb func)
|
||||||
{
|
{
|
||||||
|
|
|
@ -135,8 +135,78 @@ START_TEST(eina_inlist_simple)
|
||||||
}
|
}
|
||||||
END_TEST
|
END_TEST
|
||||||
|
|
||||||
|
typedef struct _Eina_Test_Inlist_Sorted Eina_Test_Inlist_Sorted;
|
||||||
|
struct _Eina_Test_Inlist_Sorted
|
||||||
|
{
|
||||||
|
EINA_INLIST;
|
||||||
|
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
_eina_test_inlist_cmp(const void *d1, const void *d2)
|
||||||
|
{
|
||||||
|
const Eina_Test_Inlist_Sorted *t1 = d1;
|
||||||
|
const Eina_Test_Inlist_Sorted *t2 = d2;
|
||||||
|
|
||||||
|
return t1->value - t2->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_eina_test_inlist_check(const Eina_Inlist *list)
|
||||||
|
{
|
||||||
|
const Eina_Test_Inlist_Sorted *t;
|
||||||
|
int last_value = 0;
|
||||||
|
|
||||||
|
EINA_INLIST_FOREACH(list, t)
|
||||||
|
{
|
||||||
|
fail_if(t->value < last_value);
|
||||||
|
last_value = t->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
START_TEST(eina_inlist_sorted)
|
||||||
|
{
|
||||||
|
Eina_Inlist *list = NULL;
|
||||||
|
Eina_Inlist *sorted = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
srand(time(NULL));
|
||||||
|
|
||||||
|
for (i = 0; i < 5000; ++i)
|
||||||
|
{
|
||||||
|
Eina_Test_Inlist_Sorted *tmp;
|
||||||
|
|
||||||
|
tmp = malloc(sizeof (Eina_Test_Inlist_Sorted));
|
||||||
|
if (!tmp) continue ;
|
||||||
|
|
||||||
|
tmp->value = rand();
|
||||||
|
|
||||||
|
list = eina_inlist_prepend(list, EINA_INLIST_GET(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
|
list = eina_inlist_sort(list, _eina_test_inlist_cmp);
|
||||||
|
|
||||||
|
_eina_test_inlist_check(list);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (list)
|
||||||
|
{
|
||||||
|
Eina_Inlist *tmp = list;
|
||||||
|
|
||||||
|
list = eina_inlist_remove(list, list);
|
||||||
|
|
||||||
|
sorted = eina_inlist_sorted_insert(sorted, tmp, _eina_test_inlist_cmp);
|
||||||
|
_eina_test_inlist_check(sorted);
|
||||||
|
}
|
||||||
|
|
||||||
|
_eina_test_inlist_check(sorted);
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
void
|
void
|
||||||
eina_test_inlist(TCase *tc)
|
eina_test_inlist(TCase *tc)
|
||||||
{
|
{
|
||||||
tcase_add_test(tc, eina_inlist_simple);
|
tcase_add_test(tc, eina_inlist_simple);
|
||||||
|
tcase_add_test(tc, eina_inlist_sorted);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue