JNI: rename our compile-time String type to CTString

The type lives in the QtJniTypes namespace, which is where types end up
that are declared through the Q_DECLARE_JNI_CLASS/TYPE macros. Having a
String type in that namespace prevents us from declaring the Java String
class as a QtJniTypes type, which is silly.

Perhaps this type becomes obsolete at some point with std::string being
a constexpr type in C++23, but until then we need it. It has no ABI, so
renaming it us safe.

Until submodules are ported, leave a compatibility alias String type,
which also prevents us from declaring a String JNI class in tests until
the alias is removed in a later commit.

Change-Id: I489a40a9b9e94e6495cf54548238438e9220d5c1
Reviewed-by: Zoltan Gera <zoltan.gera@qt.io>
Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io>
Reviewed-by: Petri Virkkunen <petri.virkkunen@qt.io>
This commit is contained in:
Volker Hilsheimer 2023-09-16 11:28:49 +02:00
parent dc126de22e
commit 0022b05a9a
3 changed files with 78 additions and 77 deletions

View File

@ -45,7 +45,7 @@ constexpr auto QtJniTypes::typeSignature<QtJniTypes::Type>() \
&& Signature[sizeof(Signature) - 2] == ';', \ && Signature[sizeof(Signature) - 2] == ';', \
"Type signature needs to start with 'L' or '['" \ "Type signature needs to start with 'L' or '['" \
" and end with ';'"); \ " and end with ';'"); \
return QtJniTypes::String(Signature); \ return QtJniTypes::CTString(Signature); \
} \ } \
#define Q_DECLARE_JNI_CLASS(Type, Signature) \ #define Q_DECLARE_JNI_CLASS(Type, Signature) \
@ -53,14 +53,14 @@ Q_DECLARE_JNI_TYPE_HELPER(Type) \
template<> \ template<> \
constexpr auto QtJniTypes::className<QtJniTypes::Type>() \ constexpr auto QtJniTypes::className<QtJniTypes::Type>() \
{ \ { \
return QtJniTypes::String(Signature); \ return QtJniTypes::CTString(Signature); \
} \ } \
template<> \ template<> \
constexpr auto QtJniTypes::typeSignature<QtJniTypes::Type>() \ constexpr auto QtJniTypes::typeSignature<QtJniTypes::Type>() \
{ \ { \
return QtJniTypes::String("L") \ return QtJniTypes::CTString("L") \
+ QtJniTypes::String(Signature) \ + QtJniTypes::CTString(Signature) \
+ QtJniTypes::String(";"); \ + QtJniTypes::CTString(";"); \
} \ } \
#define Q_DECLARE_JNI_NATIVE_METHOD(...) \ #define Q_DECLARE_JNI_NATIVE_METHOD(...) \

View File

@ -18,13 +18,13 @@ namespace QtJniTypes
// a constexpr type for string literals of any character width, aware of the length // a constexpr type for string literals of any character width, aware of the length
// of the string. // of the string.
template<size_t N_WITH_NULL, typename BaseType = char> template<size_t N_WITH_NULL, typename BaseType = char>
struct String struct CTString
{ {
BaseType m_data[N_WITH_NULL] = {}; BaseType m_data[N_WITH_NULL] = {};
constexpr String() noexcept {} constexpr CTString() noexcept {}
// Can be instantiated (only) with a string literal // Can be instantiated (only) with a string literal
constexpr explicit String(const BaseType (&data)[N_WITH_NULL]) noexcept constexpr explicit CTString(const BaseType (&data)[N_WITH_NULL]) noexcept
{ {
for (size_t i = 0; i < N_WITH_NULL - 1; ++i) for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
m_data[i] = data[i]; m_data[i] = data[i];
@ -71,8 +71,8 @@ struct String
} }
template<size_t N2_WITH_NULL> template<size_t N2_WITH_NULL>
friend inline constexpr bool operator==(const String<N_WITH_NULL> &lhs, friend inline constexpr bool operator==(const CTString<N_WITH_NULL> &lhs,
const String<N2_WITH_NULL> &rhs) noexcept const CTString<N2_WITH_NULL> &rhs) noexcept
{ {
if constexpr (N_WITH_NULL != N2_WITH_NULL) { if constexpr (N_WITH_NULL != N2_WITH_NULL) {
return false; return false;
@ -86,57 +86,60 @@ struct String
} }
template<size_t N2_WITH_NULL> template<size_t N2_WITH_NULL>
friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs, friend inline constexpr bool operator!=(const CTString<N_WITH_NULL> &lhs,
const String<N2_WITH_NULL> &rhs) noexcept const CTString<N2_WITH_NULL> &rhs) noexcept
{ {
return !operator==(lhs, rhs); return !operator==(lhs, rhs);
} }
template<size_t N2_WITH_NULL> template<size_t N2_WITH_NULL>
friend inline constexpr bool operator==(const String<N_WITH_NULL> &lhs, friend inline constexpr bool operator==(const CTString<N_WITH_NULL> &lhs,
const BaseType (&rhs)[N2_WITH_NULL]) noexcept const BaseType (&rhs)[N2_WITH_NULL]) noexcept
{ {
return operator==(lhs, String<N2_WITH_NULL>(rhs)); return operator==(lhs, CTString<N2_WITH_NULL>(rhs));
} }
template<size_t N2_WITH_NULL> template<size_t N2_WITH_NULL>
friend inline constexpr bool operator==(const BaseType (&lhs)[N2_WITH_NULL], friend inline constexpr bool operator==(const BaseType (&lhs)[N2_WITH_NULL],
const String<N_WITH_NULL> &rhs) noexcept const CTString<N_WITH_NULL> &rhs) noexcept
{ {
return operator==(String<N2_WITH_NULL>(lhs), rhs); return operator==(CTString<N2_WITH_NULL>(lhs), rhs);
} }
template<size_t N2_WITH_NULL> template<size_t N2_WITH_NULL>
friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs, friend inline constexpr bool operator!=(const CTString<N_WITH_NULL> &lhs,
const BaseType (&rhs)[N2_WITH_NULL]) noexcept const BaseType (&rhs)[N2_WITH_NULL]) noexcept
{ {
return operator!=(lhs, String<N2_WITH_NULL>(rhs)); return operator!=(lhs, CTString<N2_WITH_NULL>(rhs));
} }
template<size_t N2_WITH_NULL> template<size_t N2_WITH_NULL>
friend inline constexpr bool operator!=(const BaseType (&lhs)[N2_WITH_NULL], friend inline constexpr bool operator!=(const BaseType (&lhs)[N2_WITH_NULL],
const String<N_WITH_NULL> &rhs) noexcept const CTString<N_WITH_NULL> &rhs) noexcept
{ {
return operator!=(String<N2_WITH_NULL>(lhs), rhs); return operator!=(CTString<N2_WITH_NULL>(lhs), rhs);
} }
template<size_t N2_WITH_NULL> template<size_t N2_WITH_NULL>
friend inline constexpr auto operator+(const String<N_WITH_NULL> &lhs, friend inline constexpr auto operator+(const CTString<N_WITH_NULL> &lhs,
const String<N2_WITH_NULL> &rhs) noexcept const CTString<N2_WITH_NULL> &rhs) noexcept
{ {
char data[N_WITH_NULL + N2_WITH_NULL - 1] = {}; char data[N_WITH_NULL + N2_WITH_NULL - 1] = {};
for (size_t i = 0; i < N_WITH_NULL - 1; ++i) for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
data[i] = lhs[i]; data[i] = lhs[i];
for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) for (size_t i = 0; i < N2_WITH_NULL - 1; ++i)
data[N_WITH_NULL - 1 + i] = rhs[i]; data[N_WITH_NULL - 1 + i] = rhs[i];
return String<N_WITH_NULL + N2_WITH_NULL - 1>(data); return CTString<N_WITH_NULL + N2_WITH_NULL - 1>(data);
} }
}; };
// compatibility alias until submodules are ported
template<size_t N_WITH_NULL, typename BaseType = char>
using String = CTString<N_WITH_NULL, BaseType>;
// Helper types that allow us to disable variadic overloads that would conflict // Helper types that allow us to disable variadic overloads that would conflict
// with overloads that take a const char*. // with overloads that take a const char*.
template<typename T, size_t N = 0> struct IsStringType : std::false_type {}; template<typename T, size_t N = 0> struct IsStringType : std::false_type {};
template<> struct IsStringType<const char*, 0> : std::true_type {}; template<> struct IsStringType<const char*, 0> : std::true_type {};
template<size_t N> struct IsStringType<String<N>> : std::true_type {}; template<size_t N> struct IsStringType<CTString<N>> : std::true_type {};
template<size_t N> struct IsStringType<const char[N]> : std::true_type {}; template<size_t N> struct IsStringType<const char[N]> : std::true_type {};
template<bool flag = false> template<bool flag = false>
@ -153,67 +156,67 @@ constexpr auto typeSignature()
using UnderlyingType = typename std::remove_extent_t<T>; using UnderlyingType = typename std::remove_extent_t<T>;
static_assert(!std::is_array_v<UnderlyingType>, static_assert(!std::is_array_v<UnderlyingType>,
"typeSignature() does not handle multi-dimensional arrays"); "typeSignature() does not handle multi-dimensional arrays");
return String("[") + typeSignature<UnderlyingType>(); return CTString("[") + typeSignature<UnderlyingType>();
} else if constexpr (std::is_same_v<T, jobject>) { } else if constexpr (std::is_same_v<T, jobject>) {
return String("Ljava/lang/Object;"); return CTString("Ljava/lang/Object;");
} else if constexpr (std::is_same_v<T, jclass>) { } else if constexpr (std::is_same_v<T, jclass>) {
return String("Ljava/lang/Class;"); return CTString("Ljava/lang/Class;");
} else if constexpr (std::is_same_v<T, jstring>) { } else if constexpr (std::is_same_v<T, jstring>) {
return String("Ljava/lang/String;"); return CTString("Ljava/lang/String;");
} else if constexpr (std::is_same_v<T, jobjectArray>) { } else if constexpr (std::is_same_v<T, jobjectArray>) {
return String("[Ljava/lang/Object;"); return CTString("[Ljava/lang/Object;");
} else if constexpr (std::is_same_v<T, jthrowable>) { } else if constexpr (std::is_same_v<T, jthrowable>) {
return String("Ljava/lang/Throwable;"); return CTString("Ljava/lang/Throwable;");
} else if constexpr (std::is_same_v<T, jbooleanArray>) { } else if constexpr (std::is_same_v<T, jbooleanArray>) {
return String("[Z"); return CTString("[Z");
} else if constexpr (std::is_same_v<T, jbyteArray>) { } else if constexpr (std::is_same_v<T, jbyteArray>) {
return String("[B"); return CTString("[B");
} else if constexpr (std::is_same_v<T, jshortArray>) { } else if constexpr (std::is_same_v<T, jshortArray>) {
return String("[S"); return CTString("[S");
} else if constexpr (std::is_same_v<T, jintArray>) { } else if constexpr (std::is_same_v<T, jintArray>) {
return String("[I"); return CTString("[I");
} else if constexpr (std::is_same_v<T, jlongArray>) { } else if constexpr (std::is_same_v<T, jlongArray>) {
return String("[J"); return CTString("[J");
} else if constexpr (std::is_same_v<T, jfloatArray>) { } else if constexpr (std::is_same_v<T, jfloatArray>) {
return String("[F"); return CTString("[F");
} else if constexpr (std::is_same_v<T, jdoubleArray>) { } else if constexpr (std::is_same_v<T, jdoubleArray>) {
return String("[D"); return CTString("[D");
} else if constexpr (std::is_same_v<T, jcharArray>) { } else if constexpr (std::is_same_v<T, jcharArray>) {
return String("[C"); return CTString("[C");
} else if constexpr (std::is_same_v<T, jboolean>) { } else if constexpr (std::is_same_v<T, jboolean>) {
return String("Z"); return CTString("Z");
} else if constexpr (std::is_same_v<T, bool>) { } else if constexpr (std::is_same_v<T, bool>) {
return String("Z"); return CTString("Z");
} else if constexpr (std::is_same_v<T, jbyte>) { } else if constexpr (std::is_same_v<T, jbyte>) {
return String("B"); return CTString("B");
} else if constexpr (std::is_same_v<T, jchar>) { } else if constexpr (std::is_same_v<T, jchar>) {
return String("C"); return CTString("C");
} else if constexpr (std::is_same_v<T, char>) { } else if constexpr (std::is_same_v<T, char>) {
return String("C"); return CTString("C");
} else if constexpr (std::is_same_v<T, jshort>) { } else if constexpr (std::is_same_v<T, jshort>) {
return String("S"); return CTString("S");
} else if constexpr (std::is_same_v<T, short>) { } else if constexpr (std::is_same_v<T, short>) {
return String("S"); return CTString("S");
} else if constexpr (std::is_same_v<T, jint>) { } else if constexpr (std::is_same_v<T, jint>) {
return String("I"); return CTString("I");
} else if constexpr (std::is_same_v<T, int>) { } else if constexpr (std::is_same_v<T, int>) {
return String("I"); return CTString("I");
} else if constexpr (std::is_same_v<T, uint>) { } else if constexpr (std::is_same_v<T, uint>) {
return String("I"); return CTString("I");
} else if constexpr (std::is_same_v<T, jlong>) { } else if constexpr (std::is_same_v<T, jlong>) {
return String("J"); return CTString("J");
} else if constexpr (std::is_same_v<T, long>) { } else if constexpr (std::is_same_v<T, long>) {
return String("J"); return CTString("J");
} else if constexpr (std::is_same_v<T, jfloat>) { } else if constexpr (std::is_same_v<T, jfloat>) {
return String("F"); return CTString("F");
} else if constexpr (std::is_same_v<T, float>) { } else if constexpr (std::is_same_v<T, float>) {
return String("F"); return CTString("F");
} else if constexpr (std::is_same_v<T, jdouble>) { } else if constexpr (std::is_same_v<T, jdouble>) {
return String("D"); return CTString("D");
} else if constexpr (std::is_same_v<T, double>) { } else if constexpr (std::is_same_v<T, double>) {
return String("D"); return CTString("D");
} else if constexpr (std::is_same_v<T, void>) { } else if constexpr (std::is_same_v<T, void>) {
return String("V"); return CTString("V");
} }
// else: The return type becomes void, indicating that the typeSignature // else: The return type becomes void, indicating that the typeSignature
@ -232,7 +235,7 @@ template<typename T>
constexpr auto className() constexpr auto className()
{ {
if constexpr (std::is_same_v<T, jstring>) if constexpr (std::is_same_v<T, jstring>)
return String("java/lang/String"); return CTString("java/lang/String");
else else
staticAssertClassNotRegistered(); staticAssertClassNotRegistered();
} }
@ -289,9 +292,9 @@ using ValidFieldType = std::enable_if_t<
template<typename R, typename ...Args, ValidSignatureTypes<R, Args...> = true> template<typename R, typename ...Args, ValidSignatureTypes<R, Args...> = true>
static constexpr auto methodSignature() static constexpr auto methodSignature()
{ {
return (String("(") + return (CTString("(") +
... + typeSignature<q20::remove_cvref_t<Args>>()) ... + typeSignature<q20::remove_cvref_t<Args>>())
+ String(")") + CTString(")")
+ typeSignature<R>(); + typeSignature<R>();
} }

View File

@ -21,20 +21,20 @@ struct QtJavaWrapper {};
template<> template<>
constexpr auto QtJniTypes::typeSignature<QtJavaWrapper>() constexpr auto QtJniTypes::typeSignature<QtJavaWrapper>()
{ {
return QtJniTypes::String("Lorg/qtproject/qt/android/QtJavaWrapper;"); return QtJniTypes::CTString("Lorg/qtproject/qt/android/QtJavaWrapper;");
} }
template<> template<>
constexpr auto QtJniTypes::typeSignature<QJniObject>() constexpr auto QtJniTypes::typeSignature<QJniObject>()
{ {
return QtJniTypes::String("Ljava/lang/Object;"); return QtJniTypes::CTString("Ljava/lang/Object;");
} }
struct QtCustomJniObject : QJniObject {}; struct QtCustomJniObject : QJniObject {};
template<> template<>
constexpr auto QtJniTypes::typeSignature<QtCustomJniObject>() constexpr auto QtJniTypes::typeSignature<QtCustomJniObject>()
{ {
return QtJniTypes::String("Lorg/qtproject/qt/android/QtCustomJniObject;"); return QtJniTypes::CTString("Lorg/qtproject/qt/android/QtCustomJniObject;");
} }
static_assert(QtJniTypes::typeSignature<QtJavaWrapper>() == "Lorg/qtproject/qt/android/QtJavaWrapper;"); static_assert(QtJniTypes::typeSignature<QtJavaWrapper>() == "Lorg/qtproject/qt/android/QtJavaWrapper;");
@ -46,8 +46,6 @@ static_assert(QtJniTypes::typeSignature<QtJniTypes::JavaType>() == "Lorg/qtproje
Q_DECLARE_JNI_TYPE(ArrayType, "[Lorg/qtproject/qt/ArrayType;") Q_DECLARE_JNI_TYPE(ArrayType, "[Lorg/qtproject/qt/ArrayType;")
static_assert(QtJniTypes::typeSignature<QtJniTypes::ArrayType>() == "[Lorg/qtproject/qt/ArrayType;"); static_assert(QtJniTypes::typeSignature<QtJniTypes::ArrayType>() == "[Lorg/qtproject/qt/ArrayType;");
static_assert(QtJniTypes::className<jstring>() == "java/lang/String");
Q_DECLARE_JNI_CLASS(QtTextToSpeech, "org/qtproject/qt/android/speech/QtTextToSpeech") Q_DECLARE_JNI_CLASS(QtTextToSpeech, "org/qtproject/qt/android/speech/QtTextToSpeech")
static_assert(QtJniTypes::className<QtJniTypes::QtTextToSpeech>() == "org/qtproject/qt/android/speech/QtTextToSpeech"); static_assert(QtJniTypes::className<QtJniTypes::QtTextToSpeech>() == "org/qtproject/qt/android/speech/QtTextToSpeech");
@ -91,21 +89,21 @@ static_assert(QtJniTypes::isArrayType<jobject[]>());
static_assert(QtJniTypes::isArrayType<jobjectArray>()); static_assert(QtJniTypes::isArrayType<jobjectArray>());
static_assert(QtJniTypes::isArrayType<QtJavaWrapper[]>()); static_assert(QtJniTypes::isArrayType<QtJavaWrapper[]>());
static_assert(QtJniTypes::String("ABCDE").startsWith("ABC")); static_assert(QtJniTypes::CTString("ABCDE").startsWith("ABC"));
static_assert(QtJniTypes::String("ABCDE").startsWith("A")); static_assert(QtJniTypes::CTString("ABCDE").startsWith("A"));
static_assert(QtJniTypes::String("ABCDE").startsWith("ABCDE")); static_assert(QtJniTypes::CTString("ABCDE").startsWith("ABCDE"));
static_assert(!QtJniTypes::String("ABCDE").startsWith("ABCDEF")); static_assert(!QtJniTypes::CTString("ABCDE").startsWith("ABCDEF"));
static_assert(!QtJniTypes::String("ABCDE").startsWith("9AB")); static_assert(!QtJniTypes::CTString("ABCDE").startsWith("9AB"));
static_assert(QtJniTypes::String("ABCDE").startsWith('A')); static_assert(QtJniTypes::CTString("ABCDE").startsWith('A'));
static_assert(!QtJniTypes::String("ABCDE").startsWith('B')); static_assert(!QtJniTypes::CTString("ABCDE").startsWith('B'));
static_assert(QtJniTypes::String("ABCDE").endsWith("CDE")); static_assert(QtJniTypes::CTString("ABCDE").endsWith("CDE"));
static_assert(QtJniTypes::String("ABCDE").endsWith("E")); static_assert(QtJniTypes::CTString("ABCDE").endsWith("E"));
static_assert(QtJniTypes::String("ABCDE").endsWith("ABCDE")); static_assert(QtJniTypes::CTString("ABCDE").endsWith("ABCDE"));
static_assert(!QtJniTypes::String("ABCDE").endsWith("DEF")); static_assert(!QtJniTypes::CTString("ABCDE").endsWith("DEF"));
static_assert(!QtJniTypes::String("ABCDE").endsWith("ABCDEF")); static_assert(!QtJniTypes::CTString("ABCDE").endsWith("ABCDEF"));
static_assert(QtJniTypes::String("ABCDE").endsWith('E')); static_assert(QtJniTypes::CTString("ABCDE").endsWith('E'));
static_assert(!QtJniTypes::String("ABCDE").endsWith('F')); static_assert(!QtJniTypes::CTString("ABCDE").endsWith('F'));
void tst_QJniTypes::initTestCase() void tst_QJniTypes::initTestCase()
{ {