#if !defined(BOOST_PP_IS_ITERATING) // Copyright David Abrahams 2002. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) # ifndef CALLER_DWA20021121_HPP # define CALLER_DWA20021121_HPP # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include namespace boost { namespace python { namespace detail { template inline PyObject* get(mpl::int_, PyObject* const& args_) { return PyTuple_GET_ITEM(args_,N); } inline Py_ssize_t arity(PyObject* const& args_) { return PyTuple_GET_SIZE(args_); } // This "result converter" is really just used as // a dispatch tag to invoke(...), selecting the appropriate // implementation typedef int void_result_to_python; // Given a model of CallPolicies and a C++ result type, this // metafunction selects the appropriate converter to use for // converting the result to python. template struct select_result_converter : mpl::eval_if< is_same , mpl::identity , mpl::apply1 > { }; template inline ResultConverter create_result_converter( ArgPackage const& args_ , ResultConverter* , converter::context_result_converter* ) { return ResultConverter(args_); } template inline ResultConverter create_result_converter( ArgPackage const& , ResultConverter* , ... ) { return ResultConverter(); } #ifndef BOOST_PYTHON_NO_PY_SIGNATURES template struct converter_target_type { static PyTypeObject const *get_pytype() { return create_result_converter((PyObject*)0, (ResultConverter *)0, (ResultConverter *)0).get_pytype(); } }; template < > struct converter_target_type { static PyTypeObject const *get_pytype() { return 0; } }; // Generation of ret moved from caller_arity::impl::signature to here due to "feature" in MSVC 15.7.2 with /O2 // which left the ret uninitialized and caused segfaults in Python interpreter. template const signature_element* get_ret() { typedef BOOST_DEDUCED_TYPENAME Policies::template extract_return_type::type rtype; typedef typename select_result_converter::type result_converter; static const signature_element ret = { (is_void::value ? "void" : type_id().name()) , &detail::converter_target_type::get_pytype , boost::detail::indirect_traits::is_reference_to_non_const::value }; return &ret; } #endif template struct caller_arity; template struct caller; # define BOOST_PYTHON_NEXT(init,name,n) \ typedef BOOST_PP_IF(n,typename mpl::next< BOOST_PP_CAT(name,BOOST_PP_DEC(n)) >::type, init) name##n; # define BOOST_PYTHON_ARG_CONVERTER(n) \ BOOST_PYTHON_NEXT(typename mpl::next::type, arg_iter,n) \ typedef arg_from_python c_t##n; \ c_t##n c##n(get(mpl::int_(), inner_args)); \ if (!c##n.convertible()) \ return 0; # define BOOST_PP_ITERATION_PARAMS_1 \ (3, (0, BOOST_PYTHON_MAX_ARITY + 1, )) # include BOOST_PP_ITERATE() # undef BOOST_PYTHON_ARG_CONVERTER # undef BOOST_PYTHON_NEXT // A metafunction returning the base class used for caller. template struct caller_base_select { enum { arity = mpl::size::value - 1 }; typedef typename caller_arity::template impl type; }; // A function object type which wraps C++ objects as Python callable // objects. // // Template Arguments: // // F - // the C++ `function object' that will be called. Might // actually be any data for which an appropriate invoke_tag() can // be generated. invoke(...) takes care of the actual invocation syntax. // // CallPolicies - // The precall, postcall, and what kind of resultconverter to // generate for mpl::front::type // // Sig - // The `intended signature' of the function. An MPL sequence // beginning with a result type and continuing with a list of // argument types. template struct caller : caller_base_select::type { typedef typename caller_base_select< F,CallPolicies,Sig >::type base; typedef PyObject* result_type; caller(F f, CallPolicies p) : base(f,p) {} }; }}} // namespace boost::python::detail # endif // CALLER_DWA20021121_HPP #else # define N BOOST_PP_ITERATION() template <> struct caller_arity { template struct impl { impl(F f, Policies p) : m_data(f,p) {} PyObject* operator()(PyObject* args_, PyObject*) // eliminate // this // trailing // keyword dict { typedef typename mpl::begin::type first; typedef typename first::type result_t; typedef typename select_result_converter::type result_converter; typedef typename Policies::argument_package argument_package; argument_package inner_args(args_); # if N # define BOOST_PP_LOCAL_MACRO(i) BOOST_PYTHON_ARG_CONVERTER(i) # define BOOST_PP_LOCAL_LIMITS (0, N-1) # include BOOST_PP_LOCAL_ITERATE() # endif // all converters have been checked. Now we can do the // precall part of the policy if (!m_data.second().precall(inner_args)) return 0; PyObject* result = detail::invoke( detail::invoke_tag() , create_result_converter(args_, (result_converter*)0, (result_converter*)0) , m_data.first() BOOST_PP_ENUM_TRAILING_PARAMS(N, c) ); return m_data.second().postcall(inner_args, result); } static unsigned min_arity() { return N; } static py_func_sig_info signature() { const signature_element * sig = detail::signature::elements(); #ifndef BOOST_PYTHON_NO_PY_SIGNATURES // MSVC 15.7.2, when compiling to /O2 left the static const signature_element ret, // originally defined here, uninitialized. This in turn led to SegFault in Python interpreter. // Issue is resolved by moving the generation of ret to separate function in detail namespace (see above). const signature_element * ret = detail::get_ret(); py_func_sig_info res = {sig, ret }; #else py_func_sig_info res = {sig, sig }; #endif return res; } private: compressed_pair m_data; }; }; #endif // BOOST_PP_IS_ITERATING