• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
7 #ifndef boost_python_object_class_metadata_hpp_
8 #define boost_python_object_class_metadata_hpp_
9 
10 #include <boost/python/converter/shared_ptr_from_python.hpp>
11 #include <boost/python/object/inheritance.hpp>
12 #include <boost/python/object/class_wrapper.hpp>
13 #include <boost/python/object/make_instance.hpp>
14 #include <boost/python/object/value_holder.hpp>
15 #include <boost/python/object/pointer_holder.hpp>
16 #include <boost/python/object/make_ptr_instance.hpp>
17 
18 #include <boost/python/detail/force_instantiate.hpp>
19 #include <boost/python/detail/not_specified.hpp>
20 #include <boost/python/detail/type_traits.hpp>
21 
22 #include <boost/python/has_back_reference.hpp>
23 #include <boost/python/bases.hpp>
24 
25 #include <boost/mpl/if.hpp>
26 #include <boost/mpl/eval_if.hpp>
27 #include <boost/mpl/bool.hpp>
28 #include <boost/mpl/or.hpp>
29 #include <boost/mpl/identity.hpp>
30 #include <boost/mpl/for_each.hpp>
31 #include <boost/mpl/placeholders.hpp>
32 #include <boost/mpl/single_view.hpp>
33 
34 #include <boost/mpl/assert.hpp>
35 
36 #include <boost/noncopyable.hpp>
37 #include <boost/detail/workaround.hpp>
38 
39 namespace boost { namespace python { namespace objects {
40 
41 BOOST_PYTHON_DECL
42 void copy_class_object(type_info const& src, type_info const& dst);
43 
44 //
45 // Support for registering base/derived relationships
46 //
47 template <class Derived>
48 struct register_base_of
49 {
50     template <class Base>
operator ()boost::python::objects::register_base_of51     inline void operator()(Base*) const
52     {
53         BOOST_MPL_ASSERT_NOT((boost::python::detail::is_same<Base,Derived>));
54 
55         // Register the Base class
56         register_dynamic_id<Base>();
57 
58         // Register the up-cast
59         register_conversion<Derived,Base>(false);
60 
61         // Register the down-cast, if appropriate.
62         this->register_downcast((Base*)0, boost::python::detail::is_polymorphic<Base>());
63     }
64 
65  private:
register_downcastboost::python::objects::register_base_of66     static inline void register_downcast(void*, boost::python::detail::false_) {}
67 
68     template <class Base>
register_downcastboost::python::objects::register_base_of69     static inline void register_downcast(Base*, boost::python::detail::true_)
70     {
71         register_conversion<Base, Derived>(true);
72     }
73 
74 };
75 
76 //
77 // Preamble of register_class.  Also used for callback classes, which
78 // need some registration of their own.
79 //
80 
81 template <class T, class Bases>
register_shared_ptr_from_python_and_casts(T *,Bases)82 inline void register_shared_ptr_from_python_and_casts(T*, Bases)
83 {
84   // Constructor performs registration
85   python::detail::force_instantiate(converter::shared_ptr_from_python<T, boost::shared_ptr>());
86 #if !defined(BOOST_NO_CXX11_SMART_PTR)
87   python::detail::force_instantiate(converter::shared_ptr_from_python<T, std::shared_ptr>());
88 #endif
89 
90   //
91   // register all up/downcasts here.  We're using the alternate
92   // interface to mpl::for_each to avoid an MSVC 6 bug.
93   //
94   register_dynamic_id<T>();
95   mpl::for_each(register_base_of<T>(), (Bases*)0, (boost::python::detail::add_pointer<mpl::_>*)0);
96 }
97 
98 //
99 // Helper for choosing the unnamed held_type argument
100 //
101 template <class T, class Prev>
102 struct select_held_type
103   : mpl::if_<
104         mpl::or_<
105             python::detail::specifies_bases<T>
106           , boost::python::detail::is_same<T,noncopyable>
107         >
108       , Prev
109       , T
110     >
111 {
112 };
113 
114 template <
115     class T // class being wrapped
116   , class X1 // = detail::not_specified
117   , class X2 // = detail::not_specified
118   , class X3 // = detail::not_specified
119 >
120 struct class_metadata
121 {
122     //
123     // Calculate the unnamed template arguments
124     //
125 
126     // held_type_arg -- not_specified, [a class derived from] T or a
127     // smart pointer to [a class derived from] T.  Preserving
128     // not_specified allows us to give class_<T,T> a back-reference.
129     typedef typename select_held_type<
130         X1
131       , typename select_held_type<
132             X2
133           , typename select_held_type<
134                 X3
135               , python::detail::not_specified
136             >::type
137         >::type
138     >::type held_type_arg;
139 
140     // bases
141     typedef typename python::detail::select_bases<
142         X1
143       , typename python::detail::select_bases<
144             X2
145           , typename python::detail::select_bases<
146                 X3
147               , python::bases<>
148             >::type
149         >::type
150     >::type bases;
151 
152     typedef mpl::or_<
153         boost::python::detail::is_same<X1,noncopyable>
154       , boost::python::detail::is_same<X2,noncopyable>
155       , boost::python::detail::is_same<X3,noncopyable>
156     > is_noncopyable;
157 
158     //
159     // Holder computation.
160     //
161 
162     // Compute the actual type that will be held in the Holder.
163     typedef typename mpl::if_<
164         boost::python::detail::is_same<held_type_arg,python::detail::not_specified>, T, held_type_arg
165     >::type held_type;
166 
167     // Determine if the object will be held by value
168     typedef mpl::bool_<boost::python::detail::is_convertible<held_type*,T*>::value> use_value_holder;
169 
170     // Compute the "wrapped type", that is, if held_type is a smart
171     // pointer, we're talking about the pointee.
172     typedef typename mpl::eval_if<
173         use_value_holder
174       , mpl::identity<held_type>
175       , pointee<held_type>
176     >::type wrapped;
177 
178     // Determine whether to use a "back-reference holder"
179     typedef mpl::bool_<
180         mpl::or_<
181             has_back_reference<T>
182           , boost::python::detail::is_same<held_type_arg,T>
183           , is_base_and_derived<T,wrapped>
184         >::value
185     > use_back_reference;
186 
187     // Select the holder.
188     typedef typename mpl::eval_if<
189         use_back_reference
190       , mpl::if_<
191             use_value_holder
192           , value_holder_back_reference<T, wrapped>
193           , pointer_holder_back_reference<held_type,T>
194         >
195       , mpl::if_<
196             use_value_holder
197           , value_holder<T>
198           , pointer_holder<held_type,wrapped>
199         >
200     >::type holder;
201 
register_boost::python::objects::class_metadata202     inline static void register_() // Register the runtime metadata.
203     {
204         class_metadata::register_aux((T*)0);
205     }
206 
207  private:
208     template <class T2>
register_auxboost::python::objects::class_metadata209     inline static void register_aux(python::wrapper<T2>*)
210     {
211         typedef typename mpl::not_<boost::python::detail::is_same<T2,wrapped> >::type use_callback;
212         class_metadata::register_aux2((T2*)0, use_callback());
213     }
214 
register_auxboost::python::objects::class_metadata215     inline static void register_aux(void*)
216     {
217         typedef typename is_base_and_derived<T,wrapped>::type use_callback;
218         class_metadata::register_aux2((T*)0, use_callback());
219     }
220 
221     template <class T2, class Callback>
register_aux2boost::python::objects::class_metadata222     inline static void register_aux2(T2*, Callback)
223     {
224 	objects::register_shared_ptr_from_python_and_casts((T2*)0, bases());
225         class_metadata::maybe_register_callback_class((T2*)0, Callback());
226 
227         class_metadata::maybe_register_class_to_python((T2*)0, is_noncopyable());
228 
229         class_metadata::maybe_register_pointer_to_python(
230             (T2*)0, (use_value_holder*)0, (use_back_reference*)0);
231     }
232 
233 
234     //
235     // Support for converting smart pointers to python
236     //
maybe_register_pointer_to_pythonboost::python::objects::class_metadata237     inline static void maybe_register_pointer_to_python(...) {}
238 
239 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
maybe_register_pointer_to_pythonboost::python::objects::class_metadata240     inline static void maybe_register_pointer_to_python(void*,void*,mpl::true_*)
241     {
242         objects::copy_class_object(python::type_id<T>(), python::type_id<back_reference<T const &> >());
243         objects::copy_class_object(python::type_id<T>(), python::type_id<back_reference<T &> >());
244     }
245 #endif
246 
247     template <class T2>
maybe_register_pointer_to_pythonboost::python::objects::class_metadata248     inline static void maybe_register_pointer_to_python(T2*, mpl::false_*, mpl::false_*)
249     {
250         python::detail::force_instantiate(
251             objects::class_value_wrapper<
252                 held_type
253               , make_ptr_instance<T2, pointer_holder<held_type, T2> >
254             >()
255         );
256 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
257         // explicit qualification of type_id makes msvc6 happy
258         objects::copy_class_object(python::type_id<T2>(), python::type_id<held_type>());
259 #endif
260     }
261     //
262     // Support for registering to-python converters
263     //
maybe_register_class_to_pythonboost::python::objects::class_metadata264     inline static void maybe_register_class_to_python(void*, mpl::true_) {}
265 
266 
267     template <class T2>
maybe_register_class_to_pythonboost::python::objects::class_metadata268     inline static void maybe_register_class_to_python(T2*, mpl::false_)
269     {
270         python::detail::force_instantiate(class_cref_wrapper<T2, make_instance<T2, holder> >());
271 #ifndef BOOST_PYTHON_NO_PY_SIGNATURES
272         // explicit qualification of type_id makes msvc6 happy
273         objects::copy_class_object(python::type_id<T2>(), python::type_id<held_type>());
274 #endif
275     }
276 
277     //
278     // Support for registering callback classes
279     //
maybe_register_callback_classboost::python::objects::class_metadata280     inline static void maybe_register_callback_class(void*, mpl::false_) {}
281 
282     template <class T2>
maybe_register_callback_classboost::python::objects::class_metadata283     inline static void maybe_register_callback_class(T2*, mpl::true_)
284     {
285 	objects::register_shared_ptr_from_python_and_casts(
286             (wrapped*)0, mpl::single_view<T2>());
287         // explicit qualification of type_id makes msvc6 happy
288         objects::copy_class_object(python::type_id<T2>(), python::type_id<wrapped>());
289     }
290 };
291 
292 }}} // namespace boost::python::object
293 
294 #endif
295