Skip to content

Instantly share code, notes, and snippets.

@vector-of-bool
Last active August 11, 2017 06:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vector-of-bool/f73782e61723b45167b84a711f5e1d2b to your computer and use it in GitHub Desktop.
Save vector-of-bool/f73782e61723b45167b84a711f5e1d2b to your computer and use it in GitHub Desktop.
Dynamix arbitrary-arity macro
// Base template
// Der: CRTP derived class
// ThisType: Type of dynamix object. This carries CV-qualifier information about the message.
// Sig: Signature for the message
template <typename Der, typename ThisType, typename Sig> struct message_helper;
// Impl template. Here we take a signature type as our third argument as a specialization
template <typename Derived, typename ThisType, typename Ret, typename... Args>
struct message_helper<Derived, ThisType, Ret(Args...)> : public ::dynamix::internal::message_t {
using feature_instance_type = ::dynamix::internal::feature_instance<Derived>;
using return_type = Ret;
using caller_func = Ret (*)(void*, Args...);
return_type operator()(ThisType& _d_obj, Args&&... args) {
const ::dynamix::feature& _d_self = feature_instance_type::the_feature_fast();
DYNAMIX_ASSERT(static_cast<const ::dynamix::internal::message_t&>(_d_self).mechanism
== ::dynamix::internal::message_t::unicast);
const ::dynamix::internal::object_type_info::call_table_entry& _d_call_entry
= _d_obj._type_info->_call_table[_d_self.id];
const ::dynamix::internal::message_for_mixin* _d_msg_data = _d_call_entry.message_data;
DYNAMIX_MSG_THROW_UNLESS(_d_msg_data, ::dynamix::bad_message_call);
char* _d_mixin_data = _DYNAMIX_GET_MIXIN_DATA(_d_obj, _d_msg_data->_mixin_id);
const char* message_name = Derived::message_name();
auto _d_func = reinterpret_cast<caller_func>(_d_msg_data->caller);
return _d_func(_d_mixin_data, std::forward<Args>(args)...);
}
template <typename Mixin, return_type (Mixin::*Method)(Args...)>
static return_type caller_fn(void* _d_ptr, Args... args) {
auto _d_m = reinterpret_cast<Mixin*>(_d_ptr);
return (_d_m->*Method)(std::forward<Args>(args)...);
}
template <typename Mixin> dynamix::internal::func_ptr get_caller_for() {
using MixinType = typename std::conditional<std::is_const<ThisType>::value, const Mixin, Mixin>::type;
static caller_func caller = caller_fn<MixinType, Derived::method_on<Mixin>()>;
return reinterpret_cast<dynamix::internal::func_ptr>(caller);
}
message_helper()
: message_t(Derived::message_name(), unicast, false) {}
};
// This macro instead of DYNAMIX_MESSAGE_N. The varargs parameter is to capture complex return types that may be
// template specializations, since macros choke on those.
#define DYNAMIX_SUPERMESSAGE(name, ...) \
namespace { struct _DYNAMIX_MESSAGE_STRUCT_NAME(name) \
: public message_helper<_DYNAMIX_MESSAGE_STRUCT_NAME(name), ::dynamix::object, __VA_ARGS__> { \
static constexpr const char* message_name() { return #name; } \
template <typename Mixin> static constexpr decltype(&Mixin::name) method_on() { return &Mixin::name; } \
} name; }
// Usage: First arg is message name, second is a signature expression.
DYNAMIX_SUPERMESSAGE(speak, void());
DYNAMIX_SUPERMESSAGE(join, std::string(std::string, std::string));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment