/////////////////////////////////////////////////////////////////////////////// | |
// | |
// Copyright David Abrahams 2002, Joel de Guzman, 2002. | |
// Distributed under 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 INIT_JDG20020820_HPP | |
#define INIT_JDG20020820_HPP | |
# include <boost/python/detail/prefix.hpp> | |
#include <boost/python/detail/type_list.hpp> | |
#include <boost/python/args_fwd.hpp> | |
#include <boost/python/detail/make_keyword_range_fn.hpp> | |
#include <boost/python/def_visitor.hpp> | |
#include <boost/mpl/if.hpp> | |
#include <boost/mpl/eval_if.hpp> | |
#include <boost/mpl/size.hpp> | |
#include <boost/mpl/iterator_range.hpp> | |
#include <boost/mpl/empty.hpp> | |
#include <boost/mpl/begin_end.hpp> | |
#include <boost/mpl/bool.hpp> | |
#include <boost/mpl/prior.hpp> | |
#include <boost/mpl/joint_view.hpp> | |
#include <boost/mpl/back.hpp> | |
#include <boost/type_traits/is_same.hpp> | |
#include <boost/preprocessor/enum_params_with_a_default.hpp> | |
#include <boost/preprocessor/enum_params.hpp> | |
#include <utility> | |
/////////////////////////////////////////////////////////////////////////////// | |
#define BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT \ | |
BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT( \ | |
BOOST_PYTHON_MAX_ARITY, \ | |
class T, \ | |
mpl::void_) \ | |
#define BOOST_PYTHON_OVERLOAD_TYPES \ | |
BOOST_PP_ENUM_PARAMS_Z(1, \ | |
BOOST_PYTHON_MAX_ARITY, \ | |
class T) \ | |
#define BOOST_PYTHON_OVERLOAD_ARGS \ | |
BOOST_PP_ENUM_PARAMS_Z(1, \ | |
BOOST_PYTHON_MAX_ARITY, \ | |
T) \ | |
/////////////////////////////////////////////////////////////////////////////// | |
namespace boost { namespace python { | |
template <BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT> | |
class init; // forward declaration | |
template <BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT> | |
struct optional; // forward declaration | |
namespace detail | |
{ | |
namespace error | |
{ | |
template <int keywords, int init_args> | |
struct more_keywords_than_init_arguments | |
{ | |
typedef char too_many_keywords[init_args - keywords >= 0 ? 1 : -1]; | |
}; | |
} | |
// is_optional<T>::value | |
// | |
// This metaprogram checks if T is an optional | |
// | |
#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) | |
template <class T> | |
struct is_optional { | |
private: | |
template <BOOST_PYTHON_OVERLOAD_TYPES> | |
static boost::type_traits::yes_type f(optional<BOOST_PYTHON_OVERLOAD_ARGS>); | |
static boost::type_traits::no_type f(...); | |
static T t(); | |
public: | |
BOOST_STATIC_CONSTANT( | |
bool, value = | |
sizeof(f(t())) == sizeof(::boost::type_traits::yes_type)); | |
typedef mpl::bool_<value> type; | |
}; | |
#else | |
template <class T> | |
struct is_optional | |
: mpl::false_ | |
{}; | |
template <BOOST_PYTHON_OVERLOAD_TYPES> | |
struct is_optional<optional<BOOST_PYTHON_OVERLOAD_ARGS> > | |
: mpl::true_ | |
{}; | |
#endif | |
template <int NDefaults> | |
struct define_class_init_helper; | |
} // namespace detail | |
template <class DerivedT> | |
struct init_base : def_visitor<DerivedT> | |
{ | |
init_base(char const* doc_, detail::keyword_range const& keywords_) | |
: m_doc(doc_), m_keywords(keywords_) | |
{} | |
init_base(char const* doc_) | |
: m_doc(doc_) | |
{} | |
DerivedT const& derived() const | |
{ | |
return *static_cast<DerivedT const*>(this); | |
} | |
char const* doc_string() const | |
{ | |
return m_doc; | |
} | |
detail::keyword_range const& keywords() const | |
{ | |
return m_keywords; | |
} | |
static default_call_policies call_policies() | |
{ | |
return default_call_policies(); | |
} | |
private: | |
// visit | |
// | |
// Defines a set of n_defaults + 1 constructors for its | |
// class_<...> argument. Each constructor after the first has | |
// one less argument to its right. Example: | |
// | |
// init<int, optional<char, long, double> > | |
// | |
// Defines: | |
// | |
// __init__(int, char, long, double) | |
// __init__(int, char, long) | |
// __init__(int, char) | |
// __init__(int) | |
template <class classT> | |
void visit(classT& cl) const | |
{ | |
typedef typename DerivedT::signature signature; | |
typedef typename DerivedT::n_arguments n_arguments; | |
typedef typename DerivedT::n_defaults n_defaults; | |
detail::define_class_init_helper<n_defaults::value>::apply( | |
cl | |
, derived().call_policies() | |
, signature() | |
, n_arguments() | |
, derived().doc_string() | |
, derived().keywords()); | |
} | |
friend class python::def_visitor_access; | |
private: // data members | |
char const* m_doc; | |
detail::keyword_range m_keywords; | |
}; | |
template <class CallPoliciesT, class InitT> | |
class init_with_call_policies | |
: public init_base<init_with_call_policies<CallPoliciesT, InitT> > | |
{ | |
typedef init_base<init_with_call_policies<CallPoliciesT, InitT> > base; | |
public: | |
typedef typename InitT::n_arguments n_arguments; | |
typedef typename InitT::n_defaults n_defaults; | |
typedef typename InitT::signature signature; | |
init_with_call_policies( | |
CallPoliciesT const& policies_ | |
, char const* doc_ | |
, detail::keyword_range const& keywords | |
) | |
: base(doc_, keywords) | |
, m_policies(policies_) | |
{} | |
CallPoliciesT const& call_policies() const | |
{ | |
return this->m_policies; | |
} | |
private: // data members | |
CallPoliciesT m_policies; | |
}; | |
// | |
// drop1<S> is the initial length(S) elements of S | |
// | |
namespace detail | |
{ | |
template <class S> | |
struct drop1 | |
: mpl::iterator_range< | |
typename mpl::begin<S>::type | |
, typename mpl::prior< | |
typename mpl::end<S>::type | |
>::type | |
> | |
{}; | |
} | |
template <BOOST_PYTHON_OVERLOAD_TYPES> | |
class init : public init_base<init<BOOST_PYTHON_OVERLOAD_ARGS> > | |
{ | |
typedef init_base<init<BOOST_PYTHON_OVERLOAD_ARGS> > base; | |
public: | |
typedef init<BOOST_PYTHON_OVERLOAD_ARGS> self_t; | |
init(char const* doc_ = 0) | |
: base(doc_) | |
{ | |
} | |
template <std::size_t N> | |
init(char const* doc_, detail::keywords<N> const& kw) | |
: base(doc_, kw.range()) | |
{ | |
typedef typename detail::error::more_keywords_than_init_arguments< | |
N, n_arguments::value + 1 | |
>::too_many_keywords assertion; | |
} | |
template <std::size_t N> | |
init(detail::keywords<N> const& kw, char const* doc_ = 0) | |
: base(doc_, kw.range()) | |
{ | |
typedef typename detail::error::more_keywords_than_init_arguments< | |
N, n_arguments::value + 1 | |
>::too_many_keywords assertion; | |
} | |
template <class CallPoliciesT> | |
init_with_call_policies<CallPoliciesT, self_t> | |
operator[](CallPoliciesT const& policies) const | |
{ | |
return init_with_call_policies<CallPoliciesT, self_t>( | |
policies, this->doc_string(), this->keywords()); | |
} | |
typedef detail::type_list<BOOST_PYTHON_OVERLOAD_ARGS> signature_; | |
typedef detail::is_optional< | |
typename mpl::eval_if< | |
mpl::empty<signature_> | |
, mpl::false_ | |
, mpl::back<signature_> | |
>::type | |
> back_is_optional; | |
typedef typename mpl::eval_if< | |
back_is_optional | |
, mpl::back<signature_> | |
, mpl::vector0<> | |
>::type optional_args; | |
typedef typename mpl::eval_if< | |
back_is_optional | |
, mpl::if_< | |
mpl::empty<optional_args> | |
, detail::drop1<signature_> | |
, mpl::joint_view< | |
detail::drop1<signature_> | |
, optional_args | |
> | |
> | |
, signature_ | |
>::type signature; | |
// TODO: static assert to make sure there are no other optional elements | |
// Count the number of default args | |
typedef mpl::size<optional_args> n_defaults; | |
typedef mpl::size<signature> n_arguments; | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// optional | |
// | |
// optional<T0...TN>::type returns a typelist. | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
template <BOOST_PYTHON_OVERLOAD_TYPES> | |
struct optional | |
: detail::type_list<BOOST_PYTHON_OVERLOAD_ARGS> | |
{ | |
}; | |
namespace detail | |
{ | |
template <class ClassT, class CallPoliciesT, class Signature, class NArgs> | |
inline void def_init_aux( | |
ClassT& cl | |
, Signature const& | |
, NArgs | |
, CallPoliciesT const& policies | |
, char const* doc | |
, detail::keyword_range const& keywords_ | |
) | |
{ | |
cl.def( | |
"__init__" | |
, detail::make_keyword_range_constructor<Signature,NArgs>( | |
policies | |
, keywords_ | |
, (typename ClassT::metadata::holder*)0 | |
) | |
, doc | |
); | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// define_class_init_helper<N>::apply | |
// | |
// General case | |
// | |
// Accepts a class_ and an arguments list. Defines a constructor | |
// for the class given the arguments and recursively calls | |
// define_class_init_helper<N-1>::apply with one fewer argument (the | |
// rightmost argument is shaved off) | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
template <int NDefaults> | |
struct define_class_init_helper | |
{ | |
template <class ClassT, class CallPoliciesT, class Signature, class NArgs> | |
static void apply( | |
ClassT& cl | |
, CallPoliciesT const& policies | |
, Signature const& args | |
, NArgs | |
, char const* doc | |
, detail::keyword_range keywords) | |
{ | |
detail::def_init_aux(cl, args, NArgs(), policies, doc, keywords); | |
if (keywords.second > keywords.first) | |
--keywords.second; | |
typedef typename mpl::prior<NArgs>::type next_nargs; | |
define_class_init_helper<NDefaults-1>::apply( | |
cl, policies, Signature(), next_nargs(), doc, keywords); | |
} | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// define_class_init_helper<0>::apply | |
// | |
// Terminal case | |
// | |
// Accepts a class_ and an arguments list. Defines a constructor | |
// for the class given the arguments. | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
template <> | |
struct define_class_init_helper<0> { | |
template <class ClassT, class CallPoliciesT, class Signature, class NArgs> | |
static void apply( | |
ClassT& cl | |
, CallPoliciesT const& policies | |
, Signature const& args | |
, NArgs | |
, char const* doc | |
, detail::keyword_range const& keywords) | |
{ | |
detail::def_init_aux(cl, args, NArgs(), policies, doc, keywords); | |
} | |
}; | |
} | |
}} // namespace boost::python | |
#undef BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT | |
#undef BOOST_PYTHON_OVERLOAD_TYPES | |
#undef BOOST_PYTHON_OVERLOAD_ARGS | |
#undef BOOST_PYTHON_IS_OPTIONAL_VALUE | |
#undef BOOST_PYTHON_APPEND_TO_INIT | |
/////////////////////////////////////////////////////////////////////////////// | |
#endif // INIT_JDG20020820_HPP | |