boost/python/init.hpp
///////////////////////////////////////////////////////////////////////////////
//
// 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/python/detail/type_traits.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] BOOST_ATTRIBUTE_UNUSED;
};
}
// is_optional<T>::value
//
// This metaprogram checks if T is an optional
//
template <class T>
struct is_optional
: mpl::false_
{};
template <BOOST_PYTHON_OVERLOAD_TYPES>
struct is_optional<optional<BOOST_PYTHON_OVERLOAD_ARGS> >
: mpl::true_
{};
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 BOOST_ATTRIBUTE_UNUSED;
}
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 BOOST_ATTRIBUTE_UNUSED;
}
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