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
qjniarray.h
Go to the documentation of this file.
1// Copyright (C) 2023 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 QJNIARRAY_H
5#define QJNIARRAY_H
6
7#include <QtCore/qlist.h>
8
9#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
10#include <QtCore/qbytearray.h>
11#include <QtCore/qjniobject.h>
12
13#include <iterator>
14#include <utility>
15#include <QtCore/q20type_traits.h>
16
18
19template <typename T> class QJniArray;
20template <typename T>
21struct QT_TECH_PREVIEW_API QJniArrayIterator
22{
23 QJniArrayIterator() = default;
24
25 constexpr QJniArrayIterator(const QJniArrayIterator &other) noexcept = default;
26 constexpr QJniArrayIterator(QJniArrayIterator &&other) noexcept = default;
27 constexpr QJniArrayIterator &operator=(const QJniArrayIterator &other) noexcept = default;
28 constexpr QJniArrayIterator &operator=(QJniArrayIterator &&other) noexcept = default;
29
30 using difference_type = jsize;
31 using value_type = T;
32 using pointer = T *;
33 using reference = T; // difference to container requirements
35 using iterator_category = std::bidirectional_iterator_tag;
36
37 friend bool operator==(const QJniArrayIterator &lhs, const QJniArrayIterator &rhs) noexcept
38 {
39 return lhs.m_array == rhs.m_array && lhs.m_index == rhs.m_index;
40 }
41 friend bool operator!=(const QJniArrayIterator &lhs, const QJniArrayIterator &rhs) noexcept
42 {
43 return !(lhs == rhs);
44 }
46 {
47 return m_array->at(m_index);
48 }
49 friend QJniArrayIterator &operator++(QJniArrayIterator &that) noexcept
50 {
51 ++that.m_index;
52 return that;
53 }
54 friend QJniArrayIterator operator++(QJniArrayIterator &that, int) noexcept
55 {
56 auto copy = that;
57 ++that;
58 return copy;
59 }
60 friend QJniArrayIterator &operator--(QJniArrayIterator &that) noexcept
61 {
62 --that.m_index;
63 return that;
64 }
65 friend QJniArrayIterator operator--(QJniArrayIterator &that, int) noexcept
66 {
67 auto copy = that;
68 --that;
69 return copy;
70 }
71 void swap(QJniArrayIterator &other) noexcept
72 {
73 std::swap(m_index, other.m_index);
74 qt_ptr_swap(m_array, other.m_array);
75 }
76
77private:
78 using VT = std::remove_const_t<T>;
79 friend class QJniArray<VT>;
80
81 qsizetype m_index = 0;
82 const QJniArray<VT> *m_array = nullptr;
83
84 QJniArrayIterator(qsizetype index, const QJniArray<VT> *array)
85 : m_index(index), m_array(array)
86 {}
87};
88
89class QT_TECH_PREVIEW_API QJniArrayBase
90{
91 // for SFINAE'ing out the fromContainer named constructor
92 template <typename Container, typename = void> struct CanConvertHelper : std::false_type {};
93 template <typename Container>
94 struct CanConvertHelper<Container, std::void_t<decltype(std::data(std::declval<Container>())),
95 decltype(std::size(std::declval<Container>())),
96 typename Container::value_type
97 >
98 > : std::true_type {};
99
100public:
101 using size_type = jsize;
102 using difference_type = size_type;
103
104 operator QJniObject() const { return m_object; }
105
106 template <typename T = jobject>
107 T object() const { return m_object.object<T>(); }
108 bool isValid() const { return m_object.isValid(); }
109
110 size_type size() const
111 {
112 if (jarray array = m_object.object<jarray>())
113 return jniEnv()->GetArrayLength(array);
114 return 0;
115 }
116
117 template <typename Container>
118 static constexpr bool canConvert = CanConvertHelper<q20::remove_cvref_t<Container>>::value;
119 template <typename Container>
120 using IfCanConvert = std::enable_if_t<canConvert<Container>, bool>;
121 template <typename Container
122 , IfCanConvert<Container> = true
123 >
124 static auto fromContainer(Container &&container)
125 {
126 Q_ASSERT_X(size_t(std::size(container)) <= size_t((std::numeric_limits<size_type>::max)()),
127 "QJniArray::fromContainer", "Container is too large for a Java array");
128
129 using ElementType = typename std::remove_reference_t<Container>::value_type;
130 if constexpr (std::disjunction_v<std::is_same<ElementType, jobject>,
131 std::is_same<ElementType, QJniObject>,
132 std::is_same<ElementType, QString>,
133 std::is_base_of<QtJniTypes::JObjectBase, ElementType>
134 >) {
135 return makeObjectArray(std::forward<Container>(container));
136 } else if constexpr (std::is_same_v<ElementType, jfloat>) {
137 return makeArray<jfloat>(std::forward<Container>(container), &JNIEnv::NewFloatArray,
138 &JNIEnv::SetFloatArrayRegion);
139 } else if constexpr (std::is_same_v<ElementType, jdouble>) {
140 return makeArray<jdouble>(std::forward<Container>(container), &JNIEnv::NewDoubleArray,
141 &JNIEnv::SetDoubleArrayRegion);
142 } else if constexpr (std::disjunction_v<std::is_same<ElementType, jboolean>,
143 std::is_same<ElementType, bool>>) {
144 return makeArray<jboolean>(std::forward<Container>(container), &JNIEnv::NewBooleanArray,
145 &JNIEnv::SetBooleanArrayRegion);
146 } else if constexpr (std::disjunction_v<std::is_same<ElementType, jbyte>,
147 std::is_same<ElementType, char>>) {
148 return makeArray<jbyte>(std::forward<Container>(container), &JNIEnv::NewByteArray,
149 &JNIEnv::SetByteArrayRegion);
150 } else if constexpr (std::disjunction_v<std::is_same<ElementType, jchar>,
151 std::is_same<ElementType, QChar>>) {
152 return makeArray<jchar>(std::forward<Container>(container), &JNIEnv::NewCharArray,
153 &JNIEnv::SetCharArrayRegion);
154 } else if constexpr (std::is_same_v<ElementType, jshort>
155 || sizeof(ElementType) == sizeof(jshort)) {
156 return makeArray<jshort>(std::forward<Container>(container), &JNIEnv::NewShortArray,
157 &JNIEnv::SetShortArrayRegion);
158 } else if constexpr (std::is_same_v<ElementType, jint>
159 || sizeof(ElementType) == sizeof(jint)) {
160 return makeArray<jint>(std::forward<Container>(container), &JNIEnv::NewIntArray,
161 &JNIEnv::SetIntArrayRegion);
162 } else if constexpr (std::is_same_v<ElementType, jlong>
163 || sizeof(ElementType) == sizeof(jlong)) {
164 return makeArray<jlong>(std::forward<Container>(container), &JNIEnv::NewLongArray,
165 &JNIEnv::SetLongArrayRegion);
166 }
167 }
168
169protected:
170 QJniArrayBase() = default;
171 ~QJniArrayBase() = default;
172
173 explicit QJniArrayBase(jarray array)
174 : m_object(static_cast<jobject>(array))
175 {
176 }
177 explicit QJniArrayBase(const QJniObject &object)
178 : m_object(object)
179 {}
180 explicit QJniArrayBase(QJniObject &&object) noexcept
181 : m_object(std::move(object))
182 {}
183
184 JNIEnv *jniEnv() const noexcept { return QJniEnvironment::getJniEnv(); }
185
186 template <typename ElementType, typename List, typename NewFn, typename SetFn>
187 static auto makeArray(List &&list, NewFn &&newArray, SetFn &&setRegion);
188 template <typename List>
189 static auto makeObjectArray(List &&list);
190
191private:
192 QJniObject m_object;
193};
194
195template <typename T>
196class QT_TECH_PREVIEW_API QJniArray : public QJniArrayBase
197{
198 friend struct QJniArrayIterator<T>;
199public:
200 using Type = T;
201
202 using value_type = T;
203 using reference = T;
204 using const_reference = const reference;
205
206 // read-only container, so no iterator typedef
207 using const_iterator = QJniArrayIterator<const T>;
208 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
209
210 QJniArray() = default;
211 explicit QJniArray(jarray array) : QJniArrayBase(array) {}
212 explicit QJniArray(const QJniObject &object) : QJniArrayBase(object) {}
213 explicit QJniArray(QJniObject &&object) noexcept : QJniArrayBase(std::move(object)) {}
214
215 // base class destructor is protected, so need to provide all SMFs
216 QJniArray(const QJniArray &other) = default;
217 QJniArray(QJniArray &&other) noexcept = default;
218 QJniArray &operator=(const QJniArray &other) = default;
219 QJniArray &operator=(QJniArray &&other) noexcept = default;
220
221 template <typename Container
222 , IfCanConvert<Container> = true
223 >
224 explicit QJniArray(Container &&container)
225 : QJniArrayBase(QJniArrayBase::fromContainer(std::forward<Container>(container)))
226 {
227 }
228
229 template <typename E = T
230 , IfCanConvert<std::initializer_list<E>> = true
231 >
232 Q_IMPLICIT inline QJniArray(std::initializer_list<T> list)
233 : QJniArrayBase(QJniArrayBase::fromContainer(list))
234 {
235 }
236
237 template <typename Other, std::enable_if_t<std::is_convertible_v<Other, Type>, bool> = true>
238 QJniArray(QJniArray<Other> &&other)
239 : QJniArrayBase(std::forward<QJniArray<Other>>(other))
240 {
241 }
242 ~QJniArray() = default;
243
244 auto arrayObject() const
245 {
246 if constexpr (std::is_convertible_v<jobject, T>)
247 return object<jobjectArray>();
248 else if constexpr (std::is_same_v<T, jbyte>)
249 return object<jbyteArray>();
250 else if constexpr (std::is_same_v<T, jchar>)
251 return object<jcharArray>();
252 else if constexpr (std::is_same_v<T, jboolean>)
253 return object<jbooleanArray>();
254 else if constexpr (std::is_same_v<T, jshort>)
255 return object<jshortArray>();
256 else if constexpr (std::is_same_v<T, jint>)
257 return object<jintArray>();
258 else if constexpr (std::is_same_v<T, jlong>)
259 return object<jlongArray>();
260 else if constexpr (std::is_same_v<T, jfloat>)
261 return object<jfloatArray>();
262 else if constexpr (std::is_same_v<T, jdouble>)
263 return object<jdoubleArray>();
264 else
265 return object<jarray>();
266 }
267
268 const_iterator begin() const noexcept { return {0, this}; }
269 const_iterator constBegin() const noexcept { return begin(); }
270 const_iterator cbegin() const noexcept { return begin(); }
271 const_iterator end() const noexcept { return {size(), this}; }
272 const_iterator constEnd() const noexcept { return {end()}; }
273 const_iterator cend() const noexcept { return {end()}; }
274
275 const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
276 const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
277 const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); }
278 const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); }
279
280 const_reference operator[](size_type i) const { return at(i); }
281 const_reference at(size_type i) const
282 {
283 JNIEnv *env = jniEnv();
284 if constexpr (std::is_convertible_v<jobject, T>) {
285 jobject element = env->GetObjectArrayElement(object<jobjectArray>(), i);
286 if constexpr (std::is_base_of_v<QJniObject, T>)
287 return QJniObject::fromLocalRef(element);
288 else if constexpr (std::is_base_of_v<QtJniTypes::JObjectBase, T>)
289 return T::fromLocalRef(element);
290 else
291 return T{element};
292 } else if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>) {
293 // jstring, jclass etc
294 return static_cast<T>(env->GetObjectArrayElement(object<jobjectArray>(), i));
295 } else {
296 T res = {};
297 if constexpr (std::is_same_v<T, jbyte>)
298 env->GetByteArrayRegion(object<jbyteArray>(), i, 1, &res);
299 else if constexpr (std::is_same_v<T, jchar>)
300 env->GetCharArrayRegion(object<jcharArray>(), i, 1, &res);
301 else if constexpr (std::is_same_v<T, jboolean>)
302 env->GetBooleanArrayRegion(object<jbooleanArray>(), i, 1, &res);
303 else if constexpr (std::is_same_v<T, jshort>)
304 env->GetShortArrayRegion(object<jshortArray>(), i, 1, &res);
305 else if constexpr (std::is_same_v<T, jint>)
306 env->GetIntArrayRegion(object<jbyteArray>(), i, 1, &res);
307 else if constexpr (std::is_same_v<T, jlong>)
308 env->GetLongArrayRegion(object<jlongArray>(), i, 1, &res);
309 else if constexpr (std::is_same_v<T, jfloat>)
310 env->GetFloatArrayRegion(object<jfloatArray>(), i, 1, &res);
311 else if constexpr (std::is_same_v<T, jdouble>)
312 env->GetDoubleArrayRegion(object<jdoubleArray>(), i, 1, &res);
313 return res;
314 }
315 }
316 auto toContainer() const
317 {
318 JNIEnv *env = jniEnv();
319 if constexpr (std::is_same_v<T, jobject>) {
320 QList<jobject> res;
321 res.reserve(size());
322 for (auto element : *this)
323 res.append(element);
324 return res;
325 } else if constexpr (std::is_same_v<T, jstring>) {
327 res.reserve(size());
328 for (auto element : *this)
329 res.append(QJniObject(element).toString());
330 return res;
331 } else if constexpr (std::is_same_v<T, jbyte>) {
332 const qsizetype bytecount = size();
334 env->GetByteArrayRegion(object<jbyteArray>(),
335 0, bytecount, reinterpret_cast<jbyte *>(res.data()));
336 return res;
337 } else {
338 QList<T> res;
339 res.resize(size());
340 if constexpr (std::is_same_v<T, jchar>) {
341 env->GetCharArrayRegion(object<jcharArray>(),
342 0, res.size(), res.data());
343 } else if constexpr (std::is_same_v<T, jboolean>) {
344 env->GetBooleanArrayRegion(object<jbooleanArray>(),
345 0, res.size(), res.data());
346 } else if constexpr (std::is_same_v<T, jshort>) {
347 env->GetShortArrayRegion(object<jshortArray>(),
348 0, res.size(), res.data());
349 } else if constexpr (std::is_same_v<T, jint>) {
350 env->GetIntArrayRegion(object<jintArray>(),
351 0, res.size(), res.data());
352 } else if constexpr (std::is_same_v<T, jlong>) {
353 env->GetLongArrayRegion(object<jlongArray>(),
354 0, res.size(), res.data());
355 } else if constexpr (std::is_same_v<T, jfloat>) {
356 env->GetFloatArrayRegion(object<jfloatArray>(),
357 0, res.size(), res.data());
358 } else if constexpr (std::is_same_v<T, jdouble>) {
359 env->GetDoubleArrayRegion(object<jdoubleArray>(),
360 0, res.size(), res.data());
361 } else {
362 res.clear();
363 }
364 return res;
365 }
366 }
367};
368
369template <typename ElementType, typename List, typename NewFn, typename SetFn>
370auto QJniArrayBase::makeArray(List &&list, NewFn &&newArray, SetFn &&setRegion)
371{
372 const size_type length = size_type(std::size(list));
373 JNIEnv *env = QJniEnvironment::getJniEnv();
374 auto localArray = (env->*newArray)(length);
375 if (QJniEnvironment::checkAndClearExceptions(env))
376 return QJniArray<ElementType>();
377
378 // can't use static_cast here because we have signed/unsigned mismatches
379 if (length) {
380 (env->*setRegion)(localArray, 0, length,
381 reinterpret_cast<const ElementType *>(std::data(std::as_const(list))));
382 }
383 return QJniArray<ElementType>(localArray);
384};
385
386template <typename List>
387auto QJniArrayBase::makeObjectArray(List &&list)
388{
389 using ElementType = typename q20::remove_cvref_t<List>::value_type;
390 using ResultType = QJniArray<decltype(std::declval<QJniObject::LocalFrame<>>().convertToJni(
391 std::declval<ElementType>()))
392 >;
393
394 if (std::size(list) == 0)
395 return ResultType();
396
397 JNIEnv *env = QJniEnvironment::getJniEnv();
398 const size_type length = size_type(std::size(list));
399
400 // this assumes that all objects in the list have the same class
401 jclass elementClass = nullptr;
402 if constexpr (std::disjunction_v<std::is_same<ElementType, QJniObject>,
403 std::is_base_of<QtJniTypes::JObjectBase, ElementType>>) {
404 elementClass = std::begin(list)->objectClass();
405 } else if constexpr (std::is_same_v<ElementType, QString>) {
406 elementClass = env->FindClass("java/lang/String");
407 } else {
408 elementClass = env->GetObjectClass(*std::begin(list));
409 }
410 auto localArray = env->NewObjectArray(length, elementClass, nullptr);
411 if (QJniEnvironment::checkAndClearExceptions(env))
412 return ResultType();
413
414 // explicitly manage the frame for local references in chunks of 100
415 QJniObject::LocalFrame frame(env);
416 constexpr jint frameCapacity = 100;
417 qsizetype i = 0;
418 for (const auto &element : std::as_const(list)) {
419 if (i % frameCapacity == 0) {
420 if (i)
421 env->PopLocalFrame(nullptr);
422 if (env->PushLocalFrame(frameCapacity) != 0)
423 return ResultType{};
424 }
425 jobject object = frame.convertToJni(element);
426 env->SetObjectArrayElement(localArray, i, object);
427 ++i;
428 }
429 if (i)
430 env->PopLocalFrame(nullptr);
431 return ResultType(localArray);
432}
433
434namespace QtJniTypes
435{
436template <typename T> struct IsJniArray: std::false_type {};
437template <typename T> struct IsJniArray<QJniArray<T>> : std::true_type {};
438template <typename T> struct Traits<QJniArray<T>> {
439 template <IfValidFieldType<T> = true>
440 static constexpr auto signature()
441 {
442 return CTString("[") + Traits<T>::signature();
443 }
444};
445template <typename T> struct Traits<QList<T>> {
446 template <IfValidFieldType<T> = true>
447 static constexpr auto signature()
448 {
449 return CTString("[") + Traits<T>::signature();
450 }
451};
452template <> struct Traits<QByteArray> {
453 static constexpr auto signature()
454 {
455 return CTString("[B");
456 }
457};
458}
459
461
462#endif
463
464#endif // QJNIARRAY_H
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qlist.h:75
\inmodule QtCore
#define this
Definition dialogs.cpp:9
list append(new Employee("Blackpool", "Stephen"))
typename C::value_type value_type
typename C::const_iterator const_iterator
QMetaType signature()
const PluginKeyMapConstIterator cend
Combined button and popup list for selecting options.
const T & const_reference()
bool canConvert(const QQmlPropertyCache *fromMo, const QQmlPropertyCache *toMo)
std::remove_cv_t< std::remove_reference_t< T > > remove_cvref_t
static jboolean copy(JNIEnv *, jobject)
#define Q_IMPLICIT
constexpr bool operator!=(const timespec &t1, const timespec &t2)
constexpr timespec operator*(const timespec &t1, int mul)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLuint object
[3]
GLint reference
GLuint res
GLenum array
GLsizei const void * pointer
Definition qopenglext.h:384
bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
Definition qrandom.cpp:1220
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QtPrivate::QRegularExpressionMatchIteratorRangeBasedForIterator begin(const QRegularExpressionMatchIterator &iterator)
constexpr void qt_ptr_swap(T *&lhs, T *&rhs) noexcept
Definition qswap.h:29
#define QT_TECH_PREVIEW_API
ptrdiff_t qsizetype
Definition qtypes.h:165
QList< int > list
[14]
QSharedPointer< T > other(t)
[5]
this swap(other)
QFrame frame
[0]
QAction * at
char * toString(const MyType &t)
[31]
Definition moc.h:23