2011-05-24 Vincent Torri
* Implement eina_sched_prio_drop() on Windows
+
+2011-05-24 Cedric Bail
+
+ * Add eina_inlist_sorted_insert.
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.
*
* @param list The list handle to sort.
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 *
eina_inlist_sort(Eina_Inlist *head, Eina_Compare_Cb func)
{
}
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
eina_test_inlist(TCase *tc)
{
tcase_add_test(tc, eina_inlist_simple);
+ tcase_add_test(tc, eina_inlist_sorted);
}