• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright David Abrahams 2002, Joel de Guzman, 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 ///////////////////////////////////////////////////////////////////////////////
9 #ifndef INIT_JDG20020820_HPP
10 #define INIT_JDG20020820_HPP
11 
12 # include <boost/python/detail/prefix.hpp>
13 
14 #include <boost/python/detail/type_list.hpp>
15 #include <boost/python/args_fwd.hpp>
16 #include <boost/python/detail/make_keyword_range_fn.hpp>
17 #include <boost/python/def_visitor.hpp>
18 
19 #include <boost/mpl/if.hpp>
20 #include <boost/mpl/eval_if.hpp>
21 #include <boost/mpl/size.hpp>
22 #include <boost/mpl/iterator_range.hpp>
23 #include <boost/mpl/empty.hpp>
24 #include <boost/mpl/begin_end.hpp>
25 #include <boost/mpl/bool.hpp>
26 #include <boost/mpl/prior.hpp>
27 #include <boost/mpl/joint_view.hpp>
28 #include <boost/mpl/back.hpp>
29 
30 #include <boost/python/detail/type_traits.hpp>
31 
32 #include <boost/preprocessor/enum_params_with_a_default.hpp>
33 #include <boost/preprocessor/enum_params.hpp>
34 
35 #include <utility>
36 
37 ///////////////////////////////////////////////////////////////////////////////
38 #define BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT                                \
39     BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(                                        \
40         BOOST_PYTHON_MAX_ARITY,                                                 \
41         class T,                                                                \
42         mpl::void_)                                                             \
43 
44 #define BOOST_PYTHON_OVERLOAD_TYPES                                             \
45     BOOST_PP_ENUM_PARAMS_Z(1,                                                   \
46         BOOST_PYTHON_MAX_ARITY,                                                 \
47         class T)                                                                \
48 
49 #define BOOST_PYTHON_OVERLOAD_ARGS                                              \
50     BOOST_PP_ENUM_PARAMS_Z(1,                                                   \
51         BOOST_PYTHON_MAX_ARITY,                                                 \
52         T)                                                                      \
53 
54 ///////////////////////////////////////////////////////////////////////////////
55 namespace boost { namespace python {
56 
57 template <BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT>
58 class init; // forward declaration
59 
60 
61 template <BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT>
62 struct optional; // forward declaration
63 
64 namespace detail
65 {
66   namespace error
67   {
68     template <int keywords, int init_args>
69     struct more_keywords_than_init_arguments
70     {
71         typedef char too_many_keywords[init_args - keywords >= 0 ? 1 : -1] BOOST_ATTRIBUTE_UNUSED;
72     };
73   }
74 
75   //  is_optional<T>::value
76   //
77   //      This metaprogram checks if T is an optional
78   //
79 
80     template <class T>
81     struct is_optional
82       : mpl::false_
83     {};
84 
85     template <BOOST_PYTHON_OVERLOAD_TYPES>
86     struct is_optional<optional<BOOST_PYTHON_OVERLOAD_ARGS> >
87       : mpl::true_
88     {};
89 
90 
91   template <int NDefaults>
92   struct define_class_init_helper;
93 
94 } // namespace detail
95 
96 template <class DerivedT>
97 struct init_base : def_visitor<DerivedT>
98 {
init_baseboost::python::init_base99     init_base(char const* doc_, detail::keyword_range const& keywords_)
100         : m_doc(doc_), m_keywords(keywords_)
101     {}
102 
init_baseboost::python::init_base103     init_base(char const* doc_)
104         : m_doc(doc_)
105     {}
106 
derivedboost::python::init_base107     DerivedT const& derived() const
108     {
109         return *static_cast<DerivedT const*>(this);
110     }
111 
doc_stringboost::python::init_base112     char const* doc_string() const
113     {
114         return m_doc;
115     }
116 
keywordsboost::python::init_base117     detail::keyword_range const& keywords() const
118     {
119         return m_keywords;
120     }
121 
call_policiesboost::python::init_base122     static default_call_policies call_policies()
123     {
124         return default_call_policies();
125     }
126 
127  private:
128     //  visit
129     //
130     //      Defines a set of n_defaults + 1 constructors for its
131     //      class_<...> argument. Each constructor after the first has
132     //      one less argument to its right. Example:
133     //
134     //          init<int, optional<char, long, double> >
135     //
136     //      Defines:
137     //
138     //          __init__(int, char, long, double)
139     //          __init__(int, char, long)
140     //          __init__(int, char)
141     //          __init__(int)
142     template <class classT>
visitboost::python::init_base143     void visit(classT& cl) const
144     {
145         typedef typename DerivedT::signature signature;
146         typedef typename DerivedT::n_arguments n_arguments;
147         typedef typename DerivedT::n_defaults n_defaults;
148 
149         detail::define_class_init_helper<n_defaults::value>::apply(
150             cl
151           , derived().call_policies()
152           , signature()
153           , n_arguments()
154           , derived().doc_string()
155           , derived().keywords());
156     }
157 
158     friend class python::def_visitor_access;
159 
160  private: // data members
161     char const* m_doc;
162     detail::keyword_range m_keywords;
163 };
164 
165 template <class CallPoliciesT, class InitT>
166 class init_with_call_policies
167     : public init_base<init_with_call_policies<CallPoliciesT, InitT> >
168 {
169     typedef init_base<init_with_call_policies<CallPoliciesT, InitT> > base;
170  public:
171     typedef typename InitT::n_arguments n_arguments;
172     typedef typename InitT::n_defaults n_defaults;
173     typedef typename InitT::signature signature;
174 
init_with_call_policies(CallPoliciesT const & policies_,char const * doc_,detail::keyword_range const & keywords)175     init_with_call_policies(
176         CallPoliciesT const& policies_
177         , char const* doc_
178         , detail::keyword_range const& keywords
179         )
180         : base(doc_, keywords)
181         , m_policies(policies_)
182     {}
183 
call_policies() const184     CallPoliciesT const& call_policies() const
185     {
186         return this->m_policies;
187     }
188 
189  private: // data members
190     CallPoliciesT m_policies;
191 };
192 
193 //
194 // drop1<S> is the initial length(S) elements of S
195 //
196 namespace detail
197 {
198   template <class S>
199   struct drop1
200     : mpl::iterator_range<
201           typename mpl::begin<S>::type
202         , typename mpl::prior<
203               typename mpl::end<S>::type
204           >::type
205       >
206   {};
207 }
208 
209 template <BOOST_PYTHON_OVERLOAD_TYPES>
210 class init : public init_base<init<BOOST_PYTHON_OVERLOAD_ARGS> >
211 {
212     typedef init_base<init<BOOST_PYTHON_OVERLOAD_ARGS> > base;
213  public:
214     typedef init<BOOST_PYTHON_OVERLOAD_ARGS> self_t;
215 
init(char const * doc_=0)216     init(char const* doc_ = 0)
217         : base(doc_)
218     {
219     }
220 
221     template <std::size_t N>
init(char const * doc_,detail::keywords<N> const & kw)222     init(char const* doc_, detail::keywords<N> const& kw)
223         : base(doc_, kw.range())
224     {
225         typedef typename detail::error::more_keywords_than_init_arguments<
226             N, n_arguments::value + 1
227             >::too_many_keywords assertion BOOST_ATTRIBUTE_UNUSED;
228     }
229 
230     template <std::size_t N>
init(detail::keywords<N> const & kw,char const * doc_=0)231     init(detail::keywords<N> const& kw, char const* doc_ = 0)
232         : base(doc_, kw.range())
233     {
234         typedef typename detail::error::more_keywords_than_init_arguments<
235             N, n_arguments::value + 1
236             >::too_many_keywords assertion BOOST_ATTRIBUTE_UNUSED;
237     }
238 
239     template <class CallPoliciesT>
240     init_with_call_policies<CallPoliciesT, self_t>
operator [](CallPoliciesT const & policies) const241     operator[](CallPoliciesT const& policies) const
242     {
243         return init_with_call_policies<CallPoliciesT, self_t>(
244             policies, this->doc_string(), this->keywords());
245     }
246 
247     typedef detail::type_list<BOOST_PYTHON_OVERLOAD_ARGS> signature_;
248 
249     typedef detail::is_optional<
250         typename mpl::eval_if<
251             mpl::empty<signature_>
252           , mpl::false_
253           , mpl::back<signature_>
254         >::type
255     > back_is_optional;
256 
257     typedef typename mpl::eval_if<
258         back_is_optional
259       , mpl::back<signature_>
260       , mpl::vector0<>
261     >::type optional_args;
262 
263     typedef typename mpl::eval_if<
264         back_is_optional
265       , mpl::if_<
266             mpl::empty<optional_args>
267           , detail::drop1<signature_>
268           , mpl::joint_view<
269                 detail::drop1<signature_>
270               , optional_args
271             >
272         >
273       , signature_
274     >::type signature;
275 
276     // TODO: static assert to make sure there are no other optional elements
277 
278     // Count the number of default args
279     typedef mpl::size<optional_args> n_defaults;
280     typedef mpl::size<signature> n_arguments;
281 };
282 
283 ///////////////////////////////////////////////////////////////////////////////
284 //
285 //  optional
286 //
287 //      optional<T0...TN>::type returns a typelist.
288 //
289 ///////////////////////////////////////////////////////////////////////////////
290 template <BOOST_PYTHON_OVERLOAD_TYPES>
291 struct optional
292     : detail::type_list<BOOST_PYTHON_OVERLOAD_ARGS>
293 {
294 };
295 
296 namespace detail
297 {
298   template <class ClassT, class CallPoliciesT, class Signature, class NArgs>
def_init_aux(ClassT & cl,Signature const &,NArgs,CallPoliciesT const & policies,char const * doc,detail::keyword_range const & keywords_)299   inline void def_init_aux(
300       ClassT& cl
301       , Signature const&
302       , NArgs
303       , CallPoliciesT const& policies
304       , char const* doc
305       , detail::keyword_range const& keywords_
306       )
307   {
308       cl.def(
309           "__init__"
310         , detail::make_keyword_range_constructor<Signature,NArgs>(
311               policies
312             , keywords_
313             , (typename ClassT::metadata::holder*)0
314           )
315         , doc
316       );
317   }
318 
319   ///////////////////////////////////////////////////////////////////////////////
320   //
321   //  define_class_init_helper<N>::apply
322   //
323   //      General case
324   //
325   //      Accepts a class_ and an arguments list. Defines a constructor
326   //      for the class given the arguments and recursively calls
327   //      define_class_init_helper<N-1>::apply with one fewer argument (the
328   //      rightmost argument is shaved off)
329   //
330   ///////////////////////////////////////////////////////////////////////////////
331   template <int NDefaults>
332   struct define_class_init_helper
333   {
334 
335       template <class ClassT, class CallPoliciesT, class Signature, class NArgs>
applyboost::python::detail::define_class_init_helper336       static void apply(
337           ClassT& cl
338           , CallPoliciesT const& policies
339           , Signature const& args
340           , NArgs
341           , char const* doc
342           , detail::keyword_range keywords)
343       {
344           detail::def_init_aux(cl, args, NArgs(), policies, doc, keywords);
345 
346           if (keywords.second > keywords.first)
347               --keywords.second;
348 
349           typedef typename mpl::prior<NArgs>::type next_nargs;
350           define_class_init_helper<NDefaults-1>::apply(
351               cl, policies, Signature(), next_nargs(), doc, keywords);
352       }
353   };
354 
355   ///////////////////////////////////////////////////////////////////////////////
356   //
357   //  define_class_init_helper<0>::apply
358   //
359   //      Terminal case
360   //
361   //      Accepts a class_ and an arguments list. Defines a constructor
362   //      for the class given the arguments.
363   //
364   ///////////////////////////////////////////////////////////////////////////////
365   template <>
366   struct define_class_init_helper<0> {
367 
368       template <class ClassT, class CallPoliciesT, class Signature, class NArgs>
applyboost::python::detail::define_class_init_helper369       static void apply(
370           ClassT& cl
371         , CallPoliciesT const& policies
372         , Signature const& args
373         , NArgs
374         , char const* doc
375         , detail::keyword_range const& keywords)
376       {
377           detail::def_init_aux(cl, args, NArgs(), policies, doc, keywords);
378       }
379   };
380 }
381 
382 }} // namespace boost::python
383 
384 #undef BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT
385 #undef BOOST_PYTHON_OVERLOAD_TYPES
386 #undef BOOST_PYTHON_OVERLOAD_ARGS
387 #undef BOOST_PYTHON_IS_OPTIONAL_VALUE
388 #undef BOOST_PYTHON_APPEND_TO_INIT
389 
390 ///////////////////////////////////////////////////////////////////////////////
391 #endif // INIT_JDG20020820_HPP
392 
393 
394 
395 
396 
397 
398 
399 
400