1// Copyright Daniel Wallin 2006. Use, modification and distribution is
2// subject to the Boost Software License, Version 1.0. (See accompanying
3// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4
5#ifndef BOOST_PARAMETER_PYTHON_060209_HPP
6# define BOOST_PARAMETER_PYTHON_060209_HPP
7
8# include <boost/mpl/vector.hpp>
9# include <boost/mpl/fold.hpp>
10# include <boost/mpl/prior.hpp>
11# include <boost/mpl/shift_right.hpp>
12# include <boost/mpl/shift_left.hpp>
13# include <boost/mpl/bitand.hpp>
14# include <boost/mpl/pair.hpp>
15# include <boost/mpl/size.hpp>
16# include <boost/mpl/push_back.hpp>
17# include <boost/mpl/or.hpp>
18# include <boost/mpl/count_if.hpp>
19# include <boost/mpl/transform.hpp>
20# include <boost/mpl/front.hpp>
21# include <boost/mpl/iterator_range.hpp>
22# include <boost/mpl/next.hpp>
23# include <boost/mpl/begin_end.hpp>
24# include <boost/mpl/not.hpp>
25# include <boost/mpl/empty.hpp>
26# include <boost/python/def.hpp>
27# include <boost/python/make_constructor.hpp>
28# include <boost/python/init.hpp>
29# include <boost/python/to_python_converter.hpp>
30# include <boost/parameter/aux_/maybe.hpp>
31# include <boost/parameter/aux_/python/invoker.hpp>
32
33namespace boost { namespace parameter { namespace python
34{
35 namespace python_ = boost::python;
36}}}
37
38namespace boost { namespace parameter { namespace python { namespace aux
39{
40
41 inline PyObject* unspecified_type()
42 {
43 static PyTypeObject unspecified = {
44 PyObject_HEAD_INIT(NULL)
45 0, /* ob_size */
46 "Boost.Parameter.Unspecified", /* tp_name */
47 PyType_Type.tp_basicsize, /* tp_basicsize */
48 0, /* tp_itemsize */
49 0, /* tp_dealloc */
50 0, /* tp_print */
51 0, /* tp_getattr */
52 0, /* tp_setattr */
53 0, /* tp_compare */
54 0, /* tp_repr */
55 0, /* tp_as_number */
56 0, /* tp_as_sequence */
57 0, /* tp_as_mapping */
58 0, /* tp_hash */
59 0, /* tp_call */
60 0, /* tp_str */
61 0, /* tp_getattro */
62 0, /* tp_setattro */
63 0, /* tp_as_buffer */
64 Py_TPFLAGS_DEFAULT, /* tp_flags */
65 0, /* tp_doc */
66 };
67
68 if (unspecified.ob_type == 0)
69 {
70 unspecified.ob_type = &PyType_Type;
71 PyType_Ready(&unspecified);
72 }
73
74 return (PyObject*)&unspecified;
75 }
76
77 struct empty_tag {};
78
79 struct empty_tag_to_python
80 {
81 static PyObject* convert(empty_tag)
82 {
83 return python_::xincref(unspecified_type());
84 }
85 };
86
87}}}} // namespace boost::parameter::python::aux
88
89namespace boost { namespace python
90{
91
92 // Converts a Python value to a maybe<T>
93 template <class T>
94 struct arg_from_python<parameter::aux::maybe<T> >
95 : arg_from_python<T>
96 {
97 arg_from_python(PyObject* p)
98 : arg_from_python<T>(p)
99 , empty(parameter::python::aux::unspecified_type() == p)
100 {}
101
102 bool convertible() const
103 {
104 return empty || arg_from_python<T>::convertible();
105 }
106
107 parameter::aux::maybe<T> operator()()
108 {
109 if (empty)
110 {
111 return parameter::aux::maybe<T>();
112 }
113 else
114 {
115 return parameter::aux::maybe<T>(
116 arg_from_python<T>::operator()()
117 );
118 }
119 }
120
121 bool empty;
122 };
123
124}} // namespace boost::python
125
126namespace boost { namespace parameter { namespace python {
127
128namespace aux
129{
130
131 template <class K>
132 struct is_optional
133 : mpl::not_<
134 mpl::or_<typename K::required, typename K::optimized_default>
135 >
136 {};
137
138 template <class K, class Required, class Optimized, class T>
139 struct arg_spec
140 {
141 typedef K keyword;
142 typedef Required required;
143 typedef T type;
144 typedef Optimized optimized_default;
145 };
146
147 template <class K, class T, class Optimized = mpl::false_>
148 struct make_arg_spec_impl
149 {
150 typedef arg_spec<
151 typename K::first, typename K::second, Optimized, T
152 > type;
153 };
154
155 template <class K, class T>
156 struct make_arg_spec_impl<K, T, typename K::third>
157 {
158 typedef arg_spec<
159 typename K::first, typename K::second, typename K::third, T
160 > type;
161 };
162
163 template <class K, class T>
164 struct make_arg_spec
165 : make_arg_spec_impl<K, T>
166 {
167 };
168
169 template <class Spec, class State>
170 struct combinations_op
171 {
172 typedef typename State::second bits;
173 typedef typename State::first result0;
174
175 typedef typename mpl::if_<
176 mpl::or_<
177 typename Spec::required
178 , typename Spec::optimized_default
179 , mpl::bitand_<bits, mpl::long_<1> >
180 >
181 , typename mpl::push_back<result0, Spec>::type
182 , result0
183 >::type result;
184
185 typedef typename mpl::if_<
186 mpl::or_<
187 typename Spec::required
188 , typename Spec::optimized_default
189 >
190 , bits
191 , typename mpl::shift_right<bits, mpl::long_<1> >::type
192 >::type next_bits;
193
194 typedef mpl::pair<
195 result
196 , next_bits
197 > type;
198 };
199
200 // Used as start value in the recursive arg() composition below.
201 struct no_keywords
202 {
203 template <class T>
204 T const& operator,(T const& x) const
205 {
206 return x;
207 }
208 };
209
210 template <class Def, class F, class Iter, class End, class Keywords>
211 void def_combination_aux0(
212 Def def, F f, Iter, End, Keywords const& keywords, mpl::false_)
213 {
214 typedef typename mpl::deref<Iter>::type spec;
215 typedef typename spec::keyword kw;
216
217 def_combination_aux(
218 def, f, typename mpl::next<Iter>::type(), End()
219 , (
220 keywords, boost::python::arg(kw::keyword_name())
221 )
222 );
223 }
224
225 template <class Def, class F, class Iter, class End, class Keywords>
226 void def_combination_aux0(
227 Def def, F f, Iter, End, Keywords const& keywords, mpl::true_)
228 {
229 typedef typename mpl::deref<Iter>::type spec;
230 typedef typename spec::keyword kw;
231
232 def_combination_aux(
233 def, f, typename mpl::next<Iter>::type(), End()
234 , (
235 keywords, boost::python::arg(kw::keyword_name()) = empty_tag()
236 )
237 );
238 }
239
240 inline void initialize_converter()
241 {
242 static python_::to_python_converter<empty_tag, empty_tag_to_python> x;
243 }
244
245 template <class Def, class F, class Iter, class End, class Keywords>
246 void def_combination_aux(
247 Def def, F f, Iter, End, Keywords const& keywords)
248 {
249 typedef typename mpl::deref<Iter>::type spec;
250
251 typedef typename mpl::and_<
252 typename spec::optimized_default
253 , mpl::not_<typename spec::required>
254 >::type optimized_default;
255
256 def_combination_aux0(
257 def, f, Iter(), End(), keywords, optimized_default()
258 );
259 }
260
261 template <class Def, class F, class End, class Keywords>
262 void def_combination_aux(
263 Def def, F f, End, End, Keywords const& keywords)
264 {
265 def(f, keywords);
266 }
267
268 template <class Def, class F, class End>
269 void def_combination_aux(
270 Def def, F f, End, End, no_keywords const&)
271 {
272 def(f);
273 }
274
275 template <
276 class Def, class Specs, class Bits, class Invoker
277 >
278 void def_combination(
279 Def def, Specs*, Bits, Invoker*)
280 {
281 typedef typename mpl::fold<
282 Specs
283 , mpl::pair<mpl::vector0<>, Bits>
284 , combinations_op<mpl::_2, mpl::_1>
285 >::type combination0;
286
287 typedef typename combination0::first combination;
288
289 typedef typename mpl::apply_wrap1<
290 Invoker, combination
291 >::type invoker;
292
293 def_combination_aux(
294 def
295 , &invoker::execute
296 , typename mpl::begin<combination>::type()
297 , typename mpl::end<combination>::type()
298 , no_keywords()
299 );
300 }
301
302 template <
303 class Def, class Specs, class Bits, class End, class Invoker
304 >
305 void def_combinations(
306 Def def, Specs*, Bits, End, Invoker*)
307 {
308 initialize_converter();
309
310 def_combination(def, (Specs*)0, Bits(), (Invoker*)0);
311
312 def_combinations(
313 def
314 , (Specs*)0
315 , mpl::long_<Bits::value + 1>()
316 , End()
317 , (Invoker*)0
318 );
319 }
320
321 template <
322 class Def, class Specs, class End, class Invoker
323 >
324 void def_combinations(
325 Def, Specs*, End, End, Invoker*)
326 {}
327
328 struct not_specified {};
329
330 template <class CallPolicies>
331 struct call_policies_as_options
332 {
333 call_policies_as_options(CallPolicies const& call_policies)
334 : call_policies(call_policies)
335 {}
336
337 CallPolicies const& policies() const
338 {
339 return call_policies;
340 }
341
342 char const* doc() const
343 {
344 return 0;
345 }
346
347 CallPolicies call_policies;
348 };
349
350 template <class Class, class Options = not_specified>
351 struct def_class
352 {
353 def_class(Class& cl, char const* name, Options options = Options())
354 : cl(cl)
355 , name(name)
356 , options(options)
357 {}
358
359 template <class F>
360 void def(F f, not_specified const*) const
361 {
362 cl.def(name, f);
363 }
364
365 template <class F>
366 void def(F f, void const*) const
367 {
368 cl.def(name, f, options.doc(), options.policies());
369 }
370
371 template <class F>
372 void operator()(F f) const
373 {
374 this->def(f, &options);
375 }
376
377 template <class F, class Keywords>
378 void def(F f, Keywords const& keywords, not_specified const*) const
379 {
380 cl.def(name, f, keywords);
381 }
382
383 template <class F, class Keywords>
384 void def(F f, Keywords const& keywords, void const*) const
385 {
386 cl.def(name, f, keywords, options.doc(), options.policies());
387 }
388
389 template <class F, class Keywords>
390 void operator()(F f, Keywords const& keywords) const
391 {
392 this->def(f, keywords, &options);
393 }
394
395 Class& cl;
396 char const* name;
397 Options options;
398 };
399
400 template <class Class, class CallPolicies = boost::python::default_call_policies>
401 struct def_init
402 {
403 def_init(Class& cl, CallPolicies call_policies = CallPolicies())
404 : cl(cl)
405 , call_policies(call_policies)
406 {}
407
408 template <class F>
409 void operator()(F f) const
410 {
411 cl.def(
412 "__init__"
413 , boost::python::make_constructor(f, call_policies)
414 );
415 }
416
417 template <class F, class Keywords>
418 void operator()(F f, Keywords const& keywords) const
419 {
420 cl.def(
421 "__init__"
422 , boost::python::make_constructor(f, call_policies, keywords)
423 );
424 }
425
426 Class& cl;
427 CallPolicies call_policies;
428 };
429
430 struct def_function
431 {
432 def_function(char const* name)
433 : name(name)
434 {}
435
436 template <class F>
437 void operator()(F f) const
438 {
439 boost::python::def(name, f);
440 }
441
442 template <class F, class Keywords>
443 void operator()(F f, Keywords const& keywords) const
444 {
445 boost::python::def(name, f, keywords);
446 }
447
448 char const* name;
449 };
450
451} // namespace aux
452
453template <class M, class Signature>
454void def(char const* name, Signature)
455{
456 typedef mpl::iterator_range<
457 typename mpl::next<
458 typename mpl::begin<Signature>::type
459 >::type
460 , typename mpl::end<Signature>::type
461 > arg_types;
462
463 typedef typename mpl::transform<
464 typename M::keywords
465 , arg_types
466 , aux::make_arg_spec<mpl::_1, mpl::_2>
467 , mpl::back_inserter<mpl::vector0<> >
468 >::type arg_specs;
469
470 typedef typename mpl::count_if<
471 arg_specs
472 , aux::is_optional<mpl::_1>
473 >::type optional_arity;
474
475 typedef typename mpl::front<Signature>::type result_type;
476 typedef typename mpl::shift_left<mpl::long_<1>, optional_arity>::type upper;
477
478 aux::def_combinations(
479 aux::def_function(name)
480 , (arg_specs*)0
481 , mpl::long_<0>()
482 , mpl::long_<upper::value>()
483 , (aux::make_invoker<M, result_type>*)0
484 );
485}
486
487template <class M, class Class, class Signature>
488void def(Class& cl, char const* name, Signature)
489{
490 typedef mpl::iterator_range<
491 typename mpl::next<
492 typename mpl::begin<Signature>::type
493 >::type
494 , typename mpl::end<Signature>::type
495 > arg_types;
496
497 typedef typename mpl::transform<
498 typename M::keywords
499 , arg_types
500 , aux::make_arg_spec<mpl::_1, mpl::_2>
501 , mpl::back_inserter<mpl::vector0<> >
502 >::type arg_specs;
503
504 typedef typename mpl::count_if<
505 arg_specs
506 , aux::is_optional<mpl::_1>
507 >::type optional_arity;
508
509 typedef typename mpl::front<Signature>::type result_type;
510 typedef typename mpl::shift_left<mpl::long_<1>, optional_arity>::type upper;
511
512 aux::def_combinations(
513 aux::def_class<Class>(cl, name)
514 , (arg_specs*)0
515 , mpl::long_<0>()
516 , mpl::long_<upper::value>()
517 , (aux::make_invoker<M, result_type>*)0
518 );
519}
520
521namespace aux
522{
523
524 template <class K>
525 struct keyword
526 {
527 typedef K type;
528 };
529
530 template <class K>
531 struct keyword<K*>
532 {
533 typedef K type;
534 };
535
536 template <class K>
537 struct keyword<K**>
538 {
539 typedef K type;
540 };
541
542 template <class K>
543 struct required
544 {
545 typedef mpl::true_ type;
546 };
547
548 template <class K>
549 struct required<K*>
550 {
551 typedef mpl::false_ type;
552 };
553
554 template <class K>
555 struct optimized
556 {
557 typedef mpl::true_ type;
558 };
559
560 template <class K>
561 struct optimized<K**>
562 {
563 typedef mpl::false_ type;
564 };
565
566 template <class T>
567 struct make_kw_spec;
568
569 template <class K, class T>
570 struct make_kw_spec<K(T)>
571 {
572 typedef arg_spec<
573 typename keyword<K>::type
574 , typename required<K>::type
575 , typename optimized<K>::type
576 , T
577 > type;
578 };
579
580} // namespace aux
581
582template <class ParameterSpecs, class CallPolicies = boost::python::default_call_policies>
583struct init
584 : boost::python::def_visitor<init<ParameterSpecs, CallPolicies> >
585{
586 init(CallPolicies call_policies = CallPolicies())
587 : call_policies(call_policies)
588 {}
589
590 template <class CallPolicies1>
591 init<ParameterSpecs, CallPolicies1>
592 operator[](CallPolicies1 const& call_policies) const
593 {
594 return init<ParameterSpecs, CallPolicies1>(call_policies);
595 }
596
597 template <class Class>
598 void visit_aux(Class& cl, mpl::true_) const
599 {
600 cl.def(boost::python::init<>()[call_policies]);
601 }
602
603 template <class Class>
604 void visit_aux(Class& cl, mpl::false_) const
605 {
606 typedef typename mpl::transform<
607 ParameterSpecs
608 , aux::make_kw_spec<mpl::_>
609 , mpl::back_inserter<mpl::vector0<> >
610 >::type arg_specs;
611
612 typedef typename mpl::count_if<
613 arg_specs
614 , aux::is_optional<mpl::_>
615 >::type optional_arity;
616
617 typedef typename mpl::shift_left<mpl::long_<1>, optional_arity>::type upper;
618
619 aux::def_combinations(
620 aux::def_init<Class, CallPolicies>(cl, call_policies)
621 , (arg_specs*)0
622 , mpl::long_<0>()
623 , mpl::long_<upper::value>()
624 , (aux::make_init_invoker<typename Class::wrapped_type>*)0
625 );
626 }
627
628 template <class Class>
629 void visit(Class& cl) const
630 {
631 visit_aux(cl, mpl::empty<ParameterSpecs>());
632 }
633
634 CallPolicies call_policies;
635};
636
637template <class ParameterSpecs, class CallPolicies = boost::python::default_call_policies>
638struct call
639 : boost::python::def_visitor<call<ParameterSpecs, CallPolicies> >
640{
641 call(CallPolicies const& call_policies = CallPolicies())
642 : call_policies(call_policies)
643 {}
644
645 template <class CallPolicies1>
646 call<ParameterSpecs, CallPolicies1>
647 operator[](CallPolicies1 const& call_policies) const
648 {
649 return call<ParameterSpecs, CallPolicies1>(call_policies);
650 }
651
652 template <class Class>
653 void visit(Class& cl) const
654 {
655 typedef mpl::iterator_range<
656 typename mpl::next<
657 typename mpl::begin<ParameterSpecs>::type
658 >::type
659 , typename mpl::end<ParameterSpecs>::type
660 > arg_types;
661
662 typedef typename mpl::front<ParameterSpecs>::type result_type;
663
664 typedef typename mpl::transform<
665 arg_types
666 , aux::make_kw_spec<mpl::_>
667 , mpl::back_inserter<mpl::vector0<> >
668 >::type arg_specs;
669
670 typedef typename mpl::count_if<
671 arg_specs
672 , aux::is_optional<mpl::_>
673 >::type optional_arity;
674
675 typedef typename mpl::shift_left<mpl::long_<1>, optional_arity>::type upper;
676
677 typedef aux::call_policies_as_options<CallPolicies> options;
678
679 aux::def_combinations(
680 aux::def_class<Class, options>(cl, "__call__", options(call_policies))
681 , (arg_specs*)0
682 , mpl::long_<0>()
683 , mpl::long_<upper::value>()
684 , (aux::make_call_invoker<typename Class::wrapped_type, result_type>*)0
685 );
686 }
687
688 CallPolicies call_policies;
689};
690
691template <class Fwd, class ParameterSpecs>
692struct function
693 : boost::python::def_visitor<function<Fwd, ParameterSpecs> >
694{
695 template <class Class, class Options>
696 void visit(Class& cl, char const* name, Options const& options) const
697 {
698 typedef mpl::iterator_range<
699 typename mpl::next<
700 typename mpl::begin<ParameterSpecs>::type
701 >::type
702 , typename mpl::end<ParameterSpecs>::type
703 > arg_types;
704
705 typedef typename mpl::front<ParameterSpecs>::type result_type;
706
707 typedef typename mpl::transform<
708 arg_types
709 , aux::make_kw_spec<mpl::_>
710 , mpl::back_inserter<mpl::vector0<> >
711 >::type arg_specs;
712
713 typedef typename mpl::count_if<
714 arg_specs
715 , aux::is_optional<mpl::_>
716 >::type optional_arity;
717
718 typedef typename mpl::shift_left<mpl::long_<1>, optional_arity>::type upper;
719
720 aux::def_combinations(
721 aux::def_class<Class, Options>(cl, name, options)
722 , (arg_specs*)0
723 , mpl::long_<0>()
724 , mpl::long_<upper::value>()
725 , (aux::make_member_invoker<
726 Fwd, result_type, typename Class::wrapped_type
727 >*)0
728 );
729 }
730};
731
732}}} // namespace boost::parameter::python
733
734#endif // BOOST_PARAMETER_PYTHON_060209_HPP
735
736

source code of boost/boost/parameter/python.hpp