2 * sort_list: a stable sort for lists.
4 * Time complexity: O(n*log n)
5 * [assuming limited zero-element fragments]
7 * Space complexity: O(1).
29 static unsigned char been_there
[256];
30 #define BEEN_THERE(_c) \
32 if (!been_there[_c]) { \
34 printf ("Been there: %c\n", _c); \
38 #define BEEN_THERE(_c) do { } while (0)
41 // Sort one fragment. LIST_NODE_NR (==29) is a bit too high for my
42 // taste for something this simple. But, hey, it's O(1).
44 // I would use libc qsort for this, but its comparison function
45 // gets a pointer indirection extra.
46 static void array_sort(void **ptr
, int nr
, int (*cmp
)(const void *, const void *))
49 for (i
= 1; i
< nr
; i
++) {
51 if (cmp(ptr
[i
-1],p
) > 0) {
57 } while (cmp(ptr
[j
-1], p
) > 0);
64 static void verify_seq_sorted (struct ptr_list
*l
, int n
,
65 int (*cmp
)(const void *, const void *))
69 struct ptr_list
*head
= l
;
85 assert (l
!= head
|| n
== 0);
89 assert (cmp (a
, b
) <= 0);
99 assert (nbuf >= nr); \
100 memcpy ((b)->list, buffer, nr * sizeof (void *)); \
102 memmove (buffer, buffer + nr, nbuf * sizeof (void *)); \
107 assert (nbuf <= (b)->nr); \
108 memcpy ((b)->list, buffer, nbuf * sizeof (void *)); \
112 // Merge two already-sorted sequences of blocks:
113 // (b1_1, ..., b1_n) and (b2_1, ..., b2_m)
114 // Since we may be moving blocks around, we return the new head
115 // of the merged list.
116 static struct ptr_list
*
117 merge_block_seqs (struct ptr_list
*b1
, int n
,
118 struct ptr_list
*b2
, int m
,
119 int (*cmp
)(const void *, const void *))
122 const void *buffer
[2 * LIST_NODE_NR
];
124 struct ptr_list
*newhead
= b1
;
126 // printf ("Merging %d blocks at %p with %d blocks at %p\n", n, b1, m, b2);
128 // Skip empty blocks in b2.
129 while (b2
->nr
== 0) {
138 // Do a quick skip in case entire blocks from b1 are
139 // already less than smallest element in b2.
140 while (b1
->nr
== 0 ||
141 cmp (PTR_ENTRY_NOTAG(b1
, b1
->nr
- 1), PTR_ENTRY_NOTAG(b2
,0)) < 0) {
142 // printf ("Skipping whole block.\n");
152 const void *d1
= PTR_ENTRY_NOTAG(b1
,i1
);
153 const void *d2
= PTR_ENTRY_NOTAG(b2
,i2
);
155 assert (i1
>= 0 && i1
< b1
->nr
);
156 assert (i2
>= 0 && i2
< b2
->nr
);
161 if (cmp (d1
, d2
) <= 0) {
164 // Element from b1 is smaller
165 if (++i1
>= b1
->nr
) {
181 } while (b1
->nr
== 0);
186 // Element from b2 is smaller
188 if (++i2
>= b2
->nr
) {
189 struct ptr_list
*l
= b2
;
191 // OK, we finished with b2. Pull it out
192 // and plug it in before b1.
217 } while (b2
->nr
== 0);
225 void sort_list(struct ptr_list
**plist
, int (*cmp
)(const void *, const void *))
227 struct ptr_list
*head
= *plist
, *list
= head
;
233 // Sort all the sub-lists
235 array_sort(list
->list
, list
->nr
, cmp
);
237 verify_seq_sorted (list
, 1, cmp
);
240 } while (list
!= head
);
242 // Merge the damn things together
244 struct ptr_list
*block1
= head
;
247 struct ptr_list
*block2
= block1
;
248 struct ptr_list
*next
, *newhead
;
251 for (i
= 0; i
< blocks
; i
++) {
252 block2
= block2
->next
;
253 if (block2
== head
) {
254 if (block1
== head
) {
265 for (i
= 0; i
< blocks
; ) {
275 newhead
= merge_block_seqs (block1
, blocks
,
279 verify_seq_sorted (newhead
, blocks
+ i
, cmp
);
281 if (block1
== head
) {
286 } while (block1
!= head
);