Skip to content

Commit 997e84f

Browse files
committed
Keyword argument support
[SVN r15533]
1 parent bc91db6 commit 997e84f

21 files changed

+1257
-451
lines changed

include/boost/python/args.hpp

Lines changed: 103 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,117 @@
33
// copyright notice appears in all copies. This software is provided
44
// "as is" without express or implied warranty, and with no claim as
55
// to its suitability for any purpose.
6-
#ifndef ARGS_DWA2002323_HPP
7-
# define ARGS_DWA2002323_HPP
8-
# include <boost/config.hpp>
9-
# include <boost/python/detail/preprocessor.hpp>
10-
# include <boost/python/detail/type_list.hpp>
11-
# include <boost/preprocessor/enum_params.hpp>
6+
#ifndef KEYWORDS_DWA2002323_HPP
7+
# define KEYWORDS_DWA2002323_HPP
128

13-
namespace boost { namespace python {
9+
# include <boost/python/args_fwd.hpp>
10+
# include <boost/python/handle.hpp>
11+
# include <boost/config.hpp>
12+
# include <boost/python/detail/preprocessor.hpp>
13+
# include <boost/python/detail/type_list.hpp>
14+
15+
# include <boost/type_traits/is_reference.hpp>
16+
# include <boost/type_traits/remove_reference.hpp>
17+
# include <boost/type_traits/remove_cv.hpp>
18+
19+
# include <boost/preprocessor/enum_params.hpp>
20+
# include <boost/preprocessor/repeat.hpp>
21+
# include <boost/preprocessor/facilities/intercept.hpp>
22+
# include <boost/preprocessor/iteration/local.hpp>
23+
24+
# include <boost/mpl/aux_/lambda_support.hpp>
25+
# include <boost/mpl/bool_c.hpp>
1426

15-
enum no_init_t { no_init };
27+
# include <boost/type.hpp>
28+
# include <cstddef>
29+
30+
31+
namespace boost { namespace python {
1632

1733
namespace detail
1834
{
19-
template <class Args>
20-
struct args_base {};
21-
}
22-
}}
35+
struct keyword
36+
{
37+
char const* name;
38+
handle<> default_value;
39+
};
40+
41+
template <std::size_t nkeywords>
42+
struct keywords
43+
{
44+
BOOST_STATIC_CONSTANT(std::size_t, size = nkeywords);
45+
46+
keyword_range range() const
47+
{
48+
return keyword_range(elements, elements + nkeywords);
49+
}
50+
51+
keyword elements[nkeywords];
52+
};
2353

24-
namespace boost { namespace python {
54+
# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
55+
template<typename T>
56+
struct is_keywords
57+
{
58+
BOOST_STATIC_CONSTANT(bool, value = false);
59+
};
60+
61+
template<std::size_t nkeywords>
62+
struct is_keywords<keywords<nkeywords> >
63+
{
64+
BOOST_STATIC_CONSTANT(bool, value = true);
65+
};
66+
template <class T>
67+
struct is_reference_to_keywords
68+
{
69+
BOOST_STATIC_CONSTANT(bool, is_ref = is_reference<T>::value);
70+
typedef typename remove_reference<T>::type deref;
71+
typedef typename remove_cv<deref>::type key_t;
72+
BOOST_STATIC_CONSTANT(bool, is_key = is_keywords<key_t>::value);
73+
BOOST_STATIC_CONSTANT(bool, value = (is_ref & is_key));
74+
75+
typedef mpl::bool_c<value> type;
76+
BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_reference_to_keywords,(T))
77+
};
78+
# else
79+
typedef char (&yes_keywords_t)[1];
80+
typedef char (&no_keywords_t)[2];
81+
82+
no_keywords_t is_keywords_test(...);
83+
84+
template<std::size_t nkeywords>
85+
yes_keywords_t is_keywords_test(void (*)(keywords<nkeywords>&));
86+
87+
template<std::size_t nkeywords>
88+
yes_keywords_t is_keywords_test(void (*)(keywords<nkeywords> const&));
2589

26-
// A type list for specifying arguments
27-
template < BOOST_PYTHON_ENUM_WITH_DEFAULT(BOOST_PYTHON_MAX_ARITY, typename A, mpl::void_) >
28-
struct args : detail::args_base<args<BOOST_PP_ENUM_PARAMS_Z(1, BOOST_PYTHON_MAX_ARITY, A)> >
29-
, detail::type_list< BOOST_PP_ENUM_PARAMS_Z(1, BOOST_PYTHON_MAX_ARITY, A) >::type
30-
{};
90+
template<typename T>
91+
class is_reference_to_keywords
92+
{
93+
public:
94+
BOOST_STATIC_CONSTANT(
95+
bool, value = (
96+
sizeof(detail::is_keywords_test( (void (*)(T))0 ))
97+
== sizeof(detail::yes_keywords_t)));
98+
99+
typedef mpl::bool_c<value> type;
100+
BOOST_MPL_AUX_LAMBDA_SUPPORT(1,is_reference_to_keywords,(T))
101+
};
102+
# endif
103+
}
104+
105+
# define BOOST_PYTHON_ASSIGN_NAME(z, n, _) result.elements[n].name = name##n;
106+
# define BOOST_PP_LOCAL_MACRO(n) \
107+
inline detail::keywords<n> args(BOOST_PP_ENUM_PARAMS_Z(1, n, char const* name)) \
108+
{ \
109+
detail::keywords<n> result; \
110+
BOOST_PP_REPEAT_1(n, BOOST_PYTHON_ASSIGN_NAME, _) \
111+
return result; \
112+
}
113+
# define BOOST_PP_LOCAL_LIMITS (1, BOOST_PYTHON_MAX_ARITY)
114+
# include BOOST_PP_LOCAL_ITERATE()
31115

32116
}} // namespace boost::python
33117

34118

35-
# endif // ARGS_DWA2002323_HPP
119+
# endif // KEYWORDS_DWA2002323_HPP

include/boost/python/class.hpp

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
# include <boost/python/detail/defaults_def.hpp>
3535
# include <boost/python/signature.hpp>
3636
# include <boost/python/init.hpp>
37+
# include <boost/python/args_fwd.hpp>
3738

3839
namespace boost { namespace python {
3940

@@ -120,8 +121,9 @@ template <
120121
class class_ : public objects::class_base
121122
{
122123
public: // types
123-
typedef objects::class_base base;
124-
124+
typedef objects::class_base base;
125+
typedef T wrapped_type;
126+
125127
typedef class_<T,X1,X2,X3> self;
126128
BOOST_STATIC_CONSTANT(bool, is_copyable = (!detail::has_noncopyable<X1,X2,X3>::value));
127129

@@ -201,7 +203,7 @@ class class_ : public objects::class_base
201203
template <class F>
202204
self& def(char const* name, F f)
203205
{
204-
this->def_impl(name, f, default_call_policies(), 0, &f);
206+
this->def_impl(name, f, detail::keywords<>(), default_call_policies(), 0, &f);
205207
return *this;
206208
}
207209

@@ -236,6 +238,13 @@ class class_ : public objects::class_base
236238
return *this;
237239
}
238240

241+
template <class Arg1T, class Arg2T, class Arg3T, class Arg4T>
242+
self& def(char const* name, Arg1T arg1, Arg2T const& arg2, Arg3T const& arg3, Arg4T const& arg4)
243+
{
244+
dispatch_def(&arg2, name, arg1, arg2, arg3, arg4);
245+
return *this;
246+
}
247+
239248
template <detail::operator_id id, class L, class R>
240249
self& def(detail::operator_<id,L,R> const& op)
241250
{
@@ -297,22 +306,32 @@ class class_ : public objects::class_base
297306

298307
private: // helper functions
299308

300-
template <class Fn, class Policies>
301-
inline void def_impl(char const* name, Fn fn, Policies const& policies
302-
, char const* doc, ...)
309+
template <class Fn, class Policies, class Keywords>
310+
inline void def_impl(
311+
char const* name
312+
, Fn fn
313+
, Keywords const& keywords
314+
, Policies const& policies
315+
, char const* doc
316+
, ...)
303317
{
304318
objects::add_to_namespace(
305319
*this, name,
306320
make_function(
307-
// This bit of nastiness casts F to a member function of T if possible.
321+
// This bit of nastiness casts F to a member function of T if possible.
308322
detail::member_function_cast<T,Fn>::stage1(fn).stage2((T*)0).stage3(fn)
309-
, policies)
323+
, policies, keywords)
310324
, doc);
311325
}
312326

313327
template <class F>
314-
inline void def_impl(char const* name, F f, default_call_policies const&
315-
, char const* doc, object const*)
328+
inline void def_impl(
329+
char const* name
330+
, F f
331+
, detail::keywords<> const&
332+
, default_call_policies const&
333+
, char const* doc
334+
, object const*)
316335
{
317336
objects::add_to_namespace(*this, name, f, doc);
318337
}
@@ -332,33 +351,60 @@ class class_ : public objects::class_base
332351
name, overloads, *this, detail::get_signature(sig));
333352
}
334353

335-
template <class Fn, class CallPolicyOrDoc>
354+
template <class Fn, class A1>
336355
void dispatch_def(
337356
void const*,
338357
char const* name,
339358
Fn fn,
340-
CallPolicyOrDoc const& policy_or_doc)
359+
A1 const& a1)
341360
{
342-
typedef detail::def_helper<CallPolicyOrDoc> helper;
361+
detail::def_helper<A1> helper(a1);
362+
343363
this->def_impl(
344-
name, fn, helper::get_policy(policy_or_doc),
345-
helper::get_doc(policy_or_doc, 0), &fn);
364+
name, fn
365+
, helper.keywords()
366+
, helper.policies()
367+
, helper.doc()
368+
, &fn);
346369

347370
}
348371

349-
template <class Fn, class CallPolicyOrDoc1, class CallPolicyOrDoc2>
372+
template <class Fn, class A1, class A2>
350373
void dispatch_def(
351374
void const*,
352375
char const* name,
353376
Fn fn,
354-
CallPolicyOrDoc1 const& policy_or_doc1,
355-
CallPolicyOrDoc2 const& policy_or_doc2)
377+
A1 const& a1,
378+
A2 const& a2)
356379
{
357-
typedef detail::def_helper<CallPolicyOrDoc1> helper;
380+
detail::def_helper<A1,A2> helper(a1,a2);
381+
382+
this->def_impl(
383+
name, fn
384+
, helper.keywords()
385+
, helper.policies()
386+
, helper.doc()
387+
, &fn);
388+
}
358389

390+
template <class Fn, class A1, class A2, class A3>
391+
void dispatch_def(
392+
void const*,
393+
char const* name,
394+
Fn fn,
395+
A1 const& a1,
396+
A2 const& a2,
397+
A3 const& a3
398+
)
399+
{
400+
detail::def_helper<A1,A2,A3> helper(a1,a2,a3);
401+
359402
this->def_impl(
360-
name, fn, helper::get_policy(policy_or_doc1, policy_or_doc2),
361-
helper::get_doc(policy_or_doc1, policy_or_doc2), &fn);
403+
name, fn
404+
, helper.keywords()
405+
, helper.policies()
406+
, helper.doc()
407+
, &fn);
362408
}
363409
};
364410

include/boost/python/def.hpp

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,43 +12,49 @@
1212
# include <boost/python/detail/defaults_def.hpp>
1313
# include <boost/python/scope.hpp>
1414
# include <boost/python/signature.hpp>
15+
# include <boost/python/detail/scope.hpp>
1516

1617
namespace boost { namespace python {
1718

1819
namespace detail
1920
{
20-
void BOOST_PYTHON_DECL scope_setattr_doc(char const* name, object const& obj, char const* doc);
21-
22-
template <class Fn, class CallPolicyOrDoc>
21+
template <class Fn, class A1>
2322
void
2423
dispatch_def(
2524
void const*,
2625
char const* name,
2726
Fn fn,
28-
CallPolicyOrDoc const& policy_or_doc)
27+
A1 const& a1)
2928
{
30-
typedef detail::def_helper<CallPolicyOrDoc> helper;
31-
29+
def_helper<A1> helper(a1);
30+
3231
detail::scope_setattr_doc(
33-
name, boost::python::make_function(fn, helper::get_policy(policy_or_doc)),
34-
helper::get_doc(policy_or_doc, 0));
32+
name, boost::python::make_function(
33+
fn
34+
, helper.policies()
35+
, helper.keywords())
36+
, helper.doc()
37+
);
3538
}
3639

37-
template <class Fn, class CallPolicyOrDoc1, class CallPolicyOrDoc2>
40+
template <class Fn, class A1, class A2>
3841
void dispatch_def(
3942
void const*,
4043
char const* name,
4144
Fn fn,
42-
CallPolicyOrDoc1 const& policy_or_doc1,
43-
CallPolicyOrDoc2 const& policy_or_doc2)
45+
A1 const& a1,
46+
A2 const& a2)
4447
{
45-
typedef detail::def_helper<CallPolicyOrDoc1> helper;
48+
def_helper<A1,A2> helper(a1,a2);
4649

4750
detail::scope_setattr_doc(
48-
name, boost::python::make_function(
49-
fn, helper::get_policy(policy_or_doc1, policy_or_doc2)),
50-
helper::get_doc(policy_or_doc1, policy_or_doc2));
51-
}
51+
name, python::make_function(
52+
fn
53+
, helper.policies()
54+
, helper.keywords())
55+
, helper.doc()
56+
);
57+
}
5258

5359
template <class StubsT, class SigT>
5460
void dispatch_def(
@@ -87,22 +93,22 @@ void def(char const* name, Arg1T arg1, Arg2T const& arg2)
8793
template <class Arg1T, class Arg2T, class Arg3T>
8894
void def(char const* name, Arg1T arg1, Arg2T const& arg2, Arg3T const& arg3)
8995
{
90-
// The arguments are definitely:
91-
// def(name, function, policy, doc_string) // TODO: exchange policy, doc_string position
92-
9396
detail::dispatch_def(&arg2, name, arg1, arg2, arg3);
9497
}
9598

96-
//template <class Arg1T, class Arg2T, class Arg3T>
97-
//void def(char const* name, Arg1T arg1, Arg2T const& arg2, Arg3T const& arg3, char const* doc)
98-
//{
99-
// // The arguments are definitely:
100-
// // arg1: signature
101-
// // arg2: stubs
102-
// // arg3: policy
103-
//
104-
// detail::dispatch_def(&arg2, name, arg1, arg2, arg3, doc);
105-
//}
99+
template <class F, class A1, class A2, class A3>
100+
void def(char const* name, F f, A1 const& a1, A2 const& a2, A3 const& a3)
101+
{
102+
detail::def_helper<A1,A2,A3> helper(a1,a2,a3);
103+
104+
detail::scope_setattr_doc(
105+
name, python::make_function(
106+
f
107+
, helper.policies()
108+
, helper.keywords())
109+
, helper.doc()
110+
);
111+
}
106112

107113
}} // namespace boost::python
108114

0 commit comments

Comments
 (0)