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