diff --git a/include/boost/python/converter/pointee_to_python_function.hpp b/include/boost/python/converter/pointee_to_python_function.hpp new file mode 100644 index 00000000..0f1ae99e --- /dev/null +++ b/include/boost/python/converter/pointee_to_python_function.hpp @@ -0,0 +1,51 @@ +// 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 POINTEE_TO_PYTHON_FUNCTION_DWA2002128_HPP +# define POINTEE_TO_PYTHON_FUNCTION_DWA2002128_HPP + +# include +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python { namespace converter { + +// pointee_to_python_function -- +// +// essentially a "templated global reference" which holds the +// converter for converting a type to Python by-value. We "normalize" +// T by adding "const volatile&" so that fewer global variables and +// associated static initializations are generated. +namespace detail +{ + template + struct pointee_to_python_function_base + { + static to_python_function_t const& value; + }; + + template + to_python_function_t const& + pointee_to_python_function_base::value + = converter::registry::get_to_python_function(pointer_type_id()); +} + +template +struct pointee_to_python_function + : detail::pointee_to_python_function_base< + typename add_reference< + typename add_cv::type + >::type + > +{ +}; + +}}} // namespace boost::python::converter + +#endif // POINTEE_TO_PYTHON_FUNCTION_DWA2002128_HPP diff --git a/src/converter/callback.cpp b/src/converter/callback.cpp index b3158500..a248f1ad 100644 --- a/src/converter/callback.cpp +++ b/src/converter/callback.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace boost { namespace python { namespace converter { @@ -25,7 +26,10 @@ namespace detail , const_cast("no to_python (by-value) converter found for type")); throw error_already_set(); } - return converter(const_cast(source)); + + return source == 0 + ? python::detail::none() + : converter(const_cast(source)); } } @@ -45,6 +49,14 @@ namespace detail throw error_already_set(); } } + + BOOST_PYTHON_DECL void throw_no_class_registered() + { + PyErr_SetString( + PyExc_TypeError + , const_cast("class not registered for to_python type")); + throw error_already_set(); + } BOOST_PYTHON_DECL void* convert_rvalue(PyObject* src, rvalue_stage1_data& data, void* storage) { diff --git a/test/callbacks.cpp b/test/callbacks.cpp index 9991e41f..2bf285b5 100644 --- a/test/callbacks.cpp +++ b/test/callbacks.cpp @@ -7,6 +7,7 @@ #include #include #include +#include using namespace boost::python; @@ -42,9 +43,24 @@ X apply_X_X(PyObject* f, X x) return returning::call(f, x); } -void apply_void_X_ref(PyObject* f, X x) +void apply_void_X_ref(PyObject* f, X& x) { - returning::call(f, boost::ref(x)); + returning::call(f, boost::ref(x)); +} + +void apply_void_X_cref(PyObject* f, X const& x) +{ + returning::call(f, boost::cref(x)); +} + +void apply_void_X_ptr(PyObject* f, X* x) +{ + returning::call(f, ptr(x)); +} + +void apply_void_X_deep_ptr(PyObject* f, X* x) +{ + returning::call(f, x); } int X::counter; @@ -56,6 +72,9 @@ BOOST_PYTHON_MODULE_INIT(callbacks_ext) .def("apply_void_int", apply_void_int) .def("apply_X_X", apply_X_X) .def("apply_void_X_ref", apply_void_X_ref) + .def("apply_void_X_cref", apply_void_X_cref) + .def("apply_void_X_ptr", apply_void_X_ptr) + .def("apply_void_X_deep_ptr", apply_void_X_deep_ptr) .add( class_("X") .def_init(args()) @@ -67,5 +86,4 @@ BOOST_PYTHON_MODULE_INIT(callbacks_ext) ; } - - +#include "module_tail.cpp" diff --git a/test/callbacks.py b/test/callbacks.py index 16c5be94..810aad53 100644 --- a/test/callbacks.py +++ b/test/callbacks.py @@ -27,6 +27,45 @@ >>> apply_void_X_ref(increment, x) >>> x.value() 43 + +>>> apply_void_X_cref(increment, x) +>>> x.value() # const-ness is not respected, sorry! +44 + +>>> last_x = 1 +>>> def decrement(x): +... global last_x +... last_x = x +... if x is not None: +... x.set(x.value() - 1) + +>>> apply_void_X_ptr(decrement, x) +>>> x.value() +43 +>>> last_x.value() +43 +>>> increment(last_x) +>>> x.value() +44 +>>> last_x.value() +44 + +>>> apply_void_X_ptr(decrement, None) +>>> assert last_x is None +>>> x.value() +44 + +>>> last_x = 1 +>>> apply_void_X_deep_ptr(decrement, None) +>>> assert last_x is None +>>> x.value() +44 + +>>> apply_void_X_deep_ptr(decrement, x) +>>> x.value() +44 +>>> last_x.value() +43 ''' def run(args = None):