[PyQt] converting std::vector to PyList
Patrick Stinson
patrickkidd.lists at gmail.com
Fri Mar 30 08:36:53 BST 2007
good greif! That's a good response. I didn't realize you could wrap
templates like that.
Another way I found to get around this problem was to pass a python
list as a SIP_PYLIST argument and populate it with the values returned
from the C++ method after calling it with a temporary.
I shall copy your code, and I shall use your code.
On 3/27/07, Giovanni Bajo <rasky at develer.com> wrote:
> 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
>
>
> // 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
> };
>
>
--
Patrick Kidd Stinson
http://www.patrickkidd.com/
http://pkaudio.sourceforge.net/
http://pksampler.sourceforge.net/
More information about the PyQt
mailing list