]>
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 DEFINE_LIST_SORT(static, sort_lines
, struct line
, next
);
18 static int compare_strings(const struct line
*x
, const struct line
*y
)
20 return strcmp(x
->text
, y
->text
);
23 static int sort_stdin(void)
26 struct line
**tail
= &lines
;
27 struct strbuf sb
= STRBUF_INIT
;
28 struct mem_pool lines_pool
;
31 strbuf_read(&sb
, 0, 0);
34 * Split by newline, but don't create an item
35 * for the empty string after the last separator.
37 if (sb
.len
&& sb
.buf
[sb
.len
- 1] == '\n')
38 strbuf_setlen(&sb
, sb
.len
- 1);
40 mem_pool_init(&lines_pool
, 0);
43 char *eol
= strchr(p
, '\n');
44 struct line
*line
= mem_pool_alloc(&lines_pool
, sizeof(*line
));
55 sort_lines(&lines
, compare_strings
);
64 static void dist_sawtooth(int *arr
, int n
, int m
)
67 for (i
= 0; i
< n
; i
++)
71 static void dist_rand(int *arr
, int n
, int m
)
75 for (i
= 0; i
< n
; i
++)
76 arr
[i
] = minstd_rand(&seed
) % m
;
79 static void dist_stagger(int *arr
, int n
, int m
)
82 for (i
= 0; i
< n
; i
++)
83 arr
[i
] = (i
* m
+ i
) % n
;
86 static void dist_plateau(int *arr
, int n
, int m
)
89 for (i
= 0; i
< n
; i
++)
90 arr
[i
] = (i
< m
) ? i
: m
;
93 static void dist_shuffle(int *arr
, int n
, int m
)
97 for (i
= j
= 0, k
= 1; i
< n
; i
++)
98 arr
[i
] = minstd_rand(&seed
) % m
? (j
+= 2) : (k
+= 2);
101 #define DIST(name) { #name, dist_##name }
105 void (*fn
)(int *arr
, int n
, int m
);
114 static const struct dist
*get_dist_by_name(const char *name
)
117 for (i
= 0; i
< ARRAY_SIZE(dist
); i
++) {
118 if (!strcmp(dist
[i
].name
, name
))
124 static void mode_copy(int *arr
, int n
)
129 static void mode_reverse(int *arr
, int n
)
132 for (i
= 0, j
= n
- 1; i
< j
; i
++, j
--)
133 SWAP(arr
[i
], arr
[j
]);
136 static void mode_reverse_1st_half(int *arr
, int n
)
138 mode_reverse(arr
, n
/ 2);
141 static void mode_reverse_2nd_half(int *arr
, int n
)
144 mode_reverse(arr
+ half
, n
- half
);
147 static int compare_ints(const void *av
, const void *bv
)
149 const int *ap
= av
, *bp
= bv
;
150 int a
= *ap
, b
= *bp
;
151 return (a
> b
) - (a
< b
);
154 static void mode_sort(int *arr
, int n
)
156 QSORT(arr
, n
, compare_ints
);
159 static void mode_dither(int *arr
, int n
)
162 for (i
= 0; i
< n
; i
++)
166 static void unriffle(int *arr
, int n
, int *tmp
)
169 COPY_ARRAY(tmp
, arr
, n
);
170 for (i
= j
= 0; i
< n
; i
+= 2)
172 for (i
= 1; i
< n
; i
+= 2)
176 static void unriffle_recursively(int *arr
, int n
, int *tmp
)
180 unriffle(arr
, n
, tmp
);
181 unriffle_recursively(arr
, half
, tmp
);
182 unriffle_recursively(arr
+ half
, n
- half
, tmp
);
186 static void mode_unriffle(int *arr
, int n
)
190 unriffle_recursively(arr
, n
, tmp
);
194 static unsigned int prev_pow2(unsigned int n
)
196 unsigned int pow2
= 1;
202 static void unriffle_recursively_skewed(int *arr
, int n
, int *tmp
)
205 int pow2
= prev_pow2(n
);
207 unriffle(arr
+ pow2
- rest
, rest
* 2, tmp
);
208 unriffle_recursively_skewed(arr
, pow2
, tmp
);
209 unriffle_recursively_skewed(arr
+ pow2
, rest
, tmp
);
213 static void mode_unriffle_skewed(int *arr
, int n
)
217 unriffle_recursively_skewed(arr
, n
, tmp
);
221 #define MODE(name) { #name, mode_##name }
225 void (*fn
)(int *arr
, int n
);
229 MODE(reverse_1st_half
),
230 MODE(reverse_2nd_half
),
234 MODE(unriffle_skewed
),
237 static const struct mode
*get_mode_by_name(const char *name
)
240 for (i
= 0; i
< ARRAY_SIZE(mode
); i
++) {
241 if (!strcmp(mode
[i
].name
, name
))
247 static int generate(int argc
, const char **argv
)
249 const struct dist
*dist
= NULL
;
250 const struct mode
*mode
= NULL
;
256 dist
= get_dist_by_name(argv
[0]);
257 mode
= get_mode_by_name(argv
[1]);
258 n
= strtol(argv
[2], NULL
, 10);
259 m
= strtol(argv
[3], NULL
, 10);
266 for (i
= 0; i
< n
; i
++)
267 printf("%08x\n", arr
[i
]);
272 static struct stats
{
273 int get_next
, set_next
, compare
;
281 DEFINE_LIST_SORT_DEBUG(static, sort_numbers
, struct number
, next
,
282 stats
.get_next
++, stats
.set_next
++);
284 static int compare_numbers(const struct number
*an
, const struct number
*bn
)
286 int a
= an
->value
, b
= bn
->value
;
288 return (a
> b
) - (a
< b
);
291 static void clear_numbers(struct number
*list
)
294 struct number
*next
= list
->next
;
300 static int test(const struct dist
*dist
, const struct mode
*mode
, int n
, int m
)
304 struct number
*curr
, *list
, **tail
;
313 for (i
= 0, tail
= &list
; i
< n
; i
++) {
314 curr
= xmalloc(sizeof(*curr
));
315 curr
->value
= arr
[i
];
322 stats
.get_next
= stats
.set_next
= stats
.compare
= 0;
323 sort_numbers(&list
, compare_numbers
);
325 QSORT(arr
, n
, compare_ints
);
326 for (i
= 0, curr
= list
; i
< n
&& curr
; i
++, curr
= curr
->next
) {
327 if (arr
[i
] != curr
->value
)
329 if (curr
->next
&& curr
->value
== curr
->next
->value
&&
330 curr
->rank
>= curr
->next
->rank
)
334 verdict
= "too short";
336 verdict
= "too long";
337 } else if (!is_sorted
) {
338 verdict
= "not sorted";
339 } else if (!is_stable
) {
340 verdict
= "unstable";
346 printf("%-9s %-16s %8d %8d %8d %8d %8d %s\n",
347 dist
->name
, mode
->name
, n
, m
, stats
.get_next
, stats
.set_next
,
348 stats
.compare
, verdict
);
357 * A version of the qsort certification program from "Engineering a Sort
358 * Function" by Bentley and McIlroy, Software—Practice and Experience,
359 * Volume 23, Issue 11, 1249–1265 (November 1993).
361 static int run_tests(int argc
, const char **argv
)
363 const char *argv_default
[] = { "100", "1023", "1024", "1025" };
365 return run_tests(ARRAY_SIZE(argv_default
), argv_default
);
366 printf("%-9s %-16s %8s %8s %8s %8s %8s %s\n",
367 "distribut", "mode", "n", "m", "get_next", "set_next",
368 "compare", "verdict");
370 int i
, j
, m
, n
= strtol(*argv
++, NULL
, 10);
371 for (i
= 0; i
< ARRAY_SIZE(dist
); i
++) {
372 for (j
= 0; j
< ARRAY_SIZE(mode
); j
++) {
373 for (m
= 1; m
< 2 * n
; m
*= 2) {
374 if (test(&dist
[i
], &mode
[j
], n
, m
))
383 int cmd__mergesort(int argc
, const char **argv
)
388 if (argc
== 6 && !strcmp(argv
[1], "generate"))
389 return generate(argc
- 2, argv
+ 2);
390 if (argc
== 2 && !strcmp(argv
[1], "sort"))
392 if (argc
> 1 && !strcmp(argv
[1], "test"))
393 return run_tests(argc
- 2, argv
+ 2);
394 fprintf(stderr
, "usage: test-tool mergesort generate <distribution> <mode> <n> <m>\n");
395 fprintf(stderr
, " or: test-tool mergesort sort\n");
396 fprintf(stderr
, " or: test-tool mergesort test [<n>...]\n");
397 fprintf(stderr
, "\n");
398 for (i
= 0, sep
= "distributions: "; i
< ARRAY_SIZE(dist
); i
++, sep
= ", ")
399 fprintf(stderr
, "%s%s", sep
, dist
[i
].name
);
400 fprintf(stderr
, "\n");
401 for (i
= 0, sep
= "modes: "; i
< ARRAY_SIZE(mode
); i
++, sep
= ", ")
402 fprintf(stderr
, "%s%s", sep
, mode
[i
].name
);
403 fprintf(stderr
, "\n");