diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-09-12 17:48:40 +0200 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2023-09-20 17:16:28 +0200 |
commit | 1de8cb8f913f7a6d4b802c04aff5a21852168ec0 (patch) | |
tree | efa3332b6db0bf558dc4d936ee15a8ec417de668 | |
parent | 7a27609d73da8725b6a894d9f2911a0eece13bc1 (diff) |
JNI: move JNI type macros into separate header
This removes the dependency from QJniObject to QtJniTypes, and allows us
to add more useful helpers to types declared through the macros, as we
can rely on QJniObject being fully declared.
Note: this is all undocumented API, so fine to change even though it
currently lives in a public header.
Change-Id: I07478ecb80ae166d619a09aed6820f680afed31b
Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io>
-rw-r--r-- | src/corelib/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qjnienvironment.h | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qjniobject.h | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qjnitypes.h | 321 | ||||
-rw-r--r-- | src/corelib/kernel/qjnitypes_impl.h | 329 |
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 |