Правильный способ взаимодействия с массивами с помощью SWIG
Я немного потерян с картами типов в swig и тем, как использовать массивы. Я подготовил рабочий пример, который использует массивы между java и c, используя swig, но я не знаю, является ли это правильным способом сделать это.
В основном я хочу передать байтовый массивbyte[]
из java в c как & # xB4; знаковый char * `+ его размер, измените его в c и посмотрите изменения в java, создайте массив в c и используйте его в Java.
Я взглянул на эти вопросы: Как передать массив (массив long в Java) из Java в C ++, используя Swig, Передайте массив в упакованную функцию как указатель + размер или диапазон, Как я могу заставить Swig правильно обернуть буфер char *, модифицированный в C как Java-то или другое?
И на самом деле использовали решения в качестве руководства, чтобы сделать пример.
Это мой код в файле arrays.h:
#include <iostream>
bool createArray(signed char ** arrCA, int * lCA){
*lCA = 10;
*arrCA = (signed char*) calloc(*lCA, sizeof(signed char));
for(int i = 0; i < *lCA; i++){
(*arrCA)[i] = i;
}
return *arrCA != NULL;
}
bool readArray(const signed char arrRA[], const int lRA){
for(int i = 0; i < lRA; i++){
std::cout << ((unsigned int) arrRA[i]) << " ";
}
std::cout << std::endl;
return true;
}
bool modifyArrayValues(signed char arrMA[], const int lMA){
for(int i = 0; i < lMA; i++){
arrMA[i] = arrMA[i] * 2;
}
return true;
}
bool modifyArrayLength(signed char arrMALIn[], int lMALIn, signed char ** arrMALOut, int * lMALOut){
*lMALOut = 5;
*arrMALOut = (signed char*) calloc(*lMALOut, sizeof(signed char));
for(int i = 0; i < *lMALOut; i++){
(*arrMALOut)[i] = arrMALIn[i];
}
return true;
}
Это файл .i для swig (arrays.i):
%module arrays
%{
#include "arrays.h"
%}
%typemap(jtype) bool createArray "byte[]"
%typemap(jstype) bool createArray "byte[]"
%typemap(jni) bool createArray "jbyteArray"
%typemap(javaout) bool createArray { return $jnicall; }
%typemap(in, numinputs=0) signed char ** arrCA (signed char * temp) "$1=&temp;"
%typemap(in, numinputs=0) int * lCA (int l) "$1=&l;"
%typemap(argout) (signed char ** arrCA, int * lCA) {
$result = JCALL1(NewByteArray, jenv, *$2);
JCALL4(SetByteArrayRegion, jenv, $result, 0, *$2, (const jbyte*) *$1);
}
%typemap(out) bool createArray {
if (!$1) {
return NULL;
}
}
%typemap(jtype) (const signed char arrRA[], const int lRA) "byte[]"
%typemap(jstype) (const signed char arrRA[], const int lRA) "byte[]"
%typemap(jni) (const signed char arrRA[], const int lRA) "jbyteArray"
%typemap(javain) (const signed char arrRA[], const int lRA) "$javainput"
%typemap(in,numinputs=1) (const signed char arrRA[], const int lRA) {
$1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
$2 = JCALL1(GetArrayLength, jenv, $input);
}
%typemap(freearg) (const signed char arrRA[], const int lRA) {
// Or use 0 instead of ABORT to keep changes if it was a copy
JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT);
}
%typemap(jtype) (signed char arrMA[], const int lMA) "byte[]"
%typemap(jstype) (signed char arrMA[], const int lMA) "byte[]"
%typemap(jni) (signed char arrMA[], const int lMA) "jbyteArray"
%typemap(javain) (signed char arrMA[], const int lMA) "$javainput"
%typemap(in, numinputs=1) (signed char arrMA[], const int lMA) {
$1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
$2 = JCALL1(GetArrayLength, jenv, $input);
}
%typemap(freearg) (signed char arrMA[], const int lMA) {
JCALL3(ReleaseByteArrayElements, jenv, $input, $1, 0);
}
%typemap(jtype) (signed char arrMALIn[], int lMALIn) "byte[]"
%typemap(jstype) (signed char arrMALIn[], int lMALIn) "byte[]"
%typemap(jni) (signed char arrMALIn[], int lMALIn) "jbyteArray"
%typemap(javain) (signed char arrMALIn[], int lMALIn) "$javainput"
%typemap(in, numinputs=1) (signed char arrMALIn[], int lMALIn) {
$1 = JCALL2(GetByteArrayElements, jenv, $input, NULL);
$2 = JCALL1(GetArrayLength, jenv, $input);
}
%typemap(freearg) (signed char arrMALIn[], int lMALIn) {
JCALL3(ReleaseByteArrayElements, jenv, $input, $1, JNI_ABORT);
}
%typemap(jtype) bool modifyArrayLength "byte[]"
%typemap(jstype) bool modifyArrayLength "byte[]"
%typemap(jni) bool modifyArrayLength "jbyteArray"
%typemap(javaout) bool modifyArrayLength { return $jnicall; }
%typemap(in, numinputs=0) signed char ** arrMALOut (signed char * temp) "$1=&temp;"
%typemap(in, numinputs=0) int * lMALOut (int l) "$1=&l;"
%typemap(argout) (signed char ** arrMALOut, int * lMALOut) {
$result = JCALL1(NewByteArray, jenv, *$2);
JCALL4(SetByteArrayRegion, jenv, $result, 0, *$2, (const jbyte*) *$1);
}
%typemap(out) bool modifyArrayLength {
if (!$1) {
return NULL;
}
}
%include "arrays.h"
И, наконец, код Java для тестирования:
public class Run{
static {
System.loadLibrary("Arrays");
}
public static void main(String[] args){
byte[] test = arrays.createArray();
printArray(test);
arrays.readArray(test);
arrays.modifyArrayValues(test);
printArray(test);
byte[] test2 = arrays.modifyArrayLength(test);
printArray(test2);
}
private static void printArray(byte[] arr){
System.out.println("Array ref: " + arr);
if(arr != null){
System.out.println("Array length: " + arr.length);
System.out.print("Arrays items: ");
for(int i =0; i < arr.length; i++){
System.out.print(arr[i] + " ");
}
}
System.out.println();
}
}
Пример работает, но я не уверен, что это правильный путь, я имею в виду:
Есть ли более простой способ достичь того же результата?
у этого кода есть утечки памяти (с одной стороны, я думаю, что это потому, что я делаю вызов, но я не освобождаю его, но с другой стороны, я передаю его в SetByteArrayRegion, так что, возможно, освобождение приведет к ошибке)?
Копирует ли SetByteArrayRegion значения или только ссылку? Например, если вместо того, чтобы фактически выполнять вызов, что делать, если получить массив из объекта c ++ по ссылке, которая будет уничтожена при выходе из области действия?
правильно ли возвращается массив в Java при его обнулении?
Есть ли способ указать, где и где применяется карта типов? Я имею в виду, что в коде .i я предоставил карту типов для каждой функции, где я думаю, что я мог бы использовать некоторые из них, но если бы были другие функции с таким же параметры, которые я не хочу их отображать, как я могу это сделать, я не могу изменить имя параметров функций.
Я видел возможность carrays.i, описанную в этом вопросеКак передать массивы из Java в C ++ с помощью Swig?, но это означает, что если размер массива составляет 1000 элементов, и я хочу отправить его через сокет Java или создать из него строку, я должен сделать 1 вызов JNI для каждого элемента массива. И я на самом деле хочуbyte[]
в стороне Java нет набора функций для доступа к лежащему в основе массиву, поэтому уже существующий код работает без изменений.
Контекст: Причина, по которой я хочу достичь этого, состоит в том, что есть библиотека, которая имеет некоторые функциональные возможности, но важная часть здесь заключается в том, что она позволяет импортировать и экспортировать данные из библиотеки с использованием буферов протоколов Google. Таким образом, код, связанный с этим вопросом, выглядит следующим образом:
class SomeLibrary {
bool export(const std::string & sName, std::string & toExport);
bool import(const std::string & sName, const std::string & toImport);
}
Дело в том, что Protobuf в C ++ использует std :: string для хранения данных, но эти данные являются двоичными, поэтому их нельзя вернуть как обычную строку Java, так как они усекаются, подробнее об этом вSwig: конвертировать возвращаемый тип std :: string (binary) в java byte [].
Так что моя идея состоит в том, чтобы вернуться к Javabyte[]
для сериализованного Protobuf (как это делает Java-версия буферов протокола) и принятьbyte[]
для разбора protobufs. Чтобы не получитьSWIGTYPE_p_std_string
во втором аргументе экспорта и имеющем строку String для второго аргумента импорта y, обернули обе функции, используя% extension, например так:
%extend SomeLibrary{
bool export(const std::string & sName, char ** toExportData, int * toExportLength);
bool import(const std::string & sName, char * toImportData, int toImportLength);
}
И теперь я должен быть в состоянии сделать типографские карты.
Но для того, чтобы быть более общим, я попросил общее манипулирование массивами от Java до SWIG,having родная яваbyte[]
.