|
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/type_traits/is_same.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]; |
|
72 }; |
|
73 } |
|
74 |
|
75 // is_optional<T>::value |
|
76 // |
|
77 // This metaprogram checks if T is an optional |
|
78 // |
|
79 #if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) |
|
80 |
|
81 template <class T> |
|
82 struct is_optional { |
|
83 |
|
84 private: |
|
85 |
|
86 template <BOOST_PYTHON_OVERLOAD_TYPES> |
|
87 static boost::type_traits::yes_type f(optional<BOOST_PYTHON_OVERLOAD_ARGS>); |
|
88 static boost::type_traits::no_type f(...); |
|
89 static T t(); |
|
90 |
|
91 public: |
|
92 |
|
93 BOOST_STATIC_CONSTANT( |
|
94 bool, value = |
|
95 sizeof(f(t())) == sizeof(::boost::type_traits::yes_type)); |
|
96 typedef mpl::bool_<value> type; |
|
97 }; |
|
98 |
|
99 #else |
|
100 |
|
101 template <class T> |
|
102 struct is_optional |
|
103 : mpl::false_ |
|
104 {}; |
|
105 |
|
106 template <BOOST_PYTHON_OVERLOAD_TYPES> |
|
107 struct is_optional<optional<BOOST_PYTHON_OVERLOAD_ARGS> > |
|
108 : mpl::true_ |
|
109 {}; |
|
110 |
|
111 #endif |
|
112 |
|
113 template <int NDefaults> |
|
114 struct define_class_init_helper; |
|
115 |
|
116 } // namespace detail |
|
117 |
|
118 template <class DerivedT> |
|
119 struct init_base : def_visitor<DerivedT> |
|
120 { |
|
121 init_base(char const* doc_, detail::keyword_range const& keywords_) |
|
122 : m_doc(doc_), m_keywords(keywords_) |
|
123 {} |
|
124 |
|
125 init_base(char const* doc_) |
|
126 : m_doc(doc_) |
|
127 {} |
|
128 |
|
129 DerivedT const& derived() const |
|
130 { |
|
131 return *static_cast<DerivedT const*>(this); |
|
132 } |
|
133 |
|
134 char const* doc_string() const |
|
135 { |
|
136 return m_doc; |
|
137 } |
|
138 |
|
139 detail::keyword_range const& keywords() const |
|
140 { |
|
141 return m_keywords; |
|
142 } |
|
143 |
|
144 static default_call_policies call_policies() |
|
145 { |
|
146 return default_call_policies(); |
|
147 } |
|
148 |
|
149 private: |
|
150 // visit |
|
151 // |
|
152 // Defines a set of n_defaults + 1 constructors for its |
|
153 // class_<...> argument. Each constructor after the first has |
|
154 // one less argument to its right. Example: |
|
155 // |
|
156 // init<int, optional<char, long, double> > |
|
157 // |
|
158 // Defines: |
|
159 // |
|
160 // __init__(int, char, long, double) |
|
161 // __init__(int, char, long) |
|
162 // __init__(int, char) |
|
163 // __init__(int) |
|
164 template <class classT> |
|
165 void visit(classT& cl) const |
|
166 { |
|
167 typedef typename DerivedT::signature signature; |
|
168 typedef typename DerivedT::n_arguments n_arguments; |
|
169 typedef typename DerivedT::n_defaults n_defaults; |
|
170 |
|
171 detail::define_class_init_helper<n_defaults::value>::apply( |
|
172 cl |
|
173 , derived().call_policies() |
|
174 , signature() |
|
175 , n_arguments() |
|
176 , derived().doc_string() |
|
177 , derived().keywords()); |
|
178 } |
|
179 |
|
180 friend class python::def_visitor_access; |
|
181 |
|
182 private: // data members |
|
183 char const* m_doc; |
|
184 detail::keyword_range m_keywords; |
|
185 }; |
|
186 |
|
187 template <class CallPoliciesT, class InitT> |
|
188 class init_with_call_policies |
|
189 : public init_base<init_with_call_policies<CallPoliciesT, InitT> > |
|
190 { |
|
191 typedef init_base<init_with_call_policies<CallPoliciesT, InitT> > base; |
|
192 public: |
|
193 typedef typename InitT::n_arguments n_arguments; |
|
194 typedef typename InitT::n_defaults n_defaults; |
|
195 typedef typename InitT::signature signature; |
|
196 |
|
197 init_with_call_policies( |
|
198 CallPoliciesT const& policies_ |
|
199 , char const* doc_ |
|
200 , detail::keyword_range const& keywords |
|
201 ) |
|
202 : base(doc_, keywords) |
|
203 , m_policies(policies_) |
|
204 {} |
|
205 |
|
206 CallPoliciesT const& call_policies() const |
|
207 { |
|
208 return this->m_policies; |
|
209 } |
|
210 |
|
211 private: // data members |
|
212 CallPoliciesT m_policies; |
|
213 }; |
|
214 |
|
215 // |
|
216 // drop1<S> is the initial length(S) elements of S |
|
217 // |
|
218 namespace detail |
|
219 { |
|
220 template <class S> |
|
221 struct drop1 |
|
222 : mpl::iterator_range< |
|
223 typename mpl::begin<S>::type |
|
224 , typename mpl::prior< |
|
225 typename mpl::end<S>::type |
|
226 >::type |
|
227 > |
|
228 {}; |
|
229 } |
|
230 |
|
231 template <BOOST_PYTHON_OVERLOAD_TYPES> |
|
232 class init : public init_base<init<BOOST_PYTHON_OVERLOAD_ARGS> > |
|
233 { |
|
234 typedef init_base<init<BOOST_PYTHON_OVERLOAD_ARGS> > base; |
|
235 public: |
|
236 typedef init<BOOST_PYTHON_OVERLOAD_ARGS> self_t; |
|
237 |
|
238 init(char const* doc_ = 0) |
|
239 : base(doc_) |
|
240 { |
|
241 } |
|
242 |
|
243 template <std::size_t N> |
|
244 init(char const* doc_, detail::keywords<N> const& kw) |
|
245 : base(doc_, kw.range()) |
|
246 { |
|
247 typedef typename detail::error::more_keywords_than_init_arguments< |
|
248 N, n_arguments::value |
|
249 >::too_many_keywords assertion; |
|
250 } |
|
251 |
|
252 template <std::size_t N> |
|
253 init(detail::keywords<N> const& kw, char const* doc_ = 0) |
|
254 : base(doc_, kw.range()) |
|
255 { |
|
256 typedef typename detail::error::more_keywords_than_init_arguments< |
|
257 N, n_arguments::value |
|
258 >::too_many_keywords assertion; |
|
259 } |
|
260 |
|
261 template <class CallPoliciesT> |
|
262 init_with_call_policies<CallPoliciesT, self_t> |
|
263 operator[](CallPoliciesT const& policies) const |
|
264 { |
|
265 return init_with_call_policies<CallPoliciesT, self_t>( |
|
266 policies, this->doc_string(), this->keywords()); |
|
267 } |
|
268 |
|
269 typedef detail::type_list<BOOST_PYTHON_OVERLOAD_ARGS> signature_; |
|
270 |
|
271 typedef detail::is_optional< |
|
272 typename mpl::eval_if< |
|
273 mpl::empty<signature_> |
|
274 , mpl::false_ |
|
275 , mpl::back<signature_> |
|
276 >::type |
|
277 > back_is_optional; |
|
278 |
|
279 typedef typename mpl::eval_if< |
|
280 back_is_optional |
|
281 , mpl::back<signature_> |
|
282 , mpl::vector0<> |
|
283 >::type optional_args; |
|
284 |
|
285 typedef typename mpl::eval_if< |
|
286 back_is_optional |
|
287 , mpl::if_< |
|
288 mpl::empty<optional_args> |
|
289 , detail::drop1<signature_> |
|
290 , mpl::joint_view< |
|
291 detail::drop1<signature_> |
|
292 , optional_args |
|
293 > |
|
294 > |
|
295 , signature_ |
|
296 >::type signature; |
|
297 |
|
298 // TODO: static assert to make sure there are no other optional elements |
|
299 |
|
300 // Count the number of default args |
|
301 typedef mpl::size<optional_args> n_defaults; |
|
302 typedef mpl::size<signature> n_arguments; |
|
303 }; |
|
304 |
|
305 /////////////////////////////////////////////////////////////////////////////// |
|
306 // |
|
307 // optional |
|
308 // |
|
309 // optional<T0...TN>::type returns a typelist. |
|
310 // |
|
311 /////////////////////////////////////////////////////////////////////////////// |
|
312 template <BOOST_PYTHON_OVERLOAD_TYPES> |
|
313 struct optional |
|
314 : detail::type_list<BOOST_PYTHON_OVERLOAD_ARGS> |
|
315 { |
|
316 }; |
|
317 |
|
318 namespace detail |
|
319 { |
|
320 template <class ClassT, class CallPoliciesT, class Signature, class NArgs> |
|
321 inline void def_init_aux( |
|
322 ClassT& cl |
|
323 , Signature const& |
|
324 , NArgs |
|
325 , CallPoliciesT const& policies |
|
326 , char const* doc |
|
327 , detail::keyword_range const& keywords_ |
|
328 ) |
|
329 { |
|
330 cl.def( |
|
331 "__init__" |
|
332 , detail::make_keyword_range_constructor<Signature,NArgs>( |
|
333 policies |
|
334 , keywords_ |
|
335 , (typename ClassT::metadata::holder*)0 |
|
336 ) |
|
337 , doc |
|
338 ); |
|
339 } |
|
340 |
|
341 /////////////////////////////////////////////////////////////////////////////// |
|
342 // |
|
343 // define_class_init_helper<N>::apply |
|
344 // |
|
345 // General case |
|
346 // |
|
347 // Accepts a class_ and an arguments list. Defines a constructor |
|
348 // for the class given the arguments and recursively calls |
|
349 // define_class_init_helper<N-1>::apply with one fewer argument (the |
|
350 // rightmost argument is shaved off) |
|
351 // |
|
352 /////////////////////////////////////////////////////////////////////////////// |
|
353 template <int NDefaults> |
|
354 struct define_class_init_helper |
|
355 { |
|
356 |
|
357 template <class ClassT, class CallPoliciesT, class Signature, class NArgs> |
|
358 static void apply( |
|
359 ClassT& cl |
|
360 , CallPoliciesT const& policies |
|
361 , Signature const& args |
|
362 , NArgs |
|
363 , char const* doc |
|
364 , detail::keyword_range keywords) |
|
365 { |
|
366 detail::def_init_aux(cl, args, NArgs(), policies, 0, keywords); |
|
367 |
|
368 if (keywords.second > keywords.first) |
|
369 --keywords.second; |
|
370 |
|
371 typedef typename mpl::prior<NArgs>::type next_nargs; |
|
372 define_class_init_helper<NDefaults-1>::apply( |
|
373 cl, policies, Signature(), next_nargs(), doc, keywords); |
|
374 } |
|
375 }; |
|
376 |
|
377 /////////////////////////////////////////////////////////////////////////////// |
|
378 // |
|
379 // define_class_init_helper<0>::apply |
|
380 // |
|
381 // Terminal case |
|
382 // |
|
383 // Accepts a class_ and an arguments list. Defines a constructor |
|
384 // for the class given the arguments. |
|
385 // |
|
386 /////////////////////////////////////////////////////////////////////////////// |
|
387 template <> |
|
388 struct define_class_init_helper<0> { |
|
389 |
|
390 template <class ClassT, class CallPoliciesT, class Signature, class NArgs> |
|
391 static void apply( |
|
392 ClassT& cl |
|
393 , CallPoliciesT const& policies |
|
394 , Signature const& args |
|
395 , NArgs |
|
396 , char const* doc |
|
397 , detail::keyword_range const& keywords) |
|
398 { |
|
399 detail::def_init_aux(cl, args, NArgs(), policies, doc, keywords); |
|
400 } |
|
401 }; |
|
402 } |
|
403 |
|
404 }} // namespace boost::python |
|
405 |
|
406 #undef BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT |
|
407 #undef BOOST_PYTHON_OVERLOAD_TYPES |
|
408 #undef BOOST_PYTHON_OVERLOAD_ARGS |
|
409 #undef BOOST_PYTHON_IS_OPTIONAL_VALUE |
|
410 #undef BOOST_PYTHON_APPEND_TO_INIT |
|
411 |
|
412 /////////////////////////////////////////////////////////////////////////////// |
|
413 #endif // INIT_JDG20020820_HPP |
|
414 |
|
415 |
|
416 |
|
417 |
|
418 |
|
419 |
|
420 |
|
421 |