]>
git.ipfire.org Git - thirdparty/git.git/blob - t/helper/test-mergesort.c
5 static uint32_t minstd_rand(uint32_t *state
)
7 *state
= (uint64_t)*state
* 48271 % 2147483647;
16 static void *get_next(const void *a
)
18 return ((const struct line
*)a
)->next
;
21 static void set_next(void *a
, void *b
)
23 ((struct line
*)a
)->next
= b
;
26 static int compare_strings(const void *a
, const void *b
)
28 const struct line
*x
= a
, *y
= b
;
29 return strcmp(x
->text
, y
->text
);
32 static int sort_stdin(void)
34 struct line
*line
, *p
= NULL
, *lines
= NULL
;
35 struct strbuf sb
= STRBUF_INIT
;
37 while (!strbuf_getline(&sb
, stdin
)) {
38 line
= xmalloc(sizeof(struct line
));
39 line
->text
= strbuf_detach(&sb
, NULL
);
50 lines
= llist_mergesort(lines
, get_next
, set_next
, compare_strings
);
59 static void dist_sawtooth(int *arr
, int n
, int m
)
62 for (i
= 0; i
< n
; i
++)
66 static void dist_rand(int *arr
, int n
, int m
)
70 for (i
= 0; i
< n
; i
++)
71 arr
[i
] = minstd_rand(&seed
) % m
;
74 static void dist_stagger(int *arr
, int n
, int m
)
77 for (i
= 0; i
< n
; i
++)
78 arr
[i
] = (i
* m
+ i
) % n
;
81 static void dist_plateau(int *arr
, int n
, int m
)
84 for (i
= 0; i
< n
; i
++)
85 arr
[i
] = (i
< m
) ? i
: m
;
88 static void dist_shuffle(int *arr
, int n
, int m
)
92 for (i
= j
= 0, k
= 1; i
< n
; i
++)
93 arr
[i
] = minstd_rand(&seed
) % m
? (j
+= 2) : (k
+= 2);
96 #define DIST(name) { #name, dist_##name }
100 void (*fn
)(int *arr
, int n
, int m
);
109 static const struct dist
*get_dist_by_name(const char *name
)
112 for (i
= 0; i
< ARRAY_SIZE(dist
); i
++) {
113 if (!strcmp(dist
[i
].name
, name
))
119 static void mode_copy(int *arr
, int n
)
124 static void mode_reverse(int *arr
, int n
)
127 for (i
= 0, j
= n
- 1; i
< j
; i
++, j
--)
128 SWAP(arr
[i
], arr
[j
]);
131 static void mode_reverse_1st_half(int *arr
, int n
)
133 mode_reverse(arr
, n
/ 2);
136 static void mode_reverse_2nd_half(int *arr
, int n
)
139 mode_reverse(arr
+ half
, n
- half
);
142 static int compare_ints(const void *av
, const void *bv
)
144 const int *ap
= av
, *bp
= bv
;
145 int a
= *ap
, b
= *bp
;
146 return (a
> b
) - (a
< b
);
149 static void mode_sort(int *arr
, int n
)
151 QSORT(arr
, n
, compare_ints
);
154 static void mode_dither(int *arr
, int n
)
157 for (i
= 0; i
< n
; i
++)
161 static void unriffle(int *arr
, int n
, int *tmp
)
164 COPY_ARRAY(tmp
, arr
, n
);
165 for (i
= j
= 0; i
< n
; i
+= 2)
167 for (i
= 1; i
< n
; i
+= 2)
171 static void unriffle_recursively(int *arr
, int n
, int *tmp
)
175 unriffle(arr
, n
, tmp
);
176 unriffle_recursively(arr
, half
, tmp
);
177 unriffle_recursively(arr
+ half
, n
- half
, tmp
);
181 static void mode_unriffle(int *arr
, int n
)
185 unriffle_recursively(arr
, n
, tmp
);
189 static unsigned int prev_pow2(unsigned int n
)
191 unsigned int pow2
= 1;
197 static void unriffle_recursively_skewed(int *arr
, int n
, int *tmp
)
200 int pow2
= prev_pow2(n
);
202 unriffle(arr
+ pow2
- rest
, rest
* 2, tmp
);
203 unriffle_recursively_skewed(arr
, pow2
, tmp
);
204 unriffle_recursively_skewed(arr
+ pow2
, rest
, tmp
);
208 static void mode_unriffle_skewed(int *arr
, int n
)
212 unriffle_recursively_skewed(arr
, n
, tmp
);
216 #define MODE(name) { #name, mode_##name }
220 void (*fn
)(int *arr
, int n
);
224 MODE(reverse_1st_half
),
225 MODE(reverse_2nd_half
),
229 MODE(unriffle_skewed
),
232 static const struct mode
*get_mode_by_name(const char *name
)
235 for (i
= 0; i
< ARRAY_SIZE(mode
); i
++) {
236 if (!strcmp(mode
[i
].name
, name
))
242 static int generate(int argc
, const char **argv
)
244 const struct dist
*dist
= NULL
;
245 const struct mode
*mode
= NULL
;
251 dist
= get_dist_by_name(argv
[0]);
252 mode
= get_mode_by_name(argv
[1]);
253 n
= strtol(argv
[2], NULL
, 10);
254 m
= strtol(argv
[3], NULL
, 10);
261 for (i
= 0; i
< n
; i
++)
262 printf("%08x\n", arr
[i
]);
267 static struct stats
{
268 int get_next
, set_next
, compare
;
276 static void *get_next_number(const void *a
)
279 return ((const struct number
*)a
)->next
;
282 static void set_next_number(void *a
, void *b
)
285 ((struct number
*)a
)->next
= b
;
288 static int compare_numbers(const void *av
, const void *bv
)
290 const struct number
*an
= av
, *bn
= bv
;
291 int a
= an
->value
, b
= bn
->value
;
293 return (a
> b
) - (a
< b
);
296 static void clear_numbers(struct number
*list
)
299 struct number
*next
= list
->next
;
305 static int test(const struct dist
*dist
, const struct mode
*mode
, int n
, int m
)
309 struct number
*curr
, *list
, **tail
;
318 for (i
= 0, tail
= &list
; i
< n
; i
++) {
319 curr
= xmalloc(sizeof(*curr
));
320 curr
->value
= arr
[i
];
327 stats
.get_next
= stats
.set_next
= stats
.compare
= 0;
328 list
= llist_mergesort(list
, get_next_number
, set_next_number
,
331 QSORT(arr
, n
, compare_ints
);
332 for (i
= 0, curr
= list
; i
< n
&& curr
; i
++, curr
= curr
->next
) {
333 if (arr
[i
] != curr
->value
)
335 if (curr
->next
&& curr
->value
== curr
->next
->value
&&
336 curr
->rank
>= curr
->next
->rank
)
340 verdict
= "too short";
342 verdict
= "too long";
343 } else if (!is_sorted
) {
344 verdict
= "not sorted";
345 } else if (!is_stable
) {
346 verdict
= "unstable";
352 printf("%-9s %-16s %8d %8d %8d %8d %8d %s\n",
353 dist
->name
, mode
->name
, n
, m
, stats
.get_next
, stats
.set_next
,
354 stats
.compare
, verdict
);
363 * A version of the qsort certification program from "Engineering a Sort
364 * Function" by Bentley and McIlroy, Software—Practice and Experience,
365 * Volume 23, Issue 11, 1249–1265 (November 1993).
367 static int run_tests(int argc
, const char **argv
)
369 const char *argv_default
[] = { "100", "1023", "1024", "1025" };
371 return run_tests(ARRAY_SIZE(argv_default
), argv_default
);
372 printf("%-9s %-16s %8s %8s %8s %8s %8s %s\n",
373 "distribut", "mode", "n", "m", "get_next", "set_next",
374 "compare", "verdict");
376 int i
, j
, m
, n
= strtol(*argv
++, NULL
, 10);
377 for (i
= 0; i
< ARRAY_SIZE(dist
); i
++) {
378 for (j
= 0; j
< ARRAY_SIZE(mode
); j
++) {
379 for (m
= 1; m
< 2 * n
; m
*= 2) {
380 if (test(&dist
[i
], &mode
[j
], n
, m
))
389 int cmd__mergesort(int argc
, const char **argv
)
394 if (argc
== 6 && !strcmp(argv
[1], "generate"))
395 return generate(argc
- 2, argv
+ 2);
396 if (argc
== 2 && !strcmp(argv
[1], "sort"))
398 if (argc
> 1 && !strcmp(argv
[1], "test"))
399 return run_tests(argc
- 2, argv
+ 2);
400 fprintf(stderr
, "usage: test-tool mergesort generate <distribution> <mode> <n> <m>\n");
401 fprintf(stderr
, " or: test-tool mergesort sort\n");
402 fprintf(stderr
, " or: test-tool mergesort test [<n>...]\n");
403 fprintf(stderr
, "\n");
404 for (i
= 0, sep
= "distributions: "; i
< ARRAY_SIZE(dist
); i
++, sep
= ", ")
405 fprintf(stderr
, "%s%s", sep
, dist
[i
].name
);
406 fprintf(stderr
, "\n");
407 for (i
= 0, sep
= "modes: "; i
< ARRAY_SIZE(mode
); i
++, sep
= ", ")
408 fprintf(stderr
, "%s%s", sep
, mode
[i
].name
);
409 fprintf(stderr
, "\n");