I am developing some SWIG-generated Java bindings for a C library. The library contains functions that take parameters of type void *. On the C side these would
The simplest solution is to use SWIG's float and an array of int and any other types you care about. These can be converted to SWIGTYPE_p_float etc. trivially using the cast() member function. The problem is that this can't automatically be converted to a SWIGTYPE_p_void from within Java. You could in theory call:
new SWIGTYPE_p_void(FloatArray.getCPtr(myfloatarr));
but for various reasons (not least it's cumbersome) that's less than ideal. (It also has issues with memory ownership and garbage collection).
So instead I defined an interface:
public interface VoidPtr {
public long asVoidPtr();
}
That we can make the wrapped version of your library take as input and the array classes FloatArray, IntArray etc. implement for us.
This ends up with the module file:
%module test
%include
%typemap(javainterfaces) FloatArray "VoidPtr"
%typemap(javainterfaces) IntArray "VoidPtr"
%typemap(javacode) FloatArray %{
public long asVoidPtr() {
return getCPtr(this);
}
%}
%typemap(javacode) IntArray %{
public long asVoidPtr() {
return getCPtr(this);
}
%}
%array_class(float, FloatArray);
%array_class(int, IntArray);
%typemap(jstype) void *arr "VoidPtr"
%typemap(javain) void *arr "$javainput.asVoidPtr()"
void foo(void *arr);
Which modifies void *arr to be treated as our VoidPtr type and automatically calls the asVoidPtr() method. You could use typemap copying or macros to make this less repetitive. (Note, there's a possible issue with premature garbage collection that might need to be addressed here depending on how you planned to use this)
This allows us to write code like:
public class run {
public static void main(String[] argv) {
FloatArray arr = new FloatArray(100);
test.foo(arr);
}
}
I think this is the easiest, cleanest solution. There are several other ways you could solve this though:
It's also possible to write some code that would take an actual Java array rather than just the SWIG array_class and implement this interface by calling a JNI function to obtain the underlying pointer. You'd have to write a version of this for every primitive type though, just like the above.
An interface file could then look something like:
%module test
%{
void foo(void *arr);
%}
%typemap(in,numinputs=0) JNIEnv *env "$1 = jenv;"
%rename(foo) fooFloat;
%rename(foo) fooInt;
%inline %{
void fooFloat(JNIEnv *env, jfloatArray arr) {
jboolean isCopy;
foo((*env)->GetFloatArrayElements(env, arr, &isCopy));
// Release after call with desired semantics
}
void fooInt(JNIEnv *env, jintArray arr) {
jboolean isCopy;
foo((*env)->GetIntArrayElements(env, arr, &isCopy));
// Release after call
}
%}
void foo(void *arr);
Which then gives you overloads of foo which take float[] and int[] as well as SWIGTYPE_p_void.
You could use a trick with a union:
%inline %{
union Bodge {
void *v;
float *f;
int *i;
};
%}
although this is considered bad form, it does generate you a Java interface that can be used to convert from SWIGTYPE_p_int to SWIGTYPE_p_void.
I think it's possible to make FloatArray inherit from SWIGTYPE_p_void, something like the following compiled but untested code:
%module test
%include
%typemap(javabase) FloatArray "SWIGTYPE_p_void"
%typemap(javabody) FloatArray %{
private long swigCPtr; // Minor bodge to work around private variable in parent
private boolean swigCMemOwn;
public $javaclassname(long cPtr, boolean cMemoryOwn) {
super(cPtr, cMemoryOwn);
this.swigCPtr = SWIGTYPE_p_void.getCPtr(this);
swigCMemOwn = cMemoryOwn;
}
%}
%array_class(float, FloatArray);
void foo(void *arr);
This duplicates the pointer on the Java side, but nothing changes that (currently) in either the void pointer or array classes so that's not as big a problem as it first seems. (You could also make it protected in the base class with an alternative typemap I think, or use a modified version of carrays.i that gets swigCPtr via the getCPtr function instead)