Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>There's an alternative to <a href="https://stackoverflow.com/a/11018918/168175">this answer</a>, it's very different and gives a more natural solution to this problem, closer to what you were looking for originally. The other suggestions were focused on adding overloads (tedious, manual) or making the <code>array_class</code>es implement a common interface one way or another. </p> <p>What it overlooks is that <code>Object</code> is a good match for <code>void*</code> in Java most of the time. Even <a href="https://stackoverflow.com/questions/8781022/is-an-array-an-object-in-java">arrays in Java are <code>Object</code>s</a>. This means if you have SWIG map <code>void*</code> to <code>Object</code> it'll accept as inputs any arrays you might want to pass in. With a bit of care and some JNI we can then get a pointer to the start of that array to pass in to the function. Obviously we need to reject non array <code>Object</code>s with an exception though.</p> <p>We still end up writing some (private) helper functions to arrange extraction of the real underlying pointer and release it when done, but the nice thing about this solution is that we only have to do this once and then we end up with a typemap that can be used for any functions which take an array as <code>void*</code> like this.</p> <p>I ended up with the following SWIG interface for this solution: </p> <pre><code>%module test %{ #include &lt;stdint.h&gt; void foo(void *in) { printf("%p, %d, %g\n", in, *(jint*)in, *(jdouble*)in); } %} %typemap(in,numinputs=0) JNIEnv *env "$1 = jenv;" %javamethodmodifiers arr2voidd "private"; %javamethodmodifiers arr2voidi "private"; %javamethodmodifiers freearrd "private"; %javamethodmodifiers freearri "private"; %inline %{ jlong arr2voidd(JNIEnv *env, jdoubleArray arr) { void *ptr = (*env)-&gt;GetDoubleArrayElements(env, arr, NULL); return (intptr_t)ptr; } void freearrd(JNIEnv *env, jdoubleArray arr, jlong map) { void *ptr = 0; ptr = *(void **)&amp;map; (*env)-&gt;ReleaseDoubleArrayElements(env, arr, ptr, JNI_ABORT); } jlong arr2voidi(JNIEnv *env, jintArray arr) { void *ptr = (*env)-&gt;GetIntArrayElements(env, arr, NULL); return (intptr_t)ptr; } void freearri(JNIEnv *env, jintArray arr, jlong map) { void *ptr = 0; ptr = *(void **)&amp;map; (*env)-&gt;ReleaseIntArrayElements(env, arr, ptr, JNI_ABORT); } %} %pragma(java) modulecode=%{ private static long arrPtr(Object o) { if (o instanceof double[]) { return arr2voidd((double[])o); } else if (o instanceof int[]) { return arr2voidi((int[])o); } throw new IllegalArgumentException(); } private static void freeArrPtr(Object o, long addr) { if (o instanceof double[]) { freearrd((double[])o, addr); return; } else if (o instanceof int[]) { freearri((int[])o, addr); return; } throw new IllegalArgumentException(); } %} %typemap(jstype) void *arr "Object" %typemap(javain,pre=" long tmp$javainput = arrPtr($javainput);",post=" freeArrPtr($javainput, tmp$javainput);") void *arr "tmp$javainput" void foo(void *arr); </code></pre> <p>This implements it for two array types, there's a small finite number and you could use fragments or macros to help with this too. Internally SWIG uses a <code>jlong</code> to represent pointers. So for each array type we need a function that returns a pointer for a given array and another one to release it. These are private and part of the module class - nobody other than the module needs to know how this works.</p> <p>There's then two functions which take the <code>Object</code> and use <code>instanceof</code> (ugly, but arrays in Java don't have any other common base or interface and generics don't help) and call the correct function to get/release the pointers.</p> <p>With these then it's just two typemaps to set up SWIG to use it for all <code>void *arr</code> arguments. The jstype typemap instructs SWIG to use <code>Object</code> for <code>void*</code> in these cases. The javain typemap arranges for a temporary local variable to hold the pointer (in a <code>long</code>) and then for it to be used to make the call and to be cleaned up once the call has succeed or failed. </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. COThis is a very nice technique indeed, and your test code works perfectly. It *almost* works for me in context except for the detail that my C functions actually take `const void *` and not `void *`. I can avoid writing wrapper functions with `%apply void *in {const void *argv};`, but unless I redeclare all of my functions (there are 50!), as taking `void *`, I get: _Can't apply (void *in). No typemaps are defined_. Is there any way I can just tell "treat `const void *` as `void *`"?
      singulars
    2. CO@JamieBullock I think you're probably using `%apply` in the wrong place. You need to use it *after* all the typemaps have been defined. So I added `%apply void *arr { const void *argv }` at the end of the interface and it worked fine. You also need to be careful to match the parameter names exactly if you're matching on that - my example had them called `arr` but the `%apply` you showed calls it `in`, not sure if that's because you renamed it all though.
      singulars
    3. COthat doesn't work for me, but you are right `%apply void *in {const void *argv};` was erroneous. in the end I decided to make a 1 line script in my build script to generate a redeclare.i with all of my functions redeclared as taking `void *` instead of `const void *`, and then added `%include redeclare.i` to the end of my main `.i` file. Maybe not so elegant, but it does work. This combined with your solution above now lets me freely pass Java arrays as void *, which is great. Thanks!
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload