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