Chris@16: // Copyright David Abrahams 2002. Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: #ifndef OBJECT_MANAGER_DWA2002614_HPP Chris@16: # define OBJECT_MANAGER_DWA2002614_HPP Chris@16: Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: # include Chris@16: Chris@16: // Facilities for dealing with types which always manage Python Chris@16: // objects. Some examples are object, list, str, et. al. Different Chris@16: // to_python/from_python conversion rules apply here because in Chris@16: // contrast to other types which are typically embedded inside a Chris@16: // Python object, these are wrapped around a Python object. For most Chris@16: // object managers T, a C++ non-const T reference argument does not Chris@16: // imply the existence of a T lvalue embedded in the corresponding Chris@16: // Python argument, since mutating member functions on T actually only Chris@16: // modify the held Python object. Chris@16: // Chris@16: // handle is an object manager, though strictly speaking it should Chris@16: // not be. In other words, even though mutating member functions of Chris@16: // hanlde actually modify the handle and not the T object, Chris@16: // handle& arguments of wrapped functions will bind to "rvalues" Chris@16: // wrapping the actual Python argument, just as with other object Chris@16: // manager classes. Making an exception for handle is simply not Chris@16: // worth the trouble. Chris@16: // Chris@16: // borrowed cv* is an object manager so that we can use the general Chris@16: // to_python mechanisms to convert raw Python object pointers to Chris@16: // python, without the usual semantic problems of using raw pointers. Chris@16: Chris@16: Chris@16: // Object Manager Concept requirements: Chris@16: // Chris@16: // T is an Object Manager Chris@16: // p is a PyObject* Chris@16: // x is a T Chris@16: // Chris@16: // * object_manager_traits::is_specialized == true Chris@16: // Chris@16: // * T(detail::borrowed_reference(p)) Chris@16: // Manages p without checking its type Chris@16: // Chris@16: // * get_managed_object(x, boost::python::tag) Chris@16: // Convertible to PyObject* Chris@16: // Chris@16: // Additional requirements if T can be converted from_python: Chris@16: // Chris@16: // * T(object_manager_traits::adopt(p)) Chris@16: // steals a reference to p, or throws a TypeError exception if Chris@16: // p doesn't have an appropriate type. May assume p is non-null Chris@16: // Chris@16: // * X::check(p) Chris@16: // convertible to bool. True iff T(X::construct(p)) will not Chris@16: // throw. Chris@16: Chris@16: // Forward declarations Chris@16: // Chris@16: namespace boost { namespace python Chris@16: { Chris@16: namespace api Chris@16: { Chris@16: class object; Chris@16: } Chris@16: }} Chris@16: Chris@16: namespace boost { namespace python { namespace converter { Chris@16: Chris@16: Chris@16: // Specializations for handle Chris@16: template Chris@16: struct handle_object_manager_traits Chris@16: : pyobject_traits Chris@16: { Chris@16: private: Chris@16: typedef pyobject_traits base; Chris@16: Chris@16: public: Chris@16: BOOST_STATIC_CONSTANT(bool, is_specialized = true); Chris@16: Chris@16: // Initialize with a null_ok pointer for efficiency, bypassing the Chris@16: // null check since the source is always non-null. Chris@16: static null_ok* adopt(PyObject* p) Chris@16: { Chris@16: return python::allow_null(base::checked_downcast(p)); Chris@16: } Chris@16: }; Chris@16: Chris@16: template Chris@16: struct default_object_manager_traits Chris@16: { Chris@16: BOOST_STATIC_CONSTANT( Chris@16: bool, is_specialized = python::detail::is_borrowed_ptr::value Chris@16: ); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct object_manager_traits Chris@16: : mpl::if_c< Chris@16: is_handle::value Chris@16: , handle_object_manager_traits Chris@16: , default_object_manager_traits Chris@16: >::type Chris@16: { Chris@16: }; Chris@16: Chris@16: // Chris@16: // Traits for detecting whether a type is an object manager or a Chris@16: // (cv-qualified) reference to an object manager. Chris@16: // Chris@16: Chris@16: template Chris@16: struct is_object_manager Chris@16: : mpl::bool_::is_specialized> Chris@16: { Chris@16: }; Chris@16: Chris@16: # ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION Chris@16: template Chris@16: struct is_reference_to_object_manager Chris@16: : mpl::false_ Chris@16: { Chris@16: }; Chris@16: Chris@16: template Chris@16: struct is_reference_to_object_manager Chris@16: : is_object_manager Chris@16: { Chris@16: }; Chris@16: Chris@16: template Chris@16: struct is_reference_to_object_manager Chris@16: : is_object_manager Chris@16: { Chris@16: }; Chris@16: Chris@16: template Chris@16: struct is_reference_to_object_manager Chris@16: : is_object_manager Chris@16: { Chris@16: }; Chris@16: Chris@16: template Chris@16: struct is_reference_to_object_manager Chris@16: : is_object_manager Chris@16: { Chris@16: }; Chris@16: # else Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: typedef char (&yes_reference_to_object_manager)[1]; Chris@16: typedef char (&no_reference_to_object_manager)[2]; Chris@16: Chris@16: // A number of nastinesses go on here in order to work around MSVC6 Chris@16: // bugs. Chris@16: template Chris@16: struct is_object_manager_help Chris@16: { Chris@16: typedef typename mpl::if_< Chris@16: is_object_manager Chris@16: , yes_reference_to_object_manager Chris@16: , no_reference_to_object_manager Chris@16: >::type type; Chris@16: Chris@16: // If we just use the type instead of the result of calling this Chris@16: // function, VC6 will ICE. Chris@16: static type call(); Chris@16: }; Chris@16: Chris@16: // A set of overloads for each cv-qualification. The same argument Chris@16: // is passed twice: the first one is used to unwind the cv*, and the Chris@16: // second one is used to avoid relying on partial ordering for Chris@16: // overload resolution. Chris@16: template Chris@16: typename is_object_manager_help Chris@16: is_object_manager_helper(U*, void*); Chris@16: Chris@16: template Chris@16: typename is_object_manager_help Chris@16: is_object_manager_helper(U const*, void const*); Chris@16: Chris@16: template Chris@16: typename is_object_manager_help Chris@16: is_object_manager_helper(U volatile*, void volatile*); Chris@16: Chris@16: template Chris@16: typename is_object_manager_help Chris@16: is_object_manager_helper(U const volatile*, void const volatile*); Chris@16: Chris@16: template Chris@16: struct is_reference_to_object_manager_nonref Chris@16: : mpl::false_ Chris@16: { Chris@16: }; Chris@16: Chris@16: template Chris@16: struct is_reference_to_object_manager_ref Chris@16: { Chris@16: static T sample_object; Chris@16: BOOST_STATIC_CONSTANT( Chris@16: bool, value Chris@16: = (sizeof(is_object_manager_helper(&sample_object, &sample_object).call()) Chris@16: == sizeof(detail::yes_reference_to_object_manager) Chris@16: ) Chris@16: ); Chris@16: typedef mpl::bool_ type; Chris@16: }; Chris@16: } Chris@16: Chris@16: template Chris@16: struct is_reference_to_object_manager Chris@16: : mpl::if_< Chris@16: is_reference Chris@16: , detail::is_reference_to_object_manager_ref Chris@16: , detail::is_reference_to_object_manager_nonref Chris@16: >::type Chris@16: { Chris@16: }; Chris@16: # endif Chris@16: Chris@16: }}} // namespace boost::python::converter Chris@16: Chris@16: #endif // OBJECT_MANAGER_DWA2002614_HPP