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