400 lines
12 KiB
C++
400 lines
12 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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] 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|