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

Reply via email to