2012-07-20 6 views
8

としてラップ関数に配列を渡しますこれらの関数の2番目のパラメータを提供するために、配列の(既知の)サイズを使用するためにこれらの関数をラップするにはどうすればよいですか?は次のようにヘッダを考えるとポインタ+サイズまたは範囲

+0

Javaで手動でラッパーメソッドを提供するのはどうでしょうか? Javaで配列をとるメソッドのように 'int offset、int length'パラメータも付いていません。 –

+0

@ SamuelAudet - あなたはそれを行うことができますが、それはうまく設計されたインターフェースではないと主張したいと思います。問題は、もしあなたが 'byte []'を持っているなら、それを 'signed char * 'に変換するための型マップ(たいていの場合)を書くか、'%array_class'と 'for'を使う必要があるでしょうとにかくコピーを行うループ。どちらもかなり醜いです。 – Flexo

+0

@SamuelAudet - マニュアルラッパーメソッドで回答を更新しました。私の見解ではかなり醜いです。 – Flexo

答えて

12

これらの機能のいずれかをラップするには、multi-argument typemapを使用することが重要です。

プリアンブルはSWIGにはかなり標準です。あなたは、両方のタイプとしてbyte[]を使用するようにSWIGを指示するいくつかのJava typemapsを使う必要があるでしょうけれども

%module test 

%{ 
#include "test.hh" 
%} 

%pragma(java) jniclasscode=%{ 
    static { 
    try { 
     System.loadLibrary("test"); 
    } catch (UnsatisfiedLinkError e) { 
     System.err.println("Native code library failed to load. \n" + e); 
     System.exit(1); 
    } 
    } 
%} 

まず:私は自動的に知る必要インタフェースのユーザずに共有ライブラリをロードするために私の個人的な好みのprgamaを使用しましたJavaインタフェースの一部(JNIとそれを呼び出すラッパー)生成モジュールファイルでは、JNIタイプjbyteArrayを使用します。私たちは、入力を直接SWIGインターフェースから生成したJNIに渡しています。

%typemap(jtype) (const signed char *arr, size_t sz) "byte[]" 
%typemap(jstype) (const signed char *arr, size_t sz) "byte[]" 
%typemap(jni) (const signed char *arr, size_t sz) "jbyteArray" 
%typemap(javain) (const signed char *arr, size_t sz) "$javainput" 

これが行われると、我々は多引数タイプマップを書くことができます。

%typemap(in,numinputs=1) (const signed char *arr, size_t sz) { 
    $1 = JCALL2(GetByteArrayElements, jenv, $input, NULL); 
    $2 = JCALL1(GetArrayLength, jenv, $input); 
} 

タイプマップでの仕事は、私たちが本当のものにJNI呼び出しによって与えられているものから変換することです関数は実際に入力として期待しています。私はnuminputs=1を使って2つの実際の関数の引数がJava側で1つの入力しか受け付けないことを示していましたが、これはデフォルトの値なので明示的に指定する必要はありません。

このタイプマップでは、$1がタイプマップの最初の引数、つまりこの場合の関数の最初の引数です。 Java配列の基になるストレージへのポインタ(実際にはコピーであってもなくてもかまいません)を求めて設定します。 $2を2番目のtypemap引数に設定します。

ここでJCALLnマクロは、タイプマップがCとC++ JNIの両方でコンパイルできることを確認します。言語の適切な呼び出しに展開されます。

私たちは、実際の関数呼び出しが返された後にクリーンアップするために、別のタイプマップが必要になります。

%typemap(freearg) (const signed char *arr, size_t sz) { 
    // Or use 0 instead of ABORT to keep changes if it was a copy 
    JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT); 
} 

これは、我々は、アレイで行われているJVMを伝えるためにReleaseByteArrayElementsを呼び出します。私たちが入手したJava配列オブジェクトのポインタが必要です。さらに、内容がコピーされるべきかどうかを示すパラメータを受け取ります。iffこれらは変更されており、取得したポインタは最初のコピーです。 NULLを渡した引数は、コピーを受け取ったかどうかを示すjbooleanへのオプションのポインタです)。第二の変形例について

タイプマップは、実質的に類似している:

%typemap(in,numinputs=1) (const signed char *begin, const signed char *end) { 
    $1 = JCALL2(GetByteArrayElements, jenv, $input, NULL); 
    const size_t sz = JCALL1(GetArrayLength, jenv, $input); 
    $2 = $1 + sz; 
} 

%typemap(freearg) (const signed char *begin, const signed char *end) { 
    // Or use 0 instead of ABORT to keep changes if it was a copy 
    JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT); 
} 

%typemap(jtype) (const signed char *begin, const signed char *end) "byte[]" 
%typemap(jstype) (const signed char *begin, const signed char *end) "byte[]" 
%typemap(jni) (const signed char *begin, const signed char *end) "jbyteArray" 
%typemap(javain) (const signed char *begin, const signed char *end) "$javainput" 

唯一の違いはbeginポインタを使用してend arugmentを計算するローカル変数szの使用です。

唯一のことはやって左我々だけ書いたタイプマップを使用して、ヘッダファイル自体をラップするためにSWIGを伝えることです:

%include "test.hh" 

私はこれらの両方の機能をテストした:

public class run { 
    public static void main(String[] argv) { 
    byte[] arr = {0,1,2,3,4,5,6,7}; 
    System.out.println("Foo:"); 
    test.foo(arr); 
    System.out.println("Bar:"); 
    test.bar(arr); 
    } 
} 

これは期待通りに機能しました。

便宜のため、これを書いて使ったファイルをmy siteで共有しました。そのアーカイブ内のすべてのファイルのすべての行は、この回答を順番に実行することで再構築できます。私たちはどんなJNIせずに全体を行っている可能性参考のため


は、私たちが本当の機能が期待する形式に(ピュアJavaで)入力を変換使用し、過負荷を発生させるために%pragma(java) modulecodeを使用して、呼び出します。 (SWIGTYPE_p_signed_charbyte[]から行くには全く些細な方法はありません)右タイプにデータを取得するために必要な明白な(2)のコピーのほか

%module test 

%{ 
#include "test.hh" 
%} 

%include <carrays.i> 
%array_class(signed char, ByteArray); 

%pragma(java) modulecode = %{ 
    // Overload foo to take an array and do a copy for us: 
    public static void foo(byte[] array) { 
    ByteArray temp = new ByteArray(array.length); 
    for (int i = 0; i < array.length; ++i) { 
     temp.setitem(i, array[i]); 
    } 
    foo(temp.cast(), array.length); 
    // if foo can modify the input array we'll need to copy back to: 
    for (int i = 0; i < array.length; ++i) { 
     array[i] = temp.getitem(i); 
    } 
    } 

    // How do we even get a SWIGTYPE_p_signed_char for end for bar? 
    public static void bar(byte[] array) { 
    ByteArray temp = new ByteArray(array.length); 
    for (int i = 0; i < array.length; ++i) { 
     temp.setitem(i, array[i]); 
    } 
    bar(temp.cast(), make_end_ptr(temp.cast(), array.length)); 
    // if bar can modify the input array we'll need to copy back to: 
    for (int i = 0; i < array.length; ++i) { 
     array[i] = temp.getitem(i); 
    } 
    } 
%} 

// Private helper to make the 'end' pointer that bar expects 
%javamethodmodifiers make_end_ptr "private"; 
%inline { 
    signed char *make_end_ptr(signed char *begin, int sz) { 
    return begin+sz; 
    } 
} 

%include "test.hh" 

%pragma(java) jniclasscode=%{ 
    static { 
    try { 
     System.loadLibrary("test"); 
    } catch (UnsatisfiedLinkError e) { 
     System.err.println("Native code library failed to load. \n" + e); 
     System.exit(1); 
    } 
    } 
%} 

とバックこれは、別の欠点がありますするためのモジュールファイルがあったであろうことを関数foobarに固有のものですが、以前に書いたtypemapsは特定の関数に固有のものではなく、2つの関数を持つ関数があると同じ関数で複数の場合でも適用されます範囲または2つのポインタ+長さの組み合わせ。このようにする利点の1つは、他のラップされた関数があると、SWIGTYPE_p_signed_charが返ってきた場合でも、必要に応じて使用できるオーバーロードが残っていることです。 %array_classByteArrayがある場合でも、あなたはまだendを生成するために必要なJavaのポインタ算術演算を行うことはできません。

ここに示した元の方法は、Javaできれいなインターフェースを提供し、余分なコピーを作成して再利用するという追加の利点があります。

%inline { 
    void foo(jbyteArray arr) { 
    // take arr and call JNI to convert for foo 
    } 
    void bar(jbyteArray arr) { 
    // ditto for bar 
    } 
} 

これらは、Javaインターフェイスでオーバーロードとして提示されているが、それらは特定のモジュールはまだだ:


しかし、ラッピングの別の代替的なアプローチはfoobarのためにいくつかの%inlineオーバーロードを書くことであろうさらにここで必要とされるJNIは、そうでなければ必要であったよりも複雑です。jenvを何とか保留するように手配する必要があります。これはデフォルトではアクセスできません。オプションは、それを得るための遅い呼び出し、またはパラメータを自動的に埋め込むnuminputs=0タイプマップです。いずれにせよ、複数引数の型マップははるかに良いようです。

関連する問題