1 // Copyright Gottfried Ganßauge 2003..2006.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
6 * Generic Conversion of opaque C++-pointers to a Python-Wrapper.
8 # ifndef OPAQUE_POINTER_CONVERTER_HPP_
9 # define OPAQUE_POINTER_CONVERTER_HPP_
11 # include <boost/python/detail/prefix.hpp>
12 # include <boost/python/lvalue_from_pytype.hpp>
13 # include <boost/python/to_python_converter.hpp>
14 # include <boost/python/converter/registrations.hpp>
15 # include <boost/python/detail/dealloc.hpp>
16 # include <boost/python/detail/none.hpp>
17 # include <boost/python/type_id.hpp>
18 # include <boost/python/errors.hpp>
20 # include <boost/type_traits/remove_pointer.hpp>
21 # include <boost/type_traits/is_pointer.hpp>
22 # include <boost/type_traits/is_void.hpp>
24 # include <boost/implicit_cast.hpp>
26 # include <boost/mpl/eval_if.hpp>
27 # include <boost/mpl/identity.hpp>
28 # include <boost/mpl/assert.hpp>
32 // registers to- and from- python conversions for a type Pointee.
35 // In addition you need to define specializations for type_id
36 // on the type pointed to by Pointer using
37 // BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee)
39 // For an example see libs/python/test/opaque.cpp
41 namespace boost
{ namespace python
{
43 template <class Pointee
>
48 if (type_object
.tp_name
== 0)
50 type_object
.tp_name
= const_cast<char*>(type_id
<Pointee
*>().name());
51 if (PyType_Ready (&type_object
) < 0)
53 throw error_already_set();
56 this->register_self();
60 static opaque instance
;
63 static void* extract(PyObject
* op
)
65 return PyObject_TypeCheck(op
, &type_object
)
66 ? static_cast<python_instance
*>(implicit_cast
<void*>(op
))->x
71 static PyObject
* wrap(void const* px
)
73 Pointee
* x
= *static_cast<Pointee
*const*>(px
);
76 return detail::none();
78 if ( python_instance
*o
= PyObject_New(python_instance
, &type_object
) )
81 return static_cast<PyObject
*>(implicit_cast
<void*>(o
));
85 throw error_already_set();
91 converter::registration
const *existing
=
92 converter::registry::query (type_id
<Pointee
*>());
94 if ((existing
== 0) || (existing
->m_to_python
== 0))
96 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
97 converter::registry::insert(&extract
, type_id
<Pointee
>(), &get_pytype
);
98 converter::registry::insert(&wrap
, type_id
<Pointee
*>(), &get_pytype
);
100 converter::registry::insert(&extract
, type_id
<Pointee
>());
101 converter::registry::insert(&wrap
, type_id
<Pointee
*>());
106 struct python_instance
112 static PyTypeObject type_object
;
113 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
114 static PyTypeObject
const *get_pytype(){return &type_object
; }
118 template <class Pointee
>
119 opaque
<Pointee
> opaque
<Pointee
>::instance
;
121 template <class Pointee
>
122 PyTypeObject opaque
<Pointee
>::type_object
=
124 PyObject_HEAD_INIT(0)
127 sizeof( BOOST_DEDUCED_TYPENAME opaque
<Pointee
>::python_instance
),
129 ::boost::python::detail::dealloc
,
135 0, /* tp_as_number */
136 0, /* tp_as_sequence */
137 0, /* tp_as_mapping */
143 0, /* tp_as_buffer */
148 0, /* tp_richcompare */
149 0, /* tp_weaklistoffset */
157 0, /* tp_descr_get */
158 0, /* tp_descr_set */
159 0, /* tp_dictoffset */
168 0, /* tp_subclasses */
170 #if PYTHON_API_VERSION >= 1012
174 }} // namespace boost::python
176 # if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
178 # define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee)
182 // If you change the below, don't forget to alter the end of type_id.hpp
183 # define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \
184 namespace boost { namespace python { \
186 inline type_info type_id<Pointee>(BOOST_PYTHON_EXPLICIT_TT_DEF(Pointee)) \
188 return type_info (typeid (Pointee *)); \
191 inline type_info type_id<const volatile Pointee&>( \
192 BOOST_PYTHON_EXPLICIT_TT_DEF(const volatile Pointee&)) \
194 return type_info (typeid (Pointee *)); \
200 # endif // OPAQUE_POINTER_CONVERTER_HPP_