diff --git a/include/boost/python/converter/always_extract_object_manager.hpp b/include/boost/python/converter/always_extract_object_manager.hpp new file mode 100644 index 00000000..02f18143 --- /dev/null +++ b/include/boost/python/converter/always_extract_object_manager.hpp @@ -0,0 +1,35 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef ALWAYS_EXTRACT_OBJECT_MANAGER_DWA2002716_HPP +# define ALWAYS_EXTRACT_OBJECT_MANAGER_DWA2002716_HPP + +# include + +namespace boost { namespace python { namespace converter { + +// Derive specializations of extract_object_manager from this when the +// object manager is indiscriminate about the Python objects it manages +struct always_extract_object_manager +{ + BOOST_STATIC_CONSTANT(bool, is_specialized = true); + static inline bool check(PyObject* x); +}; + +// Provide a forward declaration as a convenience for clients, who all +// need it. +template struct extract_object_manager; + +// +// implementations +// +inline bool always_extract_object_manager::check(PyObject* x) +{ + return true; +} + +}}} // namespace boost::python::converter + +#endif // ALWAYS_EXTRACT_OBJECT_MANAGER_DWA2002716_HPP diff --git a/include/boost/python/converter/arg_from_python.hpp b/include/boost/python/converter/arg_from_python.hpp index 7bca5040..289b4945 100755 --- a/include/boost/python/converter/arg_from_python.hpp +++ b/include/boost/python/converter/arg_from_python.hpp @@ -19,6 +19,7 @@ # include # include # include +# include namespace boost { namespace python { @@ -139,6 +140,12 @@ struct back_reference_arg_from_python template struct select_arg_from_python { + BOOST_STATIC_CONSTANT( + bool, obj_mgr = is_object_manager::value); + + BOOST_STATIC_CONSTANT( + bool, obj_mgr_ref = is_reference_to_object_manager::value); + BOOST_STATIC_CONSTANT( bool, ptr = is_pointer::value); @@ -159,22 +166,30 @@ struct select_arg_from_python boost::python::is_back_reference::value); typedef typename mpl::select_type< - ptr - , pointer_arg_from_python - , typename mpl::select_type< - ptr_cref - , pointer_cref_arg_from_python - , typename mpl::select_type< - ref - , reference_arg_from_python - , typename mpl::select_type< - back_ref - , back_reference_arg_from_python - , arg_rvalue_from_python - >::type - >::type + obj_mgr + , object_manager_value_arg_from_python + , mpl::select_type< + obj_mgr_ref + , object_manager_ref_arg_from_python + , mpl::select_type< + ptr + , pointer_arg_from_python + , typename mpl::select_type< + ptr_cref + , pointer_cref_arg_from_python + , typename mpl::select_type< + ref + , reference_arg_from_python + , typename mpl::select_type< + back_ref + , back_reference_arg_from_python + , arg_rvalue_from_python + >::type + >::type + >::type + >::type >::type - >::type type; + >::type type; }; // ================== diff --git a/include/boost/python/converter/obj_mgr_arg_from_python.hpp b/include/boost/python/converter/obj_mgr_arg_from_python.hpp new file mode 100644 index 00000000..58cf85e4 --- /dev/null +++ b/include/boost/python/converter/obj_mgr_arg_from_python.hpp @@ -0,0 +1,105 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef OBJ_MGR_ARG_FROM_PYTHON_DWA2002628_HPP +# define OBJ_MGR_ARG_FROM_PYTHON_DWA2002628_HPP + +# include +# include +# include +# include +# include + +// +// arg_from_python converters for Python type wrappers, to be used as +// base classes for specializations. +// +namespace boost { namespace python { namespace converter { + +template +struct object_manager_value_arg_from_python +{ + typedef T result_type; + + object_manager_value_arg_from_python(PyObject*); + bool convertible() const; + T operator()(PyObject*) const; + private: + PyObject* m_source; +}; + +template +struct object_manager_ref_arg_from_python +{ + typedef Ref result_type; + + object_manager_ref_arg_from_python(PyObject*); + bool convertible() const; + Ref operator()(PyObject*) const; + ~object_manager_ref_arg_from_python(); + private: + typename python::detail::referent_storage::type m_result; +}; + +// +// implementations +// + +template +inline object_manager_value_arg_from_python::object_manager_value_arg_from_python(PyObject* x) + : m_source(x) +{ +} + +template +inline bool object_manager_value_arg_from_python::convertible() const +{ + return extract_object_manager::check(m_source); +} + +template +inline T object_manager_value_arg_from_python::operator()(PyObject* x) const +{ + return T(python::detail::borrowed_reference(x)); +} + +template +inline object_manager_ref_arg_from_python::object_manager_ref_arg_from_python(PyObject* x) +{ + python::detail::construct_referent(&m_result.bytes, python::detail::borrowed_reference(x)); +} + +template +inline object_manager_ref_arg_from_python::~object_manager_ref_arg_from_python() +{ + python::detail::destroy_referent(this->m_result.bytes); +} + +namespace detail +{ + template + inline bool object_manager_ref_check(T const& x) + { + return extract_object_manager::check((get_managed_object)(x)); + } +} + +template +inline bool object_manager_ref_arg_from_python::convertible() const +{ + return detail::object_manager_ref_check( + python::detail::void_ptr_to_reference(this->m_result.bytes, (Ref(*)())0)); +} + +template +inline Ref object_manager_ref_arg_from_python::operator()(PyObject*) const +{ + return python::detail::void_ptr_to_reference( + this->m_result.bytes, (Ref(*)())0); +} + +}}} // namespace boost::python::converter + +#endif // OBJ_MGR_ARG_FROM_PYTHON_DWA2002628_HPP diff --git a/include/boost/python/converter/object_manager.hpp b/include/boost/python/converter/object_manager.hpp index 23e70a1e..ac0ceb02 100755 --- a/include/boost/python/converter/object_manager.hpp +++ b/include/boost/python/converter/object_manager.hpp @@ -12,22 +12,55 @@ # include # include -namespace boost { namespace python { namespace api { - -class object; +// Facilities for dealing with types which always manage Python +// objects. Some examples are object, list, et. al. Different +// to_python/from_python conversion rules apply here because in +// contrast to other types which are typically embedded inside a +// Python object, these are wrapped around a Python object. For most +// object managers T, a C++ non-const T reference argument does not +// imply the existence of a T lvalue embedded in the corresponding +// Python argument, since mutating member functions on T actually only +// modify the held Python object. +// +// Note also that handle<> does not qualify as an object manager because: +// a. It might not manage a Python object (it can be null) +// b. Mutating operations visible to users modify the handle<> itself. +namespace boost { namespace python { namespace api +{ + class object; // forward declaration }}} namespace boost { namespace python { namespace converter { +// Used to create object managers of type T, taking ownership of a +// given PyObject*. Specializations X must satisfy the following, +// where p is a non-null PyObject*: +// +// X::is_specialized == true +// +// T(X::execute(p)) - constructs a T object from p, or throws a +// TypeError exception if p doesn't have an appropriate type. +// +// X::check(p), convertible to bool. True iff T(X::execute(p)) will +// not throw. +template +struct extract_object_manager +{ + BOOST_STATIC_CONSTANT(bool, is_specialized = false); +}; + +// A metafunction returning true iff its argument is an object manager. template struct is_object_manager { private: + // handle the cases that would otherwise require partial specialization BOOST_STATIC_CONSTANT(bool, hdl = is_handle::value); BOOST_STATIC_CONSTANT(bool, borrowed = python::detail::is_borrowed_ptr::value); + BOOST_STATIC_CONSTANT(bool, extract_specialized = extract_object_manager::is_specialized); public: - BOOST_STATIC_CONSTANT(bool, value = (hdl | borrowed)); + BOOST_STATIC_CONSTANT(bool, value = (hdl | borrowed | extract_specialized)); }; # ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION diff --git a/include/boost/python/converter/pytype_extract_object_manager.hpp b/include/boost/python/converter/pytype_extract_object_manager.hpp new file mode 100644 index 00000000..cd4cadc9 --- /dev/null +++ b/include/boost/python/converter/pytype_extract_object_manager.hpp @@ -0,0 +1,48 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef PYTYPE_EXTRACT_OBJECT_MANAGER_DWA2002716_HPP +# define PYTYPE_EXTRACT_OBJECT_MANAGER_DWA2002716_HPP + +# include +# include +# include +# include + +namespace boost { namespace python { namespace converter { + +// Provide a forward declaration as a convenience for clients, who all +// need it. +template struct extract_object_manager; + +// Derive specializations of extract_object_manager from this class +// when T is an object manager for a particular Python type hierarchy. +// +template +struct pytype_extract_object_manager +{ + BOOST_STATIC_CONSTANT(bool, is_specialized = true); + static inline python::detail::new_reference execute(PyObject*); + static inline bool check(PyObject* x); +}; + +// +// implementations +// +template +inline python::detail::new_reference pytype_extract_object_manager::execute(PyObject* x) +{ + return pytype_result_from_python(pytype, x); +} + +template +inline bool pytype_extract_object_manager::check(PyObject* x) +{ + return ::PyObject_IsInstance(x, python::upcast(pytype)); +} + +}}} // namespace boost::python::converter + +#endif // PYTYPE_EXTRACT_OBJECT_MANAGER_DWA2002716_HPP diff --git a/include/boost/python/converter/return_from_python.hpp b/include/boost/python/converter/return_from_python.hpp index 8cdaf81d..1f2d74cf 100755 --- a/include/boost/python/converter/return_from_python.hpp +++ b/include/boost/python/converter/return_from_python.hpp @@ -6,6 +6,7 @@ #ifndef RETURN_FROM_PYTHON_DWA200265_HPP # define RETURN_FROM_PYTHON_DWA200265_HPP +# include # include # include # include @@ -42,9 +43,19 @@ namespace detail rvalue_from_python_data m_data; }; + template + struct return_object_manager_from_python + { + typedef T result_type; + result_type operator()(PyObject*) const; + }; + template struct select_return_from_python { + BOOST_STATIC_CONSTANT( + bool, obj_mgr = is_object_manager::value); + BOOST_STATIC_CONSTANT( bool, ptr = is_pointer::value); @@ -52,14 +63,18 @@ namespace detail bool, ref = is_reference::value); typedef typename mpl::select_type< - ptr - , return_pointer_from_python + obj_mgr + , return_object_manager_from_python , typename mpl::select_type< - ref - , return_reference_from_python - , return_rvalue_from_python + ptr + , return_pointer_from_python + , typename mpl::select_type< + ref + , return_reference_from_python + , return_rvalue_from_python + >::type >::type - >::type type; + >::type type; }; } @@ -120,6 +135,14 @@ namespace detail (pointer_result_from_python)(obj, registered_pointee::converters) ); } + + template + inline T return_object_manager_from_python::operator()(PyObject* obj) const + { + return T( + extract_object_manager::execute(obj) + ); + } } }}} // namespace boost::python::converter diff --git a/include/boost/python/detail/construct.hpp b/include/boost/python/detail/construct.hpp new file mode 100644 index 00000000..55c0873f --- /dev/null +++ b/include/boost/python/detail/construct.hpp @@ -0,0 +1,37 @@ +// Copyright David Abrahams 2002. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +#ifndef CONSTRUCT_REFERENCE_DWA2002716_HPP +# define CONSTRUCT_REFERENCE_DWA2002716_HPP + +namespace boost { namespace python { namespace detail { + +template +void construct_pointee(void* storage, Arg& x, T const volatile*) +{ + new (storage) T(x); +} + +template +void construct_referent_impl(void* storage, Arg& x, T&(*)()) +{ + construct_pointee(storage, x, (T*)0); +} + +template +void construct_referent(void* storage, Arg const& x, T(*tag)() = 0) +{ + construct_referent_impl(storage, x, tag); +} + +template +void construct_referent(void* storage, Arg& x, T(*tag)() = 0) +{ + construct_referent_impl(storage, x, tag); +} + +}}} // namespace boost::python::detail + +#endif // CONSTRUCT_REFERENCE_DWA2002716_HPP diff --git a/include/boost/python/detail/raw_pyobject.hpp b/include/boost/python/detail/raw_pyobject.hpp index 5d87da56..e9d36901 100644 --- a/include/boost/python/detail/raw_pyobject.hpp +++ b/include/boost/python/detail/raw_pyobject.hpp @@ -16,7 +16,7 @@ namespace boost { namespace python { namespace detail { // friendship to all the appropriate parties. // -// New references are checked for null +// New references are normally checked for null struct new_reference_t; typedef new_reference_t* new_reference; @@ -24,6 +24,10 @@ typedef new_reference_t* new_reference; struct borrowed_reference_t; typedef borrowed_reference_t* borrowed_reference; +// New references which aren't checked for null +struct new_non_null_reference_t; +typedef new_non_null_reference_t* new_non_null_reference; + }}} // namespace boost::python::detail #endif // RAW_PYOBJECT_DWA2002628_HPP diff --git a/include/boost/python/list.hpp b/include/boost/python/list.hpp index b7948b04..63ee469b 100644 --- a/include/boost/python/list.hpp +++ b/include/boost/python/list.hpp @@ -7,8 +7,7 @@ # define LIST_DWA2002627_HPP # include -# include -# include +# include namespace boost { namespace python { @@ -95,81 +94,24 @@ class list : public object } public: // implementation detail -- for internal use only - inline explicit list(detail::borrowed_reference); - inline explicit list(detail::new_reference); + BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(list) private: - static BOOST_PYTHON_DECL detail::new_reference call(object const&); + static BOOST_PYTHON_DECL detail::new_non_null_reference call(object const&); }; // // Converter Specializations // -template struct arg_from_python; - -template <> -struct arg_from_python - : converter::pytype_wrapper_value_arg_from_python -{ - typedef converter::pytype_wrapper_value_arg_from_python base; - typedef list result_type; - - arg_from_python(PyObject* p) : base(p) {} -}; - -template <> -struct arg_from_python - : arg_from_python -{ - arg_from_python(PyObject* p) - : arg_from_python(p) {} -}; - -template <> -struct arg_from_python - : converter::pytype_wrapper_ref_arg_from_python -{ - typedef converter::pytype_wrapper_ref_arg_from_python base; - typedef list result_type; - - arg_from_python(PyObject* p) - : base(p) {} -}; - namespace converter { - template struct is_object_manager; - template <> - struct is_object_manager + struct extract_object_manager + : pytype_extract_object_manager<&PyList_Type,list> { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template struct return_from_python; - template <> - struct return_from_python - { - typedef list result_type; - - result_type operator()(PyObject* x) const - { - return list((pytype_result_from_python)(&PyList_Type, x)); - } }; } -// -// list implementation -// -inline list::list(detail::borrowed_reference p) - : object(p) -{} - -inline list::list(detail::new_reference p) - : object(p) -{} - }} // namespace boost::python #endif // LIST_DWA2002627_HPP diff --git a/include/boost/python/long.hpp b/include/boost/python/long.hpp index 1b47728e..0f1fcdf6 100644 --- a/include/boost/python/long.hpp +++ b/include/boost/python/long.hpp @@ -7,8 +7,7 @@ # define LONG_DWA2002627_HPP # include -# include -# include +# include namespace boost { namespace python { @@ -32,82 +31,25 @@ class long_ : public object { } public: // implementation detail -- for internal use only - explicit inline long_(detail::borrowed_reference); - explicit inline long_(detail::new_reference); + BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(long_) private: - static BOOST_PYTHON_DECL detail::new_reference call(object const&); - static BOOST_PYTHON_DECL detail::new_reference call(object const&, object const&); + static BOOST_PYTHON_DECL detail::new_non_null_reference call(object const&); + static BOOST_PYTHON_DECL detail::new_non_null_reference call(object const&, object const&); }; // // Converter Specializations // -template struct arg_from_python; - -template <> -struct arg_from_python - : converter::pytype_wrapper_value_arg_from_python -{ - typedef converter::pytype_wrapper_value_arg_from_python base; - typedef long_ result_type; - - arg_from_python(PyObject* p) : base(p) {} -}; - -template <> -struct arg_from_python - : arg_from_python -{ - arg_from_python(PyObject* p) - : arg_from_python(p) {} -}; - -template <> -struct arg_from_python - : converter::pytype_wrapper_ref_arg_from_python -{ - typedef converter::pytype_wrapper_ref_arg_from_python base; - typedef long_ result_type; - - arg_from_python(PyObject* p) - : base(p) {} -}; - namespace converter { - template struct is_object_manager; - template <> - struct is_object_manager + struct extract_object_manager + : pytype_extract_object_manager<&PyLong_Type,long_> { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template struct return_from_python; - template <> - struct return_from_python - { - typedef long_ result_type; - - result_type operator()(PyObject* x) const - { - return long_((pytype_result_from_python)(&PyLong_Type, x)); - } }; } -// -// long_ implementation -// -inline long_::long_(detail::borrowed_reference p) - : object(p) -{} - -inline long_::long_(detail::new_reference p) - : object(p) -{} - }} // namespace boost::python #endif // LONG_DWA2002627_HPP diff --git a/include/boost/python/object_core.hpp b/include/boost/python/object_core.hpp index 7684e044..965e966e 100755 --- a/include/boost/python/object_core.hpp +++ b/include/boost/python/object_core.hpp @@ -14,6 +14,7 @@ # include # include # include +# include # include # include @@ -227,8 +228,18 @@ namespace api public: // implementation detail -- for internal use only explicit object(detail::borrowed_reference); explicit object(detail::new_reference); + explicit object(detail::new_non_null_reference); }; + // Derived classes will usually want these as an implementation detail +# define BOOST_PYTHON_FORWARD_OBJECT_CONSTRUCTORS(derived) \ + inline explicit derived(python::detail::borrowed_reference p) \ + : object(p) {} \ + inline explicit derived(python::detail::new_reference p) \ + : object(p) {} \ + inline explicit derived(python::detail::new_non_null_reference p) \ + : object(p) {} + // // object_initializer -- get the handle to construct the object with, // based on whether T is a proxy or derived from object @@ -266,53 +277,13 @@ using api::object; // // Converter Specializations // -template struct arg_from_python; - -template <> -struct arg_from_python -{ - typedef object result_type; - - arg_from_python(PyObject*); - bool convertible() const; - object operator()(PyObject* x) const; -}; - -template <> -struct arg_from_python - : arg_from_python -{ - arg_from_python(PyObject*); -}; - -template <> -struct arg_from_python -{ - typedef object& result_type; - - arg_from_python(PyObject*); - bool convertible() const; - object& operator()(PyObject* x) const; - private: - mutable object m_result; -}; - namespace converter { - template struct is_object_manager; - template <> - struct is_object_manager + struct extract_object_manager + : always_extract_object_manager { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template struct return_from_python; - template <> - struct return_from_python - { - typedef object result_type; - result_type operator()(PyObject* x) const; + static python::detail::borrowed_reference execute(PyObject* x); }; } @@ -345,7 +316,6 @@ inline api::object_base& api::object_base::operator=(api::object_base const& rhs return *this; } - inline api::object_base::~object_base() { Py_DECREF(m_ptr); @@ -360,6 +330,10 @@ 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; @@ -368,45 +342,14 @@ inline PyObject* api::object_base::ptr() const // // Converter specialization implementations // -inline arg_from_python::arg_from_python(PyObject*) -{} - -inline bool arg_from_python::convertible() const -{ - return true; -} - -inline object arg_from_python::operator()(PyObject* x) const -{ - return object(detail::borrowed_reference(x)); -} - -inline arg_from_python::arg_from_python(PyObject*) - : arg_from_python(0) -{} - -inline arg_from_python::arg_from_python(PyObject* x) - : m_result(detail::borrowed_reference(x)) -{} - -inline bool arg_from_python::convertible() const -{ - return true; -} - -inline object& arg_from_python::operator()(PyObject* x) const -{ - return m_result; -} - namespace converter { - inline object - return_from_python::operator()(PyObject* x) const + inline python::detail::borrowed_reference + extract_object_manager::execute(PyObject* x) { - return object(python::detail::new_reference(x)); + return python::detail::borrowed_reference(python::incref(x)); } - + inline PyObject* get_managed_object(object const& x) { return x.ptr(); diff --git a/src/list.cpp b/src/list.cpp index ed7e675f..484ae121 100644 --- a/src/list.cpp +++ b/src/list.cpp @@ -7,11 +7,13 @@ namespace boost { namespace python { -BOOST_PYTHON_DECL detail::new_reference list::call(object const& arg) +BOOST_PYTHON_DECL detail::new_non_null_reference list::call(object const& arg) { - return (detail::new_reference)PyObject_CallFunction( - (PyObject*)&PyList_Type, "(O)", - arg.ptr()); + return (detail::new_non_null_reference) + (expect_non_null)( + PyObject_CallFunction( + (PyObject*)&PyList_Type, "(O)", + arg.ptr())); } BOOST_PYTHON_DECL list::list() diff --git a/src/long.cpp b/src/long.cpp index 46d3d7c5..43d4526d 100644 --- a/src/long.cpp +++ b/src/long.cpp @@ -7,16 +7,16 @@ namespace boost { namespace python { -BOOST_PYTHON_DECL detail::new_reference long_::call(object const& arg) +BOOST_PYTHON_DECL detail::new_non_null_reference long_::call(object const& arg) { - return (detail::new_reference)PyObject_CallFunction( + return (detail::new_non_null_reference)PyObject_CallFunction( (PyObject*)&PyLong_Type, "(O)", arg.ptr()); } -BOOST_PYTHON_DECL detail::new_reference long_::call(object const& arg, object const& base) +BOOST_PYTHON_DECL detail::new_non_null_reference long_::call(object const& arg, object const& base) { - return (detail::new_reference)PyObject_CallFunction( + return (detail::new_non_null_reference)PyObject_CallFunction( (PyObject*)&PyLong_Type, "(OO)", arg.ptr(), base.ptr()); }