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