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] == ';', \
"Type signature needs to start with 'L' or '['" \
" and end with ';'"); \
return QtJniTypes::String(Signature); \
return QtJniTypes::CTString(Signature); \
} \
#define Q_DECLARE_JNI_CLASS(Type, Signature) \
@ -53,14 +53,14 @@ Q_DECLARE_JNI_TYPE_HELPER(Type) \
template<> \
constexpr auto QtJniTypes::className<QtJniTypes::Type>() \
{ \
return QtJniTypes::String(Signature); \
return QtJniTypes::CTString(Signature); \
} \
template<> \
constexpr auto QtJniTypes::typeSignature<QtJniTypes::Type>() \
{ \
return QtJniTypes::String("L") \
+ QtJniTypes::String(Signature) \
+ QtJniTypes::String(";"); \
return QtJniTypes::CTString("L") \
+ QtJniTypes::CTString(Signature) \
+ QtJniTypes::CTString(";"); \
} \
#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
// of the string.
template<size_t N_WITH_NULL, typename BaseType = char>
struct String
struct CTString
{
BaseType m_data[N_WITH_NULL] = {};
constexpr String() noexcept {}
constexpr CTString() noexcept {}
// 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)
m_data[i] = data[i];
@ -71,8 +71,8 @@ struct String
}
template<size_t N2_WITH_NULL>
friend inline constexpr bool operator==(const String<N_WITH_NULL> &lhs,
const String<N2_WITH_NULL> &rhs) noexcept
friend inline constexpr bool operator==(const CTString<N_WITH_NULL> &lhs,
const CTString<N2_WITH_NULL> &rhs) noexcept
{
if constexpr (N_WITH_NULL != N2_WITH_NULL) {
return false;
@ -86,57 +86,60 @@ struct String
}
template<size_t N2_WITH_NULL>
friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs,
const String<N2_WITH_NULL> &rhs) noexcept
friend inline constexpr bool operator!=(const CTString<N_WITH_NULL> &lhs,
const CTString<N2_WITH_NULL> &rhs) noexcept
{
return !operator==(lhs, rhs);
}
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
{
return operator==(lhs, String<N2_WITH_NULL>(rhs));
return operator==(lhs, CTString<N2_WITH_NULL>(rhs));
}
template<size_t 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>
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
{
return operator!=(lhs, String<N2_WITH_NULL>(rhs));
return operator!=(lhs, CTString<N2_WITH_NULL>(rhs));
}
template<size_t 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>
friend inline constexpr auto operator+(const String<N_WITH_NULL> &lhs,
const String<N2_WITH_NULL> &rhs) noexcept
friend inline constexpr auto operator+(const CTString<N_WITH_NULL> &lhs,
const CTString<N2_WITH_NULL> &rhs) noexcept
{
char data[N_WITH_NULL + N2_WITH_NULL - 1] = {};
for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
data[i] = lhs[i];
for (size_t i = 0; i < N2_WITH_NULL - 1; ++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
// with overloads that take a const char*.
template<typename T, size_t N = 0> struct IsStringType : std::false_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<bool flag = false>
@ -153,67 +156,67 @@ constexpr auto typeSignature()
using UnderlyingType = typename std::remove_extent_t<T>;
static_assert(!std::is_array_v<UnderlyingType>,
"typeSignature() does not handle multi-dimensional arrays");
return String("[") + typeSignature<UnderlyingType>();
return CTString("[") + typeSignature<UnderlyingType>();
} 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>) {
return String("Ljava/lang/Class;");
return CTString("Ljava/lang/Class;");
} 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>) {
return String("[Ljava/lang/Object;");
return CTString("[Ljava/lang/Object;");
} 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>) {
return String("[Z");
return CTString("[Z");
} else if constexpr (std::is_same_v<T, jbyteArray>) {
return String("[B");
return CTString("[B");
} else if constexpr (std::is_same_v<T, jshortArray>) {
return String("[S");
return CTString("[S");
} else if constexpr (std::is_same_v<T, jintArray>) {
return String("[I");
return CTString("[I");
} else if constexpr (std::is_same_v<T, jlongArray>) {
return String("[J");
return CTString("[J");
} else if constexpr (std::is_same_v<T, jfloatArray>) {
return String("[F");
return CTString("[F");
} else if constexpr (std::is_same_v<T, jdoubleArray>) {
return String("[D");
return CTString("[D");
} else if constexpr (std::is_same_v<T, jcharArray>) {
return String("[C");
return CTString("[C");
} else if constexpr (std::is_same_v<T, jboolean>) {
return String("Z");
return CTString("Z");
} else if constexpr (std::is_same_v<T, bool>) {
return String("Z");
return CTString("Z");
} else if constexpr (std::is_same_v<T, jbyte>) {
return String("B");
return CTString("B");
} else if constexpr (std::is_same_v<T, jchar>) {
return String("C");
return CTString("C");
} else if constexpr (std::is_same_v<T, char>) {
return String("C");
return CTString("C");
} else if constexpr (std::is_same_v<T, jshort>) {
return String("S");
return CTString("S");
} else if constexpr (std::is_same_v<T, short>) {
return String("S");
return CTString("S");
} else if constexpr (std::is_same_v<T, jint>) {
return String("I");
return CTString("I");
} else if constexpr (std::is_same_v<T, int>) {
return String("I");
return CTString("I");
} else if constexpr (std::is_same_v<T, uint>) {
return String("I");
return CTString("I");
} else if constexpr (std::is_same_v<T, jlong>) {
return String("J");
return CTString("J");
} else if constexpr (std::is_same_v<T, long>) {
return String("J");
return CTString("J");
} else if constexpr (std::is_same_v<T, jfloat>) {
return String("F");
return CTString("F");
} else if constexpr (std::is_same_v<T, float>) {
return String("F");
return CTString("F");
} else if constexpr (std::is_same_v<T, jdouble>) {
return String("D");
return CTString("D");
} else if constexpr (std::is_same_v<T, double>) {
return String("D");
return CTString("D");
} 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
@ -232,7 +235,7 @@ template<typename T>
constexpr auto className()
{
if constexpr (std::is_same_v<T, jstring>)
return String("java/lang/String");
return CTString("java/lang/String");
else
staticAssertClassNotRegistered();
}
@ -289,9 +292,9 @@ using ValidFieldType = std::enable_if_t<
template<typename R, typename ...Args, ValidSignatureTypes<R, Args...> = true>
static constexpr auto methodSignature()
{
return (String("(") +
return (CTString("(") +
... + typeSignature<q20::remove_cvref_t<Args>>())
+ String(")")
+ CTString(")")
+ typeSignature<R>();
}

View File

@ -21,20 +21,20 @@ struct QtJavaWrapper {};
template<>
constexpr auto QtJniTypes::typeSignature<QtJavaWrapper>()
{
return QtJniTypes::String("Lorg/qtproject/qt/android/QtJavaWrapper;");
return QtJniTypes::CTString("Lorg/qtproject/qt/android/QtJavaWrapper;");
}
template<>
constexpr auto QtJniTypes::typeSignature<QJniObject>()
{
return QtJniTypes::String("Ljava/lang/Object;");
return QtJniTypes::CTString("Ljava/lang/Object;");
}
struct QtCustomJniObject : QJniObject {};
template<>
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;");
@ -46,8 +46,6 @@ static_assert(QtJniTypes::typeSignature<QtJniTypes::JavaType>() == "Lorg/qtproje
Q_DECLARE_JNI_TYPE(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")
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<QtJavaWrapper[]>());
static_assert(QtJniTypes::String("ABCDE").startsWith("ABC"));
static_assert(QtJniTypes::String("ABCDE").startsWith("A"));
static_assert(QtJniTypes::String("ABCDE").startsWith("ABCDE"));
static_assert(!QtJniTypes::String("ABCDE").startsWith("ABCDEF"));
static_assert(!QtJniTypes::String("ABCDE").startsWith("9AB"));
static_assert(QtJniTypes::String("ABCDE").startsWith('A'));
static_assert(!QtJniTypes::String("ABCDE").startsWith('B'));
static_assert(QtJniTypes::CTString("ABCDE").startsWith("ABC"));
static_assert(QtJniTypes::CTString("ABCDE").startsWith("A"));
static_assert(QtJniTypes::CTString("ABCDE").startsWith("ABCDE"));
static_assert(!QtJniTypes::CTString("ABCDE").startsWith("ABCDEF"));
static_assert(!QtJniTypes::CTString("ABCDE").startsWith("9AB"));
static_assert(QtJniTypes::CTString("ABCDE").startsWith('A'));
static_assert(!QtJniTypes::CTString("ABCDE").startsWith('B'));
static_assert(QtJniTypes::String("ABCDE").endsWith("CDE"));
static_assert(QtJniTypes::String("ABCDE").endsWith("E"));
static_assert(QtJniTypes::String("ABCDE").endsWith("ABCDE"));
static_assert(!QtJniTypes::String("ABCDE").endsWith("DEF"));
static_assert(!QtJniTypes::String("ABCDE").endsWith("ABCDEF"));
static_assert(QtJniTypes::String("ABCDE").endsWith('E'));
static_assert(!QtJniTypes::String("ABCDE").endsWith('F'));
static_assert(QtJniTypes::CTString("ABCDE").endsWith("CDE"));
static_assert(QtJniTypes::CTString("ABCDE").endsWith("E"));
static_assert(QtJniTypes::CTString("ABCDE").endsWith("ABCDE"));
static_assert(!QtJniTypes::CTString("ABCDE").endsWith("DEF"));
static_assert(!QtJniTypes::CTString("ABCDE").endsWith("ABCDEF"));
static_assert(QtJniTypes::CTString("ABCDE").endsWith('E'));
static_assert(!QtJniTypes::CTString("ABCDE").endsWith('F'));
void tst_QJniTypes::initTestCase()
{