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