Hi! On Mon, 22 Jul 2019, Richard Biener wrote:
> I've noticed that we have quite some instances using qsort > and passing down state to the comparator via a global var. > Now that we have our own qsort implementation I wonder what > the best course of action is to add a variant passing down > such state to the comparator? Copying nearly the whole > implementation would be possible but also some marshalling > of three-argument comparator calls to two-argument functions > (and some ABIs can do without actual marshalling). The > other option is templating everything (ugh). I think there are three choices. 1. Have gcc/sort.cc implement only qsort_r, use a "universal comparator adapter" int cmp2to3(void *a, void *b, void *ctx) { return (int (*)(void *, void *))ctx(a, b); } to adapt existing qsort uses. 2. Have gcc/sort.cc implement both qsort and qsort_r by duplicating code, either copying manually (ugh) or by turning netsort, mergesort, qsort_chk to templates. 3. Have gcc/sort.cc implement only qsort_r, but have existing qsort callers pass their comparators to a fancy C++ "universal comparator adapter" so they can be inlined into the three-argument wrapper and thus speed/size penalties are tiny (only from always loading the context pointer that is ignored by legacy two-argument comparators): void qsort_r(void *, size_t, size_t, int cmp(void *, void *, void *)); template<int cmp(void *, void *)> int cmp2to3(void *a, void *b, void *c) { return cmp(a, b); } #define qsort(base, sz, n, cmp) \ qsort_r(base, sz, n, cmp2to3<cmp>) static int my_cmp(void *a, void *b) { return 0; } void test(void *base, size_t sz, size_t n) { qsort(base, sz, n, my_cmp); } Alexander