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