としてラップ関数に配列を渡しますこれらの関数の2番目のパラメータを提供するために、配列の(既知の)サイズを使用するためにこれらの関数をラップするにはどうすればよいですか?は次のようにヘッダを考えるとポインタ+サイズまたは範囲
答えて
これらの機能のいずれかをラップするには、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_char
へbyte[]
から行くには全く些細な方法はありません)右タイプにデータを取得するために必要な明白な(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);
}
}
%}
とバックこれは、別の欠点がありますするためのモジュールファイルがあったであろうことを関数foo
とbar
に固有のものですが、以前に書いたtypemapsは特定の関数に固有のものではなく、2つの関数を持つ関数があると同じ関数で複数の場合でも適用されます範囲または2つのポインタ+長さの組み合わせ。このようにする利点の1つは、他のラップされた関数があると、SWIGTYPE_p_signed_char
が返ってきた場合でも、必要に応じて使用できるオーバーロードが残っていることです。 %array_class
のByteArray
がある場合でも、あなたはまだ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インターフェイスでオーバーロードとして提示されているが、それらは特定のモジュールはまだだ:
しかし、ラッピングの別の代替的なアプローチはfoo
とbar
のためにいくつかの%inline
オーバーロードを書くことであろうさらにここで必要とされるJNIは、そうでなければ必要であったよりも複雑です。jenv
を何とか保留するように手配する必要があります。これはデフォルトではアクセスできません。オプションは、それを得るための遅い呼び出し、またはパラメータを自動的に埋め込むnuminputs=0
タイプマップです。いずれにせよ、複数引数の型マップははるかに良いようです。
- 1. このように、数字のリストを考えるとフラットサブ範囲
- 2. は、どのように、次のXMLを考えるとタグ名
- 3. は次のように可能な値を考えるとスプリット
- 4. に特定の日付は、日付範囲のリストを考えると
- 5. は、次のように私は範囲を比較交差点
- 6. は次第に考える
- 7. はのは、次のことを考えてみましょう
- 8. doOnNext()は、次のチェーンを考えると
- 9. 次のようにURLを考えるとfoo.bar.car.com
- 10. は `次を考えるとアンダースコア
- 11. はどのようにJavaScriptのコード次を考えると、外側部材
- 12. 範囲外になるローカル変数...考えている
- 13. ダイナミックプログラマのように考えるには?
- 14. 次を考えるとSQL
- 15. 次のようなXMLを考えるとElementTreeの
- 16. にはどうすればボタンは、次のコードを考える
- 17. 考えているスフィンクス - 範囲内の複数のフィールド条件
- 18. は常にビューモデル次を考える
- 19. エラー私たちは次のことを考えるのPython 3
- 20. はどのように考える
- 21. 範囲は、私はこのようなngFor *巣にしようとした
- 22. パスフルスライス範囲は、以下のコードを考慮したパラメータ
- 23. スウィフト3:このように範囲をフィルタリングすることが可能であったスウィフト2では範囲
- 24. 次のようになります文書を考えるとRavenDB
- 25. 次のドロップダウンメニューと同じようにHTML5範囲の「スライダー」を作成します。
- 26. 範囲タイプを考慮したオーバーラップ番号範囲の特定方法
- 27. -Wundefは、次のコードを考える
- 28. は、次のXMLを考える
- 29. パンダは、次のデータフレームを考えるグループバリュー
- 30. パンダは、次のデータフレームを考えるグループ
Javaで手動でラッパーメソッドを提供するのはどうでしょうか? Javaで配列をとるメソッドのように 'int offset、int length'パラメータも付いていません。 –
@ SamuelAudet - あなたはそれを行うことができますが、それはうまく設計されたインターフェースではないと主張したいと思います。問題は、もしあなたが 'byte []'を持っているなら、それを 'signed char * 'に変換するための型マップ(たいていの場合)を書くか、'%array_class'と 'for'を使う必要があるでしょうとにかくコピーを行うループ。どちらもかなり醜いです。 – Flexo
@SamuelAudet - マニュアルラッパーメソッドで回答を更新しました。私の見解ではかなり醜いです。 – Flexo