source: NonGTP/Boost/boost/python/object/class_metadata.hpp @ 857

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