Ticket #2142: added_return_pointee_value.patch

File added_return_pointee_value.patch, 14.8 KB (added by Maximilian Matthe <Maxi.Matthe@…>, 14 years ago)

patch that adds return_pointee_value to boost.python

  • boost/python/return_pointee_value.hpp

     
     1// Copyright Roman Yakovenko, Maximilian Matthe 2006, 2008.
     2// Distributed under the Boost Software License, Version 1.0. (See
     3// accompanying file LICENSE_1_0.txt or copy at
     4// http://www.boost.org/LICENSE_1_0.txt)
     5/*
     6 * Generic return value policy for functions returning pointers which should be
     7 * exposed as values. Can be used to return pointers to non-exposed types.
     8 *
     9 * The code is adapted from
     10 * http://mail.python.org/pipermail/c++-sig/2006-November/011568.html .
     11 */
     12#ifndef RETURN_POINTEE_VALUE_9_11_2006
     13#define RETURN_POINTEE_VALUE_9_11_2006
     14
     15# include <boost/python/detail/prefix.hpp>
     16# include <boost/python/detail/indirect_traits.hpp>
     17# include <boost/python/object.hpp>
     18# include <boost/mpl/if.hpp>
     19# include <boost/python/to_python_indirect.hpp>
     20# include <boost/type_traits/composite_traits.hpp>
     21
     22
     23namespace boost{ namespace python{
     24        namespace detail{
     25                struct make_value_holder
     26                {
     27                        template <class T>
     28                        static PyObject* execute(T* p)
     29                        {
     30                                if (p == 0)
     31                                {
     32                                        return python::detail::none();
     33                                }
     34                                else
     35                                {
     36                                        object p_value( *p );
     37                                        return incref( p_value.ptr() );
     38                                }
     39                        }
     40                };
     41
     42                template <class R>
     43                struct reference_existing_object_requires_a_pointer_return_type
     44# if defined(__GNUC__) && __GNUC__ >= 3 || defined(__EDG__)
     45                {}
     46# endif
     47                ;
     48
     49        } //detail
     50
     51        struct return_pointee_value
     52        {
     53                template <class T>
     54                struct apply
     55                {
     56                        BOOST_STATIC_CONSTANT( bool, ok = is_pointer<T>::value );
     57
     58                        typedef typename mpl::if_c<
     59                                ok
     60                                , to_python_indirect<T, detail::make_value_holder>
     61                                , detail::reference_existing_object_requires_a_pointer_return_type<T>
     62                        >::type type;
     63                };
     64        };
     65
     66
     67} } //boost::python
     68
     69#endif//RETURN_POINTEE_VALUE_9_11_2006
     70 No newline at end of file
  • libs/python/doc/v2/reference.html

     
    877877              </dd>
    878878            </dl>
    879879          </dd>
     880                 
     881                  <dt><a href=
     882          "return_pointee_value.html">return_pointee_value.hpp</a></dt>
    880883
     884          <dd>
     885            <dl class="index">
     886              <dt><a href=
     887              "return_pointee_value.html#classes">Classes</a></dt>
     888
     889              <dd>
     890                <dl class="index">
     891                  <dt><a href=
     892                  "return_pointee_value.html#return_pointee_value-spec">
     893                  return_pointee_value</a></dt>
     894                </dl>
     895              </dd>
     896            </dl>
     897          </dd>
     898
    881899          <dt><a href="return_by_value.html">return_by_value.hpp</a></dt>
    882900
    883901          <dd>
  • libs/python/doc/v2/reference_existing_object.html

     
    8080    "with_custodian_and_ward.html#with_custodian_and_ward-spec">with_custodian_and_ward</a>.
    8181    This class is used in the implementation of <a href=
    8282    "return_internal_reference.html#return_internal_reference-spec">return_internal_reference</a>.</p>
     83        <p>This return value policy can only be used with types that were exposed with boost.python before.</p>
    8384
    8485    <h4><a name="reference_existing_object-spec-synopsis"></a>Class
    8586    <code>reference_existing_object</code> synopsis</h4>
  • libs/python/doc/v2/return_pointee_value.html

     
     1<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
     2
     3<!-- Copyright Maximilian Matthe 2008. Distributed under the Boost -->
     4<!-- Software License, Version 1.0. (See accompanying -->
     5<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
     6<html>
     7  <head>
     8    <meta name="generator" content=
     9    "HTML Tidy for Windows (vers 1st August 2002), see www.w3.org">
     10    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
     11    <link rel="stylesheet" type="text/css" href="../boost.css">
     12
     13    <title>Boost.Python -
     14    &lt;boost/python/return_pointee_value.hpp&gt;</title>
     15  </head>
     16
     17  <body>
     18    <table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
     19    "header">
     20      <tr>
     21        <td valign="top" width="300">
     22          <h3><a href="../../../../index.htm"><img height="86" width="277"
     23          alt="C++ Boost" src="../../../../boost.png" border="0"></a></h3>
     24        </td>
     25
     26        <td valign="top">
     27          <h1 align="center"><a href="../index.html">Boost.Python</a></h1>
     28
     29          <h2 align="center">Header
     30          &lt;boost/python/return_pointee_value.hpp&gt;</h2>
     31        </td>
     32      </tr>
     33    </table>
     34    <hr>
     35
     36    <h2>Contents</h2>
     37
     38    <dl class="page-index">
     39      <dt><a href="#classes">Classes</a></dt>
     40
     41      <dd>
     42        <dl class="page-index">
     43          <dt><a href="#return_pointee_value-spec">Class
     44          <code>return_pointee_value</code></a></dt>
     45
     46          <dd>
     47            <dl class="page-index">
     48              <dt><a href="#return_pointee_value-spec-synopsis">Class
     49              <code>return_pointee_value</code> synopsis</a></dt>
     50
     51              <dt><a href=
     52              "#return_pointee_value-spec-metafunctions">Class
     53              <code>return_pointee_value</code> metafunctions</a></dt>
     54            </dl>
     55          </dd>
     56        </dl>
     57      </dd>
     58
     59      <dt><a href="#examples">Example</a></dt>
     60    </dl>
     61    <hr>
     62
     63    <h2><a name="classes"></a>Classes</h2>
     64
     65    <h3><a name="return_pointee_value-spec"></a>Class
     66    <code>return_pointee_value</code></h3>
     67       
     68        <p><code>return_pointee_value</code> is a model of <a href=
     69    "ResultConverter.html#ResultConverterGenerator-concept">ResultConverterGenerator</a>
     70        which can be used to wrap C++ functions, that return a pointer to a C++ object. The
     71        policy implements the following logic:
     72       
     73        <pre>
     74if return value is NULL pointer:
     75        return None
     76else:
     77        return bp::object( * return value )
     78        </pre>
     79       
     80        It passes the value of the pointee to python, thus the conversion for T is used, if
     81        return value is of type T*.</p>
     82        <p>This return_value_policy can therefore be used to return pointers to python, which
     83        types are not known to boost.python but only a conversion for the pointees. Therefore this
     84        policy should be used to return pointers to objects whose types were wrapped with
     85        other tools, such as SWIG (see example).</p>
     86       
     87        <p><b>Please note:</b> This policy does not take ownership of the wrapped pointer. If the
     88        object pointed to is deleted in C++, the python-object will become invalid too, if your custom
     89        conversion depends on the original object.</p>
     90
     91    <h4><a name="return_pointee_value-spec-synopsis"></a>Class
     92    <code>return_pointee_value</code> synopsis</h4>
     93<pre>
     94namespace boost { namespace python
     95{
     96    struct return_pointee_value
     97    {
     98        template &lt;class T&gt; struct apply;
     99    };
     100}}
     101</pre>
     102
     103    <h4><a name="return_pointee_value-spec-metafunctions"></a>Class
     104    <code>return_pointee_value</code> metafunctions</h4>
     105<pre>
     106template &lt;class T&gt; struct apply
     107</pre>
     108
     109    <dl class="metafunction-semantics">
     110      <dt><b>Requires:</b> <code>T</code> is <code>U*</code>for some <code>U</code>.</dt>
     111
     112      <dt><b>Returns:</b> <code>typedef <a href=
     113      "to_python_indirect.html#to_python_indirect-spec">to_python_indirect</a>&lt;T,V&gt;
     114      type</code>, where <code>V</code> is a class whose
     115      static <code>execute</code> function constructs a <code>boost::python::object</code> from
     116          the dereferenced parameter of type <code>U*</code>.</dt>
     117    </dl>
     118
     119    <h2><a name="examples"></a>Example</h2>
     120        <p><b>Example 1:</b> This example demonstrates the trivial use of <code>return_pointee_value</code> for returning
     121        the value that the returned pointer points to: 
     122        </p>
     123        <p>In C++:</p>
     124        <pre>
     125#include &lt;boost/python/module.hpp&gt;
     126#include &lt;boost/python/class.hpp&gt;
     127#include &lt;boost/python/return_pointee_value.hpp&gt;
     128#include &lt;boost/python/return_value_policy.hpp&gt;
     129#inlcude &lt;wxPython.h&gt;
     130#include &lt;utility&gt;
     131
     132// The function which is going to be wrapped:
     133int* get_value()
     134{
     135        static int val = 42;
     136        return &amp;val;
     137}
     138
     139// Function that returns a NULL-Pointer
     140int* get_null_value()
     141{
     142        return NULL;
     143}
     144
     145// The wrapper
     146BOOST_PYTHON_MODULE(example)
     147{
     148        using namespace boost::python;
     149        // Wrap the functions with return_pointee_value
     150        def("get_value", get_value, return_value_policy&lt;return_pointee_value&gt;());
     151        def("get_null_value", get_null_value, return_value_policy&lt;return_pointee_value&gt;());
     152}
     153        </pre>
     154        <p>In Python:</p>
     155        <pre>
     156&gt;&gt;&gt; import example
     157&gt;&gt;&gt; f = example.get_value()
     158&gt;&gt;&gt; print f
     15942
     160&gt;&gt;&gt; f = 5
     161&gt;&gt;&gt; print example.get_value()
     16242
     163&gt;&gt;&gt; assert None is example.get_null_value()
     164        </pre>
     165        <p>Note that the value of the static C++-variable <code>val</code> is not changed when python assigns
     166        a new value to <code>f</code>. This is caused by the logic of <code>return_pointee_value</code>: It returns
     167        the <code>boost::python::object</code> which is constructed from <code>*val</code>.</p>
     168       
     169        <p><b>Example 2:</b> The following example uses return_pointee_value to return an object that is wrapped
     170        with SWIG. I use the wxPython-API because it's easier to understand.</p>
     171
     172    <p>In C++:</p>
     173<pre>
     174#include &lt;boost/python/module.hpp&gt;
     175#include &lt;boost/python/class.hpp&gt;
     176#include &lt;boost/python/return_pointee_value.hpp&gt;
     177#include &lt;boost/python/return_value_policy.hpp&gt;
     178#inlcude &lt;wxPython.h&gt;
     179#include &lt;utility&gt;
     180
     181// The following code assumes that there is set up a
     182// working wxWidgets application
     183
     184// Function to wrap:
     185wxWindow* getMainFrame()
     186{
     187        return wxGetApp().GetTopWindow();
     188}
     189
     190// Custom conversion for wxWindow.
     191struct convert_wxWindow
     192{
     193        // Method that does the conversion. Note that it takes a reference to wxWindow,
     194        // not a reference to a pointer. This is needed, because the return value policy
     195        // converts the objects not the pointers.
     196        static PyObject* convert(wxWindow const& o)
     197        {
     198                // Convert the pointer to wxWindow, instead of its value. This is how
     199                // it should be done to convert wxObjects to wxPython. The object will be
     200                // recognized well in python
     201                PyObject* arg = wxPyMake_wxObject(const_cast<wxWindow*>(&o), false);
     202                return arg;
     203        }
     204};
     205
     206// Wrapper code
     207using namespace boost::python;
     208BOOST_PYTHON_MODULE(MyApp)
     209{
     210        def("getMainFrame", getMainFrame, return_value_policy<return_pointee_value>());
     211       
     212        // register the custom converter
     213        // converter for wxWindow, its conversion_struct, false tells boost that
     214        // we do not have a get_pytype() method in it.
     215        to_python_converter&lt;wxWindow, convert_wxWindow, false&gt;();
     216}
     217</pre>
     218    In Python: The example assumes that you call the python function <code>doit</code> from C++:
     219<pre>
     220def doit():
     221        w = MyApp.getMainFrame()
     222        w.Hide()
     223        print "Haha, it's gone!"
     224        w.Show()
     225        return 0
     226       
     227</pre>
     228<p>Note that the returned wxWindow is the same object as the return value of <code>getMainFrame</code> because of
     229the custom construction for <code>boost::python::object</code> from wxWindow. The conversion just converts the pointer,
     230not the object itself.</p>
     231
     232    <p>Revised
     233    <!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
     234  22 July, 2008
     235  <!--webbot bot="Timestamp" endspan i-checksum="39359" -->
     236    </p>
     237
     238    <p><i>&copy; Copyright Maximilian Matthe, Roman Yakovenko 2006, 2008.</i></p>
     239  </body>
     240</html>
     241
  • libs/python/test/return_pointee_value.cpp

     
     1// Copyright Maximilian Matthe 2008.
     2// Distributed under the Boost Software License, Version 1.0. (See
     3// accompanying file LICENSE_1_0.txt or copy at
     4// http://www.boost.org/LICENSE_1_0.txt)
     5
     6#include <boost/python/return_pointee_value.hpp>
     7#include <boost/python/module.hpp>
     8#include <boost/python/return_value_policy.hpp>
     9#include <boost/python/def.hpp>
     10#include <boost/python/to_python_converter.hpp>
     11
     12// Out returned, unkown type
     13struct IntWrapper
     14{
     15        IntWrapper(int v) : val(v) {}
     16        int val;
     17};
     18
     19// the custom converter
     20struct convert_IntWrapper
     21{
     22        static PyObject* convert(IntWrapper const& w)
     23        {
     24                return boost::python::incref(boost::python::object(w.val).ptr());
     25        }
     26};
     27
     28IntWrapper* returnIntWrapper()
     29{
     30        static IntWrapper w(42);
     31        return &w;
     32}
     33
     34//////////////////////////////////////////////////////////
     35float* get_value()
     36{
     37        static float value = 0.5f;
     38        return &value;
     39}
     40
     41float* get_null_value()
     42{
     43        return NULL;
     44}
     45
     46BOOST_PYTHON_MODULE(return_pointee_value)
     47{
     48        using namespace boost::python;
     49        def("returnIntWrapper", returnIntWrapper, return_value_policy<return_pointee_value>());
     50       
     51        def("get_value", get_value, return_value_policy<return_pointee_value>());
     52        def("get_null_value", get_null_value, return_value_policy<return_pointee_value>());
     53       
     54        to_python_converter<IntWrapper, convert_IntWrapper, false>();
     55}
     56 No newline at end of file
  • libs/python/test/return_pointee_value.py

     
     1# Copyright Maximilian Matthe 2008
     2# Distributed under the Boost
     3# Software License, Version 1.0. (See accompanying
     4# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
     5
     6import return_pointee_value
     7
     8
     9def run(args = None):
     10        a = return_pointee_value.returnIntWrapper()
     11        assert a == 42
     12        assert 0.5 == return_pointee_value.get_value()
     13        assert None is return_pointee_value.get_null_value()
     14        return 0
     15               
     16if __name__ == '__main__':
     17        print 'running...'
     18        import sys
     19        status = run()
     20        if(status == 0):
     21                print "Succes..."
     22        else:
     23                print "Failure!"
     24        sys.exit(status)
     25       
     26 No newline at end of file