Skip to content

Commit d4e06ac

Browse files
committed
Preparation for delivering nicely-formatted error messages in
Boost.Python. The major change is that, instead of being boost::function2<PyObject*,PyObject*,PyObject*>, py_function is now a runtime-polymorphic wrapper for compile-time polymorphic behavior (just like function) of our own which carries more information/behaviors. In particular, you can retrieve an array of c-strings describing the types in the function signature. Additionally, the minimum and maximum arity are stored in the py_function object instead of in the 'function' object which wraps it. * data_members.hpp - Adjustments for the new py_function. Workarounds for CodeWarrior Pro 8.3 bugs in function template argument deduction with pointers-to-members. * has_back_reference.hpp, test/back_reference.cpp, test/select_holder.cpp - Updated to follow the metafunction protocol * init.hpp, detail/defaults_gen.hpp - Make Keywords a more-specific type in function signatures to prevent string literals that show up as char[N] from binding to the wrong argument (at least Intel 7.1 for Windows does this). * make_function.hpp - Adjustments for the new py_function. Arities are now computed by caller<>. * opaque_pointer_converter.hpp, type_id.hpp - Use BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS facilities; generate specializations that all compilers can handle. * raw_function.hpp - Adjustments for the new py_function. * caller.hpp - Added arity and signature type name reporting. * detail/config.hpp Enable __declspec(dllexport) for Cygwin, thereby fixing the recent horrible Cygwin linking problems. * detail/msvc_typeinfo.hpp - Always pass boost::type<T>* explicitly, thereby working around incompatible notions of how to specialize function templates with default arguments on various compilers. * object/function.hpp , object/function_handle.hpp , object/function_object.hpp , object/function_object.cpp Adjustments for the new py_function. Arities are carried by py_function. * object/iterator.hpp, object/iterator.cpp Adjustments for the new py_function; we have to compute a signature of types to construct it with. * object/py_function.hpp Removed dependency on boost::function; see the comment at the top of this entry for more details. * object/select_holder.hpp Clean up to more closely follow MPL idioms. * test/Jamfile - Adjust the embedding test for the new Cygwin use of declspec. Update bases and pointee tests with missing properties. * test/input_iterator.cpp - Updates for the new iterator adaptors. * test/opaque.py - Add Python encoding comment to suppress PendinDeprecationWarning with recent Python builds. * test/str.cpp Pass a Python long instead of a float to string.expandtabs, suppressing a PendinDeprecationWarning with recent Python builds. * libs/utility/counting_iterator_example.cpp Borland workaround * libs/utility/indirect_iterator_example.cpp const-correctness fix. * [SVN r19247]
1 parent 817dcd3 commit d4e06ac

25 files changed

+516
-197
lines changed

include/boost/python/data_members.hpp

Lines changed: 146 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,40 @@
2020
# include <boost/python/detail/indirect_traits.hpp>
2121
# include <boost/python/detail/not_specified.hpp>
2222

23-
# include <boost/type_traits/transform_traits.hpp>
2423
# include <boost/type_traits/add_const.hpp>
2524
# include <boost/type_traits/add_reference.hpp>
26-
# include <boost/type_traits/is_same.hpp>
25+
# include <boost/type_traits/is_member_pointer.hpp>
2726

2827
# include <boost/mpl/apply_if.hpp>
2928
# include <boost/mpl/if.hpp>
29+
# include <boost/mpl/vector/vector10.hpp>
3030

3131
# include <boost/bind.hpp>
3232

33+
# include <boost/detail/workaround.hpp>
34+
3335
namespace boost { namespace python {
3436

37+
//
38+
// This file defines the make_getter and make_setter function
39+
// families, which are responsible for turning pointers, references,
40+
// and pointers-to-data-members into callable Python objects which
41+
// can be used for attribute access on wrapped classes.
42+
//
43+
3544
namespace detail
3645
{
46+
//
47+
// Raw Getter and Setter function generators. These class templates
48+
// generate static functions which can be bound together with
49+
// policies and wrapped to generate the python callable objects
50+
// mentioned above.
51+
//
52+
53+
//
54+
// Generates get and set functions for access through
55+
// pointers-to-data-members
56+
//
3757
template <class Data, class Class, class Policies>
3858
struct member
3959
{
@@ -74,6 +94,12 @@ namespace detail
7494
}
7595
};
7696

97+
//
98+
// Generates get and set functions for access through ordinary
99+
// pointers. These are generally used to wrap static data members,
100+
// but can also be used to expose namespace-scope data as class
101+
// attributes.
102+
//
77103
template <class Data, class Policies>
78104
struct datum
79105
{
@@ -108,6 +134,17 @@ namespace detail
108134
}
109135
};
110136

137+
//
138+
// Helper metafunction for determining the default CallPolicy to use
139+
// for attribute access. If T is a [reference to a] class type X
140+
// whose conversion to python would normally produce a new copy of X
141+
// in a wrapped X class instance (as opposed to types such as
142+
// std::string, which are converted to native Python types, and
143+
// smart pointer types which produce a wrapped class instance of the
144+
// pointee type), to-python conversions will attempt to produce an
145+
// object which refers to the original C++ object, rather than a
146+
// copy. See default_member_getter_policy for rationale.
147+
//
111148
template <class T>
112149
struct default_getter_by_ref
113150
: mpl::and_<
@@ -123,145 +160,206 @@ namespace detail
123160
{
124161
};
125162

163+
// Metafunction computing the default CallPolicy to use for reading
164+
// data members
165+
//
126166
// If it's a regular class type (not an object manager or other
127167
// type for which we have to_python specializations, use
128168
// return_internal_reference so that we can do things like
129169
// x.y.z = 1
130170
// and get the right result.
131171
template <class T>
132172
struct default_member_getter_policy
133-
: mpl::if_<
134-
default_getter_by_ref<T>
135-
, return_internal_reference<>
136-
, return_value_policy<return_by_value>
137-
>
173+
: mpl::if_<
174+
default_getter_by_ref<T>
175+
, return_internal_reference<>
176+
, return_value_policy<return_by_value>
177+
>
138178
{};
139179

180+
// Metafunction computing the default CallPolicy to use for reading
181+
// non-member data.
140182
template <class T>
141183
struct default_datum_getter_policy
142-
: mpl::if_<
143-
default_getter_by_ref<T>
144-
, return_value_policy<reference_existing_object>
145-
, return_value_policy<return_by_value>
146-
>
184+
: mpl::if_<
185+
default_getter_by_ref<T>
186+
, return_value_policy<reference_existing_object>
187+
, return_value_policy<return_by_value>
188+
>
147189
{};
148190

191+
//
192+
// make_getter helper function family -- These helpers to
193+
// boost::python::make_getter are used to dispatch behavior. The
194+
// third argument is a workaround for a CWPro8 partial ordering bug
195+
// with pointers to data members. It should be convertible to
196+
// mpl::true_ iff the first argument is a pointer-to-member, and
197+
// mpl::false_ otherwise. The fourth argument is for compilers
198+
// which don't support partial ordering at all and should always be
199+
// passed 0L.
200+
//
201+
202+
// Handle non-member pointers with policies
149203
template <class D, class Policies>
150-
inline object make_getter(D* p, Policies const& policies, int)
204+
inline object make_getter(D* d, Policies const& policies, mpl::false_, int)
151205
{
152206
return objects::function_object(
207+
objects::py_function(
153208
::boost::bind(
154-
&detail::datum<D,Policies>::get, p, _1, _2
209+
&detail::datum<D,Policies>::get, d, _1, _2
155210
, policies)
156-
, 0);
211+
, mpl::vector1<D>()
212+
)
213+
);
157214
}
158-
215+
216+
// Handle non-member pointers without policies
159217
template <class D>
160-
inline object make_getter(D* p, not_specified, long)
218+
inline object make_getter(D* d, not_specified, mpl::false_, long)
161219
{
162220
typedef typename default_datum_getter_policy<D>::type policies;
163-
return make_getter(p, policies(), 0L);
221+
return detail::make_getter(d, policies(), mpl::false_(), 0);
164222
}
165223

224+
// Handle pointers-to-members with policies
166225
template <class C, class D, class Policies>
167-
inline object make_getter(D C::*pm, Policies const& policies, int)
226+
inline object make_getter(D C::*pm, Policies const& policies, mpl::true_, int)
168227
{
169228
return objects::function_object(
229+
objects::py_function(
170230
::boost::bind(
171231
&detail::member<D,C,Policies>::get, pm, _1, _2
172232
, policies)
173-
, 1);
233+
, mpl::vector2<D, C const*>()
234+
)
235+
);
174236
}
175237

238+
// Handle pointers-to-members without policies
176239
template <class C, class D>
177-
inline object make_getter(D C::*pm, not_specified, long)
240+
inline object make_getter(D C::*pm, not_specified, mpl::true_, long)
178241
{
179242
typedef typename default_member_getter_policy<D>::type policies;
180-
return make_getter(pm, policies(), 0L);
243+
return detail::make_getter(pm, policies(), mpl::true_(), 0);
181244
}
182-
183-
template <class D, class Policies>
184-
inline object make_getter(D& d, Policies const& policies, ...)
245+
246+
// Handle references
247+
template <class D, class P>
248+
inline object make_getter(D& d, P& p, mpl::false_, ...)
185249
{
186-
return detail::make_getter(&d, policies, 0L);
250+
// Just dispatch to the handler for pointer types.
251+
return detail::make_getter(&d, p, mpl::false_(), 0L);
187252
}
188253

254+
//
255+
// make_setter helper function family -- These helpers to
256+
// boost::python::make_setter are used to dispatch behavior. The
257+
// third argument is for compilers which don't support partial
258+
// ordering at all and should always be passed 0.
259+
//
260+
261+
262+
// Handle non-member pointers
189263
template <class D, class Policies>
190-
inline object make_setter(D* p, Policies const& policies, long)
264+
inline object make_setter(D* p, Policies const& policies, int)
191265
{
192266
return objects::function_object(
193-
::boost::bind(
194-
&detail::datum<D,Policies>::set, p, _1, _2
195-
, policies)
196-
, 1);
267+
objects::py_function(
268+
::boost::bind(
269+
&detail::datum<D,Policies>::set, p, _1, _2
270+
, policies)
271+
, mpl::vector2<void, D const&>()
272+
)
273+
);
197274
}
198275

276+
// Handle pointers-to-members
199277
template <class C, class D, class Policies>
200-
inline object make_setter(D C::*pm, Policies const& policies, long)
278+
inline object make_setter(D C::*pm, Policies const& policies, int)
201279
{
202280
return objects::function_object(
203-
::boost::bind(
204-
&detail::member<D,C,Policies>::set, pm, _1, _2
205-
, policies)
206-
, 2);
281+
objects::py_function(
282+
::boost::bind(
283+
&detail::member<D,C,Policies>::set, pm, _1, _2
284+
, policies)
285+
, mpl::vector3<void, C*, D const&>()
286+
)
287+
);
207288
}
208289

290+
// Handle references
209291
template <class D, class Policies>
210292
inline object make_setter(D& x, Policies const& policies, ...)
211293
{
212294
return detail::make_setter(&x, policies, 0L);
213295
}
214296
}
215297

298+
//
299+
// make_getter function family -- build a callable object which
300+
// retrieves data through the first argument and is appropriate for
301+
// use as the `get' function in Python properties . The second,
302+
// policies argument, is optional. We need both D& and D const&
303+
// overloads in order be able to handle rvalues.
304+
//
216305
template <class D, class Policies>
217306
inline object make_getter(D& d, Policies const& policies)
218307
{
219-
return detail::make_getter(d, policies, 0L);
308+
return detail::make_getter(d, policies, is_member_pointer<D>(), 0L);
220309
}
221310

222311
template <class D, class Policies>
223312
inline object make_getter(D const& d, Policies const& policies)
224313
{
225-
return detail::make_getter(d, policies, 0L);
314+
return detail::make_getter(d, policies, is_member_pointer<D>(), 0L);
226315
}
227316

228317
template <class D>
229318
inline object make_getter(D& x)
230319
{
231-
return detail::make_getter(x, detail::not_specified(), 0L);
320+
detail::not_specified policy;
321+
return detail::make_getter(x, policy, is_member_pointer<D>(), 0L);
232322
}
233323

234-
# if !(BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || BOOST_WORKAROUND(__EDG_VERSION__, <= 238))
324+
# if !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) && !BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
235325
template <class D>
236-
inline object make_getter(D const& x)
326+
inline object make_getter(D const& d)
237327
{
238-
return detail::make_getter(x, detail::not_specified(), 0L);
328+
detail::not_specified policy;
329+
return detail::make_getter(d, policy, is_member_pointer<D>(), 0L);
239330
}
240-
# endif
241-
331+
# endif
332+
333+
//
334+
// make_setter function family -- build a callable object which
335+
// writes data through the first argument and is appropriate for
336+
// use as the `set' function in Python properties . The second,
337+
// policies argument, is optional. We need both D& and D const&
338+
// overloads in order be able to handle rvalues.
339+
//
242340
template <class D, class Policies>
243341
inline object make_setter(D& x, Policies const& policies)
244342
{
245-
return detail::make_setter(x, policies, 0L);
343+
return detail::make_setter(x, policies, 0);
246344
}
247345

248346
template <class D, class Policies>
249347
inline object make_setter(D const& x, Policies const& policies)
250348
{
251-
return detail::make_setter(x, policies, 0L);
349+
return detail::make_setter(x, policies, 0);
252350
}
253351

254352
template <class D>
255353
inline object make_setter(D& x)
256354
{
257-
return detail::make_setter(x, default_call_policies(), 0L);
355+
return detail::make_setter(x, default_call_policies(), 0);
258356
}
259357

260358
# if !(BOOST_WORKAROUND(BOOST_MSVC, <= 1300) || BOOST_WORKAROUND(__EDG_VERSION__, <= 238))
261359
template <class D>
262360
inline object make_setter(D const& x)
263361
{
264-
return detail::make_setter(x, default_call_policies(), 0L);
362+
return detail::make_setter(x, default_call_policies(), 0);
265363
}
266364
# endif
267365

include/boost/python/detail/caller.hpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# include <boost/mpl/apply.hpp>
1515
# include <boost/mpl/if.hpp>
1616
# include <boost/mpl/size.hpp>
17+
# include <boost/mpl/at.hpp>
1718
# include <boost/type_traits/is_same.hpp>
1819

1920
# include <boost/python/detail/preprocessor.hpp>
@@ -25,7 +26,9 @@
2526
# include <boost/preprocessor/dec.hpp>
2627
# include <boost/preprocessor/if.hpp>
2728

29+
# include <boost/python/type_id.hpp>
2830
# include <boost/python/detail/invoke.hpp>
31+
# include <boost/python/detail/signature.hpp>
2932

3033
namespace boost { namespace python { namespace detail {
3134

@@ -58,15 +61,18 @@ struct select_result_converter
5861

5962
template <unsigned> struct caller_arity;
6063

64+
template <class F, class ConverterGenerators, class CallPolicies, class Sig>
65+
struct caller;
66+
6167
# define BOOST_PYTHON_NEXT(init,name,n) \
6268
typedef BOOST_PP_IF(n,typename BOOST_PP_CAT(name,BOOST_PP_DEC(n)) ::next, init) name##n;
6369

64-
# define BOOST_PYTHON_ARG_CONVERTER(n) \
65-
BOOST_PYTHON_NEXT(typename first::next, arg_iter,n) \
66-
BOOST_PYTHON_NEXT(ConverterGenerators, conv_iter,n) \
67-
typedef typename apply_iter1<conv_iter##n,arg_iter##n>::type c_t##n; \
68-
c_t##n c##n(PyTuple_GET_ITEM(args_, n)); \
69-
if (!c##n.convertible()) \
70+
# define BOOST_PYTHON_ARG_CONVERTER(n) \
71+
BOOST_PYTHON_NEXT(typename first::next, arg_iter,n) \
72+
BOOST_PYTHON_NEXT(ConverterGenerators, conv_iter,n) \
73+
typedef typename apply_iter1<conv_iter##n,arg_iter##n>::type c_t##n; \
74+
c_t##n c##n(PyTuple_GET_ITEM(args_, n)); \
75+
if (!c##n.convertible()) \
7076
return 0;
7177

7278
# define BOOST_PP_ITERATION_PARAMS_1 \
@@ -119,8 +125,8 @@ struct caller
119125
typedef PyObject* result_type;
120126

121127
caller(F f, CallPolicies p) : base(f,p) {}
122-
};
123128

129+
};
124130

125131
}}} // namespace boost::python::detail
126132

@@ -163,6 +169,14 @@ struct caller_arity<N>
163169

164170
return m_data.second().postcall(args_, result);
165171
}
172+
173+
static unsigned min_arity() { return N; }
174+
175+
static char const*const* type_names()
176+
{
177+
return signature<Sig>::type_names();
178+
}
179+
166180
private:
167181
compressed_pair<F,Policies> m_data;
168182
};

0 commit comments

Comments
 (0)