I'd like to develop (yet another) wrapper for java arrays in JNI code using C++ templates. Main goal is to improve my C++ template programming skills.
I compile the code using Android NDK (compiler is Clang 6.0.2)
What I've managed to do so far:
#include <jni.h>
template <typename T>
struct TypeToObjectType;
template <>
struct TypeToObjectType<jbyteArray>
{
typedef jbyte type;
};
template <>
struct TypeToObjectType<jintArray>
{
typedef jint type;
};
template <typename javaArrayT, typename nativeT>
class Java_array{
JNIEnv *env;
jboolean is_copy;
jsize array_len;
javaArrayT array;
typename TypeToObjectType<javaArrayT>::type *array_elements;
public:
Java_array(JNIEnv *_env, javaArrayT _array)
: env(_env)
, array(_array)
, array_len(-1)
{
array_elements = env->GetByteArrayElements(array, &is_copy); //TODO: make it resolving automatically to other primitives
}
~Java_array() {
env->ReleaseByteArrayElements(array, array_elements, JNI_ABORT);
}
jsize len(){
if (array_len < 0)
array_len = env->GetArrayLength(array);
return array_len;
}
operator nativeT* () const {
return reinterpret_cast<nativeT*>(array_elements);
};
};
This does not work for int[]
, float[]
and other arrays except byte[]
, since this class calls GetByteArrayElements
.
I use struct TypeToObjectType
to establish mapping jbyteArray
-> jbyte
, jintArray
-> jint
.
This mapping is missing part java type -> JEnv
method calls, that is jbyteArray
-> (GetByteArrayElements
, ReleaseByteArrayElements
), jintArray
-> (GetIntArrayElements
, ReleaseIntArrayElements
)`
How can I do it?
How can I improve my code using features from C++11, C++14?
You can add pointer to members to your trait.
template <>
struct TypeToObjectType<jbyteArray>
{
typedef jbyte type;
static constexpr jbyte * (JNIEnv::* const GetElements)(jbyteArray, jboolean *) = &JNIEnv::GetByteArrayElements;
static constexpr void (JNIEnv::* const ReleaseElements)(jbyteArray, jbyte *, decltype(JNI_ABORT)) = &JNIEnv::ReleaseByteArrayElements;
};
template <>
struct TypeToObjectType<jintArray>
{
typedef jint type;
static constexpr jint * (JNIEnv::* const GetElements)(jintArray, jboolean *) = &JNIEnv::GetIntArrayElements;
static constexpr void (JNIEnv::* const ReleaseElements)(jintArray, jint *, decltype(JNI_ABORT)) = &JNIEnv::ReleaseIntArrayElements;
};
Which you call through slightly different syntax
Java_array(JNIEnv *_env, javaArrayT _array)
: env(_env)
, array(_array)
, array_len(-1)
{
array_elements = (env->*TypeToObjectType<javaArrayT>::GetElements)(array, &is_copy);
}
~Java_array() {
(env->*TypeToObjectType<javaArrayT>::ReleaseElements)(array, array_elements, JNI_ABORT);
}