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