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, mpl::true_) const
47       {
48           std::auto_ptr<U> owner(x);
49           dispatch(owner, mpl::false_());
50       }
51 
52       template <class Ptr>
dispatchboost::python::detail::install_holder53       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   {
offset_argsboost::python::detail::offset_args84       offset_args(BaseArgs base_) : base(base_) {}
85       BaseArgs base;
86   };
87 
88   template <int N, class BaseArgs, class Offset>
get(mpl::int_<N>,offset_args<BaseArgs,Offset> const & args_)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>
arity(offset_args<BaseArgs,Offset> const & args_)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   {
constructor_policyboost::python::detail::constructor_policy103       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 #if defined _MSC_VER && _MSC_VER < 1300
108       typedef is_same<
109               typename BasePolicy_::result_converter
110             , default_result_converter
111           > same_result_converter;
112       //see above for explanation
113       BOOST_STATIC_ASSERT(same_result_converter::value) ;
114 #else
115       BOOST_MPL_ASSERT_MSG(
116          (is_same<
117               typename BasePolicy_::result_converter
118             , default_result_converter
119           >::value)
120         , MAKE_CONSTRUCTOR_SUPPLIES_ITS_OWN_RESULT_CONVERTER_THAT_WOULD_OVERRIDE_YOURS
121         , (typename BasePolicy_::result_converter)
122       );
123 #endif
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;
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