How to pass array(array of long in java) from Java to C++ using Swig

前端 未结 1 1290
清歌不尽
清歌不尽 2020-12-19 10:48

I have sample .h file like below:

class Test
{
public:
       void SelectValues(long long values[])
};

I used SWIG and created JNI interfac

相关标签:
1条回答
  • 2020-12-19 11:26

    What you've done here with array_functions is correct and usable, but it's focused on wrapping the C++ code directly, and it won't be using an underlying Java array. You can use it with something like:

    SWIGTYPE_p_long_long array = MyLib.new_long_long_array(100); // new array with 100 elements.
    for (int i = 0; i < 100; ++i) {
      long_long_array_setitem(array, i, i);
    }
    new Test().SelectValues(array);
    

    where array is just a proxy to a "real" C++ chunk of memory that you can read/write from on the Java side and pass to wrapped functions.

    I'm guessing from your question that you're interested in making this feel more "natural" on the Java side. SWIG also provides array_class which wraps an array similarly, but as a proper object rather than a collection of static functions. For example if you changed your interface file to use array_class(long long, LongLongArray) instead of array_functions you can do:

    LongLongArray array = new LongLongArray(100);
    for (int i = 0; i < 100; ++i) {
       array.setitem(i,i); 
    }
    new Test().SelectValues(array.cast());
    

    You can actually make SWIG do more than that with a few typemaps if you want to. Your example class doesn't take a length in SelectValues so I'm assuming you're 0 terminating the array although you can equally well pass the length in with a few simple changes.

    (For convenience I %inlined your class to reduce the number of files and added a dummy implementation of it for testing)

    %module MyLib
    
    %{
    #include <iostream>
    %}
    
    %typemap(jtype) long long values[] "long[]"
    %typemap(jstype) long long values[] "long[]"
    %typemap(javain) long long values[] "$javainput"
    %typemap(jni) long long values[] "jlongArray"
    %typemap(in) long long values[] {
      jboolean isCopy;
      $1 = JCALL2(GetLongArrayElements, jenv, $input, &isCopy);
    }
    
    %inline %{
    class Test
    {
    public:
      void SelectValues(long long values[]) {
        while (*values) {
          std::cout << *values++ << "\n";
        }
      }
    };
    %}
    

    Here we said that both the proxy class SWIG generates and the JNI class it generates are going to be working with long[], i.e. a Java array. We don't need to do anything in the Java Proxy to Java JNI conversion, so the javain typemap is just a straight pass through. On the C++ side of the JNI that's a jlongArray, which we also specified in another typemap.

    We then need an in typemap to arrange converting from jlongArray to long long[] in the C++ side - there's a single JNI call for that and we don't care if it's a copy or the actual memory from the JVM that we end up using. (You might care if you wanted to modify the results and make it visible back inside Java for example)

    I tested this with:

    public class run {
      public static void main(String[] argv) {
        System.loadLibrary("mylib");
        long arr[] = {100,99,1,0}; // Terminate with 0!
        new Test().SelectValues(arr);
      }
    }
    

    Which did exactly as you'd hope.

    0 讨论(0)
提交回复
热议问题