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