/////////////////////////////////////////////////////////////////////////////// // // 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