484 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			484 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | // 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> | ||
|  | 
 | ||
|  | 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: | ||
|  |       typedef object const& object_cref; | ||
|  |    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; | ||
|  |      | ||
|  |       template <class T> | ||
|  |       object_item | ||
|  |       operator[](T const& key); | ||
|  | 
 | ||
|  |       // 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; | ||
|  |      | ||
|  |       template <class T, class V> | ||
|  |       object_slice | ||
|  |       slice(T const& start, V const& end); | ||
|  |        | ||
|  |    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; | ||
|  |   }; | ||
|  | 
 | ||
|  |   template <class T, class U> | ||
|  |   struct is_derived | ||
|  |     : is_convertible< | ||
|  |           typename remove_reference<T>::type* | ||
|  |         , U const* | ||
|  |       > | ||
|  |   {}; | ||
|  | 
 | ||
|  |   template <class T> | ||
|  |   typename objects::unforward_cref<T>::type do_unforward_cref(T const& x) | ||
|  |   { | ||
|  |       return x; | ||
|  |   } | ||
|  | 
 | ||
|  |   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) | ||
|  |         : 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) {} | ||
|  | 
 | ||
|  |   // | ||
|  |   // 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() | ||
|  | { | ||
|  |     assert( Py_REFCNT(m_ptr) > 0 ); | ||
|  |     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 |