[PyQt] converting std::vector to PyList
Giovanni Bajo
rasky at develer.com
Tue Mar 27 13:13:59 BST 2007
On 3/27/2007 12:40 PM, Patrick Stinson wrote:
> I've got a method in my C++ api that takes a std::vector & as an
> argument and populates it to return a value. What would be the easiest
> way to wrap this with sip? I'd like to use a python list if possible.
> I can easily re-write the function to return the vector if necessary.
Have a look at the attached code. You just need to %Import it into your
SIP file.
Theoretically, I would like something like this to be bundled in SIP
proper, one day. Most of the code in there is duplicated though, so
probably some more support in sipgen/siplib is needed. I haven't had
time to think about it and prepare a concrete proposal for Phil.
Anyway, maybe we should put it onto the wiki at least, and make it
grow/mature/bugfix through public contributions, even in its current form.
--
Giovanni Bajo
-------------- next part --------------
// SIP support for std::vector
// by Giovanni Bajo <rasky at develer.com>
// Public domain
// ****************************************************
// SIP generic implementation for std::vector<>
// ****************************************************
// ALas, this template-based generic implementation is valid only
// if the element type is a SIP-wrapped type. For basic types (int, double, etc.)
// we are forced to cut & paste to provide a specialization.
template<TYPE>
%MappedType std::vector<TYPE>
{
%TypeHeaderCode
#include <vector>
%End
%ConvertFromTypeCode
PyObject *l;
// Create the Python list of the correct length.
if ((l = PyList_New(sipCpp -> size())) == NULL)
return NULL;
// Go through each element in the C++ instance and convert it to a
// wrapped P2d.
for (int i = 0; i < (int)sipCpp -> size(); ++i)
{
TYPE *cpp = new TYPE(sipCpp -> at(i));
PyObject *pobj;
// Get the Python wrapper for the Type instance, creating a new
// one if necessary, and handle any ownership transfer.
if ((pobj = sipConvertFromInstance(cpp, sipClass_TYPE, sipTransferObj)) == NULL)
{
// There was an error so garbage collect the Python list.
Py_DECREF(l);
return NULL;
}
// Add the wrapper to the list.
PyList_SET_ITEM(l, i, pobj);
}
// Return the Python list.
return l;
%End
%ConvertToTypeCode
// Check if type is compatible
if (sipIsErr == NULL)
{
// Must be any iterable
PyObject *i = PyObject_GetIter(sipPy);
bool iterable = (i != NULL);
Py_XDECREF(i);
return iterable;
}
// Iterate over the object
PyObject *iterator = PyObject_GetIter(sipPy);
PyObject *item;
std::vector<TYPE> *V = new std::vector<TYPE>();
while ((item = PyIter_Next(iterator)))
{
if (!sipCanConvertToInstance(item, sipClass_TYPE, SIP_NOT_NONE))
{
PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to TYPE");
*sipIsErr = 1;
break;
}
int state;
TYPE* p = reinterpret_cast<TYPE*>(
sipConvertToInstance(item, sipClass_TYPE, 0, SIP_NOT_NONE, &state, sipIsErr));
if (!*sipIsErr)
V->push_back(*p);
sipReleaseInstance(p, sipClass_TYPE, state);
Py_DECREF(item);
}
Py_DECREF(iterator);
if (*sipIsErr)
{
delete V;
return 0;
}
*sipCppPtr = V;
return sipGetState(sipTransferObj);
%End
};
// ****************************************************
// Specialization for std::vector<double>
// ****************************************************
%MappedType std::vector<double>
{
%TypeHeaderCode
#include <vector>
%End
%ConvertFromTypeCode
PyObject *l;
// Create the Python list of the correct length.
if ((l = PyList_New(sipCpp -> size())) == NULL)
return NULL;
// Go through each element in the C++ instance and convert it to a
// wrapped object.
for (int i = 0; i < (int)sipCpp -> size(); ++i)
{
// Add the wrapper to the list.
PyList_SET_ITEM(l, i, PyFloat_FromDouble(sipCpp -> at(i)));
}
// Return the Python list.
return l;
%End
%ConvertToTypeCode
// Check if type is compatible
if (sipIsErr == NULL)
{
// Must be any iterable
PyObject *i = PyObject_GetIter(sipPy);
bool iterable = (i != NULL);
Py_XDECREF(i);
return iterable;
}
// Iterate over the object
PyObject *iterator = PyObject_GetIter(sipPy);
PyObject *item;
// Maximum number of elements
int len = PyObject_Size(sipPy);
std::vector<double> *V = new std::vector<double>();
V->reserve(len);
if (len)
{
while ((item = PyIter_Next(iterator)))
{
if (!PyNumber_Check(item))
{
PyErr_Format(PyExc_TypeError, "object in iterable is not a number");
*sipIsErr = 1;
break;
}
PyObject *f = PyNumber_Float(item);
V->push_back(PyFloat_AsDouble(f));
Py_DECREF(f);
Py_DECREF(item);
}
Py_DECREF(iterator);
if (*sipIsErr)
{
delete V;
return 0;
}
}
*sipCppPtr = V;
return sipGetState(sipTransferObj);
%End
};
// ****************************************************
// Specialization for std::vector<int>
// ****************************************************
%MappedType std::vector<int>
{
%TypeHeaderCode
#include <vector>
%End
%ConvertFromTypeCode
PyObject *l;
// Create the Python list of the correct length.
if ((l = PyList_New(sipCpp -> size())) == NULL)
return NULL;
// Go through each element in the C++ instance and convert it to a
// wrapped object.
for (int i = 0; i < (int)sipCpp -> size(); ++i)
{
// Add the wrapper to the list.
PyList_SET_ITEM(l, i, PyInt_FromLong(sipCpp -> at(i)));
}
// Return the Python list.
return l;
%End
%ConvertToTypeCode
// Check if type is compatible
if (sipIsErr == NULL)
{
// Must be any iterable
PyObject *i = PyObject_GetIter(sipPy);
bool iterable = (i != NULL);
Py_XDECREF(i);
return iterable;
}
// Iterate over the object
PyObject *iterator = PyObject_GetIter(sipPy);
PyObject *item;
// Maximum number of elements
int len = PyObject_Size(sipPy);
std::vector<int> *V = new std::vector<int>();
V->reserve(len);
if (len)
{
while ((item = PyIter_Next(iterator)))
{
if (!PyInt_Check(item))
{
PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to float");
*sipIsErr = 1;
break;
}
int val = PyInt_AsLong(item);
V->push_back(val);
Py_DECREF(item);
}
Py_DECREF(iterator);
if (*sipIsErr)
{
delete V;
return 0;
}
}
*sipCppPtr = V;
return sipGetState(sipTransferObj);
%End
};
More information about the PyQt
mailing list