Правильный способ взаимодействия с массивами с помощью 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[].

Ответы на вопрос(2)

Ваш ответ на вопрос