/* * \brief Utilities for template-based meta programming * \author Norman Feske * \date 2011-02-28 */ /* * Copyright (C) 2011-2013 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. */ #ifndef _INCLUDE__UTIL__META_H_ #define _INCLUDE__UTIL__META_H_ namespace Genode { namespace Trait { /*************************************** ** Reference and non-reference types ** ***************************************/ template struct Reference { typedef T& Type; }; template struct Reference { typedef T* Type; }; template struct Reference { typedef T& Type; }; template struct Non_reference { typedef T Type; }; template struct Non_reference { typedef T Type; }; template struct Non_reference { typedef T Type; }; template struct Non_const { typedef T Type; }; template struct Non_const { typedef T Type; }; /** * Determine plain-old-data type corresponding to type 'T' */ template struct Pod { typedef typename Non_const::Type>::Type Type; }; } /* namespace Trait */ namespace Meta { /*********************************** ** Variadic template type access ** ***********************************/ template struct Variadic_type_tuple { using Type = typename Variadic_type_tuple::Type; }; template 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 struct Type_tuple { typedef HEAD Head; typedef TAIL Tail; }; /** * Type list with variable number of types */ template struct Type_list; template <> struct Type_list<> { typedef Empty Head; }; template struct Type_list : Type_tuple { }; template struct Type_list : Type_tuple > { }; /** * 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 struct Length { enum { Value = Length::Value + 1 }; }; template <> struct Length { enum { Value = 0 }; }; /** * Return index of type 'T' within typelist 'TL' */ template struct Index_of { enum { Value = Index_of::Value }; }; template struct Index_of { enum { Value = I }; }; /** * Append type list 'APPENDIX' to type list 'TL' */ template class Append { /* pass appendix towards the end of the typelist */ typedef typename Append::Type _Tail; public: /* keep head, replace tail */ typedef Type_tuple Type; }; /* replace end of type list ('Empty' type) with appendix */ template struct Append { typedef APPENDIX Type; }; /** * Return type at index 'I' of type list 'TL' */ template struct Type_at { typedef typename Type_at::Type Type; }; /* end recursion if we reached the type */ template struct Type_at { typedef typename TL::Head Type; }; /* end recursion at the end of type list */ template struct Type_at { typedef void Type; }; /* resolve ambiguous specializations */ template <> struct Type_at { typedef void Type; }; /** * Statically check if all elements of type list 'CTL' are contained in * type list 'TL' */ template struct Contains { enum { Check = Index_of::Value + Contains::Check }; }; template struct Contains { enum { Check = 0 }; }; /** * Tuple holding references */ template struct Ref_tuple : public Type_tuple { typename Trait::Reference::Type _1; typename Trait::Reference::Type _2; Ref_tuple(typename Trait::Reference::Type v1, typename Trait::Reference::Type v2) : _1(v1), _2(v2) { } typename Trait::Reference::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 struct Ref_tuple : public Type_tuple { HEAD *_1; typename Trait::Reference::Type _2; Ref_tuple(HEAD *v1, typename Trait::Reference::Type v2) : _1(v1), _2(v2) { } typename Trait::Reference::Type get() { return *_1; } }; template struct Ref_tuple_3 : public Ref_tuple > { Ref_tuple _t2; Ref_tuple_3(typename Trait::Reference::Type v1, typename Trait::Reference::Type v2, typename Trait::Reference::Type v3) : Ref_tuple >(v1, _t2), _t2(v2, v3) { } }; template struct Ref_tuple_4 : public Ref_tuple > { Ref_tuple_3 _t2; Ref_tuple_4(typename Trait::Reference::Type v1, typename Trait::Reference::Type v2, typename Trait::Reference::Type v3, typename Trait::Reference::Type v4) : Ref_tuple >(v1, _t2), _t2(v2, v3, v4) { } }; template struct Ref_tuple_5 : public Ref_tuple > { Ref_tuple_4 _t2; Ref_tuple_5(typename Trait::Reference::Type v1, typename Trait::Reference::Type v2, typename Trait::Reference::Type v3, typename Trait::Reference::Type v4, typename Trait::Reference::Type v5) : Ref_tuple >(v1, _t2), _t2(v2, v3, v4, v5) { } }; template struct Ref_tuple_6 : public Ref_tuple > { Ref_tuple_5 _t2; Ref_tuple_6(typename Trait::Reference::Type v1, typename Trait::Reference::Type v2, typename Trait::Reference::Type v3, typename Trait::Reference::Type v4, typename Trait::Reference::Type v5, typename Trait::Reference::Type v6) : Ref_tuple >(v1, _t2), _t2(v2, v3, v4, v5, v6) { } }; template struct Ref_tuple_7 : public Ref_tuple > { Ref_tuple_6 _t2; Ref_tuple_7(typename Trait::Reference::Type v1, typename Trait::Reference::Type v2, typename Trait::Reference::Type v3, typename Trait::Reference::Type v4, typename Trait::Reference::Type v5, typename Trait::Reference::Type v6, typename Trait::Reference::Type v7) : Ref_tuple >(v1, _t2), _t2(v2, v3, v4, v5, v6, v7) { } }; template struct Ref_tuple_8 : public Ref_tuple > { Ref_tuple_7 _t2; Ref_tuple_8(typename Trait::Reference::Type v1, typename Trait::Reference::Type v2, typename Trait::Reference::Type v3, typename Trait::Reference::Type v4, typename Trait::Reference::Type v5, typename Trait::Reference::Type v6, typename Trait::Reference::Type v7, typename Trait::Reference::Type v8) : Ref_tuple >(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 struct Pod_tuple { typedef typename Trait::Pod::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 struct Pod_tuple { typedef typename Trait::Non_reference::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 struct Ref_args; template <> struct Ref_args { typedef Empty Type; }; template struct Ref_args { typedef Ref_tuple Type; }; template struct Ref_args { typedef Ref_tuple_3 Type; }; template struct Ref_args { typedef Ref_tuple_4 Type; }; template struct Ref_args { typedef Ref_tuple_5 Type; }; template struct Ref_args { typedef Ref_tuple_6 Type; }; template struct Ref_args { typedef Ref_tuple_7 Type; }; template struct Ref_args { typedef Ref_tuple_8 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 struct Pod_args; template <> struct Pod_args { typedef Empty Type; }; template struct Pod_args { typedef Pod_tuple Type; }; template struct Pod_args { typedef Pod_tuple::Type> Type; }; template struct Pod_args { typedef Pod_tuple::Type> Type; }; template struct Pod_args { typedef Pod_tuple::Type> Type; }; template struct Pod_args { typedef Pod_tuple::Type> Type; }; template struct Pod_args { typedef Pod_tuple::Type> Type; }; template struct Pod_args { typedef Pod_tuple::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 static inline RET_TYPE call_member(SERVER &server, ARGS &, RET_TYPE (SERVER::*func)()) { return (server.*func)(); } template static inline RET_TYPE call_member(SERVER &server, ARGS &, RET_TYPE (SERVER::*func)() const) { return (server.*func)(); } template static inline RET_TYPE call_member(SERVER &server, ARGS &, void (SERVER::*func)()) { (server.*func)(); return Empty(); } template static inline RET_TYPE call_member(SERVER &server, ARGS &, void (SERVER::*func)() const) { (server.*func)(); return Empty(); } /* 1 */ template static inline RET_TYPE call_member(SERVER &server, ARGS &args, RET_TYPE (SERVER::*func)(typename Type_at::Type)) { return (server.*func)(args.get()); } template static inline RET_TYPE call_member(SERVER &server, ARGS &args, void (SERVER::*func)(typename Type_at::Type)) { (server.*func)(args.get()); return Empty(); } /* 2 */ template static inline RET_TYPE call_member(SERVER &server, ARGS &args, RET_TYPE (SERVER::*func)(typename Type_at::Type, typename Type_at::Type)) { return (server.*func)(args.get(), args._2.get()); } template static inline RET_TYPE call_member(SERVER &server, ARGS &args, void (SERVER::*func)(typename Type_at::Type, typename Type_at::Type)) { (server.*func)(args.get(), args._2.get()); return Empty(); } /* 3 */ template static inline RET_TYPE call_member(SERVER &server, ARGS &args, RET_TYPE (SERVER::*func)(typename Type_at::Type, typename Type_at::Type, typename Type_at::Type)) { return (server.*func)(args.get(), args._2.get(), args._2._2.get()); } template static inline RET_TYPE call_member(SERVER &server, ARGS &args, void (SERVER::*func)(typename Type_at::Type, typename Type_at::Type, typename Type_at::Type)) { (server.*func)(args.get(), args._2.get(), args._2._2.get()); return Empty(); } /* 4 */ template static inline RET_TYPE call_member(SERVER &server, ARGS &args, RET_TYPE (SERVER::*func)(typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type)) { return (server.*func)(args.get(), args._2.get(), args._2._2.get(), args._2._2._2.get()); } template static inline RET_TYPE call_member(SERVER &server, ARGS &args, void (SERVER::*func)(typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type)) { (server.*func)(args.get(), args._2.get(), args._2._2.get(), args._2._2._2.get()); return Empty(); } /* 5 */ template static inline RET_TYPE call_member(SERVER &server, ARGS &args, RET_TYPE (SERVER::*func)(typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::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 static inline RET_TYPE call_member(SERVER &server, ARGS &args, void (SERVER::*func)(typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::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 static inline RET_TYPE call_member(SERVER &server, ARGS &args, RET_TYPE (SERVER::*func)(typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::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 static inline RET_TYPE call_member(SERVER &server, ARGS &args, void (SERVER::*func)(typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::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 static inline RET_TYPE call_member(SERVER &server, ARGS &args, RET_TYPE (SERVER::*func)(typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::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 static inline RET_TYPE call_member(SERVER &server, ARGS &args, void (SERVER::*func)(typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::Type, typename Type_at::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 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 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 struct Bool_to_type { enum { V = VALUE }; }; } /* namespace Meta */ namespace Trait { template struct Functor; template struct Functor { static constexpr unsigned long argument_count = sizeof...(ARGS); using Return_type = RET; template struct Argument { static_assert(N < argument_count, "Invalid index"); using Type = typename Meta::Variadic_type_tuple::Type; }; }; } /* namespace Trait */ } #endif /* _INCLUDE__UTIL__META_H_ */