| // Copyright Daniel Wallin 2006. Use, modification and distribution is |
| // subject to the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| |
| #ifndef BOOST_PARAMETER_PYTHON_060209_HPP |
| # define BOOST_PARAMETER_PYTHON_060209_HPP |
| |
| # include <boost/mpl/vector.hpp> |
| # include <boost/mpl/fold.hpp> |
| # include <boost/mpl/prior.hpp> |
| # include <boost/mpl/shift_right.hpp> |
| # include <boost/mpl/shift_left.hpp> |
| # include <boost/mpl/bitand.hpp> |
| # include <boost/mpl/pair.hpp> |
| # include <boost/mpl/size.hpp> |
| # include <boost/mpl/push_back.hpp> |
| # include <boost/mpl/or.hpp> |
| # include <boost/mpl/count_if.hpp> |
| # include <boost/mpl/transform.hpp> |
| # include <boost/mpl/front.hpp> |
| # include <boost/mpl/iterator_range.hpp> |
| # include <boost/mpl/next.hpp> |
| # include <boost/mpl/begin_end.hpp> |
| # include <boost/mpl/not.hpp> |
| # include <boost/mpl/empty.hpp> |
| # include <boost/python/def.hpp> |
| # include <boost/python/make_constructor.hpp> |
| # include <boost/python/init.hpp> |
| # include <boost/python/to_python_converter.hpp> |
| # include <boost/parameter/aux_/maybe.hpp> |
| # include <boost/parameter/aux_/python/invoker.hpp> |
| |
| namespace boost { namespace parameter { namespace python |
| { |
| namespace python_ = boost::python; |
| }}} |
| |
| namespace boost { namespace parameter { namespace python { namespace aux |
| { |
| |
| inline PyObject* unspecified_type() |
| { |
| static PyTypeObject unspecified = { |
| PyObject_HEAD_INIT(NULL) |
| 0, /* ob_size */ |
| "Boost.Parameter.Unspecified", /* tp_name */ |
| PyType_Type.tp_basicsize, /* tp_basicsize */ |
| 0, /* tp_itemsize */ |
| 0, /* tp_dealloc */ |
| 0, /* tp_print */ |
| 0, /* tp_getattr */ |
| 0, /* tp_setattr */ |
| 0, /* tp_compare */ |
| 0, /* tp_repr */ |
| 0, /* tp_as_number */ |
| 0, /* tp_as_sequence */ |
| 0, /* tp_as_mapping */ |
| 0, /* tp_hash */ |
| 0, /* tp_call */ |
| 0, /* tp_str */ |
| 0, /* tp_getattro */ |
| 0, /* tp_setattro */ |
| 0, /* tp_as_buffer */ |
| Py_TPFLAGS_DEFAULT, /* tp_flags */ |
| 0, /* tp_doc */ |
| }; |
| |
| if (unspecified.ob_type == 0) |
| { |
| unspecified.ob_type = &PyType_Type; |
| PyType_Ready(&unspecified); |
| } |
| |
| return (PyObject*)&unspecified; |
| } |
| |
| struct empty_tag {}; |
| |
| struct empty_tag_to_python |
| { |
| static PyObject* convert(empty_tag) |
| { |
| return python_::xincref(unspecified_type()); |
| } |
| }; |
| |
| }}}} // namespace boost::parameter::python::aux |
| |
| namespace boost { namespace python |
| { |
| |
| // Converts a Python value to a maybe<T> |
| template <class T> |
| struct arg_from_python<parameter::aux::maybe<T> > |
| : arg_from_python<T> |
| { |
| arg_from_python(PyObject* p) |
| : arg_from_python<T>(p) |
| , empty(parameter::python::aux::unspecified_type() == p) |
| {} |
| |
| bool convertible() const |
| { |
| return empty || arg_from_python<T>::convertible(); |
| } |
| |
| parameter::aux::maybe<T> operator()() |
| { |
| if (empty) |
| { |
| return parameter::aux::maybe<T>(); |
| } |
| else |
| { |
| return parameter::aux::maybe<T>( |
| arg_from_python<T>::operator()() |
| ); |
| } |
| } |
| |
| bool empty; |
| }; |
| |
| }} // namespace boost::python |
| |
| namespace boost { namespace parameter { namespace python { |
| |
| namespace aux |
| { |
| |
| template <class K> |
| struct is_optional |
| : mpl::not_< |
| mpl::or_<typename K::required, typename K::optimized_default> |
| > |
| {}; |
| |
| template <class K, class Required, class Optimized, class T> |
| struct arg_spec |
| { |
| typedef K keyword; |
| typedef Required required; |
| typedef T type; |
| typedef Optimized optimized_default; |
| }; |
| |
| template <class K, class T, class Optimized = mpl::false_> |
| struct make_arg_spec_impl |
| { |
| typedef arg_spec< |
| typename K::first, typename K::second, Optimized, T |
| > type; |
| }; |
| |
| template <class K, class T> |
| struct make_arg_spec_impl<K, T, typename K::third> |
| { |
| typedef arg_spec< |
| typename K::first, typename K::second, typename K::third, T |
| > type; |
| }; |
| |
| template <class K, class T> |
| struct make_arg_spec |
| : make_arg_spec_impl<K, T> |
| { |
| }; |
| |
| template <class Spec, class State> |
| struct combinations_op |
| { |
| typedef typename State::second bits; |
| typedef typename State::first result0; |
| |
| typedef typename mpl::if_< |
| mpl::or_< |
| typename Spec::required |
| , typename Spec::optimized_default |
| , mpl::bitand_<bits, mpl::long_<1> > |
| > |
| , typename mpl::push_back<result0, Spec>::type |
| , result0 |
| >::type result; |
| |
| typedef typename mpl::if_< |
| mpl::or_< |
| typename Spec::required |
| , typename Spec::optimized_default |
| > |
| , bits |
| , typename mpl::shift_right<bits, mpl::long_<1> >::type |
| >::type next_bits; |
| |
| typedef mpl::pair< |
| result |
| , next_bits |
| > type; |
| }; |
| |
| // Used as start value in the recursive arg() composition below. |
| struct no_keywords |
| { |
| template <class T> |
| T const& operator,(T const& x) const |
| { |
| return x; |
| } |
| }; |
| |
| template <class Def, class F, class Iter, class End, class Keywords> |
| void def_combination_aux0( |
| Def def, F f, Iter, End, Keywords const& keywords, mpl::false_) |
| { |
| typedef typename mpl::deref<Iter>::type spec; |
| typedef typename spec::keyword kw; |
| |
| def_combination_aux( |
| def, f, typename mpl::next<Iter>::type(), End() |
| , ( |
| keywords, boost::python::arg(kw::keyword_name()) |
| ) |
| ); |
| } |
| |
| template <class Def, class F, class Iter, class End, class Keywords> |
| void def_combination_aux0( |
| Def def, F f, Iter, End, Keywords const& keywords, mpl::true_) |
| { |
| typedef typename mpl::deref<Iter>::type spec; |
| typedef typename spec::keyword kw; |
| |
| def_combination_aux( |
| def, f, typename mpl::next<Iter>::type(), End() |
| , ( |
| keywords, boost::python::arg(kw::keyword_name()) = empty_tag() |
| ) |
| ); |
| } |
| |
| inline void initialize_converter() |
| { |
| static python_::to_python_converter<empty_tag, empty_tag_to_python> x; |
| } |
| |
| template <class Def, class F, class Iter, class End, class Keywords> |
| void def_combination_aux( |
| Def def, F f, Iter, End, Keywords const& keywords) |
| { |
| typedef typename mpl::deref<Iter>::type spec; |
| |
| typedef typename mpl::and_< |
| typename spec::optimized_default |
| , mpl::not_<typename spec::required> |
| >::type optimized_default; |
| |
| def_combination_aux0( |
| def, f, Iter(), End(), keywords, optimized_default() |
| ); |
| } |
| |
| template <class Def, class F, class End, class Keywords> |
| void def_combination_aux( |
| Def def, F f, End, End, Keywords const& keywords) |
| { |
| def(f, keywords); |
| } |
| |
| template <class Def, class F, class End> |
| void def_combination_aux( |
| Def def, F f, End, End, no_keywords const&) |
| { |
| def(f); |
| } |
| |
| template < |
| class Def, class Specs, class Bits, class Invoker |
| > |
| void def_combination( |
| Def def, Specs*, Bits, Invoker*) |
| { |
| typedef typename mpl::fold< |
| Specs |
| , mpl::pair<mpl::vector0<>, Bits> |
| , combinations_op<mpl::_2, mpl::_1> |
| >::type combination0; |
| |
| typedef typename combination0::first combination; |
| |
| typedef typename mpl::apply_wrap1< |
| Invoker, combination |
| >::type invoker; |
| |
| def_combination_aux( |
| def |
| , &invoker::execute |
| , typename mpl::begin<combination>::type() |
| , typename mpl::end<combination>::type() |
| , no_keywords() |
| ); |
| } |
| |
| template < |
| class Def, class Specs, class Bits, class End, class Invoker |
| > |
| void def_combinations( |
| Def def, Specs*, Bits, End, Invoker*) |
| { |
| initialize_converter(); |
| |
| def_combination(def, (Specs*)0, Bits(), (Invoker*)0); |
| |
| def_combinations( |
| def |
| , (Specs*)0 |
| , mpl::long_<Bits::value + 1>() |
| , End() |
| , (Invoker*)0 |
| ); |
| } |
| |
| template < |
| class Def, class Specs, class End, class Invoker |
| > |
| void def_combinations( |
| Def, Specs*, End, End, Invoker*) |
| {} |
| |
| struct not_specified {}; |
| |
| template <class CallPolicies> |
| struct call_policies_as_options |
| { |
| call_policies_as_options(CallPolicies const& call_policies) |
| : call_policies(call_policies) |
| {} |
| |
| CallPolicies const& policies() const |
| { |
| return call_policies; |
| } |
| |
| char const* doc() const |
| { |
| return 0; |
| } |
| |
| CallPolicies call_policies; |
| }; |
| |
| template <class Class, class Options = not_specified> |
| struct def_class |
| { |
| def_class(Class& cl, char const* name, Options options = Options()) |
| : cl(cl) |
| , name(name) |
| , options(options) |
| {} |
| |
| template <class F> |
| void def(F f, not_specified const*) const |
| { |
| cl.def(name, f); |
| } |
| |
| template <class F> |
| void def(F f, void const*) const |
| { |
| cl.def(name, f, options.doc(), options.policies()); |
| } |
| |
| template <class F> |
| void operator()(F f) const |
| { |
| this->def(f, &options); |
| } |
| |
| template <class F, class Keywords> |
| void def(F f, Keywords const& keywords, not_specified const*) const |
| { |
| cl.def(name, f, keywords); |
| } |
| |
| template <class F, class Keywords> |
| void def(F f, Keywords const& keywords, void const*) const |
| { |
| cl.def(name, f, keywords, options.doc(), options.policies()); |
| } |
| |
| template <class F, class Keywords> |
| void operator()(F f, Keywords const& keywords) const |
| { |
| this->def(f, keywords, &options); |
| } |
| |
| Class& cl; |
| char const* name; |
| Options options; |
| }; |
| |
| template <class Class, class CallPolicies = boost::python::default_call_policies> |
| struct def_init |
| { |
| def_init(Class& cl, CallPolicies call_policies = CallPolicies()) |
| : cl(cl) |
| , call_policies(call_policies) |
| {} |
| |
| template <class F> |
| void operator()(F f) const |
| { |
| cl.def( |
| "__init__" |
| , boost::python::make_constructor(f, call_policies) |
| ); |
| } |
| |
| template <class F, class Keywords> |
| void operator()(F f, Keywords const& keywords) const |
| { |
| cl.def( |
| "__init__" |
| , boost::python::make_constructor(f, call_policies, keywords) |
| ); |
| } |
| |
| Class& cl; |
| CallPolicies call_policies; |
| }; |
| |
| struct def_function |
| { |
| def_function(char const* name) |
| : name(name) |
| {} |
| |
| template <class F> |
| void operator()(F f) const |
| { |
| boost::python::def(name, f); |
| } |
| |
| template <class F, class Keywords> |
| void operator()(F f, Keywords const& keywords) const |
| { |
| boost::python::def(name, f, keywords); |
| } |
| |
| char const* name; |
| }; |
| |
| } // namespace aux |
| |
| template <class M, class Signature> |
| void def(char const* name, Signature) |
| { |
| typedef mpl::iterator_range< |
| typename mpl::next< |
| typename mpl::begin<Signature>::type |
| >::type |
| , typename mpl::end<Signature>::type |
| > arg_types; |
| |
| typedef typename mpl::transform< |
| typename M::keywords |
| , arg_types |
| , aux::make_arg_spec<mpl::_1, mpl::_2> |
| , mpl::back_inserter<mpl::vector0<> > |
| >::type arg_specs; |
| |
| typedef typename mpl::count_if< |
| arg_specs |
| , aux::is_optional<mpl::_1> |
| >::type optional_arity; |
| |
| typedef typename mpl::front<Signature>::type result_type; |
| typedef typename mpl::shift_left<mpl::long_<1>, optional_arity>::type upper; |
| |
| aux::def_combinations( |
| aux::def_function(name) |
| , (arg_specs*)0 |
| , mpl::long_<0>() |
| , mpl::long_<upper::value>() |
| , (aux::make_invoker<M, result_type>*)0 |
| ); |
| } |
| |
| template <class M, class Class, class Signature> |
| void def(Class& cl, char const* name, Signature) |
| { |
| typedef mpl::iterator_range< |
| typename mpl::next< |
| typename mpl::begin<Signature>::type |
| >::type |
| , typename mpl::end<Signature>::type |
| > arg_types; |
| |
| typedef typename mpl::transform< |
| typename M::keywords |
| , arg_types |
| , aux::make_arg_spec<mpl::_1, mpl::_2> |
| , mpl::back_inserter<mpl::vector0<> > |
| >::type arg_specs; |
| |
| typedef typename mpl::count_if< |
| arg_specs |
| , aux::is_optional<mpl::_1> |
| >::type optional_arity; |
| |
| typedef typename mpl::front<Signature>::type result_type; |
| typedef typename mpl::shift_left<mpl::long_<1>, optional_arity>::type upper; |
| |
| aux::def_combinations( |
| aux::def_class<Class>(cl, name) |
| , (arg_specs*)0 |
| , mpl::long_<0>() |
| , mpl::long_<upper::value>() |
| , (aux::make_invoker<M, result_type>*)0 |
| ); |
| } |
| |
| namespace aux |
| { |
| |
| template <class K> |
| struct keyword |
| { |
| typedef K type; |
| }; |
| |
| template <class K> |
| struct keyword<K*> |
| { |
| typedef K type; |
| }; |
| |
| template <class K> |
| struct keyword<K**> |
| { |
| typedef K type; |
| }; |
| |
| template <class K> |
| struct required |
| { |
| typedef mpl::true_ type; |
| }; |
| |
| template <class K> |
| struct required<K*> |
| { |
| typedef mpl::false_ type; |
| }; |
| |
| template <class K> |
| struct optimized |
| { |
| typedef mpl::true_ type; |
| }; |
| |
| template <class K> |
| struct optimized<K**> |
| { |
| typedef mpl::false_ type; |
| }; |
| |
| template <class T> |
| struct make_kw_spec; |
| |
| template <class K, class T> |
| struct make_kw_spec<K(T)> |
| { |
| typedef arg_spec< |
| typename keyword<K>::type |
| , typename required<K>::type |
| , typename optimized<K>::type |
| , T |
| > type; |
| }; |
| |
| } // namespace aux |
| |
| template <class ParameterSpecs, class CallPolicies = boost::python::default_call_policies> |
| struct init |
| : boost::python::def_visitor<init<ParameterSpecs, CallPolicies> > |
| { |
| init(CallPolicies call_policies = CallPolicies()) |
| : call_policies(call_policies) |
| {} |
| |
| template <class CallPolicies1> |
| init<ParameterSpecs, CallPolicies1> |
| operator[](CallPolicies1 const& call_policies) const |
| { |
| return init<ParameterSpecs, CallPolicies1>(call_policies); |
| } |
| |
| template <class Class> |
| void visit_aux(Class& cl, mpl::true_) const |
| { |
| cl.def(boost::python::init<>()[call_policies]); |
| } |
| |
| template <class Class> |
| void visit_aux(Class& cl, mpl::false_) const |
| { |
| typedef typename mpl::transform< |
| ParameterSpecs |
| , aux::make_kw_spec<mpl::_> |
| , mpl::back_inserter<mpl::vector0<> > |
| >::type arg_specs; |
| |
| typedef typename mpl::count_if< |
| arg_specs |
| , aux::is_optional<mpl::_> |
| >::type optional_arity; |
| |
| typedef typename mpl::shift_left<mpl::long_<1>, optional_arity>::type upper; |
| |
| aux::def_combinations( |
| aux::def_init<Class, CallPolicies>(cl, call_policies) |
| , (arg_specs*)0 |
| , mpl::long_<0>() |
| , mpl::long_<upper::value>() |
| , (aux::make_init_invoker<typename Class::wrapped_type>*)0 |
| ); |
| } |
| |
| template <class Class> |
| void visit(Class& cl) const |
| { |
| visit_aux(cl, mpl::empty<ParameterSpecs>()); |
| } |
| |
| CallPolicies call_policies; |
| }; |
| |
| template <class ParameterSpecs, class CallPolicies = boost::python::default_call_policies> |
| struct call |
| : boost::python::def_visitor<call<ParameterSpecs, CallPolicies> > |
| { |
| call(CallPolicies const& call_policies = CallPolicies()) |
| : call_policies(call_policies) |
| {} |
| |
| template <class CallPolicies1> |
| call<ParameterSpecs, CallPolicies1> |
| operator[](CallPolicies1 const& call_policies) const |
| { |
| return call<ParameterSpecs, CallPolicies1>(call_policies); |
| } |
| |
| template <class Class> |
| void visit(Class& cl) const |
| { |
| typedef mpl::iterator_range< |
| typename mpl::next< |
| typename mpl::begin<ParameterSpecs>::type |
| >::type |
| , typename mpl::end<ParameterSpecs>::type |
| > arg_types; |
| |
| typedef typename mpl::front<ParameterSpecs>::type result_type; |
| |
| typedef typename mpl::transform< |
| arg_types |
| , aux::make_kw_spec<mpl::_> |
| , mpl::back_inserter<mpl::vector0<> > |
| >::type arg_specs; |
| |
| typedef typename mpl::count_if< |
| arg_specs |
| , aux::is_optional<mpl::_> |
| >::type optional_arity; |
| |
| typedef typename mpl::shift_left<mpl::long_<1>, optional_arity>::type upper; |
| |
| typedef aux::call_policies_as_options<CallPolicies> options; |
| |
| aux::def_combinations( |
| aux::def_class<Class, options>(cl, "__call__", options(call_policies)) |
| , (arg_specs*)0 |
| , mpl::long_<0>() |
| , mpl::long_<upper::value>() |
| , (aux::make_call_invoker<typename Class::wrapped_type, result_type>*)0 |
| ); |
| } |
| |
| CallPolicies call_policies; |
| }; |
| |
| template <class Fwd, class ParameterSpecs> |
| struct function |
| : boost::python::def_visitor<function<Fwd, ParameterSpecs> > |
| { |
| template <class Class, class Options> |
| void visit(Class& cl, char const* name, Options const& options) const |
| { |
| typedef mpl::iterator_range< |
| typename mpl::next< |
| typename mpl::begin<ParameterSpecs>::type |
| >::type |
| , typename mpl::end<ParameterSpecs>::type |
| > arg_types; |
| |
| typedef typename mpl::front<ParameterSpecs>::type result_type; |
| |
| typedef typename mpl::transform< |
| arg_types |
| , aux::make_kw_spec<mpl::_> |
| , mpl::back_inserter<mpl::vector0<> > |
| >::type arg_specs; |
| |
| typedef typename mpl::count_if< |
| arg_specs |
| , aux::is_optional<mpl::_> |
| >::type optional_arity; |
| |
| typedef typename mpl::shift_left<mpl::long_<1>, optional_arity>::type upper; |
| |
| aux::def_combinations( |
| aux::def_class<Class, Options>(cl, name, options) |
| , (arg_specs*)0 |
| , mpl::long_<0>() |
| , mpl::long_<upper::value>() |
| , (aux::make_member_invoker< |
| Fwd, result_type, typename Class::wrapped_type |
| >*)0 |
| ); |
| } |
| }; |
| |
| }}} // namespace boost::parameter::python |
| |
| #endif // BOOST_PARAMETER_PYTHON_060209_HPP |
| |