Gegeben eine Kopfzeile wie:
%Vor%(Ich habe C ++ 11 hier aus praktischen Gründen verwendet, dies könnte entweder C oder C ++ sein, wenn Sie die Implementierungen geändert haben)
Wie kann ich diese Funktionen so umschließen, dass nur ein Array auf der Java-Seite verwendet wird und die (bekannte) Größe des Arrays verwendet wird, um den zweiten Parameter für diese Funktionen bereitzustellen?
Das Entscheidende dabei ist, dass Sie, um eine dieser Funktionen zu umbrechen, eine Argumenttypemap .
Die Präambel ist ziemlich Standard für SWIG. Ich benutzte mein persönliches favorisiertes prgama, um automatisch die geteilte Bibliothek zu laden, ohne dass der Benutzer der Schnittstelle es wissen musste:
%Vor% Zunächst müssen Sie jedoch ein paar Java-Typmaps verwenden, um SWIG anzuweisen,% zu verwenden. co_de% als Typ der beiden Teile der Java-Schnittstelle - der JNI und der Wrapper, der sie aufruft. In der Generate-Modul-Datei verwenden wir den JNI-Typ byte[]
. Wir übergeben die Eingabe direkt von der SWIG-Schnittstelle an die JNI, die sie generiert.
Wenn das erledigt ist, können wir eine Multi-Argument Typmap schreiben:
%Vor% Der Job der In-Typ-Map besteht darin, von dem, was wir durch den JNI-Aufruf erhalten haben, zu dem zu konvertieren, was die reale Funktion wirklich als Eingabe erwartet. Ich habe jbyteArray
verwendet, um anzuzeigen, dass die beiden echten Funktionsargumente nur eine Eingabe auf der Java-Seite haben, aber dies ist ohnehin der Standardwert, also ist es nicht erforderlich, dies explizit anzugeben.
In diesem Typ ist numinputs=1
das erste Argument der typecap, d. h. das erste Argument unserer Funktion in diesem Fall. Wir legen das fest, indem wir nach einem Zeiger auf den zugrunde liegenden Speicher des Java-Arrays fragen (was eine Kopie wirklich sein kann oder nicht). Wir setzen , das zweite typemap-Argument auf die Größe des Arrays.
Die Makros stellen sicher, dass die Typenkarte sowohl mit C als auch mit C ++ JNI kompiliert werden kann. Es wird auf den entsprechenden Aufruf für die Sprache erweitert.
Wir brauchen eine andere type map, um aufzuräumen, sobald der echte Funktionsaufruf zurückgegeben wurde:
%Vor% Dies ruft JCALLn
auf, um der JVM mitzuteilen, dass wir mit dem Array fertig sind. Es benötigt den Zeiger und das Java-Array-Objekt, von dem wir es erhalten haben. Außerdem benötigt es einen Parameter, der angibt, ob der Inhalt zurück kopiert werden sollte, wenn er geändert wurde und der Zeiger, den wir bekommen haben, eine Kopie war. (Das Argument, das wir NULL übergeben haben, ist ein optionaler Zeiger auf ein ReleaseByteArrayElements
, das angibt, ob wir eine Kopie erhalten haben.)
Für die zweite Variante sind die Typemaps im Wesentlichen ähnlich:
%Vor% Der einzige Unterschied besteht in der Verwendung der lokalen Variablen jboolean
, um das sz
-Argument mit dem end
-Zeiger zu berechnen.
Das einzige, was noch zu tun ist, ist, SWIG zu sagen, die Header-Datei selbst zu umbrechen, indem wir die Typemaps verwenden, die wir gerade geschrieben haben:
%Vor%Ich habe beide Funktionen getestet mit:
%Vor%Was wie erwartet funktioniert hat.
Aus praktischen Gründen habe ich die Dateien, die ich zum Schreiben verwendet habe, auf meiner Website geteilt . Jede Zeile jeder Datei in diesem Archiv kann rekonstruiert werden, indem diese Antwort der Reihe nach befolgt wird.
Als Referenz hätten wir die ganze Sache ohne irgendwelche JNI-Aufrufe durchführen können, indem wir begin
verwenden, um eine Überladung zu generieren, die wir verwenden, um die Eingabe (in reinem Java) in die von den realen Funktionen erwartete Form zu konvertieren. Dafür wäre die Moduldatei gewesen:
Neben den offensichtlichen (zwei) Kopien, die erforderlich sind, um die Daten in den richtigen Typ zu bringen (es gibt keine einfache Möglichkeit, von %pragma(java) modulecode
zu byte[]
zu wechseln), hat dies einen weiteren Nachteil - es ist spezifisch für die Funktionen SWIGTYPE_p_signed_char
und foo
, während die zuvor geschriebenen Typemaps nicht für eine bestimmte Funktion spezifisch sind - sie werden überall dort angewendet, wo sie übereinstimmen, sogar mehrmals in derselben Funktion, wenn Sie eine Funktion haben, die zwei Bereiche oder zwei Zeiger + benötigt Längenkombinationen. Der einzige Vorteil dieser Vorgehensweise besteht darin, dass Sie, wenn Sie andere umbrochene Funktionen haben, die Ihnen bar
zurückgeben, immer noch die Überladungen zur Verfügung haben, die Sie verwenden können, wenn Sie dies wünschen. Selbst für den Fall, dass Sie SWIGTYPE_p_signed_char
von ByteArray
haben, können Sie die Zeigerarithmetik in Java immer noch nicht ausführen, um %array_class
für Sie zu generieren.
Der ursprüngliche Weg zeigt eine sauberere Oberfläche in Java mit den zusätzlichen Vorteilen, keine übermäßigen Kopien zu erstellen und wiederverwendbar zu sein.
Noch ein anderer alternativer Ansatz zum Umbrechen wäre, einige end
Überladungen für %inline
und foo
zu schreiben:
Diese sind in der Java-Schnittstelle als Überlastungen dargestellt, aber sie sind immer noch modulspezifisch und zusätzlich ist das JNI, das hier benötigt wird, komplexer als es sonst sein müsste - du musst irgendwie arrangieren, um bar
zu bekommen, auf das standardmäßig nicht zugegriffen werden kann. Die Optionen sind ein langsamer Aufruf, um es zu erhalten, oder eine jenv
typemap, die den Parameter automatisch ausfüllt. In jedem Fall scheint die Multi-Argument-Typ-Karte viel schöner.