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(QStringView 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::saturating_cast<jsize>(string.size());
31 return env->NewString(
reinterpret_cast<
const jchar*>(string.constData()), length);
34static inline QString toQString(jstring string, JNIEnv *env)
38 const jsize length = env->GetStringLength(string);
39 QString res(length, Qt::Uninitialized);
40 env->GetStringRegion(string, 0, length,
reinterpret_cast<jchar *>(res.data_ptr().data()));
47template<size_t N_WITH_NULL,
typename BaseType =
char>
50 BaseType m_data[N_WITH_NULL] = {};
52 constexpr CTString()
noexcept {}
54 constexpr explicit CTString(
const BaseType (&data)[N_WITH_NULL])
noexcept
56 for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
60 constexpr BaseType at(size_t i)
const {
return m_data[i]; }
61 constexpr BaseType operator[](size_t i)
const {
return at(i); }
62 static constexpr size_t size()
noexcept {
return N_WITH_NULL; }
63 constexpr operator
const BaseType *()
const noexcept {
return m_data; }
64 constexpr const BaseType *data()
const noexcept {
return m_data; }
65 template<size_t N2_WITH_NULL>
66 constexpr bool startsWith(
const BaseType (&lit)[N2_WITH_NULL])
const noexcept
68 if constexpr (N2_WITH_NULL > N_WITH_NULL) {
71 for (size_t i = 0; i < N2_WITH_NULL - 1; ++i) {
72 if (m_data[i] != lit[i])
78 constexpr bool startsWith(BaseType c)
const noexcept
80 return N_WITH_NULL > 1 && m_data[0] == c;
82 template<size_t N2_WITH_NULL>
83 constexpr bool endsWith(
const BaseType (&lit)[N2_WITH_NULL])
const noexcept
85 if constexpr (N2_WITH_NULL > N_WITH_NULL) {
88 for (size_t i = 0; i < N2_WITH_NULL; ++i) {
89 if (m_data[N_WITH_NULL - i - 1] != lit[N2_WITH_NULL - i - 1])
95 constexpr bool endsWith(BaseType c)
const noexcept
97 return N_WITH_NULL > 1 && m_data[N_WITH_NULL - 2] == c;
100 template<size_t N2_WITH_NULL>
101 friend inline constexpr bool operator==(
const CTString<N_WITH_NULL> &lhs,
102 const CTString<N2_WITH_NULL> &rhs)
noexcept
104 if constexpr (N_WITH_NULL != N2_WITH_NULL) {
107 for (size_t i = 0; i < N_WITH_NULL - 1; ++i) {
108 if (lhs.at(i) != rhs.at(i))
115 template<size_t N2_WITH_NULL>
116 friend inline constexpr bool operator!=(
const CTString<N_WITH_NULL> &lhs,
117 const CTString<N2_WITH_NULL> &rhs)
noexcept
119 return !operator==(lhs, rhs);
122 template<size_t N2_WITH_NULL>
123 friend inline constexpr bool operator==(
const CTString<N_WITH_NULL> &lhs,
124 const BaseType (&rhs)[N2_WITH_NULL])
noexcept
126 return operator==(lhs, CTString<N2_WITH_NULL>(rhs));
128 template<size_t N2_WITH_NULL>
129 friend inline constexpr bool operator==(
const BaseType (&lhs)[N2_WITH_NULL],
130 const CTString<N_WITH_NULL> &rhs)
noexcept
132 return operator==(CTString<N2_WITH_NULL>(lhs), rhs);
135 template<size_t N2_WITH_NULL>
136 friend inline constexpr bool operator!=(
const CTString<N_WITH_NULL> &lhs,
137 const BaseType (&rhs)[N2_WITH_NULL])
noexcept
139 return operator!=(lhs, CTString<N2_WITH_NULL>(rhs));
141 template<size_t N2_WITH_NULL>
142 friend inline constexpr bool operator!=(
const BaseType (&lhs)[N2_WITH_NULL],
143 const CTString<N_WITH_NULL> &rhs)
noexcept
145 return operator!=(CTString<N2_WITH_NULL>(lhs), rhs);
148 template<size_t N2_WITH_NULL>
149 friend inline constexpr auto operator+(
const CTString<N_WITH_NULL> &lhs,
150 const CTString<N2_WITH_NULL> &rhs)
noexcept
152 char data[N_WITH_NULL + N2_WITH_NULL - 1] = {};
153 for (size_t i = 0; i < N_WITH_NULL - 1; ++i)
155 for (size_t i = 0; i < N2_WITH_NULL - 1; ++i)
156 data[N_WITH_NULL - 1 + i] = rhs[i];
157 return CTString<N_WITH_NULL + N2_WITH_NULL - 1>(data);
163template<
typename T, size_t N = 0>
struct IsStringType : std::false_type {};
164template<>
struct IsStringType<
const char *, 0> : std::true_type {};
165template<>
struct IsStringType<
const char *&, 0> : std::true_type {};
166template<size_t N>
struct IsStringType<CTString<N>> : std::true_type {};
167template<size_t N>
struct IsStringType<
const char[N]> : std::true_type {};
168template<size_t N>
struct IsStringType<
const char(&)[N]> : std::true_type {};
169template<size_t N>
struct IsStringType<
char[N]> : std::true_type {};
171template <
typename T,
typename =
void>
178 static constexpr auto className()
180 if constexpr (std::is_same_v<T, jstring>)
181 return CTString(
"java/lang/String");
182 else if constexpr (std::is_same_v<T, jobject>)
183 return CTString(
"java/lang/Object");
184 else if constexpr (std::is_same_v<T, jclass>)
185 return CTString(
"java/lang/Class");
186 else if constexpr (std::is_same_v<T, jthrowable>)
187 return CTString(
"java/lang/Throwable");
191 static constexpr auto signature()
193 if constexpr (!std::is_same_v<
decltype(className()),
void>) {
195 return CTString(
"L") + className() + CTString(
";");
196 }
else if constexpr (std::is_same_v<T, jobjectArray>) {
197 return CTString(
"[Ljava/lang/Object;");
198 }
else if constexpr (std::is_same_v<T, jbooleanArray>) {
199 return CTString(
"[Z");
200 }
else if constexpr (std::is_same_v<T, jbyteArray>) {
201 return CTString(
"[B");
202 }
else if constexpr (std::is_same_v<T, jshortArray>) {
203 return CTString(
"[S");
204 }
else if constexpr (std::is_same_v<T, jintArray>) {
205 return CTString(
"[I");
206 }
else if constexpr (std::is_same_v<T, jlongArray>) {
207 return CTString(
"[J");
208 }
else if constexpr (std::is_same_v<T, jfloatArray>) {
209 return CTString(
"[F");
210 }
else if constexpr (std::is_same_v<T, jdoubleArray>) {
211 return CTString(
"[D");
212 }
else if constexpr (std::is_same_v<T, jcharArray>) {
213 return CTString(
"[C");
214 }
else if constexpr (std::is_same_v<T, jboolean>) {
215 return CTString(
"Z");
216 }
else if constexpr (std::is_same_v<T,
bool>) {
217 return CTString(
"Z");
218 }
else if constexpr (std::is_same_v<T, jbyte>) {
219 return CTString(
"B");
220 }
else if constexpr (std::is_same_v<T, jchar>) {
221 return CTString(
"C");
222 }
else if constexpr (std::is_same_v<T,
char>) {
223 return CTString(
"C");
224 }
else if constexpr (std::is_same_v<T, jshort>) {
225 return CTString(
"S");
226 }
else if constexpr (std::is_same_v<T,
short>) {
227 return CTString(
"S");
228 }
else if constexpr (std::is_same_v<T, jint>) {
229 return CTString(
"I");
230 }
else if constexpr (std::is_same_v<T,
int>) {
231 return CTString(
"I");
232 }
else if constexpr (std::is_same_v<T, uint>) {
233 return CTString(
"I");
234 }
else if constexpr (std::is_same_v<T, jlong>) {
235 return CTString(
"J");
236 }
else if constexpr (std::is_same_v<T, quint64>) {
237 return CTString(
"J");
238 }
else if constexpr (std::is_same_v<T, jfloat>) {
239 return CTString(
"F");
240 }
else if constexpr (std::is_same_v<T,
float>) {
241 return CTString(
"F");
242 }
else if constexpr (std::is_same_v<T, jdouble>) {
243 return CTString(
"D");
244 }
else if constexpr (std::is_same_v<T,
double>) {
245 return CTString(
"D");
246 }
else if constexpr (std::is_same_v<T,
void>) {
247 return CTString(
"V");
248 }
else if constexpr (std::is_enum_v<T>) {
249 return Traits<std::underlying_type_t<T>>::signature();
254 template <
typename U = T>
255 static auto convertToJni(JNIEnv *, U &&value)
257 return std::forward<U>(value);
259 static auto convertFromJni(QJniObject &&object)
261 return std::move(object);
265template <
typename Have,
typename Want>
266static constexpr bool sameTypeForJni = (QtJniTypes::Traits<Have>::signature()
267 == QtJniTypes::Traits<Want>::signature())
268 && (
sizeof(Have) ==
sizeof(Want));
270template <
typename,
typename =
void>
274#define MAKE_CALLER(Type, Method) template
276 Caller<T, std::enable_if_t<sameTypeForJni<T, Type>>> \
277{
278 static constexpr void callMethodForType(JNIEnv *env, T &res, jobject obj, jmethodID id, va_list args)
280 res = T(env->Call##Method##MethodV(obj, id, args));
282 static constexpr void callStaticMethodForType(JNIEnv *env, T &res, jclass clazz, jmethodID id, va_list args)
284 res = T(env->CallStatic##Method##MethodV(clazz, id, args));
286 static constexpr void getFieldForType(JNIEnv *env, T &res, jobject obj, jfieldID id)
288 res = T(env->Get##Method##Field(obj, id));
290 static constexpr void getStaticFieldForType(JNIEnv *env, T &res, jclass clazz, jfieldID id)
292 res = T(env->GetStatic##Method##Field(clazz, id));
294 static constexpr void setFieldForType(JNIEnv *env, jobject obj, jfieldID id, T value)
296 env->Set##Method##Field(obj, id, static_cast<Type>(value));
298 static constexpr void setStaticFieldForType(JNIEnv *env, jclass clazz, jfieldID id, T value)
300 env->SetStatic##Method##Field(clazz, id, static_cast<Type>(value));
302}
304MAKE_CALLER(jboolean, Boolean);
305MAKE_CALLER(jbyte, Byte);
306MAKE_CALLER(jchar, Char);
307MAKE_CALLER(jshort, Short);
308MAKE_CALLER(jint, Int);
309MAKE_CALLER(jlong, Long);
310MAKE_CALLER(jfloat, Float);
311MAKE_CALLER(jdouble, Double);
316static constexpr bool isPrimitiveType()
318 return Traits<T>::signature().size() == 2;
322static constexpr bool isArrayType()
324 constexpr auto signature = Traits<T>::signature();
325 return signature.startsWith(
'[') && signature.size() > 2;
329static constexpr bool isObjectType()
331 if constexpr (std::is_convertible_v<T, jobject>) {
334 constexpr auto signature = Traits<T>::signature();
335 return (signature.startsWith(
'L') && signature.endsWith(
';')) || isArrayType<T>();
340static constexpr void assertObjectType()
342 static_assert(isObjectType<T>(),
343 "Type needs to be a JNI object type (convertible to jobject, or with "
344 "an object type signature registered)!");
348template<
typename ...Types>
349constexpr bool ValidSignatureTypesDetail = !std::disjunction<std::is_same<
350 decltype(Traits<Types>::signature()),
352 IsStringType<Types>...>::value;
353template<
typename ...Types>
354using IfValidSignatureTypes = std::enable_if_t<
355 ValidSignatureTypesDetail<q20::remove_cvref_t<Types>...>,
bool>;
357template<
typename Type>
358constexpr bool ValidFieldTypeDetail = isObjectType<Type>() || isPrimitiveType<Type>();
359template<
typename Type>
360using IfValidFieldType = std::enable_if_t<
361 ValidFieldTypeDetail<q20::remove_cvref_t<Type>>,
bool>;
364template<
typename R,
typename ...Args, IfValidSignatureTypes<R, Args...> =
true>
365static constexpr auto methodSignature()
367 return (CTString(
"(") +
368 ... + Traits<q20::remove_cvref_t<Args>>::signature())
370 + Traits<R>::signature();
373template<
typename T, IfValidSignatureTypes<T> =
true>
374static constexpr auto fieldSignature()
376 return QtJniTypes::Traits<T>::signature();
379template<
typename ...Args, IfValidSignatureTypes<Args...> =
true>
380static constexpr auto constructorSignature()
382 return methodSignature<
void, Args...>();
385template<
typename Ret,
typename ...Args, IfValidSignatureTypes<Ret, Args...> =
true>
386static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jobject, Args...))
388 return methodSignature<Ret, Args...>();
391template<
typename Ret,
typename ...Args, IfValidSignatureTypes<Ret, Args...> =
true>
392static constexpr auto nativeMethodSignature(Ret (*)(JNIEnv *, jclass, Args...))
394 return methodSignature<Ret, Args...>();