584 lines
16 KiB
C++
584 lines
16 KiB
C++
// 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(::boost::python::detail::borrowed_reference p) \
|
|
: base(p) {} \
|
|
inline explicit derived(::boost::python::detail::new_reference p) \
|
|
: base(p) {} \
|
|
inline explicit derived(::boost::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
|