boot.library is no more, *.handler to *-handler.
[AROS.git] / compiler / alib / mergesortlist.c
blob950c24e2a619843fe4d3bd82bd082015a6cc1f3d
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Sort a list using a variant of the MergeSort algorithm.
6 Lang: english
7 */
9 #include <exec/lists.h>
10 #include <stddef.h>
12 /*****************************************************************************
14 NAME */
15 #if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
16 __attribute__((regparm(2)))
17 #endif
18 static inline struct MinNode *Merge(
20 /* SYNOPSIS */
21 struct MinNode *l,
22 int (*compare)(struct MinNode *n1, struct MinNode *n2, void *data),
23 void *data)
25 /* FUNCTION
26 Given a list of ordered circular sublists, merge pairs of ordered sublists into one
27 ordered circular sublist.
29 INPUTS
30 l - The first node of the first sublist. The sublists must be linked one
31 after the other one, and must be circular lists, that is their
32 first node's Pred pointer must point to their last node.
34 I.e., the 2nd sublist will be at l->mln_Pred->mln_Succ, the 3rd will be at
35 l->mln_Pred->mln_Succ->mln_Pred->mln_Succ and so on.
37 compare - Pointer to the comparison function used to merge the
38 sublists
40 data - Pointer to user-defined data which will be passed untouched
41 to the comparison function.
43 RESULT
44 Pointer to the first node of the resulting list of sublists, with the same
45 format of the input list, but with pairs of sublists merged into one.
47 ******************************************************************************/
49 struct MinNode *l1, *last_l1, *l2, *last_l2, *next_l;
50 struct MinNode *first = NULL, **first_ptr, **last_ptr = &first;
52 l1 = l;
54 /* l1 points to the 1st sublist, l2 points to the 2nd.
56 Should there be no l2, we don't need to do anything special, as
57 l1 will already be linked with the rest of the list AND it won't
58 obviously need to be merged with another list. */
59 while (l1 && (l2 = (last_l1 = l1->mln_Pred)->mln_Succ))
61 last_l2 = l2->mln_Pred;
63 next_l = last_l2->mln_Succ;
65 /* This will make the below loop slightly faster, since there will only
66 be tests against the constant NULL. */
67 last_l1->mln_Succ = NULL;
68 last_l2->mln_Succ = NULL;
70 /* Pointer to the beginning of the merged sublist */
71 first_ptr = last_ptr;
74 if (compare(l1, l2, data) < 0)
76 l1->mln_Pred = (struct MinNode *)((char *)last_ptr -
77 offsetof(struct MinNode, mln_Succ));
78 *last_ptr = l1;
79 l1 = l1->mln_Succ;
81 else
83 l2->mln_Pred = (struct MinNode *)((char *)last_ptr -
84 offsetof(struct MinNode, mln_Succ));
85 *last_ptr = l2;
86 l2 = l2->mln_Succ;
89 last_ptr = &(*last_ptr)->mln_Succ;
90 } while (l1 && l2);
92 if (l1)
94 l1->mln_Pred = (struct MinNode *)((char *)last_ptr -
95 offsetof(struct MinNode, mln_Succ));
97 *last_ptr = l1;
98 (*first_ptr)->mln_Pred = last_l1;
99 last_ptr = &last_l1->mln_Succ;
101 else
102 if (l2)
104 l2->mln_Pred = (struct MinNode *)((char *)last_ptr -
105 offsetof(struct MinNode, mln_Succ));
107 *last_ptr = l2;
108 (*first_ptr)->mln_Pred = last_l2;
109 last_ptr = &last_l2->mln_Succ;
111 else
113 (*first_ptr)->mln_Pred = (struct MinNode *)((char *)last_ptr -
114 offsetof(struct MinNode, mln_Succ));
117 l1 = *last_ptr = next_l;
120 return first;
123 /*****************************************************************************
125 NAME */
126 #include <clib/alib_protos.h>
127 void MergeSortList(
129 /* SYNOPSIS */
130 struct MinList *l,
131 int (*compare)(struct MinNode *n1, struct MinNode *n2, void *data),
132 void *data)
134 /* FUNCTION
135 Sorts an Exec-style doubly linked list, by using a variant of the merge sorting
136 algorithm, which is Theta(n log n ). No additional space is required other than
137 the one needed for local variables in the function itself. The function is not
138 recursive.
140 INPUTS
141 l - The list to sort.
143 compare - Pointer to the comparison function which establishes the order
144 of the elements in the list
146 data - Pointer to user-defined data which will be passed untouched
147 to the comparison function.
149 RESULT
150 The given list, sorted in place.
152 ******************************************************************************/
154 struct MinNode *head = (struct MinNode *)GetHead(l);
155 struct MinNode *tail = (struct MinNode *)GetTail(l);
157 struct MinNode *l1, *l2,
158 *first, **last_ptr;
160 if (!head || head == tail)
161 return;
163 tail->mln_Succ = NULL;
164 last_ptr = &first;
166 /* The Merge() function requires a list of sublists, each of which
167 has to be a circular list. Since the given list doesn't have these
168 properties, we need to divide the sorting algorithm in 2 parts:
170 1) we first go trough the list once, making every node's Pred pointer
171 point to the node itself, so that the given list of n nodes is
172 transformed in a list of n circular sublists. Here we do the merging
173 "manually", without the help of the Merge() function, as we have to
174 deal with just couples of nodes, thus we can do some extra optimization.
176 2) We then feed the resulting list to the Merge() function, as many times as
177 it takes to the Merge() function to give back just one circular list, rather
178 than a list of circular sublists: that will be our sorted list. */
180 /* This is the first part. */
181 l1 = head;
182 l2 = l1->mln_Succ;
185 /* It can happen that the 2 nodes are already in the right,
186 order and thus we only need to make a circular list out
187 of them, or their order needs to be reversed, but
188 in either case, the below line is necessary, because:
190 1) In the first case, it serves to build the
191 circular list.
193 2) In the 2nd case, it does 1/4 of the job of
194 reversing the order of the nodes (the
195 other 3/4 are done inside the if block). */
196 l1->mln_Pred = l2;
198 if (compare(l1, l2, data) >= 0)
200 /* l2 comes before l1, so rearrange them and
201 make a circular list out of them. */
202 l1->mln_Succ = l2->mln_Succ;
203 l2->mln_Succ = l1;
204 l2->mln_Pred = l1;
206 l1 = l2;
209 *last_ptr = l1;
210 last_ptr = &l1->mln_Pred->mln_Succ;
211 l1 = *last_ptr;
212 } while (l1 && (l2 = l1->mln_Succ));
214 /* An orphan node? Add it at the end of the list of sublists and
215 make a circular list out of it. */
216 if (l1)
218 l1->mln_Pred = l1;
219 *last_ptr = l1;
222 /* And this is the 2nd part. */
223 while (first->mln_Pred->mln_Succ)
224 first = Merge(first, compare, data);
226 /* Now we fix up the list header */
227 l->mlh_Head = first;
228 l->mlh_TailPred = first->mln_Pred;
229 first->mln_Pred->mln_Succ = (struct MinNode *)&l->mlh_Tail;
230 first->mln_Pred = (struct MinNode *)&l->mlh_Head;