// 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_CORE_DWA2002615_HPP | |
# define OBJECT_CORE_DWA2002615_HPP | |
# define BOOST_PYTHON_OBJECT_HAS_IS_NONE // added 2010-03-15 by rwgk | |
# include <boost/python/detail/prefix.hpp> | |
# include <boost/type.hpp> | |
# include <boost/python/call.hpp> | |
# include <boost/python/handle_fwd.hpp> | |
# include <boost/python/errors.hpp> | |
# include <boost/python/refcount.hpp> | |
# include <boost/python/detail/preprocessor.hpp> | |
# include <boost/python/tag.hpp> | |
# include <boost/python/def_visitor.hpp> | |
# include <boost/python/detail/raw_pyobject.hpp> | |
# include <boost/python/detail/dependent.hpp> | |
# include <boost/python/object/forward.hpp> | |
# include <boost/python/object/add_to_namespace.hpp> | |
# include <boost/preprocessor/iterate.hpp> | |
# include <boost/preprocessor/debug/line.hpp> | |
# include <boost/python/detail/is_xxx.hpp> | |
# include <boost/python/detail/string_literal.hpp> | |
# include <boost/python/detail/def_helper_fwd.hpp> | |
# include <boost/type_traits/is_same.hpp> | |
# include <boost/type_traits/is_convertible.hpp> | |
# include <boost/type_traits/remove_reference.hpp> | |
# if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) | |
# include <boost/type_traits/add_pointer.hpp> | |
# endif | |
# include <boost/mpl/if.hpp> | |
namespace boost { namespace python { | |
namespace detail | |
{ | |
class kwds_proxy; | |
class args_proxy; | |
} | |
namespace converter | |
{ | |
template <class T> struct arg_to_python; | |
} | |
// Put this in an inner namespace so that the generalized operators won't take over | |
namespace api | |
{ | |
// This file contains the definition of the object class and enough to | |
// construct/copy it, but not enough to do operations like | |
// attribute/item access or addition. | |
template <class Policies> class proxy; | |
struct const_attribute_policies; | |
struct attribute_policies; | |
struct const_objattribute_policies; | |
struct objattribute_policies; | |
struct const_item_policies; | |
struct item_policies; | |
struct const_slice_policies; | |
struct slice_policies; | |
class slice_nil; | |
typedef proxy<const_attribute_policies> const_object_attribute; | |
typedef proxy<attribute_policies> object_attribute; | |
typedef proxy<const_objattribute_policies> const_object_objattribute; | |
typedef proxy<objattribute_policies> object_objattribute; | |
typedef proxy<const_item_policies> const_object_item; | |
typedef proxy<item_policies> object_item; | |
typedef proxy<const_slice_policies> const_object_slice; | |
typedef proxy<slice_policies> object_slice; | |
// | |
// is_proxy -- proxy type detection | |
// | |
BOOST_PYTHON_IS_XXX_DEF(proxy, boost::python::api::proxy, 1) | |
template <class T> struct object_initializer; | |
class object; | |
typedef PyObject* (object::*bool_type)() const; | |
template <class U> | |
class object_operators : public def_visitor<U> | |
{ | |
protected: | |
# if !defined(BOOST_MSVC) || BOOST_MSVC >= 1300 | |
typedef object const& object_cref; | |
# else | |
typedef object object_cref; | |
# endif | |
public: | |
// function call | |
// | |
object operator()() const; | |
# define BOOST_PP_ITERATION_PARAMS_1 (3, (1, BOOST_PYTHON_MAX_ARITY, <boost/python/object_call.hpp>)) | |
# include BOOST_PP_ITERATE() | |
detail::args_proxy operator* () const; | |
object operator()(detail::args_proxy const &args) const; | |
object operator()(detail::args_proxy const &args, | |
detail::kwds_proxy const &kwds) const; | |
// truth value testing | |
// | |
operator bool_type() const; | |
bool operator!() const; // needed for vc6 | |
// Attribute access | |
// | |
const_object_attribute attr(char const*) const; | |
object_attribute attr(char const*); | |
const_object_objattribute attr(object const&) const; | |
object_objattribute attr(object const&); | |
// Wrap 'in' operator (aka. __contains__) | |
template <class T> | |
object contains(T const& key) const; | |
// item access | |
// | |
const_object_item operator[](object_cref) const; | |
object_item operator[](object_cref); | |
template <class T> | |
const_object_item | |
operator[](T const& key) const | |
# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 | |
; | |
# else | |
{ | |
return (*this)[object(key)]; | |
} | |
# endif | |
template <class T> | |
object_item | |
operator[](T const& key) | |
# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 | |
; | |
# else | |
{ | |
return (*this)[object(key)]; | |
} | |
# endif | |
// slicing | |
// | |
const_object_slice slice(object_cref, object_cref) const; | |
object_slice slice(object_cref, object_cref); | |
const_object_slice slice(slice_nil, object_cref) const; | |
object_slice slice(slice_nil, object_cref); | |
const_object_slice slice(object_cref, slice_nil) const; | |
object_slice slice(object_cref, slice_nil); | |
const_object_slice slice(slice_nil, slice_nil) const; | |
object_slice slice(slice_nil, slice_nil); | |
template <class T, class V> | |
const_object_slice | |
slice(T const& start, V const& end) const | |
# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 | |
; | |
# else | |
{ | |
return this->slice( | |
slice_bound<T>::type(start) | |
, slice_bound<V>::type(end)); | |
} | |
# endif | |
template <class T, class V> | |
object_slice | |
slice(T const& start, V const& end) | |
# if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 | |
; | |
# else | |
{ | |
return this->slice( | |
slice_bound<T>::type(start) | |
, slice_bound<V>::type(end)); | |
} | |
# endif | |
private: // def visitation for adding callable objects as class methods | |
template <class ClassT, class DocStringT> | |
void visit(ClassT& cl, char const* name, python::detail::def_helper<DocStringT> const& helper) const | |
{ | |
// It's too late to specify anything other than docstrings if | |
// the callable object is already wrapped. | |
BOOST_STATIC_ASSERT( | |
(is_same<char const*,DocStringT>::value | |
|| detail::is_string_literal<DocStringT const>::value)); | |
objects::add_to_namespace(cl, name, this->derived_visitor(), helper.doc()); | |
} | |
friend class python::def_visitor_access; | |
private: | |
// there is a confirmed CWPro8 codegen bug here. We prevent the | |
// early destruction of a temporary by binding a named object | |
// instead. | |
# if __MWERKS__ < 0x3000 || __MWERKS__ > 0x3003 | |
typedef object const& object_cref2; | |
# else | |
typedef object const object_cref2; | |
# endif | |
}; | |
// VC6 and VC7 require this base class in order to generate the | |
// correct copy constructor for object. We can't define it there | |
// explicitly or it will complain of ambiguity. | |
struct object_base : object_operators<object> | |
{ | |
// copy constructor without NULL checking, for efficiency. | |
inline object_base(object_base const&); | |
inline object_base(PyObject* ptr); | |
inline object_base& operator=(object_base const& rhs); | |
inline ~object_base(); | |
// Underlying object access -- returns a borrowed reference | |
inline PyObject* ptr() const; | |
inline bool is_none() const; | |
private: | |
PyObject* m_ptr; | |
}; | |
# ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION | |
template <class T, class U> | |
struct is_derived_impl | |
{ | |
static T x; | |
template <class X> | |
static X* to_pointer(X const&); | |
static char test(U const*); | |
typedef char (&no)[2]; | |
static no test(...); | |
BOOST_STATIC_CONSTANT(bool, value = sizeof(test(to_pointer(x))) == 1); | |
}; | |
template <class T, class U> | |
struct is_derived | |
: mpl::bool_<is_derived_impl<T,U>::value> | |
{}; | |
# else | |
template <class T, class U> | |
struct is_derived | |
: is_convertible< | |
typename remove_reference<T>::type* | |
, U const* | |
> | |
{}; | |
# endif | |
template <class T> | |
typename objects::unforward_cref<T>::type do_unforward_cref(T const& x) | |
{ | |
# if BOOST_WORKAROUND(__GNUC__, == 2) | |
typedef typename objects::unforward_cref<T>::type ret; | |
return ret(x); | |
# else | |
return x; | |
# endif | |
} | |
# if BOOST_WORKAROUND(__GNUC__, == 2) | |
// GCC 2.x has non-const string literals; this hacks around that problem. | |
template <unsigned N> | |
char const (& do_unforward_cref(char const(&x)[N]) )[N] | |
{ | |
return x; | |
} | |
# endif | |
class object; | |
template <class T> | |
PyObject* object_base_initializer(T const& x) | |
{ | |
typedef typename is_derived< | |
BOOST_DEDUCED_TYPENAME objects::unforward_cref<T>::type | |
, object | |
>::type is_obj; | |
return object_initializer< | |
BOOST_DEDUCED_TYPENAME unwrap_reference<T>::type | |
>::get( | |
x | |
, is_obj() | |
); | |
} | |
class object : public object_base | |
{ | |
public: | |
// default constructor creates a None object | |
object(); | |
// explicit conversion from any C++ object to Python | |
template <class T> | |
explicit object( | |
T const& x | |
# if BOOST_WORKAROUND(BOOST_MSVC, < 1300) | |
// use some SFINAE to un-confuse MSVC about its | |
// copy-initialization ambiguity claim. | |
, typename mpl::if_<is_proxy<T>,int&,int>::type* = 0 | |
# endif | |
) | |
: object_base(object_base_initializer(x)) | |
{ | |
} | |
// Throw error_already_set() if the handle is null. | |
BOOST_PYTHON_DECL explicit object(handle<> const&); | |
private: | |
public: // implementation detail -- for internal use only | |
explicit object(detail::borrowed_reference); | |
explicit object(detail::new_reference); | |
explicit object(detail::new_non_null_reference); | |
}; | |
// Macros for forwarding constructors in classes derived from | |
// object. Derived classes will usually want these as an | |
// implementation detail | |
# define BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS_(derived, base) \ | |
inline explicit derived(python::detail::borrowed_reference p) \ | |
: base(p) {} \ | |
inline explicit derived(python::detail::new_reference p) \ | |
: base(p) {} \ | |
inline explicit derived(python::detail::new_non_null_reference p) \ | |
: base(p) {} | |
# if !defined(BOOST_MSVC) || BOOST_MSVC >= 1300 | |
# define BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS_ | |
# else | |
// MSVC6 has a bug which causes an explicit template constructor to | |
// be preferred over an appropriate implicit conversion operator | |
// declared on the argument type. Normally, that would cause a | |
// runtime failure when using extract<T> to extract a type with a | |
// templated constructor. This additional constructor will turn that | |
// runtime failure into an ambiguity error at compile-time due to | |
// the lack of partial ordering, or at least a link-time error if no | |
// generalized template constructor is declared. | |
# define BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(derived, base) \ | |
BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS_(derived, base) \ | |
template <class T> \ | |
explicit derived(extract<T> const&); | |
# endif | |
// | |
// object_initializer -- get the handle to construct the object with, | |
// based on whether T is a proxy or derived from object | |
// | |
template <bool is_proxy = false, bool is_object_manager = false> | |
struct object_initializer_impl | |
{ | |
static PyObject* | |
get(object const& x, mpl::true_) | |
{ | |
return python::incref(x.ptr()); | |
} | |
template <class T> | |
static PyObject* | |
get(T const& x, mpl::false_) | |
{ | |
return python::incref(converter::arg_to_python<T>(x).get()); | |
} | |
}; | |
template <> | |
struct object_initializer_impl<true, false> | |
{ | |
template <class Policies> | |
static PyObject* | |
get(proxy<Policies> const& x, mpl::false_) | |
{ | |
return python::incref(x.operator object().ptr()); | |
} | |
}; | |
template <> | |
struct object_initializer_impl<false, true> | |
{ | |
template <class T, class U> | |
static PyObject* | |
get(T const& x, U) | |
{ | |
return python::incref(get_managed_object(x, boost::python::tag)); | |
} | |
}; | |
template <> | |
struct object_initializer_impl<true, true> | |
{}; // empty implementation should cause an error | |
template <class T> | |
struct object_initializer : object_initializer_impl< | |
is_proxy<T>::value | |
, converter::is_object_manager<T>::value | |
> | |
{}; | |
} | |
using api::object; | |
template <class T> struct extract; | |
// | |
// implementation | |
// | |
namespace detail | |
{ | |
class call_proxy | |
{ | |
public: | |
call_proxy(object target) : m_target(target) {} | |
operator object() const { return m_target;} | |
private: | |
object m_target; | |
}; | |
class kwds_proxy : public call_proxy | |
{ | |
public: | |
kwds_proxy(object o = object()) : call_proxy(o) {} | |
}; | |
class args_proxy : public call_proxy | |
{ | |
public: | |
args_proxy(object o) : call_proxy(o) {} | |
kwds_proxy operator* () const { return kwds_proxy(*this);} | |
}; | |
} | |
template <typename U> | |
detail::args_proxy api::object_operators<U>::operator* () const | |
{ | |
object_cref2 x = *static_cast<U const*>(this); | |
return boost::python::detail::args_proxy(x); | |
} | |
template <typename U> | |
object api::object_operators<U>::operator()(detail::args_proxy const &args) const | |
{ | |
U const& self = *static_cast<U const*>(this); | |
PyObject *result = PyObject_Call(get_managed_object(self, boost::python::tag), | |
args.operator object().ptr(), | |
0); | |
return object(boost::python::detail::new_reference(result)); | |
} | |
template <typename U> | |
object api::object_operators<U>::operator()(detail::args_proxy const &args, | |
detail::kwds_proxy const &kwds) const | |
{ | |
U const& self = *static_cast<U const*>(this); | |
PyObject *result = PyObject_Call(get_managed_object(self, boost::python::tag), | |
args.operator object().ptr(), | |
kwds.operator object().ptr()); | |
return object(boost::python::detail::new_reference(result)); | |
} | |
template <typename U> | |
template <class T> | |
object api::object_operators<U>::contains(T const& key) const | |
{ | |
return this->attr("__contains__")(object(key)); | |
} | |
inline object::object() | |
: object_base(python::incref(Py_None)) | |
{} | |
// copy constructor without NULL checking, for efficiency | |
inline api::object_base::object_base(object_base const& rhs) | |
: m_ptr(python::incref(rhs.m_ptr)) | |
{} | |
inline api::object_base::object_base(PyObject* p) | |
: m_ptr(p) | |
{} | |
inline api::object_base& api::object_base::operator=(api::object_base const& rhs) | |
{ | |
Py_INCREF(rhs.m_ptr); | |
Py_DECREF(this->m_ptr); | |
this->m_ptr = rhs.m_ptr; | |
return *this; | |
} | |
inline api::object_base::~object_base() | |
{ | |
Py_DECREF(m_ptr); | |
} | |
inline object::object(detail::borrowed_reference p) | |
: object_base(python::incref((PyObject*)p)) | |
{} | |
inline object::object(detail::new_reference p) | |
: object_base(expect_non_null((PyObject*)p)) | |
{} | |
inline object::object(detail::new_non_null_reference p) | |
: object_base((PyObject*)p) | |
{} | |
inline PyObject* api::object_base::ptr() const | |
{ | |
return m_ptr; | |
} | |
inline bool api::object_base::is_none() const | |
{ | |
return (m_ptr == Py_None); | |
} | |
// | |
// Converter specialization implementations | |
// | |
namespace converter | |
{ | |
template <class T> struct object_manager_traits; | |
template <> | |
struct object_manager_traits<object> | |
{ | |
BOOST_STATIC_CONSTANT(bool, is_specialized = true); | |
static bool check(PyObject*) { return true; } | |
static python::detail::new_non_null_reference adopt(PyObject* x) | |
{ | |
return python::detail::new_non_null_reference(x); | |
} | |
#ifndef BOOST_PYTHON_NO_PY_SIGNATURES | |
static PyTypeObject const *get_pytype() {return 0;} | |
#endif | |
}; | |
} | |
inline PyObject* get_managed_object(object const& x, tag_t) | |
{ | |
return x.ptr(); | |
} | |
}} // namespace boost::python | |
# include <boost/python/slice_nil.hpp> | |
#endif // OBJECT_CORE_DWA2002615_HPP |