summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/CMakeLists.txt2
-rw-r--r--src/corelib/kernel/qjnienvironment.h2
-rw-r--r--src/corelib/kernel/qjniobject.h2
-rw-r--r--src/corelib/kernel/qjnitypes.h321
-rw-r--r--src/corelib/kernel/qjnitypes_impl.h329
5 files changed, 339 insertions, 317 deletions
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index c638266256..8578afc61d 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -999,7 +999,7 @@ qt_internal_extend_target(Core CONDITION ANDROID
SOURCES
io/qstandardpaths_android.cpp
io/qstorageinfo_linux.cpp
- kernel/qjnitypes.h
+ kernel/qjnitypes.h kernel/qjnitypes_impl.h
kernel/qjnienvironment.cpp kernel/qjnienvironment.h
kernel/qjniobject.cpp kernel/qjniobject.h
kernel/qjnihelpers.cpp kernel/qjnihelpers_p.h
diff --git a/src/corelib/kernel/qjnienvironment.h b/src/corelib/kernel/qjnienvironment.h
index f7ffa836c2..2121ceb6fe 100644
--- a/src/corelib/kernel/qjnienvironment.h
+++ b/src/corelib/kernel/qjnienvironment.h
@@ -8,7 +8,7 @@
#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
#include <jni.h>
-#include <QtCore/qjnitypes.h>
+#include <QtCore/qjnitypes_impl.h>
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/kernel/qjniobject.h b/src/corelib/kernel/qjniobject.h
index 75c896a728..de73676630 100644
--- a/src/corelib/kernel/qjniobject.h
+++ b/src/corelib/kernel/qjniobject.h
@@ -9,7 +9,6 @@
#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
#include <jni.h>
#include <QtCore/qjnienvironment.h>
-#include <QtCore/qjnitypes.h>
QT_BEGIN_NAMESPACE
@@ -42,7 +41,6 @@ public:
std::forward<Args>(args)...)
{}
QJniObject(jobject globalRef);
- inline QJniObject(QtJniTypes::Object wrapper) noexcept : QJniObject(jobject(wrapper)) {}
~QJniObject();
template<typename Class, typename ...Args>
diff --git a/src/corelib/kernel/qjnitypes.h b/src/corelib/kernel/qjnitypes.h
index 067504c41d..72d6f2783c 100644
--- a/src/corelib/kernel/qjnitypes.h
+++ b/src/corelib/kernel/qjnitypes.h
@@ -4,330 +4,25 @@
#ifndef QJNITYPES_H
#define QJNITYPES_H
-#include <QtCore/qglobal.h>
-#include <QtCore/q20type_traits.h>
-
#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
-#include <jni.h>
+
+#include <QtCore/qjnitypes_impl.h>
+#include <QtCore/qjniobject.h>
QT_BEGIN_NAMESPACE
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
-{
- BaseType m_data[N_WITH_NULL] = {};
-
- constexpr String() noexcept {}
- // Can be instantiated (only) with a string literal
- constexpr explicit String(const BaseType (&data)[N_WITH_NULL]) noexcept
- {
- for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
- m_data[i] = data[i];
- }
-
- constexpr BaseType at(size_t i) const { return m_data[i]; }
- constexpr BaseType operator[](size_t i) const { return at(i); }
- static constexpr size_t size() noexcept { return N_WITH_NULL; }
- constexpr operator const BaseType *() const noexcept { return m_data; }
- constexpr const BaseType *data() const noexcept { return m_data; }
- template<size_t N2_WITH_NULL>
- constexpr bool startsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept
- {
- if constexpr (N2_WITH_NULL > N_WITH_NULL) {
- return false;
- } else {
- for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) {
- if (m_data[i] != lit[i])
- return false;
- }
- }
- return true;
- }
- constexpr bool startsWith(BaseType c) const noexcept
- {
- return N_WITH_NULL > 1 && m_data[0] == c;
- }
- template<size_t N2_WITH_NULL>
- constexpr bool endsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept
- {
- if constexpr (N2_WITH_NULL > N_WITH_NULL) {
- return false;
- } else {
- for (size_t i = 0; i < N2_WITH_NULL; ++i) {
- if (m_data[N_WITH_NULL - i - 1] != lit[N2_WITH_NULL - i - 1])
- return false;
- }
- }
- return true;
- }
- constexpr bool endsWith(BaseType c) const noexcept
- {
- return N_WITH_NULL > 1 && m_data[N_WITH_NULL - 2] == c;
- }
-
- template<size_t N2_WITH_NULL>
- friend inline constexpr bool operator==(const String<N_WITH_NULL> &lhs,
- const String<N2_WITH_NULL> &rhs) noexcept
- {
- if constexpr (N_WITH_NULL != N2_WITH_NULL) {
- return false;
- } else {
- for (size_t i = 0; i < N_WITH_NULL - 1; ++i) {
- if (lhs.at(i) != rhs.at(i))
- return false;
- }
- }
- return true;
- }
-
- template<size_t N2_WITH_NULL>
- friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs,
- const String<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,
- const BaseType (&rhs)[N2_WITH_NULL]) noexcept
- {
- return operator==(lhs, String<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
- {
- return operator==(String<N2_WITH_NULL>(lhs), rhs);
- }
-
- template<size_t N2_WITH_NULL>
- friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs,
- const BaseType (&rhs)[N2_WITH_NULL]) noexcept
- {
- return operator!=(lhs, String<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
- {
- return operator!=(String<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
- {
- 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);
- }
-};
-
-
-// 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<const char[N]> : std::true_type {};
-
-template<bool flag = false>
-static void staticAssertTypeMismatch()
-{
- static_assert(flag, "The used type is not supported by this template call. "
- "Use a JNI based type instead.");
-}
-
-template<typename T>
-constexpr auto typeSignature()
-{
- if constexpr (std::is_array_v<T>) {
- 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>();
- } else if constexpr (std::is_same_v<T, jobject>) {
- return String("Ljava/lang/Object;");
- } else if constexpr (std::is_same_v<T, jclass>) {
- return String("Ljava/lang/Class;");
- } else if constexpr (std::is_same_v<T, jstring>) {
- return String("Ljava/lang/String;");
- } else if constexpr (std::is_same_v<T, jobjectArray>) {
- return String("[Ljava/lang/Object;");
- } else if constexpr (std::is_same_v<T, jthrowable>) {
- return String("Ljava/lang/Throwable;");
- } else if constexpr (std::is_same_v<T, jbooleanArray>) {
- return String("[Z");
- } else if constexpr (std::is_same_v<T, jbyteArray>) {
- return String("[B");
- } else if constexpr (std::is_same_v<T, jshortArray>) {
- return String("[S");
- } else if constexpr (std::is_same_v<T, jintArray>) {
- return String("[I");
- } else if constexpr (std::is_same_v<T, jlongArray>) {
- return String("[J");
- } else if constexpr (std::is_same_v<T, jfloatArray>) {
- return String("[F");
- } else if constexpr (std::is_same_v<T, jdoubleArray>) {
- return String("[D");
- } else if constexpr (std::is_same_v<T, jcharArray>) {
- return String("[C");
- } else if constexpr (std::is_same_v<T, jboolean>) {
- return String("Z");
- } else if constexpr (std::is_same_v<T, bool>) {
- return String("Z");
- } else if constexpr (std::is_same_v<T, jbyte>) {
- return String("B");
- } else if constexpr (std::is_same_v<T, jchar>) {
- return String("C");
- } else if constexpr (std::is_same_v<T, char>) {
- return String("C");
- } else if constexpr (std::is_same_v<T, jshort>) {
- return String("S");
- } else if constexpr (std::is_same_v<T, short>) {
- return String("S");
- } else if constexpr (std::is_same_v<T, jint>) {
- return String("I");
- } else if constexpr (std::is_same_v<T, int>) {
- return String("I");
- } else if constexpr (std::is_same_v<T, uint>) {
- return String("I");
- } else if constexpr (std::is_same_v<T, jlong>) {
- return String("J");
- } else if constexpr (std::is_same_v<T, long>) {
- return String("J");
- } else if constexpr (std::is_same_v<T, jfloat>) {
- return String("F");
- } else if constexpr (std::is_same_v<T, float>) {
- return String("F");
- } else if constexpr (std::is_same_v<T, jdouble>) {
- return String("D");
- } else if constexpr (std::is_same_v<T, double>) {
- return String("D");
- } else if constexpr (std::is_same_v<T, void>) {
- return String("V");
- }
-
- // else: The return type becomes void, indicating that the typeSignature
- // template is not implemented for the respective type. We use this to
- // detect invalid types in the ValidSignatureTypes and ValidFieldType
- // predicates below.
-}
-
-template<bool flag = false>
-static void staticAssertClassNotRegistered()
-{
- static_assert(flag, "Class not registered, use Q_DECLARE_JNI_CLASS");
-}
-
-template<typename T>
-constexpr auto className()
-{
- if constexpr (std::is_same_v<T, jstring>)
- return String("java/lang/String");
- else
- staticAssertClassNotRegistered();
-}
-
-template<typename T>
-static constexpr bool isPrimitiveType()
-{
- return typeSignature<T>().size() == 2;
-}
-
-template<typename T>
-static constexpr bool isObjectType()
-{
- if constexpr (std::is_convertible_v<T, jobject>) {
- return true;
- } else {
- constexpr auto signature = typeSignature<T>();
- return (signature.startsWith('L') || signature.startsWith('['))
- && signature.endsWith(';');
- }
-}
-
-template<typename T>
-static constexpr bool isArrayType()
-{
- constexpr auto signature = typeSignature<T>();
- return signature.startsWith('[');
-}
-
-template<typename T>
-static constexpr void assertObjectType()
-{
- static_assert(isObjectType<T>(),
- "Type needs to be a JNI object type (convertible to jobject, or with "
- "an object type signature registered)!");
-}
-
-// A set of types is valid if typeSignature is implemented for all of them
-template<typename ...Types>
-constexpr bool ValidSignatureTypesDetail = !std::disjunction<std::is_same<
- decltype(QtJniTypes::typeSignature<Types>()),
- void>...,
- IsStringType<Types>...>::value;
-template<typename ...Types>
-using ValidSignatureTypes = std::enable_if_t<
- ValidSignatureTypesDetail<q20::remove_cvref_t<Types>...>, bool>;
-
-template<typename Type>
-constexpr bool ValidFieldTypeDetail = isObjectType<Type>() || isPrimitiveType<Type>();
-template<typename Type>
-using ValidFieldType = std::enable_if_t<
- ValidFieldTypeDetail<q20::remove_cvref_t<Type>>, bool>;
-
-
-template<typename R, typename ...Args, ValidSignatureTypes<R, Args...> = true>
-static constexpr auto methodSignature()
-{
- return (String("(") +
- ... + typeSignature<q20::remove_cvref_t<Args>>())
- + String(")")
- + typeSignature<R>();
-}
-
-template<typename T, ValidSignatureTypes<T> = true>
-static constexpr auto fieldSignature()
-{
- return QtJniTypes::typeSignature<T>();
-}
-
-template<typename ...Args, ValidSignatureTypes<Args...> = true>
-static constexpr auto constructorSignature()
-{
- return methodSignature<void, Args...>();
-}
-
-template<typename Ret, typename ...Args, ValidSignatureTypes<Ret, Args...> = true>
-static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jobject, Args...))
-{
- return methodSignature<Ret, Args...>();
-}
-
-template<typename Ret, typename ...Args, ValidSignatureTypes<Ret, Args...> = true>
-static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jclass, Args...))
-{
- return methodSignature<Ret, Args...>();
-}
-
// A generic thin wrapper around jobject, convertible to jobject.
// We need this as a baseclass so that QJniObject can be implicitly
-// constructed from the various subclasses - we can't provide an
-// operator QJniObject() here as the class is not declared.
+// constructed from the various subclasses. We can also pass instances
+// of this type (or of any of the generated subclasses) as if it was
+// a jobject.
struct Object
{
jobject _object;
constexpr operator jobject() const { return _object; }
+ operator QJniObject() const { return QJniObject(_object); }
};
} // namespace QtJniTypes
@@ -402,6 +97,6 @@ static const JNINativeMethod Method##_method = { \
QT_END_NAMESPACE
-#endif
+#endif // defined(Q_QDOC) || defined(Q_OS_ANDROID)
#endif // QJNITYPES_H
diff --git a/src/corelib/kernel/qjnitypes_impl.h b/src/corelib/kernel/qjnitypes_impl.h
new file mode 100644
index 0000000000..a7a3a30b2a
--- /dev/null
+++ b/src/corelib/kernel/qjnitypes_impl.h
@@ -0,0 +1,329 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QJNITYPES_IMPL_H
+#define QJNITYPES_IMPL_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/q20type_traits.h>
+
+#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
+#include <jni.h>
+
+QT_BEGIN_NAMESPACE
+
+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
+{
+ BaseType m_data[N_WITH_NULL] = {};
+
+ constexpr String() noexcept {}
+ // Can be instantiated (only) with a string literal
+ constexpr explicit String(const BaseType (&data)[N_WITH_NULL]) noexcept
+ {
+ for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
+ m_data[i] = data[i];
+ }
+
+ constexpr BaseType at(size_t i) const { return m_data[i]; }
+ constexpr BaseType operator[](size_t i) const { return at(i); }
+ static constexpr size_t size() noexcept { return N_WITH_NULL; }
+ constexpr operator const BaseType *() const noexcept { return m_data; }
+ constexpr const BaseType *data() const noexcept { return m_data; }
+ template<size_t N2_WITH_NULL>
+ constexpr bool startsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept
+ {
+ if constexpr (N2_WITH_NULL > N_WITH_NULL) {
+ return false;
+ } else {
+ for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) {
+ if (m_data[i] != lit[i])
+ return false;
+ }
+ }
+ return true;
+ }
+ constexpr bool startsWith(BaseType c) const noexcept
+ {
+ return N_WITH_NULL > 1 && m_data[0] == c;
+ }
+ template<size_t N2_WITH_NULL>
+ constexpr bool endsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept
+ {
+ if constexpr (N2_WITH_NULL > N_WITH_NULL) {
+ return false;
+ } else {
+ for (size_t i = 0; i < N2_WITH_NULL; ++i) {
+ if (m_data[N_WITH_NULL - i - 1] != lit[N2_WITH_NULL - i - 1])
+ return false;
+ }
+ }
+ return true;
+ }
+ constexpr bool endsWith(BaseType c) const noexcept
+ {
+ return N_WITH_NULL > 1 && m_data[N_WITH_NULL - 2] == c;
+ }
+
+ template<size_t N2_WITH_NULL>
+ friend inline constexpr bool operator==(const String<N_WITH_NULL> &lhs,
+ const String<N2_WITH_NULL> &rhs) noexcept
+ {
+ if constexpr (N_WITH_NULL != N2_WITH_NULL) {
+ return false;
+ } else {
+ for (size_t i = 0; i < N_WITH_NULL - 1; ++i) {
+ if (lhs.at(i) != rhs.at(i))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ template<size_t N2_WITH_NULL>
+ friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs,
+ const String<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,
+ const BaseType (&rhs)[N2_WITH_NULL]) noexcept
+ {
+ return operator==(lhs, String<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
+ {
+ return operator==(String<N2_WITH_NULL>(lhs), rhs);
+ }
+
+ template<size_t N2_WITH_NULL>
+ friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs,
+ const BaseType (&rhs)[N2_WITH_NULL]) noexcept
+ {
+ return operator!=(lhs, String<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
+ {
+ return operator!=(String<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
+ {
+ 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);
+ }
+};
+
+
+// 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<const char[N]> : std::true_type {};
+
+template<bool flag = false>
+static void staticAssertTypeMismatch()
+{
+ static_assert(flag, "The used type is not supported by this template call. "
+ "Use a JNI based type instead.");
+}
+
+template<typename T>
+constexpr auto typeSignature()
+{
+ if constexpr (std::is_array_v<T>) {
+ 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>();
+ } else if constexpr (std::is_same_v<T, jobject>) {
+ return String("Ljava/lang/Object;");
+ } else if constexpr (std::is_same_v<T, jclass>) {
+ return String("Ljava/lang/Class;");
+ } else if constexpr (std::is_same_v<T, jstring>) {
+ return String("Ljava/lang/String;");
+ } else if constexpr (std::is_same_v<T, jobjectArray>) {
+ return String("[Ljava/lang/Object;");
+ } else if constexpr (std::is_same_v<T, jthrowable>) {
+ return String("Ljava/lang/Throwable;");
+ } else if constexpr (std::is_same_v<T, jbooleanArray>) {
+ return String("[Z");
+ } else if constexpr (std::is_same_v<T, jbyteArray>) {
+ return String("[B");
+ } else if constexpr (std::is_same_v<T, jshortArray>) {
+ return String("[S");
+ } else if constexpr (std::is_same_v<T, jintArray>) {
+ return String("[I");
+ } else if constexpr (std::is_same_v<T, jlongArray>) {
+ return String("[J");
+ } else if constexpr (std::is_same_v<T, jfloatArray>) {
+ return String("[F");
+ } else if constexpr (std::is_same_v<T, jdoubleArray>) {
+ return String("[D");
+ } else if constexpr (std::is_same_v<T, jcharArray>) {
+ return String("[C");
+ } else if constexpr (std::is_same_v<T, jboolean>) {
+ return String("Z");
+ } else if constexpr (std::is_same_v<T, bool>) {
+ return String("Z");
+ } else if constexpr (std::is_same_v<T, jbyte>) {
+ return String("B");
+ } else if constexpr (std::is_same_v<T, jchar>) {
+ return String("C");
+ } else if constexpr (std::is_same_v<T, char>) {
+ return String("C");
+ } else if constexpr (std::is_same_v<T, jshort>) {
+ return String("S");
+ } else if constexpr (std::is_same_v<T, short>) {
+ return String("S");
+ } else if constexpr (std::is_same_v<T, jint>) {
+ return String("I");
+ } else if constexpr (std::is_same_v<T, int>) {
+ return String("I");
+ } else if constexpr (std::is_same_v<T, uint>) {
+ return String("I");
+ } else if constexpr (std::is_same_v<T, jlong>) {
+ return String("J");
+ } else if constexpr (std::is_same_v<T, long>) {
+ return String("J");
+ } else if constexpr (std::is_same_v<T, jfloat>) {
+ return String("F");
+ } else if constexpr (std::is_same_v<T, float>) {
+ return String("F");
+ } else if constexpr (std::is_same_v<T, jdouble>) {
+ return String("D");
+ } else if constexpr (std::is_same_v<T, double>) {
+ return String("D");
+ } else if constexpr (std::is_same_v<T, void>) {
+ return String("V");
+ }
+
+ // else: The return type becomes void, indicating that the typeSignature
+ // template is not implemented for the respective type. We use this to
+ // detect invalid types in the ValidSignatureTypes and ValidFieldType
+ // predicates below.
+}
+
+template<bool flag = false>
+static void staticAssertClassNotRegistered()
+{
+ static_assert(flag, "Class not registered, use Q_DECLARE_JNI_CLASS");
+}
+
+template<typename T>
+constexpr auto className()
+{
+ if constexpr (std::is_same_v<T, jstring>)
+ return String("java/lang/String");
+ else
+ staticAssertClassNotRegistered();
+}
+
+template<typename T>
+static constexpr bool isPrimitiveType()
+{
+ return typeSignature<T>().size() == 2;
+}
+
+template<typename T>
+static constexpr bool isObjectType()
+{
+ if constexpr (std::is_convertible_v<T, jobject>) {
+ return true;
+ } else {
+ constexpr auto signature = typeSignature<T>();
+ return (signature.startsWith('L') || signature.startsWith('['))
+ && signature.endsWith(';');
+ }
+}
+
+template<typename T>
+static constexpr bool isArrayType()
+{
+ constexpr auto signature = typeSignature<T>();
+ return signature.startsWith('[');
+}
+
+template<typename T>
+static constexpr void assertObjectType()
+{
+ static_assert(isObjectType<T>(),
+ "Type needs to be a JNI object type (convertible to jobject, or with "
+ "an object type signature registered)!");
+}
+
+// A set of types is valid if typeSignature is implemented for all of them
+template<typename ...Types>
+constexpr bool ValidSignatureTypesDetail = !std::disjunction<std::is_same<
+ decltype(QtJniTypes::typeSignature<Types>()),
+ void>...,
+ IsStringType<Types>...>::value;
+template<typename ...Types>
+using ValidSignatureTypes = std::enable_if_t<
+ ValidSignatureTypesDetail<q20::remove_cvref_t<Types>...>, bool>;
+
+template<typename Type>
+constexpr bool ValidFieldTypeDetail = isObjectType<Type>() || isPrimitiveType<Type>();
+template<typename Type>
+using ValidFieldType = std::enable_if_t<
+ ValidFieldTypeDetail<q20::remove_cvref_t<Type>>, bool>;
+
+
+template<typename R, typename ...Args, ValidSignatureTypes<R, Args...> = true>
+static constexpr auto methodSignature()
+{
+ return (String("(") +
+ ... + typeSignature<q20::remove_cvref_t<Args>>())
+ + String(")")
+ + typeSignature<R>();
+}
+
+template<typename T, ValidSignatureTypes<T> = true>
+static constexpr auto fieldSignature()
+{
+ return QtJniTypes::typeSignature<T>();
+}
+
+template<typename ...Args, ValidSignatureTypes<Args...> = true>
+static constexpr auto constructorSignature()
+{
+ return methodSignature<void, Args...>();
+}
+
+template<typename Ret, typename ...Args, ValidSignatureTypes<Ret, Args...> = true>
+static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jobject, Args...))
+{
+ return methodSignature<Ret, Args...>();
+}
+
+template<typename Ret, typename ...Args, ValidSignatureTypes<Ret, Args...> = true>
+static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jclass, Args...))
+{
+ return methodSignature<Ret, Args...>();
+}
+
+} // namespace QtJniTypes
+
+QT_END_NAMESPACE
+
+#endif
+
+#endif // QJNITYPES_IMPL_H