I have sample .h file like below:
class Test
{
public:
void SelectValues(long long values[])
};
I used SWIG and created JNI interface from below .i file
%module MyLib
%include "carrays.i"
%array_functions(long long, long_long_array )
%{
#include "Test.h"
%}
/* Let's just grab the original header file here */
%include <windows.i> /*This line is used for calling conventions*/
% include "Test.h"
When I create Java method it creates like:
public void SelectValues(SWIGTYPE_p_long_long includeKeys)
Also for JNI file it is taking argument as jlongArray
but taking simple jlong
only. Due to this issue I cannot create array of long like long[]={1L,2L}
and pass it to above Java method to call appropriate JNI method.
I want SWIG to generate interface in such a way that I can pass above mentioned array to my C++ method.
I have read this question, but it didn't help me see how to pass an array from Java to C++.
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 %inline
d 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With