1 /* EINA - EFL data type library
2 * Copyright (C) 2002-2008 Carsten Haitzler, Vincent Torri
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>.
28 #include "eina_config.h"
29 #include "eina_private.h"
30 #include "eina_error.h"
33 /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
34 #include "eina_safety_checks.h"
35 #include "eina_inlist.h"
37 /* FIXME: TODO please, refactor this :) */
39 /*============================================================================*
41 *============================================================================*/
47 #define EINA_INLIST_SORT_STACK_SIZE 32
49 typedef struct _Eina_Iterator_Inlist Eina_Iterator_Inlist;
50 typedef struct _Eina_Accessor_Inlist Eina_Accessor_Inlist;
52 struct _Eina_Iterator_Inlist
54 Eina_Iterator iterator;
55 const Eina_Inlist *head;
56 const Eina_Inlist *current;
59 struct _Eina_Accessor_Inlist
61 Eina_Accessor accessor;
63 const Eina_Inlist *head;
64 const Eina_Inlist *current;
69 struct _Eina_Inlist_Sorted_State
71 Eina_Inlist *jump_table[EINA_INLIST_JUMP_SIZE];
73 unsigned short jump_limit;
80 eina_inlist_iterator_next(Eina_Iterator_Inlist *it, void **data) {
85 *data = (void *)it->current;
87 it->current = it->current->next;
93 eina_inlist_iterator_get_container(Eina_Iterator_Inlist *it) {
94 return (Eina_Inlist *)it->head;
98 eina_inlist_iterator_free(Eina_Iterator_Inlist *it) {
103 eina_inlist_accessor_get_at(Eina_Accessor_Inlist *it,
106 const Eina_Inlist *over;
110 if (it->index == idx)
112 else if (idx > it->index)
113 /* Looking after current. */
114 for (i = it->index, over = it->current;
116 ++i, over = over->next)
120 middle = it->index >> 1;
123 /* Looking backward from current. */
124 for (i = it->index, over = it->current;
126 --i, over = over->prev)
129 /* Looking from the start. */
130 for (i = 0, over = it->head;
132 ++i, over = over->next)
143 *data = (void *)over;
149 eina_inlist_accessor_get_container(Eina_Accessor_Inlist *it) {
150 return (Eina_Inlist *)it->head;
154 eina_inlist_accessor_free(Eina_Accessor_Inlist *it) {
159 eina_inlist_sort_merge(Eina_Inlist *a, Eina_Inlist *b, Eina_Compare_Cb func)
161 Eina_Inlist *first, *last;
164 a = (last = first = a)->next;
166 b = (last = first = b)->next;
170 a = (last = last->next = a)->next;
172 b = (last = last->next = b)->next;
174 last->next = a ? a : b;
180 eina_inlist_sort_rebuild_prev(Eina_Inlist *list)
182 Eina_Inlist *prev = NULL;
184 for (; list; list = list->next)
194 _eina_inlist_sorted_state_compact(Eina_Inlist_Sorted_State *state)
198 /* compress the jump table */
199 state->jump_div *= 2;
200 state->jump_limit /= 2;
203 i < EINA_INLIST_JUMP_SIZE;
205 state->jump_table[j] = state->jump_table[i];
213 /*============================================================================*
215 *============================================================================*/
217 /*============================================================================*
219 *============================================================================*/
222 eina_inlist_append(Eina_Inlist *list, Eina_Inlist *new_l)
226 EINA_SAFETY_ON_NULL_RETURN_VAL(new_l, list);
239 for (l = list; (l) && (l->next); l = l->next)
249 eina_inlist_prepend(Eina_Inlist *list, Eina_Inlist *new_l)
251 EINA_SAFETY_ON_NULL_RETURN_VAL(new_l, list);
263 new_l->last = list->last;
269 eina_inlist_append_relative(Eina_Inlist *list,
271 Eina_Inlist *relative)
273 EINA_SAFETY_ON_NULL_RETURN_VAL(new_l, list);
279 new_l->next = relative->next;
280 relative->next->prev = new_l;
285 relative->next = new_l;
286 new_l->prev = relative;
293 return eina_inlist_append(list, new_l);
297 eina_inlist_prepend_relative(Eina_Inlist *list,
299 Eina_Inlist *relative)
301 EINA_SAFETY_ON_NULL_RETURN_VAL(new_l, list);
305 new_l->prev = relative->prev;
306 new_l->next = relative;
307 relative->prev = new_l;
310 new_l->prev->next = new_l;
311 /* new_l->next could not be NULL, as it was set to 'relative' */
317 /* new_l->next could not be NULL, as it was set to 'relative' */
320 new_l->last = list->last;
326 return eina_inlist_prepend(list, new_l);
330 eina_inlist_remove(Eina_Inlist *list, Eina_Inlist *item)
332 Eina_Inlist *return_l;
335 EINA_SAFETY_ON_NULL_RETURN_VAL(list, NULL);
336 EINA_SAFETY_ON_NULL_RETURN_VAL(item, list);
337 if (EINA_UNLIKELY((item != list) && (!item->prev) && (!item->next)))
339 eina_error_set(EINA_ERROR_SAFETY_FAILED);
340 EINA_LOG_ERR("safety check failed: item %p does not appear to be part of an inlist!", item);
345 item->next->prev = item->prev;
349 item->prev->next = item->next;
354 return_l = item->next;
356 return_l->last = list->last;
359 if (item == list->last)
360 list->last = item->prev;
368 eina_inlist_promote(Eina_Inlist *list, Eina_Inlist *item)
370 EINA_SAFETY_ON_NULL_RETURN_VAL(list, NULL);
371 EINA_SAFETY_ON_NULL_RETURN_VAL(item, list);
377 item->next->prev = item->prev;
379 item->prev->next = item->next;
381 if (list->last == item)
382 list->last = item->prev;
386 item->last = list->last;
395 eina_inlist_demote(Eina_Inlist *list, Eina_Inlist *item)
399 EINA_SAFETY_ON_NULL_RETURN_VAL(list, NULL);
400 EINA_SAFETY_ON_NULL_RETURN_VAL(item, list);
402 if (list->last == item)
407 for (l = list; l->next; l = l->next)
414 item->prev->next = item->next;
418 item->next->prev = item->prev;
420 list->last->next = item;
421 item->prev = list->last;
429 eina_inlist_find(Eina_Inlist *list, Eina_Inlist *item)
433 EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
435 for (l = list; l; l = l->next) {
443 eina_inlist_count(const Eina_Inlist *list)
445 const Eina_Inlist *l;
448 for (l = list; l; l = l->next)
455 eina_inlist_sorted_state_init(Eina_Inlist_Sorted_State *state, Eina_Inlist *list)
457 Eina_Inlist *ct = NULL;
462 * prepare a jump table to avoid doing unnecessary rewalk
463 * of the inlist as much as possible.
465 for (ct = list; ct; ct = ct->next, jump_count++, count++)
467 if (jump_count == state->jump_div)
469 if (state->jump_limit == EINA_INLIST_JUMP_SIZE)
471 _eina_inlist_sorted_state_compact(state);
474 state->jump_table[state->jump_limit] = ct;
480 state->inserted = count;
484 EAPI Eina_Inlist_Sorted_State *
485 eina_inlist_sorted_state_new(void)
487 Eina_Inlist_Sorted_State *r;
489 r = calloc(1, sizeof (Eina_Inlist_Sorted_State));
498 eina_inlist_sorted_state_free(Eina_Inlist_Sorted_State *state)
504 _eina_inlist_sorted_state_insert(Eina_Inlist_Sorted_State *state,
514 if (offset != 0) idx++;
515 for (; idx < state->jump_limit; idx++)
517 state->jump_table[idx] = state->jump_table[idx]->prev;
520 start = state->jump_limit - 3;
524 last = state->jump_table[start];
527 /* Correctly rebuild end of list */
528 for (jump_count = 0; last->next != NULL; last = last->next, jump_count++)
530 if (jump_count == state->jump_div)
532 if (state->jump_limit == start)
534 if (state->jump_limit == EINA_INLIST_JUMP_SIZE)
536 _eina_inlist_sorted_state_compact(state);
537 start = state->jump_limit - 1;
546 state->jump_table[start++] = last;
553 eina_inlist_sorted_insert(Eina_Inlist *list,
555 Eina_Compare_Cb func)
557 Eina_Inlist *ct = NULL;
558 Eina_Inlist_Sorted_State state;
564 EINA_SAFETY_ON_NULL_RETURN_VAL(item, list);
565 EINA_SAFETY_ON_NULL_RETURN_VAL(func, list);
567 if (!list) return eina_inlist_append(NULL, item);
571 cmp = func(list, item);
574 return eina_inlist_append(list, item);
575 return eina_inlist_prepend(list, item);
579 state.jump_limit = 0;
580 count = eina_inlist_sorted_state_init(&state, list);
583 * now do a dychotomic search directly inside the jump_table.
586 sup = state.jump_limit - 1;
588 ct = state.jump_table[cur];
589 cmp = func(ct, item);
593 cur = inf + ((sup - inf) >> 1);
594 ct = state.jump_table[cur];
596 cmp = func(ct, item);
612 /* If at the beginning of the table and cmp < 0,
613 * insert just after the head */
614 if (cur == 0 && cmp > 0)
615 return eina_inlist_prepend_relative(list, item, ct);
617 /* If at the end of the table and cmp >= 0,
618 * just append the item to the list */
619 if (cmp < 0 && ct == list->last)
620 return eina_inlist_append(list, item);
623 * Now do a dychotomic search between two entries inside the jump_table
625 cur *= state.jump_div;
626 inf = cur - state.jump_div - 1;
627 sup = cur + state.jump_div + 1;
629 if (sup > count - 1) sup = count - 1;
630 if (inf < 0) inf = 0;
636 cur = inf + ((sup - inf) >> 1);
638 for (; tmp != cur; tmp++, ct = ct->next);
640 for (; tmp != cur; tmp--, ct = ct->prev);
642 cmp = func(ct, item);
659 return eina_inlist_append_relative(list, item, ct);
660 return eina_inlist_prepend_relative(list, item, ct);
664 eina_inlist_sorted_state_insert(Eina_Inlist *list,
666 Eina_Compare_Cb func,
667 Eina_Inlist_Sorted_State *state)
669 Eina_Inlist *ct = NULL;
680 state->jump_limit = 1;
681 state->jump_table[0] = item;
682 return eina_inlist_append(NULL, item);
687 cmp = func(list, item);
689 state->jump_limit = 2;
694 state->jump_table[1] = item;
695 return eina_inlist_append(list, item);
697 state->jump_table[1] = state->jump_table[0];
698 state->jump_table[0] = item;
699 return eina_inlist_prepend(list, item);
702 count = state->inserted;
705 * now do a dychotomic search directly inside the jump_table.
708 sup = state->jump_limit - 1;
710 ct = state->jump_table[cur];
711 cmp = func(ct, item);
715 cur = inf + ((sup - inf) >> 1);
716 ct = state->jump_table[cur];
718 cmp = func(ct, item);
734 /* If at the beginning of the table and cmp < 0,
735 * insert just after the head */
736 if (cur == 0 && cmp > 0)
738 ct = eina_inlist_prepend_relative(list, item, ct);
739 _eina_inlist_sorted_state_insert(state, 0, 0);
743 /* If at the end of the table and cmp >= 0,
744 * just append the item to the list */
745 if (cmp < 0 && ct == list->last)
747 ct = eina_inlist_append(list, item);
748 _eina_inlist_sorted_state_insert(state, state->jump_limit - 1, 1);
753 * Now do a dychotomic search between two entries inside the jump_table
755 cur *= state->jump_div;
756 inf = cur - state->jump_div - 1;
757 sup = cur + state->jump_div + 1;
759 if (sup > count - 1) sup = count - 1;
760 if (inf < 0) inf = 0;
766 cur = inf + ((sup - inf) >> 1);
768 for (; tmp != cur; tmp++, ct = ct->next);
770 for (; tmp != cur; tmp--, ct = ct->prev);
772 cmp = func(ct, item);
792 ct = eina_inlist_append_relative(list, item, ct);
796 ct = eina_inlist_prepend_relative(list, item, ct);
799 head = cur / state->jump_div;
800 offset = cur % state->jump_div;
802 _eina_inlist_sorted_state_insert(state, head, offset);
807 eina_inlist_sort(Eina_Inlist *head, Eina_Compare_Cb func)
811 Eina_Inlist *tail = head;
812 Eina_Inlist *unsort = NULL;
813 Eina_Inlist *stack[EINA_INLIST_SORT_STACK_SIZE];
815 EINA_SAFETY_ON_NULL_RETURN_VAL(head, NULL);
816 EINA_SAFETY_ON_NULL_RETURN_VAL(func, head);
820 unsigned int idx, tmp;
822 Eina_Inlist *a = tail;
823 Eina_Inlist *b = tail->next;
834 ((stack[i++] = a)->next = b)->next = 0;
836 ((stack[i++] = b)->next = a)->next = 0;
839 for (idx = n ^ tmp; idx &= idx - 1; i--)
840 stack[i - 2] = eina_inlist_sort_merge(stack[i - 2], stack[i - 1], func);
844 stack[i - 1] = eina_inlist_sort_merge(stack[i - 1], stack[i], func);
847 tail = eina_inlist_sort_rebuild_prev(head);
862 eina_inlist_iterator_new(const Eina_Inlist *list)
864 Eina_Iterator_Inlist *it;
867 it = calloc(1, sizeof (Eina_Iterator_Inlist));
870 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
877 it->iterator.version = EINA_ITERATOR_VERSION;
878 it->iterator.next = FUNC_ITERATOR_NEXT(eina_inlist_iterator_next);
879 it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
880 eina_inlist_iterator_get_container);
881 it->iterator.free = FUNC_ITERATOR_FREE(eina_inlist_iterator_free);
883 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
885 return &it->iterator;
889 eina_inlist_accessor_new(const Eina_Inlist *list)
891 Eina_Accessor_Inlist *ac;
894 ac = calloc(1, sizeof (Eina_Accessor_Inlist));
897 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
905 ac->accessor.version = EINA_ACCESSOR_VERSION;
906 ac->accessor.get_at = FUNC_ACCESSOR_GET_AT(eina_inlist_accessor_get_at);
907 ac->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(
908 eina_inlist_accessor_get_container);
909 ac->accessor.free = FUNC_ACCESSOR_FREE(eina_inlist_accessor_free);
911 EINA_MAGIC_SET(&ac->accessor, EINA_MAGIC_ACCESSOR);
913 return &ac->accessor;