opaque_pointer_converter.hpp 5.9 KB

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