|
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 // |
|
41 namespace boost { namespace python { |
|
42 |
|
43 template <class Pointee> |
|
44 struct 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; |
|
61 private: |
|
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 converter::registry::insert(&extract, type_id<Pointee>()); |
|
97 converter::registry::insert(&wrap, type_id<Pointee*>()); |
|
98 } |
|
99 } |
|
100 |
|
101 struct python_instance |
|
102 { |
|
103 PyObject_HEAD |
|
104 Pointee* x; |
|
105 }; |
|
106 |
|
107 static PyTypeObject type_object; |
|
108 }; |
|
109 |
|
110 template <class Pointee> |
|
111 opaque<Pointee> opaque<Pointee>::instance; |
|
112 |
|
113 template <class Pointee> |
|
114 PyTypeObject opaque<Pointee>::type_object = |
|
115 { |
|
116 PyObject_HEAD_INIT(0) |
|
117 0, |
|
118 0, |
|
119 sizeof( BOOST_DEDUCED_TYPENAME opaque<Pointee>::python_instance ), |
|
120 0, |
|
121 ::boost::python::detail::dealloc, |
|
122 0, /* tp_print */ |
|
123 0, /* tp_getattr */ |
|
124 0, /* tp_setattr */ |
|
125 0, /* tp_compare */ |
|
126 0, /* tp_repr */ |
|
127 0, /* tp_as_number */ |
|
128 0, /* tp_as_sequence */ |
|
129 0, /* tp_as_mapping */ |
|
130 0, /* tp_hash */ |
|
131 0, /* tp_call */ |
|
132 0, /* tp_str */ |
|
133 0, /* tp_getattro */ |
|
134 0, /* tp_setattro */ |
|
135 0, /* tp_as_buffer */ |
|
136 0, /* tp_flags */ |
|
137 0, /* tp_doc */ |
|
138 0, /* tp_traverse */ |
|
139 0, /* tp_clear */ |
|
140 0, /* tp_richcompare */ |
|
141 0, /* tp_weaklistoffset */ |
|
142 0, /* tp_iter */ |
|
143 0, /* tp_iternext */ |
|
144 0, /* tp_methods */ |
|
145 0, /* tp_members */ |
|
146 0, /* tp_getset */ |
|
147 0, /* tp_base */ |
|
148 0, /* tp_dict */ |
|
149 0, /* tp_descr_get */ |
|
150 0, /* tp_descr_set */ |
|
151 0, /* tp_dictoffset */ |
|
152 0, /* tp_init */ |
|
153 0, /* tp_alloc */ |
|
154 0, /* tp_new */ |
|
155 0, /* tp_free */ |
|
156 0, /* tp_is_gc */ |
|
157 0, /* tp_bases */ |
|
158 0, /* tp_mro */ |
|
159 0, /* tp_cache */ |
|
160 0, /* tp_subclasses */ |
|
161 0, /* tp_weaklist */ |
|
162 #if PYTHON_API_VERSION >= 1012 |
|
163 0 /* tp_del */ |
|
164 #endif |
|
165 }; |
|
166 }} // namespace boost::python |
|
167 |
|
168 # if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) |
|
169 |
|
170 # define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) |
|
171 |
|
172 # else |
|
173 |
|
174 // If you change the below, don't forget to alter the end of type_id.hpp |
|
175 # define BOOST_PYTHON_OPAQUE_SPECIALIZED_TYPE_ID(Pointee) \ |
|
176 namespace boost { namespace python { \ |
|
177 template<> \ |
|
178 inline type_info type_id<Pointee>(BOOST_PYTHON_EXPLICIT_TT_DEF(Pointee)) \ |
|
179 { \ |
|
180 return type_info (typeid (Pointee *)); \ |
|
181 } \ |
|
182 template<> \ |
|
183 inline type_info type_id<const volatile Pointee&>( \ |
|
184 BOOST_PYTHON_EXPLICIT_TT_DEF(const volatile Pointee&)) \ |
|
185 { \ |
|
186 return type_info (typeid (Pointee *)); \ |
|
187 } \ |
|
188 }} |
|
189 |
|
190 # endif |
|
191 |
|
192 # endif // OPAQUE_POINTER_CONVERTER_HPP_ |