5#ifndef QJNITYPES_IMPL_H
6#define QJNITYPES_IMPL_H
8#include <QtCore/qstring.h>
10#include <QtCore/q26numeric.h>
11#include <QtCore/q20type_traits.h>
12#include <QtCore/q20utility.h>
14#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
26static inline jstring fromQString(
const QString &string, JNIEnv *env)
28 if (!q20::in_range<jsize>(string.size()))
29 qWarning(
"String is too large for a Java string and will be truncated");
30 const jsize length = q26::saturate_cast<jsize>(string.size());
31 return env->NewString(
reinterpret_cast<
const jchar*>(string.constData()), length);
34static inline QString toQString(jstring string, JNIEnv *env)
37 const jsize length = env->GetStringLength(string);
38 QString res(length, Qt::Uninitialized);
39 env->GetStringRegion(string, 0, length,
reinterpret_cast<jchar *>(res.data_ptr().data()));
46template<size_t N_WITH_NULL,
typename BaseType =
char>
49 BaseType m_data[N_WITH_NULL] = {};
51 constexpr CTString()
noexcept {}
53 constexpr explicit CTString(
const BaseType (&data)[N_WITH_NULL])
noexcept
55 for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
59 constexpr BaseType at(size_t i)
const {
return m_data[i]; }
60 constexpr BaseType operator[](size_t i)
const {
return at(i); }
61 static constexpr size_t size()
noexcept {
return N_WITH_NULL; }
62 constexpr operator
const BaseType *()
const noexcept {
return m_data; }
63 constexpr const BaseType *data()
const noexcept {
return m_data; }
64 template<size_t N2_WITH_NULL>
65 constexpr bool startsWith(
const BaseType (&lit)[N2_WITH_NULL])
const noexcept
67 if constexpr (N2_WITH_NULL > N_WITH_NULL) {
70 for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) {
71 if (m_data[i] != lit[i])
77 constexpr bool startsWith(BaseType c)
const noexcept
79 return N_WITH_NULL > 1 && m_data[0] == c;
81 template<size_t N2_WITH_NULL>
82 constexpr bool endsWith(
const BaseType (&lit)[N2_WITH_NULL])
const noexcept
84 if constexpr (N2_WITH_NULL > N_WITH_NULL) {
87 for (size_t i = 0; i < N2_WITH_NULL; ++i) {
88 if (m_data[N_WITH_NULL - i - 1] != lit[N2_WITH_NULL - i - 1])
94 constexpr bool endsWith(BaseType c)
const noexcept
96 return N_WITH_NULL > 1 && m_data[N_WITH_NULL - 2] == c;
99 template<size_t N2_WITH_NULL>
100 friend inline constexpr bool operator==(
const CTString<N_WITH_NULL> &lhs,
101 const CTString<N2_WITH_NULL> &rhs)
noexcept
103 if constexpr (N_WITH_NULL != N2_WITH_NULL) {
106 for (size_t i = 0; i < N_WITH_NULL - 1; ++i) {
107 if (lhs.at(i) != rhs.at(i))
114 template<size_t N2_WITH_NULL>
115 friend inline constexpr bool operator!=(
const CTString<N_WITH_NULL> &lhs,
116 const CTString<N2_WITH_NULL> &rhs)
noexcept
118 return !operator==(lhs, rhs);
121 template<size_t N2_WITH_NULL>
122 friend inline constexpr bool operator==(
const CTString<N_WITH_NULL> &lhs,
123 const BaseType (&rhs)[N2_WITH_NULL])
noexcept
125 return operator==(lhs, CTString<N2_WITH_NULL>(rhs));
127 template<size_t N2_WITH_NULL>
128 friend inline constexpr bool operator==(
const BaseType (&lhs)[N2_WITH_NULL],
129 const CTString<N_WITH_NULL> &rhs)
noexcept
131 return operator==(CTString<N2_WITH_NULL>(lhs), rhs);
134 template<size_t N2_WITH_NULL>
135 friend inline constexpr bool operator!=(
const CTString<N_WITH_NULL> &lhs,
136 const BaseType (&rhs)[N2_WITH_NULL])
noexcept
138 return operator!=(lhs, CTString<N2_WITH_NULL>(rhs));
140 template<size_t N2_WITH_NULL>
141 friend inline constexpr bool operator!=(
const BaseType (&lhs)[N2_WITH_NULL],
142 const CTString<N_WITH_NULL> &rhs)
noexcept
144 return operator!=(CTString<N2_WITH_NULL>(lhs), rhs);
147 template<size_t N2_WITH_NULL>
148 friend inline constexpr auto operator+(
const CTString<N_WITH_NULL> &lhs,
149 const CTString<N2_WITH_NULL> &rhs)
noexcept
151 char data[N_WITH_NULL + N2_WITH_NULL - 1] = {};
152 for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
154 for (size_t i = 0; i < N2_WITH_NULL - 1; ++i)
155 data[N_WITH_NULL - 1 + i] = rhs[i];
156 return CTString<N_WITH_NULL + N2_WITH_NULL - 1>(data);
162template<
typename T, size_t N = 0>
struct IsStringType : std::false_type {};
163template<>
struct IsStringType<
const char *, 0> : std::true_type {};
164template<>
struct IsStringType<
const char *&, 0> : std::true_type {};
165template<size_t N>
struct IsStringType<CTString<N>> : std::true_type {};
166template<size_t N>
struct IsStringType<
const char[N]> : std::true_type {};
167template<size_t N>
struct IsStringType<
const char(&)[N]> : std::true_type {};
168template<size_t N>
struct IsStringType<
char[N]> : std::true_type {};
170template <
typename T,
typename =
void>
177 static constexpr auto className()
179 if constexpr (std::is_same_v<T, jstring>)
180 return CTString(
"java/lang/String");
181 else if constexpr (std::is_same_v<T, jobject>)
182 return CTString(
"java/lang/Object");
183 else if constexpr (std::is_same_v<T, jclass>)
184 return CTString(
"java/lang/Class");
185 else if constexpr (std::is_same_v<T, jthrowable>)
186 return CTString(
"java/lang/Throwable");
190 static constexpr auto signature()
192 if constexpr (!std::is_same_v<
decltype(className()),
void>) {
194 return CTString(
"L") + className() + CTString(
";");
195 }
else if constexpr (std::is_same_v<T, jobjectArray>) {
196 return CTString(
"[Ljava/lang/Object;");
197 }
else if constexpr (std::is_same_v<T, jbooleanArray>) {
198 return CTString(
"[Z");
199 }
else if constexpr (std::is_same_v<T, jbyteArray>) {
200 return CTString(
"[B");
201 }
else if constexpr (std::is_same_v<T, jshortArray>) {
202 return CTString(
"[S");
203 }
else if constexpr (std::is_same_v<T, jintArray>) {
204 return CTString(
"[I");
205 }
else if constexpr (std::is_same_v<T, jlongArray>) {
206 return CTString(
"[J");
207 }
else if constexpr (std::is_same_v<T, jfloatArray>) {
208 return CTString(
"[F");
209 }
else if constexpr (std::is_same_v<T, jdoubleArray>) {
210 return CTString(
"[D");
211 }
else if constexpr (std::is_same_v<T, jcharArray>) {
212 return CTString(
"[C");
213 }
else if constexpr (std::is_same_v<T, jboolean>) {
214 return CTString(
"Z");
215 }
else if constexpr (std::is_same_v<T,
bool>) {
216 return CTString(
"Z");
217 }
else if constexpr (std::is_same_v<T, jbyte>) {
218 return CTString(
"B");
219 }
else if constexpr (std::is_same_v<T, jchar>) {
220 return CTString(
"C");
221 }
else if constexpr (std::is_same_v<T,
char>) {
222 return CTString(
"C");
223 }
else if constexpr (std::is_same_v<T, jshort>) {
224 return CTString(
"S");
225 }
else if constexpr (std::is_same_v<T,
short>) {
226 return CTString(
"S");
227 }
else if constexpr (std::is_same_v<T, jint>) {
228 return CTString(
"I");
229 }
else if constexpr (std::is_same_v<T,
int>) {
230 return CTString(
"I");
231 }
else if constexpr (std::is_same_v<T, uint>) {
232 return CTString(
"I");
233 }
else if constexpr (std::is_same_v<T, jlong>) {
234 return CTString(
"J");
235 }
else if constexpr (std::is_same_v<T, quint64>) {
236 return CTString(
"J");
237 }
else if constexpr (std::is_same_v<T, jfloat>) {
238 return CTString(
"F");
239 }
else if constexpr (std::is_same_v<T,
float>) {
240 return CTString(
"F");
241 }
else if constexpr (std::is_same_v<T, jdouble>) {
242 return CTString(
"D");
243 }
else if constexpr (std::is_same_v<T,
double>) {
244 return CTString(
"D");
245 }
else if constexpr (std::is_same_v<T,
void>) {
246 return CTString(
"V");
247 }
else if constexpr (std::is_enum_v<T>) {
248 return Traits<std::underlying_type_t<T>>::signature();
253 template <
typename U = T>
254 static auto convertToJni(JNIEnv *, U &&value)
256 return std::forward<U>(value);
258 static auto convertFromJni(QJniObject &&object)
260 return std::move(object);
264template <
typename Have,
typename Want>
265static constexpr bool sameTypeForJni = (QtJniTypes::Traits<Have>::signature()
266 == QtJniTypes::Traits<Want>::signature())
267 && (
sizeof(Have) ==
sizeof(Want));
269template <
typename,
typename =
void>
273#define MAKE_CALLER(Type, Method) template
275 Caller<T, std::enable_if_t<sameTypeForJni<T, Type>>> \
276{
277 static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj, jmethodID id, va_list args)
279 res = T(env->Call##Method##MethodV(obj, id, args));
281 static constexpr void callStaticMethodForType(JNIEnv *env, T &res, jclass clazz, jmethodID id, va_list args)
283 res = T(env->CallStatic##Method##MethodV(clazz, id, args));
285 static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, jfieldID id)
287 res = T(env->Get##Method##Field(obj, id));
289 static constexpr void getStaticFieldForType(JNIEnv *env, T &res, jclass clazz, jfieldID id)
291 res = T(env->GetStatic##Method##Field(clazz, id));
293 static constexpr void setFieldForType(JNIEnv *env, jobject obj, jfieldID id, T value)
295 env->Set##Method##Field(obj, id, static_cast<Type>(value));
297 static constexpr void setStaticFieldForType(JNIEnv *env, jclass clazz, jfieldID id, T value)
299 env->SetStatic##Method##Field(clazz, id, static_cast<Type>(value));
301}
303MAKE_CALLER(jboolean, Boolean);
304MAKE_CALLER(jbyte, Byte);
305MAKE_CALLER(jchar, Char);
306MAKE_CALLER(jshort, Short);
307MAKE_CALLER(jint, Int);
308MAKE_CALLER(jlong, Long);
309MAKE_CALLER(jfloat, Float);
310MAKE_CALLER(jdouble, Double);
315static constexpr bool isPrimitiveType()
317 return Traits<T>::signature().size() == 2;
321static constexpr bool isArrayType()
323 constexpr auto signature = Traits<T>::signature();
324 return signature.startsWith(
'[') && signature.size() > 2;
328static constexpr bool isObjectType()
330 if constexpr (std::is_convertible_v<T, jobject>) {
333 constexpr auto signature = Traits<T>::signature();
334 return (signature.startsWith(
'L') && signature.endsWith(
';')) || isArrayType<T>();
339static constexpr void assertObjectType()
341 static_assert(isObjectType<T>(),
342 "Type needs to be a JNI object type (convertible to jobject, or with "
343 "an object type signature registered)!");
347template<
typename ...Types>
348constexpr bool ValidSignatureTypesDetail = !std::disjunction<std::is_same<
349 decltype(Traits<Types>::signature()),
351 IsStringType<Types>...>::value;
352template<
typename ...Types>
353using IfValidSignatureTypes = std::enable_if_t<
354 ValidSignatureTypesDetail<q20::remove_cvref_t<Types>...>,
bool>;
356template<
typename Type>
357constexpr bool ValidFieldTypeDetail = isObjectType<Type>() || isPrimitiveType<Type>();
358template<
typename Type>
359using IfValidFieldType = std::enable_if_t<
360 ValidFieldTypeDetail<q20::remove_cvref_t<Type>>,
bool>;
363template<
typename R,
typename ...Args, IfValidSignatureTypes<R, Args...> =
true>
364static constexpr auto methodSignature()
366 return (CTString(
"(") +
367 ... + Traits<q20::remove_cvref_t<Args>>::signature())
369 + Traits<R>::signature();
372template<
typename T, IfValidSignatureTypes<T> =
true>
373static constexpr auto fieldSignature()
375 return QtJniTypes::Traits<T>::signature();
378template<
typename ...Args, IfValidSignatureTypes<Args...> =
true>
379static constexpr auto constructorSignature()
381 return methodSignature<
void, Args...>();
384template<
typename Ret,
typename ...Args, IfValidSignatureTypes<Ret, Args...> =
true>
385static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jobject, Args...))
387 return methodSignature<Ret, Args...>();
390template<
typename Ret,
typename ...Args, IfValidSignatureTypes<Ret, Args...> =
true>
391static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jclass, Args...))
393 return methodSignature<Ret, Args...>();