diff options
Diffstat (limited to 'src/corelib/kernel/qjnitypes_impl.h')
-rw-r--r-- | src/corelib/kernel/qjnitypes_impl.h | 329 |
1 files changed, 329 insertions, 0 deletions
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 |