Tuesday, April 28, 2009

Making C++ do C99 things (part 2/3)

XSetWindowAttributes_ xswa = {
‍ ‍ bit_gravity_ = ForgetGravity,
‍ ‍ background_pixmap_ = None
};
So here is how you do it. Note that this is a sketch of an implementation rather than a full implementation, but it should suffice as a proof of viability of the concept. (Though not of its sanity. If you want that, see the previous post's equivalence.)

For reference, XSetWindowAttributes is defined here.


// If this line doesn't work -- it's untested -- it may be necessary
// to extract the type via template deduction instead.
#define MEMBER_TYPEOF(x) BOOST_TYPEOF((NULL)->*(x))

struct background_pixmap_tag {
‍ ‍ typedef MEMBER_TYPEOF(XSetWindowAttributes::background_pixmap) type;
‍ ‍ static type XSetWindowAttributes::* const mptr =
‍ ‍ ‍ ‍ XSetWindowAttributes::background_pixmap;
‍ ‍ static void apply(XSetWindowAttributes &str, char const *buf)
‍ ‍ { str.*mptr = *(type const *)buf; }
};

struct background_pixel_tag {
‍ ‍ typedef MEMBER_TYPEOF(XSetWindowAttributes::background_pixel) type;
‍ ‍ static type XSetWindowAttributes::* const mptr =
‍ ‍ ‍ ‍ XSetWindowAttributes::background_pixel;
‍ ‍ static void apply(XSetWindowAttributes &str, char const *buf)
‍ ‍ { str.*mptr = *(type const *)buf; }
};

// ... and so forth; these tag-types are boring and can be generated by,
// e.g., a macro taking the type name and a Boost.PP Sequence of member names.
// (And save that sequence; you'll want it for other things.)



// Compute the maximum size of the raw data types of each member of the
// underlying struct; this is left as an exercise for the reader. Hint:
// generate a boost::mpl::vector of tag-types from the Boost.PP.Sequence
// of member names.
static const size_t max_data_size = boost::mpl:: ... ;

struct ParameterSetter {
‍ ‍ apply_fptr_t apply_fun;
‍ ‍ char buffer[max_data_size];
}

template <typename Tag>
struct Parameter {
‍ ‍ ParameterSetter operator=(typename Tag::type value) {
‍ ‍ ‍ ‍ inline ParameterSetter ps = { &Tag::apply };
‍ ‍ ‍ ‍ (typename Tag::type *)(void *)(char *)(ps.buffer) = value;
‍ ‍ ‍ ‍ return ps;
‍ ‍ }
};

Parameter background_pixmap_;
Parameter background_pixel_;
// ... more preprocessor-handlable declarations ...

struct XSetWindowAttributes_ {
‍ ‍ ParameterSetter a0;
‍ ‍ ParameterSetter a1;
‍ ‍ // ... the maximum N needed is the sequence size == member count ...
‍ ‍ ParameterSetter aN;

‍ ‍ XSetWindowAttributes attr;
‍ ‍ inline operator XSetWindowAttributes &() {
‍ ‍ ‍ ‍ if (a0.apply_fun) (a0.apply_fun)(attr, a0.buffer) else return attr;
‍ ‍ ‍ ‍ if (a1.apply_fun) (a1.apply_fun)(attr, a1.buffer) else return attr;
‍ ‍ ‍ ‍ // ... you know the drill by now ...
‍ ‍ ‍ ‍ if (aN.apply_fun) (aN.apply_fun)(attr, aN.buffer) else return attr;
‍ ‍ ‍ ‍ return attr;
‍ ‍ }
‍ ‍ inline XSetWindowAttributes* operator &()
‍ ‍ { return &(this->operator XSetWindowAttributes &()); }
};

// ... and Bob's your uncle.

XSetWindowAttributes_ xswa = {
‍ ‍ bit_gravity_ = ForgetGravity,
‍ ‍ background_pixmap_ = None
};


(Explanations next time.)

No comments: