This is a good example. Without trampolines, this could look like this (Godbolt: https://godbolt.org/z/nK5fqMxjs).
int main() {
struct Point {
int x, y;
} points[3] = {
{ 3, 1 },
{ 2, 2 },
{ 5, 7 }
};
struct Point target = { 4, 5 };
long dsq(const struct Point *p) {
long dx = p->x - target.x, dy = p->y - target.y;
return dx*dx + dy*dy;
}
typedef typeof(dsq) dsq_f;
int compare(const void *p, const void *q, void *data) {
wide(dsq_f) *dsq = data;
long a = CALL(*dsq, (p)), b = CALL(*dsq, (q));
return (a > b) - (a < b);
}
qsort_r(points, 3, sizeof(struct Point), compare, &CLOSURE(dsq_f, dsq));
for (int i = 0; i < 3; ++i)
printf("%d,%d\n", points[i].x, points[i].y);
}
There are slightly different ways how to define the helper macros, I am still experimenting a bit. Here you could avoid the typedef if defined differently. But ideally, there would be native language support that avoids these macros.Or without qsort_r, you could use a thread local variable:
typedef typeof(dsq) dsq_f;
_Thread_local static wide(dsq_f) wdsq;
wdsq = CLOSURE(dsq_f, dsq);
https://godbolt.org/z/3e157c6b1
Well, if you're already using qsort_r, what's the point of using nested functions, if you can have a context pointer with the target?
And if you're not using qsort_r, but reaching for _Thread_local, the target can be _Thread_local instead of dsq.