From 390bb1988d648a3f3e2b5b5aac49deadb3ec2ddd Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Fri, 10 May 2002 15:48:27 +0000 Subject: [PATCH] implemented back_reference<> [SVN r13811] --- include/boost/python/back_reference.hpp | 97 +++++++++++++++++++ .../boost/python/converter/from_python.hpp | 44 ++++++++- test/back_reference.cpp | 14 +++ test/back_reference.py | 4 + 4 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 include/boost/python/back_reference.hpp diff --git a/include/boost/python/back_reference.hpp b/include/boost/python/back_reference.hpp new file mode 100644 index 00000000..bde26dcd --- /dev/null +++ b/include/boost/python/back_reference.hpp @@ -0,0 +1,97 @@ +// 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 BACK_REFERENCE_DWA2002510_HPP +# define BACK_REFERENCE_DWA2002510_HPP + +# include + +namespace boost { namespace python { + +template +struct back_reference +{ + public: + typedef T type; + + back_reference(PyObject*, T); + ref reference() const; + T get() const; + private: + ref m_reference; + T m_value; +}; + +# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +class is_back_reference +{ + public: + BOOST_STATIC_CONSTANT(bool, value = false); +}; + +template +class is_back_reference > +{ + public: + BOOST_STATIC_CONSTANT(bool, value = true); +}; + +# else // no partial specialization + +}} // namespace boost::python + +#include + +namespace boost { namespace python { + +namespace detail +{ + typedef char (&yes_back_reference_t)[1]; + typedef char (&no_back_reference_t)[2]; + + no_back_reference_t is_back_reference_test(...); + + template + yes_back_reference_t is_back_reference_test(type< back_reference >); +} + +template +class is_back_reference +{ + public: + BOOST_STATIC_CONSTANT( + bool, value = ( + sizeof(detail::is_back_reference_test(type())) + == sizeof(detail::yes_back_reference_t))); +}; + +# endif // BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +// +// implementations +// +template +back_reference::back_reference(PyObject* p, T x) + : m_reference(p, ref::increment_count) + , m_value(x) +{ +} + +template +ref back_reference::reference() const +{ + return m_reference; +} + +template +T back_reference::get() const +{ + return m_value; +} + +}} // namespace boost::python + +#endif // BACK_REFERENCE_DWA2002510_HPP diff --git a/include/boost/python/converter/from_python.hpp b/include/boost/python/converter/from_python.hpp index 1c6a8b3c..a4923ae5 100644 --- a/include/boost/python/converter/from_python.hpp +++ b/include/boost/python/converter/from_python.hpp @@ -16,6 +16,12 @@ # include # include # include +# include + +namespace boost { namespace python +{ + template struct from_python; +}} namespace boost { namespace python { namespace converter { @@ -82,6 +88,21 @@ class rvalue_from_python rvalue_data m_data; }; +// ------- back-reference converters -------- + +// Converts to a (PyObject*,T) bundle, for when you need a reference +// back to the Python object + +template +struct back_reference_from_python + : boost::python::from_python +{ + back_reference_from_python(PyObject*); + T operator()(PyObject*); + private: + typedef boost::python::from_python base; +}; + template struct select_from_python { @@ -100,6 +121,10 @@ struct select_from_python boost::python::detail::is_reference_to_non_const::value || boost::python::detail::is_reference_to_volatile::value); + BOOST_STATIC_CONSTANT( + bool, back_ref = + boost::python::is_back_reference::value); + typedef typename mpl::select_type< ptr , pointer_from_python @@ -109,7 +134,11 @@ struct select_from_python , typename mpl::select_type< ref , reference_from_python - , rvalue_from_python + , typename mpl::select_type< + back_ref + , back_reference_from_python + , rvalue_from_python + >::type >::type >::type >::type type; @@ -232,6 +261,19 @@ rvalue_from_python::operator()(PyObject* p) return python::detail::void_ptr_to_reference(m_data.stage1.convertible, (result_type(*)())0); } +template +back_reference_from_python::back_reference_from_python(PyObject* x) + : base(x) +{ +} + +template +inline T +back_reference_from_python::operator()(PyObject* x) +{ + return T(x, base::operator()(x)); +} + }}} // namespace boost::python::converter #endif // FROM_PYTHON_DWA2002127_HPP diff --git a/test/back_reference.cpp b/test/back_reference.cpp index e1338eaa..577aa6ef 100644 --- a/test/back_reference.cpp +++ b/test/back_reference.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -73,6 +74,17 @@ namespace boost { namespace python }; }} +// prove that back_references get initialized with the right PyObject* +PyObject* y_identity(back_reference y) +{ + return y.reference().release(); +} + +// prove that back_references contain the right value +bool y_equality(back_reference y1, Y const& y2) +{ + return &y1.get() == &y2; +} BOOST_PYTHON_MODULE_INIT(back_reference_ext) { @@ -93,6 +105,8 @@ BOOST_PYTHON_MODULE_INIT(back_reference_ext) .def("value", &Z::value) .def("set", &Z::set) ) + .def("y_identity", y_identity) + .def("y_equality", y_equality) ; } diff --git a/test/back_reference.py b/test/back_reference.py index 552deec8..21d5d1c0 100644 --- a/test/back_reference.py +++ b/test/back_reference.py @@ -10,6 +10,10 @@ >>> z2 = copy_Z(z) >>> x_instances() 4 +>>> y_identity(y) is y +1 +>>> y_equality(y, y) +1 ''' def run(args = None):