From 82d3b85b848fe420b06db214bedc1f9a2f9d75aa Mon Sep 17 00:00:00 2001 From: Jason Newton Date: Sun, 16 Aug 2015 04:51:44 -0700 Subject: [PATCH 1/2] use SFINAE and function_types for signature generation --- include/boost/python/signature.hpp | 216 ++++++++++++++----------------------- 1 file changed, 82 insertions(+), 134 deletions(-) diff --git a/include/boost/python/signature.hpp b/include/boost/python/signature.hpp index f1143e3ab..cfd3bafcb 100644 --- a/include/boost/python/signature.hpp +++ b/include/boost/python/signature.hpp @@ -6,8 +6,6 @@ // http://www.boost.org/LICENSE_1_0.txt) // /////////////////////////////////////////////////////////////////////////////// -#if !defined(BOOST_PP_IS_ITERATING) - # ifndef SIGNATURE_JDG20020813_HPP # define SIGNATURE_JDG20020813_HPP @@ -15,23 +13,19 @@ # include # include - -# include -# include -# include -# include -# include -# include -# include -# include - -# include -# include -# include -# include - -# define BOOST_PYTHON_LIST_INC(n) \ - BOOST_PP_CAT(mpl::vector, BOOST_PP_INC(n)) +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace python { namespace detail { @@ -108,145 +102,99 @@ struct most_derived // // @group { -// 'default' calling convention - -# define BOOST_PYTHON_FN_CC - -# define BOOST_PP_ITERATION_PARAMS_1 \ - (3, (0, BOOST_PYTHON_MAX_ARITY, )) - -# include BOOST_PP_ITERATE() - -# undef BOOST_PYTHON_FN_CC - -// __cdecl calling convention +template +struct is_callable_detect { +private: + typedef char(&yes)[1]; + typedef char(&no)[2]; -# if defined(BOOST_PYTHON_ENABLE_CDECL) + struct Fallback { void operator()(); }; + struct Derived : T, Fallback { }; -# define BOOST_PYTHON_FN_CC __cdecl -# define BOOST_PYTHON_FN_CC_IS_CDECL + template struct Check; -# define BOOST_PP_ITERATION_PARAMS_1 \ - (3, (0, BOOST_PYTHON_MAX_ARITY, )) + template + static yes test(...); -# include BOOST_PP_ITERATE() + template + static no test(Check*); -# undef BOOST_PYTHON_FN_CC -# undef BOOST_PYTHON_FN_CC_IS_CDECL +public: + static const bool value = sizeof(test(0)) == sizeof(yes); +}; -# endif // defined(BOOST_PYTHON_ENABLE_CDECL) +template +struct is_callable + : conditional< + is_class::value, + is_callable_detect, + false_type + >::type +{ }; -// __stdcall calling convention +template +struct get_signature_helper; -# if defined(BOOST_PYTHON_ENABLE_STDCALL) -# define BOOST_PYTHON_FN_CC __stdcall +template +struct get_signature_helper::value>::type>{ + typedef typename function_types::components::types components; -# define BOOST_PP_ITERATION_PARAMS_1 \ - (3, (0, BOOST_PYTHON_MAX_ARITY, )) + inline static components signature(CallableT, Target * = 0){ return components(); } +}; -# include BOOST_PP_ITERATE() -# undef BOOST_PYTHON_FN_CC +#if (__cplusplus > 199711L) && !defined(BOOST_NO_CXX11_LAMBDAS) +template +struct get_signature_helper::value>::type>{ + typedef decltype(&CallableT::operator()) operator_type; + typedef typename function_types::components::types components; -# endif // defined(BOOST_PYTHON_ENABLE_STDCALL) + inline static components signature(CallableT, Target * = 0){ return components(); } +}; +#endif -// __fastcall calling convention +template +struct get_signature_helper::value>::type>{ + typedef typename function_types::components::type>::types components; -# if defined(BOOST_PYTHON_ENABLE_FASTCALL) + inline static components signature(CallableT, Target * = 0){ return components(); } +}; -# define BOOST_PYTHON_FN_CC __fastcall +template +struct get_signature_helper::value>::type>{ + typedef typename function_types::components::types base_components; + typedef typename mpl::at_c::type return_type; + typedef typename decay::type + >::type + >::type class_type; -# define BOOST_PP_ITERATION_PARAMS_1 \ - (3, (0, BOOST_PYTHON_MAX_ARITY, )) + typedef typename mpl::advance_c::type, 2>::type param_types_begin; + typedef typename mpl::end::type param_types_end; + typedef mpl::iterator_range param_types; -# include BOOST_PP_ITERATE() + typedef typename mpl::if_c::value, + class_type, + typename most_derived::type + >::type target_type; -# undef BOOST_PYTHON_FN_CC + typedef mpl::vector result_and_class_type; + typedef mpl::joint_view types_view; -# endif // defined(BOOST_PYTHON_ENABLE_FASTCALL) + typedef typename mpl::reverse_copy > >::type target_components; + typedef target_components components; -# undef BOOST_PYTHON_LIST_INC + inline static components signature(CallableT, Target * = 0){ return components();} +}; -// } +template +inline typename get_signature_helper::components get_signature(CallableT c, Target *p = 0){ + return get_signature_helper::signature(boost::forward(c), p); +} }}} // namespace boost::python::detail # endif // SIGNATURE_JDG20020813_HPP - -// For gcc 4.4 compatability, we must include the -// BOOST_PP_ITERATION_DEPTH test inside an #else clause. -#else // BOOST_PP_IS_ITERATING -#if BOOST_PP_ITERATION_DEPTH() == 1 // defined(BOOST_PP_IS_ITERATING) - -# define N BOOST_PP_ITERATION() - - // as 'get_signature(RT(*)(T0...TN), void* = 0)' is the same - // function as 'get_signature(RT(__cdecl *)(T0...TN), void* = 0)', - // we don't define it twice -# if !defined(BOOST_PYTHON_FN_CC_IS_CDECL) - -template < - class RT BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class T)> -inline BOOST_PYTHON_LIST_INC(N)< - RT BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T)> -get_signature(RT(BOOST_PYTHON_FN_CC *)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)), void* = 0) -{ - return BOOST_PYTHON_LIST_INC(N)< - RT BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T) - >(); -} - -# endif // !defined(BOOST_PYTHON_FN_CC_IS_CDECL) - -# undef N - -# define BOOST_PP_ITERATION_PARAMS_2 \ - (3, (0, 3, )) -# include BOOST_PP_ITERATE() - -#else - -# define N BOOST_PP_RELATIVE_ITERATION(1) -# define Q BOOST_PYTHON_CV_QUALIFIER(BOOST_PP_ITERATION()) - -template < - class RT, class ClassT BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class T)> -inline BOOST_PYTHON_LIST_INC(BOOST_PP_INC(N))< - RT, ClassT& BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T)> -get_signature(RT(BOOST_PYTHON_FN_CC ClassT::*)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)) Q) -{ - return BOOST_PYTHON_LIST_INC(BOOST_PP_INC(N))< - RT, ClassT& BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T) - >(); -} - -template < - class Target - , class RT - , class ClassT - BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, class T) -> -inline BOOST_PYTHON_LIST_INC(BOOST_PP_INC(N))< - RT - , typename most_derived::type& - BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T) -> -get_signature( - RT(BOOST_PYTHON_FN_CC ClassT::*)(BOOST_PP_ENUM_PARAMS_Z(1, N, T)) Q - , Target* -) -{ - return BOOST_PYTHON_LIST_INC(BOOST_PP_INC(N))< - RT - , BOOST_DEDUCED_TYPENAME most_derived::type& - BOOST_PP_ENUM_TRAILING_PARAMS_Z(1, N, T) - >(); -} - -# undef Q -# undef N - -#endif // BOOST_PP_ITERATION_DEPTH() -#endif // !defined(BOOST_PP_IS_ITERATING) From 8568f248d2cefc8066973cfb4eb2f212e8ccab56 Mon Sep 17 00:00:00 2001 From: Jason Newton Date: Sun, 16 Aug 2015 04:59:17 -0700 Subject: [PATCH 2/2] add a test for lambda as member support --- test/class.cpp | 12 +++++++++++- test/class.py | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/test/class.cpp b/test/class.cpp index 078bebdf6..6acaecb48 100644 --- a/test/class.cpp +++ b/test/class.cpp @@ -11,18 +11,28 @@ using namespace boost::python; struct X { int x; - X(int n) : x(n) { } + int foo; + X(int n) : x(n), foo(0){ } }; int x_function(X& x) { return x.x; } +int y_function(X& x) +{ return x.foo++; +} BOOST_PYTHON_MODULE(class_ext) { class_("X", init()); def("x_function", x_function); +#if (__cplusplus > 199711L) && !defined(BOOST_NO_CXX11_LAMBDAS) + def("y_function", [&foo](int) -> int { return foo++; }); +#else + def("y_function", y_function); + +#endif } #include "module_tail.cpp" diff --git a/test/class.py b/test/class.py index d68ff4378..e15bb0d56 100755 --- a/test/class.py +++ b/test/class.py @@ -9,6 +9,10 @@ >>> x = X(42) >>> x_function(x) 42 + >>> y_function(x) + 0 + >>> y_function(x) + 1 Demonstrate extraction in the presence of metaclass changes: