JNI: add generic support for array-types

The typeSignature for a type T[] is always "[" + typeSignature<t>, so we
can just implicitly support arrays of any known type. To prevent support
for multi-dimensional arrays, make sure that the underlying type is not
also an array.

By adding a QJniTypes::isArrayType in addition (that is true for any
type with a signature starting with '['), methods like
QJniObject::callMethod could then return a special QJniArray type that
provides array-specific functionality.

As a drive-by, and since all lines need to be touched to add braces,
replace std::is_same<>::value with std::is_same_v.

Change-Id: Iccadf03cfceb8544381a8f635bb54baeddf46c99
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
bb10
Volker Hilsheimer 2022-10-07 20:56:53 +02:00
parent ad736e9150
commit 2ef130a41d
2 changed files with 54 additions and 32 deletions

View File

@ -148,70 +148,76 @@ static void staticAssertTypeMismatch()
template<typename T>
constexpr auto typeSignature()
{
if constexpr(std::is_same<T, jobject>::value)
if constexpr(std::is_array_v<T>) {
using UnderlyingType = typename std::remove_extent<T>::type;
static_assert(!std::is_array_v<UnderlyingType>,
"typeSignature() does not handle multi-dimensional arrays");
return String("[") + typeSignature<UnderlyingType>();
} else if constexpr(std::is_same_v<T, jobject>) {
return String("Ljava/lang/Object;");
else if constexpr(std::is_same<T, jclass>::value)
} else if constexpr(std::is_same_v<T, jclass>) {
return String("Ljava/lang/Class;");
else if constexpr(std::is_same<T, jstring>::value)
} else if constexpr(std::is_same_v<T, jstring>) {
return String("Ljava/lang/String;");
else if constexpr(std::is_same<T, jobjectArray>::value)
} else if constexpr(std::is_same_v<T, jobjectArray>) {
return String("[Ljava/lang/Object;");
else if constexpr(std::is_same<T, jthrowable>::value)
} else if constexpr(std::is_same_v<T, jthrowable>) {
return String("Ljava/lang/Throwable;");
else if constexpr(std::is_same<T, jbooleanArray>::value)
} else if constexpr(std::is_same_v<T, jbooleanArray>) {
return String("[Z");
else if constexpr(std::is_same<T, jbyteArray>::value)
} else if constexpr(std::is_same_v<T, jbyteArray>) {
return String("[B");
else if constexpr(std::is_same<T, jshortArray>::value)
} else if constexpr(std::is_same_v<T, jshortArray>) {
return String("[S");
else if constexpr(std::is_same<T, jintArray>::value)
} else if constexpr(std::is_same_v<T, jintArray>) {
return String("[I");
else if constexpr(std::is_same<T, jlongArray>::value)
} else if constexpr(std::is_same_v<T, jlongArray>) {
return String("[J");
else if constexpr(std::is_same<T, jfloatArray>::value)
} else if constexpr(std::is_same_v<T, jfloatArray>) {
return String("[F");
else if constexpr(std::is_same<T, jdoubleArray>::value)
} else if constexpr(std::is_same_v<T, jdoubleArray>) {
return String("[D");
else if constexpr(std::is_same<T, jcharArray>::value)
} else if constexpr(std::is_same_v<T, jcharArray>) {
return String("[C");
else if constexpr(std::is_same<T, jboolean>::value)
} else if constexpr(std::is_same_v<T, jboolean>) {
return String("Z");
else if constexpr(std::is_same<T, bool>::value)
} else if constexpr(std::is_same_v<T, bool>) {
return String("Z");
else if constexpr(std::is_same<T, jbyte>::value)
} else if constexpr(std::is_same_v<T, jbyte>) {
return String("B");
else if constexpr(std::is_same<T, jchar>::value)
} else if constexpr(std::is_same_v<T, jchar>) {
return String("C");
else if constexpr(std::is_same<T, char>::value)
} else if constexpr(std::is_same_v<T, char>) {
return String("C");
else if constexpr(std::is_same<T, jshort>::value)
} else if constexpr(std::is_same_v<T, jshort>) {
return String("S");
else if constexpr(std::is_same<T, short>::value)
} else if constexpr(std::is_same_v<T, short>) {
return String("S");
else if constexpr(std::is_same<T, jint>::value)
} else if constexpr(std::is_same_v<T, jint>) {
return String("I");
else if constexpr(std::is_same<T, int>::value)
} else if constexpr(std::is_same_v<T, int>) {
return String("I");
else if constexpr(std::is_same<T, uint>::value)
} else if constexpr(std::is_same_v<T, uint>) {
return String("I");
else if constexpr(std::is_same<T, jlong>::value)
} else if constexpr(std::is_same_v<T, jlong>) {
return String("J");
else if constexpr(std::is_same<T, long>::value)
} else if constexpr(std::is_same_v<T, long>) {
return String("J");
else if constexpr(std::is_same<T, jfloat>::value)
} else if constexpr(std::is_same_v<T, jfloat>) {
return String("F");
else if constexpr(std::is_same<T, float>::value)
} else if constexpr(std::is_same_v<T, float>) {
return String("F");
else if constexpr(std::is_same<T, jdouble>::value)
} else if constexpr(std::is_same_v<T, jdouble>) {
return String("D");
else if constexpr(std::is_same<T, double>::value)
} else if constexpr(std::is_same_v<T, double>) {
return String("D");
else if constexpr(std::is_same<T, void>::value)
} else if constexpr(std::is_same_v<T, void>) {
return String("V");
else if constexpr(IsStringType<T>::value)
} else if constexpr(IsStringType<T>::value) {
static_assert(!IsStringType<T>::value, "Don't use a literal type, call data!");
else
} else {
staticAssertTypeMismatch();
}
}
template<bool flag = false>
@ -247,6 +253,13 @@ static constexpr bool isObjectType()
}
}
template<typename T>
static constexpr bool isArrayType()
{
constexpr auto signature = typeSignature<T>();
return signature.startsWith('[');
}
template<typename T>
static constexpr void assertPrimitiveType()
{

View File

@ -52,14 +52,17 @@ Q_DECLARE_JNI_CLASS(QtTextToSpeech, "org/qtproject/qt/android/speech/QtTextToSpe
static_assert(QtJniTypes::className<QtJniTypes::QtTextToSpeech>() == "org/qtproject/qt/android/speech/QtTextToSpeech");
static_assert(QtJniTypes::fieldSignature<jint>() == "I");
static_assert(QtJniTypes::fieldSignature<jint[]>() == "[I");
static_assert(QtJniTypes::fieldSignature<jint>() != "X");
static_assert(QtJniTypes::fieldSignature<jint>() != "Ljava/lang/Object;");
static_assert(QtJniTypes::fieldSignature<jlong>() == "J");
static_assert(QtJniTypes::fieldSignature<jstring>() == "Ljava/lang/String;");
static_assert(QtJniTypes::fieldSignature<jobject>() == "Ljava/lang/Object;");
static_assert(QtJniTypes::fieldSignature<jobject[]>() == "[Ljava/lang/Object;");
static_assert(QtJniTypes::fieldSignature<jobjectArray>() == "[Ljava/lang/Object;");
static_assert(QtJniTypes::fieldSignature<QJniObject>() == "Ljava/lang/Object;");
static_assert(QtJniTypes::fieldSignature<QtJavaWrapper>() == "Lorg/qtproject/qt/android/QtJavaWrapper;");
static_assert(QtJniTypes::fieldSignature<QtJavaWrapper[]>() == "[Lorg/qtproject/qt/android/QtJavaWrapper;");
static_assert(QtJniTypes::fieldSignature<QtCustomJniObject>() == "Lorg/qtproject/qt/android/QtCustomJniObject;");
static_assert(QtJniTypes::methodSignature<void>() == "()V");
@ -82,6 +85,12 @@ static_assert(QtJniTypes::isObjectType<jobject>());
static_assert(QtJniTypes::isObjectType<jobjectArray>());
static_assert(QtJniTypes::isObjectType<QtCustomJniObject>());
static_assert(!QtJniTypes::isArrayType<jint>());
static_assert(QtJniTypes::isArrayType<jint[]>());
static_assert(QtJniTypes::isArrayType<jobject[]>());
static_assert(QtJniTypes::isArrayType<jobjectArray>());
static_assert(QtJniTypes::isArrayType<QtJavaWrapper[]>());
static_assert(QtJniTypes::String("ABCDE").startsWith("ABC"));
static_assert(QtJniTypes::String("ABCDE").startsWith("A"));
static_assert(QtJniTypes::String("ABCDE").startsWith("ABCDE"));