Passing array from C# to SWIG as Span<T>

62 views Asked by At

I'm looking for a way to pass an array from C# to C/C++ code without additional data copy. At the first glance using built-in SWIG typemap for C# is a way to go. But there is a couple of things that bugging me.

First thing: I want to use C# spans, because my data is not always represented by C# array.

Second thing: I want to pass span or array length to C/C++ code automatically. I.e. I want to wrap this two-argument C function:

// Calculator.hpp
long long CalculateSum(int* numbers, int count);

Into this single-argument C# method:

// Calculator.cs
public static long CalculateSum(Span<int> numbers)
{
    // ...
}

This is what I managed to do so far:

// Calculator.i

%module Calculator
%{
    #include "Calculator.hpp"
%}

// A macro based on `CSHARP_ARRAYS_FIXED` from `arrays_csharp.i`:
%define CSHARP_FIXED_SPAN( CTYPE, CSTYPE )
    %typemap(ctype)   CTYPE FIXED_SPAN "CTYPE*"
    %typemap(imtype)  CTYPE FIXED_SPAN "global::System.IntPtr"
    %typemap(cstype)  CTYPE FIXED_SPAN "global::System.Span<CSTYPE>"
    %typemap(csin,
            pre=       "    fixed ( CSTYPE* swig_ptrTo_$csinput = $csinput ) {",
            terminator="    }") 
                    CTYPE FIXED_SPAN "(global::System.IntPtr)swig_ptrTo_$csinput"

    %typemap(in)      CTYPE FIXED_SPAN "$1 = $input;"
    %typemap(freearg) CTYPE FIXED_SPAN ""
    %typemap(argout)  CTYPE FIXED_SPAN ""
%enddef // CSHARP_FIXED_SPAN

// Instantiate fixed span typemap from the macro only for int/int types:
CSHARP_FIXED_SPAN(int, int)

// Apply the typemap to the `CalculateSum` method signature:
%apply int FIXED_SPAN {int *numbers}

// Apply `unsafe` modifier to generated C# method:
%csmethodmodifiers CalculateSum "public unsafe";

%include "Calculator.hpp"

It solves the first thing (I'm able to use spans now). But it does not solve the second thing, because the count argument still gets into generated C# code:

// Calculator.cs (generated)
public unsafe static long CalculateSum(global::System.Span<int> numbers, int count) {
  fixed ( int* swig_ptrTo_numbers = numbers ) {
  {
    long ret = CalculatorPINVOKE.CalculateSum((global::System.IntPtr)swig_ptrTo_numbers, count);
    return ret;
  }
  }
}

How do I get rid of the count argument in the generated wrapper mehtod? I.e. how to make SWIG generate C# wrapper code which will pass numbers.Length to C/C++ code?

0

There are 0 answers