Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Python, how to use a C++ function which returns an allocated array of structs via a ** parameter?

Tags:

python

swig

I'd like to use some existing C++ code, NvTriStrip, in a Python tool.

SWIG easily handles the functions with simple parameters, but the main function, GenerateStrips, is much more complicated.

What do I need to put in the SWIG interface file to indicate that primGroups is really an output parameter and that it must be cleaned up with delete[]?

///////////////////////////////////////////////////////////////////////////
// GenerateStrips()
//
// in_indices: input index list, the indices you would use to render
// in_numIndices: number of entries in in_indices
// primGroups: array of optimized/stripified PrimitiveGroups
// numGroups: number of groups returned
//
// Be sure to call delete[] on the returned primGroups to avoid leaking mem
//
bool GenerateStrips( const unsigned short* in_indices,
                     const unsigned int    in_numIndices,
                     PrimitiveGroup**      primGroups,
                     unsigned short*       numGroups,
                     bool                  validateEnabled = false );

FYI, here is the PrimitiveGroup declaration:

enum PrimType
{
    PT_LIST,
    PT_STRIP,
    PT_FAN
};

struct PrimitiveGroup
{
    PrimType type;
    unsigned int numIndices;
    unsigned short* indices;

    PrimitiveGroup() : type(PT_STRIP), numIndices(0), indices(NULL) {}
    ~PrimitiveGroup()
    {
        if(indices)
            delete[] indices;
        indices = NULL;
    }
};
like image 652
Jon-Eric Avatar asked May 24 '10 14:05

Jon-Eric


People also ask

How can a function return an array from a struct?

You can't return arrays from functions — period. You can return pointers though, provided the storage will continue to exist after the function returns. Or you can pass a pointer to the function pointing to the storage that the function should use. Don't forget to pass the size of the array too.

How do you return a pointer to an array from a function in C?

C programming does not allow to return an entire array as an argument to a function. However, you can return a pointer to an array by specifying the array's name without an index.

Can you store a struct in an array?

A structure may contain elements of different data types – int, char, float, double, etc. It may also contain an array as its member. Such an array is called an array within a structure. An array within a structure is a member of the structure and can be accessed just as we access other elements of the structure.

What is C library in Python?

C (and less commonly, Fortran) libraries are a necessary evil in Python since they significantly speed up compute-intensive routines, such as math calculations. This makes them indispensable to data analysis and machine learning packages, from TensorFlow to NumPy to Scikit-Learn.


2 Answers

Have you looked at the documentation of SWIG regarding their "cpointer.i" and "carray.i" libraries? They're found here. That's how you have to manipulate things unless you want to create your own utility libraries to accompany the wrapped code. Here's the link to the Python handling of pointers with SWIG.

Onto your question on getting it to recognize input versus output. They've got another section in the documentation here, that describes exactly that. You lable things OUTPUT in the *.i file. So in your case you'd write:

%inline{
extern bool GenerateStrips( const unsigned short* in_dices,
                            const unsigned short* in_numIndices,
                            PrimitiveGroup** OUTPUT,
                            unsigned short* numGroups,
                            bool validated );
%}

which gives you a function that returns both the bool and the PrimitiveGroup* array as a tuple.

Does that help?

like image 83
wheaties Avatar answered Oct 05 '22 02:10

wheaties


It's actually so easy to make python bindings for things directly that I don't know why people bother with confusing wrapper stuff like SWIG.

Just use Py_BuildValue once per element of the outer array, producing one tuple per row. Store those tuples in a C array. Then Call PyList_New and PyList_SetSlice to generate a list of tuples, and return the list pointer from your C function.

like image 41
apenwarr Avatar answered Oct 05 '22 00:10

apenwarr