]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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> | |
b32b8144 | 20 | #include <boost/python/detail/type_traits.hpp> |
7c673cae FG |
21 | |
22 | #include <boost/python/has_back_reference.hpp> | |
23 | #include <boost/python/bases.hpp> | |
24 | ||
7c673cae FG |
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> | |
7c673cae FG |
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> | |
51 | inline void operator()(Base*) const | |
52 | { | |
b32b8144 | 53 | BOOST_MPL_ASSERT_NOT((boost::python::detail::is_same<Base,Derived>)); |
7c673cae FG |
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. | |
b32b8144 | 62 | this->register_downcast((Base*)0, boost::python::detail::is_polymorphic<Base>()); |
7c673cae FG |
63 | } |
64 | ||
65 | private: | |
b32b8144 | 66 | static inline void register_downcast(void*, boost::python::detail::false_) {} |
7c673cae FG |
67 | |
68 | template <class Base> | |
b32b8144 | 69 | static inline void register_downcast(Base*, boost::python::detail::true_) |
7c673cae FG |
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> | |
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>()); | |
b32b8144 | 86 | #if !defined(BOOST_NO_CXX11_SMART_PTR) |
7c673cae FG |
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>(); | |
b32b8144 | 95 | mpl::for_each(register_base_of<T>(), (Bases*)0, (boost::python::detail::add_pointer<mpl::_>*)0); |
7c673cae FG |
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> | |
b32b8144 | 106 | , boost::python::detail::is_same<T,noncopyable> |
7c673cae FG |
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_< | |
b32b8144 FG |
153 | boost::python::detail::is_same<X1,noncopyable> |
154 | , boost::python::detail::is_same<X2,noncopyable> | |
155 | , boost::python::detail::is_same<X3,noncopyable> | |
7c673cae FG |
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_< | |
b32b8144 | 164 | boost::python::detail::is_same<held_type_arg,python::detail::not_specified>, T, held_type_arg |
7c673cae FG |
165 | >::type held_type; |
166 | ||
167 | // Determine if the object will be held by value | |
b32b8144 | 168 | typedef mpl::bool_<boost::python::detail::is_convertible<held_type*,T*>::value> use_value_holder; |
7c673cae FG |
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> | |
b32b8144 | 182 | , boost::python::detail::is_same<held_type_arg,T> |
7c673cae FG |
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 | ||
202 | inline static void register_() // Register the runtime metadata. | |
203 | { | |
204 | class_metadata::register_aux((T*)0); | |
205 | } | |
206 | ||
207 | private: | |
208 | template <class T2> | |
209 | inline static void register_aux(python::wrapper<T2>*) | |
210 | { | |
b32b8144 | 211 | typedef typename mpl::not_<boost::python::detail::is_same<T2,wrapped> >::type use_callback; |
7c673cae FG |
212 | class_metadata::register_aux2((T2*)0, use_callback()); |
213 | } | |
214 | ||
215 | 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> | |
222 | 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 | // | |
237 | inline static void maybe_register_pointer_to_python(...) {} | |
238 | ||
239 | #ifndef BOOST_PYTHON_NO_PY_SIGNATURES | |
b32b8144 | 240 | inline static void maybe_register_pointer_to_python(void*,void*,mpl::true_*) |
7c673cae FG |
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> | |
248 | 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 | // | |
264 | inline static void maybe_register_class_to_python(void*, mpl::true_) {} | |
265 | ||
266 | ||
267 | template <class T2> | |
268 | 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 | // | |
280 | inline static void maybe_register_callback_class(void*, mpl::false_) {} | |
281 | ||
282 | template <class T2> | |
283 | 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 |