[857] | 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 |
|
---|
| 42 | namespace boost { namespace python { namespace objects {
|
---|
| 43 |
|
---|
| 44 | BOOST_PYTHON_DECL
|
---|
| 45 | void copy_class_object(type_info const& src, type_info const& dst);
|
---|
| 46 |
|
---|
| 47 | //
|
---|
| 48 | // Support for registering base/derived relationships
|
---|
| 49 | //
|
---|
| 50 | template <class Derived>
|
---|
| 51 | struct 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 | //
|
---|
| 87 | template <class T, class Bases>
|
---|
| 88 | inline 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 | //
|
---|
| 104 | template <class T, class Prev>
|
---|
| 105 | struct 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 |
|
---|
| 117 | template <
|
---|
| 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 | >
|
---|
| 123 | struct 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
|
---|