Am 01.10.2018 um 22:37 schrieb René Scharfe: > Am 01.10.2018 um 21:26 schrieb Derrick Stolee: >> On 10/1/2018 3:16 PM, René Scharfe wrote: >>> Am 28.06.2018 um 14:31 schrieb Derrick Stolee via GitGitGadget: >>>> diff --git a/commit-reach.c b/commit-reach.c >>>> index c58e50fbb..ac132c8e4 100644 >>>> --- a/commit-reach.c >>>> +++ b/commit-reach.c >>>> @@ -513,65 +513,88 @@ int commit_contains(struct ref_filter *filter, struct commit *commit, >>>> return is_descendant_of(commit, list); >>>> } >>>> >>>> -int reachable(struct commit *from, int with_flag, int assign_flag, >>>> - time_t min_commit_date) >>>> +static int compare_commits_by_gen(const void *_a, const void *_b) >>>> { >>>> - struct prio_queue work = { compare_commits_by_commit_date }; >>>> + const struct commit *a = (const struct commit *)_a; >>>> + const struct commit *b = (const struct commit *)_b; >>> This cast is bogus. QSORT gets handed a struct commit **, i.e. an array >>> of pointers, and qsort(1) passes references to those pointers to the >>> compare function, and not the pointer values. >> >> Good catch! I'm disappointed that we couldn't use type-checking here, as >> it is quite difficult to discover that the types are wrong here. > > Generics in C are hard, and type checking traditionally falls by the > wayside. You could use macros for that, like klib [*] does, but that > has its own downsides (more object text, debugging the sort macros > themselves is harder). > > [*] https://github.com/attractivechaos/klib/blob/master/ksort.h We could also do something like this to reduce the amount of manual casting, but do we want to? (Macro at the bottom, three semi-random examples at the top.) --- bisect.c | 11 +++-------- commit-graph.c | 9 ++------- commit-reach.c | 12 +++++------- git-compat-util.h | 12 ++++++++++++ 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/bisect.c b/bisect.c index e8b17cf7e1..06be3a3c15 100644 --- a/bisect.c +++ b/bisect.c @@ -192,16 +192,11 @@ struct commit_dist { int distance; }; -static int compare_commit_dist(const void *a_, const void *b_) -{ - struct commit_dist *a, *b; - - a = (struct commit_dist *)a_; - b = (struct commit_dist *)b_; +DEFINE_SORT(sort_by_commit_dist, struct commit_dist, a, b, { if (a->distance != b->distance) return b->distance - a->distance; /* desc sort */ return oidcmp(&a->commit->object.oid, &b->commit->object.oid); -} +}) static struct commit_list *best_bisection_sorted(struct commit_list *list, int nr) { @@ -223,7 +218,7 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n array[cnt].distance = distance; cnt++; } - QSORT(array, cnt, compare_commit_dist); + sort_by_commit_dist(array, cnt); for (p = list, i = 0; i < cnt; i++) { struct object *obj = &(array[i].commit->object); diff --git a/commit-graph.c b/commit-graph.c index 7f4519ec3b..a2202414e0 100644 --- a/commit-graph.c +++ b/commit-graph.c @@ -550,12 +550,7 @@ static void write_graph_chunk_large_edges(struct hashfile *f, } } -static int commit_compare(const void *_a, const void *_b) -{ - const struct object_id *a = (const struct object_id *)_a; - const struct object_id *b = (const struct object_id *)_b; - return oidcmp(a, b); -} +DEFINE_SORT(sort_oids, struct object_id, a, b, return oidcmp(a, b)) struct packed_commit_list { struct commit **list; @@ -780,7 +775,7 @@ void write_commit_graph(const char *obj_dir, close_reachable(&oids); - QSORT(oids.list, oids.nr, commit_compare); + sort_oids(oids.list, oids.nr); count_distinct = 1; for (i = 1; i < oids.nr; i++) { diff --git a/commit-reach.c b/commit-reach.c index 2f5e592d16..3aef47c3dd 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -527,17 +527,15 @@ int commit_contains(struct ref_filter *filter, struct commit *commit, return is_descendant_of(commit, list); } -static int compare_commits_by_gen(const void *_a, const void *_b) -{ - const struct commit *a = *(const struct commit * const *)_a; - const struct commit *b = *(const struct commit * const *)_b; - +DEFINE_SORT(sort_commits_by_gen, struct commit *, ap, bp, { + const struct commit *a = *ap; + const struct commit *b = *bp; if (a->generation < b->generation) return -1; if (a->generation > b->generation) return 1; return 0; -} +}) int can_all_from_reach_with_flag(struct object_array *from, unsigned int with_flag, @@ -580,7 +578,7 @@ int can_all_from_reach_with_flag(struct object_array *from, nr_commits++; } - QSORT(list, nr_commits, compare_commits_by_gen); + sort_commits_by_gen(list, nr_commits); for (i = 0; i < nr_commits; i++) { /* DFS from list[i] */ diff --git a/git-compat-util.h b/git-compat-util.h index 5f2e90932f..f9e78d69a2 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -1066,6 +1066,18 @@ static inline void sane_qsort(void *base, size_t nmemb, size_t size, qsort(base, nmemb, size, compar); } +#define DEFINE_SORT(name, elemtype, one, two, code) \ +static int name##_compare(const void *one##_v_, const void *two##_v_) \ +{ \ + elemtype const *one = one##_v_; \ + elemtype const *two = two##_v_; \ + code; \ +} \ +static void name(elemtype *array, size_t n) \ +{ \ + QSORT(array, n, name##_compare); \ +} + #ifndef HAVE_ISO_QSORT_S int git_qsort_s(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *, void *), void *ctx); -- 2.19.0