Index: boost/python/return_pointee_value.hpp =================================================================== --- boost/python/return_pointee_value.hpp (revision 0) +++ boost/python/return_pointee_value.hpp (revision 0) @@ -0,0 +1,69 @@ +// Copyright Roman Yakovenko, Maximilian Matthe 2006, 2008. +// 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) +/* + * Generic return value policy for functions returning pointers which should be + * exposed as values. Can be used to return pointers to non-exposed types. + * + * The code is adapted from + * http://mail.python.org/pipermail/c++-sig/2006-November/011568.html . + */ +#ifndef RETURN_POINTEE_VALUE_9_11_2006 +#define RETURN_POINTEE_VALUE_9_11_2006 + +# include +# include +# include +# include +# include +# include + + +namespace boost{ namespace python{ + namespace detail{ + struct make_value_holder + { + template + static PyObject* execute(T* p) + { + if (p == 0) + { + return python::detail::none(); + } + else + { + object p_value( *p ); + return incref( p_value.ptr() ); + } + } + }; + + template + struct reference_existing_object_requires_a_pointer_return_type +# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__) + {} +# endif + ; + + } //detail + + struct return_pointee_value + { + template + struct apply + { + BOOST_STATIC_CONSTANT( bool, ok = is_pointer::value ); + + typedef typename mpl::if_c< + ok + , to_python_indirect + , detail::reference_existing_object_requires_a_pointer_return_type + >::type type; + }; + }; + + +} } //boost::python + +#endif//RETURN_POINTEE_VALUE_9_11_2006 \ No newline at end of file Index: libs/python/doc/v2/reference.html =================================================================== --- libs/python/doc/v2/reference.html (revision 47690) +++ libs/python/doc/v2/reference.html (working copy) @@ -877,7 +877,25 @@ + +
return_pointee_value.hpp
+
+
+
Classes
+ +
+
+
+ return_pointee_value
+
+
+
+
+
return_by_value.hpp
Index: libs/python/doc/v2/reference_existing_object.html =================================================================== --- libs/python/doc/v2/reference_existing_object.html (revision 47690) +++ libs/python/doc/v2/reference_existing_object.html (working copy) @@ -80,6 +80,7 @@ "with_custodian_and_ward.html#with_custodian_and_ward-spec">with_custodian_and_ward. This class is used in the implementation of return_internal_reference.

+

This return value policy can only be used with types that were exposed with boost.python before.

Class reference_existing_object synopsis

Index: libs/python/doc/v2/return_pointee_value.html =================================================================== --- libs/python/doc/v2/return_pointee_value.html (revision 0) +++ libs/python/doc/v2/return_pointee_value.html (revision 0) @@ -0,0 +1,241 @@ + + + + + + + + + + + + Boost.Python - + <boost/python/return_pointee_value.hpp> + + + + + + + + + +
+

C++ Boost

+
+

Boost.Python

+ +

Header + <boost/python/return_pointee_value.hpp>

+
+
+ +

Contents

+ +
+
Classes
+ +
+
+
Class + return_pointee_value
+ +
+
+
Class + return_pointee_value synopsis
+ +
Class + return_pointee_value metafunctions
+
+
+
+
+ +
Example
+
+
+ +

Classes

+ +

Class + return_pointee_value

+ +

return_pointee_value is a model of ResultConverterGenerator + which can be used to wrap C++ functions, that return a pointer to a C++ object. The + policy implements the following logic: + +

+if return value is NULL pointer:
+	return None
+else:
+	return bp::object( * return value )
+	
+ + It passes the value of the pointee to python, thus the conversion for T is used, if + return value is of type T*.

+

This return_value_policy can therefore be used to return pointers to python, which + types are not known to boost.python but only a conversion for the pointees. Therefore this + policy should be used to return pointers to objects whose types were wrapped with + other tools, such as SWIG (see example).

+ +

Please note: This policy does not take ownership of the wrapped pointer. If the + object pointed to is deleted in C++, the python-object will become invalid too, if your custom + conversion depends on the original object.

+ +

Class + return_pointee_value synopsis

+
+namespace boost { namespace python
+{
+    struct return_pointee_value
+    {
+        template <class T> struct apply;
+    };
+}}
+
+ +

Class + return_pointee_value metafunctions

+
+template <class T> struct apply
+
+ +
+
Requires: T is U*for some U.
+ +
Returns: typedef to_python_indirect<T,V> + type, where V is a class whose + static execute function constructs a boost::python::object from + the dereferenced parameter of type U*.
+
+ +

Example

+

Example 1: This example demonstrates the trivial use of return_pointee_value for returning + the value that the returned pointer points to: +

+

In C++:

+
+#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/return_pointee_value.hpp>
+#include <boost/python/return_value_policy.hpp>
+#inlcude <wxPython.h>
+#include <utility>
+
+// The function which is going to be wrapped:
+int* get_value() 
+{
+	static int val = 42;
+	return &val;
+}
+
+// Function that returns a NULL-Pointer
+int* get_null_value()
+{
+	return NULL;
+}
+
+// The wrapper
+BOOST_PYTHON_MODULE(example)
+{
+	using namespace boost::python;
+	// Wrap the functions with return_pointee_value
+	def("get_value", get_value, return_value_policy<return_pointee_value>());
+	def("get_null_value", get_null_value, return_value_policy<return_pointee_value>());
+}
+	
+

In Python:

+
+>>> import example
+>>> f = example.get_value()
+>>> print f
+42
+>>> f = 5
+>>> print example.get_value()
+42
+>>> assert None is example.get_null_value() 
+	
+

Note that the value of the static C++-variable val is not changed when python assigns + a new value to f. This is caused by the logic of return_pointee_value: It returns + the boost::python::object which is constructed from *val.

+ +

Example 2: The following example uses return_pointee_value to return an object that is wrapped + with SWIG. I use the wxPython-API because it's easier to understand.

+ +

In C++:

+
+#include <boost/python/module.hpp>
+#include <boost/python/class.hpp>
+#include <boost/python/return_pointee_value.hpp>
+#include <boost/python/return_value_policy.hpp>
+#inlcude <wxPython.h>
+#include <utility>
+
+// The following code assumes that there is set up a
+// working wxWidgets application 
+
+// Function to wrap:
+wxWindow* getMainFrame()
+{
+	return wxGetApp().GetTopWindow();
+}
+
+// Custom conversion for wxWindow.
+struct convert_wxWindow
+{
+	// Method that does the conversion. Note that it takes a reference to wxWindow, 
+	// not a reference to a pointer. This is needed, because the return value policy
+	// converts the objects not the pointers.
+	static PyObject* convert(wxWindow const& o)
+	{
+		// Convert the pointer to wxWindow, instead of its value. This is how
+		// it should be done to convert wxObjects to wxPython. The object will be
+		// recognized well in python
+		PyObject* arg = wxPyMake_wxObject(const_cast(&o), false);
+		return arg;
+	}
+};
+
+// Wrapper code
+using namespace boost::python;
+BOOST_PYTHON_MODULE(MyApp)
+{
+	def("getMainFrame", getMainFrame, return_value_policy());
+	
+	// register the custom converter
+	// converter for wxWindow, its conversion_struct, false tells boost that
+	// we do not have a get_pytype() method in it.
+	to_python_converter<wxWindow, convert_wxWindow, false>();
+}
+
+ In Python: The example assumes that you call the python function doit from C++: +
+def doit():
+	w = MyApp.getMainFrame()
+	w.Hide()
+	print "Haha, it's gone!"
+	w.Show()
+	return 0
+	
+
+

Note that the returned wxWindow is the same object as the return value of getMainFrame because of +the custom construction for boost::python::object from wxWindow. The conversion just converts the pointer, +not the object itself.

+ +

Revised + + 22 July, 2008 + +

+ +

© Copyright Maximilian Matthe, Roman Yakovenko 2006, 2008.

+ + + Index: libs/python/test/return_pointee_value.cpp =================================================================== --- libs/python/test/return_pointee_value.cpp (revision 0) +++ libs/python/test/return_pointee_value.cpp (revision 0) @@ -0,0 +1,55 @@ +// Copyright Maximilian Matthe 2008. +// 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) + +#include +#include +#include +#include +#include + +// Out returned, unkown type +struct IntWrapper +{ + IntWrapper(int v) : val(v) {} + int val; +}; + +// the custom converter +struct convert_IntWrapper +{ + static PyObject* convert(IntWrapper const& w) + { + return boost::python::incref(boost::python::object(w.val).ptr()); + } +}; + +IntWrapper* returnIntWrapper() +{ + static IntWrapper w(42); + return &w; +} + +////////////////////////////////////////////////////////// +float* get_value() +{ + static float value = 0.5f; + return &value; +} + +float* get_null_value() +{ + return NULL; +} + +BOOST_PYTHON_MODULE(return_pointee_value) +{ + using namespace boost::python; + def("returnIntWrapper", returnIntWrapper, return_value_policy()); + + def("get_value", get_value, return_value_policy()); + def("get_null_value", get_null_value, return_value_policy()); + + to_python_converter(); +} \ No newline at end of file Index: libs/python/test/return_pointee_value.py =================================================================== --- libs/python/test/return_pointee_value.py (revision 0) +++ libs/python/test/return_pointee_value.py (revision 0) @@ -0,0 +1,25 @@ +# Copyright Maximilian Matthe 2008 +# 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) + +import return_pointee_value + + +def run(args = None): + a = return_pointee_value.returnIntWrapper() + assert a == 42 + assert 0.5 == return_pointee_value.get_value() + assert None is return_pointee_value.get_null_value() + return 0 + +if __name__ == '__main__': + print 'running...' + import sys + status = run() + if(status == 0): + print "Succes..." + else: + print "Failure!" + sys.exit(status) + \ No newline at end of file