diff --git a/include/boost/python/args.hpp b/include/boost/python/args.hpp index e488f3d8..4e2e922b 100644 --- a/include/boost/python/args.hpp +++ b/include/boost/python/args.hpp @@ -3,33 +3,117 @@ // copyright notice appears in all copies. This software is provided // "as is" without express or implied warranty, and with no claim as // to its suitability for any purpose. -#ifndef ARGS_DWA2002323_HPP -# define ARGS_DWA2002323_HPP -# include -# include -# include -# include +#ifndef KEYWORDS_DWA2002323_HPP +# define KEYWORDS_DWA2002323_HPP + +# include +# include +# include +# include +# include + +# include +# include +# include + +# include +# include +# include +# include + +# include +# include + +# include +# include + namespace boost { namespace python { -enum no_init_t { no_init }; - namespace detail { - template - struct args_base {}; + struct keyword + { + char const* name; + handle<> default_value; + }; + + template + struct keywords + { + BOOST_STATIC_CONSTANT(std::size_t, size = nkeywords); + + keyword_range range() const + { + return keyword_range(elements, elements + nkeywords); + } + + keyword elements[nkeywords]; + }; + +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + template + struct is_keywords + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; + + template + struct is_keywords > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template + struct is_reference_to_keywords + { + BOOST_STATIC_CONSTANT(bool, is_ref = is_reference::value); + typedef typename remove_reference::type deref; + typedef typename remove_cv::type key_t; + BOOST_STATIC_CONSTANT(bool, is_key = is_keywords::value); + BOOST_STATIC_CONSTANT(bool, value = (is_ref & is_key)); + + typedef mpl::bool_c type; + BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_reference_to_keywords,(T)) + }; +# else + typedef char (&yes_keywords_t)[1]; + typedef char (&no_keywords_t)[2]; + + no_keywords_t is_keywords_test(...); + + template + yes_keywords_t is_keywords_test(void (*)(keywords&)); + + template + yes_keywords_t is_keywords_test(void (*)(keywords const&)); + + template + class is_reference_to_keywords + { + public: + BOOST_STATIC_CONSTANT( + bool, value = ( + sizeof(detail::is_keywords_test( (void (*)(T))0 )) + == sizeof(detail::yes_keywords_t))); + + typedef mpl::bool_c type; + BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_reference_to_keywords,(T)) + }; +# endif } -}} -namespace boost { namespace python { - -// A type list for specifying arguments -template < BOOST_PYTHON_ENUM_WITH_DEFAULT(BOOST_PYTHON_MAX_ARITY, typename A, mpl::void_) > -struct args : detail::args_base > - , detail::type_list< BOOST_PP_ENUM_PARAMS_Z(1, BOOST_PYTHON_MAX_ARITY, A) >::type -{}; +# define BOOST_PYTHON_ASSIGN_NAME(z, n, _) result.elements[n].name = name##n; +# define BOOST_PP_LOCAL_MACRO(n) \ +inline detail::keywords args(BOOST_PP_ENUM_PARAMS_Z(1, n, char const* name)) \ +{ \ + detail::keywords result; \ + BOOST_PP_REPEAT_1(n, BOOST_PYTHON_ASSIGN_NAME, _) \ + return result; \ +} +# define BOOST_PP_LOCAL_LIMITS (1, BOOST_PYTHON_MAX_ARITY) +# include BOOST_PP_LOCAL_ITERATE() }} // namespace boost::python -# endif // ARGS_DWA2002323_HPP +# endif // KEYWORDS_DWA2002323_HPP diff --git a/include/boost/python/class.hpp b/include/boost/python/class.hpp index ceeb516c..2e0840b3 100644 --- a/include/boost/python/class.hpp +++ b/include/boost/python/class.hpp @@ -34,6 +34,7 @@ # include # include # include +# include namespace boost { namespace python { @@ -120,8 +121,9 @@ template < class class_ : public objects::class_base { public: // types - typedef objects::class_base base; - + typedef objects::class_base base; + typedef T wrapped_type; + typedef class_ self; BOOST_STATIC_CONSTANT(bool, is_copyable = (!detail::has_noncopyable::value)); @@ -201,7 +203,7 @@ class class_ : public objects::class_base template self& def(char const* name, F f) { - this->def_impl(name, f, default_call_policies(), 0, &f); + this->def_impl(name, f, detail::keywords<>(), default_call_policies(), 0, &f); return *this; } @@ -236,6 +238,13 @@ class class_ : public objects::class_base return *this; } + template + self& def(char const* name, Arg1T arg1, Arg2T const& arg2, Arg3T const& arg3, Arg4T const& arg4) + { + dispatch_def(&arg2, name, arg1, arg2, arg3, arg4); + return *this; + } + template self& def(detail::operator_ const& op) { @@ -297,22 +306,32 @@ class class_ : public objects::class_base private: // helper functions - template - inline void def_impl(char const* name, Fn fn, Policies const& policies - , char const* doc, ...) + template + inline void def_impl( + char const* name + , Fn fn + , Keywords const& keywords + , Policies const& policies + , char const* doc + , ...) { objects::add_to_namespace( *this, name, make_function( - // This bit of nastiness casts F to a member function of T if possible. + // This bit of nastiness casts F to a member function of T if possible. detail::member_function_cast::stage1(fn).stage2((T*)0).stage3(fn) - , policies) + , policies, keywords) , doc); } template - inline void def_impl(char const* name, F f, default_call_policies const& - , char const* doc, object const*) + inline void def_impl( + char const* name + , F f + , detail::keywords<> const& + , default_call_policies const& + , char const* doc + , object const*) { objects::add_to_namespace(*this, name, f, doc); } @@ -332,33 +351,60 @@ class class_ : public objects::class_base name, overloads, *this, detail::get_signature(sig)); } - template + template void dispatch_def( void const*, char const* name, Fn fn, - CallPolicyOrDoc const& policy_or_doc) + A1 const& a1) { - typedef detail::def_helper helper; + detail::def_helper helper(a1); + this->def_impl( - name, fn, helper::get_policy(policy_or_doc), - helper::get_doc(policy_or_doc, 0), &fn); + name, fn + , helper.keywords() + , helper.policies() + , helper.doc() + , &fn); } - template + template void dispatch_def( void const*, char const* name, Fn fn, - CallPolicyOrDoc1 const& policy_or_doc1, - CallPolicyOrDoc2 const& policy_or_doc2) + A1 const& a1, + A2 const& a2) { - typedef detail::def_helper helper; - + detail::def_helper helper(a1,a2); + this->def_impl( - name, fn, helper::get_policy(policy_or_doc1, policy_or_doc2), - helper::get_doc(policy_or_doc1, policy_or_doc2), &fn); + name, fn + , helper.keywords() + , helper.policies() + , helper.doc() + , &fn); + } + + template + void dispatch_def( + void const*, + char const* name, + Fn fn, + A1 const& a1, + A2 const& a2, + A3 const& a3 + ) + { + detail::def_helper helper(a1,a2,a3); + + this->def_impl( + name, fn + , helper.keywords() + , helper.policies() + , helper.doc() + , &fn); } }; diff --git a/include/boost/python/def.hpp b/include/boost/python/def.hpp index 1ade4fd1..f6218886 100644 --- a/include/boost/python/def.hpp +++ b/include/boost/python/def.hpp @@ -12,43 +12,49 @@ # include # include # include +# include namespace boost { namespace python { namespace detail { - void BOOST_PYTHON_DECL scope_setattr_doc(char const* name, object const& obj, char const* doc); - - template + template void dispatch_def( void const*, char const* name, Fn fn, - CallPolicyOrDoc const& policy_or_doc) + A1 const& a1) { - typedef detail::def_helper helper; - + def_helper helper(a1); + detail::scope_setattr_doc( - name, boost::python::make_function(fn, helper::get_policy(policy_or_doc)), - helper::get_doc(policy_or_doc, 0)); + name, boost::python::make_function( + fn + , helper.policies() + , helper.keywords()) + , helper.doc() + ); } - template + template void dispatch_def( void const*, char const* name, Fn fn, - CallPolicyOrDoc1 const& policy_or_doc1, - CallPolicyOrDoc2 const& policy_or_doc2) + A1 const& a1, + A2 const& a2) { - typedef detail::def_helper helper; + def_helper helper(a1,a2); detail::scope_setattr_doc( - name, boost::python::make_function( - fn, helper::get_policy(policy_or_doc1, policy_or_doc2)), - helper::get_doc(policy_or_doc1, policy_or_doc2)); - } + name, python::make_function( + fn + , helper.policies() + , helper.keywords()) + , helper.doc() + ); + } template void dispatch_def( @@ -87,22 +93,22 @@ void def(char const* name, Arg1T arg1, Arg2T const& arg2) template void def(char const* name, Arg1T arg1, Arg2T const& arg2, Arg3T const& arg3) { - // The arguments are definitely: - // def(name, function, policy, doc_string) // TODO: exchange policy, doc_string position - detail::dispatch_def(&arg2, name, arg1, arg2, arg3); } -//template -//void def(char const* name, Arg1T arg1, Arg2T const& arg2, Arg3T const& arg3, char const* doc) -//{ -// // The arguments are definitely: -// // arg1: signature -// // arg2: stubs -// // arg3: policy -// -// detail::dispatch_def(&arg2, name, arg1, arg2, arg3, doc); -//} +template +void def(char const* name, F f, A1 const& a1, A2 const& a2, A3 const& a3) +{ + detail::def_helper helper(a1,a2,a3); + + detail::scope_setattr_doc( + name, python::make_function( + f + , helper.policies() + , helper.keywords()) + , helper.doc() + ); +} }} // namespace boost::python diff --git a/include/boost/python/detail/def_helper.hpp b/include/boost/python/detail/def_helper.hpp index b9931cfe..4135af55 100644 --- a/include/boost/python/detail/def_helper.hpp +++ b/include/boost/python/detail/def_helper.hpp @@ -6,72 +6,146 @@ #ifndef DEF_HELPER_DWA200287_HPP # define DEF_HELPER_DWA200287_HPP +# include # include # include -# include +# include +# include +# include +# include +# include +# include +# include +# include -namespace boost { namespace python { namespace detail { +namespace boost { namespace python { -// -// def_helper -- -// -// A helper for def() functions which determines how to interpret -// an argument of type T which could be either CallPolicies or a -// string literal representing a docstring. -// -// Generates two static functions: -// -// get_policy(x), where x is of type T, returns a policies -// object: either a reference to x or default_call_policies() -// if x is a string literal. -// -// get_doc(x, s), where s convertible to char const*, returns x -// if x is a string literal, s otherwise. +struct default_call_policies; -template -struct def_helper_impl +namespace detail { - template - static P const& - get_policy(P const& x) { return x; } - - template - static P1 const& - get_policy(P1 const& x, P2 const&) { return x; } // select left - - template - static char const* - get_doc(P const&, char const* doc) { return doc; } // select right -}; - -template <> -struct def_helper_impl -{ - static python::default_call_policies - get_policy(char const*) - { return default_call_policies(); } - - template - static P2 const& - get_policy(P1 const&, P2 const& y) { return y; } // select right - - template - static char const* - get_doc(char const* doc, P const&) // select left - { return doc; } -}; + template + struct tuple_extract; -template -struct def_helper - : def_helper_impl< - type_traits::ice_or< - is_string_literal::value - , is_same::value - , is_same::value ->::value -> -{}; + template + struct tuple_extract_impl + { + template + struct apply + { + typedef typename Tuple::head_type result_type; + + static typename Tuple::head_type extract(Tuple const& x) + { + return x.get_head(); + } + }; + }; + + template <> + struct tuple_extract_impl + { + template + struct apply + : tuple_extract + { + // All of this forwarding would be unneeded if tuples were + // derived from their tails. + typedef tuple_extract base; + typedef typename base::result_type result_type; + static result_type extract(Tuple const& x) + { + return base::extract(x.get_tail()); + } + }; + }; -}}} // namespace boost::python::detail + template + struct tuple_extract_base_select + { + typedef typename Tuple::head_type head_type; + typedef typename mpl::apply1::type match_t; + BOOST_STATIC_CONSTANT(bool, match = match_t::value); + typedef typename tuple_extract_impl::template apply type; + }; + + template + struct tuple_extract + : tuple_extract_base_select< + Tuple + , typename mpl::lambda::type + >::type + { + }; + + template + struct doc_extract + : tuple_extract< + Tuple, + mpl::logical_not< + is_reference_to_class< + add_reference + > + > > + { + }; + + template + struct keyword_extract + : tuple_extract > > + { + }; + + template + struct policy_extract + : tuple_extract< + Tuple, + mpl::logical_and< + is_reference_to_class > + , mpl::logical_not > > + > + > + { + }; + +# define BOOST_PYTHON_DEF_HELPER_TAIL default_call_policies, keywords<0>, char const* + template + struct def_helper + { + typedef typename mpl::if_< + is_same + , boost::tuples::tuple + , typename mpl::if_< + is_same + , boost::tuples::tuple + , boost::tuples::tuple + >::type + >::type all_t; + + def_helper(T1 const& a1) : m_all(a1) {} + def_helper(T1 const& a1, T2 const& a2) : m_all(a1,a2) {} + def_helper(T1 const& a1, T2 const& a2, T3 const& a3) : m_all(a1,a2,a3) {} + + char const* doc() const + { + return doc_extract::extract(m_all); + } + + typename keyword_extract::result_type keywords() const + { + return keyword_extract::extract(m_all); + } + + typename policy_extract::result_type policies() const + { + return policy_extract::extract(m_all); + } + + all_t m_all; + }; +# undef BOOST_PYTHON_DEF_HELPER_TAIL +} + +}} // namespace boost::python::detail #endif // DEF_HELPER_DWA200287_HPP diff --git a/include/boost/python/detail/defaults_def.hpp b/include/boost/python/detail/defaults_def.hpp index 721fc37f..d7262316 100644 --- a/include/boost/python/detail/defaults_def.hpp +++ b/include/boost/python/detail/defaults_def.hpp @@ -19,9 +19,11 @@ #include #include #include -#include #include #include +#include +#include +#include /////////////////////////////////////////////////////////////////////////////// namespace boost { namespace python { @@ -33,78 +35,92 @@ namespace objects struct class_base; } -namespace detail { - -template -static void name_space_def( - NameSpaceT& name_space, - char const* name, - Func f, - CallPolicies const& policies, - char const* doc, - objects::class_base* - ) +namespace detail { - name_space.def( - name, f, policies, doc); -} + template struct member_function_cast; + + template + static void name_space_def( + NameSpaceT& name_space + , char const* name + , Func f + , keyword_range const& kw + , CallPolicies const& policies + , char const* doc + , objects::class_base* + ) + { + typedef typename NameSpaceT::wrapped_type wrapped_type; + + objects::add_to_namespace( + name_space, name, + make_keyword_range_function( + // This bit of nastiness casts F to a member function of T if possible. + member_function_cast::stage1(f).stage2((wrapped_type*)0).stage3(f) + , policies, kw) + , doc); + } -template -static void name_space_def( - object& name_space, - char const* name, - Func f, - CallPolicies const& policies, - char const* doc, - ... - ) -{ - scope within(name_space); + template + static void name_space_def( + object& name_space + , char const* name + , Func f + , keyword_range const& kw + , CallPolicies const& policies + , char const* doc + , ... + ) + { + scope within(name_space); - def(name, f, policies, doc); -} + detail::scope_setattr_doc( + name + , detail::make_keyword_range_function(f, policies, kw) + , doc); + } -// For backward compatibility -template -static void name_space_def( - NameSpaceT& name_space, - char const* name, - Func f, - CallPolicies const& policies, - char const* doc, - module* - ) -{ - name_space.def( - name, f, policies, doc); -} + // For backward compatibility + template + static void name_space_def( + NameSpaceT& name_space + , char const* name + , Func f + , keyword_range const& kw // ignored + , CallPolicies const& policies + , char const* doc + , module* + ) + { + name_space.def(name, f, policies, doc); + } -/////////////////////////////////////////////////////////////////////////////// -// -// This Boost PP code generates expansions for -// -// template -// inline void -// define_stub_function( -// char const* name, StubsT s, NameSpaceT& name_space, mpl::int_c) -// { -// name_space.def(name, &StubsT::func_N); -// } -// -// where N runs from 0 to BOOST_PYTHON_MAX_ARITY -// -// The set of overloaded functions (define_stub_function) expects: -// -// 1. char const* name: function name that will be visible to python -// 2. StubsT: a function stubs struct (see defaults_gen.hpp) -// 3. NameSpaceT& name_space: a python::class_ or python::module instance -// 4. int_t: the Nth overloaded function (StubsT::func_N) -// (see defaults_gen.hpp) -// 5. char const* name: doc string -// -/////////////////////////////////////////////////////////////////////////////// -template -struct define_stub_function {}; + /////////////////////////////////////////////////////////////////////////////// + // + // This Boost PP code generates expansions for + // + // template + // inline void + // define_stub_function( + // char const* name, OverloadsT s, NameSpaceT& name_space, mpl::int_c) + // { + // name_space.def(name, &OverloadsT::func_N); + // } + // + // where N runs from 0 to BOOST_PYTHON_MAX_ARITY + // + // The set of overloaded functions (define_stub_function) expects: + // + // 1. char const* name: function name that will be visible to python + // 2. OverloadsT: a function overloads struct (see defaults_gen.hpp) + // 3. NameSpaceT& name_space: a python::class_ or python::module instance + // 4. int_t: the Nth overloaded function (OverloadsT::func_N) + // (see defaults_gen.hpp) + // 5. char const* name: doc string + // + /////////////////////////////////////////////////////////////////////////////// + template + struct define_stub_function {}; #define BOOST_PP_ITERATION_PARAMS_1 \ (3, (0, BOOST_PYTHON_MAX_ARITY, )) @@ -120,10 +136,10 @@ struct define_stub_function {}; // terminal case define_with_defaults_helper<0>. The struct and its // specialization has a sole static member function def that expects: // -// 1. char const* name: function name that will be visible to python -// 2. StubsT: a function stubs struct (see defaults_gen.hpp) -// 3. NameSpaceT& name_space: a python::class_ or python::module instance -// 4. char const* name: doc string +// 1. char const* name: function name that will be visible to python +// 2. OverloadsT: a function overloads struct (see defaults_gen.hpp) +// 3. NameSpaceT& name_space: a python::class_ or python::module instance +// 4. char const* name: doc string // // The def static member function calls a corresponding // define_stub_function. The general case recursively calls @@ -139,14 +155,19 @@ struct define_stub_function {}; def( char const* name, StubsT stubs, + keyword_range kw, CallPolicies const& policies, NameSpaceT& name_space, char const* doc) { // define the NTH stub function of stubs - define_stub_function::define(name, stubs, policies, name_space, doc); + define_stub_function::define(name, stubs, kw, policies, name_space, doc); + + if (kw.second > kw.first) + --kw.second; + // call the next define_with_defaults_helper - define_with_defaults_helper::def(name, stubs, policies, name_space, doc); + define_with_defaults_helper::def(name, stubs, kw, policies, name_space, doc); } }; @@ -159,12 +180,13 @@ struct define_stub_function {}; def( char const* name, StubsT stubs, + keyword_range const& kw, CallPolicies const& policies, NameSpaceT& name_space, char const* doc) { // define the Oth stub function of stubs - define_stub_function<0>::define(name, stubs, policies, name_space, doc); + define_stub_function<0>::define(name, stubs, kw, policies, name_space, doc); // return } }; @@ -174,7 +196,7 @@ struct define_stub_function {}; // define_with_defaults // // 1. char const* name: function name that will be visible to python -// 2. StubsT: a function stubs struct (see defaults_gen.hpp) +// 2. OverloadsT: a function overloads struct (see defaults_gen.hpp) // 3. CallPolicies& policies: Call policies // 4. NameSpaceT& name_space: a python::class_ or python::module instance // 5. SigT sig: Function signature typelist (see defaults_gen.hpp) @@ -191,17 +213,17 @@ struct define_stub_function {}; // void C::foo(int) mpl::list // /////////////////////////////////////////////////////////////////////////////// - template + template inline void define_with_defaults( char const* name, - StubsT const& stubs, + OverloadsT const& overloads, NameSpaceT& name_space, SigT sig) { typedef typename mpl::front::type return_type; - typedef typename StubsT::void_return_type void_return_type; - typedef typename StubsT::non_void_return_type non_void_return_type; + typedef typename OverloadsT::void_return_type void_return_type; + typedef typename OverloadsT::non_void_return_type non_void_return_type; typedef typename mpl::if_c< boost::is_same::value @@ -213,8 +235,13 @@ struct define_stub_function {}; (stubs_type::max_args) <= mpl::size::value); typedef typename stubs_type::template gen gen_type; - define_with_defaults_helper::def - (name, gen_type(), stubs.call_policies(), name_space, stubs.doc_string()); + define_with_defaults_helper::def( + name + , gen_type() + , overloads.keywords() + , overloads.call_policies() + , name_space + , overloads.doc_string()); } } // namespace detail @@ -232,17 +259,21 @@ template <> struct define_stub_function { template static void define( - char const* name, - StubsT, - CallPolicies const& policies, - NameSpaceT& name_space, - char const* doc) + char const* name + , StubsT const& + , keyword_range const& kw + , CallPolicies const& policies + , NameSpaceT& name_space + , char const* doc) { - detail::name_space_def(name_space, - name, - &StubsT::BOOST_PP_CAT(func_, BOOST_PP_ITERATION()), - policies, - doc, &name_space); + detail::name_space_def( + name_space + , name + , &StubsT::BOOST_PP_CAT(func_, BOOST_PP_ITERATION()) + , kw + , policies + , doc + , &name_space); } }; diff --git a/include/boost/python/detail/defaults_gen.hpp b/include/boost/python/detail/defaults_gen.hpp index d8b96d53..6106ce54 100644 --- a/include/boost/python/detail/defaults_gen.hpp +++ b/include/boost/python/detail/defaults_gen.hpp @@ -29,74 +29,96 @@ namespace boost { namespace python { -// overloads_base is used as a base class for all function -// stubs. This class holds the doc_string of the stubs. - namespace detail { + // overloads_base is used as a base class for all function + // stubs. This class holds the doc_string of the stubs. struct overloads_base { overloads_base(char const* doc_) - : doc(doc_) {} + : m_doc(doc_) {} + + overloads_base(char const* doc_, detail::keyword_range const& kw) + : m_doc(doc_), m_keywords(kw) {} char const* doc_string() const - { return doc; } + { + return m_doc; + } - char const* doc; + detail::keyword_range const& keywords() const + { + return m_keywords; + } + + private: + char const* m_doc; + detail::keyword_range m_keywords; }; -} -// overloads_proxy is generated by the overloads_common operator[] (see -// below). This class holds a user defined call policies of the stubs. + // overloads_proxy is generated by the overloads_common operator[] (see + // below). This class holds a user defined call policies of the stubs. + template + struct overloads_proxy + : public overloads_base + { + typedef typename OverloadsT::non_void_return_type non_void_return_type; + typedef typename OverloadsT::void_return_type void_return_type; -template -struct overloads_proxy - : public detail::overloads_base -{ - typedef typename OverloadsT::non_void_return_type non_void_return_type; - typedef typename OverloadsT::void_return_type void_return_type; + overloads_proxy( + CallPoliciesT const& policies_ + , char const* doc + , keyword_range const& kw + ) + : overloads_base(doc, kw) + , policies(policies_) + {} - overloads_proxy(CallPoliciesT const& policies_, char const* doc) - : detail::overloads_base(doc), policies(policies_) {} + CallPoliciesT + call_policies() const + { + return policies; + } - CallPoliciesT - call_policies() const - { return policies; } + CallPoliciesT policies; + }; - CallPoliciesT policies; -}; + // overloads_common is our default function stubs base class. This + // class returns the default_call_policies in its call_policies() + // member function. It can generate a overloads_proxy however through + // its operator[] + template + struct overloads_common + : public overloads_base + { + overloads_common(char const* doc) + : overloads_base(doc) {} -// overloads_common is our default function stubs base class. This class -// returns the default_call_policies in its call_policies() member function. -// It can generate a overloads_proxy however through its operator[] + overloads_common(char const* doc, keyword_range const& kw) + : overloads_base(doc, kw) {} -template -struct overloads_common -: public detail::overloads_base { + default_call_policies + call_policies() const + { + return default_call_policies(); + } - overloads_common(char const* doc) - : detail::overloads_base(doc) {} + template + overloads_proxy + operator[](CallPoliciesT const& policies) const + { + return overloads_proxy( + policies, this->doc_string(), this->keywords()); + } + }; - default_call_policies - call_policies() const - { return default_call_policies(); } +}}} // namespace boost::python::detail - template - ::boost::python::overloads_proxy - operator[](CallPoliciesT const& policies) const - { - return overloads_proxy - (policies, doc); - } -}; -}} // namespace boost::python - -/////////////////////////////////////////////////////////////////////////////// #define BOOST_PYTHON_TYPEDEF_GEN(z, index, data) \ typedef typename BOOST_PP_CAT(iter, index)::next \ BOOST_PP_CAT(iter, BOOST_PP_INC(index)); \ - typedef typename BOOST_PP_CAT(iter, index)::type BOOST_PP_CAT(T, index); \ + typedef typename BOOST_PP_CAT(iter, index)::type BOOST_PP_CAT(T, index); #define BOOST_PYTHON_FUNC_WRAPPER_GEN(z, index, data) \ static RT BOOST_PP_CAT(func_, \ @@ -112,14 +134,14 @@ struct overloads_common } #define BOOST_PYTHON_GEN_FUNCTION(fname, fstubs_name, n_args, n_dflts, ret) \ - struct fstubs_name { \ - \ + struct fstubs_name \ + { \ BOOST_STATIC_CONSTANT(int, n_funcs = BOOST_PP_INC(n_dflts)); \ BOOST_STATIC_CONSTANT(int, max_args = n_funcs); \ \ template \ - struct gen { \ - \ + struct gen \ + { \ typedef typename ::boost::mpl::begin::type rt_iter; \ typedef typename rt_iter::type RT; \ typedef typename rt_iter::next iter0; \ @@ -151,14 +173,14 @@ struct overloads_common } #define BOOST_PYTHON_GEN_MEM_FUNCTION(fname, fstubs_name, n_args, n_dflts, ret) \ - struct fstubs_name { \ - \ + struct fstubs_name \ + { \ BOOST_STATIC_CONSTANT(int, n_funcs = BOOST_PP_INC(n_dflts)); \ BOOST_STATIC_CONSTANT(int, max_args = n_funcs + 1); \ \ template \ - struct gen { \ - \ + struct gen \ + { \ typedef typename ::boost::mpl::begin::type rt_iter; \ typedef typename rt_iter::type RT; \ \ @@ -179,75 +201,82 @@ struct overloads_common }; \ }; -/////////////////////////////////////////////////////////////////////////////// -#if defined(BOOST_NO_VOID_RETURNS) - -#define BOOST_PYTHON_GEN_FUNCTION_STUB(fname, fstubs_name, n_args, n_dflts) \ - BOOST_PYTHON_GEN_FUNCTION \ - (fname, BOOST_PP_CAT(fstubs_name, _NV), n_args, n_dflts, return) \ - BOOST_PYTHON_GEN_FUNCTION \ - (fname, BOOST_PP_CAT(fstubs_name, _V), n_args, n_dflts, ;) \ - struct fstubs_name \ - : public boost::python::overloads_common \ - { \ - typedef BOOST_PP_CAT(fstubs_name, _NV) non_void_return_type; \ - typedef BOOST_PP_CAT(fstubs_name, _V) void_return_type; \ - \ - fstubs_name(char const* doc = 0) \ - : boost::python:: \ - overloads_common(doc) {} \ - }; \ - -/////////////////////////////////////////////////////////////////////////////// -#define BOOST_PYTHON_GEN_MEM_FUNCTION_STUB(fname, fstubs_name, n_args, n_dflts) \ - BOOST_PYTHON_GEN_MEM_FUNCTION \ - (fname, BOOST_PP_CAT(fstubs_name, _NV), n_args, n_dflts, return) \ - BOOST_PYTHON_GEN_MEM_FUNCTION \ - (fname, BOOST_PP_CAT(fstubs_name, _V), n_args, n_dflts, ;) \ - struct fstubs_name \ - : public boost::python::overloads_common \ +#define BOOST_PYTHON_OVERLOAD_CONSTRUCTORS(fstubs_name, n_args, n_dflts) \ + fstubs_name(char const* doc = 0) \ + : ::boost::python::detail::overloads_common(doc) {} \ + template \ + fstubs_name(char const* doc, Keywords const& keywords) \ + : ::boost::python::detail::overloads_common( \ + doc, keywords.range()) \ { \ - typedef BOOST_PP_CAT(fstubs_name, _NV) non_void_return_type; \ - typedef BOOST_PP_CAT(fstubs_name, _V) void_return_type; \ - \ - fstubs_name(char const* doc = 0) \ - : boost::python:: \ - overloads_common(doc) {} \ - }; \ - -#else - -/////////////////////////////////////////////////////////////////////////////// -#define BOOST_PYTHON_GEN_FUNCTION_STUB(fname, fstubs_name, n_args, n_dflts) \ - BOOST_PYTHON_GEN_FUNCTION \ - (fname, BOOST_PP_CAT(fstubs_name, _NV), n_args, n_dflts, return) \ - struct fstubs_name \ - : public boost::python::overloads_common \ + typedef typename ::boost::python::detail:: \ + error::more_keywords_than_function_arguments< \ + Keywords::size,(n_args+n_dflts)>::too_many_keywords assertion; \ + } \ + template \ + fstubs_name(Keywords const& keywords, char const* doc = 0) \ + : ::boost::python::detail::overloads_common( \ + doc, keywords.range()) \ { \ - typedef BOOST_PP_CAT(fstubs_name, _NV) non_void_return_type; \ - typedef BOOST_PP_CAT(fstubs_name, _NV) void_return_type; \ - \ - fstubs_name(char const* doc = 0) \ - : boost::python:: \ - overloads_common(doc) {} \ - }; \ + typedef typename ::boost::python::detail:: \ + error::more_keywords_than_function_arguments< \ + Keywords::size,(n_args+n_dflts)>::too_many_keywords assertion; \ + } -/////////////////////////////////////////////////////////////////////////////// -#define BOOST_PYTHON_GEN_MEM_FUNCTION_STUB(fname, fstubs_name, n_args, n_dflts) \ - BOOST_PYTHON_GEN_MEM_FUNCTION \ - (fname, BOOST_PP_CAT(fstubs_name, _NV), n_args, n_dflts, return) \ +# if defined(BOOST_NO_VOID_RETURNS) + +# define BOOST_PYTHON_GEN_FUNCTION_STUB(fname, fstubs_name, n_args, n_dflts) \ + BOOST_PYTHON_GEN_FUNCTION( \ + fname, BOOST_PP_CAT(fstubs_name, NonVoid), n_args, n_dflts, return) \ + BOOST_PYTHON_GEN_FUNCTION( \ + fname, BOOST_PP_CAT(fstubs_name, Void), n_args, n_dflts, ;) \ struct fstubs_name \ - : public boost::python::overloads_common \ + : public ::boost::python::detail::overloads_common \ { \ - typedef BOOST_PP_CAT(fstubs_name, _NV) non_void_return_type; \ - typedef BOOST_PP_CAT(fstubs_name, _NV) void_return_type; \ - \ - fstubs_name(char const* doc = 0) \ - : boost::python:: \ - overloads_common(doc) {} \ - }; \ + typedef BOOST_PP_CAT(fstubs_name, NonVoid) non_void_return_type; \ + typedef BOOST_PP_CAT(fstubs_name, Void) void_return_type; \ + BOOST_PYTHON_OVERLOAD_CONSTRUCTORS(fstubs_name, n_args, n_dflts) \ + }; -#endif // defined(BOOST_MSVC) +# define BOOST_PYTHON_GEN_MEM_FUNCTION_STUB(fname, fstubs_name, n_args, n_dflts) \ + BOOST_PYTHON_GEN_MEM_FUNCTION( \ + fname, BOOST_PP_CAT(fstubs_name, NonVoid), n_args, n_dflts, return) \ + BOOST_PYTHON_GEN_MEM_FUNCTION( \ + fname, BOOST_PP_CAT(fstubs_name, Void), n_args, n_dflts, ;) \ + struct fstubs_name \ + : public ::boost::python::detail::overloads_common \ + { \ + typedef BOOST_PP_CAT(fstubs_name, NonVoid) non_void_return_type; \ + typedef BOOST_PP_CAT(fstubs_name, Void) void_return_type; \ + BOOST_PYTHON_OVERLOAD_CONSTRUCTORS(fstubs_name, n_args, n_dflts) \ + }; + +# else // !defined(BOOST_NO_VOID_RETURNS) + +# define BOOST_PYTHON_GEN_FUNCTION_STUB(fname, fstubs_name, n_args, n_dflts) \ + BOOST_PYTHON_GEN_FUNCTION( \ + fname, BOOST_PP_CAT(fstubs_name, NonVoid), n_args, n_dflts, return) \ + struct fstubs_name \ + : public ::boost::python::detail::overloads_common \ + { \ + typedef BOOST_PP_CAT(fstubs_name, NonVoid) non_void_return_type; \ + typedef BOOST_PP_CAT(fstubs_name, NonVoid) void_return_type; \ + BOOST_PYTHON_OVERLOAD_CONSTRUCTORS(fstubs_name, n_args, n_dflts) \ + }; + + +# define BOOST_PYTHON_GEN_MEM_FUNCTION_STUB(fname, fstubs_name, n_args, n_dflts) \ + BOOST_PYTHON_GEN_MEM_FUNCTION( \ + fname, BOOST_PP_CAT(fstubs_name, NonVoid), n_args, n_dflts, return) \ + struct fstubs_name \ + : public ::boost::python::detail::overloads_common \ + { \ + typedef BOOST_PP_CAT(fstubs_name, NonVoid) non_void_return_type; \ + typedef BOOST_PP_CAT(fstubs_name, NonVoid) void_return_type; \ + BOOST_PYTHON_OVERLOAD_CONSTRUCTORS(fstubs_name, n_args, n_dflts) \ + }; + +# endif // !defined(BOOST_NO_VOID_RETURNS) /////////////////////////////////////////////////////////////////////////////// // @@ -278,14 +307,14 @@ struct overloads_common // // Generates this code: // -// struct foo_stubs_NV { -// +// struct foo_stubsNonVoid +// { // static const int n_funcs = 4; // static const int max_args = n_funcs; // // template -// struct gen { -// +// struct gen +// { // typedef typename ::boost::mpl::begin::type rt_iter; // typedef typename rt_iter::type RT; // typedef typename rt_iter::next iter0; @@ -312,28 +341,27 @@ struct overloads_common // }; // }; // -// struct foo_stubs -// : public boost::python::overloads_common +// struct foo_overloads +// : public boost::python::detail::overloads_common +// { +// typedef foo_overloadsNonVoid non_void_return_type; +// typedef foo_overloadsNonVoid void_return_type; // -// typedef foo_stubs_NV non_void_return_type; -// typedef foo_stubs_NV void_return_type; -// -// fstubs_name(char const* doc = 0) -// : boost::python:: -// overloads_common(doc) {} +// foo_overloads(char const* doc = 0) +// : boost::python::detail::overloads_common(doc) {} // }; // // The typedefs non_void_return_type and void_return_type are // used to handle compilers that do not support void returns. The // example above typedefs non_void_return_type and -// void_return_type to foo_stubs_NV. On compilers that do not -// support void returns, there are two versions: foo_stubs_NV and -// foo_stubs_V. The "V" version is almost identical to the "NV" -// version except for the return type (void) and the lack of the -// return keyword. +// void_return_type to foo_overloadsNonVoid. On compilers that do +// not support void returns, there are two versions: +// foo_overloadsNonVoid and foo_overloadsVoid. The "Void" +// version is almost identical to the "NonVoid" version except +// for the return type (void) and the lack of the return keyword. // -// See the overloads_common above for a description of the foo_stubs' -// base class. +// See the overloads_common above for a description of the +// foo_overloads' base class. // /////////////////////////////////////////////////////////////////////////////// #define BOOST_PYTHON_FUNCTION_OVERLOADS(generator_name, fname, min_args, max_args) \ diff --git a/include/boost/python/detail/indirect_traits.hpp b/include/boost/python/detail/indirect_traits.hpp index c6f8bcc7..5d1a2697 100644 --- a/include/boost/python/detail/indirect_traits.hpp +++ b/include/boost/python/detail/indirect_traits.hpp @@ -16,6 +16,8 @@ # include # include # include +# include +# include namespace boost { namespace python { namespace detail { @@ -163,6 +165,8 @@ struct is_reference_to_class >::value >::value) ); + typedef mpl::bool_c type; + BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_reference_to_class,(T)) }; template @@ -343,7 +347,6 @@ struct is_reference_to_volatile { }; - template typename is_pointer_help::type reference_to_pointer_helper(V&); outer_no_type reference_to_pointer_helper(...); @@ -370,8 +373,10 @@ struct is_reference_to_class BOOST_STATIC_CONSTANT( bool, value = (is_reference::value - && sizeof(reference_to_class_helper(t)) == sizeof(inner_yes_type)) + & (sizeof(reference_to_class_helper(t)) == sizeof(inner_yes_type))) ); + typedef mpl::bool_c type; + BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_reference_to_class,(T)) }; template diff --git a/include/boost/python/detail/make_keyword_range_fn.hpp b/include/boost/python/detail/make_keyword_range_fn.hpp new file mode 100644 index 00000000..e807f158 --- /dev/null +++ b/include/boost/python/detail/make_keyword_range_fn.hpp @@ -0,0 +1,45 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef MAKE_KEYWORD_RANGE_FN_DWA2002927_HPP +# define MAKE_KEYWORD_RANGE_FN_DWA2002927_HPP + +# include +# include +# include +# include + +namespace boost { namespace python { namespace detail { + +template +object make_keyword_range_function(F f, Policies const& policies, keyword_range const& kw) +{ + enum { n_arguments = detail::arg_tuple_size::value }; + return objects::function_object( + ::boost::bind(detail::caller(), f, _1, _2, policies) + , n_arguments + , kw); +} + +template +object make_keyword_range_constructor( + Policies const& policies + , detail::keyword_range const& kw + , HolderGenerator* = 0 + , ArgList* = 0) +{ + enum { nargs = mpl::size::value }; + + return objects::function_object( + ::boost::bind(detail::caller(), + objects::make_holder + ::template apply::execute + , _1, _2, policies) + , nargs + 1, kw); +} + +}}} // namespace boost::python::detail + +#endif // MAKE_KEYWORD_RANGE_FN_DWA2002927_HPP diff --git a/include/boost/python/detail/scope.hpp b/include/boost/python/detail/scope.hpp new file mode 100644 index 00000000..f8ece8f9 --- /dev/null +++ b/include/boost/python/detail/scope.hpp @@ -0,0 +1,15 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef SCOPE_DWA2002927_HPP +# define SCOPE_DWA2002927_HPP + +namespace boost { namespace python { namespace detail { + +void BOOST_PYTHON_DECL scope_setattr_doc(char const* name, object const& obj, char const* doc); + +}}} // namespace boost::python::detail + +#endif // SCOPE_DWA2002927_HPP diff --git a/include/boost/python/init.hpp b/include/boost/python/init.hpp index 5565caba..1e3f23bb 100644 --- a/include/boost/python/init.hpp +++ b/include/boost/python/init.hpp @@ -11,6 +11,7 @@ #define INIT_JDG20020820_HPP #include +#include #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include @@ -34,6 +36,8 @@ #include #include +#include + /////////////////////////////////////////////////////////////////////////////// #define BOOST_PYTHON_OVERLOAD_TYPES_WITH_DEFAULT \ BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT( \ @@ -55,13 +59,22 @@ namespace boost { namespace python { template -struct init; // forward declaration +class init; // forward declaration + -/////////////////////////////////////// template struct optional; // forward declaration -namespace detail { +namespace detail +{ + namespace error + { + template + struct more_keywords_than_init_arguments + { + typedef char too_many_keywords[init_args - keywords >= 0 ? 1 : -1]; + }; + } /////////////////////////////////////////////////////////////////////////// // @@ -89,7 +102,7 @@ namespace detail { sizeof(f(t())) == sizeof(::boost::type_traits::yes_type)); typedef mpl::bool_c type; - BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_optional,(T)) // needed for MSVC & Borland + BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_optional,(T)) }; /////////////////////////////////////// @@ -111,61 +124,114 @@ namespace detail { struct is_optional : is_optional_impl { typedef mpl::bool_c::value> type; - BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_optional,(T)) // needed for MSVC & Borland + BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_optional,(T)) }; #endif // defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) } // namespace detail template -struct init_base { - +struct init_base +{ + 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(this); } + { + return *static_cast(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: // data members + char const* m_doc; + detail::keyword_range m_keywords; }; template -struct init_with_call_policies -: public init_base > +class init_with_call_policies + : public init_base > { + typedef init_base > base; + public: BOOST_STATIC_CONSTANT(int, n_arguments = InitT::n_arguments); BOOST_STATIC_CONSTANT(int, n_defaults = InitT::n_defaults); typedef typename InitT::reversed_args reversed_args; - init_with_call_policies(CallPoliciesT const& policies_, char const* doc_) - : policies(policies_), doc(doc_) {} + init_with_call_policies( + CallPoliciesT const& policies_ + , char const* doc_ + , detail::keyword_range const& keywords + ) + : base(doc_, keywords) + , m_policies(policies_) + {} - char const* doc_string() const - { return doc; } - - CallPoliciesT - call_policies() const - { return policies; } - - CallPoliciesT policies; - char const* doc; + CallPoliciesT const& call_policies() const + { + return this->m_policies; + } + + private: // data members + CallPoliciesT m_policies; }; template -struct init : public init_base > +class init : public init_base > { + typedef init_base > base; + public: typedef init self_t; init(char const* doc_ = 0) - : doc(doc_) {} + : base(doc_) + { + } + + template + init(char const* doc_, Keywords const& kw) + : base(doc_, std::make_pair(kw.base(), kw.base() + Keywords::size)) + { + typedef typename detail::error::more_keywords_than_init_arguments< + Keywords::size, n_arguments + >::too_many_keywords assertion; + } - char const* doc_string() const - { return doc; } - - default_call_policies - call_policies() const - { return default_call_policies(); } + template + init(Keywords const& kw) + : base(0, kw.range()) + { + typedef typename detail::error::more_keywords_than_init_arguments< + Keywords::size, n_arguments + >::too_many_keywords assertion; + } template init_with_call_policies operator[](CallPoliciesT const& policies) const - { return init_with_call_policies(policies, doc); } + { + return init_with_call_policies( + policies, this->doc_string(), this->keywords()); + } typedef detail::type_list signature_; typedef typename mpl::end::type finish; @@ -213,37 +279,47 @@ struct init : public init_base > // Count the maximum number of arguments BOOST_STATIC_CONSTANT(int, n_arguments = mpl::size::value); - - char const* doc; }; +# if 1 template <> // specialization for zero args -struct init<> : public init_base > +class init<> : public init_base > { + typedef init_base > base; + public: typedef init<> self_t; init(char const* doc_ = 0) - : doc(doc_) {} + : base(doc_) + { + } + + template + init(char const* doc_, Keywords const& kw) + : base(doc_, std::make_pair(kw.base(), kw.base() + Keywords::size)) + { + } - char const* doc_string() const - { return doc; } - - default_call_policies - call_policies() const - { return default_call_policies(); } + template + init(Keywords const& kw) + : base(0, std::make_pair(kw.base(), kw.base() + Keywords::size)) + { + } template init_with_call_policies operator[](CallPoliciesT const& policies) const - { return init_with_call_policies(policies, doc); } + { + return init_with_call_policies( + policies, this->doc_string(), this->keywords()); + } BOOST_STATIC_CONSTANT(int, n_defaults = 0); BOOST_STATIC_CONSTANT(int, n_arguments = 0); typedef detail::type_list<> reversed_args; - - char const* doc; }; +# endif /////////////////////////////////////////////////////////////////////////////// // @@ -261,7 +337,13 @@ struct optional namespace detail { template - void def_init_reversed(ClassT& cl, ReversedArgs const&, CallPoliciesT const& policies, char const* doc) + void def_init_reversed( + ClassT& cl + , ReversedArgs const& + , CallPoliciesT const& policies + , char const* doc + , detail::keyword_range const& keywords_ + ) { typedef typename mpl::fold< ReversedArgs @@ -274,8 +356,9 @@ namespace detail cl.def( "__init__", - python::make_constructor( + detail::make_keyword_range_constructor( policies + , keywords_ // Using runtime type selection works around a CWPro7 bug. , holder_selector_t::execute((held_type_t*)0).get() ) @@ -299,12 +382,20 @@ namespace detail struct define_class_init_helper { template - static void apply(ClassT& cl, CallPoliciesT const& policies, ReversedArgs const& args, char const* doc) + static void apply( + ClassT& cl + , CallPoliciesT const& policies + , ReversedArgs const& args + , char const* doc + , detail::keyword_range keywords) { - def_init_reversed(cl, args, policies, doc); + def_init_reversed(cl, args, policies, doc, keywords); + if (keywords.second > keywords.first) + --keywords.second; + typename mpl::pop_front::type next; - define_class_init_helper::apply(cl, policies, next, doc); + define_class_init_helper::apply(cl, policies, next, doc, keywords); } }; @@ -322,9 +413,14 @@ namespace detail struct define_class_init_helper<0> { template - static void apply(ClassT& cl, CallPoliciesT const& policies, ReversedArgs const& args, char const* doc) + static void apply( + ClassT& cl + , CallPoliciesT const& policies + , ReversedArgs const& args + , char const* doc + , detail::keyword_range const& keywords) { - def_init_reversed(cl, args, policies, doc); + def_init_reversed(cl, args, policies, doc, keywords); } }; } @@ -356,7 +452,7 @@ define_init(ClassT& cl, InitT const& i) { typedef typename InitT::reversed_args reversed_args; detail::define_class_init_helper::apply( - cl, i.call_policies(), reversed_args(), i.doc_string()); + cl, i.call_policies(), reversed_args(), i.doc_string(), i.keywords()); } }} // namespace boost::python diff --git a/include/boost/python/make_function.hpp b/include/boost/python/make_function.hpp index decdf5b4..2277371f 100644 --- a/include/boost/python/make_function.hpp +++ b/include/boost/python/make_function.hpp @@ -7,6 +7,7 @@ # define MAKE_FUNCTION_DWA20011221_HPP # include +# include # include # include # include @@ -32,6 +33,20 @@ object make_function(F f, Policies const& policies) , detail::arg_tuple_size::value); } +template +object make_function(F f, Policies const& policies, Keywords const& keywords) +{ + enum { n_arguments = detail::arg_tuple_size::value }; + typedef typename detail::error::more_keywords_than_function_arguments< + Keywords::size, n_arguments + >::too_many_keywords assertion; + + return objects::function_object( + ::boost::bind(detail::caller(), f, _1, _2, policies) + , n_arguments + , keywords.range()); +} + template object make_constructor(HolderGenerator* = 0, ArgList* = 0) { diff --git a/include/boost/python/module.hpp b/include/boost/python/module.hpp index 2bf923c0..69e9001d 100644 --- a/include/boost/python/module.hpp +++ b/include/boost/python/module.hpp @@ -71,11 +71,12 @@ class module : public detail::module_base char const* doc, void const*) { - typedef detail::def_helper helper; + detail::def_helper helper(policy_or_doc, doc); this->setattr_doc( - name, boost::python::make_function(fn, helper::get_policy(policy_or_doc)), - helper::get_doc(policy_or_doc, doc)); + name + , boost::python::make_function(fn, helper.policies()) + , helper.doc()); } template diff --git a/include/boost/python/object/function.hpp b/include/boost/python/object/function.hpp index c14f57e3..1a3c3f5f 100644 --- a/include/boost/python/object/function.hpp +++ b/include/boost/python/object/function.hpp @@ -7,6 +7,7 @@ # define FUNCTION_DWA20011214_HPP # include +# include # include # include # include @@ -17,7 +18,13 @@ namespace boost { namespace python { namespace objects { struct BOOST_PYTHON_DECL function : PyObject { - function(py_function const&, unsigned min_args, unsigned max_args = 0); + function( + py_function const& + , unsigned min_arity + , unsigned max_arity + , python::detail::keyword const* names_and_defaults + , unsigned num_keywords); + ~function(); PyObject* call(PyObject*, PyObject*) const; @@ -42,11 +49,12 @@ struct BOOST_PYTHON_DECL function : PyObject private: // data members py_function m_fn; - unsigned m_min_args; - unsigned m_max_args; + unsigned m_min_arity; + unsigned m_max_arity; handle m_overloads; object m_name; object m_doc; + object m_arg_names; }; // @@ -66,7 +74,7 @@ inline object const& function::name() const { return this->m_name; } - + }}} // namespace boost::python::objects #endif // FUNCTION_DWA20011214_HPP diff --git a/include/boost/python/object/function_object.hpp b/include/boost/python/object/function_object.hpp index 03535ec3..d3661563 100644 --- a/include/boost/python/object/function_object.hpp +++ b/include/boost/python/object/function_object.hpp @@ -8,17 +8,36 @@ # include # include # include +# include +# include -namespace boost { namespace python { namespace objects { +namespace boost { namespace python { -BOOST_PYTHON_DECL api::object function_object_impl(boost::function2 const& f, unsigned min_args, unsigned max_args = 0); +namespace objects +{ + BOOST_PYTHON_DECL api::object function_object( + py_function const& f + , unsigned min_arity, unsigned max_arity + , python::detail::keyword_range const&); -template -inline object function_object(F const& f, unsigned min_args, unsigned max_args = 0) -{ - return objects::function_object_impl(boost::function2(f), min_args, max_args); + BOOST_PYTHON_DECL api::object function_object( + py_function const& f + , unsigned arity + , python::detail::keyword_range const&); + + BOOST_PYTHON_DECL api::object function_object(py_function const& f, unsigned arity); + + // Add an attribute to the name_space with the given name. If it is + // a Boost.Python function object + // (boost/python/object/function.hpp), and an existing function is + // already there, add it as an overload. + BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute); + + BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute, char const* doc); } -}}} // namespace boost::python::objects +}} // namespace boost::python::objects #endif // FUNCTION_OBJECT_DWA2002725_HPP diff --git a/src/module.cpp b/src/module.cpp index 2dd476d1..d81e626a 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -6,8 +6,8 @@ // The author gratefully acknowleges the support of Dragon Systems, Inc., in // producing this work. +#include #include -#include #include #include #include @@ -35,7 +35,7 @@ void module_base::setattr_doc(const char* name, python::object const& x, char co { // Use function::add_to_namespace to achieve overloading if // appropriate. - objects::function::add_to_namespace(python::object(m_module), name, x, doc); + objects::add_to_namespace(python::object(m_module), name, x, doc); } void BOOST_PYTHON_DECL scope_setattr_doc(char const* name, object const& x, char const* doc) @@ -43,7 +43,7 @@ void BOOST_PYTHON_DECL scope_setattr_doc(char const* name, object const& x, char // Use function::add_to_namespace to achieve overloading if // appropriate. scope current; - objects::function::add_to_namespace(current, name, x, doc); + objects::add_to_namespace(current, name, x, doc); } void module_base::add(type_handle const& x) diff --git a/src/object/function.cpp b/src/object/function.cpp index 6d013b3a..259bfb86 100644 --- a/src/object/function.cpp +++ b/src/object/function.cpp @@ -7,22 +7,54 @@ #include #include #include -#include #include #include +#include +#include +#include + #include #include -#include namespace boost { namespace python { namespace objects { extern PyTypeObject function_type; -function::function(py_function const& implementation, unsigned min_args, unsigned max_args) +function::function( + py_function const& implementation + , unsigned min_arity + , unsigned max_arity + , python::detail::keyword const* names_and_defaults + , unsigned num_keywords + ) : m_fn(implementation) - , m_min_args(min_args) - , m_max_args(std::max(max_args,min_args)) + , m_min_arity(min_arity) + // was using std::max here, but a problem with MinGW-2.95 and + // our directory prevents it. + , m_max_arity(max_arity > min_arity ? max_arity : min_arity) { + if (names_and_defaults != 0) + { + unsigned keyword_offset + = m_max_arity > num_keywords ? m_max_arity - num_keywords : 0; + + + m_arg_names = object(handle<>(PyTuple_New(m_max_arity))); + for (unsigned j = 0; j < keyword_offset; ++j) + PyTuple_SET_ITEM(m_arg_names.ptr(), j, incref(Py_None)); + + for (unsigned i = 0; i < num_keywords; ++i) + { + PyTuple_SET_ITEM( + m_arg_names.ptr() + , i + keyword_offset + , expect_non_null( + PyString_FromString(const_cast(names_and_defaults[i].name)) + ) + ); + } + } + PyObject* p = this; if (function_type.ob_type == 0) { @@ -39,14 +71,51 @@ function::~function() PyObject* function::call(PyObject* args, PyObject* keywords) const { std::size_t nargs = PyTuple_GET_SIZE(args); + std::size_t nkeywords = keywords ? PyDict_Size(keywords) : 0; + std::size_t total_args = nargs + nkeywords; + function const* f = this; do { // Check for a plausible number of arguments - if (nargs >= f->m_min_args && nargs <= f->m_max_args) + if (total_args >= f->m_min_arity && total_args <= f->m_max_arity) { + handle<> args2(allow_null(borrowed(args))); + if (nkeywords > 0) + { + if (!f->m_arg_names + || static_cast(PyTuple_Size(f->m_arg_names.ptr())) < total_args) + { + args2 = handle<>(); // signal failure + } + else + { + // build a new arg tuple + args2 = handle<>(PyTuple_New(total_args)); + + // Fill in the positional arguments + for (std::size_t i = 0; i < nargs; ++i) + PyTuple_SET_ITEM(args2.get(), i, incref(PyTuple_GET_ITEM(args, i))); + + // Grab remaining arguments by name from the keyword dictionary + for (std::size_t j = nargs; j < total_args; ++j) + { + PyObject* value = PyDict_GetItem( + keywords, PyTuple_GET_ITEM(f->m_arg_names.ptr(), j)); + + if (!value) + { + PyErr_Clear(); + args2 = handle<>(); + break; + } + PyTuple_SET_ITEM(args2.get(), j, incref(value)); + } + } + } + // Call the function - PyObject* result = f->m_fn(args, keywords); + PyObject* result = args2 ? f->m_fn(args2.get(), 0) : 0; // If the result is NULL but no error was set, m_fn failed // the argument-matching test. @@ -154,7 +223,10 @@ namespace handle not_implemented_function() { - static object keeper(function_object(¬_implemented_impl, 2, 3)); + static object keeper( + function_object(¬_implemented_impl, 2, 3 + , python::detail::keyword_range()) + ); return handle(borrowed(downcast(keeper.ptr()))); } } @@ -222,6 +294,19 @@ void function::add_to_namespace( } } +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute) +{ + function::add_to_namespace(name_space, name, attribute); +} + +BOOST_PYTHON_DECL void add_to_namespace( + object const& name_space, char const* name, object const& attribute, char const* doc) +{ + function::add_to_namespace(name_space, name, attribute, doc); +} + + namespace { struct bind_return @@ -350,31 +435,35 @@ PyTypeObject function_type = { 0 /* tp_new */ }; -object function_object_impl(py_function const& f, unsigned min_args, unsigned max_args) +object function_object( + py_function const& f, unsigned min_arity, unsigned max_arity + , python::detail::keyword_range const& keywords) { return python::object( python::detail::new_non_null_reference( - new function(f, min_args, max_args))); + new function( + f, min_arity, max_arity, keywords.first, keywords.second - keywords.first))); } -handle<> function_handle_impl(py_function const& f, unsigned min_args, unsigned max_args) +object function_object( + py_function const& f + , unsigned arity + , python::detail::keyword_range const& kw) +{ + return function_object(f, arity, arity, kw); +} + +object function_object(py_function const& f, unsigned arity) +{ + return function_object(f, arity, arity, python::detail::keyword_range()); +} + + +handle<> function_handle_impl(py_function const& f, unsigned min_arity, unsigned max_arity) { return python::handle<>( allow_null( - new function(f, min_args, max_args))); + new function(f, min_arity, max_arity, 0, 0))); } -BOOST_PYTHON_DECL void add_to_namespace( - object const& name_space, char const* name, object const& attribute) -{ - function::add_to_namespace(name_space, name, attribute); -} - -BOOST_PYTHON_DECL void add_to_namespace( - object const& name_space, char const* name, object const& attribute, char const* doc) -{ - function::add_to_namespace(name_space, name, attribute, doc); -} - - }}} // namespace boost::python::objects diff --git a/src/object/iterator.cpp b/src/object/iterator.cpp index 384d6845..1718ee59 100644 --- a/src/object/iterator.cpp +++ b/src/object/iterator.cpp @@ -5,7 +5,6 @@ // to its suitability for any purpose. #include -#include #include #include diff --git a/test/Jamfile b/test/Jamfile index f8e3d631..6e305b42 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -54,10 +54,10 @@ rule bpl-test ( name ? : files * : requirements * ) boost-python-runtest $(name) : $(py) $(modules) ; } -bpl-test numpy ; - -bpl-test enum ; bpl-test minimal ; +bpl-test args ; +bpl-test numpy ; +bpl-test enum ; bpl-test docstring ; bpl-test exception_translator ; bpl-test pearu1 : test_cltree.py cltree.cpp ; diff --git a/test/args.cpp b/test/args.cpp new file mode 100644 index 00000000..9727b902 --- /dev/null +++ b/test/args.cpp @@ -0,0 +1,81 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#include +#include +#include +#include +#include +#include +#include "test_class.hpp" + +using namespace boost::python; + +tuple f(int x = 1, double y = 4.25, char const* z = "wow") +{ + return make_tuple(x, y, z); +} + +BOOST_PYTHON_FUNCTION_OVERLOADS(f_overloads, f, 0, 3) + +typedef test_class<> Y; + +struct X +{ + X(int a0 = 0, int a1 = 1) : inner0(a0), inner1(a1) {} + tuple f(int x = 1, double y = 4.25, char const* z = "wow") + { + return make_tuple(x, y, z); + } + + Y const& inner(bool n) const { return n ? inner1 : inner0; } + + Y inner0; + Y inner1; +}; + +BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_f_overloads, X::f, 0, 3) + +BOOST_PYTHON_MODULE_INIT(args_ext) +{ + def("f", f, args("x", "y", "z") + , "This is f's docstring" + ); + +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1200 + // MSVC6 gives a fatal error LNK1179: invalid or corrupt file: + // duplicate comdat error if we try to re-use the exact type of f + // here, so substitute long for int. + tuple (*f)(long,double,char const*) = 0; +#endif + def("f1", f, f_overloads("f1's docstring", args("x", "y", "z"))); + def("f2", f, f_overloads(args("x", "y", "z"))); + def("f3", f, f_overloads(args("x", "y", "z"), "f3's docstring")); + + class_("Y", init()) + .def("value", &Y::value) + ; + + class_("X", "This is X's docstring") + .def(init >(args("a0", "a1"))) + .def("f", &X::f + , "This is X.f's docstring" + , args("x", "y", "z")) + + // Just to prove that all the different argument combinations work + .def("inner0", &X::inner, return_internal_reference<>(), args("n"), "docstring") + .def("inner1", &X::inner, return_internal_reference<>(), "docstring", args("n")) + + .def("inner2", &X::inner, args("n"), return_internal_reference<>(), "docstring") + .def("inner3", &X::inner, "docstring", return_internal_reference<>(), args("n")) + + .def("inner4", &X::inner, args("n"), "docstring", return_internal_reference<>()) + .def("inner5", &X::inner, "docstring", args("n"), return_internal_reference<>()) + + .def("f1", &X::f, X_f_overloads(args("x", "y", "z"))) + ; + + def("inner", &X::inner, "docstring", args("self", "n"), return_internal_reference<>()); +} diff --git a/test/args.py b/test/args.py new file mode 100644 index 00000000..665fae41 --- /dev/null +++ b/test/args.py @@ -0,0 +1,161 @@ +""" +>>> from args_ext import * + +>>> f(x= 1, y = 3, z = 'hello') +(1, 3.0, 'hello') + +>>> f(z = 'hello', x = 3, y = 2.5) +(3, 2.5, 'hello') + +>>> f(1, z = 'hi', y = 3) +(1, 3.0, 'hi') + +>>> try: f(1, 2, 'hello', bar = 'baz') +... except TypeError: pass +... else: print 'expected an exception: unknown keyword' + + + Exercise the functions using default stubs + +>>> f1(z = 'nix', y = .125, x = 2) +(2, 0.125, 'nix') +>>> f1(y = .125, x = 2) +(2, 0.125, 'wow') +>>> f1(x = 2) +(2, 4.25, 'wow') +>>> f1() +(1, 4.25, 'wow') + +>>> f2(z = 'nix', y = .125, x = 2) +(2, 0.125, 'nix') +>>> f2(y = .125, x = 2) +(2, 0.125, 'wow') +>>> f2(x = 2) +(2, 4.25, 'wow') +>>> f2() +(1, 4.25, 'wow') + +>>> f3(z = 'nix', y = .125, x = 2) +(2, 0.125, 'nix') +>>> f3(y = .125, x = 2) +(2, 0.125, 'wow') +>>> f3(x = 2) +(2, 4.25, 'wow') +>>> f3() +(1, 4.25, 'wow') + + Member function tests + +>>> q = X() +>>> q.f(x= 1, y = 3, z = 'hello') +(1, 3.0, 'hello') + +>>> q.f(z = 'hello', x = 3, y = 2.5) +(3, 2.5, 'hello') + +>>> q.f(1, z = 'hi', y = 3) +(1, 3.0, 'hi') + +>>> try: q.f(1, 2, 'hello', bar = 'baz') +... except TypeError: pass +... else: print 'expected an exception: unknown keyword' + + Exercise member functions using default stubs + +>>> q.f1(z = 'nix', y = .125, x = 2) +(2, 0.125, 'nix') +>>> q.f1(y = .125, x = 2) +(2, 0.125, 'wow') +>>> q.f1(x = 2) +(2, 4.25, 'wow') +>>> q.f1() +(1, 4.25, 'wow') + +>>> X.f.__doc__ +"This is X.f's docstring" + +>>> xfuncs = (X.inner0, X.inner1, X.inner2, X.inner3, X.inner4, X.inner5) +>>> for f in xfuncs: +... print f(q,1).value(), +... print f(q, n = 1).value(), +... print f(q, n = 0).value(), +... print f.__doc__ +1 1 0 docstring +1 1 0 docstring +1 1 0 docstring +1 1 0 docstring +1 1 0 docstring +1 1 0 docstring + +>>> x = X(a1 = 44, a0 = 22) +>>> x.inner0(0).value() +22 +>>> x.inner0(1).value() +44 + +>>> x = X(a0 = 7) +>>> x.inner0(0).value() +7 +>>> x.inner0(1).value() +1 + +>>> inner(n = 1, self = q).value() +1 +""" +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + sys.exit(run()[0]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/bienstman2.cpp b/test/bienstman2.cpp index dd7ba532..7e4f951c 100644 --- a/test/bienstman2.cpp +++ b/test/bienstman2.cpp @@ -2,6 +2,9 @@ #include #include +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1200 // works around a name lookup bug +# define C C_ +#endif struct C {}; struct D {};