lundi 25 janvier 2016

Describing pixel format information in C++ in a way that is usable at both compile-time and runtime

I have a library that does operations on pixels. The pixels can by in many different formats. I am looking for an effective way to describe the formats in the library API (internally and externally).

For some classes the pixel format is a template argument, for others it is a runtime argument. So the pixel formats need to be usable both runtime (as constructor or function argument) and compile time (as template argument). I want to describe the pixel formats only once.

What I have now is something like this:

enum class color_space : uint8_t { rgb, cmyk /* , etc... */ };

struct pixel_layout {
    color_space space;
    uint8_t channels;
    /* etc... */
}

template <color_space ColorSpace, uint8_t Channels /* etc.. */>
struct pixel_type {
    static constexpr color_space space = ColorSpace;
    static constexpr uint8_t channels = Channels;
    /* etc... */

    static constexpr layout layout() {
        return {space, channels /* , etc... */ };
    }
}

struct rgb  : public pixel_type<color_space::rgb, 3 /* , etc... */ > {};
struct rgba : public pixel_type<color_space::rgb, 4 /* , etc... */ > {};

This works fairly well. I can use these as runtime and compile time arguments:

template <class PixelType>
class image { };

class transform {
    transform(const pixel_layout from, const pixel_layout to)
        : from(from), to(to) { /* ... */ }
};

Also convert from compile-time type to runtime type:

transform(rgb::layout(), rgba::layout());

However, duplicating and storing the pixel_layout details of the pixel types whenever they are used at runtime seems silly to me. Conceptually, all the program should need is an ID/address/reference to a specific pixel_type and a way to retrieve the associated properties (color space, channels, etc) at both compile time and runtime.

Also, if I want to get a derived property from a pixel type, I need to implement it on pixel_layout if I want to avoid duplicating logic. Then to use it at compile time, I need to go from pixel_type<...> class to pixel_layout instance to derived property. That too, seems a little silly.

Can I avoid passing around the pixel_layout details, and instead use some kind of reference to the pixel_type<...> (sub)classes?

I tried using enums, because enums work as template argument & function argument. But I struggled to get from enum value (e.g. rgba) to pixel type property (e.g. 4 channels) at runtime & compile time in an idiomatic C++ way.

Also, enums as template arguments give far less useful diagnostics during compile error. For example, I get image<(pixel_type)2> rather than image<rgba> in compile error messages with clang. So this does not seem like a useful approach.

Aucun commentaire:

Enregistrer un commentaire