// 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 |