[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