Skip to content

Commit 22e82ae

Browse files
committed
void pointer conversion support, from Niall Douglas, then heavily
edited by DWA. Merged from python-voidptr [SVN r32857]
1 parent 2d117bc commit 22e82ae

File tree

9 files changed

+180
-123
lines changed

9 files changed

+180
-123
lines changed

doc/news.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ <h2 align="center">News/Change Log</h2>
3939
<li>New <a href="v2/docstring_options.html"
4040
><code>docstring_options.hpp</code></a> header to
4141
control the content of docstrings.
42+
43+
<li>Support for converting <code>void*</code> to/from python,
44+
with <code><a
45+
href="v2/opaque_pointer_converter.html">opaque_pointer_converter</a></code>
46+
as the return value policy. Thanks to Niall Douglas for the
47+
initial patch.
4248
</ul>
4349
</dd>
4450

doc/v2/faq.html

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,6 @@ <h2 align="center">Frequently Asked Questions (FAQs)</h2>
6767
>error C2064: term does not evaluate to a function taking 2 arguments</a>
6868
</dt>
6969

70-
<dt><a href="#voidptr">How do I handle <tt>void *</tt> conversion?</a></dt>
71-
7270
<dt><a href="#custom_string"
7371
>How can I automatically convert my custom string type to
7472
and from a Python string?</a></dt>
@@ -693,29 +691,6 @@ <h2><a name="msvcthrowbug"></a>error C2064: term does
693691
.def("setAutoDelete", (bool (FXThread::*)(bool)) &amp;FXThread::setAutoDelete)</pre>
694692
<p>(The bug has been reported to Microsoft.)</p>
695693

696-
<hr>
697-
<h2><a name="voidptr"></a>How do I handle <tt>void *</tt> conversion?</h2>
698-
<font size="-1"><i>Niall Douglas provides these notes:</i></font><p>
699-
For several reasons Boost.Python does not support <tt>void *</tt> as
700-
an argument or as a return value. However, it is possible to wrap
701-
functions with <tt>void *</tt> arguments or return values using
702-
thin wrappers and the <i>opaque pointer</i> facility. E.g.:
703-
<pre>// Declare the following in each translation unit
704-
struct void_ {};
705-
BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(void_);
706-
707-
void *foo(int par1, void *par2);
708-
709-
void_ *foo_wrapper(int par1, void_ *par2)
710-
{
711-
return (void_ *) foo(par1, par2);
712-
}
713-
...
714-
BOOST_PYTHON_MODULE(bar)
715-
{
716-
def("foo", &amp;foo_wrapper);
717-
}</pre>
718-
719694
<hr>
720695
<h2><a name="custom_string"></a>How can I automatically
721696
convert my custom string type to and from a Python string?</h2>

include/boost/python/converter/registered.hpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
# include <boost/python/converter/registrations.hpp>
1010
# include <boost/type_traits/transform_traits.hpp>
1111
# include <boost/type_traits/cv_traits.hpp>
12+
# include <boost/type_traits/is_void.hpp>
1213
# include <boost/detail/workaround.hpp>
14+
# include <boost/python/type_id.hpp>
15+
# include <boost/type.hpp>
1316

1417
namespace boost {
1518

@@ -77,15 +80,30 @@ namespace detail
7780
}
7881

7982
template <class T>
80-
registration const&
81-
registry_lookup(T&(*)())
83+
inline registration const&
84+
registry_lookup2(T&(*)())
8285
{
8386
detail::register_shared_ptr1((T*)0);
8487
return registry::lookup(type_id<T&>());
8588
}
8689

8790
template <class T>
88-
registration const& registered_base<T>::converters = detail::registry_lookup((T(*)())0);
91+
inline registration const&
92+
registry_lookup1(type<T>)
93+
{
94+
return registry_lookup2((T(*)())0);
95+
}
96+
97+
inline registration const&
98+
registry_lookup1(type<const volatile void>)
99+
{
100+
detail::register_shared_ptr1((void*)0);
101+
return registry::lookup(type_id<void>());
102+
}
103+
104+
template <class T>
105+
registration const& registered_base<T>::converters = detail::registry_lookup1(type<T>());
106+
89107
}
90108

91109
}}} // namespace boost::python::converter

include/boost/python/opaque_pointer_converter.hpp

Lines changed: 62 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,22 @@
1313
# include <boost/python/to_python_converter.hpp>
1414
# include <boost/python/detail/dealloc.hpp>
1515
# include <boost/python/detail/none.hpp>
16+
# include <boost/python/type_id.hpp>
17+
# include <boost/python/errors.hpp>
18+
1619
# include <boost/type_traits/remove_pointer.hpp>
1720
# include <boost/type_traits/is_pointer.hpp>
21+
# include <boost/type_traits/is_void.hpp>
1822

19-
// opaque_pointer_converter --
20-
//
21-
// usage: opaque_pointer_converter<Pointer>("name")
23+
# include <boost/implicit_cast.hpp>
24+
25+
# include <boost/mpl/eval_if.hpp>
26+
# include <boost/mpl/identity.hpp>
27+
# include <boost/mpl/assert.hpp>
28+
29+
// opaque --
2230
//
23-
// registers to- and from- python conversions for a type Pointer,
24-
// and a corresponding Python type called "name".
31+
// registers to- and from- python conversions for a type Pointee.
2532
//
2633
// Note:
2734
// In addition you need to define specializations for type_id
@@ -31,83 +38,65 @@
3138
// For an example see libs/python/test/opaque.cpp
3239
//
3340
namespace boost { namespace python {
34-
namespace detail {
35-
template <class R>
36-
struct opaque_pointer_converter_requires_a_pointer_type
37-
# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__)
38-
{}
39-
# endif
40-
;
41-
}
4241

43-
template <class Pointer>
44-
struct opaque_pointer_converter
45-
: to_python_converter<
46-
Pointer, opaque_pointer_converter<Pointer> >
42+
template <class Pointee>
43+
struct opaque
4744
{
48-
BOOST_STATIC_CONSTANT(
49-
bool, ok = is_pointer<Pointer>::value);
50-
51-
typedef typename mpl::if_c<
52-
ok
53-
, Pointer
54-
, detail::opaque_pointer_converter_requires_a_pointer_type<Pointer>
55-
>::type ptr_type;
56-
45+
opaque()
46+
{
47+
type_object.tp_name = const_cast<char*>(type_id<Pointee*>().name());
48+
converter::registry::insert(&extract, type_id<Pointee>());
49+
converter::registry::insert(&wrap, type_id<Pointee*>());
50+
}
51+
52+
static opaque instance;
5753
private:
58-
struct instance;
59-
60-
public:
61-
explicit opaque_pointer_converter(char const* name)
54+
55+
static void* extract(PyObject* op)
6256
{
63-
type_object.tp_name = const_cast<char *> (name);
64-
65-
lvalue_from_pytype<
66-
opaque_pointer_converter<ptr_type>,
67-
&opaque_pointer_converter<ptr_type>::type_object
68-
>();
57+
return PyObject_TypeCheck(op, &type_object)
58+
? static_cast<python_instance*>(implicit_cast<void*>(op))->x
59+
: 0
60+
;
6961
}
7062

71-
static PyObject* convert(ptr_type x)
63+
static PyObject* wrap(void const* px)
7264
{
73-
PyObject *result = 0;
65+
Pointee* x = *static_cast<Pointee*const*>(px);
7466

75-
if (x != 0) {
76-
instance *o = PyObject_New (instance, &type_object);
67+
if (x == 0)
68+
return detail::none();
7769

78-
o->x = x;
79-
result = &o->base_;
80-
} else {
81-
result = detail::none();
70+
if ( python_instance *o = PyObject_New(python_instance, &type_object) )
71+
{
72+
o->x = x;
73+
return static_cast<PyObject*>(implicit_cast<void*>(o));
74+
}
75+
else
76+
{
77+
throw error_already_set();
8278
}
83-
84-
return (result);
85-
}
86-
87-
static typename ::boost::remove_pointer<ptr_type>::type&
88-
execute(instance &p_)
89-
{
90-
return *p_.x;
9179
}
9280

93-
private:
94-
static PyTypeObject type_object;
95-
96-
// This is a POD so we can use PyObject_Del on it, for example.
97-
struct instance
81+
struct python_instance
9882
{
99-
PyObject base_;
100-
ptr_type x;
83+
PyObject_HEAD
84+
Pointee* x;
10185
};
86+
87+
static PyTypeObject type_object;
10288
};
10389

104-
template <class Pointer>
105-
PyTypeObject opaque_pointer_converter<Pointer>::type_object =
90+
template <class Pointee>
91+
opaque<Pointee> opaque<Pointee>::instance;
92+
93+
template <class Pointee>
94+
PyTypeObject opaque<Pointee>::type_object =
10695
{
107-
PyObject_HEAD_INIT(NULL)
96+
PyObject_HEAD_INIT(0)
10897
0,
10998
0,
110-
sizeof(typename opaque_pointer_converter<Pointer>::instance),
99+
sizeof( BOOST_DEDUCED_TYPENAME opaque<Pointee>::python_instance ),
111100
0,
112101
::boost::python::detail::dealloc,
113102
0, /* tp_print */
@@ -155,11 +144,14 @@ PyTypeObject opaque_pointer_converter<Pointer>::type_object =
155144
#endif
156145
};
157146
}} // namespace boost::python
158-
# ifdef BOOST_MSVC
159-
// MSC works without this workaround, but needs another one ...
160-
# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \
161-
BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(Pointee)
147+
148+
# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
149+
150+
# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee)
151+
162152
# else
153+
154+
// If you change the below, don't forget to alter the end of type_id.hpp
163155
# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \
164156
namespace boost { namespace python { \
165157
template<> \
@@ -173,6 +165,8 @@ PyTypeObject opaque_pointer_converter<Pointer>::type_object =
173165
{ \
174166
return type_info (typeid (Pointee *)); \
175167
} \
176-
}}
168+
}}
169+
177170
# endif
171+
178172
# endif // OPAQUE_POINTER_CONVERTER_HPP_

include/boost/python/return_opaque_pointer.hpp

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,47 +10,38 @@
1010

1111
# include <boost/python/detail/prefix.hpp>
1212
# include <boost/python/opaque_pointer_converter.hpp>
13-
# include <boost/python/detail/indirect_traits.hpp>
14-
# include <boost/mpl/if.hpp>
13+
# include <boost/python/detail/force_instantiate.hpp>
14+
# include <boost/python/to_python_value.hpp>
15+
# include <boost/python/detail/value_arg.hpp>
16+
# include <boost/mpl/assert.hpp>
1517

1618
namespace boost { namespace python {
1719

1820
namespace detail
1921
{
20-
template <class Pointer>
21-
struct opaque_conversion_holder
22+
template <class Pointee>
23+
static void opaque_pointee(Pointee const volatile*)
2224
{
23-
inline PyObject *operator()(Pointer p) const
24-
{
25-
static opaque_pointer_converter<Pointer> converter (
26-
typeid (Pointer).name());
27-
28-
return converter.convert(p);
29-
}
30-
};
31-
32-
template <class R>
33-
struct return_opaque_pointer_requires_a_pointer_type
34-
# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__)
35-
{}
36-
# endif
37-
;
25+
force_instantiate(opaque<Pointee>::instance);
26+
}
3827
}
39-
28+
4029
struct return_opaque_pointer
4130
{
4231
template <class R>
4332
struct apply
4433
{
45-
BOOST_STATIC_CONSTANT(
46-
bool, ok = is_pointer<R>::value);
34+
BOOST_MPL_ASSERT_MSG( is_pointer<R>::value, RETURN_OPAQUE_POINTER_EXPECTS_A_POINTER_TYPE, (R));
4735

48-
typedef typename mpl::if_c<
49-
ok
50-
, detail::opaque_conversion_holder<R>
51-
, detail::return_opaque_pointer_requires_a_pointer_type<R>
52-
>::type type;
36+
struct type :
37+
boost::python::to_python_value<
38+
typename detail::value_arg<R>::type
39+
>
40+
{
41+
type() { detail::opaque_pointee(R()); }
42+
};
5343
};
5444
};
45+
5546
}} // namespace boost::python
5647
# endif // RETURN_OPAQUE_POINTER_HPP_

include/boost/python/type_id.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
# include <boost/static_assert.hpp>
1515
# include <boost/detail/workaround.hpp>
1616
# include <boost/type_traits/same_traits.hpp>
17+
# include <boost/type_traits/broken_compiler_spec.hpp>
1718

1819
# ifndef BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE
1920
# if defined(__GNUC__) \
@@ -168,6 +169,22 @@ inline char const* type_info::name() const
168169

169170
BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream&, type_info const&);
170171

172+
# if !BOOST_WORKAROUND(BOOST_MSVC, == 1200)
173+
template<>
174+
inline type_info type_id<void>(BOOST_PYTHON_EXPLICIT_TT_DEF(void))
175+
{
176+
return type_info (typeid (void *));
177+
}
178+
# ifndef BOOST_NO_CV_VOID_SPECIALIZATIONS
179+
template<>
180+
inline type_info type_id<const volatile void>(BOOST_PYTHON_EXPLICIT_TT_DEF(const volatile void))
181+
{
182+
return type_info (typeid (void *));
183+
}
184+
# endif
185+
186+
# endif
187+
171188
}} // namespace boost::python
172189

173190
#endif // TYPE_ID_DWA2002517_HPP

test/Jamfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ bpl-test crossmod_exception
157157
[ bpl-test extract ]
158158

159159
[ bpl-test opaque ]
160+
[ bpl-test voidptr ]
160161

161162
[ bpl-test pickle1 ]
162163
[ bpl-test pickle2 ]

test/Jamfile.v2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ bpl-test crossmod_exception
110110
[ bpl-test extract ]
111111

112112
[ bpl-test opaque ]
113+
[ bpl-test voidptr ]
113114

114115
[ bpl-test pickle1 ]
115116
[ bpl-test pickle2 ]

0 commit comments

Comments
 (0)