Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qjnitypes.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_H
5#define QJNITYPES_H
6
7#include <QtCore/qglobal.h>
8
9#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
10#include <jni.h>
11
13
14namespace QtJniTypes
15{
16
17// a constexpr type for string literals of any character width, aware of the length
18// of the string.
19template<size_t N_WITH_NULL, typename BaseType = char>
20struct String
21{
22 BaseType m_data[N_WITH_NULL] = {};
23
24 constexpr String() noexcept {}
25 // Can be instantiated (only) with a string literal
26 constexpr explicit String(const BaseType (&data)[N_WITH_NULL]) noexcept
27 {
28 for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
29 m_data[i] = data[i];
30 }
31
32 constexpr BaseType at(size_t i) const { return m_data[i]; }
33 constexpr BaseType operator[](size_t i) const { return at(i); }
34 static constexpr size_t size() noexcept { return N_WITH_NULL; }
35 constexpr operator const BaseType *() const noexcept { return m_data; }
36 constexpr const BaseType *data() const noexcept { return m_data; }
37 template<size_t N2_WITH_NULL>
38 constexpr bool startsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept
39 {
40 if constexpr (N2_WITH_NULL > N_WITH_NULL) {
41 return false;
42 } else {
43 for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) {
44 if (m_data[i] != lit[i])
45 return false;
46 }
47 }
48 return true;
49 }
50 constexpr bool startsWith(BaseType c) const noexcept
51 {
52 return N_WITH_NULL > 1 && m_data[0] == c;
53 }
54 template<size_t N2_WITH_NULL>
55 constexpr bool endsWith(const BaseType (&lit)[N2_WITH_NULL]) const noexcept
56 {
57 if constexpr (N2_WITH_NULL > N_WITH_NULL) {
58 return false;
59 } else {
60 for (size_t i = 0; i < N2_WITH_NULL; ++i) {
61 if (m_data[N_WITH_NULL - i - 1] != lit[N2_WITH_NULL - i - 1])
62 return false;
63 }
64 }
65 return true;
66 }
67 constexpr bool endsWith(BaseType c) const noexcept
68 {
69 return N_WITH_NULL > 1 && m_data[N_WITH_NULL - 2] == c;
70 }
71
72 template<size_t N2_WITH_NULL>
73 friend inline constexpr bool operator==(const String<N_WITH_NULL> &lhs,
74 const String<N2_WITH_NULL> &rhs) noexcept
75 {
76 if constexpr (N_WITH_NULL != N2_WITH_NULL) {
77 return false;
78 } else {
79 for (size_t i = 0; i < N_WITH_NULL - 1; ++i) {
80 if (lhs.at(i) != rhs.at(i))
81 return false;
82 }
83 }
84 return true;
85 }
86
87 template<size_t N2_WITH_NULL>
88 friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs,
89 const String<N2_WITH_NULL> &rhs) noexcept
90 {
91 return !operator==(lhs, rhs);
92 }
93
94 template<size_t N2_WITH_NULL>
95 friend inline constexpr bool operator==(const String<N_WITH_NULL> &lhs,
96 const BaseType (&rhs)[N2_WITH_NULL]) noexcept
97 {
98 return operator==(lhs, String<N2_WITH_NULL>(rhs));
99 }
100 template<size_t N2_WITH_NULL>
101 friend inline constexpr bool operator==(const BaseType (&lhs)[N2_WITH_NULL],
102 const String<N_WITH_NULL> &rhs) noexcept
103 {
104 return operator==(String<N2_WITH_NULL>(lhs), rhs);
105 }
106
107 template<size_t N2_WITH_NULL>
108 friend inline constexpr bool operator!=(const String<N_WITH_NULL> &lhs,
109 const BaseType (&rhs)[N2_WITH_NULL]) noexcept
110 {
111 return operator!=(lhs, String<N2_WITH_NULL>(rhs));
112 }
113 template<size_t N2_WITH_NULL>
114 friend inline constexpr bool operator!=(const BaseType (&lhs)[N2_WITH_NULL],
115 const String<N_WITH_NULL> &rhs) noexcept
116 {
117 return operator!=(String<N2_WITH_NULL>(lhs), rhs);
118 }
119
120 template<size_t N2_WITH_NULL>
121 friend inline constexpr auto operator+(const String<N_WITH_NULL> &lhs,
122 const String<N2_WITH_NULL> &rhs) noexcept
123 {
124 char data[N_WITH_NULL + N2_WITH_NULL - 1] = {};
125 for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
126 data[i] = lhs[i];
127 for (size_t i = 0; i < N2_WITH_NULL - 1; ++i)
128 data[N_WITH_NULL - 1 + i] = rhs[i];
129 return String<N_WITH_NULL + N2_WITH_NULL - 1>(data);
130 }
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<size_t N> struct IsStringType<String<N>> : std::true_type {};
139template<size_t N> struct IsStringType<const char[N]> : std::true_type {};
140
141template<bool flag = false>
142static void staticAssertTypeMismatch()
143{
144 static_assert(flag, "The used type is not supported by this template call. "
145 "Use a JNI based type instead.");
146}
147
148template<typename T>
149constexpr auto typeSignature()
150{
151 if constexpr(std::is_array_v<T>) {
152 using UnderlyingType = typename std::remove_extent<T>::type;
153 static_assert(!std::is_array_v<UnderlyingType>,
154 "typeSignature() does not handle multi-dimensional arrays");
155 return String("[") + typeSignature<UnderlyingType>();
156 } else if constexpr(std::is_same_v<T, jobject>) {
157 return String("Ljava/lang/Object;");
158 } else if constexpr(std::is_same_v<T, jclass>) {
159 return String("Ljava/lang/Class;");
160 } else if constexpr(std::is_same_v<T, jstring>) {
161 return String("Ljava/lang/String;");
162 } else if constexpr(std::is_same_v<T, jobjectArray>) {
163 return String("[Ljava/lang/Object;");
164 } else if constexpr(std::is_same_v<T, jthrowable>) {
165 return String("Ljava/lang/Throwable;");
166 } else if constexpr(std::is_same_v<T, jbooleanArray>) {
167 return String("[Z");
168 } else if constexpr(std::is_same_v<T, jbyteArray>) {
169 return String("[B");
170 } else if constexpr(std::is_same_v<T, jshortArray>) {
171 return String("[S");
172 } else if constexpr(std::is_same_v<T, jintArray>) {
173 return String("[I");
174 } else if constexpr(std::is_same_v<T, jlongArray>) {
175 return String("[J");
176 } else if constexpr(std::is_same_v<T, jfloatArray>) {
177 return String("[F");
178 } else if constexpr(std::is_same_v<T, jdoubleArray>) {
179 return String("[D");
180 } else if constexpr(std::is_same_v<T, jcharArray>) {
181 return String("[C");
182 } else if constexpr(std::is_same_v<T, jboolean>) {
183 return String("Z");
184 } else if constexpr(std::is_same_v<T, bool>) {
185 return String("Z");
186 } else if constexpr(std::is_same_v<T, jbyte>) {
187 return String("B");
188 } else if constexpr(std::is_same_v<T, jchar>) {
189 return String("C");
190 } else if constexpr(std::is_same_v<T, char>) {
191 return String("C");
192 } else if constexpr(std::is_same_v<T, jshort>) {
193 return String("S");
194 } else if constexpr(std::is_same_v<T, short>) {
195 return String("S");
196 } else if constexpr(std::is_same_v<T, jint>) {
197 return String("I");
198 } else if constexpr(std::is_same_v<T, int>) {
199 return String("I");
200 } else if constexpr(std::is_same_v<T, uint>) {
201 return String("I");
202 } else if constexpr(std::is_same_v<T, jlong>) {
203 return String("J");
204 } else if constexpr(std::is_same_v<T, long>) {
205 return String("J");
206 } else if constexpr(std::is_same_v<T, jfloat>) {
207 return String("F");
208 } else if constexpr(std::is_same_v<T, float>) {
209 return String("F");
210 } else if constexpr(std::is_same_v<T, jdouble>) {
211 return String("D");
212 } else if constexpr(std::is_same_v<T, double>) {
213 return String("D");
214 } else if constexpr(std::is_same_v<T, void>) {
215 return String("V");
216 } else if constexpr(IsStringType<T>::value) {
217 static_assert(!IsStringType<T>::value, "Don't use a literal type, call data!");
218 } else {
219 staticAssertTypeMismatch();
220 }
221}
222
223template<bool flag = false>
224static void staticAssertClassNotRegistered()
225{
226 static_assert(flag, "Class not registered, use Q_DECLARE_JNI_CLASS");
227}
228
229template<typename T>
230constexpr auto className()
231{
232 if constexpr(std::is_same<T, jstring>::value)
233 return String("java/lang/String");
234 else
235 staticAssertClassNotRegistered();
236}
237
238template<typename T>
239static constexpr bool isPrimitiveType()
240{
241 return typeSignature<T>().size() == 2;
242}
243
244template<typename T>
245static constexpr bool isObjectType()
246{
247 if constexpr(std::is_convertible<T, jobject>::value) {
248 return true;
249 } else {
250 constexpr auto signature = typeSignature<T>();
251 return (signature.startsWith('L') || signature.startsWith('['))
252 && signature.endsWith(';');
253 }
254}
255
256template<typename T>
257static constexpr bool isArrayType()
258{
259 constexpr auto signature = typeSignature<T>();
260 return signature.startsWith('[');
261}
262
263template<typename T>
264static constexpr void assertPrimitiveType()
265{
266 static_assert(isPrimitiveType<T>(), "Type needs to be a primitive JNI type!");
267}
268
269template<typename T>
270static constexpr void assertObjectType()
271{
272 static_assert(isObjectType<T>(),
273 "Type needs to be a JNI object type (convertible to jobject, or with "
274 "an object type signature registered)!");
275}
276
277template<typename T>
278static constexpr void assertType()
279{
280 static_assert(isPrimitiveType<T>() || isObjectType<T>(),
281 "Type needs to be a JNI type!");
282}
283
284template<typename R, typename ...Args>
285static constexpr auto methodSignature()
286{
287 return (String("(") +
288 ... + typeSignature<std::decay_t<Args>>())
289 + String(")")
290 + typeSignature<R>();
291}
292
293template<typename T>
294static constexpr auto fieldSignature()
295{
296 return QtJniTypes::typeSignature<T>();
297}
298
299template<typename ...Args>
300static constexpr auto constructorSignature()
301{
302 return methodSignature<void, Args...>();
303}
304
305template<typename Ret, typename ...Args>
306static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jobject, Args...))
307{
308 return methodSignature<Ret, Args...>();
309}
310
311template<typename Ret, typename ...Args>
312static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jclass, Args...))
313{
314 return methodSignature<Ret, Args...>();
315}
316
317// A generic thin wrapper around jobject, convertible to jobject.
318// We need this as a baseclass so that QJniObject can be implicitly
319// constructed from the various subclasses - we can't provide an
320// operator QJniObject() here as the class is not declared.
321struct Object
322{
323 jobject _object;
324 constexpr operator jobject() const { return _object; }
325};
326
327} // namespace QtJniTypes
328
329#define Q_DECLARE_JNI_TYPE_HELPER(Type) \
330namespace QtJniTypes { \
331struct Type : Object \
332{ \
333 constexpr Type(jobject o) noexcept : Object{o} {} \
334}; \
335} \
336
337
338#define Q_DECLARE_JNI_TYPE(Type, Signature) \
339Q_DECLARE_JNI_TYPE_HELPER(Type) \
340template<> \
341constexpr auto QtJniTypes::typeSignature<QtJniTypes::Type>() \
342{ \
343 static_assert((Signature[0] == 'L' || Signature[0] == '[') \
344 && Signature[sizeof(Signature) - 2] == ';', \
345 "Type signature needs to start with 'L' or '['" \
346 " and end with ';'"); \
347 return QtJniTypes::String(Signature); \
348} \
349
350#define Q_DECLARE_JNI_CLASS(Type, Signature) \
351Q_DECLARE_JNI_TYPE_HELPER(Type) \
352template<> \
353constexpr auto QtJniTypes::className<QtJniTypes::Type>() \
354{ \
355 return QtJniTypes::String(Signature); \
356} \
357template<> \
358constexpr auto QtJniTypes::typeSignature<QtJniTypes::Type>() \
359{ \
360 return QtJniTypes::String("L") \
361 + QtJniTypes::String(Signature) \
362 + QtJniTypes::String(";"); \
363} \
364
365#define Q_DECLARE_JNI_NATIVE_METHOD(...) \
366 QT_OVERLOADED_MACRO(QT_DECLARE_JNI_NATIVE_METHOD, __VA_ARGS__) \
367
368#define QT_DECLARE_JNI_NATIVE_METHOD_2(Method, Name) \
369namespace QtJniMethods { \
370static constexpr auto Method##_signature = \
371 QtJniTypes::nativeMethodSignature(Method); \
372static const JNINativeMethod Method##_method = { \
373 #Name, Method##_signature.data(), \
374 reinterpret_cast<void *>(Method) \
375}; \
376} \
377
378#define QT_DECLARE_JNI_NATIVE_METHOD_1(Method) \
379 QT_DECLARE_JNI_NATIVE_METHOD_2(Method, Method) \
380
381#define Q_JNI_NATIVE_METHOD(Method) QtJniMethods::Method##_method
382
383#define Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(...) \
384 QT_OVERLOADED_MACRO(QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE, __VA_ARGS__) \
385
386#define QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(Method, Name) \
387 static inline constexpr auto Method##_signature = QtJniTypes::nativeMethodSignature(Method); \
388 static inline const JNINativeMethod Method##_method = { \
389 #Name, Method##_signature.data(), reinterpret_cast<void *>(Method) \
390 };
391
392#define QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_1(Method) \
393 QT_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE_2(Method, Method) \
394
395#define Q_JNI_NATIVE_SCOPED_METHOD(Method, Scope) Scope::Method##_method
396
398
399#endif
400
401#endif // QJNITYPES_H
NSData * m_data
Definition main.cpp:8
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:261
Q_CORE_EXPORT Q_DECL_PURE_FUNCTION bool startsWith(QByteArrayView haystack, QByteArrayView needle) noexcept
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
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:1219
const char className[16]
[1]
Definition qwizard.cpp:100
QAction * at