Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qjnitypes_impl.h
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QJNITYPES_IMPL_H
5#define QJNITYPES_IMPL_H
6
7#include <QtCore/qglobal.h>
8#include <QtCore/q20type_traits.h>
9
10#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
11#include <jni.h>
12
14
15namespace QtJniTypes
16{
17
18// a constexpr type for string literals of any character width, aware of the length
19// of the string.
20template<size_t N_WITH_NULL, typename BaseType = char>
21struct CTString
22{
23 BaseType m_data[N_WITH_NULL] = {};
24
25 constexpr CTString() noexcept {}
26 // Can be instantiated (only) with a string literal
27 constexpr explicit CTString(const BaseType (&data)[N_WITH_NULL]) noexcept
28 {
29 for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
30 m_data[i] = data[i];
31 }
32
33 constexpr BaseType at(size_t i) const { return m_data[i]; }
34 constexpr BaseType operator[](size_t i) const { return at(i); }
35 static constexpr size_t size() noexcept { return N_WITH_NULL; }
36 constexpr operator const BaseType *() const noexcept { return m_data; }
37 constexpr const BaseType *data() const noexcept { return m_data; }
38 template<size_t N2_WITH_NULL>
39 constexpr bool startsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept
40 {
41 if constexpr (N2_WITH_NULL > N_WITH_NULL) {
42 return false;
43 } else {
44 for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) {
45 if (m_data[i] != lit[i])
46 return false;
47 }
48 }
49 return true;
50 }
51 constexpr bool startsWith(BaseType c) const noexcept
52 {
53 return N_WITH_NULL > 1 && m_data[0] == c;
54 }
55 template<size_t N2_WITH_NULL>
56 constexpr bool endsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept
57 {
58 if constexpr (N2_WITH_NULL > N_WITH_NULL) {
59 return false;
60 } else {
61 for (size_t i = 0; i < N2_WITH_NULL; ++i) {
62 if (m_data[N_WITH_NULL - i - 1] != lit[N2_WITH_NULL - i - 1])
63 return false;
64 }
65 }
66 return true;
67 }
68 constexpr bool endsWith(BaseType c) const noexcept
69 {
70 return N_WITH_NULL > 1 && m_data[N_WITH_NULL - 2] == c;
71 }
72
73 template<size_t N2_WITH_NULL>
74 friend inline constexpr bool operator==(const CTString<N_WITH_NULL> &lhs,
75 const CTString<N2_WITH_NULL> &rhs) noexcept
76 {
77 if constexpr (N_WITH_NULL != N2_WITH_NULL) {
78 return false;
79 } else {
80 for (size_t i = 0; i < N_WITH_NULL - 1; ++i) {
81 if (lhs.at(i) != rhs.at(i))
82 return false;
83 }
84 }
85 return true;
86 }
87
88 template<size_t N2_WITH_NULL>
89 friend inline constexpr bool operator!=(const CTString<N_WITH_NULL> &lhs,
90 const CTString<N2_WITH_NULL> &rhs) noexcept
91 {
92 return !operator==(lhs, rhs);
93 }
94
95 template<size_t N2_WITH_NULL>
96 friend inline constexpr bool operator==(const CTString<N_WITH_NULL> &lhs,
97 const BaseType (&rhs)[N2_WITH_NULL]) noexcept
98 {
99 return operator==(lhs, CTString<N2_WITH_NULL>(rhs));
100 }
101 template<size_t N2_WITH_NULL>
102 friend inline constexpr bool operator==(const BaseType (&lhs)[N2_WITH_NULL],
103 const CTString<N_WITH_NULL> &rhs) noexcept
104 {
105 return operator==(CTString<N2_WITH_NULL>(lhs), rhs);
106 }
107
108 template<size_t N2_WITH_NULL>
109 friend inline constexpr bool operator!=(const CTString<N_WITH_NULL> &lhs,
110 const BaseType (&rhs)[N2_WITH_NULL]) noexcept
111 {
112 return operator!=(lhs, CTString<N2_WITH_NULL>(rhs));
113 }
114 template<size_t N2_WITH_NULL>
115 friend inline constexpr bool operator!=(const BaseType (&lhs)[N2_WITH_NULL],
116 const CTString<N_WITH_NULL> &rhs) noexcept
117 {
118 return operator!=(CTString<N2_WITH_NULL>(lhs), rhs);
119 }
120
121 template<size_t N2_WITH_NULL>
122 friend inline constexpr auto operator+(const CTString<N_WITH_NULL> &lhs,
123 const CTString<N2_WITH_NULL> &rhs) noexcept
124 {
125 char data[N_WITH_NULL + N2_WITH_NULL - 1] = {};
126 for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
127 data[i] = lhs[i];
128 for (size_t i = 0; i < N2_WITH_NULL - 1; ++i)
129 data[N_WITH_NULL - 1 + i] = rhs[i];
130 return CTString<N_WITH_NULL + N2_WITH_NULL - 1>(data);
131 }
132};
133
134// Helper types that allow us to disable variadic overloads that would conflict
135// with overloads that take a const char*.
136template<typename T, size_t N = 0> struct IsStringType : std::false_type {};
137template<> struct IsStringType<const char *, 0> : std::true_type {};
138template<> struct IsStringType<const char *&, 0> : std::true_type {};
139template<size_t N> struct IsStringType<CTString<N>> : std::true_type {};
140template<size_t N> struct IsStringType<const char[N]> : std::true_type {};
141template<size_t N> struct IsStringType<const char(&)[N]> : std::true_type {};
142template<size_t N> struct IsStringType<char[N]> : std::true_type {};
143
144template <typename T>
145struct Traits {
146 // The return type of className/signature becomes void for any type
147 // not handled here. This indicates that the Traits type is not specialized
148 // for the respective type, which we use to detect invalid types in the
149 // IfValidSignatureTypes and IfValidFieldType predicates below.
150
151 static constexpr auto className()
152 {
153 if constexpr (std::is_same_v<T, jstring>)
154 return CTString("java/lang/String");
155 else if constexpr (std::is_same_v<T, jobject>)
156 return CTString("java/lang/Object");
157 else if constexpr (std::is_same_v<T, jclass>)
158 return CTString("java/lang/Class");
159 else if constexpr (std::is_same_v<T, jthrowable>)
160 return CTString("java/lang/Throwable");
161 // else: return void -> not implemented
162 }
163
164 static constexpr auto signature()
165 {
166 if constexpr (!std::is_same_v<decltype(className()), void>) {
167 // the type signature of any object class is L<className>;
168 return CTString("L") + className() + CTString(";");
169 } else if constexpr (std::is_array_v<T>) {
170 using UnderlyingType = typename std::remove_extent_t<T>;
171 static_assert(!std::is_array_v<UnderlyingType>,
172 "Traits::signature() does not handle multi-dimensional arrays");
173 return CTString("[") + Traits<UnderlyingType>::signature();
174 } else if constexpr (std::is_same_v<T, jobjectArray>) {
175 return CTString("[Ljava/lang/Object;");
176 } else if constexpr (std::is_same_v<T, jbooleanArray>) {
177 return CTString("[Z");
178 } else if constexpr (std::is_same_v<T, jbyteArray>) {
179 return CTString("[B");
180 } else if constexpr (std::is_same_v<T, jshortArray>) {
181 return CTString("[S");
182 } else if constexpr (std::is_same_v<T, jintArray>) {
183 return CTString("[I");
184 } else if constexpr (std::is_same_v<T, jlongArray>) {
185 return CTString("[J");
186 } else if constexpr (std::is_same_v<T, jfloatArray>) {
187 return CTString("[F");
188 } else if constexpr (std::is_same_v<T, jdoubleArray>) {
189 return CTString("[D");
190 } else if constexpr (std::is_same_v<T, jcharArray>) {
191 return CTString("[C");
192 } else if constexpr (std::is_same_v<T, jboolean>) {
193 return CTString("Z");
194 } else if constexpr (std::is_same_v<T, bool>) {
195 return CTString("Z");
196 } else if constexpr (std::is_same_v<T, jbyte>) {
197 return CTString("B");
198 } else if constexpr (std::is_same_v<T, jchar>) {
199 return CTString("C");
200 } else if constexpr (std::is_same_v<T, char>) {
201 return CTString("C");
202 } else if constexpr (std::is_same_v<T, jshort>) {
203 return CTString("S");
204 } else if constexpr (std::is_same_v<T, short>) {
205 return CTString("S");
206 } else if constexpr (std::is_same_v<T, jint>) {
207 return CTString("I");
208 } else if constexpr (std::is_same_v<T, int>) {
209 return CTString("I");
210 } else if constexpr (std::is_same_v<T, uint>) {
211 return CTString("I");
212 } else if constexpr (std::is_same_v<T, jlong>) {
213 return CTString("J");
214 } else if constexpr (std::is_same_v<T, quint64>) {
215 return CTString("J");
216 } else if constexpr (std::is_same_v<T, jfloat>) {
217 return CTString("F");
218 } else if constexpr (std::is_same_v<T, float>) {
219 return CTString("F");
220 } else if constexpr (std::is_same_v<T, jdouble>) {
221 return CTString("D");
222 } else if constexpr (std::is_same_v<T, double>) {
223 return CTString("D");
224 } else if constexpr (std::is_same_v<T, void>) {
225 return CTString("V");
226 } else if constexpr (std::is_enum_v<T>) {
227 return Traits<std::underlying_type_t<T>>::signature();
228 } else if constexpr (std::is_same_v<T, QString>) {
229 return CTString("Ljava/lang/String;");
230 }
231 // else: return void -> not implemented
232 }
233};
234
235template <typename Have, typename Want>
236static constexpr bool sameTypeForJni = (QtJniTypes::Traits<Have>::signature()
237 == QtJniTypes::Traits<Want>::signature())
238 && (sizeof(Have) == sizeof(Want));
239
240template <typename, typename = void>
241struct Caller
242{};
243
244#define MAKE_CALLER(Type, Method) \
245template <typename T> \
246struct Caller<T, std::enable_if_t<sameTypeForJni<T, Type>>> \
247{ \
248 static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj, jmethodID id, va_list args) \
249 { \
250 res = T(env->Call##Method##MethodV(obj, id, args)); \
251 } \
252 static constexpr void callStaticMethodForType(JNIEnv *env, T &res, jclass clazz, jmethodID id, va_list args) \
253 { \
254 res = T(env->CallStatic##Method##MethodV(clazz, id, args)); \
255 } \
256 static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, jfieldID id) \
257 { \
258 res = T(env->Get##Method##Field(obj, id)); \
259 } \
260 static constexpr void getStaticFieldForType(JNIEnv *env, T &res, jclass clazz, jfieldID id) \
261 { \
262 res = T(env->GetStatic##Method##Field(clazz, id)); \
263 } \
264 static constexpr void setFieldForType(JNIEnv *env, jobject obj, jfieldID id, T value) \
265 { \
266 env->Set##Method##Field(obj, id, static_cast<Type>(value)); \
267 } \
268 static constexpr void setStaticFieldForType(JNIEnv *env, jclass clazz, jfieldID id, T value) \
269 { \
270 env->SetStatic##Method##Field(clazz, id, static_cast<Type>(value)); \
271 } \
272}
273
274MAKE_CALLER(jboolean, Boolean);
275MAKE_CALLER(jbyte, Byte);
276MAKE_CALLER(jchar, Char);
277MAKE_CALLER(jshort, Short);
278MAKE_CALLER(jint, Int);
279MAKE_CALLER(jlong, Long);
280MAKE_CALLER(jfloat, Float);
281MAKE_CALLER(jdouble, Double);
282
283#undef MAKE_CALLER
284
285template<typename T>
286static constexpr bool isPrimitiveType()
287{
288 return Traits<T>::signature().size() == 2;
289}
290
291template<typename T>
292static constexpr bool isArrayType()
293{
294 constexpr auto signature = Traits<T>::signature();
295 return signature.startsWith('[') && signature.size() > 2;
296}
297
298template<typename T>
299static constexpr bool isObjectType()
300{
301 if constexpr (std::is_convertible_v<T, jobject>) {
302 return true;
303 } else {
304 constexpr auto signature = Traits<T>::signature();
305 return (signature.startsWith('L') && signature.endsWith(';')) || isArrayType<T>();
306 }
307}
308
309template<typename T>
310static constexpr void assertObjectType()
311{
312 static_assert(isObjectType<T>(),
313 "Type needs to be a JNI object type (convertible to jobject, or with "
314 "an object type signature registered)!");
315}
316
317// A set of types is valid if Traits::signature is implemented for all of them
318template<typename ...Types>
319constexpr bool ValidSignatureTypesDetail = !std::disjunction<std::is_same<
320 decltype(Traits<Types>::signature()),
321 void>...,
322 IsStringType<Types>...>::value;
323template<typename ...Types>
324using IfValidSignatureTypes = std::enable_if_t<
325 ValidSignatureTypesDetail<q20::remove_cvref_t<Types>...>, bool>;
326
327template<typename Type>
328constexpr bool ValidFieldTypeDetail = isObjectType<Type>() || isPrimitiveType<Type>();
329template<typename Type>
330using IfValidFieldType = std::enable_if_t<
331 ValidFieldTypeDetail<q20::remove_cvref_t<Type>>, bool>;
332
333
334template<typename R, typename ...Args, IfValidSignatureTypes<R, Args...> = true>
335static constexpr auto methodSignature()
336{
337 return (CTString("(") +
338 ... + Traits<q20::remove_cvref_t<Args>>::signature())
339 + CTString(")")
340 + Traits<R>::signature();
341}
342
343template<typename T, IfValidSignatureTypes<T> = true>
344static constexpr auto fieldSignature()
345{
346 return QtJniTypes::Traits<T>::signature();
347}
348
349template<typename ...Args, IfValidSignatureTypes<Args...> = true>
350static constexpr auto constructorSignature()
351{
352 return methodSignature<void, Args...>();
353}
354
355template<typename Ret, typename ...Args, IfValidSignatureTypes<Ret, Args...> = true>
356static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jobject, Args...))
357{
358 return methodSignature<Ret, Args...>();
359}
360
361template<typename Ret, typename ...Args, IfValidSignatureTypes<Ret, Args...> = true>
362static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jclass, Args...))
363{
364 return methodSignature<Ret, Args...>();
365}
366
367} // namespace QtJniTypes
368
370
371#endif
372
373#endif // QJNITYPES_IMPL_H
NSData * m_data
QMetaType signature()
Combined button and popup list for selecting options.
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool endsWith(QByteArrayView haystack, QByteArrayView needle) noexcept
void assertObjectType(QObjectPrivate *d)
Definition qobject_p.h:262
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool startsWith(QByteArrayView haystack, QByteArrayView needle) noexcept
std::remove_cv_t< std::remove_reference_t< T > > remove_cvref_t
constexpr bool operator!=(const timespec &t1, const timespec &t2)
constexpr timespec operator+(const timespec &t1, const timespec &t2)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
const GLubyte * c
static QT_BEGIN_NAMESPACE bool isPrimitiveType(QMetaType metaType)
bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
Definition qrandom.cpp:1220
char Char
const char className[16]
[1]
Definition qwizard.cpp:100
QAction * at