4#ifndef QJNITYPES_IMPL_H
5#define QJNITYPES_IMPL_H
7#include <QtCore/qstring.h>
9#include <QtCore/q26numeric.h>
10#include <QtCore/q20type_traits.h>
11#include <QtCore/q20utility.h>
13#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
25static inline jstring fromQString(
const QString &string, JNIEnv *env)
27 if (!q20::in_range<jsize>(string.size()))
28 qWarning(
"String is too large for a Java string and will be truncated");
29 const jsize length = q26::saturate_cast<jsize>(string.size());
30 return env->NewString(
reinterpret_cast<
const jchar*>(string.constData()), length);
33static inline QString toQString(jstring string, JNIEnv *env)
36 const jsize length = env->GetStringLength(string);
37 QString res(length, Qt::Uninitialized);
38 env->GetStringRegion(string, 0, length,
reinterpret_cast<jchar *>(res.data_ptr().data()));
45template<size_t N_WITH_NULL,
typename BaseType =
char>
48 BaseType m_data[N_WITH_NULL] = {};
50 constexpr CTString()
noexcept {}
52 constexpr explicit CTString(
const BaseType (&data)[N_WITH_NULL])
noexcept
54 for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
58 constexpr BaseType at(size_t i)
const {
return m_data[i]; }
59 constexpr BaseType operator[](size_t i)
const {
return at(i); }
60 static constexpr size_t size()
noexcept {
return N_WITH_NULL; }
61 constexpr operator
const BaseType *()
const noexcept {
return m_data; }
62 constexpr const BaseType *data()
const noexcept {
return m_data; }
63 template<size_t N2_WITH_NULL>
64 constexpr bool startsWith(
const BaseType (&lit)[N2_WITH_NULL])
const noexcept
66 if constexpr (N2_WITH_NULL > N_WITH_NULL) {
69 for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) {
70 if (m_data[i] != lit[i])
76 constexpr bool startsWith(BaseType c)
const noexcept
78 return N_WITH_NULL > 1 && m_data[0] == c;
80 template<size_t N2_WITH_NULL>
81 constexpr bool endsWith(
const BaseType (&lit)[N2_WITH_NULL])
const noexcept
83 if constexpr (N2_WITH_NULL > N_WITH_NULL) {
86 for (size_t i = 0; i < N2_WITH_NULL; ++i) {
87 if (m_data[N_WITH_NULL - i - 1] != lit[N2_WITH_NULL - i - 1])
93 constexpr bool endsWith(BaseType c)
const noexcept
95 return N_WITH_NULL > 1 && m_data[N_WITH_NULL - 2] == c;
98 template<size_t N2_WITH_NULL>
99 friend inline constexpr bool operator==(
const CTString<N_WITH_NULL> &lhs,
100 const CTString<N2_WITH_NULL> &rhs)
noexcept
102 if constexpr (N_WITH_NULL != N2_WITH_NULL) {
105 for (size_t i = 0; i < N_WITH_NULL - 1; ++i) {
106 if (lhs.at(i) != rhs.at(i))
113 template<size_t N2_WITH_NULL>
114 friend inline constexpr bool operator!=(
const CTString<N_WITH_NULL> &lhs,
115 const CTString<N2_WITH_NULL> &rhs)
noexcept
117 return !operator==(lhs, rhs);
120 template<size_t N2_WITH_NULL>
121 friend inline constexpr bool operator==(
const CTString<N_WITH_NULL> &lhs,
122 const BaseType (&rhs)[N2_WITH_NULL])
noexcept
124 return operator==(lhs, CTString<N2_WITH_NULL>(rhs));
126 template<size_t N2_WITH_NULL>
127 friend inline constexpr bool operator==(
const BaseType (&lhs)[N2_WITH_NULL],
128 const CTString<N_WITH_NULL> &rhs)
noexcept
130 return operator==(CTString<N2_WITH_NULL>(lhs), rhs);
133 template<size_t N2_WITH_NULL>
134 friend inline constexpr bool operator!=(
const CTString<N_WITH_NULL> &lhs,
135 const BaseType (&rhs)[N2_WITH_NULL])
noexcept
137 return operator!=(lhs, CTString<N2_WITH_NULL>(rhs));
139 template<size_t N2_WITH_NULL>
140 friend inline constexpr bool operator!=(
const BaseType (&lhs)[N2_WITH_NULL],
141 const CTString<N_WITH_NULL> &rhs)
noexcept
143 return operator!=(CTString<N2_WITH_NULL>(lhs), rhs);
146 template<size_t N2_WITH_NULL>
147 friend inline constexpr auto operator+(
const CTString<N_WITH_NULL> &lhs,
148 const CTString<N2_WITH_NULL> &rhs)
noexcept
150 char data[N_WITH_NULL + N2_WITH_NULL - 1] = {};
151 for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
153 for (size_t i = 0; i < N2_WITH_NULL - 1; ++i)
154 data[N_WITH_NULL - 1 + i] = rhs[i];
155 return CTString<N_WITH_NULL + N2_WITH_NULL - 1>(data);
161template<
typename T, size_t N = 0>
struct IsStringType : std::false_type {};
162template<>
struct IsStringType<
const char *, 0> : std::true_type {};
163template<>
struct IsStringType<
const char *&, 0> : std::true_type {};
164template<size_t N>
struct IsStringType<CTString<N>> : std::true_type {};
165template<size_t N>
struct IsStringType<
const char[N]> : std::true_type {};
166template<size_t N>
struct IsStringType<
const char(&)[N]> : std::true_type {};
167template<size_t N>
struct IsStringType<
char[N]> : std::true_type {};
169template <
typename T,
typename =
void>
176 static constexpr auto className()
178 if constexpr (std::is_same_v<T, jstring>)
179 return CTString(
"java/lang/String");
180 else if constexpr (std::is_same_v<T, jobject>)
181 return CTString(
"java/lang/Object");
182 else if constexpr (std::is_same_v<T, jclass>)
183 return CTString(
"java/lang/Class");
184 else if constexpr (std::is_same_v<T, jthrowable>)
185 return CTString(
"java/lang/Throwable");
189 static constexpr auto signature()
191 if constexpr (!std::is_same_v<
decltype(className()),
void>) {
193 return CTString(
"L") + className() + CTString(
";");
194 }
else if constexpr (std::is_same_v<T, jobjectArray>) {
195 return CTString(
"[Ljava/lang/Object;");
196 }
else if constexpr (std::is_same_v<T, jbooleanArray>) {
197 return CTString(
"[Z");
198 }
else if constexpr (std::is_same_v<T, jbyteArray>) {
199 return CTString(
"[B");
200 }
else if constexpr (std::is_same_v<T, jshortArray>) {
201 return CTString(
"[S");
202 }
else if constexpr (std::is_same_v<T, jintArray>) {
203 return CTString(
"[I");
204 }
else if constexpr (std::is_same_v<T, jlongArray>) {
205 return CTString(
"[J");
206 }
else if constexpr (std::is_same_v<T, jfloatArray>) {
207 return CTString(
"[F");
208 }
else if constexpr (std::is_same_v<T, jdoubleArray>) {
209 return CTString(
"[D");
210 }
else if constexpr (std::is_same_v<T, jcharArray>) {
211 return CTString(
"[C");
212 }
else if constexpr (std::is_same_v<T, jboolean>) {
213 return CTString(
"Z");
214 }
else if constexpr (std::is_same_v<T,
bool>) {
215 return CTString(
"Z");
216 }
else if constexpr (std::is_same_v<T, jbyte>) {
217 return CTString(
"B");
218 }
else if constexpr (std::is_same_v<T, jchar>) {
219 return CTString(
"C");
220 }
else if constexpr (std::is_same_v<T,
char>) {
221 return CTString(
"C");
222 }
else if constexpr (std::is_same_v<T, jshort>) {
223 return CTString(
"S");
224 }
else if constexpr (std::is_same_v<T,
short>) {
225 return CTString(
"S");
226 }
else if constexpr (std::is_same_v<T, jint>) {
227 return CTString(
"I");
228 }
else if constexpr (std::is_same_v<T,
int>) {
229 return CTString(
"I");
230 }
else if constexpr (std::is_same_v<T, uint>) {
231 return CTString(
"I");
232 }
else if constexpr (std::is_same_v<T, jlong>) {
233 return CTString(
"J");
234 }
else if constexpr (std::is_same_v<T, quint64>) {
235 return CTString(
"J");
236 }
else if constexpr (std::is_same_v<T, jfloat>) {
237 return CTString(
"F");
238 }
else if constexpr (std::is_same_v<T,
float>) {
239 return CTString(
"F");
240 }
else if constexpr (std::is_same_v<T, jdouble>) {
241 return CTString(
"D");
242 }
else if constexpr (std::is_same_v<T,
double>) {
243 return CTString(
"D");
244 }
else if constexpr (std::is_same_v<T,
void>) {
245 return CTString(
"V");
246 }
else if constexpr (std::is_enum_v<T>) {
247 return Traits<std::underlying_type_t<T>>::signature();
252 template <
typename U = T>
253 static auto convertToJni(JNIEnv *, U &&value)
255 return std::forward<U>(value);
257 static auto convertFromJni(QJniObject &&object)
259 return std::move(object);
263template <
typename Have,
typename Want>
264static constexpr bool sameTypeForJni = (QtJniTypes::Traits<Have>::signature()
265 == QtJniTypes::Traits<Want>::signature())
266 && (
sizeof(Have) ==
sizeof(Want));
268template <
typename,
typename =
void>
272#define MAKE_CALLER(Type, Method) template
274 Caller<T, std::enable_if_t<sameTypeForJni<T, Type>>> \
275{
276 static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj, jmethodID id, va_list args)
278 res = T(env->Call##Method##MethodV(obj, id, args));
280 static constexpr void callStaticMethodForType(JNIEnv *env, T &res, jclass clazz, jmethodID id, va_list args)
282 res = T(env->CallStatic##Method##MethodV(clazz, id, args));
284 static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, jfieldID id)
286 res = T(env->Get##Method##Field(obj, id));
288 static constexpr void getStaticFieldForType(JNIEnv *env, T &res, jclass clazz, jfieldID id)
290 res = T(env->GetStatic##Method##Field(clazz, id));
292 static constexpr void setFieldForType(JNIEnv *env, jobject obj, jfieldID id, T value)
294 env->Set##Method##Field(obj, id, static_cast<Type>(value));
296 static constexpr void setStaticFieldForType(JNIEnv *env, jclass clazz, jfieldID id, T value)
298 env->SetStatic##Method##Field(clazz, id, static_cast<Type>(value));
300}
302MAKE_CALLER(jboolean, Boolean);
303MAKE_CALLER(jbyte, Byte);
304MAKE_CALLER(jchar, Char);
305MAKE_CALLER(jshort, Short);
306MAKE_CALLER(jint, Int);
307MAKE_CALLER(jlong, Long);
308MAKE_CALLER(jfloat, Float);
309MAKE_CALLER(jdouble, Double);
314static constexpr bool isPrimitiveType()
316 return Traits<T>::signature().size() == 2;
320static constexpr bool isArrayType()
322 constexpr auto signature = Traits<T>::signature();
323 return signature.startsWith(
'[') && signature.size() > 2;
327static constexpr bool isObjectType()
329 if constexpr (std::is_convertible_v<T, jobject>) {
332 constexpr auto signature = Traits<T>::signature();
333 return (signature.startsWith(
'L') && signature.endsWith(
';')) || isArrayType<T>();
338static constexpr void assertObjectType()
340 static_assert(isObjectType<T>(),
341 "Type needs to be a JNI object type (convertible to jobject, or with "
342 "an object type signature registered)!");
346template<
typename ...Types>
347constexpr bool ValidSignatureTypesDetail = !std::disjunction<std::is_same<
348 decltype(Traits<Types>::signature()),
350 IsStringType<Types>...>::value;
351template<
typename ...Types>
352using IfValidSignatureTypes = std::enable_if_t<
353 ValidSignatureTypesDetail<q20::remove_cvref_t<Types>...>,
bool>;
355template<
typename Type>
356constexpr bool ValidFieldTypeDetail = isObjectType<Type>() || isPrimitiveType<Type>();
357template<
typename Type>
358using IfValidFieldType = std::enable_if_t<
359 ValidFieldTypeDetail<q20::remove_cvref_t<Type>>,
bool>;
362template<
typename R,
typename ...Args, IfValidSignatureTypes<R, Args...> =
true>
363static constexpr auto methodSignature()
365 return (CTString(
"(") +
366 ... + Traits<q20::remove_cvref_t<Args>>::signature())
368 + Traits<R>::signature();
371template<
typename T, IfValidSignatureTypes<T> =
true>
372static constexpr auto fieldSignature()
374 return QtJniTypes::Traits<T>::signature();
377template<
typename ...Args, IfValidSignatureTypes<Args...> =
true>
378static constexpr auto constructorSignature()
380 return methodSignature<
void, Args...>();
383template<
typename Ret,
typename ...Args, IfValidSignatureTypes<Ret, Args...> =
true>
384static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jobject, Args...))
386 return methodSignature<Ret, Args...>();
389template<
typename Ret,
typename ...Args, IfValidSignatureTypes<Ret, Args...> =
true>
390static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jclass, Args...))
392 return methodSignature<Ret, Args...>();