10 static void *get_next(const void *a
)
12 return ((const struct line
*)a
)->next
;
15 static void set_next(void *a
, void *b
)
17 ((struct line
*)a
)->next
= b
;
20 static int compare_strings(const void *a
, const void *b
)
22 const struct line
*x
= a
, *y
= b
;
23 return strcmp(x
->text
, y
->text
);
26 static int sort_stdin(void)
28 struct line
*line
, *p
= NULL
, *lines
= NULL
;
29 struct strbuf sb
= STRBUF_INIT
;
31 while (!strbuf_getline(&sb
, stdin
)) {
32 line
= xmalloc(sizeof(struct line
));
33 line
->text
= strbuf_detach(&sb
, NULL
);
44 lines
= llist_mergesort(lines
, get_next
, set_next
, compare_strings
);
53 static void dist_sawtooth(int *arr
, int n
, int m
)
56 for (i
= 0; i
< n
; i
++)
60 static void dist_rand(int *arr
, int n
, int m
)
63 for (i
= 0; i
< n
; i
++)
67 static void dist_stagger(int *arr
, int n
, int m
)
70 for (i
= 0; i
< n
; i
++)
71 arr
[i
] = (i
* m
+ i
) % n
;
74 static void dist_plateau(int *arr
, int n
, int m
)
77 for (i
= 0; i
< n
; i
++)
78 arr
[i
] = (i
< m
) ? i
: m
;
81 static void dist_shuffle(int *arr
, int n
, int m
)
84 for (i
= j
= 0, k
= 1; i
< n
; i
++)
85 arr
[i
] = (rand() % m
) ? (j
+= 2) : (k
+= 2);
88 #define DIST(name) { #name, dist_##name }
92 void (*fn
)(int *arr
, int n
, int m
);
101 static const struct dist
*get_dist_by_name(const char *name
)
104 for (i
= 0; i
< ARRAY_SIZE(dist
); i
++) {
105 if (!strcmp(dist
[i
].name
, name
))
111 static void mode_copy(int *arr
, int n
)
116 static void mode_reverse(int *arr
, int n
)
119 for (i
= 0, j
= n
- 1; i
< j
; i
++, j
--)
120 SWAP(arr
[i
], arr
[j
]);
123 static void mode_reverse_1st_half(int *arr
, int n
)
125 mode_reverse(arr
, n
/ 2);
128 static void mode_reverse_2nd_half(int *arr
, int n
)
131 mode_reverse(arr
+ half
, n
- half
);
134 static int compare_ints(const void *av
, const void *bv
)
136 const int *ap
= av
, *bp
= bv
;
137 int a
= *ap
, b
= *bp
;
138 return (a
> b
) - (a
< b
);
141 static void mode_sort(int *arr
, int n
)
143 QSORT(arr
, n
, compare_ints
);
146 static void mode_dither(int *arr
, int n
)
149 for (i
= 0; i
< n
; i
++)
153 static void unriffle(int *arr
, int n
, int *tmp
)
156 COPY_ARRAY(tmp
, arr
, n
);
157 for (i
= j
= 0; i
< n
; i
+= 2)
159 for (i
= 1; i
< n
; i
+= 2)
163 static void unriffle_recursively(int *arr
, int n
, int *tmp
)
167 unriffle(arr
, n
, tmp
);
168 unriffle_recursively(arr
, half
, tmp
);
169 unriffle_recursively(arr
+ half
, n
- half
, tmp
);
173 static void mode_unriffle(int *arr
, int n
)
177 unriffle_recursively(arr
, n
, tmp
);
181 static unsigned int prev_pow2(unsigned int n
)
183 unsigned int pow2
= 1;
189 static void unriffle_recursively_skewed(int *arr
, int n
, int *tmp
)
192 int pow2
= prev_pow2(n
);
194 unriffle(arr
+ pow2
- rest
, rest
* 2, tmp
);
195 unriffle_recursively_skewed(arr
, pow2
, tmp
);
196 unriffle_recursively_skewed(arr
+ pow2
, rest
, tmp
);
200 static void mode_unriffle_skewed(int *arr
, int n
)
204 unriffle_recursively_skewed(arr
, n
, tmp
);
208 #define MODE(name) { #name, mode_##name }
212 void (*fn
)(int *arr
, int n
);
216 MODE(reverse_1st_half
),
217 MODE(reverse_2nd_half
),
221 MODE(unriffle_skewed
),
224 static const struct mode
*get_mode_by_name(const char *name
)
227 for (i
= 0; i
< ARRAY_SIZE(mode
); i
++) {
228 if (!strcmp(mode
[i
].name
, name
))
234 static int generate(int argc
, const char **argv
)
236 const struct dist
*dist
= NULL
;
237 const struct mode
*mode
= NULL
;
243 dist
= get_dist_by_name(argv
[0]);
244 mode
= get_mode_by_name(argv
[1]);
245 n
= strtol(argv
[2], NULL
, 10);
246 m
= strtol(argv
[3], NULL
, 10);
253 for (i
= 0; i
< n
; i
++)
254 printf("%08x\n", arr
[i
]);
259 static struct stats
{
260 int get_next
, set_next
, compare
;
268 static void *get_next_number(const void *a
)
271 return ((const struct number
*)a
)->next
;
274 static void set_next_number(void *a
, void *b
)
277 ((struct number
*)a
)->next
= b
;
280 static int compare_numbers(const void *av
, const void *bv
)
282 const struct number
*an
= av
, *bn
= bv
;
283 int a
= an
->value
, b
= bn
->value
;
285 return (a
> b
) - (a
< b
);
288 static void clear_numbers(struct number
*list
)
291 struct number
*next
= list
->next
;
297 static int test(const struct dist
*dist
, const struct mode
*mode
, int n
, int m
)
301 struct number
*curr
, *list
, **tail
;
310 for (i
= 0, tail
= &list
; i
< n
; i
++) {
311 curr
= xmalloc(sizeof(*curr
));
312 curr
->value
= arr
[i
];
319 stats
.get_next
= stats
.set_next
= stats
.compare
= 0;
320 list
= llist_mergesort(list
, get_next_number
, set_next_number
,
323 QSORT(arr
, n
, compare_ints
);
324 for (i
= 0, curr
= list
; i
< n
&& curr
; i
++, curr
= curr
->next
) {
325 if (arr
[i
] != curr
->value
)
327 if (curr
->next
&& curr
->value
== curr
->next
->value
&&
328 curr
->rank
>= curr
->next
->rank
)
332 verdict
= "too short";
334 verdict
= "too long";
335 } else if (!is_sorted
) {
336 verdict
= "not sorted";
337 } else if (!is_stable
) {
338 verdict
= "unstable";
344 printf("%-9s %-16s %8d %8d %8d %8d %8d %s\n",
345 dist
->name
, mode
->name
, n
, m
, stats
.get_next
, stats
.set_next
,
346 stats
.compare
, verdict
);
355 * A version of the qsort certification program from "Engineering a Sort
356 * Function" by Bentley and McIlroy, Software—Practice and Experience,
357 * Volume 23, Issue 11, 1249–1265 (November 1993).
359 static int run_tests(int argc
, const char **argv
)
361 const char *argv_default
[] = { "100", "1023", "1024", "1025" };
363 return run_tests(ARRAY_SIZE(argv_default
), argv_default
);
364 printf("%-9s %-16s %8s %8s %8s %8s %8s %s\n",
365 "distribut", "mode", "n", "m", "get_next", "set_next",
366 "compare", "verdict");
368 int i
, j
, m
, n
= strtol(*argv
++, NULL
, 10);
369 for (i
= 0; i
< ARRAY_SIZE(dist
); i
++) {
370 for (j
= 0; j
< ARRAY_SIZE(mode
); j
++) {
371 for (m
= 1; m
< 2 * n
; m
*= 2) {
372 if (test(&dist
[i
], &mode
[j
], n
, m
))
381 int cmd__mergesort(int argc
, const char **argv
)
386 if (argc
== 6 && !strcmp(argv
[1], "generate"))
387 return generate(argc
- 2, argv
+ 2);
388 if (argc
== 2 && !strcmp(argv
[1], "sort"))
390 if (argc
> 1 && !strcmp(argv
[1], "test"))
391 return run_tests(argc
- 2, argv
+ 2);
392 fprintf(stderr
, "usage: test-tool mergesort generate <distribution> <mode> <n> <m>\n");
393 fprintf(stderr
, " or: test-tool mergesort sort\n");
394 fprintf(stderr
, " or: test-tool mergesort test [<n>...]\n");
395 fprintf(stderr
, "\n");
396 for (i
= 0, sep
= "distributions: "; i
< ARRAY_SIZE(dist
); i
++, sep
= ", ")
397 fprintf(stderr
, "%s%s", sep
, dist
[i
].name
);
398 fprintf(stderr
, "\n");
399 for (i
= 0, sep
= "modes: "; i
< ARRAY_SIZE(mode
); i
++, sep
= ", ")
400 fprintf(stderr
, "%s%s", sep
, mode
[i
].name
);
401 fprintf(stderr
, "\n");