1 #include "ecore_private.h"
3 #include "Ecore_Data.h"
5 /* Some tests showed that beyond that value heap sort is faster than merge sort
6 * (in this implementation). This value has to be changed or at least review
7 * if someone is changing the implementation. */
8 #define ECORE_MERGESORT_LIMIT 40000
10 /* Return information about the list */
11 static void *_ecore_list_current(Ecore_List * list);
13 /* Adding functions */
14 static int _ecore_list_insert(Ecore_List * list, Ecore_List_Node *node);
15 static int _ecore_list_append_0(Ecore_List * list, Ecore_List_Node *node);
16 static int _ecore_list_prepend_0(Ecore_List * list, Ecore_List_Node *node);
18 /* Remove functions */
19 static void *_ecore_list_remove_0(Ecore_List * list);
20 static void *_ecore_list_first_remove(Ecore_List * list);
21 static void *_ecore_list_last_remove(Ecore_List * list);
23 /* Basic traversal functions */
24 static void *_ecore_list_next(Ecore_List * list);
25 static void *_ecore_list_last_goto(Ecore_List * list);
26 static void *_ecore_list_first_goto(Ecore_List * list);
27 static void *_ecore_list_goto(Ecore_List * list, const void *data);
28 static void *_ecore_list_index_goto(Ecore_List *list, int index);
30 /* Iterative functions */
31 static int _ecore_list_for_each(Ecore_List *list, Ecore_For_Each function,
33 static void *_ecore_list_find(Ecore_List *list, Ecore_Compare_Cb function,
34 const void *user_data);
36 /* Sorting functions */
37 static Ecore_List_Node *_ecore_list_node_mergesort(Ecore_List_Node *first,
38 int n, Ecore_Compare_Cb compare, int order);
39 static Ecore_List_Node *_ecore_list_node_merge(Ecore_List_Node *first,
40 Ecore_List_Node *second,
41 Ecore_Compare_Cb compare,
43 static Ecore_List_Node *_ecore_dlist_node_mergesort(Ecore_List_Node *first,
44 int n, Ecore_Compare_Cb compare, int order);
45 static Ecore_List_Node *_ecore_dlist_node_merge(Ecore_List_Node *first,
46 Ecore_List_Node *second,
47 Ecore_Compare_Cb compare,
50 /* Private double linked list functions */
51 static void *_ecore_dlist_previous(Ecore_DList * list);
52 static void *_ecore_dlist_first_remove(Ecore_DList *list);
53 static void *_ecore_dlist_index_goto(Ecore_DList *list, int index);
55 /* XXX: Begin deprecated code */
57 _ecore_list2_append(void *in_list, void *in_item)
59 Ecore_List2 *l, *new_l;
60 Ecore_List2 *list, *item;
72 if (list->last) l = list->last;
73 else for (l = list; l; l = l->next);
81 _ecore_list2_prepend(void *in_list, void *in_item)
84 Ecore_List2 *list, *item;
98 new_l->last = list->last;
104 _ecore_list2_append_relative(void *in_list, void *in_item, void *in_relative)
107 Ecore_List2 *list, *item, *relative;
111 relative = in_relative;
112 for (l = list; l; l = l->next)
121 new_l->next = l->next;
122 l->next->prev = new_l;
125 else new_l->next = NULL;
133 return _ecore_list2_append(list, item);
137 _ecore_list2_prepend_relative(void *in_list, void *in_item, void *in_relative)
140 Ecore_List2 *list, *item, *relative;
144 relative = in_relative;
145 for (l = list; l; l = l->next)
152 new_l->prev = l->prev;
157 new_l->prev->next = new_l;
168 new_l->last = list->last;
175 return _ecore_list2_prepend(list, item);
179 _ecore_list2_remove(void *in_list, void *in_item)
181 Ecore_List2 *return_l;
182 Ecore_List2 *list, *item;
190 if (!item) return list;
192 item->next->prev = item->prev;
195 item->prev->next = item->next;
200 return_l = item->next;
202 return_l->last = list->last;
204 if (item == list->last)
205 list->last = item->prev;
212 _ecore_list2_find(void *in_list, void *in_item)
215 Ecore_List2 *list, *item;
219 for (l = list; l; l = l->next)
221 if (l == item) return item;
225 /* XXX: End deprecated code */
228 @defgroup Ecore_Data_List_Creation_Group List Creation/Destruction Functions
230 Functions that create, initialize and destroy Ecore_Lists.
234 * Create and initialize a new list.
235 * @return A new initialized list on success, @c NULL on failure.
236 * @ingroup Ecore_Data_List_Creation_Group
243 list = (Ecore_List *)malloc(sizeof(Ecore_List));
247 if (!ecore_list_init(list))
257 * Initialize a list to some sane starting values.
258 * @param list The list to initialize.
259 * @return @c TRUE if successful, @c FALSE if an error occurs.
260 * @ingroup Ecore_Data_List_Creation_Group
263 ecore_list_init(Ecore_List *list)
265 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
267 memset(list, 0, sizeof(Ecore_List));
273 * Free a list and all of it's nodes.
274 * @param list The list to be freed.
275 * @ingroup Ecore_Data_List_Creation_Group
278 ecore_list_destroy(Ecore_List *list)
282 CHECK_PARAM_POINTER("list", list);
286 data = _ecore_list_first_remove(list);
288 list->free_func(data);
295 * Set the function for freeing data.
296 * @param list The list that will use this function when nodes are
298 * @param free_func The function that will free the key data.
299 * @return @c TRUE on successful set, @c FALSE otherwise.
302 ecore_list_free_cb_set(Ecore_List *list, Ecore_Free_Cb free_func)
304 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
306 list->free_func = free_func;
312 * Checks the list for any nodes.
313 * @param list The list to check for nodes
314 * @return @c TRUE if no nodes in list, @c FALSE if the list contains nodes
317 ecore_list_empty_is(Ecore_List *list)
321 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
330 * Returns the number of the current node.
331 * @param list The list to return the number of the current node.
332 * @return The number of the current node in the list.
335 ecore_list_index(Ecore_List *list)
339 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
347 * Find the number of nodes in the list.
348 * @param list The list to find the number of nodes
349 * @return The number of nodes in the list.
352 ecore_list_count(Ecore_List *list)
356 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
364 @defgroup Ecore_Data_List_Add_Item_Group List Item Adding Functions
366 Functions that are used to add nodes to an Ecore_List.
370 * Append data to the list.
371 * @param list The list.
372 * @param data The data to append.
373 * @return @c FALSE if an error occurs, @c TRUE if appended successfully
374 * @ingroup Ecore_Data_List_Add_Item_Group
377 ecore_list_append(Ecore_List *list, void *data)
380 Ecore_List_Node *node;
382 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
384 node = ecore_list_node_new();
387 ret = _ecore_list_append_0(list, node);
392 /* For adding items to the end of the list */
394 _ecore_list_append_0(Ecore_List *list, Ecore_List_Node *end)
397 list->last->next = end;
401 if (list->first == NULL)
405 list->current = NULL;
408 if (list->index >= list->nodes)
417 * Prepend data to the beginning of the list.
418 * @param list The list.
419 * @param data The data to prepend.
420 * @return @c FALSE if an error occurs, @c TRUE if prepended successfully.
421 * @ingroup Ecore_Data_List_Add_Item_Group
424 ecore_list_prepend(Ecore_List *list, void *data)
427 Ecore_List_Node *node;
429 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
431 node = ecore_list_node_new();
434 ret = _ecore_list_prepend_0(list, node);
439 /* For adding items to the beginning of the list */
441 _ecore_list_prepend_0(Ecore_List *list, Ecore_List_Node *start)
443 /* Put it at the beginning of the list */
444 start->next = list->first;
448 /* If no last node, then the first node is the last node */
449 if (list->last == NULL)
450 list->last = list->first;
459 * Insert data in front of the current point in the list.
460 * @param list The list to hold the inserted @p data.
461 * @param data The data to insert into @p list.
462 * @return @c FALSE if there is an error, @c TRUE on success
463 * @ingroup Ecore_Data_List_Add_Item_Group
466 ecore_list_insert(Ecore_List *list, void *data)
469 Ecore_List_Node *node;
471 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
473 node = ecore_list_node_new();
476 ret = _ecore_list_insert(list, node);
481 /* For adding items in front of the current position in the list */
483 _ecore_list_insert(Ecore_List *list, Ecore_List_Node *new_node)
486 * If the current point is at the beginning of the list, then it's the
487 * same as prepending it to the list.
489 if (list->current == list->first)
490 return _ecore_list_prepend_0(list, new_node);
492 if (list->current == NULL)
496 ret_value = _ecore_list_append_0(list, new_node);
497 list->current = list->last;
502 /* Setup the fields of the new node */
503 new_node->next = list->current;
505 /* And hook the node into the list */
506 _ecore_list_index_goto(list, ecore_list_index(list) - 1);
508 list->current->next = new_node;
510 /* Now move the current item to the inserted item */
511 list->current = new_node;
517 * Append a list to the list.
518 * @param list The list.
519 * @param append The list to append.
520 * @return @c FALSE if an error occurs, @c TRUE if appended successfully
521 * @ingroup Ecore_Data_List_Add_Item_Group
525 ecore_list_append_list(Ecore_List *list, Ecore_List *append)
527 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
528 CHECK_PARAM_POINTER_RETURN("append", append, FALSE);
530 if (ecore_list_empty_is(append)) return TRUE;
532 if (ecore_list_empty_is(list))
534 list->first = append->first;
535 list->current = list->first;
536 list->last = append->last;
537 list->nodes = append->nodes;
541 list->last->next = append->first;
542 list->last = append->last;
543 list->nodes += append->nodes;
545 ecore_list_init(append);
550 * Prepend a list to the beginning of the list.
551 * @param list The list.
552 * @param prepend The list to prepend.
553 * @return @c FALSE if an error occurs, @c TRUE if prepended successfully.
554 * @ingroup Ecore_Data_List_Add_Item_Group
557 ecore_list_prepend_list(Ecore_List *list, Ecore_List *prepend)
559 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
560 CHECK_PARAM_POINTER_RETURN("prepend", prepend, FALSE);
562 if (ecore_list_empty_is(prepend)) return TRUE;
564 if (ecore_list_empty_is(list))
566 list->first = prepend->first;
567 list->current = NULL;
568 list->last = prepend->last;
569 list->nodes = prepend->nodes;
573 prepend->last->next = list->first;
574 list->first = prepend->first;
575 list->nodes += prepend->nodes;
576 list->index += prepend->nodes;
578 ecore_list_init(prepend);
583 @defgroup Ecore_Data_List_Remove_Item_Group List Item Removing Functions
585 Functions that remove nodes from an Ecore_List.
589 * Remove the current item from the list.
590 * @param list The list to remove the current item
591 * @return A pointer to the removed data on success, @c NULL on failure.
592 * @ingroup Ecore_Data_List_Remove_Item_Group
595 ecore_list_remove(Ecore_List *list)
599 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
601 ret = _ecore_list_remove_0(list);
606 /* Remove the current item from the list */
608 _ecore_list_remove_0(Ecore_List *list)
611 Ecore_List_Node *old;
616 if (ecore_list_empty_is(list))
622 if (list->current == list->first)
623 return _ecore_list_first_remove(list);
625 if (list->current == list->last)
626 return _ecore_list_last_remove(list);
630 _ecore_list_index_goto(list, list->index - 1);
632 list->current->next = old->next;
637 _ecore_list_next(list);
639 ecore_list_node_destroy(old, NULL);
646 * Remove and free the data in lists current position.
647 * @param list The list to remove and free the current item.
648 * @return @c TRUE on success, @c FALSE on error
649 * @ingroup Ecore_Data_List_Remove_Item_Group
652 ecore_list_remove_destroy(Ecore_List *list)
656 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
658 data = _ecore_list_remove_0(list);
660 list->free_func(data);
666 * Remove the first item from the list.
667 * @param list The list to remove the current item
668 * @return Returns a pointer to the removed data on success, @c NULL on
670 * @ingroup Ecore_Data_List_Remove_Item_Group
673 ecore_list_first_remove(Ecore_List *list)
677 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
679 ret = _ecore_list_first_remove(list);
684 /* Remove the first item from the list */
686 _ecore_list_first_remove(Ecore_List *list)
689 Ecore_List_Node *old;
694 if (ecore_list_empty_is(list))
699 list->first = list->first->next;
701 if (list->current == old)
702 list->current = list->first;
704 (list->index ? list->index-- : 0);
706 if (list->last == old)
707 list->last = list->first;
712 ecore_list_node_destroy(old, NULL);
719 * Remove the last item from the list.
720 * @param list The list to remove the last node from
721 * @return A pointer to the removed data on success, @c NULL on failure.
722 * @ingroup Ecore_Data_List_Remove_Item_Group
725 ecore_list_last_remove(Ecore_List *list)
729 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
731 ret = _ecore_list_last_remove(list);
736 /* Remove the last item from the list */
738 _ecore_list_last_remove(Ecore_List *list)
741 Ecore_List_Node *old, *prev;
746 if (ecore_list_empty_is(list))
750 if (list->current == old)
751 list->current = NULL;
753 if (list->first == old)
755 for (prev = list->first; prev && prev->next != old; prev = prev->next);
764 ecore_list_node_destroy(old, NULL);
771 @defgroup Ecore_Data_List_Traverse_Group List Traversal Functions
773 Functions that can be used to traverse an Ecore_List.
777 * Make the current item the item with the given index number.
778 * @param list The list.
779 * @param index The position to move the current item.
780 * @return A pointer to new current item on success, @c NULL on failure.
781 * @ingroup Ecore_Data_List_Traverse_Group
784 ecore_list_index_goto(Ecore_List *list, int index)
788 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
790 ret = _ecore_list_index_goto(list, index);
795 /* This is the non-threadsafe version, use this inside internal functions that
796 * already lock the list */
798 _ecore_list_index_goto(Ecore_List *list, int index)
805 if (ecore_list_empty_is(list))
808 if (index > ecore_list_count(list) || index < 0)
811 if (index < list->index)
813 _ecore_list_first_goto(list);
819 for (; i < index && _ecore_list_next(list); i++);
821 if (i >= list->nodes)
826 return list->current->data;
830 * Make the current item the node that contains @p data.
831 * @param list The list.
832 * @param data The data to find.
833 * @return A pointer to @p data on success, @c NULL on failure.
834 * @ingroup Ecore_Data_List_Traverse_Group
837 ecore_list_goto(Ecore_List *list, const void *data)
841 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
843 ret = _ecore_list_goto(list, data);
848 /* Set the current position to the node containing data */
850 _ecore_list_goto(Ecore_List *list, const void *data)
853 Ecore_List_Node *node;
861 while (node && node->data)
863 Ecore_List_Node *next;
865 if (node->data == data)
878 list->current = node;
881 return list->current->data;
885 * Make the current item the first item in the list
886 * @param list The list.
887 * @return A pointer to the first item on success, @c NULL on failure
888 * @ingroup Ecore_Data_List_Traverse_Group
891 ecore_list_first_goto(Ecore_List *list)
895 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
897 ret = _ecore_list_first_goto(list);
902 /* Set the current position to the start of the list */
904 _ecore_list_first_goto(Ecore_List *list)
906 if (!list || !list->first)
909 list->current = list->first;
912 return list->current->data;
916 * Make the current item the last item in the list.
917 * @param list The list.
918 * @return A pointer to the last item on success, @c NULL on failure.
919 * @ingroup Ecore_Data_List_Traverse_Group
922 ecore_list_last_goto(Ecore_List *list)
926 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
928 ret = _ecore_list_last_goto(list);
933 /* Set the current position to the end of the list */
935 _ecore_list_last_goto(Ecore_List *list)
937 if (!list || !list->last)
940 list->current = list->last;
941 list->index = (list->nodes - 1);
943 return list->current->data;
947 * Retrieve the data pointed to by the current item in @p list.
948 * @param list The list.
949 * @return Returns the data at current position, can be @c NULL.
952 ecore_list_current(Ecore_List *list)
956 ret = _ecore_list_current(list);
962 * Retrieve the data pointed to by the first item in @p list.
963 * @param list The list.
964 * @return Returns the data at current position, can be @c NULL.
967 ecore_list_first(Ecore_List *list)
973 ret = list->first->data;
979 * Retrieve the data pointed to by the last item in @p list.
980 * @param list The list.
981 * @return Returns the data at current position, can be @c NULL.
984 ecore_list_last(Ecore_List *list)
990 ret = list->last->data;
995 /* Return the data of the current node without incrementing */
997 _ecore_list_current(Ecore_List *list)
1004 ret = list->current->data;
1010 * Retrieve the data pointed to by the current item, and make the next item
1012 * @param list The list to retrieve data from.
1013 * @return The current item in the list on success, @c NULL on failure.
1016 ecore_list_next(Ecore_List *list)
1020 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1022 data = _ecore_list_next(list);
1027 /* Return the data contained in the current node and go to the next node */
1029 _ecore_list_next(Ecore_List *list)
1032 Ecore_List_Node *ret;
1033 Ecore_List_Node *next;
1038 ret = list->current;
1039 next = list->current->next;
1041 list->current = next;
1050 * Remove all nodes from @p list.
1051 * @param list The list.
1052 * @return Returns @c TRUE on success, @c FALSE on error.
1053 * @note The data for each item on the list is not freed by
1054 * @c ecore_list_clear().
1057 ecore_list_clear(Ecore_List *list)
1059 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1061 while (!ecore_list_empty_is(list))
1062 _ecore_list_first_remove(list);
1068 * Execute function for each node in @p list.
1069 * @param list The list.
1070 * @param function The function to pass each node from @p list to.
1071 * @return Returns @c TRUE on success, @c FALSE on failure.
1072 * @ingroup Ecore_Data_List_Traverse_Group
1075 ecore_list_for_each(Ecore_List *list, Ecore_For_Each function, void *user_data)
1079 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1081 ret = _ecore_list_for_each(list, function, user_data);
1086 /* The real meat of executing the function for each data node */
1088 _ecore_list_for_each(Ecore_List *list, Ecore_For_Each function, void *user_data)
1092 if (!list || !function)
1095 _ecore_list_first_goto(list);
1096 while ((value = _ecore_list_next(list)) != NULL)
1097 function(value, user_data);
1103 * Find data in @p list using the compare function @p func
1104 * @param list The list.
1105 * @param function The function to test each node of @p list with
1106 * @param user_data Data to match against (used by @p function)
1107 * @return the first matching data node, or NULL if none match
1110 ecore_list_find(Ecore_List *list, Ecore_Compare_Cb function, const void *user_data)
1112 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1114 return _ecore_list_find(list, function, user_data);
1117 /* The real meat of finding a node via a compare cb */
1119 _ecore_list_find(Ecore_List *list, Ecore_Compare_Cb function, const void *user_data)
1122 if (!list || !function) return NULL;
1124 _ecore_list_first_goto(list);
1125 while ((value = _ecore_list_current(list)) != NULL)
1127 if (!function(value, user_data)) return value;
1128 ecore_list_next(list);
1135 * Sort data in @p list using the compare function @p compare
1136 * @param list The list.
1137 * @param compare The function to compare the data of @p list
1138 * @param order The sort direction, possible values are ECORE_SORT_MIN and
1140 * @return true on success
1142 * This is a wrapper function for mergesort and heapsort. It
1143 * tries to choose the fastest algorithm depending on the
1144 * number of notes. Note: The sort may be unstable.
1147 ecore_list_sort(Ecore_List *list, Ecore_Compare_Cb compare, char order)
1149 CHECK_PARAM_POINTER_RETURN("list", list, 0);
1151 if (list->nodes < 2)
1153 if (list->nodes < ECORE_MERGESORT_LIMIT)
1154 return ecore_list_mergesort(list, compare, order);
1155 if (!ecore_list_heapsort(list, compare, order))
1156 return ecore_list_mergesort(list, compare, order);
1162 * Sort data in @p list using the compare function @p compare
1163 * @param list The list.
1164 * @param compare The function to compare the data of @p list
1165 * @param order The sort direction, possible values are ECORE_SORT_MIN and
1167 * @return true on success
1169 * Mergesort is a stable, in-place sorting algorithm
1172 ecore_list_mergesort(Ecore_List *list, Ecore_Compare_Cb compare, char order)
1174 Ecore_List_Node *node;
1176 CHECK_PARAM_POINTER_RETURN("list", list, 0);
1177 if (list->nodes < 2)
1180 if (order == ECORE_SORT_MIN)
1185 node = _ecore_list_node_mergesort(list->first, list->nodes, compare, order);
1188 /* maybe there is a better way to do that but our last node has changed */
1193 _ecore_list_first_goto(list);
1199 * Merge the @p l2 into the @p list using the compare function @p compare.
1200 * Both lists need to be sorted else a corrupt list could be the result.
1201 * @param list The list.
1202 * @param l2 The second list, this list will be empty after the merge
1203 * @param compare The function to compare the data of @p list and @p l2
1204 * @param order The sort direction, possible values are ECORE_SORT_MIN and
1208 ecore_list_merge(Ecore_List *list, Ecore_List *l2, Ecore_Compare_Cb compare, char order)
1210 CHECK_PARAM_POINTER("list", list);
1211 CHECK_PARAM_POINTER("l2", l2);
1213 if (ecore_list_empty_is(l2)) return;
1215 if (ecore_list_empty_is(list))
1217 ecore_list_append_list(list, l2);
1221 if (order == ECORE_SORT_MIN)
1226 list->first = _ecore_list_node_merge(list->first, l2->first, compare, order);
1228 if ((order * compare(list->last->data, l2->last->data)) < 0)
1229 list->last = l2->last;
1231 list->nodes += l2->nodes;
1232 ecore_list_init(l2);
1235 /* this is the internal recrusive function for the merge sort */
1236 static Ecore_List_Node *
1237 _ecore_list_node_mergesort(Ecore_List_Node *first, int n,
1238 Ecore_Compare_Cb compare, int order)
1240 Ecore_List_Node *middle;
1241 Ecore_List_Node *premid;
1251 if (compare(first->data, first->next->data) * order > 0)
1255 data = first->next->data;
1256 first->next->data = first->data;
1262 /* first find the premiddle node*/
1263 for (premid = first, i = 0; i < mid - 1; i++)
1264 premid = premid->next;
1266 /* split the list */
1267 middle = premid->next;
1268 premid->next = NULL;
1270 /* sort the the partial lists */
1271 first = _ecore_list_node_mergesort(first, mid, compare, order);
1272 middle = _ecore_list_node_mergesort(middle, n - mid, compare, order);
1274 return _ecore_list_node_merge(first, middle, compare, order);
1277 /* this function is used to merge the partial sorted lists */
1278 static Ecore_List_Node *
1279 _ecore_list_node_merge(Ecore_List_Node *first, Ecore_List_Node *second,
1280 Ecore_Compare_Cb compare, int order)
1282 Ecore_List_Node *list;
1285 /* select the first node outside the loop, because we need to keep
1286 * a pointer to it */
1287 if (compare(first->data, second->data) * order > 0)
1290 second = second->next;
1295 first = first->next;
1298 /* and now start the merging */
1299 while (first && second)
1301 if (compare(first->data, second->data) * order > 0)
1303 l = l->next = second;
1304 second = second->next;
1308 l = l->next = first;
1309 first = first->next;
1313 /* append the rest or set it to NULL */
1325 * Sort data in @p list using the compare function @p compare
1326 * @param list The list.
1327 * @param compare The function to compare the data of @p list
1328 * @param order The sort direction, possible values are ECORE_SORT_MIN and
1330 * @return true on success
1332 * Heapsort is a unstable sorting algorithm, it needs to allocate extra memomry,
1333 * but there for it is for a great number of nodes faster than mergesort
1336 ecore_list_heapsort(Ecore_List *list, Ecore_Compare_Cb compare, char order)
1339 Ecore_List_Node *node;
1342 CHECK_PARAM_POINTER_RETURN("list", list, 0);
1344 * Push the data into a heap.
1346 heap = ecore_sheap_new(compare, list->nodes);
1350 ecore_sheap_order_set(heap, order);
1351 _ecore_list_first_goto(list);
1352 while ((data = _ecore_list_next(list)))
1354 ecore_sheap_insert(heap, data);
1358 * Extract in sorted order.
1363 node->data = ecore_sheap_extract(heap);
1367 ecore_sheap_destroy(heap);
1369 _ecore_list_first_goto(list);
1373 /* Initialize a node to starting values */
1375 ecore_list_node_init(Ecore_List_Node *node)
1377 CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
1386 @defgroup Ecore_Data_List_Node_Group List Node Functions
1388 Functions that are used in the creation, maintenance and destruction of
1393 * Allocates and initializes a new list node.
1394 * @return A new Ecore_List_Node on success, @c NULL otherwise.
1395 * @ingroup Ecore_Data_List_Node_Group
1397 EAPI Ecore_List_Node *
1398 ecore_list_node_new()
1400 Ecore_List_Node *new_node;
1402 new_node = malloc(sizeof(Ecore_List_Node));
1404 if (!ecore_list_node_init(new_node))
1414 * Calls the function to free the data and the node.
1415 * @param node Node to destroy.
1416 * @param free_func Function to call if @p node points to data to free.
1418 * @ingroup Ecore_Data_List_Node_Group
1421 ecore_list_node_destroy(Ecore_List_Node *node, Ecore_Free_Cb free_func)
1423 CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
1425 if (free_func && node->data)
1426 free_func(node->data);
1434 * @defgroup Ecore_Data_DList_Creation_Group Doubly Linked List Creation/Destruction Functions
1436 * Functions used to create, initialize and destroy @c Ecore_DLists.
1440 * Creates and initialises a new doubly linked list.
1441 * @return A new initialised doubly linked list on success, @c NULL
1443 * @ingroup Ecore_Data_DList_Creation_Group
1448 Ecore_DList *list = NULL;
1450 list = (Ecore_DList *)malloc(sizeof(Ecore_DList));
1454 if (!ecore_dlist_init(list))
1464 * Initialises a list to some sane starting values.
1465 * @param list The doubly linked list to initialise.
1466 * @return @c TRUE if successful, @c FALSE if an error occurs.
1467 * @ingroup Ecore_Data_DList_Creation_Group
1470 ecore_dlist_init(Ecore_DList *list)
1472 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1474 memset(list, 0, sizeof(Ecore_DList));
1480 * Frees a doubly linked list and all of its nodes.
1481 * @param list The doubly linked list to be freed.
1482 * @ingroup Ecore_Data_DList_Creation_Group
1485 ecore_dlist_destroy(Ecore_DList *list)
1488 CHECK_PARAM_POINTER("list", list);
1492 data = _ecore_dlist_first_remove(list);
1493 if (list->free_func)
1494 list->free_func(data);
1501 * Sets the function used for freeing data stored in a doubly linked list.
1502 * @param list The doubly linked list that will use this function when
1503 * nodes are destroyed.
1504 * @param free_func The function that will free the key data
1505 * @return @c TRUE on success, @c FALSE on failure.
1506 * @ingroup Ecore_Data_DList_Creation_Group
1509 ecore_dlist_free_cb_set(Ecore_DList *list, Ecore_Free_Cb free_func)
1511 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1513 return ecore_list_free_cb_set(ECORE_LIST(list), free_func);
1517 * Returns whether there is anything in the given doubly linked list.
1518 * @param list The given doubly linked list.
1519 * @return @c TRUE if there are nodes, @c FALSE otherwise.
1522 ecore_dlist_empty_is(Ecore_DList *list)
1524 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1526 return ecore_list_empty_is(ECORE_LIST(list));
1530 * Retrieves the index of the current node of the given doubly linked list.
1531 * @param list The given doubly linked list.
1532 * @return The index of the current node.
1535 ecore_dlist_index(Ecore_DList *list)
1537 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1539 return ecore_list_index(ECORE_LIST(list));
1543 * @defgroup Ecore_Data_DList_Add_Item_Group Doubly Linked List Adding Functions
1545 * Functions that are used to add nodes to an Ecore_DList.
1549 * Appends data to the given doubly linked list.
1550 * @param list The given doubly linked list.
1551 * @param data The data to append.
1552 * @return @c TRUE if the data is successfully appended, @c FALSE otherwise.
1553 * @ingroup Ecore_Data_DList_Add_Item_Group
1556 ecore_dlist_append(Ecore_DList *list, void *data)
1559 Ecore_DList_Node *prev;
1560 Ecore_DList_Node *node;
1562 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1564 node = ecore_dlist_node_new();
1565 ECORE_LIST_NODE(node)->data = data;
1567 prev = ECORE_DLIST_NODE(ECORE_LIST(list)->last);
1568 ret = _ecore_list_append_0(ECORE_LIST(list), ECORE_LIST_NODE(node));
1570 node->previous = prev;
1576 * Adds data to the very beginning of the given doubly linked list.
1577 * @param list The given doubly linked list.
1578 * @param data The data to prepend.
1579 * @return @c TRUE if the data is successfully prepended, @c FALSE otherwise.
1580 * @ingroup Ecore_Data_DList_Add_Item_Group
1583 ecore_dlist_prepend(Ecore_DList *list, void *data)
1586 Ecore_DList_Node *prev;
1587 Ecore_DList_Node *node;
1589 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1591 node = ecore_dlist_node_new();
1592 ECORE_LIST_NODE(node)->data = data;
1594 prev = ECORE_DLIST_NODE(ECORE_LIST(list)->first);
1595 ret = _ecore_list_prepend_0(ECORE_LIST(list), ECORE_LIST_NODE(node));
1597 prev->previous = node;
1603 * Inserts data at the current point in the given doubly linked list.
1604 * @param list The given doubly linked list.
1605 * @param data The data to be inserted.
1606 * @return @c TRUE on success, @c FALSE otherwise.
1607 * @ingroup Ecore_Data_DList_Add_Item_Group
1610 ecore_dlist_insert(Ecore_DList *list, void *data)
1613 Ecore_DList_Node *prev;
1614 Ecore_DList_Node *node;
1616 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1619 * Identify and shortcut the end cases.
1621 if (!ECORE_LIST(list)->current)
1622 return ecore_dlist_append(list, data);
1623 if (ECORE_LIST(list)->current == ECORE_LIST(list)->first)
1624 return ecore_dlist_prepend(list, data);
1626 node = ecore_dlist_node_new();
1627 ECORE_LIST_NODE(node)->data = data;
1629 /* Setup the fields of the new node */
1630 ECORE_LIST_NODE(node)->next = ECORE_LIST(list)->current;
1632 /* And hook the node into the list */
1633 prev = ECORE_DLIST_NODE(ECORE_LIST(list)->current)->previous;
1634 ECORE_LIST_NODE(prev)->next = ECORE_LIST_NODE(node);
1635 ECORE_DLIST_NODE(ECORE_LIST(list)->current)->previous = node;
1636 node->previous = prev;
1638 /* Now move the current item to the inserted item */
1639 ECORE_LIST(list)->current = ECORE_LIST_NODE(node);
1640 ECORE_LIST(list)->nodes++;
1646 * Appends a list to the given doubly linked list.
1647 * @param list The given doubly linked list.
1648 * @param append The list to append.
1649 * @return @c TRUE if the data is successfully appended, @c FALSE otherwise.
1650 * @ingroup Ecore_Data_DList_Add_Item_Group
1653 ecore_dlist_append_list(Ecore_DList *list, Ecore_DList *append)
1655 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1656 CHECK_PARAM_POINTER_RETURN("append", append, FALSE);
1658 if (ecore_dlist_empty_is(append)) return TRUE;
1660 if (ecore_dlist_empty_is(list))
1662 list->first = append->first;
1663 list->current = NULL;
1664 list->last = append->last;
1665 list->nodes = append->nodes;
1669 list->last->next = append->first;
1670 ECORE_DLIST_NODE(append->first)->previous = ECORE_DLIST_NODE(list->last);
1671 list->last = append->last;
1672 list->nodes += append->nodes;
1674 ecore_dlist_init(append);
1679 * Adds a list to the very beginning of the given doubly linked list.
1680 * @param list The given doubly linked list.
1681 * @param prepend The list to prepend.
1682 * @return @c TRUE if the data is successfully prepended, @c FALSE otherwise.
1683 * @ingroup Ecore_Data_DList_Add_Item_Group
1686 ecore_dlist_prepend_list(Ecore_DList *list, Ecore_DList *prepend)
1688 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1689 CHECK_PARAM_POINTER_RETURN("prepend", prepend, FALSE);
1691 if (ecore_dlist_empty_is(prepend)) return TRUE;
1693 if (ecore_dlist_empty_is(list))
1695 list->first = prepend->first;
1696 list->current = NULL;
1697 list->last = prepend->last;
1698 list->nodes = prepend->nodes;
1702 prepend->last->next = list->first;
1703 ECORE_DLIST_NODE(list->first)->previous = ECORE_DLIST_NODE(prepend->last);
1704 list->first = prepend->first;
1705 list->nodes += prepend->nodes;
1706 list->index += prepend->nodes;
1708 ecore_dlist_init(prepend);
1713 * @defgroup Ecore_Data_DList_Remove_Item_Group Doubly Linked List Removing Functions
1715 * Functions that remove nodes from an @c Ecore_DList.
1719 * Removes the current item from the given doubly linked list.
1720 * @param list The given doubly linked list.
1721 * @return A pointer to the removed data on success, @c NULL otherwise.
1722 * @ingroup Ecore_Data_DList_Remove_Item_Group
1725 ecore_dlist_remove(Ecore_DList *list)
1728 Ecore_List *l2 = ECORE_LIST(list);
1729 Ecore_DList_Node *node;
1731 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1735 node = ECORE_DLIST_NODE(list->current->next);
1737 node->previous = ECORE_DLIST_NODE(l2->current)->previous;
1739 ret = _ecore_list_remove_0(list);
1745 * Removes the first item from the given doubly linked list.
1746 * @param list The given doubly linked list.
1747 * @return A pointer to the removed data on success, @c NULL on failure.
1748 * @ingroup Ecore_Data_DList_Remove_Item_Group
1751 ecore_dlist_first_remove(Ecore_DList *list)
1755 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1757 ret = _ecore_dlist_first_remove(list);
1763 * Removes and frees the data at the current position in the given doubly
1765 * @param list The given doubly linked list.
1766 * @return @c TRUE on success, @c FALSE otherwise.
1767 * @ingroup Ecore_Data_DList_Remove_Item_Group
1770 ecore_dlist_remove_destroy(Ecore_DList *list)
1774 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1776 data = ecore_dlist_remove(list);
1780 if (list->free_func)
1781 list->free_func(data);
1787 _ecore_dlist_first_remove(Ecore_DList *list)
1794 ret = _ecore_list_first_remove(list);
1795 if (ret && ECORE_LIST(list)->first)
1796 ECORE_DLIST_NODE(ECORE_LIST(list)->first)->previous = NULL;
1802 * Removes the last item from the given doubly linked list.
1803 * @param list The given doubly linked list.
1804 * @return A pointer to the removed data on success, @c NULL otherwise.
1805 * @ingroup Ecore_Data_DList_Remove_Item_Group
1808 ecore_dlist_last_remove(Ecore_DList *list)
1811 Ecore_List_Node *node;
1813 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1815 if (ecore_list_empty_is(list))
1819 list->last = ECORE_LIST_NODE(ECORE_DLIST_NODE(node)->previous);
1821 list->last->next = NULL;
1822 if (list->first == node)
1824 if (list->current == node)
1825 list->current = NULL;
1828 ecore_list_node_destroy(node, NULL);
1831 if (list->index >= list->nodes)
1838 * Moves the current item to the index number in the given doubly linked list.
1839 * @param list The given doubly linked list.
1840 * @param index The position to move the current item
1841 * @return The node at specified index on success, @c NULL on error.
1844 ecore_dlist_index_goto(Ecore_DList *list, int index)
1848 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1850 ret = _ecore_dlist_index_goto(list, index);
1855 /* This is the non-threadsafe version, use this inside internal functions that
1856 * already lock the list */
1858 _ecore_dlist_index_goto(Ecore_DList *list, int index)
1865 if (ecore_list_empty_is(ECORE_LIST(list)))
1868 if (index > ecore_list_count(ECORE_LIST(list)) || index < 0)
1871 if (ECORE_LIST(list)->index >= ECORE_LIST(list)->nodes)
1872 _ecore_list_last_goto(ECORE_LIST(list));
1874 if (index < ECORE_LIST(list)->index)
1879 for (i = ECORE_LIST(list)->index; i != index; i += increment)
1882 _ecore_list_next(list);
1884 _ecore_dlist_previous(list);
1887 return _ecore_list_current(list);
1891 * @brief Move the current item to the node that contains data
1892 * @param list: the list to move the current item in
1893 * @param data: the data to find and set the current item to
1895 * @return Returns specified data on success, NULL on error
1898 ecore_dlist_goto(Ecore_DList *list, void *data)
1902 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1904 ret = _ecore_list_goto(ECORE_LIST(list), data);
1910 * @brief Move the current pointer to the first item in the list
1911 * @param list: the list to change the current to the first item
1913 * @return Returns a pointer to the first item on success, NULL on failure.
1916 ecore_dlist_first_goto(Ecore_DList *list)
1920 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1922 ret = _ecore_list_first_goto(list);
1928 * @brief Move the pointer to the current item to the last item
1929 * @param list: the list to move the current item pointer to the last
1930 * @return Returns a pointer to the last item in the list , NULL if empty.
1933 ecore_dlist_last_goto(Ecore_DList *list)
1937 CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1939 ret = _ecore_list_last_goto(ECORE_LIST(list));
1945 * @brief Return the data in the current list item
1946 * @param list: the list to the return the current data
1947 * @return Returns value of the current data item, NULL if no current item
1950 ecore_dlist_current(Ecore_DList *list)
1954 ret = _ecore_list_current(ECORE_LIST(list));
1960 * @brief Move to the next item in the list and return current item
1961 * @param list: the list to move to the next item in.
1962 * @return Returns data in the current list node, or NULL on error
1965 ecore_dlist_next(Ecore_DList *list)
1969 data = _ecore_list_next(list);
1975 * @brief Move to the previous item and return current item
1976 * @param list: the list to move to the previous item in.
1977 * @return Returns data in the current list node, or NULL on error
1980 ecore_dlist_previous(Ecore_DList *list)
1984 data = _ecore_dlist_previous(list);
1990 _ecore_dlist_previous(Ecore_DList *list)
1997 if (ECORE_LIST(list)->current)
1999 data = ECORE_LIST(list)->current->data;
2000 ECORE_LIST(list)->current = ECORE_LIST_NODE(ECORE_DLIST_NODE(
2001 ECORE_LIST(list)->current)->previous);
2002 ECORE_LIST(list)->index--;
2005 _ecore_list_last_goto(ECORE_LIST(list));
2011 * @brief Remove all nodes from the list.
2012 * @param list: the list to remove all nodes from
2014 * @return Returns TRUE on success, FALSE on errors
2017 ecore_dlist_clear(Ecore_DList *list)
2019 CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
2021 ecore_list_clear(ECORE_LIST(list));
2027 * Sort data in @p list using the compare function @p compare
2028 * @param list The list.
2029 * @param compare The function to compare the data of @p list
2030 * @param order The sort direction, possible values are ECORE_SORT_MIN and
2032 * @return true on success
2034 * This is a wrapper function for mergesort and heapsort. It
2035 * tries to choose the fastest algorithm depending on the
2036 * number of notes. Note: The sort may be unstable.
2039 ecore_dlist_sort(Ecore_List *list, Ecore_Compare_Cb compare, char order)
2041 CHECK_PARAM_POINTER_RETURN("list", list, 0);
2043 if (list->nodes < 2)
2045 if (list->nodes < ECORE_MERGESORT_LIMIT)
2046 return ecore_dlist_mergesort(list, compare, order);
2047 if (!ecore_dlist_heapsort(list, compare, order))
2048 return ecore_dlist_mergesort(list, compare, order);
2054 * Sort data in @p list using the compare function @p compare
2055 * @param list The list.
2056 * @param compare The function to compare the data of @p list
2057 * @param order The sort direction, possible values are ECORE_SORT_MIN and
2059 * @return true on success
2061 * Mergesort is a stable, in-place sorting algorithm
2064 ecore_dlist_mergesort(Ecore_DList *list, Ecore_Compare_Cb compare, char order)
2066 Ecore_List_Node *node;
2068 CHECK_PARAM_POINTER_RETURN("list", list, 0);
2069 if (list->nodes < 2)
2072 if (order == ECORE_SORT_MIN)
2077 node = _ecore_dlist_node_mergesort(list->first, list->nodes, compare, order);
2080 /* maybe there is a better way to do that but our last node has changed */
2085 _ecore_list_first_goto(list);
2091 * Merge the @p l2 into the @p list using the compare function @p compare.
2092 * Both lists need to be sorted else a corrupt list could be the result.
2093 * @param list The list.
2094 * @param l2 The second list, this list will be empty after the merge
2095 * @param compare The function to compare the data of @p list and @p l2
2096 * @param order The sort direction, possible values are ECORE_SORT_MIN and
2100 ecore_dlist_merge(Ecore_DList *list, Ecore_DList *l2, Ecore_Compare_Cb compare, char order)
2102 CHECK_PARAM_POINTER("list", list);
2103 CHECK_PARAM_POINTER("l2", l2);
2105 if (ecore_dlist_empty_is(l2)) return;
2107 if (ecore_dlist_empty_is(list))
2109 ecore_dlist_append_list(list, l2);
2113 if (order == ECORE_SORT_MIN)
2118 list->first = _ecore_dlist_node_merge(list->first, l2->first, compare, order);
2120 if ((order * compare(list->last->data, l2->last->data)) < 0)
2121 list->last = l2->last;
2123 list->nodes += l2->nodes;
2124 ecore_dlist_init(l2);
2127 /* this is the internal recrusive function for the merge sort */
2128 static Ecore_List_Node *
2129 _ecore_dlist_node_mergesort(Ecore_List_Node *first, int n,
2130 Ecore_Compare_Cb compare, int order)
2132 Ecore_List_Node *middle;
2133 Ecore_List_Node *premid;
2143 if (compare(first->data, first->next->data) * order > 0)
2147 data = first->next->data;
2148 first->next->data = first->data;
2154 /* first find the premiddle node*/
2155 for (premid = first, i = 0; i < mid - 1; i++)
2156 premid = premid->next;
2158 /* split the list */
2159 middle = premid->next;
2160 premid->next = NULL;
2161 ECORE_DLIST_NODE(middle)->previous = NULL;
2163 /* sort the the partial lists */
2164 first = _ecore_dlist_node_mergesort(first, mid, compare, order);
2165 middle = _ecore_dlist_node_mergesort(middle, n - mid, compare, order);
2167 return _ecore_dlist_node_merge(first, middle, compare, order);
2170 /* this function is used to merge the partial sorted lists */
2171 static Ecore_List_Node *
2172 _ecore_dlist_node_merge(Ecore_List_Node *first, Ecore_List_Node *second,
2173 Ecore_Compare_Cb compare, int order)
2175 Ecore_List_Node *list;
2178 /* select the first node outside the loop, because we need to keep
2179 * a pointer to it */
2180 if (compare(first->data, second->data) * order > 0)
2183 second = second->next;
2188 first = first->next;
2191 /* and now start the merging */
2192 while (first && second)
2194 if (compare(first->data, second->data) * order > 0)
2196 ECORE_DLIST_NODE(second)->previous = ECORE_DLIST_NODE(l);
2197 l = l->next = second;
2198 second = second->next;
2202 ECORE_DLIST_NODE(first)->previous = ECORE_DLIST_NODE(l);
2203 l = l->next = first;
2204 first = first->next;
2208 /* append the rest or set it to NULL */
2211 ECORE_DLIST_NODE(first)->previous = ECORE_DLIST_NODE(l);
2216 ECORE_DLIST_NODE(second)->previous = ECORE_DLIST_NODE(l);
2226 * @brief Initialize a node to sane starting values
2227 * @param node: the node to initialize
2228 * @return Returns TRUE on success, FALSE on errors
2231 ecore_dlist_node_init(Ecore_DList_Node *node)
2235 CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
2237 ret = ecore_list_node_init(ECORE_LIST_NODE(node));
2239 node->previous = NULL;
2245 * @brief Allocate and initialize a new list node
2246 * @return Returns NULL on error, new list node on success
2248 EAPI Ecore_DList_Node *
2249 ecore_dlist_node_new()
2251 Ecore_DList_Node *new_node;
2253 new_node = malloc(sizeof(Ecore_DList_Node));
2258 if (!ecore_dlist_node_init(new_node))
2268 * @brief Call the data's free callback function, then free the node
2269 * @param node: the node to be freed
2270 * @param free_func: the callback function to execute on the data
2271 * @return Returns TRUE on success, FALSE on error
2274 ecore_dlist_node_destroy(Ecore_DList_Node * node, Ecore_Free_Cb free_func)
2276 CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
2278 return ecore_list_node_destroy(ECORE_LIST_NODE(node), free_func);