2018-03-24 07:44:46 +00:00
|
|
|
|
#include "test-tool.h"
|
2023-04-11 07:41:47 +00:00
|
|
|
|
#include "mem-pool.h"
|
2012-03-31 22:10:11 +00:00
|
|
|
|
#include "mergesort.h"
|
2023-04-22 20:17:08 +00:00
|
|
|
|
#include "strbuf.h"
|
2012-03-31 22:10:11 +00:00
|
|
|
|
|
2021-10-08 04:04:42 +00:00
|
|
|
|
static uint32_t minstd_rand(uint32_t *state)
|
|
|
|
|
{
|
|
|
|
|
*state = (uint64_t)*state * 48271 % 2147483647;
|
|
|
|
|
return *state;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-31 22:10:11 +00:00
|
|
|
|
struct line {
|
|
|
|
|
char *text;
|
|
|
|
|
struct line *next;
|
|
|
|
|
};
|
|
|
|
|
|
2022-07-16 16:57:18 +00:00
|
|
|
|
DEFINE_LIST_SORT(static, sort_lines, struct line, next);
|
2012-03-31 22:10:11 +00:00
|
|
|
|
|
2022-07-16 16:57:18 +00:00
|
|
|
|
static int compare_strings(const struct line *x, const struct line *y)
|
2012-03-31 22:10:11 +00:00
|
|
|
|
{
|
|
|
|
|
return strcmp(x->text, y->text);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-01 09:11:19 +00:00
|
|
|
|
static int sort_stdin(void)
|
2012-03-31 22:10:11 +00:00
|
|
|
|
{
|
2022-08-28 10:34:05 +00:00
|
|
|
|
struct line *lines;
|
|
|
|
|
struct line **tail = &lines;
|
2012-03-31 22:10:11 +00:00
|
|
|
|
struct strbuf sb = STRBUF_INIT;
|
2022-08-28 10:34:47 +00:00
|
|
|
|
struct mem_pool lines_pool;
|
2022-08-28 10:34:05 +00:00
|
|
|
|
char *p;
|
2012-03-31 22:10:11 +00:00
|
|
|
|
|
2022-08-28 10:34:05 +00:00
|
|
|
|
strbuf_read(&sb, 0, 0);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Split by newline, but don't create an item
|
|
|
|
|
* for the empty string after the last separator.
|
|
|
|
|
*/
|
|
|
|
|
if (sb.len && sb.buf[sb.len - 1] == '\n')
|
|
|
|
|
strbuf_setlen(&sb, sb.len - 1);
|
|
|
|
|
|
2022-08-28 10:34:47 +00:00
|
|
|
|
mem_pool_init(&lines_pool, 0);
|
2022-08-28 10:34:05 +00:00
|
|
|
|
p = sb.buf;
|
|
|
|
|
for (;;) {
|
|
|
|
|
char *eol = strchr(p, '\n');
|
2022-08-28 10:34:47 +00:00
|
|
|
|
struct line *line = mem_pool_alloc(&lines_pool, sizeof(*line));
|
2022-08-28 10:34:05 +00:00
|
|
|
|
line->text = p;
|
|
|
|
|
*tail = line;
|
|
|
|
|
tail = &line->next;
|
|
|
|
|
if (!eol)
|
|
|
|
|
break;
|
|
|
|
|
*eol = '\0';
|
|
|
|
|
p = eol + 1;
|
2012-03-31 22:10:11 +00:00
|
|
|
|
}
|
2022-08-28 10:34:05 +00:00
|
|
|
|
*tail = NULL;
|
2012-03-31 22:10:11 +00:00
|
|
|
|
|
2022-07-16 16:57:18 +00:00
|
|
|
|
sort_lines(&lines, compare_strings);
|
2012-03-31 22:10:11 +00:00
|
|
|
|
|
|
|
|
|
while (lines) {
|
2021-10-01 09:10:09 +00:00
|
|
|
|
puts(lines->text);
|
2012-03-31 22:10:11 +00:00
|
|
|
|
lines = lines->next;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2021-10-01 09:11:19 +00:00
|
|
|
|
|
2021-10-01 09:12:27 +00:00
|
|
|
|
static void dist_sawtooth(int *arr, int n, int m)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
|
arr[i] = i % m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void dist_rand(int *arr, int n, int m)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
2021-10-08 04:04:42 +00:00
|
|
|
|
uint32_t seed = 1;
|
2021-10-01 09:12:27 +00:00
|
|
|
|
for (i = 0; i < n; i++)
|
2021-10-08 04:04:42 +00:00
|
|
|
|
arr[i] = minstd_rand(&seed) % m;
|
2021-10-01 09:12:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void dist_stagger(int *arr, int n, int m)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
|
arr[i] = (i * m + i) % n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void dist_plateau(int *arr, int n, int m)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
|
arr[i] = (i < m) ? i : m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void dist_shuffle(int *arr, int n, int m)
|
|
|
|
|
{
|
|
|
|
|
int i, j, k;
|
2021-10-08 04:04:42 +00:00
|
|
|
|
uint32_t seed = 1;
|
2021-10-01 09:12:27 +00:00
|
|
|
|
for (i = j = 0, k = 1; i < n; i++)
|
2021-10-08 04:04:42 +00:00
|
|
|
|
arr[i] = minstd_rand(&seed) % m ? (j += 2) : (k += 2);
|
2021-10-01 09:12:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define DIST(name) { #name, dist_##name }
|
|
|
|
|
|
|
|
|
|
static struct dist {
|
|
|
|
|
const char *name;
|
|
|
|
|
void (*fn)(int *arr, int n, int m);
|
|
|
|
|
} dist[] = {
|
|
|
|
|
DIST(sawtooth),
|
|
|
|
|
DIST(rand),
|
|
|
|
|
DIST(stagger),
|
|
|
|
|
DIST(plateau),
|
|
|
|
|
DIST(shuffle),
|
|
|
|
|
};
|
|
|
|
|
|
2021-10-01 09:14:32 +00:00
|
|
|
|
static const struct dist *get_dist_by_name(const char *name)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dist); i++) {
|
|
|
|
|
if (!strcmp(dist[i].name, name))
|
|
|
|
|
return &dist[i];
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-01 09:12:27 +00:00
|
|
|
|
static void mode_copy(int *arr, int n)
|
|
|
|
|
{
|
|
|
|
|
/* nothing */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mode_reverse(int *arr, int n)
|
|
|
|
|
{
|
|
|
|
|
int i, j;
|
|
|
|
|
for (i = 0, j = n - 1; i < j; i++, j--)
|
|
|
|
|
SWAP(arr[i], arr[j]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mode_reverse_1st_half(int *arr, int n)
|
|
|
|
|
{
|
|
|
|
|
mode_reverse(arr, n / 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mode_reverse_2nd_half(int *arr, int n)
|
|
|
|
|
{
|
|
|
|
|
int half = n / 2;
|
|
|
|
|
mode_reverse(arr + half, n - half);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int compare_ints(const void *av, const void *bv)
|
|
|
|
|
{
|
|
|
|
|
const int *ap = av, *bp = bv;
|
|
|
|
|
int a = *ap, b = *bp;
|
|
|
|
|
return (a > b) - (a < b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mode_sort(int *arr, int n)
|
|
|
|
|
{
|
|
|
|
|
QSORT(arr, n, compare_ints);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mode_dither(int *arr, int n)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
|
arr[i] += i % 5;
|
|
|
|
|
}
|
|
|
|
|
|
test-mergesort: add unriffle mode
Add a mode that turns sorted items into adversarial input for mergesort.
Do that by running mergesort in reverse and rearranging the items in
such a way that each merge needs the maximum number of operations to
undo it.
To riffle is a card shuffling technique and involves splitting a deck
into two and then to interleave them. A perfect riffle takes one card
from each half in turn. That's similar to the most expensive merge,
which has to take one item from each sublist in turn, which requires the
maximum number of comparisons (n-1).
So unriffle does that in reverse, i.e. it generates the first sublist
out of the items at even indexes and the second sublist out of the items
at odd indexes, without changing their order in any other way. Done
recursively until we reach the trivial sublist length of one, this
twists the list into an order that requires the maximum effort for
mergesort to untangle.
As a baseline, here are the rand distributions with the highest number
of comparisons from "test-tool mergesort test":
$ t/helper/test-tool mergesort test | awk '
NR > 1 && $1 != "rand" {next}
$7 > max[$3] {max[$3] = $7; line[$3] = $0}
END {for (n in line) print line[n]}
'
distribut mode n m get_next set_next compare verdict
rand copy 100 32 1184 700 569 OK
rand reverse_1st_half 1023 256 16373 10230 8976 OK
rand reverse_1st_half 1024 512 16384 10240 8993 OK
rand dither 1025 64 18454 11275 9970 OK
And here are the most expensive ones overall:
$ t/helper/test-tool mergesort test | awk '
$7 > max[$3] {max[$3] = $7; line[$3] = $0}
END {for (n in line) print line[n]}
'
distribut mode n m get_next set_next compare verdict
stagger reverse 100 64 1184 700 580 OK
sawtooth unriffle 1023 1024 16373 10230 9179 OK
sawtooth unriffle 1024 1024 16384 10240 9217 OK
stagger unriffle 1025 2048 18454 11275 10241 OK
The sawtooth distribution with m>=n generates a sorted list. The
unriffle mode is designed to turn that into adversarial input for
mergesort, and that checks out for n=1023 and n=1024, where it produces
the list that requires the most comparisons.
Item counts that are not powers of two have other winners, and that's
because unriffle recursively splits lists into equal-sized halves, while
llist_mergesort() splits them into the biggest power of two smaller than
n and the rest, e.g. for n=1025 it sorts the first 1024 separately and
finally merges them to the last item.
So unriffle mode works as designed for the intended use case, but to
consistently generate adversarial input for unbalanced merges we need
something else.
Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-10-01 09:16:49 +00:00
|
|
|
|
static void unriffle(int *arr, int n, int *tmp)
|
|
|
|
|
{
|
|
|
|
|
int i, j;
|
|
|
|
|
COPY_ARRAY(tmp, arr, n);
|
|
|
|
|
for (i = j = 0; i < n; i += 2)
|
|
|
|
|
arr[j++] = tmp[i];
|
|
|
|
|
for (i = 1; i < n; i += 2)
|
|
|
|
|
arr[j++] = tmp[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void unriffle_recursively(int *arr, int n, int *tmp)
|
|
|
|
|
{
|
|
|
|
|
if (n > 1) {
|
|
|
|
|
int half = n / 2;
|
|
|
|
|
unriffle(arr, n, tmp);
|
|
|
|
|
unriffle_recursively(arr, half, tmp);
|
|
|
|
|
unriffle_recursively(arr + half, n - half, tmp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mode_unriffle(int *arr, int n)
|
|
|
|
|
{
|
|
|
|
|
int *tmp;
|
|
|
|
|
ALLOC_ARRAY(tmp, n);
|
|
|
|
|
unriffle_recursively(arr, n, tmp);
|
|
|
|
|
free(tmp);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-01 09:17:57 +00:00
|
|
|
|
static unsigned int prev_pow2(unsigned int n)
|
|
|
|
|
{
|
|
|
|
|
unsigned int pow2 = 1;
|
|
|
|
|
while (pow2 * 2 < n)
|
|
|
|
|
pow2 *= 2;
|
|
|
|
|
return pow2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void unriffle_recursively_skewed(int *arr, int n, int *tmp)
|
|
|
|
|
{
|
|
|
|
|
if (n > 1) {
|
|
|
|
|
int pow2 = prev_pow2(n);
|
|
|
|
|
int rest = n - pow2;
|
|
|
|
|
unriffle(arr + pow2 - rest, rest * 2, tmp);
|
|
|
|
|
unriffle_recursively_skewed(arr, pow2, tmp);
|
|
|
|
|
unriffle_recursively_skewed(arr + pow2, rest, tmp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mode_unriffle_skewed(int *arr, int n)
|
|
|
|
|
{
|
|
|
|
|
int *tmp;
|
|
|
|
|
ALLOC_ARRAY(tmp, n);
|
|
|
|
|
unriffle_recursively_skewed(arr, n, tmp);
|
|
|
|
|
free(tmp);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-01 09:12:27 +00:00
|
|
|
|
#define MODE(name) { #name, mode_##name }
|
|
|
|
|
|
|
|
|
|
static struct mode {
|
|
|
|
|
const char *name;
|
|
|
|
|
void (*fn)(int *arr, int n);
|
|
|
|
|
} mode[] = {
|
|
|
|
|
MODE(copy),
|
|
|
|
|
MODE(reverse),
|
|
|
|
|
MODE(reverse_1st_half),
|
|
|
|
|
MODE(reverse_2nd_half),
|
|
|
|
|
MODE(sort),
|
|
|
|
|
MODE(dither),
|
test-mergesort: add unriffle mode
Add a mode that turns sorted items into adversarial input for mergesort.
Do that by running mergesort in reverse and rearranging the items in
such a way that each merge needs the maximum number of operations to
undo it.
To riffle is a card shuffling technique and involves splitting a deck
into two and then to interleave them. A perfect riffle takes one card
from each half in turn. That's similar to the most expensive merge,
which has to take one item from each sublist in turn, which requires the
maximum number of comparisons (n-1).
So unriffle does that in reverse, i.e. it generates the first sublist
out of the items at even indexes and the second sublist out of the items
at odd indexes, without changing their order in any other way. Done
recursively until we reach the trivial sublist length of one, this
twists the list into an order that requires the maximum effort for
mergesort to untangle.
As a baseline, here are the rand distributions with the highest number
of comparisons from "test-tool mergesort test":
$ t/helper/test-tool mergesort test | awk '
NR > 1 && $1 != "rand" {next}
$7 > max[$3] {max[$3] = $7; line[$3] = $0}
END {for (n in line) print line[n]}
'
distribut mode n m get_next set_next compare verdict
rand copy 100 32 1184 700 569 OK
rand reverse_1st_half 1023 256 16373 10230 8976 OK
rand reverse_1st_half 1024 512 16384 10240 8993 OK
rand dither 1025 64 18454 11275 9970 OK
And here are the most expensive ones overall:
$ t/helper/test-tool mergesort test | awk '
$7 > max[$3] {max[$3] = $7; line[$3] = $0}
END {for (n in line) print line[n]}
'
distribut mode n m get_next set_next compare verdict
stagger reverse 100 64 1184 700 580 OK
sawtooth unriffle 1023 1024 16373 10230 9179 OK
sawtooth unriffle 1024 1024 16384 10240 9217 OK
stagger unriffle 1025 2048 18454 11275 10241 OK
The sawtooth distribution with m>=n generates a sorted list. The
unriffle mode is designed to turn that into adversarial input for
mergesort, and that checks out for n=1023 and n=1024, where it produces
the list that requires the most comparisons.
Item counts that are not powers of two have other winners, and that's
because unriffle recursively splits lists into equal-sized halves, while
llist_mergesort() splits them into the biggest power of two smaller than
n and the rest, e.g. for n=1025 it sorts the first 1024 separately and
finally merges them to the last item.
So unriffle mode works as designed for the intended use case, but to
consistently generate adversarial input for unbalanced merges we need
something else.
Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-10-01 09:16:49 +00:00
|
|
|
|
MODE(unriffle),
|
2021-10-01 09:17:57 +00:00
|
|
|
|
MODE(unriffle_skewed),
|
2021-10-01 09:12:27 +00:00
|
|
|
|
};
|
|
|
|
|
|
2021-10-01 09:14:32 +00:00
|
|
|
|
static const struct mode *get_mode_by_name(const char *name)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(mode); i++) {
|
|
|
|
|
if (!strcmp(mode[i].name, name))
|
|
|
|
|
return &mode[i];
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int generate(int argc, const char **argv)
|
|
|
|
|
{
|
|
|
|
|
const struct dist *dist = NULL;
|
|
|
|
|
const struct mode *mode = NULL;
|
|
|
|
|
int i, n, m, *arr;
|
|
|
|
|
|
|
|
|
|
if (argc != 4)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
dist = get_dist_by_name(argv[0]);
|
|
|
|
|
mode = get_mode_by_name(argv[1]);
|
|
|
|
|
n = strtol(argv[2], NULL, 10);
|
|
|
|
|
m = strtol(argv[3], NULL, 10);
|
|
|
|
|
if (!dist || !mode)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
ALLOC_ARRAY(arr, n);
|
|
|
|
|
dist->fn(arr, n, m);
|
|
|
|
|
mode->fn(arr, n);
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
|
printf("%08x\n", arr[i]);
|
|
|
|
|
free(arr);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-01 09:12:27 +00:00
|
|
|
|
static struct stats {
|
|
|
|
|
int get_next, set_next, compare;
|
|
|
|
|
} stats;
|
|
|
|
|
|
|
|
|
|
struct number {
|
|
|
|
|
int value, rank;
|
|
|
|
|
struct number *next;
|
|
|
|
|
};
|
|
|
|
|
|
2022-07-16 16:56:32 +00:00
|
|
|
|
DEFINE_LIST_SORT_DEBUG(static, sort_numbers, struct number, next,
|
|
|
|
|
stats.get_next++, stats.set_next++);
|
2021-10-01 09:12:27 +00:00
|
|
|
|
|
2022-07-16 16:56:32 +00:00
|
|
|
|
static int compare_numbers(const struct number *an, const struct number *bn)
|
2021-10-01 09:12:27 +00:00
|
|
|
|
{
|
|
|
|
|
int a = an->value, b = bn->value;
|
|
|
|
|
stats.compare++;
|
|
|
|
|
return (a > b) - (a < b);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void clear_numbers(struct number *list)
|
|
|
|
|
{
|
|
|
|
|
while (list) {
|
|
|
|
|
struct number *next = list->next;
|
|
|
|
|
free(list);
|
|
|
|
|
list = next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int test(const struct dist *dist, const struct mode *mode, int n, int m)
|
|
|
|
|
{
|
|
|
|
|
int *arr;
|
|
|
|
|
size_t i;
|
|
|
|
|
struct number *curr, *list, **tail;
|
|
|
|
|
int is_sorted = 1;
|
|
|
|
|
int is_stable = 1;
|
|
|
|
|
const char *verdict;
|
|
|
|
|
int result = -1;
|
|
|
|
|
|
|
|
|
|
ALLOC_ARRAY(arr, n);
|
|
|
|
|
dist->fn(arr, n, m);
|
|
|
|
|
mode->fn(arr, n);
|
|
|
|
|
for (i = 0, tail = &list; i < n; i++) {
|
|
|
|
|
curr = xmalloc(sizeof(*curr));
|
|
|
|
|
curr->value = arr[i];
|
|
|
|
|
curr->rank = i;
|
|
|
|
|
*tail = curr;
|
|
|
|
|
tail = &curr->next;
|
|
|
|
|
}
|
|
|
|
|
*tail = NULL;
|
|
|
|
|
|
|
|
|
|
stats.get_next = stats.set_next = stats.compare = 0;
|
2022-07-16 16:56:32 +00:00
|
|
|
|
sort_numbers(&list, compare_numbers);
|
2021-10-01 09:12:27 +00:00
|
|
|
|
|
|
|
|
|
QSORT(arr, n, compare_ints);
|
|
|
|
|
for (i = 0, curr = list; i < n && curr; i++, curr = curr->next) {
|
|
|
|
|
if (arr[i] != curr->value)
|
|
|
|
|
is_sorted = 0;
|
|
|
|
|
if (curr->next && curr->value == curr->next->value &&
|
|
|
|
|
curr->rank >= curr->next->rank)
|
|
|
|
|
is_stable = 0;
|
|
|
|
|
}
|
|
|
|
|
if (i < n) {
|
|
|
|
|
verdict = "too short";
|
|
|
|
|
} else if (curr) {
|
|
|
|
|
verdict = "too long";
|
|
|
|
|
} else if (!is_sorted) {
|
|
|
|
|
verdict = "not sorted";
|
|
|
|
|
} else if (!is_stable) {
|
|
|
|
|
verdict = "unstable";
|
|
|
|
|
} else {
|
|
|
|
|
verdict = "OK";
|
|
|
|
|
result = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
printf("%-9s %-16s %8d %8d %8d %8d %8d %s\n",
|
|
|
|
|
dist->name, mode->name, n, m, stats.get_next, stats.set_next,
|
|
|
|
|
stats.compare, verdict);
|
|
|
|
|
|
|
|
|
|
clear_numbers(list);
|
|
|
|
|
free(arr);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* A version of the qsort certification program from "Engineering a Sort
|
|
|
|
|
* Function" by Bentley and McIlroy, Software—Practice and Experience,
|
|
|
|
|
* Volume 23, Issue 11, 1249–1265 (November 1993).
|
|
|
|
|
*/
|
|
|
|
|
static int run_tests(int argc, const char **argv)
|
|
|
|
|
{
|
|
|
|
|
const char *argv_default[] = { "100", "1023", "1024", "1025" };
|
|
|
|
|
if (!argc)
|
|
|
|
|
return run_tests(ARRAY_SIZE(argv_default), argv_default);
|
|
|
|
|
printf("%-9s %-16s %8s %8s %8s %8s %8s %s\n",
|
|
|
|
|
"distribut", "mode", "n", "m", "get_next", "set_next",
|
|
|
|
|
"compare", "verdict");
|
|
|
|
|
while (argc--) {
|
|
|
|
|
int i, j, m, n = strtol(*argv++, NULL, 10);
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dist); i++) {
|
|
|
|
|
for (j = 0; j < ARRAY_SIZE(mode); j++) {
|
|
|
|
|
for (m = 1; m < 2 * n; m *= 2) {
|
|
|
|
|
if (test(&dist[i], &mode[j], n, m))
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-01 09:11:19 +00:00
|
|
|
|
int cmd__mergesort(int argc, const char **argv)
|
|
|
|
|
{
|
2021-10-01 09:14:32 +00:00
|
|
|
|
int i;
|
|
|
|
|
const char *sep;
|
|
|
|
|
|
|
|
|
|
if (argc == 6 && !strcmp(argv[1], "generate"))
|
|
|
|
|
return generate(argc - 2, argv + 2);
|
2021-10-01 09:11:19 +00:00
|
|
|
|
if (argc == 2 && !strcmp(argv[1], "sort"))
|
|
|
|
|
return sort_stdin();
|
2021-10-01 09:12:27 +00:00
|
|
|
|
if (argc > 1 && !strcmp(argv[1], "test"))
|
|
|
|
|
return run_tests(argc - 2, argv + 2);
|
2021-10-01 09:14:32 +00:00
|
|
|
|
fprintf(stderr, "usage: test-tool mergesort generate <distribution> <mode> <n> <m>\n");
|
|
|
|
|
fprintf(stderr, " or: test-tool mergesort sort\n");
|
2021-10-01 09:12:27 +00:00
|
|
|
|
fprintf(stderr, " or: test-tool mergesort test [<n>...]\n");
|
2021-10-01 09:14:32 +00:00
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
|
for (i = 0, sep = "distributions: "; i < ARRAY_SIZE(dist); i++, sep = ", ")
|
|
|
|
|
fprintf(stderr, "%s%s", sep, dist[i].name);
|
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
|
for (i = 0, sep = "modes: "; i < ARRAY_SIZE(mode); i++, sep = ", ")
|
|
|
|
|
fprintf(stderr, "%s%s", sep, mode[i].name);
|
|
|
|
|
fprintf(stderr, "\n");
|
2021-10-01 09:12:27 +00:00
|
|
|
|
return 129;
|
2021-10-01 09:11:19 +00:00
|
|
|
|
}
|