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)
5/*
6 * Generic Conversion of opaque C++-pointers to a Python-Wrapper.
7 */
8# ifndef OPAQUE_POINTER_CONVERTER_HPP_
9# define OPAQUE_POINTER_CONVERTER_HPP_
10
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>
19
20# include <boost/type_traits/remove_pointer.hpp>
21# include <boost/type_traits/is_pointer.hpp>
22# include <boost/type_traits/is_void.hpp>
23
24# include <boost/implicit_cast.hpp>
25
26# include <boost/mpl/eval_if.hpp>
27# include <boost/mpl/identity.hpp>
28# include <boost/mpl/assert.hpp>
29
30// opaque --
31//
32// registers to- and from- python conversions for a type Pointee.
33//
34// Note:
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)
38//
39// For an example see libs/python/test/opaque.cpp
40//
41namespace boost { namespace python {
42
43template <class Pointee>
44struct opaque
45{
46 opaque()
47 {
48 if (type_object.tp_name == 0)
49 {
50 type_object.tp_name = const_cast<char*>(type_id<Pointee*>().name());
51 if (PyType_Ready (&type_object) < 0)
52 {
53 throw error_already_set();
54 }
55
56 this->register_self();
57 }
58 }
59
60 static opaque instance;
61private:
62
63 static void* extract(PyObject* op)
64 {
65 return PyObject_TypeCheck(op, &type_object)
66 ? static_cast<python_instance*>(implicit_cast<void*>(op))->x
67 : 0
68 ;
69 }
70
71 static PyObject* wrap(void const* px)
72 {
73 Pointee* x = *static_cast<Pointee*const*>(px);
74
75 if (x == 0)
76 return detail::none();
77
78 if ( python_instance *o = PyObject_New(python_instance, &type_object) )
79 {
80 o->x = x;
81 return static_cast<PyObject*>(implicit_cast<void*>(o));
82 }
83 else
84 {
85 throw error_already_set();
86 }
87 }
88
89 void register_self()
90 {
91 converter::registration const *existing =
92 converter::registry::query (type_id<Pointee*>());
93
94 if ((existing == 0) || (existing->m_to_python == 0))
95 {
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);
99#else
100 converter::registry::insert(&extract, type_id<Pointee>());
101 converter::registry::insert(&wrap, type_id<Pointee*>());
102#endif
103 }
104 }
105
106 struct python_instance
107 {
108 PyObject_HEAD
109 Pointee* x;
110 };
111
112 static PyTypeObject type_object;
113#ifndef BOOST_PYTHON_NO_PY_SIGNATURES
114 static PyTypeObject const *get_pytype(){return &type_object; }
115#endif
116};
117
118template <class Pointee>
119opaque<Pointee> opaque<Pointee>::instance;
120
121template <class Pointee>
122PyTypeObject opaque<Pointee>::type_object =
123{
124 PyVarObject_HEAD_INIT(NULL, 0)
125 0,
126 sizeof( BOOST_DEDUCED_TYPENAME opaque<Pointee>::python_instance ),
127 0,
128 ::boost::python::detail::dealloc,
129 0, /* tp_print */
130 0, /* tp_getattr */
131 0, /* tp_setattr */
132 0, /* tp_compare */
133 0, /* tp_repr */
134 0, /* tp_as_number */
135 0, /* tp_as_sequence */
136 0, /* tp_as_mapping */
137 0, /* tp_hash */
138 0, /* tp_call */
139 0, /* tp_str */
140 0, /* tp_getattro */
141 0, /* tp_setattro */
142 0, /* tp_as_buffer */
143 0, /* tp_flags */
144 0, /* tp_doc */
145 0, /* tp_traverse */
146 0, /* tp_clear */
147 0, /* tp_richcompare */
148 0, /* tp_weaklistoffset */
149 0, /* tp_iter */
150 0, /* tp_iternext */
151 0, /* tp_methods */
152 0, /* tp_members */
153 0, /* tp_getset */
154 0, /* tp_base */
155 0, /* tp_dict */
156 0, /* tp_descr_get */
157 0, /* tp_descr_set */
158 0, /* tp_dictoffset */
159 0, /* tp_init */
160 0, /* tp_alloc */
161 0, /* tp_new */
162 0, /* tp_free */
163 0, /* tp_is_gc */
164 0, /* tp_bases */
165 0, /* tp_mro */
166 0, /* tp_cache */
167 0, /* tp_subclasses */
168 0, /* tp_weaklist */
169#if PYTHON_API_VERSION >= 1012
170 0 /* tp_del */
171#endif
172};
173}} // namespace boost::python
174
175// If you change the below, don't forget to alter the end of type_id.hpp
176# define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \
177 namespace boost { namespace python { \
178 template<> \
179 inline type_info type_id<Pointee>() \
180 { \
181 return type_info (typeid (Pointee *)); \
182 } \
183 template<> \
184 inline type_info type_id<const volatile Pointee&>() \
185 { \
186 return type_info (typeid (Pointee *)); \
187 } \
188 }}
189
190# endif // OPAQUE_POINTER_CONVERTER_HPP_
191

source code of boost/boost/python/opaque_pointer_converter.hpp