source: NonGTP/Boost/boost/python/detail/caller.hpp @ 857

Revision 857, 6.8 KB checked in by igarcia, 18 years ago (diff)
Line 
1#if !defined(BOOST_PP_IS_ITERATING)
2
3// Copyright David Abrahams 2002.
4// Distributed under the Boost Software License, Version 1.0. (See
5// accompanying file LICENSE_1_0.txt or copy at
6// http://www.boost.org/LICENSE_1_0.txt)
7
8# ifndef CALLER_DWA20021121_HPP
9#  define CALLER_DWA20021121_HPP
10
11#  include <boost/python/type_id.hpp>
12#  include <boost/python/handle.hpp>
13
14#  include <boost/python/detail/invoke.hpp>
15#  include <boost/python/detail/signature.hpp>
16#  include <boost/python/detail/preprocessor.hpp>
17
18#  include <boost/python/arg_from_python.hpp>
19#  include <boost/python/converter/context_result_converter.hpp>
20
21#  include <boost/preprocessor/iterate.hpp>
22#  include <boost/preprocessor/cat.hpp>
23#  include <boost/preprocessor/dec.hpp>
24#  include <boost/preprocessor/if.hpp>
25#  include <boost/preprocessor/iteration/local.hpp>
26#  include <boost/preprocessor/repetition/enum_trailing_params.hpp>
27#  include <boost/preprocessor/repetition/repeat.hpp>
28
29#  include <boost/compressed_pair.hpp>
30
31#  include <boost/type_traits/is_same.hpp>
32#  include <boost/type_traits/is_convertible.hpp>
33
34#  include <boost/mpl/apply.hpp>
35#  include <boost/mpl/eval_if.hpp>
36#  include <boost/mpl/identity.hpp>
37#  include <boost/mpl/size.hpp>
38#  include <boost/mpl/at.hpp>
39#  include <boost/mpl/int.hpp>
40#  include <boost/mpl/next.hpp>
41
42namespace boost { namespace python { namespace detail {
43
44template <int N>
45inline PyObject* get(mpl::int_<N>, PyObject* const& args_)
46{
47    return PyTuple_GET_ITEM(args_,N);
48}
49
50inline unsigned arity(PyObject* const& args_)
51{
52    return PyTuple_GET_SIZE(args_);
53}
54
55// This "result converter" is really just used as
56// a dispatch tag to invoke(...), selecting the appropriate
57// implementation
58typedef int void_result_to_python;
59
60// Given a model of CallPolicies and a C++ result type, this
61// metafunction selects the appropriate converter to use for
62// converting the result to python.
63template <class Policies, class Result>
64struct select_result_converter
65  : mpl::eval_if<
66        is_same<Result,void>
67      , mpl::identity<void_result_to_python>
68      , mpl::apply1<typename Policies::result_converter,Result>
69    >
70{
71};
72
73template <class ArgPackage, class ResultConverter>
74inline ResultConverter create_result_converter(
75    ArgPackage const& args_
76  , ResultConverter*
77  , converter::context_result_converter*
78)
79{
80    return ResultConverter(args_);
81}
82   
83template <class ArgPackage, class ResultConverter>
84inline ResultConverter create_result_converter(
85    ArgPackage const&
86  , ResultConverter*
87  , ...
88)
89{
90    return ResultConverter();
91}
92   
93template <unsigned> struct caller_arity;
94
95template <class F, class CallPolicies, class Sig>
96struct caller;
97
98#  define BOOST_PYTHON_NEXT(init,name,n)                                                        \
99    typedef BOOST_PP_IF(n,typename mpl::next< BOOST_PP_CAT(name,BOOST_PP_DEC(n)) >::type, init) name##n;
100
101#  define BOOST_PYTHON_ARG_CONVERTER(n)                                         \
102     BOOST_PYTHON_NEXT(typename mpl::next<first>::type, arg_iter,n)             \
103     typedef arg_from_python<BOOST_DEDUCED_TYPENAME arg_iter##n::type> c_t##n;  \
104     c_t##n c##n(get(mpl::int_<n>(), inner_args));                              \
105     if (!c##n.convertible())                                                   \
106          return 0;
107
108#  define BOOST_PP_ITERATION_PARAMS_1                                            \
109        (3, (0, BOOST_PYTHON_MAX_ARITY + 1, <boost/python/detail/caller.hpp>))
110#  include BOOST_PP_ITERATE()
111
112#  undef BOOST_PYTHON_ARG_CONVERTER
113#  undef BOOST_PYTHON_NEXT
114
115// A metafunction returning the base class used for caller<class F,
116// class ConverterGenerators, class CallPolicies, class Sig>.
117template <class F, class CallPolicies, class Sig>
118struct caller_base_select
119{
120    enum { arity = mpl::size<Sig>::value - 1 };
121    typedef typename caller_arity<arity>::template impl<F,CallPolicies,Sig> type;
122};
123
124// A function object type which wraps C++ objects as Python callable
125// objects.
126//
127// Template Arguments:
128//
129//   F -
130//      the C++ `function object' that will be called. Might
131//      actually be any data for which an appropriate invoke_tag() can
132//      be generated. invoke(...) takes care of the actual invocation syntax.
133//
134//   CallPolicies -
135//      The precall, postcall, and what kind of resultconverter to
136//      generate for mpl::front<Sig>::type
137//
138//   Sig -
139//      The `intended signature' of the function. An MPL sequence
140//      beginning with a result type and continuing with a list of
141//      argument types.
142template <class F, class CallPolicies, class Sig>
143struct caller
144    : caller_base_select<F,CallPolicies,Sig>::type
145{
146    typedef typename caller_base_select<
147        F,CallPolicies,Sig
148        >::type base;
149
150    typedef PyObject* result_type;
151   
152    caller(F f, CallPolicies p) : base(f,p) {}
153
154};
155
156}}} // namespace boost::python::detail
157
158# endif // CALLER_DWA20021121_HPP
159
160#else
161
162# define N BOOST_PP_ITERATION()
163
164template <>
165struct caller_arity<N>
166{
167    template <class F, class Policies, class Sig>
168    struct impl
169    {
170        impl(F f, Policies p) : m_data(f,p) {}
171
172        PyObject* operator()(PyObject* args_, PyObject*) // eliminate
173                                                         // this
174                                                         // trailing
175                                                         // keyword dict
176        {
177            typedef typename mpl::begin<Sig>::type first;
178            typedef typename first::type result_t;
179            typedef typename select_result_converter<Policies, result_t>::type result_converter;
180            typedef typename Policies::argument_package argument_package;
181           
182            argument_package inner_args(args_);
183
184# if N
185#  define BOOST_PP_LOCAL_MACRO(i) BOOST_PYTHON_ARG_CONVERTER(i)
186#  define BOOST_PP_LOCAL_LIMITS (0, N-1)
187#  include BOOST_PP_LOCAL_ITERATE()
188# endif
189            // all converters have been checked. Now we can do the
190            // precall part of the policy
191            if (!m_data.second().precall(inner_args))
192                return 0;
193
194            PyObject* result = detail::invoke(
195                detail::invoke_tag<result_t,F>()
196              , create_result_converter(args_, (result_converter*)0, (result_converter*)0)
197              , m_data.first()
198                BOOST_PP_ENUM_TRAILING_PARAMS(N, c)
199            );
200           
201            return m_data.second().postcall(inner_args, result);
202        }
203
204        static unsigned min_arity() { return N; }
205       
206        static signature_element const* signature()
207        {
208            return detail::signature<Sig>::elements();
209        }
210       
211     private:
212        compressed_pair<F,Policies> m_data;
213    };
214};
215
216
217
218#endif // BOOST_PP_IS_ITERATING
219
220
Note: See TracBrowser for help on using the repository browser.