Manera correcta de interactuar con matrices utilizando SWIG

Estoy un poco perdido con typemaps en swig y cómo usar arreglos. He preparado un ejemplo de trabajo que utiliza matrices entre java y c usando swig, pero no sé si es la forma correcta de hacerlo.

Básicamente quiero pasar una matriz de bytesbyte[] de java a c como un caracter firmado * `+ su tamaño, modifíquelo en c y vea los cambios en java y cree una matriz en c y utilícelo en Java.

He echado un vistazo a estas preguntas:Cómo pasar un array (array de long en java) de Java a C ++ usando Swig, Pase una matriz a una función ajustada como puntero + tamaño o rango, ¿Cómo puedo hacer que Swig envuelva correctamente un búfer char * que se modifique en C como algo de Java u otro?

Y de hecho usé las soluciones como una guía para hacer el ejemplo.

Este es mi código en el archivo 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;
}

Este es el archivo .i para 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"

Y finalmente el código de Java para probarlo:

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();
    }
}

El ejemplo funciona, pero no estoy seguro de que esa sea la forma correcta, quiero decir:

¿Hay una manera más fácil de lograr el mismo resultado?

¿este código tiene fugas de memoria (por un lado creo que sí porque hago callocs pero no lo libero, pero por otro lado lo paso a SetByteArrayRegion, por lo que liberarlo causaría un error)?

¿SetByteArrayRegion copia los valores o solo la referencia ?, por ejemplo, si en lugar de hacer un calloc, ¿qué sucede si se obtiene una matriz de un objeto c ++ por referencia que se destruirá cuando salga del alcance?

¿la matriz devuelta a Java se libera correctamente al anularla?

¿hay una manera de especificar desde dónde se aplica un mapa de tipos ?, quiero decir, en el código .i proporcioné un mapa de tipos para cada función, donde creo que podría reutilizar algunas de ellas, pero si hubiera otras funciones con la misma parámetros que no quiero tipografiar, no puedo modificar el nombre de los parámetros de las funciones.

He visto la posibilidad de carrays.i descrita en esta pregunta¿Cómo paso matrices de Java a C ++ usando Swig?, pero eso implica que si el tamaño de la matriz es de 1000 elementos y quiero enviarlo a través de un Socket de Java o crear una cadena a partir de ella, tengo que hacer 1 llamada JNI para cada elemento de la matriz. Y en realidad quiero unbyte[] en el lado de Java, no es un conjunto de funciones para acceder a la matriz subyacente, por lo que el código ya existente funciona sin modificaciones.

Contexto: la razón por la que quiero lograr esto es que hay una biblioteca que tiene alguna funcionalidad, pero la parte importante aquí es que permite importar y exportar datos de la biblioteca haciendo uso de los búferes de protocolos de Google. Así que el código relacionado con esta pregunta se ve así:

class SomeLibrary {

  bool export(const std::string & sName, std::string & toExport);

  bool import(const std::string & sName, const std::string & toImport);

}

La cosa es que Protobuf en C ++ usa std :: string para almacenar los datos, pero estos datos son binarios, por lo que no pueden devolverse como una cadena Java normal porque se truncan, más de esto enSwig: convierte el tipo de retorno std :: string (binario) a byte java [].

Así que mi idea es volver a Java unbyte[] para el Protobuf serializado (al igual que la versión de Java de los búferes de protocolo) y aceptebyte[] para el análisis de protobufs. Para evitar conseguirSWIGTYPE_p_std_string en el segundo argumento de la exportación, y tener la Cadena para el segundo argumento de importación y ha envuelto ambas funciones usando% extend, de esta manera:

%extend SomeLibrary{

  bool export(const std::string & sName, char ** toExportData, int * toExportLength);

  bool import(const std::string & sName, char * toImportData, int toImportLength);

}

Y ahora debería poder hacer los typemaps.

Pero para ser más general, pedí el general de la manipulación de arreglos de Java a SWIG,teniendo el Java nativobyte[].

Respuestas a la pregunta(2)

Su respuesta a la pregunta