2
0
mirror of https://github.com/boostorg/python.git synced 2026-01-24 06:02:14 +00:00

Default Arguments Handling

[SVN r14786]
This commit is contained in:
Joel de Guzman
2002-08-12 14:22:36 +00:00
parent bbc90bcc9c
commit cdf49c6ac0
6 changed files with 541 additions and 23 deletions

View File

@@ -28,16 +28,17 @@
# include <boost/python/make_function.hpp>
# include <boost/python/object/add_to_namespace.hpp>
# include <boost/python/detail/def_helper.hpp>
# include <boost/python/detail/defaults_def.hpp>
namespace boost { namespace python {
namespace boost { namespace python {
namespace detail
{
struct write_type_id;
template <class T, class Prev = detail::not_specified>
struct select_held_type;
template <class T1, class T2, class T3>
struct has_noncopyable;
@@ -58,7 +59,11 @@ namespace detail
template <class T, class Holder>
static inline void register_copy_constructor(mpl::bool_t<false> const&, Holder*, object const&, T* = 0)
{
}
}
// Forward declaration (detail/defaults_def.hpp)
template <typename DerivedT>
struct func_stubs_base;
}
//
@@ -79,18 +84,18 @@ class class_ : public objects::class_base
typedef class_<T,X1,X2,X3> self;
BOOST_STATIC_CONSTANT(bool, is_copyable = (!detail::has_noncopyable<X1,X2,X3>::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<CallPolicyOrDoc> 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_<id,L,R> op_t;
return this->def(op.name(), &op_t::template apply<T>::execute);
}
template <typename DerivedT, typename ArgsT>
self& def(detail::func_stubs_base<DerivedT> 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 <class Args>
@@ -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<CallPolicyOrDoc> helper;
return this->def(
"__init__",
python::make_constructor<Args>(
@@ -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<T,Fn>::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<X1
, typename detail::select_bases<X2
, typename boost::python::detail::select_bases<X3>::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<T>();
// Write the rest of the elements into succeeding positions.
class_id* p = ids + 1;
mpl::for_each<bases, void, detail::write_type_id>::execute(&p);
}
BOOST_STATIC_CONSTANT(
std::size_t, size = mpl::size<bases>::value + 1);
class_id ids[size];
@@ -265,7 +278,7 @@ inline class_<T,X1,X2,X3>::class_()
{
// register converters
objects::register_class_from_python<T,bases>();
detail::register_copy_constructor<T>(
mpl::bool_t<is_copyable>()
, objects::select_holder<T,held_type>((held_type*)0).get()
@@ -278,7 +291,7 @@ inline class_<T,X1,X2,X3>::class_(char const* name, char const* doc)
{
// register converters
objects::register_class_from_python<T,bases>();
detail::register_copy_constructor<T>(
mpl::bool_t<is_copyable>()
, objects::select_holder<T,held_type>((held_type*)0).get()

View File

@@ -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 <boost/python/detail/defaults_gen.hpp>
#include <boost/type_traits.hpp>
#include <boost/mpl/int_t.hpp>
#include <boost/mpl/size.hpp>
#include <boost/static_assert.hpp>
#include <boost/python/class.hpp>
#include <boost/python/module.hpp>
///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace python {
namespace detail {
///////////////////////////////////////////////////////////////////////////////
#define BPL_IMPL_STUB_FUNC_DEF(INDEX, DATA) \
\
template <typename StubsT, typename HolderT> \
inline void \
define_stub_function \
( \
char const* name, \
StubsT, \
HolderT& holder, \
boost::mpl::int_t<INDEX> \
) \
{ \
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 <int N>
struct define_with_defaults_helper {
template <typename StubsT, typename HolderT>
static void
def(char const* name, StubsT stubs, HolderT& holder)
{
define_stub_function(name, stubs, holder, boost::mpl::int_t<N>());
define_with_defaults_helper<N-1>::def(name, stubs, holder);
}
};
///////////////////////////////////////
template <>
struct define_with_defaults_helper<0> {
template <typename StubsT, typename HolderT>
static void
def(char const* name, StubsT stubs, HolderT& holder)
{
define_stub_function(name, stubs, holder, boost::mpl::int_t<0>());
}
};
///////////////////////////////////////////////////////////////////////////////
template <typename StubsT, typename HolderT, typename ArgsT>
inline void
define_with_defaults(StubsT, HolderT& holder, ArgsT args)
{
typedef typename mpl::select_type
<
boost::is_same<void, typename mpl::at<0, ArgsT>::type>::value,
typename StubsT::v_type,
typename StubsT::nv_type
>
::type stubs_type;
BOOST_STATIC_ASSERT(
(stubs_type::max_args + 1) == boost::mpl::size<ArgsT>::value);
typedef stubs_type::template gen<ArgsT> gen_type;
define_with_defaults_helper<stubs_type::n_funcs-1>::def
(stubs_type::name(), gen_type(), holder);
}
} // namespace detail
}} // namespace boost::python
///////////////////////////////////////////////////////////////////////////////
#endif // DEFAULTS_DEF_JDG20020811_HPP

View File

@@ -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 <boost/preprocessor/repeat_2nd.hpp>
#include <boost/preprocessor/repeat.hpp>
#include <boost/preprocessor/enum.hpp>
#include <boost/preprocessor/enum_params.hpp>
#include <boost/preprocessor/tuple.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/arithmetic/add.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/inc.hpp>
#include <boost/preprocessor/empty.hpp>
#include <boost/config.hpp>
#include <boost/python/class.hpp>
#include <boost/python/module.hpp>
///////////////////////////////////////////////////////////////////////////////
namespace boost { namespace python { namespace detail {
template <typename DerivedT>
struct func_stubs_base {
typedef DerivedT derived_t;
DerivedT& derived()
{ return *static_cast<DerivedT*>(this); }
DerivedT const& derived() const
{ return *static_cast<DerivedT const*>(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 <typename ArgsT> \
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 <typename ArgsT> \
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<FSTUBS_NAME> { \
\
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<FSTUBS_NAME> { \
\
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<FSTUBS_NAME> { \
\
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<FSTUBS_NAME> { \
\
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

View File

@@ -14,6 +14,7 @@
# include <boost/python/module_init.hpp>
# include <boost/python/object_core.hpp>
# include <boost/python/detail/def_helper.hpp>
# include <boost/python/detail/defaults_def.hpp>
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 <class T1, class T2 , class T3, class T4>
module& add(class_<T1,T2,T3,T4> const& c)
{
this->add_class(type_handle(borrowed((PyTypeObject*)c.ptr())));
return *this;
}
template <class Fn>
module& def(char const* name, Fn fn)
{
this->setattr_doc(
name, boost::python::make_function(fn), 0);
return *this;
}
template <class Fn, class CallPolicyOrDoc>
module& def(char const* name, Fn fn, CallPolicyOrDoc const& policy_or_doc, char const* doc = 0)
{
typedef detail::def_helper<CallPolicyOrDoc> 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 <typename DerivedT, typename ArgsT>
module& def(detail::func_stubs_base<DerivedT> const& stubs, ArgsT args)
{
// JDG 8-12-2002
detail::define_with_defaults(stubs.derived(), *this, args);
return *this;
}
};

64
test/defaults.cpp Normal file
View File

@@ -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 <boost/python/module.hpp>
#include <boost/python/class.hpp>
#include <sstream>
#if defined(_AIX) && defined(__EDG_VERSION__) && __EDG_VERSION__ < 245
# include <iostream> // 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<std::string, int, char, std::string, double>());
class_<X> xc("X");
m.add(xc);
xc.def_init();
xc.def(X_bar_stubs(), args<std::string, X const&, int, char, std::string, double>());
}
#include "module_tail.cpp"

82
test/defaults.py Normal file
View File

@@ -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])