#pragma once #include #include #include #include #include #include #include #include // ms visual c++ (as of 2013) doesn't accept the standard syntax for calling a // templated member function (foo->template bar();) #ifdef _MSC_VER # define FC_CALL_MEMBER_TEMPLATE_KEYWORD #else # define FC_CALL_MEMBER_TEMPLATE_KEYWORD template #endif namespace fc { namespace detail { namespace hana = boost::hana; /// This metafunction determines whether its template argument is an instantiation of fc::optional template struct is_optional : public std::false_type {}; template struct is_optional> : public std::true_type {}; /// This metafunction determines whether all of its template arguments are instantiations of fc::optional template struct all_optionals; template<> struct all_optionals<> : public std::true_type {}; template struct all_optionals : public std::false_type {}; template struct all_optionals, Ts...> : public all_optionals {}; /// A wrapper of std::function allowing callers to omit the last several arguments if those arguments are /// fc::optional types. i.e. given a function taking (int, double, bool, fc::optional, fc::optional), /// whereas normally the last two arguments must be provided, this template allows them to be omitted. /// Note that this only applies to trailing optional arguments, i.e. given a callable taking /// (fc::optional, int, fc::optional), only the last argument can be omitted. template struct optionals_callable : public std::function { using std::function::operator(); /// Overload the function call operator, enabled if the caller provides fewer arguments than there are parameters. /// Pads out the provided arguments with default-constructed optionals, checking that they are indeed optional types template std::enable_if_t operator()(Args... args) { auto arguments = hana::make_tuple(std::forward(args)...); // Get the parameter types corresponding to the omitted arguments auto optional_types = hana::take_back(hana::tuple_t, hana::size_c); // Transform the types into default-constructed values, checking that they are optional types auto optional_values = hana::transform(optional_types, [](auto hanatype) { using type = std::decay_t; static_assert(is_optional::value, "All omitted arguments must correspond to optional parameters."); return type(); }); auto padded_arguments = hana::concat(arguments, optional_values); return hana::unpack(padded_arguments, [this](auto... params) { return (*this)(std::forward(params)...); }); } }; } // This is no longer used and probably no longer can be used without generalizing the infrastructure around it, but I // kept it because it is informative. // struct identity_member { // template // static std::function functor( P&& p, R (C::*mem_func)(Args...) ); // template // static std::function functor( P&& p, R (C::*mem_func)(Args...)const ); // }; /// Used as the Transform template parameter for APIs, this type has two main purposes: first, it reads the argument /// list and return type of a method into template parameters; and second, it uses those types in conjunction with the /// optionals_callable template above to create a function pointer which supports optional arguments. struct identity_member_with_optionals { template static detail::optionals_callable functor( P&& p, R (C::*mem_func)(Args...) ); template static detail::optionals_callable functor( P&& p, R (C::*mem_func)(Args...)const ); }; template< typename Interface, typename Transform > struct vtable : public std::enable_shared_from_this> { private: vtable(); }; template struct vtable_copy_visitor { typedef OtherType other_type; vtable_copy_visitor( OtherType& s):_source( s ){} template void operator()( const char* name, std::function& memb, MemberPtr m )const { OtherType* src = &_source; memb = [src,m]( Args... args ){ return (src->*m)(args...); }; } OtherType& _source; }; template class api; class api_connection; typedef uint32_t api_id_type; class api_base { public: api_base() {} virtual ~api_base() {} virtual uint64_t get_handle()const = 0; virtual api_id_type register_api( api_connection& conn )const = 0; // defined in api_connection.hpp template< typename T > api as(); }; typedef std::shared_ptr< api_base > api_ptr; class api_connection; template class api : public api_base { public: typedef vtable vtable_type; api():_vtable( std::make_shared() ) {} /** T is anything with pointer semantics */ template api( const T& p ) :_vtable( std::make_shared() ) { _data = std::make_shared(p); T& ptr = boost::any_cast(*_data); auto& pointed_at = *ptr; typedef typename std::remove_reference::type source_vtable_type; _vtable->FC_CALL_MEMBER_TEMPLATE_KEYWORD visit_other( vtable_copy_visitor(pointed_at) ); } api( const api& cpy ):_vtable(cpy._vtable),_data(cpy._data) {} virtual ~api() {} friend bool operator == ( const api& a, const api& b ) { return a._data == b._data && a._vtable == b._vtable; } friend bool operator != ( const api& a, const api& b ) { return !(a._data == b._data && a._vtable == b._vtable); } virtual uint64_t get_handle()const override { return uint64_t(_data.get()); } virtual api_id_type register_api( api_connection& conn )const override; // defined in api_connection.hpp vtable_type& operator*()const { FC_ASSERT( _vtable ); return *_vtable; } vtable_type* operator->()const { FC_ASSERT( _vtable ); return _vtable.get(); } protected: std::shared_ptr _vtable; std::shared_ptr _data; }; } // namespace fc #include #include #include #include #include #include #include #define FC_API_VTABLE_DEFINE_MEMBER( r, data, elem ) \ decltype(Transform::functor( (data*)nullptr, &data::elem)) elem; #define FC_API_VTABLE_DEFINE_VISIT_OTHER( r, data, elem ) \ { typedef typename Visitor::other_type OtherType; \ v( BOOST_PP_STRINGIZE(elem), elem, &OtherType::elem ); } #define FC_API_VTABLE_DEFINE_VISIT( r, data, elem ) \ v( BOOST_PP_STRINGIZE(elem), elem ); #define FC_API( CLASS, METHODS ) \ namespace fc { \ template \ struct vtable : public std::enable_shared_from_this> { \ BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_MEMBER, CLASS, METHODS ) \ template \ void visit_other( Visitor&& v ){ \ BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_VISIT_OTHER, CLASS, METHODS ) \ } \ template \ void visit( Visitor&& v ){ \ BOOST_PP_SEQ_FOR_EACH( FC_API_VTABLE_DEFINE_VISIT, CLASS, METHODS ) \ } \ }; \ }