opaque_pointer_converter.hpp 5.8 KB

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