mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-23 15:32:25 +00:00
660 lines
26 KiB
C++
660 lines
26 KiB
C++
/*
|
|
* \brief Utilities for template-based meta programming
|
|
* \author Norman Feske
|
|
* \date 2011-02-28
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2011-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
#ifndef _INCLUDE__UTIL__META_H_
|
|
#define _INCLUDE__UTIL__META_H_
|
|
|
|
namespace Genode {
|
|
|
|
namespace Trait {
|
|
|
|
/***************************************
|
|
** Reference and non-reference types **
|
|
***************************************/
|
|
|
|
template <typename T> struct Reference { typedef T& Type; };
|
|
template <typename T> struct Reference<T*> { typedef T* Type; };
|
|
template <typename T> struct Reference<T&> { typedef T& Type; };
|
|
|
|
template <typename T> struct Non_reference { typedef T Type; };
|
|
template <typename T> struct Non_reference<T*> { typedef T Type; };
|
|
template <typename T> struct Non_reference<T&> { typedef T Type; };
|
|
|
|
template <typename T> struct Non_const { typedef T Type; };
|
|
template <typename T> struct Non_const<T const> { typedef T Type; };
|
|
|
|
/**
|
|
* Determine plain-old-data type corresponding to type 'T'
|
|
*/
|
|
template <typename T> struct Pod {
|
|
typedef typename Non_const<typename Non_reference<T>::Type>::Type Type; };
|
|
|
|
} /* namespace Trait */
|
|
|
|
namespace Meta {
|
|
|
|
/***********************************
|
|
** Variadic template type access **
|
|
***********************************/
|
|
|
|
template <unsigned long N, typename HEAD, typename... TAIL>
|
|
struct Variadic_type_tuple
|
|
{
|
|
using Type = typename Variadic_type_tuple<N-1, TAIL...>::Type;
|
|
};
|
|
|
|
template <typename HEAD, typename... TAIL>
|
|
struct Variadic_type_tuple<0, HEAD, TAIL...>
|
|
{
|
|
using Type = HEAD;
|
|
};
|
|
|
|
|
|
/***************
|
|
** Type list **
|
|
***************/
|
|
|
|
/**
|
|
* Type representing an omitted template argument
|
|
*/
|
|
struct Void { };
|
|
|
|
/**
|
|
* Marker for end of type list
|
|
*/
|
|
struct Empty { };
|
|
|
|
/**
|
|
* Basic building block for creating type lists
|
|
*/
|
|
template <typename HEAD, typename TAIL>
|
|
struct Type_tuple
|
|
{
|
|
typedef HEAD Head;
|
|
typedef TAIL Tail;
|
|
};
|
|
|
|
/**
|
|
* Type list with variable number of types
|
|
*/
|
|
template <typename...>
|
|
struct Type_list;
|
|
|
|
template <>
|
|
struct Type_list<> { typedef Empty Head; };
|
|
|
|
template <typename T>
|
|
struct Type_list<T> : Type_tuple<T, Empty> { };
|
|
|
|
template <typename HEAD, typename... TAIL>
|
|
struct Type_list<HEAD, TAIL...> : Type_tuple<HEAD, Type_list<TAIL...> > { };
|
|
|
|
/**
|
|
* Macro for wrapping the 'Type_list' template
|
|
*
|
|
* This macro allows for specifying a type list as macro argument. If we supplied
|
|
* the 'Type_list' template with the types as arguments, the preprocessor would
|
|
* take the comma between the type-list arguments as separator for the macro
|
|
* arguments.
|
|
*/
|
|
#define GENODE_TYPE_LIST(...) ::Genode::Meta::Type_list<__VA_ARGS__>
|
|
|
|
/**
|
|
* Calculate the length of typelist 'TL'
|
|
*/
|
|
template <typename TL>
|
|
struct Length { enum { Value = Length<typename TL::Tail>::Value + 1 }; };
|
|
|
|
template <> struct Length<Empty> { enum { Value = 0 }; };
|
|
|
|
|
|
/**
|
|
* Return index of type 'T' within typelist 'TL'
|
|
*/
|
|
template <typename TL, typename T, unsigned I = 0>
|
|
struct Index_of {
|
|
enum { Value = Index_of<typename TL::Tail, T, I + 1>::Value }; };
|
|
|
|
template <typename TL, unsigned I>
|
|
struct Index_of<TL, typename TL::Head, I> { enum { Value = I }; };
|
|
|
|
|
|
/**
|
|
* Append type list 'APPENDIX' to type list 'TL'
|
|
*/
|
|
template <typename TL, typename APPENDIX>
|
|
class Append
|
|
{
|
|
/* pass appendix towards the end of the typelist */
|
|
typedef typename Append<typename TL::Tail, APPENDIX>::Type _Tail;
|
|
|
|
public:
|
|
|
|
/* keep head, replace tail */
|
|
typedef Type_tuple<typename TL::Head, _Tail> Type;
|
|
};
|
|
|
|
|
|
/* replace end of type list ('Empty' type) with appendix */
|
|
template <typename APPENDIX>
|
|
struct Append<Empty, APPENDIX> { typedef APPENDIX Type; };
|
|
|
|
|
|
/**
|
|
* Return type at index 'I' of type list 'TL'
|
|
*/
|
|
template <typename TL, unsigned I>
|
|
struct Type_at {
|
|
typedef typename Type_at<typename TL::Tail, I - 1>::Type Type; };
|
|
|
|
/* end recursion if we reached the type */
|
|
template <typename TL>
|
|
struct Type_at<TL, 0U> { typedef typename TL::Head Type; };
|
|
|
|
/* end recursion at the end of type list */
|
|
template <unsigned I> struct Type_at<Empty, I> { typedef void Type; };
|
|
|
|
/* resolve ambiguous specializations */
|
|
template <> struct Type_at<Empty, 0> { typedef void Type; };
|
|
|
|
|
|
/**
|
|
* Statically check if all elements of type list 'CTL' are contained in
|
|
* type list 'TL'
|
|
*/
|
|
template <typename TL, typename CTL>
|
|
struct Contains {
|
|
enum { Check = Index_of<TL, typename CTL::Head>::Value
|
|
+ Contains<TL, typename CTL::Tail>::Check }; };
|
|
|
|
template <typename TL> struct Contains<TL, Empty> { enum { Check = 0 }; };
|
|
|
|
|
|
/**
|
|
* Tuple holding references
|
|
*/
|
|
template <typename HEAD, typename TAIL>
|
|
struct Ref_tuple : public Type_tuple<HEAD, TAIL>
|
|
{
|
|
typename Trait::Reference<HEAD>::Type _1;
|
|
typename Trait::Reference<TAIL>::Type _2;
|
|
|
|
Ref_tuple(typename Trait::Reference<HEAD>::Type v1,
|
|
typename Trait::Reference<TAIL>::Type v2) : _1(v1), _2(v2) { }
|
|
|
|
typename Trait::Reference<HEAD>::Type get() { return _1; }
|
|
};
|
|
|
|
/**
|
|
* Specialization of 'Ref_tuple' used if the 'HEAD' is a pointer type
|
|
*
|
|
* The differentiation between pointer and non-pointer types is
|
|
* necessary to obtain a reference to the pointed-to object via the
|
|
* 'get' function when marshalling or unmarshalling a pointer.
|
|
*/
|
|
template <typename HEAD, typename TAIL>
|
|
struct Ref_tuple<HEAD *, TAIL> : public Type_tuple<HEAD *, TAIL>
|
|
{
|
|
HEAD *_1;
|
|
typename Trait::Reference<TAIL>::Type _2;
|
|
|
|
Ref_tuple(HEAD *v1, typename Trait::Reference<TAIL>::Type v2)
|
|
: _1(v1), _2(v2) { }
|
|
|
|
typename Trait::Reference<HEAD>::Type get() { return *_1; }
|
|
};
|
|
|
|
template <typename T1, typename T2, typename T3>
|
|
struct Ref_tuple_3 : public Ref_tuple<T1, Ref_tuple<T2, T3> >
|
|
{
|
|
Ref_tuple<T2, T3> _t2;
|
|
Ref_tuple_3(typename Trait::Reference<T1>::Type v1,
|
|
typename Trait::Reference<T2>::Type v2,
|
|
typename Trait::Reference<T3>::Type v3)
|
|
: Ref_tuple<T1, Ref_tuple<T2, T3> >(v1, _t2), _t2(v2, v3) { }
|
|
};
|
|
|
|
template <typename T1, typename T2, typename T3, typename T4>
|
|
struct Ref_tuple_4 : public Ref_tuple<T1, Ref_tuple_3<T2, T3, T4> >
|
|
{
|
|
Ref_tuple_3<T2, T3, T4> _t2;
|
|
Ref_tuple_4(typename Trait::Reference<T1>::Type v1,
|
|
typename Trait::Reference<T2>::Type v2,
|
|
typename Trait::Reference<T3>::Type v3,
|
|
typename Trait::Reference<T4>::Type v4)
|
|
: Ref_tuple<T1, Ref_tuple_3<T2, T3, T4> >(v1, _t2), _t2(v2, v3, v4) { }
|
|
};
|
|
|
|
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
|
struct Ref_tuple_5 : public Ref_tuple<T1, Ref_tuple_4<T2, T3, T4, T5> >
|
|
{
|
|
Ref_tuple_4<T2, T3, T4, T5> _t2;
|
|
Ref_tuple_5(typename Trait::Reference<T1>::Type v1,
|
|
typename Trait::Reference<T2>::Type v2,
|
|
typename Trait::Reference<T3>::Type v3,
|
|
typename Trait::Reference<T4>::Type v4,
|
|
typename Trait::Reference<T5>::Type v5)
|
|
: Ref_tuple<T1, Ref_tuple_4<T2, T3, T4, T5> >(v1, _t2), _t2(v2, v3, v4, v5) { }
|
|
};
|
|
|
|
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
|
|
struct Ref_tuple_6 : public Ref_tuple<T1, Ref_tuple_5<T2, T3, T4, T5, T6> >
|
|
{
|
|
Ref_tuple_5<T2, T3, T4, T5, T6> _t2;
|
|
Ref_tuple_6(typename Trait::Reference<T1>::Type v1,
|
|
typename Trait::Reference<T2>::Type v2,
|
|
typename Trait::Reference<T3>::Type v3,
|
|
typename Trait::Reference<T4>::Type v4,
|
|
typename Trait::Reference<T5>::Type v5,
|
|
typename Trait::Reference<T6>::Type v6)
|
|
: Ref_tuple<T1, Ref_tuple_5<T2, T3, T4, T5, T6> >(v1, _t2), _t2(v2, v3, v4, v5, v6) { }
|
|
};
|
|
|
|
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
|
|
struct Ref_tuple_7 : public Ref_tuple<T1, Ref_tuple_6<T2, T3, T4, T5, T6, T7> >
|
|
{
|
|
Ref_tuple_6<T2, T3, T4, T5, T6, T7> _t2;
|
|
Ref_tuple_7(typename Trait::Reference<T1>::Type v1,
|
|
typename Trait::Reference<T2>::Type v2,
|
|
typename Trait::Reference<T3>::Type v3,
|
|
typename Trait::Reference<T4>::Type v4,
|
|
typename Trait::Reference<T5>::Type v5,
|
|
typename Trait::Reference<T6>::Type v6,
|
|
typename Trait::Reference<T7>::Type v7)
|
|
: Ref_tuple<T1, Ref_tuple_6<T2, T3, T4, T5, T6, T7> >(v1, _t2), _t2(v2, v3, v4, v5, v6, v7) { }
|
|
};
|
|
|
|
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
|
|
struct Ref_tuple_8 : public Ref_tuple<T1, Ref_tuple_7<T2, T3, T4, T5, T6, T7, T8> >
|
|
{
|
|
Ref_tuple_7<T2, T3, T4, T5, T6, T7, T8> _t2;
|
|
Ref_tuple_8(typename Trait::Reference<T1>::Type v1,
|
|
typename Trait::Reference<T2>::Type v2,
|
|
typename Trait::Reference<T3>::Type v3,
|
|
typename Trait::Reference<T4>::Type v4,
|
|
typename Trait::Reference<T5>::Type v5,
|
|
typename Trait::Reference<T6>::Type v6,
|
|
typename Trait::Reference<T7>::Type v7,
|
|
typename Trait::Reference<T8>::Type v8)
|
|
: Ref_tuple<T1, Ref_tuple_7<T2, T3, T4, T5, T6, T7, T8> >(v1, _t2), _t2(v2, v3, v4, v5, v6, v7, v8) { }
|
|
};
|
|
|
|
/**
|
|
* Tuple holding raw (plain old) data
|
|
*
|
|
* Has to be an aggregate type to allow non-default-constructible RPC
|
|
* arguments. But aggregate types must not derive from a base class in
|
|
* C++11. So we do not derive from Meta::Type_tuple although it is an
|
|
* empty class.
|
|
*/
|
|
template <typename HEAD, typename TAIL>
|
|
struct Pod_tuple
|
|
{
|
|
typedef typename Trait::Pod<HEAD>::Type Stored_head;
|
|
Stored_head _1;
|
|
TAIL _2;
|
|
|
|
typedef HEAD Head;
|
|
typedef TAIL Tail;
|
|
|
|
/**
|
|
* Accessor for requesting the data reference to '_1'
|
|
*/
|
|
Stored_head &get() { return _1; }
|
|
};
|
|
|
|
/**
|
|
* Specialization of 'Pod_tuple' for pointer types
|
|
*
|
|
* For pointer types, the corresponding data structure must be able to
|
|
* host a copy of the pointed-to object. However, the accessor for data
|
|
* must be consistent with the input (pointer) type. Hence, the 'get'
|
|
* function returns a pointer to the stored copy.
|
|
*/
|
|
template <typename HEAD, typename TAIL>
|
|
struct Pod_tuple<HEAD *, TAIL>
|
|
{
|
|
typedef typename Trait::Non_reference<HEAD>::Type Stored_head;
|
|
Stored_head _1;
|
|
TAIL _2;
|
|
|
|
typedef HEAD* Head;
|
|
typedef TAIL Tail;
|
|
|
|
HEAD *get() { return &_1; }
|
|
};
|
|
|
|
|
|
/*************************************************************************
|
|
** Support for representing function arguments in a normalized fashion **
|
|
*************************************************************************/
|
|
|
|
/**
|
|
* Return recursive type for holding the specified reference argument types
|
|
*
|
|
* Depending on the number of supplied template arguments, a differently
|
|
* dimensioned type is returned. This template is called with the variable
|
|
* argument list used by the 'GENODE_RPC' macro and effectifely translates the
|
|
* argument list to a recursive type that can be processed with template meta
|
|
* programming. The result of the translation is returned as 'Ref_args::Type'.
|
|
*/
|
|
template <typename T1 = Void, typename T2 = Void, typename T3 = Void,
|
|
typename T4 = Void, typename T5 = Void, typename T6 = Void,
|
|
typename T7 = Void, typename T8 = Void>
|
|
struct Ref_args;
|
|
|
|
template <>
|
|
struct Ref_args<Void> {
|
|
typedef Empty Type; };
|
|
|
|
template <typename T1>
|
|
struct Ref_args<T1, Void> {
|
|
typedef Ref_tuple<T1, Empty> Type; };
|
|
|
|
template <typename T1, typename T2>
|
|
struct Ref_args<T1, T2, Void> {
|
|
typedef Ref_tuple_3<T1, T2, Empty> Type; };
|
|
|
|
template <typename T1, typename T2, typename T3>
|
|
struct Ref_args<T1, T2, T3, Void> {
|
|
typedef Ref_tuple_4<T1, T2, T3, Empty> Type; };
|
|
|
|
template <typename T1, typename T2, typename T3, typename T4>
|
|
struct Ref_args<T1, T2, T3, T4, Void> {
|
|
typedef Ref_tuple_5<T1, T2, T3, T4, Empty> Type; };
|
|
|
|
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
|
struct Ref_args<T1, T2, T3, T4, T5, Void> {
|
|
typedef Ref_tuple_6<T1, T2, T3, T4, T5, Empty> Type; };
|
|
|
|
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
|
|
struct Ref_args<T1, T2, T3, T4, T5, T6, Void> {
|
|
typedef Ref_tuple_7<T1, T2, T3, T4, T5, T6, Empty> Type; };
|
|
|
|
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
|
|
struct Ref_args<T1, T2, T3, T4, T5, T6, T7, Void> {
|
|
typedef Ref_tuple_8<T1, T2, T3, T4, T5, T6, T7, Empty> Type; };
|
|
|
|
|
|
/**
|
|
* Return recursive type for storing the specified data types
|
|
*
|
|
* The 'Pod_args' template works analogously to the 'Ref_args' template, except
|
|
* for returning a type for storing values, not references.
|
|
*/
|
|
template <typename T1 = Void, typename T2 = Void, typename T3 = Void,
|
|
typename T4 = Void, typename T5 = Void, typename T6 = Void,
|
|
typename T7 = Void, typename T8 = Void>
|
|
struct Pod_args;
|
|
|
|
template <>
|
|
struct Pod_args<Void> { typedef Empty Type; };
|
|
|
|
template <typename T1>
|
|
struct Pod_args<T1, Void> { typedef Pod_tuple<T1, Empty> Type; };
|
|
|
|
template <typename T1, typename T2>
|
|
struct Pod_args<T1, T2, Void> { typedef Pod_tuple<T1, typename Pod_args<T2, Void>::Type> Type; };
|
|
|
|
template <typename T1, typename T2, typename T3>
|
|
struct Pod_args<T1, T2, T3, Void> { typedef Pod_tuple<T1, typename Pod_args<T2, T3, Void>::Type> Type; };
|
|
|
|
template <typename T1, typename T2, typename T3, typename T4>
|
|
struct Pod_args<T1, T2, T3, T4, Void> { typedef Pod_tuple<T1, typename Pod_args<T2, T3, T4, Void>::Type> Type; };
|
|
|
|
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
|
struct Pod_args<T1, T2, T3, T4, T5, Void> { typedef Pod_tuple<T1, typename Pod_args<T2, T3, T4, T5, Void>::Type> Type; };
|
|
|
|
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
|
|
struct Pod_args<T1, T2, T3, T4, T5, T6, Void> { typedef Pod_tuple<T1, typename Pod_args<T2, T3, T4, T5, T6, Void>::Type> Type; };
|
|
|
|
template <typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
|
|
struct Pod_args<T1, T2, T3, T4, T5, T6, T7, Void> { typedef Pod_tuple<T1, typename Pod_args<T2, T3, T4, T5, T6, T7, Void>::Type> Type; };
|
|
|
|
|
|
/**
|
|
* Helper for calling member functions via a uniform interface
|
|
*
|
|
* Member functions differ in their types and numbers of arguments as
|
|
* well as their return types or their lack of a return type. This
|
|
* makes them difficult to call from generic template code. The
|
|
* 'call_member' function template remedies this issue by providing a
|
|
* wrapper function with a unified signature. For each case, the
|
|
* compiler generates a new overload of the 'call_member' function. For
|
|
* each number of function arguments, there exists a pair of overloads,
|
|
* one used if a return type is present, the other used for functions
|
|
* with no return value.
|
|
*
|
|
* \param RET_TYPE return type of member function, or 'Meta::Empty'
|
|
* if the function has no return type
|
|
* \param SERVER class that hosts the member function to call
|
|
* \param ARGS recursively defined 'Pod_args' type composed of
|
|
* the function-argument types expected by the member
|
|
* function
|
|
* \param ret reference for storing the return value of the
|
|
* member function
|
|
* \param server reference to the object to be used for the call
|
|
* \param args function arguments
|
|
* \param func pointer-to-member function to invoke
|
|
*/
|
|
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &,
|
|
RET_TYPE (SERVER::*func)())
|
|
{ return (server.*func)(); }
|
|
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &,
|
|
RET_TYPE (SERVER::*func)() const)
|
|
{ return (server.*func)(); }
|
|
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &,
|
|
void (SERVER::*func)())
|
|
{ (server.*func)(); return Empty(); }
|
|
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &,
|
|
void (SERVER::*func)() const)
|
|
{ (server.*func)(); return Empty(); }
|
|
|
|
/* 1 */
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
RET_TYPE (SERVER::*func)(typename Type_at<ARGS, 0>::Type))
|
|
{ return (server.*func)(args.get()); }
|
|
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
void (SERVER::*func)(typename Type_at<ARGS, 0>::Type))
|
|
{ (server.*func)(args.get()); return Empty(); }
|
|
|
|
/* 2 */
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
RET_TYPE (SERVER::*func)(typename Type_at<ARGS, 0>::Type,
|
|
typename Type_at<ARGS, 1>::Type))
|
|
{ return (server.*func)(args.get(), args._2.get()); }
|
|
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
void (SERVER::*func)(typename Type_at<ARGS, 0>::Type,
|
|
typename Type_at<ARGS, 1>::Type))
|
|
{ (server.*func)(args.get(), args._2.get()); return Empty(); }
|
|
|
|
/* 3 */
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
RET_TYPE (SERVER::*func)(typename Type_at<ARGS, 0>::Type,
|
|
typename Type_at<ARGS, 1>::Type,
|
|
typename Type_at<ARGS, 2>::Type))
|
|
{ return (server.*func)(args.get(), args._2.get(), args._2._2.get()); }
|
|
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
void (SERVER::*func)(typename Type_at<ARGS, 0>::Type,
|
|
typename Type_at<ARGS, 1>::Type,
|
|
typename Type_at<ARGS, 2>::Type))
|
|
{ (server.*func)(args.get(), args._2.get(), args._2._2.get()); return Empty(); }
|
|
|
|
/* 4 */
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
RET_TYPE (SERVER::*func)(typename Type_at<ARGS, 0>::Type,
|
|
typename Type_at<ARGS, 1>::Type,
|
|
typename Type_at<ARGS, 2>::Type,
|
|
typename Type_at<ARGS, 3>::Type))
|
|
{ return (server.*func)(args.get(), args._2.get(), args._2._2.get(), args._2._2._2.get()); }
|
|
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
void (SERVER::*func)(typename Type_at<ARGS, 0>::Type,
|
|
typename Type_at<ARGS, 1>::Type,
|
|
typename Type_at<ARGS, 2>::Type,
|
|
typename Type_at<ARGS, 3>::Type))
|
|
{ (server.*func)(args.get(), args._2.get(), args._2._2.get(), args._2._2._2.get()); return Empty(); }
|
|
|
|
/* 5 */
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
RET_TYPE (SERVER::*func)(typename Type_at<ARGS, 0>::Type,
|
|
typename Type_at<ARGS, 1>::Type,
|
|
typename Type_at<ARGS, 2>::Type,
|
|
typename Type_at<ARGS, 3>::Type,
|
|
typename Type_at<ARGS, 4>::Type))
|
|
{ return (server.*func)(args.get(), args._2.get(), args._2._2.get(), args._2._2._2.get(), args._2._2._2._2.get()); }
|
|
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
void (SERVER::*func)(typename Type_at<ARGS, 0>::Type,
|
|
typename Type_at<ARGS, 1>::Type,
|
|
typename Type_at<ARGS, 2>::Type,
|
|
typename Type_at<ARGS, 3>::Type,
|
|
typename Type_at<ARGS, 4>::Type))
|
|
{ (server.*func)(args.get(), args._2.get(), args._2._2.get(), args._2._2._2.get(), args._2._2._2._2.get()); return Empty(); }
|
|
|
|
/* 6 */
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
RET_TYPE (SERVER::*func)(typename Type_at<ARGS, 0>::Type,
|
|
typename Type_at<ARGS, 1>::Type,
|
|
typename Type_at<ARGS, 2>::Type,
|
|
typename Type_at<ARGS, 3>::Type,
|
|
typename Type_at<ARGS, 4>::Type,
|
|
typename Type_at<ARGS, 5>::Type))
|
|
{ return (server.*func)(args.get(), args._2.get(), args._2._2.get(), args._2._2._2.get(),
|
|
args._2._2._2._2.get(), args._2._2._2._2._2.get()); }
|
|
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
void (SERVER::*func)(typename Type_at<ARGS, 0>::Type,
|
|
typename Type_at<ARGS, 1>::Type,
|
|
typename Type_at<ARGS, 2>::Type,
|
|
typename Type_at<ARGS, 3>::Type,
|
|
typename Type_at<ARGS, 4>::Type,
|
|
typename Type_at<ARGS, 5>::Type))
|
|
{ (server.*func)(args.get(), args._2.get(), args._2._2.get(), args._2._2._2.get(),
|
|
args._2._2._2._2.get(), args._2._2._2._2._2.get()); return Empty(); }
|
|
|
|
/* 7 */
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
RET_TYPE (SERVER::*func)(typename Type_at<ARGS, 0>::Type,
|
|
typename Type_at<ARGS, 1>::Type,
|
|
typename Type_at<ARGS, 2>::Type,
|
|
typename Type_at<ARGS, 3>::Type,
|
|
typename Type_at<ARGS, 4>::Type,
|
|
typename Type_at<ARGS, 5>::Type,
|
|
typename Type_at<ARGS, 6>::Type))
|
|
{ return (server.*func)(args.get(), args._2.get(), args._2._2.get(), args._2._2._2.get(),
|
|
args._2._2._2._2.get(), args._2._2._2._2._2.get(), args._2._2._2._2._2._2.get()); }
|
|
|
|
template <typename RET_TYPE, typename SERVER, typename ARGS>
|
|
static inline RET_TYPE call_member(SERVER &server, ARGS &args,
|
|
void (SERVER::*func)(typename Type_at<ARGS, 0>::Type,
|
|
typename Type_at<ARGS, 1>::Type,
|
|
typename Type_at<ARGS, 2>::Type,
|
|
typename Type_at<ARGS, 3>::Type,
|
|
typename Type_at<ARGS, 4>::Type,
|
|
typename Type_at<ARGS, 5>::Type,
|
|
typename Type_at<ARGS, 6>::Type))
|
|
{ (server.*func)(args.get(), args._2.get(), args._2._2.get(), args._2._2._2.get(),
|
|
args._2._2._2._2.get(), args._2._2._2._2._2.get(), args._2._2._2._2._2._2.get()); return Empty(); }
|
|
|
|
|
|
/********************
|
|
** Misc utilities **
|
|
********************/
|
|
|
|
/**
|
|
* Round unsigned long value to next machine-word-aligned value
|
|
*/
|
|
template <unsigned long SIZE>
|
|
struct Round_to_machine_word {
|
|
enum { Value = (SIZE + sizeof(long) - 1) & ~(sizeof(long) - 1) }; };
|
|
|
|
/**
|
|
* Utility for partial specialization of member function templates
|
|
*
|
|
* By passing an artificial 'Overload_selector' argument to a function
|
|
* template, we can use overloading to partially specify such a
|
|
* function template. The selection of the overload to use is directed
|
|
* by one or two types specified as template arguments of
|
|
* 'Overload_selector'.
|
|
*/
|
|
template <typename T1, typename T2 = T1>
|
|
struct Overload_selector
|
|
{
|
|
/*
|
|
* Make class unique for different template arguments. The types
|
|
* are never used.
|
|
*/
|
|
typedef T1 _T1;
|
|
typedef T2 _T2;
|
|
|
|
/* prevent zero initialization of objects */
|
|
Overload_selector() { }
|
|
};
|
|
|
|
/**
|
|
* Convert boolean value to type
|
|
*/
|
|
template <bool VALUE> struct Bool_to_type { enum { V = VALUE }; };
|
|
|
|
} /* namespace Meta */
|
|
|
|
namespace Trait {
|
|
|
|
template<typename T> struct Functor;
|
|
|
|
template<typename RET, typename T, typename... ARGS>
|
|
struct Functor<RET (T::*)(ARGS...) const>
|
|
{
|
|
static constexpr unsigned long argument_count = sizeof...(ARGS);
|
|
|
|
using Return_type = RET;
|
|
|
|
template <unsigned long N>
|
|
struct Argument
|
|
{
|
|
static_assert(N < argument_count, "Invalid index");
|
|
|
|
using Type =
|
|
typename Meta::Variadic_type_tuple<N, ARGS...>::Type;
|
|
};
|
|
};
|
|
} /* namespace Trait */
|
|
}
|
|
|
|
#endif /* _INCLUDE__UTIL__META_H_ */
|