]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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/detail/indirect_traits.hpp> | |
15 | ||
16 | # include <boost/python/detail/invoke.hpp> | |
17 | # include <boost/python/detail/signature.hpp> | |
18 | # include <boost/python/detail/preprocessor.hpp> | |
19 | ||
20 | # include <boost/python/arg_from_python.hpp> | |
21 | # include <boost/python/converter/context_result_converter.hpp> | |
22 | # include <boost/python/converter/builtin_converters.hpp> | |
23 | ||
24 | # include <boost/preprocessor/iterate.hpp> | |
25 | # include <boost/preprocessor/cat.hpp> | |
26 | # include <boost/preprocessor/dec.hpp> | |
27 | # include <boost/preprocessor/if.hpp> | |
28 | # include <boost/preprocessor/iteration/local.hpp> | |
29 | # include <boost/preprocessor/repetition/enum_trailing_params.hpp> | |
30 | # include <boost/preprocessor/repetition/repeat.hpp> | |
31 | ||
32 | # include <boost/compressed_pair.hpp> | |
33 | ||
34 | # include <boost/type_traits/is_same.hpp> | |
35 | # include <boost/type_traits/is_convertible.hpp> | |
36 | ||
37 | # include <boost/mpl/apply.hpp> | |
38 | # include <boost/mpl/eval_if.hpp> | |
39 | # include <boost/mpl/identity.hpp> | |
40 | # include <boost/mpl/size.hpp> | |
41 | # include <boost/mpl/at.hpp> | |
42 | # include <boost/mpl/int.hpp> | |
43 | # include <boost/mpl/next.hpp> | |
44 | ||
45 | namespace boost { namespace python { namespace detail { | |
46 | ||
47 | template <int N> | |
48 | inline PyObject* get(mpl::int_<N>, PyObject* const& args_) | |
49 | { | |
50 | return PyTuple_GET_ITEM(args_,N); | |
51 | } | |
52 | ||
53 | inline unsigned arity(PyObject* const& args_) | |
54 | { | |
55 | return PyTuple_GET_SIZE(args_); | |
56 | } | |
57 | ||
58 | // This "result converter" is really just used as | |
59 | // a dispatch tag to invoke(...), selecting the appropriate | |
60 | // implementation | |
61 | typedef int void_result_to_python; | |
62 | ||
63 | // Given a model of CallPolicies and a C++ result type, this | |
64 | // metafunction selects the appropriate converter to use for | |
65 | // converting the result to python. | |
66 | template <class Policies, class Result> | |
67 | struct select_result_converter | |
68 | : mpl::eval_if< | |
69 | is_same<Result,void> | |
70 | , mpl::identity<void_result_to_python> | |
71 | , mpl::apply1<typename Policies::result_converter,Result> | |
72 | > | |
73 | { | |
74 | }; | |
75 | ||
76 | template <class ArgPackage, class ResultConverter> | |
77 | inline ResultConverter create_result_converter( | |
78 | ArgPackage const& args_ | |
79 | , ResultConverter* | |
80 | , converter::context_result_converter* | |
81 | ) | |
82 | { | |
83 | return ResultConverter(args_); | |
84 | } | |
85 | ||
86 | template <class ArgPackage, class ResultConverter> | |
87 | inline ResultConverter create_result_converter( | |
88 | ArgPackage const& | |
89 | , ResultConverter* | |
90 | , ... | |
91 | ) | |
92 | { | |
93 | return ResultConverter(); | |
94 | } | |
95 | ||
96 | #ifndef BOOST_PYTHON_NO_PY_SIGNATURES | |
97 | template <class ResultConverter> | |
98 | struct converter_target_type | |
99 | { | |
100 | static PyTypeObject const *get_pytype() | |
101 | { | |
102 | return create_result_converter((PyObject*)0, (ResultConverter *)0, (ResultConverter *)0).get_pytype(); | |
103 | } | |
104 | }; | |
105 | ||
106 | template < > | |
107 | struct converter_target_type <void_result_to_python > | |
108 | { | |
109 | static PyTypeObject const *get_pytype() | |
110 | { | |
111 | return 0; | |
112 | } | |
113 | }; | |
114 | #endif | |
115 | ||
116 | ||
117 | template <unsigned> struct caller_arity; | |
118 | ||
119 | template <class F, class CallPolicies, class Sig> | |
120 | struct caller; | |
121 | ||
122 | # define BOOST_PYTHON_NEXT(init,name,n) \ | |
123 | typedef BOOST_PP_IF(n,typename mpl::next< BOOST_PP_CAT(name,BOOST_PP_DEC(n)) >::type, init) name##n; | |
124 | ||
125 | # define BOOST_PYTHON_ARG_CONVERTER(n) \ | |
126 | BOOST_PYTHON_NEXT(typename mpl::next<first>::type, arg_iter,n) \ | |
127 | typedef arg_from_python<BOOST_DEDUCED_TYPENAME arg_iter##n::type> c_t##n; \ | |
128 | c_t##n c##n(get(mpl::int_<n>(), inner_args)); \ | |
129 | if (!c##n.convertible()) \ | |
130 | return 0; | |
131 | ||
132 | # define BOOST_PP_ITERATION_PARAMS_1 \ | |
133 | (3, (0, BOOST_PYTHON_MAX_ARITY + 1, <boost/python/detail/caller.hpp>)) | |
134 | # include BOOST_PP_ITERATE() | |
135 | ||
136 | # undef BOOST_PYTHON_ARG_CONVERTER | |
137 | # undef BOOST_PYTHON_NEXT | |
138 | ||
139 | // A metafunction returning the base class used for caller<class F, | |
140 | // class ConverterGenerators, class CallPolicies, class Sig>. | |
141 | template <class F, class CallPolicies, class Sig> | |
142 | struct caller_base_select | |
143 | { | |
144 | enum { arity = mpl::size<Sig>::value - 1 }; | |
145 | typedef typename caller_arity<arity>::template impl<F,CallPolicies,Sig> type; | |
146 | }; | |
147 | ||
148 | // A function object type which wraps C++ objects as Python callable | |
149 | // objects. | |
150 | // | |
151 | // Template Arguments: | |
152 | // | |
153 | // F - | |
154 | // the C++ `function object' that will be called. Might | |
155 | // actually be any data for which an appropriate invoke_tag() can | |
156 | // be generated. invoke(...) takes care of the actual invocation syntax. | |
157 | // | |
158 | // CallPolicies - | |
159 | // The precall, postcall, and what kind of resultconverter to | |
160 | // generate for mpl::front<Sig>::type | |
161 | // | |
162 | // Sig - | |
163 | // The `intended signature' of the function. An MPL sequence | |
164 | // beginning with a result type and continuing with a list of | |
165 | // argument types. | |
166 | template <class F, class CallPolicies, class Sig> | |
167 | struct caller | |
168 | : caller_base_select<F,CallPolicies,Sig>::type | |
169 | { | |
170 | typedef typename caller_base_select< | |
171 | F,CallPolicies,Sig | |
172 | >::type base; | |
173 | ||
174 | typedef PyObject* result_type; | |
175 | ||
176 | caller(F f, CallPolicies p) : base(f,p) {} | |
177 | ||
178 | }; | |
179 | ||
180 | }}} // namespace boost::python::detail | |
181 | ||
182 | # endif // CALLER_DWA20021121_HPP | |
183 | ||
184 | #else | |
185 | ||
186 | # define N BOOST_PP_ITERATION() | |
187 | ||
188 | template <> | |
189 | struct caller_arity<N> | |
190 | { | |
191 | template <class F, class Policies, class Sig> | |
192 | struct impl | |
193 | { | |
194 | impl(F f, Policies p) : m_data(f,p) {} | |
195 | ||
196 | PyObject* operator()(PyObject* args_, PyObject*) // eliminate | |
197 | // this | |
198 | // trailing | |
199 | // keyword dict | |
200 | { | |
201 | typedef typename mpl::begin<Sig>::type first; | |
202 | typedef typename first::type result_t; | |
203 | typedef typename select_result_converter<Policies, result_t>::type result_converter; | |
204 | typedef typename Policies::argument_package argument_package; | |
205 | ||
206 | argument_package inner_args(args_); | |
207 | ||
208 | # if N | |
209 | # define BOOST_PP_LOCAL_MACRO(i) BOOST_PYTHON_ARG_CONVERTER(i) | |
210 | # define BOOST_PP_LOCAL_LIMITS (0, N-1) | |
211 | # include BOOST_PP_LOCAL_ITERATE() | |
212 | # endif | |
213 | // all converters have been checked. Now we can do the | |
214 | // precall part of the policy | |
215 | if (!m_data.second().precall(inner_args)) | |
216 | return 0; | |
217 | ||
218 | PyObject* result = detail::invoke( | |
219 | detail::invoke_tag<result_t,F>() | |
220 | , create_result_converter(args_, (result_converter*)0, (result_converter*)0) | |
221 | , m_data.first() | |
222 | BOOST_PP_ENUM_TRAILING_PARAMS(N, c) | |
223 | ); | |
224 | ||
225 | return m_data.second().postcall(inner_args, result); | |
226 | } | |
227 | ||
228 | static unsigned min_arity() { return N; } | |
229 | ||
230 | static py_func_sig_info signature() | |
231 | { | |
232 | const signature_element * sig = detail::signature<Sig>::elements(); | |
233 | #ifndef BOOST_PYTHON_NO_PY_SIGNATURES | |
234 | ||
235 | typedef BOOST_DEDUCED_TYPENAME Policies::template extract_return_type<Sig>::type rtype; | |
236 | typedef typename select_result_converter<Policies, rtype>::type result_converter; | |
237 | ||
238 | static const signature_element ret = { | |
239 | (boost::is_void<rtype>::value ? "void" : type_id<rtype>().name()) | |
240 | , &detail::converter_target_type<result_converter>::get_pytype | |
241 | , boost::detail::indirect_traits::is_reference_to_non_const<rtype>::value | |
242 | }; | |
243 | py_func_sig_info res = {sig, &ret }; | |
244 | #else | |
245 | py_func_sig_info res = {sig, sig }; | |
246 | #endif | |
247 | ||
248 | return res; | |
249 | } | |
250 | private: | |
251 | compressed_pair<F,Policies> m_data; | |
252 | }; | |
253 | }; | |
254 | ||
255 | ||
256 | ||
257 | #endif // BOOST_PP_IS_ITERATING | |
258 | ||
259 |