efl
2162 строки · 50.7 Кб
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdlib.h>
6#include <string.h>
7
8#include "Ecore_Data.h"
9
10/* Some tests showed that beyond that value heap sort is faster than merge sort
11* (in this implementation). This value has to be changed or at least review
12* if someone is changing the implementation. */
13#define ECORE_MERGESORT_LIMIT 40000
14
15/* Return information about the list */
16static void * _ecore_list_current(Ecore_List *list);
17
18/* Adding functions */
19static int _ecore_list_insert(Ecore_List *list,
20Ecore_List_Node *node);
21static int _ecore_list_append_0(Ecore_List *list,
22Ecore_List_Node *node);
23static int _ecore_list_prepend_0(Ecore_List *list,
24Ecore_List_Node *node);
25
26/* Remove functions */
27static void * _ecore_list_remove_0(Ecore_List *list);
28static void * _ecore_list_first_remove(Ecore_List *list);
29static void * _ecore_list_last_remove(Ecore_List *list);
30
31/* Basic traversal functions */
32static void * _ecore_list_next(Ecore_List *list);
33static void * _ecore_list_last_goto(Ecore_List *list);
34static void * _ecore_list_first_goto(Ecore_List *list);
35static void * _ecore_list_goto(Ecore_List *list, const void *data);
36static void * _ecore_list_index_goto(Ecore_List *list, int idx);
37
38/* Iterative functions */
39static int _ecore_list_for_each(Ecore_List *list,
40Ecore_For_Each function,
41void *user_data);
42static void * _ecore_list_find(Ecore_List *list,
43Ecore_Compare_Cb function,
44const void *user_data);
45
46/* Sorting functions */
47static Ecore_List_Node *_ecore_list_node_mergesort(Ecore_List_Node *first,
48int n,
49Ecore_Compare_Cb compare,
50int order);
51static Ecore_List_Node *_ecore_list_node_merge(Ecore_List_Node *first,
52Ecore_List_Node *second,
53Ecore_Compare_Cb compare,
54int order);
55static Ecore_List_Node *_ecore_dlist_node_mergesort(Ecore_List_Node *first,
56int n,
57Ecore_Compare_Cb compare,
58int order);
59static Ecore_List_Node *_ecore_dlist_node_merge(Ecore_List_Node *first,
60Ecore_List_Node *second,
61Ecore_Compare_Cb compare,
62int order);
63
64/* Private double linked list functions */
65static void *_ecore_dlist_previous(Ecore_DList *list);
66static void *_ecore_dlist_first_remove(Ecore_DList *list);
67static void *_ecore_dlist_index_goto(Ecore_DList *list, int idx);
68
69/**
70@defgroup Ecore_Data_List_Creation_Group List Creation/Destruction Functions
71
72Functions that create, initialize and destroy Ecore_Lists.
73*/
74
75/**
76* Create and initialize a new list.
77* @return A new initialized list on success, @c NULL on failure.
78* @ingroup Ecore_Data_List_Creation_Group
79*/
80EAPI Ecore_List *
81ecore_list_new(void)
82{
83Ecore_List *list;
84
85list = (Ecore_List *)malloc(sizeof(Ecore_List));
86if (!list)
87return NULL;
88
89if (!ecore_list_init(list))
90{
91FREE(list);
92return NULL;
93}
94
95return list;
96}
97
98/**
99* Initialize a list to some sane starting values.
100* @param list The list to initialize.
101* @return @c TRUE if successful, @c FALSE if an error occurs.
102* @ingroup Ecore_Data_List_Creation_Group
103*/
104EAPI int
105ecore_list_init(Ecore_List *list)
106{
107CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
108
109memset(list, 0, sizeof(Ecore_List));
110
111return TRUE;
112}
113
114/**
115* Free a list and all of it's nodes.
116* @param list The list to be freed.
117* @ingroup Ecore_Data_List_Creation_Group
118*/
119EAPI void
120ecore_list_destroy(Ecore_List *list)
121{
122void *data;
123
124CHECK_PARAM_POINTER("list", list);
125
126while (list->first)
127{
128data = _ecore_list_first_remove(list);
129if (list->free_func)
130list->free_func(data);
131}
132
133FREE(list);
134}
135
136/**
137* Set the function for freeing data.
138* @param list The list that will use this function when nodes are
139* destroyed.
140* @param free_func The function that will free the key data.
141* @return @c TRUE on successful set, @c FALSE otherwise.
142*/
143EAPI int
144ecore_list_free_cb_set(Ecore_List *list, Ecore_Free_Cb free_func)
145{
146CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
147
148list->free_func = free_func;
149
150return TRUE;
151}
152
153/**
154* Checks the list for any nodes.
155* @param list The list to check for nodes
156* @return @c TRUE if no nodes in list, @c FALSE if the list contains nodes
157*/
158EAPI int
159ecore_list_empty_is(Ecore_List *list)
160{
161int ret = TRUE;
162
163CHECK_PARAM_POINTER_RETURN("list", list, TRUE);
164
165if (list->nodes)
166ret = FALSE;
167
168return ret;
169}
170
171/**
172* Returns the number of the current node.
173* @param list The list to return the number of the current node.
174* @return The number of the current node in the list.
175*/
176EAPI int
177ecore_list_index(Ecore_List *list)
178{
179int ret;
180
181CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
182
183ret = list->index;
184
185return ret;
186}
187
188/**
189* Find the number of nodes in the list.
190* @param list The list to find the number of nodes
191* @return The number of nodes in the list.
192*/
193EAPI int
194ecore_list_count(Ecore_List *list)
195{
196int ret = 0;
197
198CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
199
200ret = list->nodes;
201
202return ret;
203}
204
205/**
206@defgroup Ecore_Data_List_Add_Item_Group List Item Adding Functions
207
208Functions that are used to add nodes to an Ecore_List.
209*/
210
211/**
212* Append data to the list.
213* @param list The list.
214* @param data The data to append.
215* @return @c FALSE if an error occurs, @c TRUE if appended successfully
216* @ingroup Ecore_Data_List_Add_Item_Group
217*/
218EAPI inline int
219ecore_list_append(Ecore_List *list, void *data)
220{
221int ret;
222Ecore_List_Node *node;
223
224CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
225
226node = ecore_list_node_new();
227node->data = data;
228
229ret = _ecore_list_append_0(list, node);
230
231return ret;
232}
233
234/* For adding items to the end of the list */
235static int
236_ecore_list_append_0(Ecore_List *list, Ecore_List_Node *end)
237{
238if (list->last)
239list->last->next = end;
240
241list->last = end;
242
243if (!list->first)
244{
245list->first = end;
246list->index = 0;
247list->current = NULL;
248}
249
250if (list->index >= list->nodes)
251list->index++;
252
253list->nodes++;
254
255return TRUE;
256}
257
258/**
259* Prepend data to the beginning of the list.
260* @param list The list.
261* @param data The data to prepend.
262* @return @c FALSE if an error occurs, @c TRUE if prepended successfully.
263* @ingroup Ecore_Data_List_Add_Item_Group
264*/
265EAPI inline int
266ecore_list_prepend(Ecore_List *list, void *data)
267{
268int ret;
269Ecore_List_Node *node;
270
271CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
272
273node = ecore_list_node_new();
274node->data = data;
275
276ret = _ecore_list_prepend_0(list, node);
277
278return ret;
279}
280
281/* For adding items to the beginning of the list */
282static int
283_ecore_list_prepend_0(Ecore_List *list, Ecore_List_Node *start)
284{
285/* Put it at the beginning of the list */
286start->next = list->first;
287
288list->first = start;
289
290/* If no last node, then the first node is the last node */
291if (!list->last)
292list->last = list->first;
293
294list->nodes++;
295list->index++;
296
297return TRUE;
298}
299
300/**
301* Insert data in front of the current point in the list.
302* @param list The list to hold the inserted @p data.
303* @param data The data to insert into @p list.
304* @return @c FALSE if there is an error, @c TRUE on success
305* @ingroup Ecore_Data_List_Add_Item_Group
306*/
307EAPI inline int
308ecore_list_insert(Ecore_List *list, void *data)
309{
310int ret;
311Ecore_List_Node *node;
312
313CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
314
315node = ecore_list_node_new();
316node->data = data;
317
318ret = _ecore_list_insert(list, node);
319
320return ret;
321}
322
323/* For adding items in front of the current position in the list */
324static int
325_ecore_list_insert(Ecore_List *list, Ecore_List_Node *new_node)
326{
327/*
328* If the current point is at the beginning of the list, then it's the
329* same as prepending it to the list.
330*/
331if (list->current == list->first)
332return _ecore_list_prepend_0(list, new_node);
333
334if (!list->current)
335{
336int ret_value;
337
338ret_value = _ecore_list_append_0(list, new_node);
339list->current = list->last;
340
341return ret_value;
342}
343
344/* Setup the fields of the new node */
345new_node->next = list->current;
346
347/* And hook the node into the list */
348_ecore_list_index_goto(list, ecore_list_index(list) - 1);
349
350list->current->next = new_node;
351
352/* Now move the current item to the inserted item */
353list->current = new_node;
354list->nodes++;
355
356return TRUE;
357}
358/**
359* Append a list to the list.
360* @param list The list.
361* @param append The list to append.
362* @return @c FALSE if an error occurs, @c TRUE if appended successfully
363* @ingroup Ecore_Data_List_Add_Item_Group
364*/
365
366EAPI int
367ecore_list_append_list(Ecore_List *list, Ecore_List *append)
368{
369CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
370CHECK_PARAM_POINTER_RETURN("append", append, FALSE);
371
372if (ecore_list_empty_is(append))
373return TRUE;
374
375if (ecore_list_empty_is(list))
376{
377list->first = append->first;
378list->current = list->first;
379list->last = append->last;
380list->nodes = append->nodes;
381}
382else
383{
384list->last->next = append->first;
385list->last = append->last;
386list->nodes += append->nodes;
387}
388
389ecore_list_init(append);
390return TRUE;
391}
392
393/**
394* Prepend a list to the beginning of the list.
395* @param list The list.
396* @param prepend The list to prepend.
397* @return @c FALSE if an error occurs, @c TRUE if prepended successfully.
398* @ingroup Ecore_Data_List_Add_Item_Group
399*/
400EAPI int
401ecore_list_prepend_list(Ecore_List *list, Ecore_List *prepend)
402{
403CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
404CHECK_PARAM_POINTER_RETURN("prepend", prepend, FALSE);
405
406if (ecore_list_empty_is(prepend))
407return TRUE;
408
409if (ecore_list_empty_is(list))
410{
411list->first = prepend->first;
412list->current = NULL;
413list->last = prepend->last;
414list->nodes = prepend->nodes;
415}
416else
417{
418prepend->last->next = list->first;
419list->first = prepend->first;
420list->nodes += prepend->nodes;
421list->index += prepend->nodes;
422}
423
424ecore_list_init(prepend);
425return TRUE;
426}
427
428/**
429@defgroup Ecore_Data_List_Remove_Item_Group List Item Removing Functions
430
431Functions that remove nodes from an Ecore_List.
432*/
433
434/**
435* Remove the current item from the list.
436* @param list The list to remove the current item
437* @return A pointer to the removed data on success, @c NULL on failure.
438* @ingroup Ecore_Data_List_Remove_Item_Group
439*/
440EAPI inline void *
441ecore_list_remove(Ecore_List *list)
442{
443void *ret;
444
445CHECK_PARAM_POINTER_RETURN("list", list, NULL);
446
447ret = _ecore_list_remove_0(list);
448
449return ret;
450}
451
452/* Remove the current item from the list */
453static void *
454_ecore_list_remove_0(Ecore_List *list)
455{
456void *ret = NULL;
457Ecore_List_Node *old;
458
459if (!list)
460return NULL;
461
462if (ecore_list_empty_is(list))
463return NULL;
464
465if (!list->current)
466return NULL;
467
468if (list->current == list->first)
469return _ecore_list_first_remove(list);
470
471if (list->current == list->last)
472return _ecore_list_last_remove(list);
473
474old = list->current;
475
476_ecore_list_index_goto(list, list->index - 1);
477
478list->current->next = old->next;
479old->next = NULL;
480ret = old->data;
481old->data = NULL;
482
483_ecore_list_next(list);
484
485ecore_list_node_destroy(old, NULL);
486list->nodes--;
487
488return ret;
489}
490
491/**
492* Remove and free the data in lists current position.
493* @param list The list to remove and free the current item.
494* @return @c TRUE on success, @c FALSE on error
495* @ingroup Ecore_Data_List_Remove_Item_Group
496*/
497EAPI int
498ecore_list_remove_destroy(Ecore_List *list)
499{
500void *data;
501
502CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
503
504data = _ecore_list_remove_0(list);
505if (list->free_func)
506list->free_func(data);
507
508return TRUE;
509}
510
511/**
512* Remove the first item from the list.
513* @param list The list to remove the current item
514* @return Returns a pointer to the removed data on success, @c NULL on
515* failure.
516* @ingroup Ecore_Data_List_Remove_Item_Group
517*/
518EAPI inline void *
519ecore_list_first_remove(Ecore_List *list)
520{
521void *ret;
522
523CHECK_PARAM_POINTER_RETURN("list", list, NULL);
524
525ret = _ecore_list_first_remove(list);
526
527return ret;
528}
529
530/* Remove the first item from the list */
531static void *
532_ecore_list_first_remove(Ecore_List *list)
533{
534void *ret = NULL;
535Ecore_List_Node *old;
536
537if (!list)
538return NULL;
539
540if (ecore_list_empty_is(list))
541return NULL;
542
543old = list->first;
544
545list->first = list->first->next;
546
547if (list->current == old)
548list->current = list->first;
549else
550(list->index ? list->index-- : 0);
551
552if (list->last == old)
553list->last = list->first;
554
555ret = old->data;
556old->data = NULL;
557
558ecore_list_node_destroy(old, NULL);
559list->nodes--;
560
561return ret;
562}
563
564/**
565* Remove the last item from the list.
566* @param list The list to remove the last node from
567* @return A pointer to the removed data on success, @c NULL on failure.
568* @ingroup Ecore_Data_List_Remove_Item_Group
569*/
570EAPI inline void *
571ecore_list_last_remove(Ecore_List *list)
572{
573void *ret;
574
575CHECK_PARAM_POINTER_RETURN("list", list, NULL);
576
577ret = _ecore_list_last_remove(list);
578
579return ret;
580}
581
582/* Remove the last item from the list */
583static void *
584_ecore_list_last_remove(Ecore_List *list)
585{
586void *ret = NULL;
587Ecore_List_Node *old, *prev;
588
589if (!list)
590return NULL;
591
592if (ecore_list_empty_is(list))
593return NULL;
594
595old = list->last;
596if (list->current == old)
597list->current = NULL;
598
599if (list->first == old)
600list->first = NULL;
601
602for (prev = list->first; prev && prev->next != old; prev = prev->next) ;
603list->last = prev;
604if (prev)
605prev->next = NULL;
606
607old->next = NULL;
608ret = old->data;
609old->data = NULL;
610
611ecore_list_node_destroy(old, NULL);
612list->nodes--;
613
614return ret;
615}
616
617/**
618@defgroup Ecore_Data_List_Traverse_Group List Traversal Functions
619
620Functions that can be used to traverse an Ecore_List.
621*/
622
623/**
624* Make the current item the item with the given index number.
625* @param list The list.
626* @param idx The position to move the current item.
627* @return A pointer to new current item on success, @c NULL on failure.
628* @ingroup Ecore_Data_List_Traverse_Group
629*/
630EAPI inline void *
631ecore_list_index_goto(Ecore_List *list, int idx)
632{
633void *ret;
634
635CHECK_PARAM_POINTER_RETURN("list", list, NULL);
636
637ret = _ecore_list_index_goto(list, idx);
638
639return ret;
640}
641
642/* This is the non-threadsafe version, use this inside internal functions that
643* already lock the list */
644static void *
645_ecore_list_index_goto(Ecore_List *list, int idx)
646{
647int i;
648
649if (!list)
650return NULL;
651
652if (ecore_list_empty_is(list))
653return NULL;
654
655if (idx > ecore_list_count(list) || idx < 0)
656return NULL;
657
658if (idx < list->index)
659{
660_ecore_list_first_goto(list);
661i = 0;
662}
663else
664i = list->index;
665
666for (; i < idx && _ecore_list_next(list); i++) ;
667
668if (i >= list->nodes)
669return NULL;
670
671list->index = i;
672
673return list->current->data;
674}
675
676/**
677* Make the current item the node that contains @p data.
678* @param list The list.
679* @param data The data to find.
680* @return A pointer to @p data on success, @c NULL on failure.
681* @ingroup Ecore_Data_List_Traverse_Group
682*/
683EAPI inline void *
684ecore_list_goto(Ecore_List *list, const void *data)
685{
686void *ret;
687
688CHECK_PARAM_POINTER_RETURN("list", list, NULL);
689
690ret = _ecore_list_goto(list, data);
691
692return ret;
693}
694
695/* Set the current position to the node containing data */
696static void *
697_ecore_list_goto(Ecore_List *list, const void *data)
698{
699int idx;
700Ecore_List_Node *node;
701
702if (!list)
703return NULL;
704
705idx = 0;
706
707node = list->first;
708while (node && node->data)
709{
710Ecore_List_Node *next;
711
712if (node->data == data)
713break;
714
715next = node->next;
716
717node = next;
718
719idx++;
720}
721
722if (!node)
723return NULL;
724
725list->current = node;
726list->index = idx;
727
728return list->current->data;
729}
730
731/**
732* Make the current item the first item in the list
733* @param list The list.
734* @return A pointer to the first item on success, @c NULL on failure
735* @ingroup Ecore_Data_List_Traverse_Group
736*/
737EAPI inline void *
738ecore_list_first_goto(Ecore_List *list)
739{
740void *ret;
741
742CHECK_PARAM_POINTER_RETURN("list", list, NULL);
743
744ret = _ecore_list_first_goto(list);
745
746return ret;
747}
748
749/* Set the current position to the start of the list */
750static void *
751_ecore_list_first_goto(Ecore_List *list)
752{
753if (!list || !list->first)
754return NULL;
755
756list->current = list->first;
757list->index = 0;
758
759return list->current->data;
760}
761
762/**
763* Make the current item the last item in the list.
764* @param list The list.
765* @return A pointer to the last item on success, @c NULL on failure.
766* @ingroup Ecore_Data_List_Traverse_Group
767*/
768EAPI inline void *
769ecore_list_last_goto(Ecore_List *list)
770{
771void *ret;
772
773CHECK_PARAM_POINTER_RETURN("list", list, NULL);
774
775ret = _ecore_list_last_goto(list);
776
777return ret;
778}
779
780/* Set the current position to the end of the list */
781static void *
782_ecore_list_last_goto(Ecore_List *list)
783{
784if (!list || !list->last)
785return NULL;
786
787list->current = list->last;
788list->index = (list->nodes - 1);
789
790return list->current->data;
791}
792
793/**
794* Retrieve the data pointed to by the current item in @p list.
795* @param list The list.
796* @return Returns the data at current position, can be @c NULL.
797*/
798EAPI inline void *
799ecore_list_current(Ecore_List *list)
800{
801void *ret;
802
803ret = _ecore_list_current(list);
804
805return ret;
806}
807
808/**
809* Retrieve the data pointed to by the first item in @p list.
810* @param list The list.
811* @return Returns the data at current position, can be @c NULL.
812*/
813EAPI inline void *
814ecore_list_first(Ecore_List *list)
815{
816void *ret;
817
818if (!list->first)
819return NULL;
820
821ret = list->first->data;
822
823return ret;
824}
825
826/**
827* Retrieve the data pointed to by the last item in @p list.
828* @param list The list.
829* @return Returns the data at current position, can be @c NULL.
830*/
831EAPI inline void *
832ecore_list_last(Ecore_List *list)
833{
834void *ret;
835
836if (!list->last)
837return NULL;
838
839ret = list->last->data;
840
841return ret;
842}
843
844/* Return the data of the current node without incrementing */
845static void *
846_ecore_list_current(Ecore_List *list)
847{
848void *ret;
849
850if (!list->current)
851return NULL;
852
853ret = list->current->data;
854
855return ret;
856}
857
858/**
859* Retrieve the data pointed to by the current item, and make the next item
860* the current item.
861* @param list The list to retrieve data from.
862* @return The current item in the list on success, @c NULL on failure.
863*/
864EAPI inline void *
865ecore_list_next(Ecore_List *list)
866{
867void *data;
868
869CHECK_PARAM_POINTER_RETURN("list", list, NULL);
870
871data = _ecore_list_next(list);
872
873return data;
874}
875
876/* Return the data contained in the current node and go to the next node */
877static void *
878_ecore_list_next(Ecore_List *list)
879{
880void *data;
881Ecore_List_Node *ret;
882Ecore_List_Node *next;
883
884if (!list->current)
885return NULL;
886
887ret = list->current;
888next = list->current->next;
889
890list->current = next;
891list->index++;
892
893data = ret->data;
894
895return data;
896}
897
898/**
899* Remove all nodes from @p list.
900* @param list The list.
901* @return Returns @c TRUE on success, @c FALSE on error.
902* @note The data for each item on the list is not freed by
903* @c ecore_list_clear().
904*/
905EAPI int
906ecore_list_clear(Ecore_List *list)
907{
908CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
909
910while (!ecore_list_empty_is(list))
911_ecore_list_first_remove(list);
912
913return TRUE;
914}
915
916/**
917* Execute function for each node in @p list.
918* @param list The list.
919* @param function The function to pass each node from @p list to.
920* @return Returns @c TRUE on success, @c FALSE on failure.
921* @ingroup Ecore_Data_List_Traverse_Group
922*/
923EAPI int
924ecore_list_for_each(Ecore_List *list, Ecore_For_Each function, void *user_data)
925{
926int ret;
927
928CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
929
930ret = _ecore_list_for_each(list, function, user_data);
931
932return ret;
933}
934
935/* The real meat of executing the function for each data node */
936static int
937_ecore_list_for_each(Ecore_List *list, Ecore_For_Each function, void *user_data)
938{
939void *value;
940
941if (!list || !function)
942return FALSE;
943
944_ecore_list_first_goto(list);
945while ((value = _ecore_list_next(list)))
946function(value, user_data);
947
948return TRUE;
949}
950
951/**
952* Find data in @p list using the compare function @p func
953* @param list The list.
954* @param function The function to test each node of @p list with
955* @param user_data Data to match against (used by @p function)
956* @return the first matching data node, or NULL if none match
957*/
958EAPI void *
959ecore_list_find(Ecore_List *list,
960Ecore_Compare_Cb function,
961const void *user_data)
962{
963CHECK_PARAM_POINTER_RETURN("list", list, NULL);
964
965return _ecore_list_find(list, function, user_data);
966}
967
968/* The real meat of finding a node via a compare cb */
969static void *
970_ecore_list_find(Ecore_List *list,
971Ecore_Compare_Cb function,
972const void *user_data)
973{
974void *value;
975if (!list || !function)
976return NULL;
977
978_ecore_list_first_goto(list);
979while ((value = _ecore_list_current(list)))
980{
981if (!function(value, user_data))
982return value;
983
984ecore_list_next(list);
985}
986
987return NULL;
988}
989
990/**
991* Sort data in @p list using the compare function @p compare
992* @param list The list.
993* @param compare The function to compare the data of @p list
994* @param order The sort direction, possible values are ECORE_SORT_MIN and
995* ECORE_SORT_MAX
996* @return true on success
997*
998* This is a wrapper function for mergesort and heapsort. It
999* tries to choose the fastest algorithm depending on the
1000* number of notes. Note: The sort may be unstable.
1001*/
1002EAPI int
1003ecore_list_sort(Ecore_List *list, Ecore_Compare_Cb compare, char order)
1004{
1005CHECK_PARAM_POINTER_RETURN("list", list, 0);
1006
1007if (list->nodes < 2)
1008return 1;
1009
1010if (list->nodes < ECORE_MERGESORT_LIMIT)
1011return ecore_list_mergesort(list, compare, order);
1012
1013if (!ecore_list_heapsort(list, compare, order))
1014return ecore_list_mergesort(list, compare, order);
1015
1016return 1;
1017}
1018
1019/**
1020* Sort data in @p list using the compare function @p compare
1021* @param list The list.
1022* @param compare The function to compare the data of @p list
1023* @param order The sort direction, possible values are ECORE_SORT_MIN and
1024* ECORE_SORT_MAX
1025* @return true on success
1026*
1027* Mergesort is a stable, in-place sorting algorithm
1028*/
1029EAPI int
1030ecore_list_mergesort(Ecore_List *list, Ecore_Compare_Cb compare, char order)
1031{
1032Ecore_List_Node *node;
1033
1034CHECK_PARAM_POINTER_RETURN("list", list, 0);
1035if (list->nodes < 2)
1036return 1;
1037
1038if (order == ECORE_SORT_MIN)
1039order = 1;
1040else
1041order = -1;
1042
1043node = _ecore_list_node_mergesort(list->first, list->nodes, compare, order);
1044list->first = node;
1045
1046/* maybe there is a better way to do that but our last node has changed */
1047while (node->next)
1048node = node->next;
1049list->last = node;
1050
1051_ecore_list_first_goto(list);
1052
1053return 1;
1054}
1055
1056/**
1057* Merge the @p l2 into the @p list using the compare function @p compare.
1058* Both lists need to be sorted else a corrupt list could be the result.
1059* @param list The list.
1060* @param l2 The second list, this list will be empty after the merge
1061* @param compare The function to compare the data of @p list and @p l2
1062* @param order The sort direction, possible values are ECORE_SORT_MIN and
1063* ECORE_SORT_MAX
1064*/
1065EAPI void
1066ecore_list_merge(Ecore_List *list,
1067Ecore_List *l2,
1068Ecore_Compare_Cb compare,
1069char order)
1070{
1071CHECK_PARAM_POINTER("list", list);
1072CHECK_PARAM_POINTER("l2", l2);
1073
1074if (ecore_list_empty_is(l2))
1075return;
1076
1077if (ecore_list_empty_is(list))
1078{
1079ecore_list_append_list(list, l2);
1080return;
1081}
1082
1083if (order == ECORE_SORT_MIN)
1084order = 1;
1085else
1086order = -1;
1087
1088list->first = _ecore_list_node_merge(list->first, l2->first, compare, order);
1089
1090if ((order * compare(list->last->data, l2->last->data)) < 0)
1091list->last = l2->last;
1092
1093list->nodes += l2->nodes;
1094ecore_list_init(l2);
1095}
1096
1097/* this is the internal recrusive function for the merge sort */
1098static Ecore_List_Node *
1099_ecore_list_node_mergesort(Ecore_List_Node *first, int n,
1100Ecore_Compare_Cb compare, int order)
1101{
1102Ecore_List_Node *middle;
1103Ecore_List_Node *premid;
1104int mid;
1105int i;
1106
1107mid = n / 2;
1108
1109if (n < 2)
1110return first;
1111else if (n == 2)
1112{
1113if (compare(first->data, first->next->data) * order > 0)
1114{
1115/* swap the data */
1116void *data;
1117data = first->next->data;
1118first->next->data = first->data;
1119first->data = data;
1120}
1121
1122return first;
1123}
1124
1125/* first find the premiddle node*/
1126for (premid = first, i = 0; i < mid - 1; i++)
1127premid = premid->next;
1128
1129/* split the list */
1130middle = premid->next;
1131premid->next = NULL;
1132
1133/* sort the the partial lists */
1134first = _ecore_list_node_mergesort(first, mid, compare, order);
1135middle = _ecore_list_node_mergesort(middle, n - mid, compare, order);
1136
1137return _ecore_list_node_merge(first, middle, compare, order);
1138}
1139
1140/* this function is used to merge the partial sorted lists */
1141static Ecore_List_Node *
1142_ecore_list_node_merge(Ecore_List_Node *first, Ecore_List_Node *second,
1143Ecore_Compare_Cb compare, int order)
1144{
1145Ecore_List_Node *list;
1146Ecore_List_Node *l;
1147
1148/* select the first node outside the loop, because we need to keep
1149* a pointer to it */
1150if (compare(first->data, second->data) * order > 0)
1151{
1152list = l = second;
1153second = second->next;
1154}
1155else
1156{
1157list = l = first;
1158first = first->next;
1159}
1160
1161/* and now start the merging */
1162while (first && second)
1163{
1164if (compare(first->data, second->data) * order > 0)
1165{
1166l = l->next = second;
1167second = second->next;
1168}
1169else
1170{
1171l = l->next = first;
1172first = first->next;
1173}
1174}
1175
1176/* append the rest or set it to NULL */
1177if (first)
1178l->next = first;
1179else if (second)
1180l->next = second;
1181else
1182l->next = NULL;
1183
1184return list;
1185}
1186
1187/**
1188* Sort data in @p list using the compare function @p compare
1189* @param list The list.
1190* @param compare The function to compare the data of @p list
1191* @param order The sort direction, possible values are ECORE_SORT_MIN and
1192* ECORE_SORT_MAX
1193* @return true on success
1194*
1195* Heapsort is a unstable sorting algorithm, it needs to allocate extra memomry,
1196* but there for it is for a great number of nodes faster than mergesort
1197*/
1198EAPI int
1199ecore_list_heapsort(Ecore_List *list, Ecore_Compare_Cb compare, char order)
1200{
1201Ecore_Sheap *heap;
1202Ecore_List_Node *node;
1203void *data;
1204
1205CHECK_PARAM_POINTER_RETURN("list", list, 0);
1206/*
1207* Push the data into a heap.
1208*/
1209heap = ecore_sheap_new(compare, list->nodes);
1210if (!heap)
1211return 0;
1212
1213ecore_sheap_order_set(heap, order);
1214_ecore_list_first_goto(list);
1215while ((data = _ecore_list_next(list)))
1216{
1217ecore_sheap_insert(heap, data);
1218}
1219
1220/*
1221* Extract in sorted order.
1222*/
1223node = list->first;
1224while (node)
1225{
1226node->data = ecore_sheap_extract(heap);
1227node = node->next;
1228}
1229
1230ecore_sheap_destroy(heap);
1231
1232_ecore_list_first_goto(list);
1233return 1;
1234}
1235
1236/* Initialize a node to starting values */
1237EAPI int
1238ecore_list_node_init(Ecore_List_Node *node)
1239{
1240CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
1241
1242node->next = NULL;
1243node->data = NULL;
1244
1245return TRUE;
1246}
1247
1248/**
1249@defgroup Ecore_Data_List_Node_Group List Node Functions
1250
1251Functions that are used in the creation, maintenance and destruction of
1252Ecore_List nodes.
1253*/
1254
1255/**
1256* Allocates and initializes a new list node.
1257* @return A new Ecore_List_Node on success, @c NULL otherwise.
1258* @ingroup Ecore_Data_List_Node_Group
1259*/
1260EAPI Ecore_List_Node *
1261ecore_list_node_new()
1262{
1263Ecore_List_Node *new_node;
1264
1265new_node = malloc(sizeof(Ecore_List_Node));
1266
1267if (!ecore_list_node_init(new_node))
1268{
1269FREE(new_node);
1270return NULL;
1271}
1272
1273return new_node;
1274}
1275
1276/**
1277* Calls the function to free the data and the node.
1278* @param node Node to destroy.
1279* @param free_func Function to call if @p node points to data to free.
1280* @return @c TRUE.
1281* @ingroup Ecore_Data_List_Node_Group
1282*/
1283EAPI int
1284ecore_list_node_destroy(Ecore_List_Node *node, Ecore_Free_Cb free_func)
1285{
1286CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
1287
1288if (free_func && node->data)
1289free_func(node->data);
1290
1291FREE(node);
1292
1293return TRUE;
1294}
1295
1296/**
1297* @defgroup Ecore_Data_DList_Creation_Group Doubly Linked List Creation/Destruction Functions
1298*
1299* Functions used to create, initialize and destroy @c Ecore_DLists.
1300*/
1301
1302/**
1303* Creates and initialises a new doubly linked list.
1304* @return A new initialised doubly linked list on success, @c NULL
1305* on failure.
1306* @ingroup Ecore_Data_DList_Creation_Group
1307*/
1308EAPI Ecore_DList *
1309ecore_dlist_new()
1310{
1311Ecore_DList *list = NULL;
1312
1313list = (Ecore_DList *)malloc(sizeof(Ecore_DList));
1314if (!list)
1315return NULL;
1316
1317if (!ecore_dlist_init(list))
1318{
1319IF_FREE(list);
1320return NULL;
1321}
1322
1323return list;
1324}
1325
1326/**
1327* Initialises a list to some sane starting values.
1328* @param list The doubly linked list to initialise.
1329* @return @c TRUE if successful, @c FALSE if an error occurs.
1330* @ingroup Ecore_Data_DList_Creation_Group
1331*/
1332EAPI int
1333ecore_dlist_init(Ecore_DList *list)
1334{
1335CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1336
1337memset(list, 0, sizeof(Ecore_DList));
1338
1339return TRUE;
1340}
1341
1342/**
1343* Frees a doubly linked list and all of its nodes.
1344* @param list The doubly linked list to be freed.
1345* @ingroup Ecore_Data_DList_Creation_Group
1346*/
1347EAPI void
1348ecore_dlist_destroy(Ecore_DList *list)
1349{
1350void *data;
1351CHECK_PARAM_POINTER("list", list);
1352
1353while (list->first)
1354{
1355data = _ecore_dlist_first_remove(list);
1356if (list->free_func)
1357list->free_func(data);
1358}
1359
1360FREE(list);
1361}
1362
1363/**
1364* Sets the function used for freeing data stored in a doubly linked list.
1365* @param list The doubly linked list that will use this function when
1366* nodes are destroyed.
1367* @param free_func The function that will free the key data
1368* @return @c TRUE on success, @c FALSE on failure.
1369* @ingroup Ecore_Data_DList_Creation_Group
1370*/
1371EAPI int
1372ecore_dlist_free_cb_set(Ecore_DList *list, Ecore_Free_Cb free_func)
1373{
1374CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1375
1376return ecore_list_free_cb_set(ECORE_LIST(list), free_func);
1377}
1378
1379/**
1380* Returns whether there is anything in the given doubly linked list.
1381* @param list The given doubly linked list.
1382* @return @c TRUE if there are nodes, @c FALSE otherwise.
1383*/
1384EAPI int
1385ecore_dlist_empty_is(Ecore_DList *list)
1386{
1387CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1388
1389return ecore_list_empty_is(ECORE_LIST(list));
1390}
1391
1392/**
1393* Retrieves the index of the current node of the given doubly linked list.
1394* @param list The given doubly linked list.
1395* @return The index of the current node.
1396*/
1397EAPI inline int
1398ecore_dlist_index(Ecore_DList *list)
1399{
1400CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1401
1402return ecore_list_index(ECORE_LIST(list));
1403}
1404
1405/**
1406* @defgroup Ecore_Data_DList_Add_Item_Group Doubly Linked List Adding Functions
1407*
1408* Functions that are used to add nodes to an Ecore_DList.
1409*/
1410
1411/**
1412* Appends data to the given doubly linked list.
1413* @param list The given doubly linked list.
1414* @param data The data to append.
1415* @return @c TRUE if the data is successfully appended, @c FALSE otherwise.
1416* @ingroup Ecore_Data_DList_Add_Item_Group
1417*/
1418EAPI int
1419ecore_dlist_append(Ecore_DList *list, void *data)
1420{
1421int ret;
1422Ecore_DList_Node *prev;
1423Ecore_DList_Node *node;
1424
1425CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1426
1427node = ecore_dlist_node_new();
1428ECORE_LIST_NODE(node)->data = data;
1429
1430prev = ECORE_DLIST_NODE(ECORE_LIST(list)->last);
1431ret = _ecore_list_append_0(ECORE_LIST(list), ECORE_LIST_NODE(node));
1432if (ret)
1433node->previous = prev;
1434
1435return ret;
1436}
1437
1438/**
1439* Adds data to the very beginning of the given doubly linked list.
1440* @param list The given doubly linked list.
1441* @param data The data to prepend.
1442* @return @c TRUE if the data is successfully prepended, @c FALSE otherwise.
1443* @ingroup Ecore_Data_DList_Add_Item_Group
1444*/
1445EAPI int
1446ecore_dlist_prepend(Ecore_DList *list, void *data)
1447{
1448int ret;
1449Ecore_DList_Node *prev;
1450Ecore_DList_Node *node;
1451
1452CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1453
1454node = ecore_dlist_node_new();
1455ECORE_LIST_NODE(node)->data = data;
1456
1457prev = ECORE_DLIST_NODE(ECORE_LIST(list)->first);
1458ret = _ecore_list_prepend_0(ECORE_LIST(list), ECORE_LIST_NODE(node));
1459if (ret && prev)
1460prev->previous = node;
1461
1462return ret;
1463}
1464
1465/**
1466* Inserts data at the current point in the given doubly linked list.
1467* @param list The given doubly linked list.
1468* @param data The data to be inserted.
1469* @return @c TRUE on success, @c FALSE otherwise.
1470* @ingroup Ecore_Data_DList_Add_Item_Group
1471*/
1472EAPI int
1473ecore_dlist_insert(Ecore_DList *list, void *data)
1474{
1475int ret = TRUE;
1476Ecore_DList_Node *prev;
1477Ecore_DList_Node *node;
1478
1479CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1480
1481/*
1482* Identify and shortcut the end cases.
1483*/
1484if (!ECORE_LIST(list)->current)
1485return ecore_dlist_append(list, data);
1486
1487if (ECORE_LIST(list)->current == ECORE_LIST(list)->first)
1488return ecore_dlist_prepend(list, data);
1489
1490node = ecore_dlist_node_new();
1491ECORE_LIST_NODE(node)->data = data;
1492
1493/* Setup the fields of the new node */
1494ECORE_LIST_NODE(node)->next = ECORE_LIST(list)->current;
1495
1496/* And hook the node into the list */
1497prev = ECORE_DLIST_NODE(ECORE_LIST(list)->current)->previous;
1498ECORE_LIST_NODE(prev)->next = ECORE_LIST_NODE(node);
1499ECORE_DLIST_NODE(ECORE_LIST(list)->current)->previous = node;
1500node->previous = prev;
1501
1502/* Now move the current item to the inserted item */
1503ECORE_LIST(list)->current = ECORE_LIST_NODE(node);
1504ECORE_LIST(list)->nodes++;
1505
1506return ret;
1507}
1508
1509/**
1510* Appends a list to the given doubly linked list.
1511* @param list The given doubly linked list.
1512* @param append The list to append.
1513* @return @c TRUE if the data is successfully appended, @c FALSE otherwise.
1514* @ingroup Ecore_Data_DList_Add_Item_Group
1515*/
1516EAPI int
1517ecore_dlist_append_list(Ecore_DList *list, Ecore_DList *append)
1518{
1519CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1520CHECK_PARAM_POINTER_RETURN("append", append, FALSE);
1521
1522if (ecore_dlist_empty_is(append))
1523return TRUE;
1524
1525if (ecore_dlist_empty_is(list))
1526{
1527list->first = append->first;
1528list->current = NULL;
1529list->last = append->last;
1530list->nodes = append->nodes;
1531}
1532else
1533{
1534list->last->next = append->first;
1535ECORE_DLIST_NODE(append->first)->previous = ECORE_DLIST_NODE(list->last);
1536list->last = append->last;
1537list->nodes += append->nodes;
1538}
1539
1540ecore_dlist_init(append);
1541return TRUE;
1542}
1543
1544/**
1545* Adds a list to the very beginning of the given doubly linked list.
1546* @param list The given doubly linked list.
1547* @param prepend The list to prepend.
1548* @return @c TRUE if the data is successfully prepended, @c FALSE otherwise.
1549* @ingroup Ecore_Data_DList_Add_Item_Group
1550*/
1551EAPI int
1552ecore_dlist_prepend_list(Ecore_DList *list, Ecore_DList *prepend)
1553{
1554CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1555CHECK_PARAM_POINTER_RETURN("prepend", prepend, FALSE);
1556
1557if (ecore_dlist_empty_is(prepend))
1558return TRUE;
1559
1560if (ecore_dlist_empty_is(list))
1561{
1562list->first = prepend->first;
1563list->current = NULL;
1564list->last = prepend->last;
1565list->nodes = prepend->nodes;
1566}
1567else
1568{
1569prepend->last->next = list->first;
1570ECORE_DLIST_NODE(list->first)->previous = ECORE_DLIST_NODE(
1571prepend->last);
1572list->first = prepend->first;
1573list->nodes += prepend->nodes;
1574list->index += prepend->nodes;
1575}
1576
1577ecore_dlist_init(prepend);
1578return TRUE;
1579}
1580
1581/**
1582* @defgroup Ecore_Data_DList_Remove_Item_Group Doubly Linked List Removing Functions
1583*
1584* Functions that remove nodes from an @c Ecore_DList.
1585*/
1586
1587/**
1588* Removes the current item from the given doubly linked list.
1589* @param list The given doubly linked list.
1590* @return A pointer to the removed data on success, @c NULL otherwise.
1591* @ingroup Ecore_Data_DList_Remove_Item_Group
1592*/
1593EAPI void *
1594ecore_dlist_remove(Ecore_DList *list)
1595{
1596void *ret;
1597Ecore_List *l2 = ECORE_LIST(list);
1598Ecore_DList_Node *node;
1599
1600CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1601
1602if (l2->current)
1603{
1604node = ECORE_DLIST_NODE(list->current->next);
1605if (node)
1606node->previous = ECORE_DLIST_NODE(l2->current)->previous;
1607}
1608
1609ret = _ecore_list_remove_0(list);
1610
1611return ret;
1612}
1613
1614/**
1615* Removes the first item from the given doubly linked list.
1616* @param list The given doubly linked list.
1617* @return A pointer to the removed data on success, @c NULL on failure.
1618* @ingroup Ecore_Data_DList_Remove_Item_Group
1619*/
1620EAPI void *
1621ecore_dlist_first_remove(Ecore_DList *list)
1622{
1623void *ret;
1624
1625CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1626
1627ret = _ecore_dlist_first_remove(list);
1628
1629return ret;
1630}
1631
1632/**
1633* Removes and frees the data at the current position in the given doubly
1634* linked list.
1635* @param list The given doubly linked list.
1636* @return @c TRUE on success, @c FALSE otherwise.
1637* @ingroup Ecore_Data_DList_Remove_Item_Group
1638*/
1639EAPI int
1640ecore_dlist_remove_destroy(Ecore_DList *list)
1641{
1642void *data;
1643
1644CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1645
1646data = ecore_dlist_remove(list);
1647if (!data)
1648return FALSE;
1649
1650if (list->free_func)
1651list->free_func(data);
1652
1653return TRUE;
1654}
1655
1656static void *
1657_ecore_dlist_first_remove(Ecore_DList *list)
1658{
1659void *ret;
1660
1661if (!list)
1662return NULL;
1663
1664ret = _ecore_list_first_remove(list);
1665if (ret && ECORE_LIST(list)->first)
1666ECORE_DLIST_NODE(ECORE_LIST(list)->first)->previous = NULL;
1667
1668return ret;
1669}
1670
1671/**
1672* Removes the last item from the given doubly linked list.
1673* @param list The given doubly linked list.
1674* @return A pointer to the removed data on success, @c NULL otherwise.
1675* @ingroup Ecore_Data_DList_Remove_Item_Group
1676*/
1677EAPI void *
1678ecore_dlist_last_remove(Ecore_DList *list)
1679{
1680void *ret;
1681Ecore_List_Node *node;
1682
1683CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1684
1685if (ecore_list_empty_is(list))
1686return NULL;
1687
1688node = list->last;
1689list->last = ECORE_LIST_NODE(ECORE_DLIST_NODE(node)->previous);
1690if (list->last)
1691list->last->next = NULL;
1692
1693if (list->first == node)
1694list->first = NULL;
1695
1696if (list->current == node)
1697list->current = NULL;
1698
1699ret = node->data;
1700ecore_list_node_destroy(node, NULL);
1701
1702list->nodes--;
1703if (list->index >= list->nodes)
1704list->index--;
1705
1706return ret;
1707}
1708
1709/**
1710* Moves the current item to the index number in the given doubly linked list.
1711* @param list The given doubly linked list.
1712* @param idx The position to move the current item
1713* @return The node at specified index on success, @c NULL on error.
1714*/
1715EAPI void *
1716ecore_dlist_index_goto(Ecore_DList *list, int idx)
1717{
1718void *ret;
1719
1720CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1721
1722ret = _ecore_dlist_index_goto(list, idx);
1723
1724return ret;
1725}
1726
1727/* This is the non-threadsafe version, use this inside internal functions that
1728* already lock the list */
1729static void *
1730_ecore_dlist_index_goto(Ecore_DList *list, int idx)
1731{
1732int i, increment;
1733
1734if (!list)
1735return NULL;
1736
1737if (ecore_list_empty_is(ECORE_LIST(list)))
1738return NULL;
1739
1740if (idx > ecore_list_count(ECORE_LIST(list)) || idx < 0)
1741return NULL;
1742
1743if (ECORE_LIST(list)->index >= ECORE_LIST(list)->nodes)
1744_ecore_list_last_goto(ECORE_LIST(list));
1745
1746if (idx < ECORE_LIST(list)->index)
1747increment = -1;
1748else
1749increment = 1;
1750
1751for (i = ECORE_LIST(list)->index; i != idx; i += increment)
1752{
1753if (increment > 0)
1754_ecore_list_next(list);
1755else
1756_ecore_dlist_previous(list);
1757}
1758
1759return _ecore_list_current(list);
1760}
1761
1762/**
1763* @brief Move the current item to the node that contains data
1764* @param list: the list to move the current item in
1765* @param data: the data to find and set the current item to
1766*
1767* @return Returns specified data on success, NULL on error
1768*/
1769EAPI void *
1770ecore_dlist_goto(Ecore_DList *list, void *data)
1771{
1772void *ret;
1773
1774CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1775
1776ret = _ecore_list_goto(ECORE_LIST(list), data);
1777
1778return ret;
1779}
1780
1781/**
1782* @brief Move the current pointer to the first item in the list
1783* @param list: the list to change the current to the first item
1784*
1785* @return Returns a pointer to the first item on success, NULL on failure.
1786*/
1787EAPI void *
1788ecore_dlist_first_goto(Ecore_DList *list)
1789{
1790void *ret;
1791
1792CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1793
1794ret = _ecore_list_first_goto(list);
1795
1796return ret;
1797}
1798
1799/**
1800* @brief Move the pointer to the current item to the last item
1801* @param list: the list to move the current item pointer to the last
1802* @return Returns a pointer to the last item in the list , NULL if empty.
1803*/
1804EAPI void *
1805ecore_dlist_last_goto(Ecore_DList *list)
1806{
1807void *ret;
1808
1809CHECK_PARAM_POINTER_RETURN("list", list, NULL);
1810
1811ret = _ecore_list_last_goto(ECORE_LIST(list));
1812
1813return ret;
1814}
1815
1816/**
1817* @brief Return the data in the current list item
1818* @param list: the list to the return the current data
1819* @return Returns value of the current data item, NULL if no current item
1820*/
1821EAPI void *
1822ecore_dlist_current(Ecore_DList *list)
1823{
1824void *ret;
1825
1826ret = _ecore_list_current(ECORE_LIST(list));
1827
1828return ret;
1829}
1830
1831/**
1832* @brief Move to the next item in the list and return current item
1833* @param list: the list to move to the next item in.
1834* @return Returns data in the current list node, or NULL on error
1835*/
1836EAPI void *
1837ecore_dlist_next(Ecore_DList *list)
1838{
1839void *data;
1840
1841data = _ecore_list_next(list);
1842
1843return data;
1844}
1845
1846/**
1847* @brief Move to the previous item and return current item
1848* @param list: the list to move to the previous item in.
1849* @return Returns data in the current list node, or NULL on error
1850*/
1851EAPI void *
1852ecore_dlist_previous(Ecore_DList *list)
1853{
1854void *data;
1855
1856data = _ecore_dlist_previous(list);
1857
1858return data;
1859}
1860
1861static void *
1862_ecore_dlist_previous(Ecore_DList *list)
1863{
1864void *data = NULL;
1865
1866if (!list)
1867return NULL;
1868
1869if (ECORE_LIST(list)->current)
1870{
1871data = ECORE_LIST(list)->current->data;
1872ECORE_LIST(list)->
1873current = ECORE_LIST_NODE(ECORE_DLIST_NODE(
1874ECORE_LIST(list)->
1875current)->previous);
1876ECORE_LIST(list)->index
1877--;
1878}
1879else
1880_ecore_list_last_goto(
1881ECORE_LIST(list));
1882
1883return data;
1884}
1885
1886/**
1887* @brief Remove all nodes from the list.
1888* @param list: the list to remove all nodes from
1889*
1890* @return Returns TRUE on success, FALSE on errors
1891*/
1892EAPI int
1893ecore_dlist_clear(Ecore_DList *list)
1894{
1895CHECK_PARAM_POINTER_RETURN("list", list, FALSE);
1896
1897ecore_list_clear(ECORE_LIST(list));
1898
1899return TRUE;
1900}
1901
1902/**
1903* Sort data in @p list using the compare function @p compare
1904* @param list The list.
1905* @param compare The function to compare the data of @p list
1906* @param order The sort direction, possible values are ECORE_SORT_MIN and
1907* ECORE_SORT_MAX
1908* @return true on success
1909*
1910* This is a wrapper function for mergesort and heapsort. It
1911* tries to choose the fastest algorithm depending on the
1912* number of notes. Note: The sort may be unstable.
1913*/
1914EAPI int
1915ecore_dlist_sort(Ecore_List *list, Ecore_Compare_Cb compare, char order)
1916{
1917CHECK_PARAM_POINTER_RETURN("list", list, 0);
1918
1919if (list->nodes < 2)
1920return 1;
1921
1922if (list->nodes < ECORE_MERGESORT_LIMIT)
1923return ecore_dlist_mergesort(list, compare, order);
1924
1925if (!ecore_dlist_heapsort(list, compare, order))
1926return ecore_dlist_mergesort(list, compare, order);
1927
1928return 1;
1929}
1930
1931/**
1932* Sort data in @p list using the compare function @p compare
1933* @param list The list.
1934* @param compare The function to compare the data of @p list
1935* @param order The sort direction, possible values are ECORE_SORT_MIN and
1936* ECORE_SORT_MAX
1937* @return true on success
1938*
1939* Mergesort is a stable, in-place sorting algorithm
1940*/
1941EAPI int
1942ecore_dlist_mergesort(Ecore_DList *list, Ecore_Compare_Cb compare, char order)
1943{
1944Ecore_List_Node *node;
1945
1946CHECK_PARAM_POINTER_RETURN("list", list, 0);
1947if (list->nodes < 2)
1948return 1;
1949
1950if (order == ECORE_SORT_MIN)
1951order = 1;
1952else
1953order = -1;
1954
1955node = _ecore_dlist_node_mergesort(list->first, list->nodes, compare, order);
1956list->first = node;
1957
1958/* maybe there is a better way to do that but our last node has changed */
1959while (node->next)
1960node = node->next;
1961list->last = node;
1962
1963_ecore_list_first_goto(list);
1964
1965return 1;
1966}
1967
1968/**
1969* Merge the @p l2 into the @p list using the compare function @p compare.
1970* Both lists need to be sorted else a corrupt list could be the result.
1971* @param list The list.
1972* @param l2 The second list, this list will be empty after the merge
1973* @param compare The function to compare the data of @p list and @p l2
1974* @param order The sort direction, possible values are ECORE_SORT_MIN and
1975* ECORE_SORT_MAX
1976*/
1977EAPI void
1978ecore_dlist_merge(Ecore_DList *list,
1979Ecore_DList *l2,
1980Ecore_Compare_Cb compare,
1981char order)
1982{
1983CHECK_PARAM_POINTER("list", list);
1984CHECK_PARAM_POINTER("l2", l2);
1985
1986if (ecore_dlist_empty_is(l2))
1987return;
1988
1989if (ecore_dlist_empty_is(list))
1990{
1991ecore_dlist_append_list(list, l2);
1992return;
1993}
1994
1995if (order == ECORE_SORT_MIN)
1996order = 1;
1997else
1998order = -1;
1999
2000list->first = _ecore_dlist_node_merge(list->first, l2->first, compare, order);
2001
2002if ((order * compare(list->last->data, l2->last->data)) < 0)
2003list->last = l2->last;
2004
2005list->nodes += l2->nodes;
2006ecore_dlist_init(l2);
2007}
2008
2009/* this is the internal recrusive function for the merge sort */
2010static Ecore_List_Node *
2011_ecore_dlist_node_mergesort(Ecore_List_Node *first, int n,
2012Ecore_Compare_Cb compare, int order)
2013{
2014Ecore_List_Node *middle;
2015Ecore_List_Node *premid;
2016int mid;
2017int i;
2018
2019mid = n / 2;
2020
2021if (n < 2)
2022return first;
2023else if (n == 2)
2024{
2025if (compare(first->data, first->next->data) * order > 0)
2026{
2027/* swap the data */
2028void *data;
2029data = first->next->data;
2030first->next->data = first->data;
2031first->data = data;
2032}
2033
2034return first;
2035}
2036
2037/* first find the premiddle node*/
2038for (premid = first, i = 0; i < mid - 1; i++)
2039premid = premid->next;
2040
2041/* split the list */
2042middle = premid->next;
2043premid->next = NULL;
2044ECORE_DLIST_NODE(middle)->previous = NULL;
2045
2046/* sort the the partial lists */
2047first = _ecore_dlist_node_mergesort(first, mid, compare, order);
2048middle = _ecore_dlist_node_mergesort(middle, n - mid, compare, order);
2049
2050return _ecore_dlist_node_merge(first, middle, compare, order);
2051}
2052
2053/* this function is used to merge the partial sorted lists */
2054static Ecore_List_Node *
2055_ecore_dlist_node_merge(Ecore_List_Node *first, Ecore_List_Node *second,
2056Ecore_Compare_Cb compare, int order)
2057{
2058Ecore_List_Node *list;
2059Ecore_List_Node *l;
2060
2061/* select the first node outside the loop, because we need to keep
2062* a pointer to it */
2063if (compare(first->data, second->data) * order > 0)
2064{
2065list = l = second;
2066second = second->next;
2067}
2068else
2069{
2070list = l = first;
2071first = first->next;
2072}
2073
2074/* and now start the merging */
2075while (first && second)
2076{
2077if (compare(first->data, second->data) * order > 0)
2078{
2079ECORE_DLIST_NODE(second)->previous = ECORE_DLIST_NODE(l);
2080l = l->next = second;
2081second = second->next;
2082}
2083else
2084{
2085ECORE_DLIST_NODE(first)->previous = ECORE_DLIST_NODE(l);
2086l = l->next = first;
2087first = first->next;
2088}
2089}
2090
2091/* append the rest or set it to NULL */
2092if (first)
2093{
2094ECORE_DLIST_NODE(first)->previous = ECORE_DLIST_NODE(l);
2095l->next = first;
2096}
2097else if (second)
2098{
2099ECORE_DLIST_NODE(second)->previous = ECORE_DLIST_NODE(l);
2100l->next = second;
2101}
2102else
2103l->next = NULL;
2104
2105return list;
2106}
2107
2108/*
2109* @brief Initialize a node to sane starting values
2110* @param node: the node to initialize
2111* @return Returns TRUE on success, FALSE on errors
2112*/
2113EAPI int
2114ecore_dlist_node_init(Ecore_DList_Node *node)
2115{
2116int ret;
2117
2118CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
2119
2120ret = ecore_list_node_init(ECORE_LIST_NODE(node));
2121if (ret)
2122node->previous = NULL;
2123
2124return ret;
2125}
2126
2127/*
2128* @brief Allocate and initialize a new list node
2129* @return Returns NULL on error, new list node on success
2130*/
2131EAPI Ecore_DList_Node *
2132ecore_dlist_node_new()
2133{
2134Ecore_DList_Node *new_node;
2135
2136new_node = malloc(sizeof(Ecore_DList_Node));
2137
2138if (!new_node)
2139return NULL;
2140
2141if (!ecore_dlist_node_init(new_node))
2142{
2143FREE(new_node);
2144return NULL;
2145}
2146
2147return new_node;
2148}
2149
2150/*
2151* @brief Call the data's free callback function, then free the node
2152* @param node: the node to be freed
2153* @param free_func: the callback function to execute on the data
2154* @return Returns TRUE on success, FALSE on error
2155*/
2156EAPI int
2157ecore_dlist_node_destroy(Ecore_DList_Node *node, Ecore_Free_Cb free_func)
2158{
2159CHECK_PARAM_POINTER_RETURN("node", node, FALSE);
2160
2161return ecore_list_node_destroy(ECORE_LIST_NODE(node), free_func);
2162}
2163