736 lines
19 KiB
C++
Executable File
736 lines
19 KiB
C++
Executable File
// 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
|
|
|