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