这个答案有一个替代方案,它非常不同,并且为这个问题提供了一个更自然的解决方案,更接近你最初寻找的东西。其他建议集中在添加重载(繁琐、手动)或使array_class
es 以一种或另一种方式实现公共接口。
它忽略了大部分时间在 Java中Object
是一个很好的匹配。void*
甚至Java 中的数组也是Object
s。这意味着,如果您有 SWIG 映射void*
到Object
它,它将接受您可能想要传入的任何数组作为输入。稍加注意和一些 JNI,我们就可以获取指向该数组开头的指针以传递给函数。显然,我们需要拒绝非数组Object
,但有一个例外。
我们最终仍然会编写一些(私有)辅助函数来安排提取真正的底层指针并在完成后释放它,但是这个解决方案的好处是我们只需要这样做一次,然后我们最终得到一个类型映射可用于任何void*
像这样采用数组的函数。
我最终得到了这个解决方案的以下 SWIG 界面:
%module test
%{
#include <stdint.h>
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)->GetDoubleArrayElements(env, arr, NULL);
return (intptr_t)ptr;
}
void freearrd(JNIEnv *env, jdoubleArray arr, jlong map) {
void *ptr = 0;
ptr = *(void **)↦
(*env)->ReleaseDoubleArrayElements(env, arr, ptr, JNI_ABORT);
}
jlong arr2voidi(JNIEnv *env, jintArray arr) {
void *ptr = (*env)->GetIntArrayElements(env, arr, NULL);
return (intptr_t)ptr;
}
void freearri(JNIEnv *env, jintArray arr, jlong map) {
void *ptr = 0;
ptr = *(void **)↦
(*env)->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);
这为两种数组类型实现了它,有一个小的有限数,您也可以使用片段或宏来帮助解决这个问题。在内部 SWIG 使用 ajlong
来表示指针。因此,对于每种数组类型,我们都需要一个函数,该函数返回一个给定数组的指针并释放另一个指针。这些是私有的并且是模块类的一部分——除了模块之外没有人需要知道它是如何工作的。
然后有两个函数接受Object
并使用instanceof
(丑陋,但Java中的数组没有任何其他公共基础或接口,泛型没有帮助)并调用正确的函数来获取/释放指针。
有了这些,只需两个类型图即可设置 SWIG 以将其用于所有void *arr
参数。jstype 类型映射指示 SWIG在这些情况下使用Object
for 。void*
javain 类型映射安排一个临时局部变量来保存指针(在 a 中long
),然后将其用于进行调用,并在调用成功或失败后进行清理。