I have a library of C classes that I am building a Python interface for using SWIG. Many of these classes have methods that take in a double* array or int* array parameter without inputting a size. For example, there are many methods that have a declaration like one of the following:
void func(double* array);
void func2(double* array, double unrelated_parameter, ...);
I would like to be able to use these functions in Python, with the user passing in a Python numpy array. The size of these arrays are never given as a parameter to the function. The size of the input array is given in the constructor of the objects of these C classes and it is assumed that every input array that is given as a parameter to these class methods will have the same size. All of the numpy examples I have seen require me to add an int array_size parameter to the C method/function being wrapped.
Is there a way to wrap these C functions without having change the API of my entire C library to include an int array_size parameter for every single function? Ideally, a user should pass in a Python numpy array and SWIG will automatically convert it to a double or int array on the C side.
I have already included numpy.i and followed the instructions here: https://numpy.org/doc/stable/reference/swig.interface-file.html but am getting errors like the following:
TypeError: in method 'func', argument 2 of type 'double *'
CodePudding user response:
One way I can think of is to suppress the "no size" version of the function and extend the class to have a version with a throw-away dimension variable that uses the actual parameter in the class.
Example:
test.i
%module test
%{
#define SWIG_FILE_WITH_INIT
class Test {
public:
int _dim; // needs to be public, or have a public accessor.
Test(int dim) : _dim(dim) {}
double func(double* array) {
double sum = 0.0;
for(int i = 0; i < _dim; i)
sum = array[i];
return sum;
}
};
%}
%include "numpy.i"
%init %{
import_array();
%}
%apply (double* IN_ARRAY1, int DIM1) {(double* array, int /*unused*/)};
%ignore Test::func; // so the one-parameter version isn't wrapped
class Test {
public:
Test(int dim);
double func(double* array);
};
%rename("%s") Test::func; // unignore so the two-parameter version will be used.
%extend Test {
double func(double* array, int /*unused*/) {
return $self->func(array);
}
}
Demo:
>>> import test
>>> t = test.Test(5)
>>> import numpy as np
>>> a = np.array([1.5,2.0,2.5,3.75,4.25])
>>> t.func(a)
14.0