From: Derrick Stolee Date: Mon, 15 Oct 2018 15:31:12 GMT Subject: Re: [PATCH 15/16] commit-reach: make can_all_from_reach... linear Message-ID: <0cd89b69-4b65-f961-a025-c74851f8c999@gmail.com> In-Reply-To: On 10/14/2018 10:29 AM, René Scharfe wrote: > It still has some repetition, converted code is a bit longer than the > current one, and I don't know how to build a Coccinelle rule that would > do that conversion. > > Looked for a possibility to at least leave QSORT call-sites alone by > enhancing that macro, but didn't find any. Found a few websites > showing off mindblowing macros, thouhg, this one in particular: > > https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms > > Anyway, drove the generative approach a bit further, and came up with > the new DEFINE_SORT below. I'm unsure about the name; perhaps it should > be called DEFINE_SORT_BY_COMPARE_FUNCTION_BODY, but that's a bit long. > It handles casts and const attributes behind the scenes and avoids > repetition, but looks a bit weird, as it is placed where a function > signature would go. > > Apart from that the macro is simple and doesn't use any tricks or > added checks. It just sets up boilerplate functions to offer type-safe > sorting. > > diffcore-rename.c and refs/packed-backend.c receive special treatment in > the patch because their compare functions are used outside of sorting as > well. I made them take typed pointers nevertheless and used them from > DEFINE_SORT; the wrapper generated by that macro is supposed to be > private. Given that such reuse is rare and I think we don't need a way > to make it public. > > What do y'all think about this direction? > > --- [snip] > diff --git a/git-compat-util.h b/git-compat-util.h > index 5f2e90932f..491230fc57 100644 > --- a/git-compat-util.h > +++ b/git-compat-util.h > @@ -1066,6 +1066,21 @@ static inline void sane_qsort(void *base, size_t nmemb, size_t size, > qsort(base, nmemb, size, compar); > } > > +#define DECLARE_SORT(scope, name, elemtype) \ > +scope void name(elemtype, size_t) > + > +#define DEFINE_SORT(scope, name, elemtype, one, two) \ > +static int name##_compare(const elemtype, const elemtype); \ > +static int name##_compare_void(const void *a, const void *b) \ > +{ \ > + return name##_compare(a, b); \ > +} \ > +scope void name(elemtype base, size_t nmemb) \ > +{ \ > + QSORT(base, nmemb, name##_compare_void); \ > +} \ > +static int name##_compare(const elemtype one, const elemtype two) > + Since you were worried about the "private" name of the compare function, maybe split this macro into two: DEFINE_COMPARE and DEFINE_SORT. Then, if someone wants direct access to the compare function, they could use the DEFINE_COMPARE to ensure the typing is correct, and use QSORT as normal with name##_compare_void. As I think about this, I think this is less of a problem than is worth this split. The commit-slab definitions generate a lot of methods using the "name##" convention, so perhaps we should just trust developers using the macros to look up the macro definition or similar examples. In that sense, including a conversion that consumes the compare function directly can be a signpost for future callers. I would say that maybe the times where you need to do something special should be pulled out into their own patches, so we can call attention to them directly. [snip] > diff --git a/midx.c b/midx.c > index 713d6f9dde..4407db7949 100644 > --- a/midx.c > +++ b/midx.c > @@ -419,10 +419,8 @@ struct pack_pair { > char *pack_name; > }; > > -static int pack_pair_compare(const void *_a, const void *_b) > +DEFINE_SORT(static, sort_by_pack_name, struct pack_pair *, a, b) > { > - struct pack_pair *a = (struct pack_pair *)_a; > - struct pack_pair *b = (struct pack_pair *)_b; > return strcmp(a->pack_name, b->pack_name); > } > > @@ -438,7 +436,7 @@ static void sort_packs_by_name(char **pack_names, uint32_t nr_packs, uint32_t *p > pairs[i].pack_name = pack_names[i]; > } > > - QSORT(pairs, nr_packs, pack_pair_compare); > + sort_by_pack_name(pairs, nr_packs); I like this "sort_by_" convention.. > > for (i = 0; i < nr_packs; i++) { > pack_names[i] = pairs[i].pack_name; > @@ -455,10 +453,8 @@ struct pack_midx_entry { > uint64_t offset; > }; > > -static int midx_oid_compare(const void *_a, const void *_b) > +DEFINE_SORT(static, sort_midx, struct pack_midx_entry *, a, b) > { > - const struct pack_midx_entry *a = (const struct pack_midx_entry *)_a; > - const struct pack_midx_entry *b = (const struct pack_midx_entry *)_b; > int cmp = oidcmp(&a->oid, &b->oid); > > if (cmp) > @@ -573,7 +569,7 @@ static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m, > } > } > > - QSORT(entries_by_fanout, nr_fanout, midx_oid_compare); > + sort_midx(entries_by_fanout, nr_fanout); ...but it isn't followed here. Perhaps "sort_by_oid"? Thanks, -Stolee