efl/src/bindings/eo_cxx/eo_inherit_bindings.hh

348 lines
11 KiB
C++

#ifndef EFL_CXX_DETAIL_INHERIT_BINDINGS_HH
#define EFL_CXX_DETAIL_INHERIT_BINDINGS_HH
#include <typeinfo>
#include <eina_integer_sequence.hh>
namespace efl { namespace eo { namespace detail {
/// @addtogroup Efl_Cxx_Detail
/// @{
/// @internal
///
/// @brief Invokes the <em>EO C Constructor</em> that corresponds to the
/// binded <em>EO C++ Class</em>.
///
/// @param T The corresponding <em>EO C++ Class</em>
/// @param Args An heterogeneous list of constructor arguments
///
/// @param tag Used to instruct the compiler during compile-time which
/// of the overloads should be invoked.
/// @param eo A pointer to the <em>EO C Object</em> to be constructed.
/// @param cls Unused.
/// @param args An heterogenous vector containing the constructor
/// arguments, in the correct order.
///
/// To ensure full reciprocity of the C++ binding there must exist one
/// (and only one) implementation of @ref efl::eo::detail::call_constructor
/// for each available <em>EO C++ Class</em> --- the implementations
/// are differentiated by this unique specialization of
/// @ref efl::eo::detail::tag for the first argument of
/// @ref efl::eo::detail::call_constructor.
///
/// For example this is how the overload for @ref eo_simple is
/// written as follows:
///
/// @dontinclude eo_simple.hh
/// @skip call_constructor
/// @until }
///
/// As you can see @c ::simple_constructor is called with a single
/// argument in this case. Each EO Class has its own constructor
/// prototype -- which can have different argument types as well as
/// distinct number of arguments, etc. -- hence the need to specify a
/// choice for every known <em>EO C++ Class</em>.
///
/// @see efl::eo::detail::tag
///
template <typename T, typename Args>
void call_constructor(efl::eo::detail::tag<T> tag, Eo* eo, Eo_Class const* cls, Args args);
/// @internal
///
/// @brief Sums up the number of <em>EO Operations</em> of each class
/// passed as argument to the template.
///
/// @see efl::eo::detail::operation_description_class_size
///
template <typename... E>
struct operation_description_size;
template <typename E0, typename... E>
struct operation_description_size<E0, E...>
{
static const int value = operation_description_class_size<E0>::value +
operation_description_size<E...>::value;
};
template <>
struct operation_description_size<>
{
static const int value = 0;
};
template <typename T>
struct is_args_class : std::false_type
{
};
template <typename T, typename Tuple>
struct is_args_class<args_class<T, Tuple> >
: std::true_type
{
};
template <typename Tuple>
struct are_args_class;
template <>
struct are_args_class<std::tuple<> >
: std::true_type
{
};
template <typename T0, typename... T>
struct are_args_class<std::tuple<T0, T...> >
: std::integral_constant
<bool
, is_args_class<T0>::value
&& are_args_class<std::tuple<T...> >::value
>
{
};
template <typename T, typename Tuple>
struct has_args_class : std::false_type
{
typedef std::integral_constant<std::size_t, 0u> index;
};
template <typename T, typename Tuple, typename... Args>
struct has_args_class<T, std::tuple<detail::args_class<T, Tuple>, Args...> >
: std::true_type
{
typedef detail::args_class<T, Tuple> type;
typedef std::integral_constant<std::size_t, 0u> index;
};
template <typename T, typename T0, typename... Args>
struct has_args_class<T, std::tuple<T0, Args...> >
: has_args_class<T, std::tuple<Args...> >
{
typedef has_args_class<T, std::tuple<Args...> > base_type;
typedef std::integral_constant
<std::size_t, 1u + base_type::index::value> index;
};
/// @internal
///
/// @brief An auxiliary template-class used to select the correct
/// implementation of @ref efl::eo::call_constructor for @p T with
/// proper parameters and variadic size.
///
/// @param T An <em>EO C++ Class</em>.
///
template <typename T, std::size_t N>
struct call_constructor_aux
{
template <typename Args, typename P>
static void do_(Args const&, Eo* eo, Eo_Class const* cls
, P, typename std::enable_if<!P::value>::type* = 0)
{
call_constructor(tag<T>(), eo, cls, args_class<T, std::tuple<> >(std::tuple<>()));
}
template <typename Args, typename P>
static void do_(Args const& args, Eo* eo, Eo_Class const* cls
, P, typename std::enable_if<P::value>::type* = 0)
{
call_constructor(tag<T>(), eo, cls, std::get<P::index::value>(args));
}
/// @internal
///
/// @brief Invoke @def efl::eo::detail::call_constructor
/// implementation for the parent and each available extension.
///
/// @param args An heterogenous sequence of arguments.
/// @param eo The opaque <em>EO Object</em>.
/// @param cls The opaque <em>EO Class</em>.
///
template <typename Args>
static int do_(Args const& args, Eo* eo, Eo_Class const* cls)
{
static_assert(std::tuple_size<Args>::value <= N, "");
static_assert(are_args_class<Args>::value, "");
do_(args, eo, cls, has_args_class<T, Args>());
return 0;
}
};
template <typename T>
struct call_constructor_aux<T, 1u>
{
template <typename Args>
static void do_(Args const& args, Eo* eo, Eo_Class const* cls
, std::true_type)
{
static_assert(std::tuple_size<Args>::value == 1, "");
static_assert(std::is_same
<typename std::tuple_element<0u, Args>::type::class_type
, T>::value, "");
call_constructor(tag<T>(), eo, cls, std::get<0u>(args));
}
template <typename Args>
static void do_(Args const& args, Eo* eo, Eo_Class const* cls
, std::false_type)
{
call_constructor(tag<T>(), eo, cls, args_class<T, Args>(args));
}
template <typename Args>
static int do_(Args const& args, Eo* eo, Eo_Class const* cls)
{
do_(args, eo, cls, has_args_class<T, Args>());
return 0;
}
};
template <typename... Args>
void call_varargs(Args...)
{
}
/// @internal
///
/// @brief The procedure that actually is invoked when the constructor
/// of @c D is sought from the <em>EO Subsystem</em>.
///
/// @param obj The opaque <em>EO Object</em>.
/// @param self A pointer to @p obj's private data.
/// @param this_ A void pointer to the opaque <em>EO Class</em> ---
/// passed as <em>user data</em>.
/// @param args The arguments for the underlying constructor.
///
template <typename D, typename Args, typename... E>
void inherit_constructor_impl(Eo* obj, Inherit_Private_Data* self, void* this_, Args args)
{
self->this_ = this_;
Eo_Class const* cls = static_cast<inherit<D, E...>*>(this_)->_eo_class();
detail::call_varargs(detail::call_constructor_aux<E, sizeof...(E)>::do_(args, obj, cls) ...);
}
/// @internal
///
/// @brief Find the correct function for the <em>"constructor"</em>
/// operation and invoke it.
///
/// @param this_ The <em>user data</em> to be passed to the resolved function.
/// @param args An heterogeneous sequence of arguments.
///
template <typename Args, typename... E>
EAPI void inherit_constructor(void* this_, Args args)
{
typedef void (*func_t)(Eo *, void *, void*, Args);
Eo_Op_Call_Data call;
static Eo_Op op = EO_NOOP;
if ( op == EO_NOOP )
op = _eo_api_op_id_get
(reinterpret_cast<void*>
(static_cast<void(*)(void*, Args)>(&detail::inherit_constructor<Args, E...>)),
__FILE__, __LINE__);
if (!_eo_call_resolve("detail::inherit_constructor", op, &call, __FILE__, __LINE__))
{
assert(_eo_call_resolve("detail::inherit_constructor", op, &call, __FILE__, __LINE__));
return;
}
func_t func = (func_t) call.func;
EO_HOOK_CALL_PREPARE(eo_hook_call_pre);
func(call.obj, call.data, this_, args);
EO_HOOK_CALL_PREPARE(eo_hook_call_post);
}
template <typename T>
int initialize_operation_description(detail::tag<void>, void*);
template <std::size_t I, typename... E>
struct
operation_description_index
{
typedef std::tuple<E...> tuple_type;
static const std::size_t value =
detail::operation_description_size
< typename std::tuple_element
<I-1, tuple_type>::type >::value +
operation_description_index<I-1, E...>::value;
};
template <typename... E>
struct
operation_description_index<0u, E...>
{
static const std::size_t value = 0u;
};
/// @internal
///
/// @brief This function is responsible for declaring a new <em>EO C
/// Class</em> representing @p D within <em>EO Subsystem</em>.
///
/// @param D The derived class
/// @param P The parent class
/// @param En Class extensions (either mixins or interfaces)
/// @param Args An heterogeneous list of arguments to be passed to the
/// constructor of this class.
///
/// @see efl::eo::inherit::inherit
///
template <typename D, typename TupleArgs, typename... E, std::size_t ... S>
Eo_Class const* create_class(eina::index_sequence<S...>)
{
static const Eo_Class* my_class = NULL;
static Eo_Op_Description op_descs
[ detail::operation_description_size<E...>::value + 2 ];
op_descs[detail::operation_description_size<E...>::value].func =
reinterpret_cast<void*>
(
static_cast<void(*)(Eo*, Inherit_Private_Data*, void*, TupleArgs)>
(&detail::inherit_constructor_impl<D, TupleArgs, E...>)
);
op_descs[detail::operation_description_size<E...>::value].api_func =
reinterpret_cast<void*>
(
static_cast<void(*)(void*, TupleArgs)>
(&detail::inherit_constructor<TupleArgs, E...>)
);
op_descs[detail::operation_description_size<E...>::value].op = EO_NOOP;
op_descs[detail::operation_description_size<E...>::value].op_type = EO_OP_TYPE_REGULAR;
op_descs[detail::operation_description_size<E...>::value].doc = NULL;
op_descs[detail::operation_description_size<E...>::value+1].func = 0;
op_descs[detail::operation_description_size<E...>::value+1].api_func = 0;
op_descs[detail::operation_description_size<E...>::value+1].op = 0;
op_descs[detail::operation_description_size<E...>::value+1].op_type = EO_OP_TYPE_INVALID;
op_descs[detail::operation_description_size<E...>::value+1].doc = NULL;
typedef inherit<D, E...> inherit_type;
using namespace detail;
call_varargs(
initialize_operation_description<inherit_type>
(detail::tag<E>(),
&op_descs[operation_description_index<S, E...>::value]) ...
);
//locks
if(!my_class)
{
static Eo_Class_Description class_desc = {
EO_VERSION,
"Eo C++ Class",
EO_CLASS_TYPE_REGULAR,
EO_CLASS_DESCRIPTION_OPS(op_descs),
NULL,
sizeof(detail::Inherit_Private_Data),
NULL,
NULL
};
my_class = detail::do_eo_class_new<E...>(class_desc);
}
return my_class;
}
} } } // namespace efl { namespace eo { namespace detail {
#endif // EFL_CXX_DETAIL_INHERIT_BINDINGS_HH