2

I was wondering whether it's possible to fill in a buffer (with the following conditions) in Python and if so how?

I have a buffer in C++ that I need to fill in Python. The Address of the buffer is obtained through the GetAddress method which returns a void pointer to the buffer's address.

#include <boost/smart_ptr/shared_ptr.hpp>
class Foo
{
public:
    Foo(const unsigned int length)
    {
        m_buffer = boost::shared_ptr< unsigned char >( new unsigned char[ length ] );
    }

    ~Foo(){}

    void* GetAddress( ) const
    {
        // cast for the sake of this question
        return reinterpret_cast< void* >( m_buffer.get() );
    }

private:
    boost::shared_ptr< unsigned char > m_buffer;
    Foo();
    Foo(const Foo&);
};

Using Py++ I can generate the Boost.Python wrapper to export the class to Python as follows:

#include "boost/python.hpp"
#include "foo.hpp"

namespace bp = boost::python;

BOOST_PYTHON_MODULE(MyWrapper){
    { //::Foo
        typedef bp::class_< Foo, boost::noncopyable > Foo_exposer_t;
        Foo_exposer_t Foo_exposer = Foo_exposer_t( "Foo", bp::init< unsigned int >(( bp::arg("length") )) );
        bp::scope Foo_scope( Foo_exposer );
        bp::implicitly_convertible< unsigned int const, Foo >();
        { //::Foo::GetAddress

            typedef void * ( ::Foo::*GetAddress_function_type )(  ) const;

            Foo_exposer.def( 
                "GetAddress"
                , GetAddress_function_type( &::Foo::GetAddress )
                , bp::return_value_policy< bp::return_opaque_pointer >() );

        }
    }
}

In Python, the output of the GetAddress is a void * to the memory address:

>>> import MyWrapper
>>> foo = MyWrapper.Foo(100)
>>> address = foo.GetAddress()
>>> print address
<void * object at 0x01E200B0>
>>>

Problem is Python doesn't let me do anything with the void * address object. If I try to access the second element in buffer, none of the following work:

>>> address + 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'void *' and 'int'
>>> address[1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'void *' object is unsubscriptable
>>>

Environment: Visual Studio 2008, Boost 1.44, gcc-xml 0.9.0, py++ 1.0.0, pygccxml 1.1.0, Python 2.6.6

5
  • So... what is your question? What doesn't work as expected? What can't you figure out how to do, exactly? Commented May 1, 2012 at 20:10
  • Problem is I can get the address of the buffer as a void pointer but I can't do anything with it. For example, it doesn't support iterating over and value assignment. All in all good point! I'll edit my question.. Commented May 1, 2012 at 20:22
  • So what sort of interface for filling the buffer are you looking for? Indexing in? Treating it as a stream? Have you looked at existing classes like buffer, StringIO etc.? What are you going to do with the buffer once it's filled? Commented May 1, 2012 at 20:26
  • I get the errors posted at the end of the question Commented May 1, 2012 at 20:31
  • I have looked at buffer and StringIO but don't know how I can pass the void pointer object to them. Commented May 1, 2012 at 20:42

1 Answer 1

2

Python does not really deal with pointers. You can export one as a opaque cookie, but you can never do anything with it (except pass it back to c++).

What I would do in your case, is to reverse it. Instead of returning to pointer to python, have a function in c++ that takes a "buffer" from python.

namespace bp = boost::python
void FillBuffer(Foo& this, bp::list buff)
{
    unsigned char* addr = reinterpret_cast< unsigned char* >( this.GetAddress() );
    for(int i = 0; i < bp::len(buff); i++)
        addr[i] = bp::extract< unsigned char >( buff[i] );
}

Foo_exposer.def("FillBuffer", &FillBuffer);

Now you can pass a list in to fill the buffer. You can create an similar function to stuff a buffer into a list and return it python. You will, of course, want to be much more careful about buffer overruns and such, but this should give you the right idea.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! I tried it and it works. It would've been nice to be able to do this on the Python side.
And thanks for fixing my code. I was away from my main box, and skipped compiling it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.