diff --git a/include/boost/python/detail/extension_class.hpp b/include/boost/python/detail/extension_class.hpp index 94d9bf6b..567f0db8 100644 --- a/include/boost/python/detail/extension_class.hpp +++ b/include/boost/python/detail/extension_class.hpp @@ -22,6 +22,7 @@ # include # include # include +# include namespace boost { namespace python { @@ -133,6 +134,26 @@ class class_registry static std::vector static_derived_class_info; }; +template +struct is_null_helper +{ + template + static bool test(Ptr x) { return x == 0; } +}; + +template <> +struct is_null_helper +{ + template + static bool test(Ptr x) { return x.get() == 0; } +}; + +template +bool is_null(const Ptr& x) +{ + return is_null_helper<(is_pointer::value)>::test(x); +}; + }}} // namespace boost::python::detail BOOST_PYTHON_BEGIN_CONVERSION_NAMESPACE @@ -178,9 +199,9 @@ class python_extension_class_converters new boost::python::detail::instance_value_holder(result.get(), x))); return result.release(); } - - // Convert to T* - friend T* from_python(PyObject* obj, boost::python::type) + + friend + T* non_null_from_python(PyObject* obj, boost::python::type) { // downcast to an extension_instance, then find the actual T boost::python::detail::extension_instance* self = boost::python::detail::get_extension_instance(obj); @@ -201,6 +222,15 @@ class python_extension_class_converters throw boost::python::argument_error(); } + // Convert to T* + friend T* from_python(PyObject* obj, boost::python::type) + { + if (obj == Py_None) + return 0; + else + return non_null_from_python(obj, boost::python::type()); + } + // Convert to PtrType, where PtrType can be dereferenced to obtain a T. template static PtrType& ptr_from_python(PyObject* obj, boost::python::type) @@ -220,9 +250,25 @@ class python_extension_class_converters throw boost::python::argument_error(); } + template + static const PtrType& ptr_const_ref_from_python(PyObject* obj, boost::python::type) + { + if (obj == Py_None) + { + static PtrType null_ptr; + return null_ptr; + } + return ptr_from_python(obj, boost::python::type()); + } + template static PyObject* ptr_to_python(PtrType x) { + if (boost::python::detail::is_null(x)) + { + return boost::python::detail::none(); + } + boost::python::reference result(create_instance()); result->add_implementation( std::auto_ptr( @@ -254,7 +300,7 @@ class python_extension_class_converters // Convert to T& friend T& from_python(PyObject* p, boost::python::type) - { return *boost::python::detail::check_non_null(from_python(p, boost::python::type())); } + { return *boost::python::detail::check_non_null(non_null_from_python(p, boost::python::type())); } // Convert to const T& friend const T& from_python(PyObject* p, boost::python::type) @@ -267,11 +313,11 @@ class python_extension_class_converters friend std::auto_ptr& from_python(PyObject* p, boost::python::type&>) { return ptr_from_python(p, boost::python::type >()); } - friend std::auto_ptr& from_python(PyObject* p, boost::python::type >) - { return ptr_from_python(p, boost::python::type >()); } + friend const std::auto_ptr& from_python(PyObject* p, boost::python::type >) + { return ptr_const_ref_from_python(p, boost::python::type >()); } friend const std::auto_ptr& from_python(PyObject* p, boost::python::type&>) - { return ptr_from_python(p, boost::python::type >()); } + { return ptr_const_ref_from_python(p, boost::python::type >()); } friend PyObject* to_python(std::auto_ptr x) { return ptr_to_python(x); } @@ -279,11 +325,11 @@ class python_extension_class_converters friend boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) { return ptr_from_python(p, boost::python::type >()); } - friend boost::shared_ptr& from_python(PyObject* p, boost::python::type >) - { return ptr_from_python(p, boost::python::type >()); } + friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type >) + { return ptr_const_ref_from_python(p, boost::python::type >()); } friend const boost::shared_ptr& from_python(PyObject* p, boost::python::type&>) - { return ptr_from_python(p, boost::python::type >()); } + { return ptr_const_ref_from_python(p, boost::python::type >()); } friend PyObject* to_python(boost::shared_ptr x) { return ptr_to_python(x); }