Limited "generics" in C without macros or UB June 5, 2017 on Drew DeVault's blog

I should start this post off by clarifying that what I have to show you today is not, in fact, generics. However, it’s useful in some situations to solve the same problems that generics might. This is a pattern I’ve started using to reduce the number of void* pointers floating around in my code: multiple definitions of a struct.

Errata: we rolled this approach back in wlroots because it causes problems with LTO. I no longer recommend it.

Let’s take a look at a specific example. In wlroots, wlr_output is a generic type that can be implemented by any number of backends, like DRM (direct rendering manager), wayland windows, X11 windows, RDP outputs, etc. The wlr/types.h header includes this structure:

struct wlr_output_impl;
struct wlr_output_state;

struct wlr_output {
    const struct wlr_output_impl *impl;
    struct wlr_output_state *state;
    // [...]
};

void wlr_output_enable(struct wlr_output *output, bool enable);
bool wlr_output_set_mode(struct wlr_output *output,
    struct wlr_output_mode *mode);
void wlr_output_destroy(struct wlr_output *output);

wlr_output_impl is defined elsewhere:

struct wlr_output_impl {
    void (*enable)(struct wlr_output_state *state, bool enable);
    bool (*set_mode)(struct wlr_output_state *state,
        struct wlr_output_mode *mode);
    void (*destroy)(struct wlr_output_state *state);
};

struct wlr_output *wlr_output_create(struct wlr_output_impl *impl,
        struct wlr_output_state *state);
void wlr_output_free(struct wlr_output *output);

Nowhere, however, is wlr_output_state defined. It’s left an incomplete type throughout all of the common wlr_output code. The “generic” part is that each output implementation, in its own private headers, defines the wlr_output_state struct for itself, like the DRM backend:

struct wlr_output_state {
    uint32_t connector;
    char name[16];
    uint32_t crtc;
    drmModeCrtc *old_crtc;
    struct wlr_drm_renderer *renderer;
    struct gbm_surface *gbm;
    EGLSurface *egl;
    bool pageflip_pending;
    enum wlr_drm_output_state state;
    // [...]
};

This allows implementations of the enable, set_mode, and destroy functions to avoid casting a void* to the appropriate type:

static struct wlr_output_impl output_impl = {
    .enable = wlr_drm_output_enable,
    // [...]
};

static void wlr_drm_output_enable(struct wlr_output_state *output,
        bool enable) {
    struct wlr_backend_state *state =
        wl_container_of(output->renderer, state, renderer);
    if (output->state != DRM_OUTPUT_CONNECTED) {
        return;
    }
    if (enable) {
        drmModeConnectorSetProperty(state->fd,
            output->connector,
            output->props.dpms,
            DRM_MODE_DPMS_ON);
        // [...]
    } else {
        drmModeConnectorSetProperty(state->fd,
            output->connector,
            output->props.dpms,
            DRM_MODE_DPMS_STANDBY);
    }
}

// [...]
struct wlr_output output = wlr_output_create(&output_impl, output);

The limitations of this approach are apparent: you cannot work with multiple definitions of wlr_output_state in the same file. However, you get improved type safety, have to write less code, and improve readability.

Have a comment on one of my posts? Start a discussion in my public inbox by sending an email to ~sircmpwn/public-inbox@lists.sr.ht [mailing list etiquette]

Articles from blogs I read Generated by openring

What's cooking on Sourcehut? September 2022

Guten Morgen, SourceHut! Today, I count 681 new users, for a grand total of 32281 registered users. As always, a warm welcome to them and the reminder to everyone else to help them feel welcome while they get settled. Today, I am filling in for Drew on short…

via Blogs on Sourcehut September 15, 2022

Status update, September 2022

Hi all! This month I’ve been working on stuff I’d usually not work on willingly. And by that I mean Rust and screen tearing of course. I’ve been randomly typing keys on my keyboard and before I knew it, a wlroots-rs repository was created. Everybody is saying…

via emersion September 15, 2022

Futurist prediction methods and accuracy

I've been reading a lot of predictions from people who are looking to understand what problems humanity will face 10-50 years out (and sometimes longer) in order to work in areas that will be instrumental for the future and wondering how accurate thes…

via danluu.com September 12, 2022