]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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] 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 | { | |
99 | init_base(char const* doc_, detail::keyword_range const& keywords_) | |
100 | : m_doc(doc_), m_keywords(keywords_) | |
101 | {} | |
102 | ||
103 | init_base(char const* doc_) | |
104 | : m_doc(doc_) | |
105 | {} | |
106 | ||
107 | DerivedT const& derived() const | |
108 | { | |
109 | return *static_cast<DerivedT const*>(this); | |
110 | } | |
111 | ||
112 | char const* doc_string() const | |
113 | { | |
114 | return m_doc; | |
115 | } | |
116 | ||
117 | detail::keyword_range const& keywords() const | |
118 | { | |
119 | return m_keywords; | |
120 | } | |
121 | ||
122 | 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> | |
143 | 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 | ||
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 | ||
184 | 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 | ||
216 | init(char const* doc_ = 0) | |
217 | : base(doc_) | |
218 | { | |
219 | } | |
220 | ||
221 | template <std::size_t N> | |
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> | |
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> | |
241 | 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> | |
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> | |
336 | 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> | |
369 | 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 |