From cdf49c6ac00eb4fe46eb1ca47b1aee8e32aff3f7 Mon Sep 17 00:00:00 2001 From: Joel de Guzman Date: Mon, 12 Aug 2002 14:22:36 +0000 Subject: [PATCH] Default Arguments Handling [SVN r14786] --- include/boost/python/class.hpp | 47 ++-- include/boost/python/detail/defaults_def.hpp | 97 +++++++ include/boost/python/detail/defaults_gen.hpp | 253 +++++++++++++++++++ include/boost/python/module.hpp | 21 +- test/defaults.cpp | 64 +++++ test/defaults.py | 82 ++++++ 6 files changed, 541 insertions(+), 23 deletions(-) create mode 100644 include/boost/python/detail/defaults_def.hpp create mode 100644 include/boost/python/detail/defaults_gen.hpp create mode 100644 test/defaults.cpp create mode 100644 test/defaults.py diff --git a/include/boost/python/class.hpp b/include/boost/python/class.hpp index 4af8d3e7..cf918ed6 100644 --- a/include/boost/python/class.hpp +++ b/include/boost/python/class.hpp @@ -28,16 +28,17 @@ # include # include # include +# include -namespace boost { namespace python { +namespace boost { namespace python { namespace detail { struct write_type_id; - + template struct select_held_type; - + template struct has_noncopyable; @@ -58,7 +59,11 @@ namespace detail template static inline void register_copy_constructor(mpl::bool_t const&, Holder*, object const&, T* = 0) { - } + } + + // Forward declaration (detail/defaults_def.hpp) + template + struct func_stubs_base; } // @@ -79,18 +84,18 @@ class class_ : public objects::class_base typedef class_ self; BOOST_STATIC_CONSTANT(bool, is_copyable = (!detail::has_noncopyable::value)); - + typedef typename detail::select_held_type< X1, typename detail::select_held_type< X2, typename detail::select_held_type< X3 >::type>::type>::type held_type; - + public: // Automatically derive the class name - only works on some // compilers because type_info::name is sometimes mangled (gcc) class_(); - + // Construct with the class name. [ Would have used a default // argument but gcc-2.95.2 choked on typeid(T).name() as a default // parameter value] @@ -111,7 +116,7 @@ class class_ : public objects::class_base self& def(char const* name, Fn fn, CallPolicyOrDoc const& policy_or_doc, char const* doc = 0) { typedef detail::def_helper helper; - + this->def_impl( name, fn, helper::get_policy(policy_or_doc), helper::get_doc(policy_or_doc, doc), &fn); @@ -124,7 +129,15 @@ class class_ : public objects::class_base typedef detail::operator_ op_t; return this->def(op.name(), &op_t::template apply::execute); } - + + template + self& def(detail::func_stubs_base const& stubs, ArgsT args) + { + // JDG 8-12-2002 + detail::define_with_defaults(stubs.derived(), *this, args); + return *this; + } + // Define the constructor with the given Args, which should be an // MPL sequence of types. template @@ -142,7 +155,7 @@ class class_ : public objects::class_base self& def_init(Args const&, CallPolicyOrDoc const& policy_or_doc, char const* doc = 0) { typedef detail::def_helper helper; - + return this->def( "__init__", python::make_constructor( @@ -211,7 +224,7 @@ class class_ : public objects::class_base 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) , doc); @@ -226,13 +239,13 @@ class class_ : public objects::class_base private: // types typedef objects::class_id class_id; - + typedef typename detail::select_bases::type >::type >::type bases; - + // A helper class which will contain an array of id objects to be // passed to the base class constructor struct id_vector @@ -242,12 +255,12 @@ class class_ : public objects::class_base { // Stick the derived class id into the first element of the array ids[0] = type_id(); - + // Write the rest of the elements into succeeding positions. class_id* p = ids + 1; mpl::for_each::execute(&p); } - + BOOST_STATIC_CONSTANT( std::size_t, size = mpl::size::value + 1); class_id ids[size]; @@ -265,7 +278,7 @@ inline class_::class_() { // register converters objects::register_class_from_python(); - + detail::register_copy_constructor( mpl::bool_t() , objects::select_holder((held_type*)0).get() @@ -278,7 +291,7 @@ inline class_::class_(char const* name, char const* doc) { // register converters objects::register_class_from_python(); - + detail::register_copy_constructor( mpl::bool_t() , objects::select_holder((held_type*)0).get() diff --git a/include/boost/python/detail/defaults_def.hpp b/include/boost/python/detail/defaults_def.hpp new file mode 100644 index 00000000..6563bed0 --- /dev/null +++ b/include/boost/python/detail/defaults_def.hpp @@ -0,0 +1,97 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 DEFAULTS_DEF_JDG20020811_HPP +#define DEFAULTS_DEF_JDG20020811_HPP + +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace python { + +namespace detail { + +/////////////////////////////////////////////////////////////////////////////// +#define BPL_IMPL_STUB_FUNC_DEF(INDEX, DATA) \ + \ + template \ + inline void \ + define_stub_function \ + ( \ + char const* name, \ + StubsT, \ + HolderT& holder, \ + boost::mpl::int_t \ + ) \ + { \ + holder.def(name, &StubsT::BOOST_PP_CAT(func_, INDEX)); \ + } \ + +BOOST_PP_REPEAT(BOOST_PYTHON_MAX_ARITY, BPL_IMPL_STUB_FUNC_DEF, BOOST_PP_EMPTY) + +/////////////////////////////////////////////////////////////////////////////// + template + struct define_with_defaults_helper { + + template + static void + def(char const* name, StubsT stubs, HolderT& holder) + { + define_stub_function(name, stubs, holder, boost::mpl::int_t()); + define_with_defaults_helper::def(name, stubs, holder); + } + }; + +/////////////////////////////////////// + template <> + struct define_with_defaults_helper<0> { + + template + static void + def(char const* name, StubsT stubs, HolderT& holder) + { + define_stub_function(name, stubs, holder, boost::mpl::int_t<0>()); + } + }; + +/////////////////////////////////////////////////////////////////////////////// + template + inline void + define_with_defaults(StubsT, HolderT& holder, ArgsT args) + { + typedef typename mpl::select_type + < + boost::is_same::type>::value, + typename StubsT::v_type, + typename StubsT::nv_type + > + ::type stubs_type; + + BOOST_STATIC_ASSERT( + (stubs_type::max_args + 1) == boost::mpl::size::value); + + typedef stubs_type::template gen gen_type; + define_with_defaults_helper::def + (stubs_type::name(), gen_type(), holder); + } + +} // namespace detail + +}} // namespace boost::python + +/////////////////////////////////////////////////////////////////////////////// +#endif // DEFAULTS_DEF_JDG20020811_HPP + + diff --git a/include/boost/python/detail/defaults_gen.hpp b/include/boost/python/detail/defaults_gen.hpp new file mode 100644 index 00000000..eee45d59 --- /dev/null +++ b/include/boost/python/detail/defaults_gen.hpp @@ -0,0 +1,253 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// 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 DEFAULTS_GEN_JDG20020807_HPP +#define DEFAULTS_GEN_JDG20020807_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace python { namespace detail { + +template +struct func_stubs_base { + + typedef DerivedT derived_t; + + DerivedT& derived() + { return *static_cast(this); } + + DerivedT const& derived() const + { return *static_cast(this); } +}; + +}}} // namespace boost::python::detail + +/////////////////////////////////////////////////////////////////////////////// +// Temporary BOOST_PP fix before the CVS stabalizes /*$$$ FIX ME $$$*/ + +#define BOOST_PP_FIX_REPEAT_2ND(c, m, d) /* ... */ \ + BOOST_PP_CAT(BOOST_PP_R2_, c)(m, d) \ + /**/ + +/////////////////////////////////////////////////////////////////////////////// +#define BPL_IMPL_TEMPLATE_GEN(INDEX, DATA) typename BOOST_PP_CAT(T, INDEX) + +#define BPL_IMPL_TYPEDEF_GEN(INDEX, DATA) \ + typedef typename boost::mpl::at \ + < \ + BOOST_PP_ADD(INDEX, DATA), \ + ArgsT \ + >::type BOOST_PP_CAT(T, INDEX); \ + +#define BPL_IMPL_ARGS_GEN(INDEX, DATA) \ + BOOST_PP_CAT(T, INDEX) BOOST_PP_CAT(arg, INDEX) \ + +#define BPL_IMPL_FUNC_WRAPPER_GEN(INDEX, DATA) \ + static RT BOOST_PP_CAT(func_, INDEX) \ + ( \ + BOOST_PP_ENUM \ + ( \ + BOOST_PP_ADD(BOOST_PP_TUPLE_ELEM(3, 1, DATA), INDEX), \ + BPL_IMPL_ARGS_GEN, \ + BOOST_PP_EMPTY \ + ) \ + ) \ + { \ + BOOST_PP_TUPLE_ELEM(3, 2, DATA) \ + BOOST_PP_TUPLE_ELEM(3, 0, DATA) \ + ( \ + BOOST_PP_ENUM_PARAMS \ + ( \ + BOOST_PP_ADD(BOOST_PP_TUPLE_ELEM(3, 1, DATA), INDEX), \ + arg \ + ) \ + ); \ + } \ + +#define BPL_IMPL_GEN_FUNCTION(FNAME, FSTUBS_NAME, N_ARGS, N_DFLTS, RETURN) \ + struct FSTUBS_NAME { \ + \ + BOOST_STATIC_CONSTANT(int, n_funcs = BOOST_PP_INC(N_DFLTS)); \ + BOOST_STATIC_CONSTANT(int, max_args = n_funcs); \ + \ + static char const* \ + name() { return BOOST_PP_STRINGIZE(FNAME); } \ + \ + template \ + struct gen { \ + \ + typedef typename boost::mpl::at<0, ArgsT>::type RT; \ + \ + BOOST_PP_FIX_REPEAT_2ND \ + ( \ + BOOST_PP_INC(N_DFLTS), \ + BPL_IMPL_TYPEDEF_GEN, \ + 1 \ + ) \ + \ + BOOST_PP_FIX_REPEAT_2ND \ + ( \ + BOOST_PP_INC(N_DFLTS), \ + BPL_IMPL_FUNC_WRAPPER_GEN, \ + (FNAME, BOOST_PP_SUB(N_ARGS, N_DFLTS), RETURN) \ + ) \ + }; \ + }; \ + +/////////////////////////////////////////////////////////////////////////////// +#define BPL_IMPL_MEM_FUNC_WRAPPER_GEN(INDEX, DATA) \ + static RT BOOST_PP_CAT(func_, INDEX) \ + ( \ + ClassT obj, \ + BOOST_PP_ENUM \ + ( \ + BOOST_PP_ADD(BOOST_PP_TUPLE_ELEM(3, 1, DATA), INDEX), \ + BPL_IMPL_ARGS_GEN, \ + BOOST_PP_EMPTY \ + ) \ + ) \ + { \ + BOOST_PP_TUPLE_ELEM(3, 2, DATA) obj. \ + BOOST_PP_TUPLE_ELEM(3, 0, DATA) \ + ( \ + BOOST_PP_ENUM_PARAMS \ + ( \ + BOOST_PP_ADD(BOOST_PP_TUPLE_ELEM(3, 1, DATA), INDEX), \ + arg \ + ) \ + ); \ + } \ + +#define BPL_IMPL_GEN_MEM_FUNCTION(FNAME, FSTUBS_NAME, N_ARGS, N_DFLTS, RETURN) \ + struct FSTUBS_NAME { \ + \ + BOOST_STATIC_CONSTANT(int, n_funcs = BOOST_PP_INC(N_DFLTS)); \ + BOOST_STATIC_CONSTANT(int, max_args = n_funcs + 1); \ + \ + static char const* \ + name() { return BOOST_PP_STRINGIZE(FNAME); } \ + \ + template \ + struct gen { \ + \ + typedef typename boost::mpl::at<0, ArgsT>::type RT; \ + typedef typename boost::mpl::at<1, ArgsT>::type ClassT; \ + \ + BOOST_PP_FIX_REPEAT_2ND \ + ( \ + BOOST_PP_INC(N_DFLTS), \ + BPL_IMPL_TYPEDEF_GEN, \ + 2 \ + ) \ + \ + BOOST_PP_FIX_REPEAT_2ND \ + ( \ + BOOST_PP_INC(N_DFLTS), \ + BPL_IMPL_MEM_FUNC_WRAPPER_GEN, \ + (FNAME, BOOST_PP_SUB(N_ARGS, N_DFLTS), RETURN) \ + ) \ + }; \ + }; \ + \ + +/////////////////////////////////////////////////////////////////////////////// +#if defined(BOOST_MSVC) + +#define BPL_IMPL_GEN_FUNCTION_STUB(FNAME, FSTUBS_NAME, N_ARGS, N_DFLTS) \ + BPL_IMPL_GEN_FUNCTION \ + (FNAME, BOOST_PP_CAT(FSTUBS_NAME, _NV), N_ARGS, N_DFLTS, return) \ + BPL_IMPL_GEN_FUNCTION \ + (FNAME, BOOST_PP_CAT(FSTUBS_NAME, _V), N_ARGS, N_DFLTS, ;) \ + struct FSTUBS_NAME \ + : public boost::python::detail::func_stubs_base { \ + \ + typedef BOOST_PP_CAT(FSTUBS_NAME, _NV) nv_type; \ + typedef BOOST_PP_CAT(FSTUBS_NAME, _V) v_type; \ + }; \ + +/////////////////////////////////////////////////////////////////////////////// +#define BPL_IMPL_GEN_MEM_FUNCTION_STUB(FNAME, FSTUBS_NAME, N_ARGS, N_DFLTS) \ + BPL_IMPL_GEN_MEM_FUNCTION \ + (FNAME, BOOST_PP_CAT(FSTUBS_NAME, _NV), N_ARGS, N_DFLTS, return) \ + BPL_IMPL_GEN_MEM_FUNCTION \ + (FNAME, BOOST_PP_CAT(FSTUBS_NAME, _V), N_ARGS, N_DFLTS, ;) \ + struct FSTUBS_NAME \ + : public boost::python::detail::func_stubs_base { \ + \ + typedef BOOST_PP_CAT(FSTUBS_NAME, _NV) nv_type; \ + typedef BOOST_PP_CAT(FSTUBS_NAME, _V) v_type; \ + }; \ + +#else + +/////////////////////////////////////////////////////////////////////////////// +#define BPL_IMPL_GEN_FUNCTION_STUB(FNAME, FSTUBS_NAME, N_ARGS, N_DFLTS) \ + BPL_IMPL_GEN_FUNCTION \ + (FNAME, BOOST_PP_CAT(FSTUBS_NAME, _NV), N_ARGS, N_DFLTS, return) \ + struct FSTUBS_NAME \ + : public boost::python::detail::func_stubs_base { \ + \ + typedef BOOST_PP_CAT(FSTUBS_NAME, _NV) nv_type; \ + typedef BOOST_PP_CAT(FSTUBS_NAME, _NV) v_type; \ + }; \ + +/////////////////////////////////////////////////////////////////////////////// +#define BPL_IMPL_GEN_MEM_FUNCTION_STUB(FNAME, FSTUBS_NAME, N_ARGS, N_DFLTS) \ + BPL_IMPL_GEN_MEM_FUNCTION \ + (FNAME, BOOST_PP_CAT(FSTUBS_NAME, _NV), N_ARGS, N_DFLTS, return) \ + struct FSTUBS_NAME \ + : public boost::python::detail::func_stubs_base { \ + \ + typedef BOOST_PP_CAT(FSTUBS_NAME, _NV) nv_type; \ + typedef BOOST_PP_CAT(FSTUBS_NAME, _NV) v_type; \ + }; \ + +#endif // defined(BOOST_MSVC) + +/////////////////////////////////////////////////////////////////////////////// +// +// MAIN MACROS +// +/////////////////////////////////////////////////////////////////////////////// +#define BOOST_PYTHON_FUNCTION_GEN(GENERATOR_NAME, FNAME, MIN_ARGS, MAX_ARGS) \ + BPL_IMPL_GEN_FUNCTION_STUB \ + ( \ + FNAME, \ + GENERATOR_NAME, \ + MAX_ARGS, \ + BOOST_PP_SUB(MAX_ARGS, MIN_ARGS) \ + ) \ + +#define BOOST_PYTHON_MEMBER_FUNCTION_GEN(GENERATOR_NAME, FNAME, MIN_ARGS, MAX_ARGS)\ + BPL_IMPL_GEN_MEM_FUNCTION_STUB \ + ( \ + FNAME, \ + GENERATOR_NAME, \ + MAX_ARGS, \ + BOOST_PP_SUB(MAX_ARGS, MIN_ARGS) \ + ) \ + +/////////////////////////////////////////////////////////////////////////////// +#endif // DEFAULTS_GEN_JDG20020807_HPP + + diff --git a/include/boost/python/module.hpp b/include/boost/python/module.hpp index af6434ce..90bc6e5d 100644 --- a/include/boost/python/module.hpp +++ b/include/boost/python/module.hpp @@ -14,6 +14,7 @@ # include # include # include +# include namespace boost { namespace python { @@ -32,33 +33,41 @@ class module : public detail::module_base this->module_base::setattr_doc(name, python::object(x), 0); return *this; } - + module& add(type_handle x); // just use the type's name - + template module& add(class_ const& c) { this->add_class(type_handle(borrowed((PyTypeObject*)c.ptr()))); return *this; } - + template module& def(char const* name, Fn fn) { this->setattr_doc( name, boost::python::make_function(fn), 0); - + return *this; } template module& def(char const* name, Fn fn, CallPolicyOrDoc const& policy_or_doc, char const* doc = 0) { typedef detail::def_helper helper; - + this->setattr_doc( name, boost::python::make_function(fn, helper::get_policy(policy_or_doc)), helper::get_doc(policy_or_doc, doc)); - + + return *this; + } + + template + module& def(detail::func_stubs_base const& stubs, ArgsT args) + { + // JDG 8-12-2002 + detail::define_with_defaults(stubs.derived(), *this, args); return *this; } }; diff --git a/test/defaults.cpp b/test/defaults.cpp new file mode 100644 index 00000000..e64a4349 --- /dev/null +++ b/test/defaults.cpp @@ -0,0 +1,64 @@ +// 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 + +#if defined(_AIX) && defined(__EDG_VERSION__) && __EDG_VERSION__ < 245 +# include // works around a KCC intermediate code generation bug +#endif + +using namespace boost::python; +using namespace std; + +/////////////////////////////////////////////////////////////////////////////// + +std::string +foo(int a, char b = 'D', std::string c = "default", double d = 0.0) +{ + std::stringstream stream; + stream << "int(" << a << "); "; + stream << "char(" << b << "); "; + stream << "string(" << c << "); "; + stream << "double(" << d << "); "; + return stream.str(); +} + +BOOST_PYTHON_FUNCTION_GEN(foo_stubs, foo, 1, 4) + +/////////////////////////////////////////////////////////////////////////////// + +struct X { + + std::string + bar(int a, char b = 'D', std::string c = "default", double d = 0.0) const + { + std::stringstream stream; + stream << "int(" << a << "); "; + stream << "char(" << b << "); "; + stream << "string(" << c << "); "; + stream << "double(" << d << "); "; + return stream.str(); + } +}; + +BOOST_PYTHON_MEMBER_FUNCTION_GEN(X_bar_stubs, bar, 1, 4) + +/////////////////////////////////////////////////////////////////////////////// + +BOOST_PYTHON_MODULE_INIT(defaults_ext) +{ + module m("defaults_ext"); + m.def(foo_stubs(), args()); + + class_ xc("X"); + m.add(xc); + + xc.def_init(); + xc.def(X_bar_stubs(), args()); +} + +#include "module_tail.cpp" diff --git a/test/defaults.py b/test/defaults.py new file mode 100644 index 00000000..1261453a --- /dev/null +++ b/test/defaults.py @@ -0,0 +1,82 @@ +""" + +>>> from defaults_ext import * +>>> foo(1) +'int(1); char(D); string(default); double(0); ' +>>> foo(2, 'X') +'int(2); char(X); string(default); double(0); ' +>>> foo(3, 'Y', "Hello World") +'int(3); char(Y); string(Hello World); double(0); ' +>>> foo(4, 'Z', "Hi There", 3.3) +'int(4); char(Z); string(Hi There); double(3.3); ' +>>> x = X() +>>> x.bar(1) +'int(1); char(D); string(default); double(0); ' +>>> x.bar(2, 'X') +'int(2); char(X); string(default); double(0); ' +>>> x.bar(3, 'Y', "Hello World") +'int(3); char(Y); string(Hello World); double(0); ' +>>> x.bar(4, 'Z', "Hi There", 3.3) +'int(4); char(Z); string(Hi There); double(3.3); ' +>>> + + + +""" +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]) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +