この答えには別の方法があります。それは非常に異なり、この問題に対してより自然な解決策を提供し、最初に探していたものに近づけます。他の提案は、オーバーロード (面倒、手動) を追加するか、何らかの方法でarray_class
es に共通のインターフェイスを実装させることに焦点を当てていました。
それが見落としているのは、ほとんどの場合、これが Java にObject
適しているということです。Java の配列でvoid*
さえsです。これは、SWIG マップを持っている場合、渡したい配列を入力として受け入れることを意味します。少し注意して JNI を使用すると、その配列の先頭へのポインターを取得して、関数に渡すことができます。明らかに、例外を除いて非配列を拒否する必要があります。Object
void*
Object
Object
実際の基になるポインターの抽出を調整し、完了したらそれを解放するために、いくつかの (プライベート) ヘルパー関数を作成することになりますが、このソリューションの優れている点は、これを 1 回実行するだけで、次の型マップになることです。このように配列を取る任意の関数に使用できます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);
これは 2 つの配列型に対して実装されます。有限数は少なく、フラグメントやマクロを使用してこれを支援することもできます。内部的には、SWIG はjlong
ポインターを表すために a を使用します。したがって、配列の型ごとに、特定の配列のポインターを返す関数と、それを解放する別の関数が必要です。これらは非公開で、モジュール クラスの一部です。モジュール以外の誰も、これがどのように機能するかを知る必要はありません。
Object
次に、 and を使用する2 つの関数がありinstanceof
(醜いですが、Java の配列には他の共通ベースまたはインターフェイスがなく、ジェネリックは役に立ちません)、正しい関数を呼び出してポインターを取得/解放します。
これらを使用すると、SWIG をすべてのvoid *arr
引数に使用するように設定するのは 2 つのタイプマップだけです。jstype タイプマップは、これらの場合に使用Object
するように SWIG に指示します。void*
javain typemap は、一時的なローカル変数がポインターを ( 内にlong
) 保持し、それを使用して呼び出しを行い、呼び出しが成功または失敗したときにクリーンアップされるように調整します。