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 
33 namespace boost { namespace parameter { namespace python
34 {
35   namespace python_ = boost::python;
36 }}}
37 
38 namespace boost { namespace parameter { namespace python { namespace aux
39 {
40 
unspecified_type()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   {
convertboost::parameter::python::aux::empty_tag_to_python81       static PyObject* convert(empty_tag)
82       {
83           return python_::xincref(unspecified_type());
84       }
85   };
86 
87 }}}} // namespace boost::parameter::python::aux
88 
89 namespace 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   {
arg_from_pythonboost::python::arg_from_python97       arg_from_python(PyObject* p)
98         : arg_from_python<T>(p)
99         , empty(parameter::python::aux::unspecified_type() == p)
100       {}
101 
convertibleboost::python::arg_from_python102       bool convertible() const
103       {
104           return empty || arg_from_python<T>::convertible();
105       }
106 
operator ()boost::python::arg_from_python107       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 
126 namespace boost { namespace parameter { namespace python {
127 
128 namespace 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>
operator ,boost::parameter::python::aux::no_keywords204       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>
def_combination_aux0(Def def,F f,Iter,End,Keywords const & keywords,mpl::false_)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>
def_combination_aux0(Def def,F f,Iter,End,Keywords const & keywords,mpl::true_)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 
initialize_converter()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>
def_combination_aux(Def def,F f,Iter,End,Keywords const & 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>
def_combination_aux(Def def,F f,End,End,Keywords const & 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>
def_combination_aux(Def def,F f,End,End,no_keywords const &)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   >
def_combination(Def def,Specs *,Bits,Invoker *)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   >
def_combinations(Def def,Specs *,Bits,End,Invoker *)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   >
def_combinations(Def,Specs *,End,End,Invoker *)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   {
call_policies_as_optionsboost::parameter::python::aux::call_policies_as_options333       call_policies_as_options(CallPolicies const& call_policies)
334         : call_policies(call_policies)
335       {}
336 
policiesboost::parameter::python::aux::call_policies_as_options337       CallPolicies const& policies() const
338       {
339           return call_policies;
340       }
341 
docboost::parameter::python::aux::call_policies_as_options342       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   {
def_classboost::parameter::python::aux::def_class353       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>
defboost::parameter::python::aux::def_class360       void def(F f, not_specified const*) const
361       {
362           cl.def(name, f);
363       }
364 
365       template <class F>
defboost::parameter::python::aux::def_class366       void def(F f, void const*) const
367       {
368           cl.def(name, f, options.doc(), options.policies());
369       }
370 
371       template <class F>
operator ()boost::parameter::python::aux::def_class372       void operator()(F f) const
373       {
374           this->def(f, &options);
375       }
376 
377       template <class F, class Keywords>
defboost::parameter::python::aux::def_class378       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>
defboost::parameter::python::aux::def_class384       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>
operator ()boost::parameter::python::aux::def_class390       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   {
def_initboost::parameter::python::aux::def_init403       def_init(Class& cl, CallPolicies call_policies = CallPolicies())
404         : cl(cl)
405         , call_policies(call_policies)
406       {}
407 
408       template <class F>
operator ()boost::parameter::python::aux::def_init409       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>
operator ()boost::parameter::python::aux::def_init418       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   {
def_functionboost::parameter::python::aux::def_function432       def_function(char const* name)
433         : name(name)
434       {}
435 
436       template <class F>
operator ()boost::parameter::python::aux::def_function437       void operator()(F f) const
438       {
439           boost::python::def(name, f);
440       }
441 
442       template <class F, class Keywords>
operator ()boost::parameter::python::aux::def_function443       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 
453 template <class M, class Signature>
def(char const * name,Signature)454 void 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 
487 template <class M, class Class, class Signature>
def(Class & cl,char const * name,Signature)488 void 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 
521 namespace 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 
582 template <class ParameterSpecs, class CallPolicies = boost::python::default_call_policies>
583 struct init
584   : boost::python::def_visitor<init<ParameterSpecs, CallPolicies> >
585 {
initboost::parameter::python::init586     init(CallPolicies call_policies = CallPolicies())
587       : call_policies(call_policies)
588     {}
589 
590     template <class CallPolicies1>
591     init<ParameterSpecs, CallPolicies1>
operator []boost::parameter::python::init592     operator[](CallPolicies1 const& call_policies) const
593     {
594         return init<ParameterSpecs, CallPolicies1>(call_policies);
595     }
596 
597     template <class Class>
visit_auxboost::parameter::python::init598     void visit_aux(Class& cl, mpl::true_) const
599     {
600         cl.def(boost::python::init<>()[call_policies]);
601     }
602 
603     template <class Class>
visit_auxboost::parameter::python::init604     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>
visitboost::parameter::python::init629     void visit(Class& cl) const
630     {
631         visit_aux(cl, mpl::empty<ParameterSpecs>());
632     }
633 
634     CallPolicies call_policies;
635 };
636 
637 template <class ParameterSpecs, class CallPolicies = boost::python::default_call_policies>
638 struct call
639   : boost::python::def_visitor<call<ParameterSpecs, CallPolicies> >
640 {
callboost::parameter::python::call641     call(CallPolicies const& call_policies = CallPolicies())
642       : call_policies(call_policies)
643     {}
644 
645     template <class CallPolicies1>
646     call<ParameterSpecs, CallPolicies1>
operator []boost::parameter::python::call647     operator[](CallPolicies1 const& call_policies) const
648     {
649         return call<ParameterSpecs, CallPolicies1>(call_policies);
650     }
651 
652     template <class Class>
visitboost::parameter::python::call653     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 
691 template <class Fwd, class ParameterSpecs>
692 struct function
693   : boost::python::def_visitor<function<Fwd, ParameterSpecs> >
694 {
695     template <class Class, class Options>
visitboost::parameter::python::function696     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