1 | // Copyright David Abrahams 2001. |
2 | // Distributed under the Boost Software License, Version 1.0. (See |
3 | // accompanying file LICENSE_1_0.txt or copy at |
4 | // http://www.boost.org/LICENSE_1_0.txt) |
5 | #ifndef MAKE_CONSTRUCTOR_DWA20011221_HPP |
6 | # define MAKE_CONSTRUCTOR_DWA20011221_HPP |
7 | |
8 | # include <boost/python/detail/prefix.hpp> |
9 | |
10 | # include <boost/python/default_call_policies.hpp> |
11 | # include <boost/python/args.hpp> |
12 | # include <boost/python/object_fwd.hpp> |
13 | |
14 | # include <boost/python/object/function_object.hpp> |
15 | # include <boost/python/object/make_holder.hpp> |
16 | # include <boost/python/object/pointer_holder.hpp> |
17 | # include <boost/python/converter/context_result_converter.hpp> |
18 | |
19 | # include <boost/python/detail/caller.hpp> |
20 | # include <boost/python/detail/none.hpp> |
21 | |
22 | # include <boost/mpl/size.hpp> |
23 | # include <boost/mpl/int.hpp> |
24 | # include <boost/mpl/push_front.hpp> |
25 | # include <boost/mpl/pop_front.hpp> |
26 | # include <boost/mpl/assert.hpp> |
27 | |
28 | namespace boost { namespace python { |
29 | |
30 | namespace detail |
31 | { |
32 | template <class T> |
33 | struct install_holder : converter::context_result_converter |
34 | { |
35 | install_holder(PyObject* args_) |
36 | : m_self(PyTuple_GetItem(args_, 0)) {} |
37 | |
38 | PyObject* operator()(T x) const |
39 | { |
40 | dispatch(x, is_pointer<T>()); |
41 | return none(); |
42 | } |
43 | |
44 | private: |
45 | template <class U> |
46 | void dispatch(U* x, mpl::true_) const |
47 | { |
48 | std::auto_ptr<U> owner(x); |
49 | dispatch(owner, mpl::false_()); |
50 | } |
51 | |
52 | template <class Ptr> |
53 | void dispatch(Ptr x, mpl::false_) const |
54 | { |
55 | typedef typename pointee<Ptr>::type value_type; |
56 | typedef objects::pointer_holder<Ptr,value_type> holder; |
57 | typedef objects::instance<holder> instance_t; |
58 | |
59 | void* memory = holder::allocate(this->m_self, offsetof(instance_t, storage), sizeof(holder)); |
60 | try { |
61 | (new (memory) holder(x))->install(this->m_self); |
62 | } |
63 | catch(...) { |
64 | holder::deallocate(this->m_self, memory); |
65 | throw; |
66 | } |
67 | } |
68 | |
69 | PyObject* m_self; |
70 | }; |
71 | |
72 | struct constructor_result_converter |
73 | { |
74 | template <class T> |
75 | struct apply |
76 | { |
77 | typedef install_holder<T> type; |
78 | }; |
79 | }; |
80 | |
81 | template <class BaseArgs, class Offset> |
82 | struct offset_args |
83 | { |
84 | offset_args(BaseArgs base_) : base(base_) {} |
85 | BaseArgs base; |
86 | }; |
87 | |
88 | template <int N, class BaseArgs, class Offset> |
89 | inline PyObject* get(mpl::int_<N>, offset_args<BaseArgs,Offset> const& args_) |
90 | { |
91 | return get(mpl::int_<(N+Offset::value)>(), args_.base); |
92 | } |
93 | |
94 | template <class BaseArgs, class Offset> |
95 | inline unsigned arity(offset_args<BaseArgs,Offset> const& args_) |
96 | { |
97 | return arity(args_.base) - Offset::value; |
98 | } |
99 | |
100 | template <class BasePolicy_ = default_call_policies> |
101 | struct constructor_policy : BasePolicy_ |
102 | { |
103 | constructor_policy(BasePolicy_ base) : BasePolicy_(base) {} |
104 | |
105 | // If the BasePolicy_ supplied a result converter it would be |
106 | // ignored; issue an error if it's not the default. |
107 | BOOST_MPL_ASSERT_MSG( |
108 | (is_same< |
109 | typename BasePolicy_::result_converter |
110 | , default_result_converter |
111 | >::value) |
112 | , MAKE_CONSTRUCTOR_SUPPLIES_ITS_OWN_RESULT_CONVERTER_THAT_WOULD_OVERRIDE_YOURS |
113 | , (typename BasePolicy_::result_converter) |
114 | ); |
115 | typedef constructor_result_converter result_converter; |
116 | typedef offset_args<typename BasePolicy_::argument_package, mpl::int_<1> > argument_package; |
117 | }; |
118 | |
119 | template <class InnerSignature> |
120 | struct outer_constructor_signature |
121 | { |
122 | typedef typename mpl::pop_front<InnerSignature>::type inner_args; |
123 | typedef typename mpl::push_front<inner_args,object>::type outer_args; |
124 | typedef typename mpl::push_front<outer_args,void>::type type; |
125 | }; |
126 | |
127 | // ETI workaround |
128 | template <> |
129 | struct outer_constructor_signature<int> |
130 | { |
131 | typedef int type; |
132 | }; |
133 | |
134 | // |
135 | // These helper functions for make_constructor (below) do the raw work |
136 | // of constructing a Python object from some invokable entity. See |
137 | // <boost/python/detail/caller.hpp> for more information about how |
138 | // the Sig arguments is used. |
139 | // |
140 | // @group make_constructor_aux { |
141 | template <class F, class CallPolicies, class Sig> |
142 | object make_constructor_aux( |
143 | F f // An object that can be invoked by detail::invoke() |
144 | , CallPolicies const& p // CallPolicies to use in the invocation |
145 | , Sig const& // An MPL sequence of argument types expected by F |
146 | ) |
147 | { |
148 | typedef typename outer_constructor_signature<Sig>::type outer_signature; |
149 | |
150 | typedef constructor_policy<CallPolicies> inner_policy; |
151 | |
152 | return objects::function_object( |
153 | f: objects::py_function( |
154 | detail::caller<F,inner_policy,Sig>(f, inner_policy(p)) |
155 | , outer_signature() |
156 | ) |
157 | ); |
158 | } |
159 | |
160 | // As above, except that it accepts argument keywords. NumKeywords |
161 | // is used only for a compile-time assertion to make sure the user |
162 | // doesn't pass more keywords than the function can accept. To |
163 | // disable all checking, pass mpl::int_<0> for NumKeywords. |
164 | template <class F, class CallPolicies, class Sig, class NumKeywords> |
165 | object make_constructor_aux( |
166 | F f |
167 | , CallPolicies const& p |
168 | , Sig const& |
169 | , detail::keyword_range const& kw // a [begin,end) pair of iterators over keyword names |
170 | , NumKeywords // An MPL integral type wrapper: the size of kw |
171 | ) |
172 | { |
173 | enum { arity = mpl::size<Sig>::value - 1 }; |
174 | |
175 | typedef typename detail::error::more_keywords_than_function_arguments< |
176 | NumKeywords::value, arity |
177 | >::too_many_keywords assertion; |
178 | |
179 | typedef typename outer_constructor_signature<Sig>::type outer_signature; |
180 | |
181 | typedef constructor_policy<CallPolicies> inner_policy; |
182 | |
183 | return objects::function_object( |
184 | f: objects::py_function( |
185 | detail::caller<F,inner_policy,Sig>(f, inner_policy(p)) |
186 | , outer_signature() |
187 | ) |
188 | , kw |
189 | ); |
190 | } |
191 | // } |
192 | |
193 | // |
194 | // These dispatch functions are used to discriminate between the |
195 | // cases when the 3rd argument is keywords or when it is a |
196 | // signature. |
197 | // |
198 | // @group Helpers for make_constructor when called with 3 arguments. { |
199 | // |
200 | template <class F, class CallPolicies, class Keywords> |
201 | object make_constructor_dispatch(F f, CallPolicies const& policies, Keywords const& kw, mpl::true_) |
202 | { |
203 | return detail::make_constructor_aux( |
204 | f |
205 | , policies |
206 | , detail::get_signature(f) |
207 | , kw.range() |
208 | , mpl::int_<Keywords::size>() |
209 | ); |
210 | } |
211 | |
212 | template <class F, class CallPolicies, class Signature> |
213 | object make_constructor_dispatch(F f, CallPolicies const& policies, Signature const& sig, mpl::false_) |
214 | { |
215 | return detail::make_constructor_aux( |
216 | f |
217 | , policies |
218 | , sig |
219 | ); |
220 | } |
221 | // } |
222 | } |
223 | |
224 | // These overloaded functions wrap a function or member function |
225 | // pointer as a Python object, using optional CallPolicies, |
226 | // Keywords, and/or Signature. @group { |
227 | // |
228 | template <class F> |
229 | object make_constructor(F f) |
230 | { |
231 | return detail::make_constructor_aux( |
232 | f,default_call_policies(), detail::get_signature(f)); |
233 | } |
234 | |
235 | template <class F, class CallPolicies> |
236 | object make_constructor(F f, CallPolicies const& policies) |
237 | { |
238 | return detail::make_constructor_aux( |
239 | f, policies, detail::get_signature(f)); |
240 | } |
241 | |
242 | template <class F, class CallPolicies, class KeywordsOrSignature> |
243 | object make_constructor( |
244 | F f |
245 | , CallPolicies const& policies |
246 | , KeywordsOrSignature const& keywords_or_signature) |
247 | { |
248 | typedef typename |
249 | detail::is_reference_to_keywords<KeywordsOrSignature&>::type |
250 | is_kw; |
251 | |
252 | return detail::make_constructor_dispatch( |
253 | f |
254 | , policies |
255 | , keywords_or_signature |
256 | , is_kw() |
257 | ); |
258 | } |
259 | |
260 | template <class F, class CallPolicies, class Keywords, class Signature> |
261 | object make_constructor( |
262 | F f |
263 | , CallPolicies const& policies |
264 | , Keywords const& kw |
265 | , Signature const& sig |
266 | ) |
267 | { |
268 | return detail::make_constructor_aux( |
269 | f |
270 | , policies |
271 | , sig |
272 | , kw.range() |
273 | , mpl::int_<Keywords::size>() |
274 | ); |
275 | } |
276 | // } |
277 | |
278 | }} |
279 | |
280 | |
281 | #endif // MAKE_CONSTRUCTOR_DWA20011221_HPP |
282 | |