I need some help with SWIG on this.
I have a C++ pure virtual function that I need to implement in python and it gets an std:span<uint8_t> as an output argument.
virtual void fill_buffer(size_t offset, std::span<uint8_t> buffer) = 0;
The python side is responsible to fill up that buffer with data. What I did so far to make it work is create some utility functions like:
%inline %{
PyObject* size(const std::span<uint8_t>& span) {
return PyInt_FromLong(span.size());
}
void fill_buffer(const std::span<uint8_t>& span, const std::vector<uint8_t>& buffer) {
std::copy(buffer.begin(), buffer.end(), span.data());
}
%}
And then in the python side I have:
def fill_buffer(self, offset, buffer):
buffer_size = size(buffer)
with open(self.resource_file, 'rb') as file:
file.seek(offset)
read_bytes = file.read(buffer_size)
fill_buffer(buffer, read_bytes)
But I am thinking there must be a better way to do this. Maybe using a typemap? I would like to seamlessly use the buffer object in python without the helper functions, maybe something like:
def fill_buffer(self, offset, buffer):
with open(self.resource_file, 'rb') as file:
file.seek(offset)
buffer = file.read(buffer.size())
Given the following, complete test:
Our goal is to wrap it nicely into Python, such that the following example can work:
(Note that
readintois the neat way to go from file read straight into a buffer of your choosing)What we need to make this work is a "directorin" typemap. As luck would have it Python 3's C API has a function that does almost exactly what we want.
PyMemoryView_FromMemorycreates a buffer object that's a pretty good Python equivalent forstd::span.We can do fancier things if the type in your span was not just a
uint8_t, but for this case the simple interface is sufficient. (Also since the buffer we create allows for in place modification there's no need for a "directorargout" typemap, however an "in" typemap might be a useful addition here)