class_metadata.hpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // Copyright David Abrahams 2004.
  2. // Copyright Stefan Seefeld 2016.
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef boost_python_object_class_metadata_hpp_
  7. #define boost_python_object_class_metadata_hpp_
  8. #include <boost/python/converter/shared_ptr_from_python.hpp>
  9. #include <boost/python/object/inheritance.hpp>
  10. #include <boost/python/object/class_wrapper.hpp>
  11. #include <boost/python/object/make_instance.hpp>
  12. #include <boost/python/object/value_holder.hpp>
  13. #include <boost/python/object/pointer_holder.hpp>
  14. #include <boost/python/object/make_ptr_instance.hpp>
  15. #include <boost/python/detail/force_instantiate.hpp>
  16. #include <boost/python/detail/not_specified.hpp>
  17. #include <boost/python/detail/type_traits.hpp>
  18. #include <boost/python/has_back_reference.hpp>
  19. #include <boost/python/bases.hpp>
  20. #include <boost/mpl/if.hpp>
  21. #include <boost/mpl/eval_if.hpp>
  22. #include <boost/mpl/bool.hpp>
  23. #include <boost/mpl/or.hpp>
  24. #include <boost/mpl/identity.hpp>
  25. #include <boost/mpl/for_each.hpp>
  26. #include <boost/mpl/placeholders.hpp>
  27. #include <boost/mpl/single_view.hpp>
  28. #include <boost/mpl/assert.hpp>
  29. #include <boost/noncopyable.hpp>
  30. #include <boost/detail/workaround.hpp>
  31. namespace boost { namespace python { namespace objects {
  32. BOOST_PYTHON_DECL
  33. void copy_class_object(type_info const& src, type_info const& dst);
  34. //
  35. // Support for registering base/derived relationships
  36. //
  37. template <class Derived>
  38. struct register_base_of
  39. {
  40. template <class Base>
  41. inline void operator()(Base*) const
  42. {
  43. BOOST_MPL_ASSERT_NOT((boost::python::detail::is_same<Base,Derived>));
  44. // Register the Base class
  45. register_dynamic_id<Base>();
  46. // Register the up-cast
  47. register_conversion<Derived,Base>(false);
  48. // Register the down-cast, if appropriate.
  49. this->register_downcast((Base*)0, boost::python::detail::is_polymorphic<Base>());
  50. }
  51. private:
  52. static inline void register_downcast(void*, boost::python::detail::false_) {}
  53. template <class Base>
  54. static inline void register_downcast(Base*, boost::python::detail::true_)
  55. {
  56. register_conversion<Base, Derived>(true);
  57. }
  58. };
  59. //
  60. // Preamble of register_class. Also used for callback classes, which
  61. // need some registration of their own.
  62. //
  63. template <class T, class Bases>
  64. inline void register_shared_ptr_from_python_and_casts(T*, Bases)
  65. {
  66. // Constructor performs registration
  67. python::detail::force_instantiate(converter::shared_ptr_from_python<T, boost::shared_ptr>());
  68. #if !defined(BOOST_NO_CXX11_SMART_PTR)
  69. python::detail::force_instantiate(converter::shared_ptr_from_python<T, std::shared_ptr>());
  70. #endif
  71. //
  72. // register all up/downcasts here. We're using the alternate
  73. // interface to mpl::for_each to avoid an MSVC 6 bug.
  74. //
  75. register_dynamic_id<T>();
  76. mpl::for_each(register_base_of<T>(), (Bases*)0, (boost::python::detail::add_pointer<mpl::_>*)0);
  77. }
  78. //
  79. // Helper for choosing the unnamed held_type argument
  80. //
  81. template <class T, class Prev>
  82. struct select_held_type
  83. : mpl::if_<
  84. mpl::or_<
  85. python::detail::specifies_bases<T>
  86. , boost::python::detail::is_same<T,noncopyable>
  87. >
  88. , Prev
  89. , T
  90. >
  91. {
  92. };
  93. template <
  94. class T // class being wrapped
  95. , class X1 // = detail::not_specified
  96. , class X2 // = detail::not_specified
  97. , class X3 // = detail::not_specified
  98. >
  99. struct class_metadata
  100. {
  101. //
  102. // Calculate the unnamed template arguments
  103. //
  104. // held_type_arg -- not_specified, [a class derived from] T or a
  105. // smart pointer to [a class derived from] T. Preserving
  106. // not_specified allows us to give class_<T,T> a back-reference.
  107. typedef typename select_held_type<
  108. X1
  109. , typename select_held_type<
  110. X2
  111. , typename select_held_type<
  112. X3
  113. , python::detail::not_specified
  114. >::type
  115. >::type
  116. >::type held_type_arg;
  117. // bases
  118. typedef typename python::detail::select_bases<
  119. X1
  120. , typename python::detail::select_bases<
  121. X2
  122. , typename python::detail::select_bases<
  123. X3
  124. , python::bases<>
  125. >::type
  126. >::type
  127. >::type bases;
  128. typedef mpl::or_<
  129. boost::python::detail::is_same<X1,noncopyable>
  130. , boost::python::detail::is_same<X2,noncopyable>
  131. , boost::python::detail::is_same<X3,noncopyable>
  132. > is_noncopyable;
  133. //
  134. // Holder computation.
  135. //
  136. // Compute the actual type that will be held in the Holder.
  137. typedef typename mpl::if_<
  138. boost::python::detail::is_same<held_type_arg,python::detail::not_specified>, T, held_type_arg
  139. >::type held_type;
  140. // Determine if the object will be held by value
  141. typedef mpl::bool_<boost::python::detail::is_convertible<held_type*,T*>::value> use_value_holder;
  142. // Compute the "wrapped type", that is, if held_type is a smart
  143. // pointer, we're talking about the pointee.
  144. typedef typename mpl::eval_if<
  145. use_value_holder
  146. , mpl::identity<held_type>
  147. , pointee<held_type>
  148. >::type wrapped;
  149. // Determine whether to use a "back-reference holder"
  150. typedef mpl::bool_<
  151. mpl::or_<
  152. has_back_reference<T>
  153. , boost::python::detail::is_same<held_type_arg,T>
  154. , is_base_and_derived<T,wrapped>
  155. >::value
  156. > use_back_reference;
  157. // Select the holder.
  158. typedef typename mpl::eval_if<
  159. use_back_reference
  160. , mpl::if_<
  161. use_value_holder
  162. , value_holder_back_reference<T, wrapped>
  163. , pointer_holder_back_reference<held_type,T>
  164. >
  165. , mpl::if_<
  166. use_value_holder
  167. , value_holder<T>
  168. , pointer_holder<held_type,wrapped>
  169. >
  170. >::type holder;
  171. inline static void register_() // Register the runtime metadata.
  172. {
  173. class_metadata::register_aux((T*)0);
  174. }
  175. private:
  176. template <class T2>
  177. inline static void register_aux(python::wrapper<T2>*)
  178. {
  179. typedef typename mpl::not_<boost::python::detail::is_same<T2,wrapped> >::type use_callback;
  180. class_metadata::register_aux2((T2*)0, use_callback());
  181. }
  182. inline static void register_aux(void*)
  183. {
  184. typedef typename is_base_and_derived<T,wrapped>::type use_callback;
  185. class_metadata::register_aux2((T*)0, use_callback());
  186. }
  187. template <class T2, class Callback>
  188. inline static void register_aux2(T2*, Callback)
  189. {
  190. objects::register_shared_ptr_from_python_and_casts((T2*)0, bases());
  191. class_metadata::maybe_register_callback_class((T2*)0, Callback());
  192. class_metadata::maybe_register_class_to_python((T2*)0, is_noncopyable());
  193. class_metadata::maybe_register_pointer_to_python(
  194. (T2*)0, (use_value_holder*)0, (use_back_reference*)0);
  195. }
  196. //
  197. // Support for converting smart pointers to python
  198. //
  199. inline static void maybe_register_pointer_to_python(...) {}
  200. #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
  201. inline static void maybe_register_pointer_to_python(void*,void*,mpl::true_*)
  202. {
  203. objects::copy_class_object(python::type_id<T>(), python::type_id<back_reference<T const &> >());
  204. objects::copy_class_object(python::type_id<T>(), python::type_id<back_reference<T &> >());
  205. }
  206. #endif
  207. template <class T2>
  208. inline static void maybe_register_pointer_to_python(T2*, mpl::false_*, mpl::false_*)
  209. {
  210. python::detail::force_instantiate(
  211. objects::class_value_wrapper<
  212. held_type
  213. , make_ptr_instance<T2, pointer_holder<held_type, T2> >
  214. >()
  215. );
  216. #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
  217. // explicit qualification of type_id makes msvc6 happy
  218. objects::copy_class_object(python::type_id<T2>(), python::type_id<held_type>());
  219. #endif
  220. }
  221. //
  222. // Support for registering to-python converters
  223. //
  224. inline static void maybe_register_class_to_python(void*, mpl::true_) {}
  225. template <class T2>
  226. inline static void maybe_register_class_to_python(T2*, mpl::false_)
  227. {
  228. python::detail::force_instantiate(class_cref_wrapper<T2, make_instance<T2, holder> >());
  229. #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
  230. // explicit qualification of type_id makes msvc6 happy
  231. objects::copy_class_object(python::type_id<T2>(), python::type_id<held_type>());
  232. #endif
  233. }
  234. //
  235. // Support for registering callback classes
  236. //
  237. inline static void maybe_register_callback_class(void*, mpl::false_) {}
  238. template <class T2>
  239. inline static void maybe_register_callback_class(T2*, mpl::true_)
  240. {
  241. objects::register_shared_ptr_from_python_and_casts(
  242. (wrapped*)0, mpl::single_view<T2>());
  243. // explicit qualification of type_id makes msvc6 happy
  244. objects::copy_class_object(python::type_id<T2>(), python::type_id<wrapped>());
  245. }
  246. };
  247. }}} // namespace boost::python::object
  248. #endif