mirror of
https://github.com/git/git.git
synced 2024-05-09 09:06:57 +02:00
Merge branch 'rs/mergesort'
Make our mergesort implementation type-safe. * rs/mergesort: mergesort: remove llist_mergesort() packfile: use DEFINE_LIST_SORT fetch-pack: use DEFINE_LIST_SORT commit: use DEFINE_LIST_SORT blame: use DEFINE_LIST_SORT test-mergesort: use DEFINE_LIST_SORT test-mergesort: use DEFINE_LIST_SORT_DEBUG mergesort: add macros for typed sort of linked lists mergesort: tighten merge loop mergesort: unify ranks loops
This commit is contained in:
commit
4e0d160bbc
1
Makefile
1
Makefile
|
@ -992,7 +992,6 @@ LIB_OBJS += merge-ort.o
|
||||||
LIB_OBJS += merge-ort-wrappers.o
|
LIB_OBJS += merge-ort-wrappers.o
|
||||||
LIB_OBJS += merge-recursive.o
|
LIB_OBJS += merge-recursive.o
|
||||||
LIB_OBJS += merge.o
|
LIB_OBJS += merge.o
|
||||||
LIB_OBJS += mergesort.o
|
|
||||||
LIB_OBJS += midx.o
|
LIB_OBJS += midx.o
|
||||||
LIB_OBJS += name-hash.o
|
LIB_OBJS += name-hash.o
|
||||||
LIB_OBJS += negotiator/default.o
|
LIB_OBJS += negotiator/default.o
|
||||||
|
|
30
blame.c
30
blame.c
|
@ -1098,30 +1098,22 @@ static struct blame_entry *blame_merge(struct blame_entry *list1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *get_next_blame(const void *p)
|
DEFINE_LIST_SORT(static, sort_blame_entries, struct blame_entry, next);
|
||||||
{
|
|
||||||
return ((struct blame_entry *)p)->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_next_blame(void *p1, void *p2)
|
|
||||||
{
|
|
||||||
((struct blame_entry *)p1)->next = p2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Final image line numbers are all different, so we don't need a
|
* Final image line numbers are all different, so we don't need a
|
||||||
* three-way comparison here.
|
* three-way comparison here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int compare_blame_final(const void *p1, const void *p2)
|
static int compare_blame_final(const struct blame_entry *e1,
|
||||||
|
const struct blame_entry *e2)
|
||||||
{
|
{
|
||||||
return ((struct blame_entry *)p1)->lno > ((struct blame_entry *)p2)->lno
|
return e1->lno > e2->lno ? 1 : -1;
|
||||||
? 1 : -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compare_blame_suspect(const void *p1, const void *p2)
|
static int compare_blame_suspect(const struct blame_entry *s1,
|
||||||
|
const struct blame_entry *s2)
|
||||||
{
|
{
|
||||||
const struct blame_entry *s1 = p1, *s2 = p2;
|
|
||||||
/*
|
/*
|
||||||
* to allow for collating suspects, we sort according to the
|
* to allow for collating suspects, we sort according to the
|
||||||
* respective pointer value as the primary sorting criterion.
|
* respective pointer value as the primary sorting criterion.
|
||||||
|
@ -1138,8 +1130,7 @@ static int compare_blame_suspect(const void *p1, const void *p2)
|
||||||
|
|
||||||
void blame_sort_final(struct blame_scoreboard *sb)
|
void blame_sort_final(struct blame_scoreboard *sb)
|
||||||
{
|
{
|
||||||
sb->ent = llist_mergesort(sb->ent, get_next_blame, set_next_blame,
|
sort_blame_entries(&sb->ent, compare_blame_final);
|
||||||
compare_blame_final);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compare_commits_by_reverse_commit_date(const void *a,
|
static int compare_commits_by_reverse_commit_date(const void *a,
|
||||||
|
@ -1964,9 +1955,7 @@ static void pass_blame_to_parent(struct blame_scoreboard *sb,
|
||||||
parent, target, 0);
|
parent, target, 0);
|
||||||
*d.dstq = NULL;
|
*d.dstq = NULL;
|
||||||
if (ignore_diffs)
|
if (ignore_diffs)
|
||||||
newdest = llist_mergesort(newdest, get_next_blame,
|
sort_blame_entries(&newdest, compare_blame_suspect);
|
||||||
set_next_blame,
|
|
||||||
compare_blame_suspect);
|
|
||||||
queue_blames(sb, parent, newdest);
|
queue_blames(sb, parent, newdest);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -2383,8 +2372,7 @@ static int num_scapegoats(struct rev_info *revs, struct commit *commit, int reve
|
||||||
*/
|
*/
|
||||||
static void distribute_blame(struct blame_scoreboard *sb, struct blame_entry *blamed)
|
static void distribute_blame(struct blame_scoreboard *sb, struct blame_entry *blamed)
|
||||||
{
|
{
|
||||||
blamed = llist_mergesort(blamed, get_next_blame, set_next_blame,
|
sort_blame_entries(&blamed, compare_blame_suspect);
|
||||||
compare_blame_suspect);
|
|
||||||
while (blamed)
|
while (blamed)
|
||||||
{
|
{
|
||||||
struct blame_origin *porigin = blamed->suspect;
|
struct blame_origin *porigin = blamed->suspect;
|
||||||
|
|
20
commit.c
20
commit.c
|
@ -642,10 +642,11 @@ struct commit_list * commit_list_insert_by_date(struct commit *item, struct comm
|
||||||
return commit_list_insert(item, pp);
|
return commit_list_insert(item, pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int commit_list_compare_by_date(const void *a, const void *b)
|
static int commit_list_compare_by_date(const struct commit_list *a,
|
||||||
|
const struct commit_list *b)
|
||||||
{
|
{
|
||||||
timestamp_t a_date = ((const struct commit_list *)a)->item->date;
|
timestamp_t a_date = a->item->date;
|
||||||
timestamp_t b_date = ((const struct commit_list *)b)->item->date;
|
timestamp_t b_date = b->item->date;
|
||||||
if (a_date < b_date)
|
if (a_date < b_date)
|
||||||
return 1;
|
return 1;
|
||||||
if (a_date > b_date)
|
if (a_date > b_date)
|
||||||
|
@ -653,20 +654,11 @@ static int commit_list_compare_by_date(const void *a, const void *b)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *commit_list_get_next(const void *a)
|
DEFINE_LIST_SORT(static, commit_list_sort, struct commit_list, next);
|
||||||
{
|
|
||||||
return ((const struct commit_list *)a)->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void commit_list_set_next(void *a, void *next)
|
|
||||||
{
|
|
||||||
((struct commit_list *)a)->next = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
void commit_list_sort_by_date(struct commit_list **list)
|
void commit_list_sort_by_date(struct commit_list **list)
|
||||||
{
|
{
|
||||||
*list = llist_mergesort(*list, commit_list_get_next, commit_list_set_next,
|
commit_list_sort(list, commit_list_compare_by_date);
|
||||||
commit_list_compare_by_date);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct commit *pop_most_recent_commit(struct commit_list **list,
|
struct commit *pop_most_recent_commit(struct commit_list **list,
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "commit-reach.h"
|
#include "commit-reach.h"
|
||||||
#include "commit-graph.h"
|
#include "commit-graph.h"
|
||||||
#include "sigchain.h"
|
#include "sigchain.h"
|
||||||
|
#include "mergesort.h"
|
||||||
|
|
||||||
static int transfer_unpack_limit = -1;
|
static int transfer_unpack_limit = -1;
|
||||||
static int fetch_unpack_limit = -1;
|
static int fetch_unpack_limit = -1;
|
||||||
|
@ -1025,6 +1026,13 @@ static int get_pack(struct fetch_pack_args *args,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ref_compare_name(const struct ref *a, const struct ref *b)
|
||||||
|
{
|
||||||
|
return strcmp(a->name, b->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_LIST_SORT(static, sort_ref_list, struct ref, next);
|
||||||
|
|
||||||
static int cmp_ref_by_name(const void *a_, const void *b_)
|
static int cmp_ref_by_name(const void *a_, const void *b_)
|
||||||
{
|
{
|
||||||
const struct ref *a = *((const struct ref **)a_);
|
const struct ref *a = *((const struct ref **)a_);
|
||||||
|
|
84
mergesort.c
84
mergesort.c
|
@ -1,84 +0,0 @@
|
||||||
#include "cache.h"
|
|
||||||
#include "mergesort.h"
|
|
||||||
|
|
||||||
/* Combine two sorted lists. Take from `list` on equality. */
|
|
||||||
static void *llist_merge(void *list, void *other,
|
|
||||||
void *(*get_next_fn)(const void *),
|
|
||||||
void (*set_next_fn)(void *, void *),
|
|
||||||
int (*compare_fn)(const void *, const void *))
|
|
||||||
{
|
|
||||||
void *result = list, *tail;
|
|
||||||
|
|
||||||
if (compare_fn(list, other) > 0) {
|
|
||||||
result = other;
|
|
||||||
goto other;
|
|
||||||
}
|
|
||||||
for (;;) {
|
|
||||||
do {
|
|
||||||
tail = list;
|
|
||||||
list = get_next_fn(list);
|
|
||||||
if (!list) {
|
|
||||||
set_next_fn(tail, other);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} while (compare_fn(list, other) <= 0);
|
|
||||||
set_next_fn(tail, other);
|
|
||||||
other:
|
|
||||||
do {
|
|
||||||
tail = other;
|
|
||||||
other = get_next_fn(other);
|
|
||||||
if (!other) {
|
|
||||||
set_next_fn(tail, list);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} while (compare_fn(list, other) > 0);
|
|
||||||
set_next_fn(tail, list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Perform an iterative mergesort using an array of sublists.
|
|
||||||
*
|
|
||||||
* n is the number of items.
|
|
||||||
* ranks[i] is undefined if n & 2^i == 0, and assumed empty.
|
|
||||||
* ranks[i] contains a sublist of length 2^i otherwise.
|
|
||||||
*
|
|
||||||
* The number of bits in a void pointer limits the number of objects
|
|
||||||
* that can be created, and thus the number of array elements necessary
|
|
||||||
* to be able to sort any valid list.
|
|
||||||
*
|
|
||||||
* Adding an item to this array is like incrementing a binary number;
|
|
||||||
* positional values for set bits correspond to sublist lengths.
|
|
||||||
*/
|
|
||||||
void *llist_mergesort(void *list,
|
|
||||||
void *(*get_next_fn)(const void *),
|
|
||||||
void (*set_next_fn)(void *, void *),
|
|
||||||
int (*compare_fn)(const void *, const void *))
|
|
||||||
{
|
|
||||||
void *ranks[bitsizeof(void *)];
|
|
||||||
size_t n = 0;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
while (list) {
|
|
||||||
void *next = get_next_fn(list);
|
|
||||||
if (next)
|
|
||||||
set_next_fn(list, NULL);
|
|
||||||
for (i = 0; n & ((size_t)1 << i); i++)
|
|
||||||
list = llist_merge(ranks[i], list, get_next_fn,
|
|
||||||
set_next_fn, compare_fn);
|
|
||||||
n++;
|
|
||||||
ranks[i] = list;
|
|
||||||
list = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; n; i++, n >>= 1) {
|
|
||||||
if (!(n & 1))
|
|
||||||
continue;
|
|
||||||
if (list)
|
|
||||||
list = llist_merge(ranks[i], list, get_next_fn,
|
|
||||||
set_next_fn, compare_fn);
|
|
||||||
else
|
|
||||||
list = ranks[i];
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
108
mergesort.h
108
mergesort.h
|
@ -1,17 +1,105 @@
|
||||||
#ifndef MERGESORT_H
|
#ifndef MERGESORT_H
|
||||||
#define MERGESORT_H
|
#define MERGESORT_H
|
||||||
|
|
||||||
|
/* Combine two sorted lists. Take from `list` on equality. */
|
||||||
|
#define DEFINE_LIST_MERGE_INTERNAL(name, type) \
|
||||||
|
static type *name##__merge(type *list, type *other, \
|
||||||
|
int (*compare_fn)(const type *, const type *))\
|
||||||
|
{ \
|
||||||
|
type *result = list, *tail; \
|
||||||
|
int prefer_list = compare_fn(list, other) <= 0; \
|
||||||
|
\
|
||||||
|
if (!prefer_list) { \
|
||||||
|
result = other; \
|
||||||
|
SWAP(list, other); \
|
||||||
|
} \
|
||||||
|
for (;;) { \
|
||||||
|
do { \
|
||||||
|
tail = list; \
|
||||||
|
list = name##__get_next(list); \
|
||||||
|
if (!list) { \
|
||||||
|
name##__set_next(tail, other); \
|
||||||
|
return result; \
|
||||||
|
} \
|
||||||
|
} while (compare_fn(list, other) < prefer_list); \
|
||||||
|
name##__set_next(tail, other); \
|
||||||
|
prefer_list ^= 1; \
|
||||||
|
SWAP(list, other); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sort linked list in place.
|
* Perform an iterative mergesort using an array of sublists.
|
||||||
* - get_next_fn() returns the next element given an element of a linked list.
|
*
|
||||||
* - set_next_fn() takes two elements A and B, and makes B the "next" element
|
* n is the number of items.
|
||||||
* of A on the list.
|
* ranks[i] is undefined if n & 2^i == 0, and assumed empty.
|
||||||
* - compare_fn() takes two elements A and B, and returns negative, 0, positive
|
* ranks[i] contains a sublist of length 2^i otherwise.
|
||||||
* as the same sign as "subtracting" B from A.
|
*
|
||||||
|
* The number of bits in a void pointer limits the number of objects
|
||||||
|
* that can be created, and thus the number of array elements necessary
|
||||||
|
* to be able to sort any valid list.
|
||||||
|
*
|
||||||
|
* Adding an item to this array is like incrementing a binary number;
|
||||||
|
* positional values for set bits correspond to sublist lengths.
|
||||||
*/
|
*/
|
||||||
void *llist_mergesort(void *list,
|
#define DEFINE_LIST_SORT_INTERNAL(scope, name, type) \
|
||||||
void *(*get_next_fn)(const void *),
|
scope void name(type **listp, \
|
||||||
void (*set_next_fn)(void *, void *),
|
int (*compare_fn)(const type *, const type *)) \
|
||||||
int (*compare_fn)(const void *, const void *));
|
{ \
|
||||||
|
type *list = *listp; \
|
||||||
|
type *ranks[bitsizeof(type *)]; \
|
||||||
|
size_t n = 0; \
|
||||||
|
\
|
||||||
|
if (!list) \
|
||||||
|
return; \
|
||||||
|
\
|
||||||
|
for (;;) { \
|
||||||
|
int i; \
|
||||||
|
size_t m; \
|
||||||
|
type *next = name##__get_next(list); \
|
||||||
|
if (next) \
|
||||||
|
name##__set_next(list, NULL); \
|
||||||
|
for (i = 0, m = n;; i++, m >>= 1) { \
|
||||||
|
if (m & 1) { \
|
||||||
|
list = name##__merge(ranks[i], list, \
|
||||||
|
compare_fn); \
|
||||||
|
} else if (next) { \
|
||||||
|
break; \
|
||||||
|
} else if (!m) { \
|
||||||
|
*listp = list; \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
n++; \
|
||||||
|
ranks[i] = list; \
|
||||||
|
list = next; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DECLARE_LIST_SORT(scope, name, type) \
|
||||||
|
scope void name(type **listp, \
|
||||||
|
int (*compare_fn)(const type *, const type *))
|
||||||
|
|
||||||
|
#define DEFINE_LIST_SORT_DEBUG(scope, name, type, next_member, \
|
||||||
|
on_get_next, on_set_next) \
|
||||||
|
\
|
||||||
|
static inline type *name##__get_next(const type *elem) \
|
||||||
|
{ \
|
||||||
|
on_get_next; \
|
||||||
|
return elem->next_member; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline void name##__set_next(type *elem, type *next) \
|
||||||
|
{ \
|
||||||
|
on_set_next; \
|
||||||
|
elem->next_member = next; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
DEFINE_LIST_MERGE_INTERNAL(name, type) \
|
||||||
|
DEFINE_LIST_SORT_INTERNAL(scope, name, type) \
|
||||||
|
DECLARE_LIST_SORT(scope, name, type)
|
||||||
|
|
||||||
|
#define DEFINE_LIST_SORT(scope, name, type, next_member) \
|
||||||
|
DEFINE_LIST_SORT_DEBUG(scope, name, type, next_member, (void)0, (void)0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
18
packfile.c
18
packfile.c
|
@ -941,20 +941,10 @@ unsigned long repo_approximate_object_count(struct repository *r)
|
||||||
return r->objects->approximate_object_count;
|
return r->objects->approximate_object_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *get_next_packed_git(const void *p)
|
DEFINE_LIST_SORT(static, sort_packs, struct packed_git, next);
|
||||||
{
|
|
||||||
return ((const struct packed_git *)p)->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_next_packed_git(void *p, void *next)
|
static int sort_pack(const struct packed_git *a, const struct packed_git *b)
|
||||||
{
|
{
|
||||||
((struct packed_git *)p)->next = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sort_pack(const void *a_, const void *b_)
|
|
||||||
{
|
|
||||||
const struct packed_git *a = a_;
|
|
||||||
const struct packed_git *b = b_;
|
|
||||||
int st;
|
int st;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -981,9 +971,7 @@ static int sort_pack(const void *a_, const void *b_)
|
||||||
|
|
||||||
static void rearrange_packed_git(struct repository *r)
|
static void rearrange_packed_git(struct repository *r)
|
||||||
{
|
{
|
||||||
r->objects->packed_git = llist_mergesort(
|
sort_packs(&r->objects->packed_git, sort_pack);
|
||||||
r->objects->packed_git, get_next_packed_git,
|
|
||||||
set_next_packed_git, sort_pack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prepare_packed_git_mru(struct repository *r)
|
static void prepare_packed_git_mru(struct repository *r)
|
||||||
|
|
22
remote.c
22
remote.c
|
@ -11,7 +11,6 @@
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
#include "string-list.h"
|
#include "string-list.h"
|
||||||
#include "mergesort.h"
|
|
||||||
#include "strvec.h"
|
#include "strvec.h"
|
||||||
#include "commit-reach.h"
|
#include "commit-reach.h"
|
||||||
#include "advice.h"
|
#include "advice.h"
|
||||||
|
@ -1082,27 +1081,6 @@ void free_refs(struct ref *ref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ref_compare_name(const void *va, const void *vb)
|
|
||||||
{
|
|
||||||
const struct ref *a = va, *b = vb;
|
|
||||||
return strcmp(a->name, b->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *ref_list_get_next(const void *a)
|
|
||||||
{
|
|
||||||
return ((const struct ref *)a)->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ref_list_set_next(void *a, void *next)
|
|
||||||
{
|
|
||||||
((struct ref *)a)->next = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
void sort_ref_list(struct ref **l, int (*cmp)(const void *, const void *))
|
|
||||||
{
|
|
||||||
*l = llist_mergesort(*l, ref_list_get_next, ref_list_set_next, cmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
int count_refspec_match(const char *pattern,
|
int count_refspec_match(const char *pattern,
|
||||||
struct ref *refs,
|
struct ref *refs,
|
||||||
struct ref **matched_ref)
|
struct ref **matched_ref)
|
||||||
|
|
2
remote.h
2
remote.h
|
@ -207,9 +207,7 @@ struct ref *find_ref_by_name(const struct ref *list, const char *name);
|
||||||
struct ref *alloc_ref(const char *name);
|
struct ref *alloc_ref(const char *name);
|
||||||
struct ref *copy_ref(const struct ref *ref);
|
struct ref *copy_ref(const struct ref *ref);
|
||||||
struct ref *copy_ref_list(const struct ref *ref);
|
struct ref *copy_ref_list(const struct ref *ref);
|
||||||
void sort_ref_list(struct ref **, int (*cmp)(const void *, const void *));
|
|
||||||
int count_refspec_match(const char *, struct ref *refs, struct ref **matched_ref);
|
int count_refspec_match(const char *, struct ref *refs, struct ref **matched_ref);
|
||||||
int ref_compare_name(const void *, const void *);
|
|
||||||
|
|
||||||
int check_ref_type(const struct ref *ref, int flags);
|
int check_ref_type(const struct ref *ref, int flags);
|
||||||
|
|
||||||
|
|
|
@ -13,19 +13,10 @@ struct line {
|
||||||
struct line *next;
|
struct line *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void *get_next(const void *a)
|
DEFINE_LIST_SORT(static, sort_lines, struct line, next);
|
||||||
{
|
|
||||||
return ((const struct line *)a)->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_next(void *a, void *b)
|
static int compare_strings(const struct line *x, const struct line *y)
|
||||||
{
|
{
|
||||||
((struct line *)a)->next = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_strings(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
const struct line *x = a, *y = b;
|
|
||||||
return strcmp(x->text, y->text);
|
return strcmp(x->text, y->text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +38,7 @@ static int sort_stdin(void)
|
||||||
p = line;
|
p = line;
|
||||||
}
|
}
|
||||||
|
|
||||||
lines = llist_mergesort(lines, get_next, set_next, compare_strings);
|
sort_lines(&lines, compare_strings);
|
||||||
|
|
||||||
while (lines) {
|
while (lines) {
|
||||||
puts(lines->text);
|
puts(lines->text);
|
||||||
|
@ -273,21 +264,11 @@ struct number {
|
||||||
struct number *next;
|
struct number *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void *get_next_number(const void *a)
|
DEFINE_LIST_SORT_DEBUG(static, sort_numbers, struct number, next,
|
||||||
{
|
stats.get_next++, stats.set_next++);
|
||||||
stats.get_next++;
|
|
||||||
return ((const struct number *)a)->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_next_number(void *a, void *b)
|
static int compare_numbers(const struct number *an, const struct number *bn)
|
||||||
{
|
{
|
||||||
stats.set_next++;
|
|
||||||
((struct number *)a)->next = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int compare_numbers(const void *av, const void *bv)
|
|
||||||
{
|
|
||||||
const struct number *an = av, *bn = bv;
|
|
||||||
int a = an->value, b = bn->value;
|
int a = an->value, b = bn->value;
|
||||||
stats.compare++;
|
stats.compare++;
|
||||||
return (a > b) - (a < b);
|
return (a > b) - (a < b);
|
||||||
|
@ -325,8 +306,7 @@ static int test(const struct dist *dist, const struct mode *mode, int n, int m)
|
||||||
*tail = NULL;
|
*tail = NULL;
|
||||||
|
|
||||||
stats.get_next = stats.set_next = stats.compare = 0;
|
stats.get_next = stats.set_next = stats.compare = 0;
|
||||||
list = llist_mergesort(list, get_next_number, set_next_number,
|
sort_numbers(&list, compare_numbers);
|
||||||
compare_numbers);
|
|
||||||
|
|
||||||
QSORT(arr, n, compare_ints);
|
QSORT(arr, n, compare_ints);
|
||||||
for (i = 0, curr = list; i < n && curr; i++, curr = curr->next) {
|
for (i = 0, curr = list; i < n && curr; i++, curr = curr->next) {
|
||||||
|
|
|
@ -40,11 +40,11 @@ done
|
||||||
|
|
||||||
for file in unsorted sorted reversed
|
for file in unsorted sorted reversed
|
||||||
do
|
do
|
||||||
test_perf "llist_mergesort() $file" "
|
test_perf "DEFINE_LIST_SORT $file" "
|
||||||
test-tool mergesort sort <$file >actual
|
test-tool mergesort sort <$file >actual
|
||||||
"
|
"
|
||||||
|
|
||||||
test_expect_success "llist_mergesort() $file sorts like sort(1)" "
|
test_expect_success "DEFINE_LIST_SORT $file sorts like sort(1)" "
|
||||||
test_cmp_bin sorted actual
|
test_cmp_bin sorted actual
|
||||||
"
|
"
|
||||||
done
|
done
|
||||||
|
|
|
@ -5,7 +5,7 @@ test_description='verify sort functions'
|
||||||
TEST_PASSES_SANITIZE_LEAK=true
|
TEST_PASSES_SANITIZE_LEAK=true
|
||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
|
|
||||||
test_expect_success 'llist_mergesort()' '
|
test_expect_success 'DEFINE_LIST_SORT_DEBUG' '
|
||||||
test-tool mergesort test
|
test-tool mergesort test
|
||||||
'
|
'
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue