Есть альтернатива этому ответу, она очень отличается и дает более естественное решение этой проблемы, ближе к тому, что вы искали для изначально. Другие предложения были сосредоточены на добавлении перегрузок (утомительных, ручных) или на том, чтобы array_class
es так или иначе реализовывали общий интерфейс.
Он упускает из виду, что Object
в большинстве случаев хорошо подходит для void*
в Java. Даже массивы в Java равны Object
s. Это означает, что если у вас есть карта SWIG с void*
по Object
, она примет в качестве входных данных любые массивы, которые вы, возможно, захотите передать. С некоторой осторожностью и некоторым JNI мы можем затем получить указатель на начало этого массива для передачи в функция. Очевидно, нам нужно отклонить немассивные Object
s с исключением.
Мы по-прежнему пишем некоторые (частные) вспомогательные функции, чтобы организовать извлечение реального базового указателя и освободить его, когда закончите, но хорошая вещь в этом решении заключается в том, что нам нужно сделать это только один раз, а затем мы получим карту типов, которая может использоваться для любых функций, которые принимают массив как void*
, как это.
В итоге я получил следующий интерфейс SWIG для этого решения:
%module test
%{
#include <stdint.h>
void foo(void *in) {
printf("%p, %d, %g\n", in, *(jint*)in, *(jdouble*)in);
}
%}
%typemap(in,numinputs=0) JNIEnv *env "$1 = jenv;"
%javamethodmodifiers arr2voidd "private";
%javamethodmodifiers arr2voidi "private";
%javamethodmodifiers freearrd "private";
%javamethodmodifiers freearri "private";
%inline %{
jlong arr2voidd(JNIEnv *env, jdoubleArray arr) {
void *ptr = (*env)->GetDoubleArrayElements(env, arr, NULL);
return (intptr_t)ptr;
}
void freearrd(JNIEnv *env, jdoubleArray arr, jlong map) {
void *ptr = 0;
ptr = *(void **)↦
(*env)->ReleaseDoubleArrayElements(env, arr, ptr, JNI_ABORT);
}
jlong arr2voidi(JNIEnv *env, jintArray arr) {
void *ptr = (*env)->GetIntArrayElements(env, arr, NULL);
return (intptr_t)ptr;
}
void freearri(JNIEnv *env, jintArray arr, jlong map) {
void *ptr = 0;
ptr = *(void **)↦
(*env)->ReleaseIntArrayElements(env, arr, ptr, JNI_ABORT);
}
%}
%pragma(java) modulecode=%{
private static long arrPtr(Object o) {
if (o instanceof double[]) {
return arr2voidd((double[])o);
}
else if (o instanceof int[]) {
return arr2voidi((int[])o);
}
throw new IllegalArgumentException();
}
private static void freeArrPtr(Object o, long addr) {
if (o instanceof double[]) {
freearrd((double[])o, addr);
return;
}
else if (o instanceof int[]) {
freearri((int[])o, addr);
return;
}
throw new IllegalArgumentException();
}
%}
%typemap(jstype) void *arr "Object"
%typemap(javain,pre=" long tmp$javainput = arrPtr($javainput);",post=" freeArrPtr($javainput, tmp$javainput);") void *arr "tmp$javainput"
void foo(void *arr);
Это реализует его для двух типов массивов, есть небольшое конечное число, и вы также можете использовать фрагменты или макросы, чтобы помочь с этим. Внутри SWIG использует jlong
для представления указателей. Итак, для каждого типа массива нам нужна функция, которая возвращает указатель на данный массив, и еще одна, чтобы освободить его. Они частные и являются частью класса модуля — никто, кроме самого модуля, не должен знать, как это работает.
Затем есть две функции, которые принимают Object
и используют instanceof
(уродливо, но массивы в Java не имеют какой-либо другой общей базы или интерфейса, и дженерики не помогают) и вызывают правильную функцию для получения/освобождения указателей.
С ними остается всего две карты типов, чтобы настроить SWIG на использование для всех void *arr
аргументов. Карта типов jstype предписывает SWIG использовать Object
вместо void*
в этих случаях. Карта типов javain обеспечивает временную локальную переменную для хранения указателя (в long
), а затем для его использования для выполнения вызова и очистки после успешного или неудачного вызова.
person
Flexo
schedule
14.06.2012