logoalt Hacker News

ueckeryesterday at 2:39 PM2 repliesview on HN

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.

Replies

listeriayesterday at 3:08 PM

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.

show 1 reply
ueckeryesterday at 2:42 PM

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