Search code examples
c++python-3.xlinuxg++swig

SWIG: how to wrap a function that takes reference to int64_t as parameter?


My interface file TestRef.i:

%module test_ref
%{
#include <iostream>
%}

%include <stdint.i>
%include <typemaps.i>
%inline %{
struct Result {
    uint64_t len;
    void* data;
};

Result read(int64_t& idx) {
    std::cout << idx << std::endl; // just to use idx
    idx++;
    return Result{1, nullptr};
}

void set_value(double& a) {
  a = 42.;
}

%}
%apply int64_t& INOUT { int64_t& idx };

%apply double& INOUT { double& a };
void set_value(double& a);

My goal is to call read(), which returns a C struct (actually packed) and an int64_t via the reference parameter.

Here is how I built:

$ swig -python -c++ -I/usr/include TestRef.i 
$ g++ -fPIC -c TestRef_wrap.cxx -I/opt/rh/rh-python38/root/usr/include/python3.8 -std=c++17 -O3
$ g++ -shared TestRef_wrap.o -o _test_ref.so -lrt

Here is the error I got:

>>> import test_ref
>>> idx = 1000
>>> p = test_ref.read(idx)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/hc/test/cpp/test_ref.py", line 79, in read
    return _test_ref.read(idx)
TypeError: in method 'read', argument 1 of type 'int64_t &'

Some post suggested that reference will be "returned" and so I should do:

>>> p, idx = test_ref.read(idx)

But same error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/hc/test/cpp/test_ref.py", line 79, in read
    return _test_ref.read(idx)
TypeError: in method 'read', argument 1 of type 'int64_t &'

Then, I found this post.

And I tried (TestRef.i above already included set()):

>>> a = 0.0
>>> a = set_value(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/hc/test/cpp/test_ref.py", line 66, in set_value
    return _test_ref.set_value(a)
TypeError: in method 'set_value', argument 1 of type 'double &'

I am using SWIG 4.0.


Solution

  • According to this post, [t]he typemap must also be declared before SWIG parses test.

    Changing my TestRef.i to

    %module test_ref
    %{
    #include <iostream>
    %}
    
    %include <stdint.i>
    %include <typemaps.i>
    
    %apply int64_t& INOUT { int64_t& idx };
    
    %apply double& INOUT { double& a };
    
    %inline %{
    struct Result {
        uint64_t len;
        void* data;
    };
    
    Result read(int64_t& idx) {
        std::cout << idx << std::endl; // just to use idx
        idx++;
        return Result{1, nullptr};
    }
    
    void set(double& a) {
      a = 42.;
    }
    

    works:

    >>> import test_ref
    >>> idx = 1024
    >>> p, idx = test_ref.read(idx)
    1024
    >>> print(idx)
    1025
    >>>