7#include <QtCore/qlist.h>
9#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
10#include <QtCore/qbytearray.h>
11#include <QtCore/qjniobject.h>
14#include <QtCore/q26numeric.h>
15#include <QtCore/q20type_traits.h>
16#include <QtCore/q20utility.h>
20using jarray = jobject;
25template <
typename T>
class QJniArray;
26template <
typename T>
struct QJniArrayMutableIterator;
29namespace QtAndroidPrivate
31 Q_CORE_EXPORT jclass findClass(
const char *className, JNIEnv *env);
35struct QJniArrayIterator
38 using VT = std::remove_const_t<T>;
39 friend class QJniArray<VT>;
40 friend struct QJniArrayMutableIterator<VT>;
44 struct QJniArrayValueRef {
46 const T *operator->()
const {
return &ref; }
50 QJniArrayIterator() =
default;
51 constexpr QJniArrayIterator(
const QJniArrayMutableIterator<VT> &other)
noexcept
52 : m_index(other.m_index), m_array(other.m_array)
54 constexpr QJniArrayIterator(QJniArrayMutableIterator<VT> &&other)
noexcept
55 : m_index(std::exchange(other.m_index, -1)), m_array(std::exchange(other.m_array,
nullptr))
58 constexpr QJniArrayIterator(
const QJniArrayIterator &other)
noexcept =
default;
59 constexpr QJniArrayIterator(QJniArrayIterator &&other)
noexcept =
default;
60 constexpr QJniArrayIterator &operator=(
const QJniArrayIterator &other)
noexcept =
default;
61 constexpr QJniArrayIterator &operator=(QJniArrayIterator &&other)
noexcept =
default;
63 using difference_type = jsize;
65 using pointer = QJniArrayValueRef;
67 using const_reference = reference;
68 using iterator_category = std::random_access_iterator_tag;
70 const_reference operator*()
const
72 return m_array->at(m_index);
75 QJniArrayValueRef operator->()
const
77 return {m_array->at(m_index)};
80 const_reference operator[](difference_type n)
const
82 return m_array->at(m_index + n);
85 friend QJniArrayIterator &operator++(QJniArrayIterator &that)
noexcept
90 friend QJniArrayIterator operator++(QJniArrayIterator &that,
int)
noexcept
96 friend QJniArrayIterator operator+(
const QJniArrayIterator &that, difference_type n)
noexcept
98 return {that.m_index + n, that.m_array};
100 friend QJniArrayIterator operator+(difference_type n,
const QJniArrayIterator &that)
noexcept
104 friend QJniArrayIterator &operator+=(QJniArrayIterator &that, difference_type n)
noexcept
109 friend QJniArrayIterator &operator--(QJniArrayIterator &that)
noexcept
114 friend QJniArrayIterator operator--(QJniArrayIterator &that,
int)
noexcept
120 friend QJniArrayIterator operator-(
const QJniArrayIterator &that, difference_type n)
noexcept
122 return {that.m_index - n, that.m_array};
124 friend QJniArrayIterator operator-(difference_type n,
const QJniArrayIterator &that)
noexcept
126 return {n - that.m_index, that.m_array};
128 friend QJniArrayIterator &operator-=(QJniArrayIterator &that, difference_type n)
noexcept
133 friend difference_type operator-(
const QJniArrayIterator &lhs,
const QJniArrayIterator &rhs)
135 Q_ASSERT(lhs.m_array == rhs.m_array);
136 return lhs.m_index - rhs.m_index;
138 void swap(QJniArrayIterator &other)
noexcept
140 std::swap(m_index, other.m_index);
141 qt_ptr_swap(m_array, other.m_array);
145 friend constexpr bool comparesEqual(
const QJniArrayIterator &lhs,
146 const QJniArrayIterator &rhs)
noexcept
148 Q_ASSERT(lhs.m_array == rhs.m_array);
149 return lhs.m_index == rhs.m_index;
151 friend constexpr Qt::strong_ordering compareThreeWay(
const QJniArrayIterator &lhs,
152 const QJniArrayIterator &rhs)
noexcept
154 Q_ASSERT(lhs.m_array == rhs.m_array);
155 return Qt::compareThreeWay(lhs.m_index, rhs.m_index);
157 Q_DECLARE_STRONGLY_ORDERED(QJniArrayIterator)
159 qsizetype m_index = 0;
160 const QJniArray<VT> *m_array =
nullptr;
162 QJniArrayIterator(qsizetype index,
const QJniArray<VT> *array)
163 : m_index(index), m_array(array)
168struct QJniArrayMutableValueRef;
171struct QJniArrayMutableIterator
174 friend struct QJniArrayIterator<
const T>;
175 friend struct QJniArrayMutableValueRef<T>;
178 constexpr QJniArrayMutableIterator()
noexcept =
default;
179 constexpr QJniArrayMutableIterator(
const QJniArrayIterator<
const T> &other)
noexcept
180 : m_index(other.m_index), m_array(other.m_array)
182 constexpr QJniArrayMutableIterator(QJniArrayIterator<
const T> &&other)
noexcept
183 : m_index(std::exchange(other.m_index, -1)), m_array(std::exchange(other.m_array,
nullptr))
186 constexpr QJniArrayMutableIterator(
const QJniArrayMutableIterator &other)
noexcept =
default;
187 constexpr QJniArrayMutableIterator(QJniArrayMutableIterator &&other)
noexcept =
default;
188 constexpr QJniArrayMutableIterator &operator=(
const QJniArrayMutableIterator &other)
noexcept =
default;
189 constexpr QJniArrayMutableIterator &operator=(QJniArrayMutableIterator &&other)
noexcept =
default;
191 using difference_type = jsize;
192 using value_type = T;
193 using pointer = QJniArrayMutableValueRef<T>;
194 using reference = QJniArrayMutableValueRef<T>;
195 using const_reference = T;
196 using iterator_category = std::random_access_iterator_tag;
198 const_reference operator*()
const
200 return m_array->at(m_index);
203 reference operator*()
205 return {m_array->at(m_index), *
this};
208 const pointer operator->()
const
210 return {m_array->at(m_index)};
215 return {m_array->at(m_index), *
this};
218 const_reference operator[](difference_type n)
const
220 return m_array->at(m_index + n);
222 reference operator[](difference_type n)
224 return {m_array->at(m_index + n), *
this};
227 friend QJniArrayMutableIterator &operator++(QJniArrayMutableIterator &that)
noexcept
232 friend QJniArrayMutableIterator operator++(QJniArrayMutableIterator &that,
int)
noexcept
238 friend QJniArrayMutableIterator operator+(
const QJniArrayMutableIterator &that, difference_type n)
noexcept
240 return {that.m_index + n, that.m_array};
242 friend QJniArrayMutableIterator operator+(difference_type n,
const QJniArrayMutableIterator &that)
noexcept
246 friend QJniArrayMutableIterator &operator+=(QJniArrayMutableIterator &that, difference_type n)
noexcept
251 friend QJniArrayMutableIterator &operator--(QJniArrayMutableIterator &that)
noexcept
256 friend QJniArrayMutableIterator operator--(QJniArrayMutableIterator &that,
int)
noexcept
262 friend QJniArrayMutableIterator operator-(
const QJniArrayMutableIterator &that, difference_type n)
noexcept
264 return {that.m_index - n, that.m_array};
266 friend QJniArrayMutableIterator operator-(difference_type n,
const QJniArrayMutableIterator &that)
noexcept
268 return {n - that.m_index, that.m_array};
270 friend QJniArrayMutableIterator &operator-=(QJniArrayMutableIterator &that, difference_type n)
noexcept
275 friend difference_type operator-(
const QJniArrayMutableIterator &lhs,
276 const QJniArrayMutableIterator &rhs)
278 Q_ASSERT(lhs.m_array == rhs.m_array);
279 return lhs.m_index - rhs.m_index;
281 void swap(QJniArrayMutableIterator &other)
noexcept
283 std::swap(m_index, other.m_index);
284 qt_ptr_swap(m_array, other.m_array);
288 friend constexpr bool comparesEqual(
const QJniArrayMutableIterator &lhs,
289 const QJniArrayMutableIterator &rhs)
291 Q_ASSERT(lhs.m_array == rhs.m_array);
292 return lhs.m_index == rhs.m_index;
294 friend constexpr bool comparesEqual(
const QJniArrayMutableIterator &lhs,
295 const QJniArrayIterator<
const T> &rhs)
297 Q_ASSERT(lhs.m_array == rhs.m_array);
298 return lhs.m_index == rhs.m_index;
300 friend constexpr Qt::strong_ordering compareThreeWay(
const QJniArrayMutableIterator &lhs,
301 const QJniArrayMutableIterator &rhs)
303 Q_ASSERT(lhs.m_array == rhs.m_array);
304 return Qt::compareThreeWay(lhs.m_index, rhs.m_index);
306 friend constexpr Qt::strong_ordering compareThreeWay(
const QJniArrayMutableIterator &lhs,
307 const QJniArrayIterator<
const T> &rhs)
309 Q_ASSERT(lhs.m_array == rhs.m_array);
310 return Qt::compareThreeWay(lhs.m_index, rhs.m_index);
312 Q_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT(QJniArrayMutableIterator)
313 Q_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT(QJniArrayMutableIterator, QJniArrayIterator<
const T>)
315 using VT = std::remove_const_t<T>;
316 friend class QJniArray<VT>;
318 qsizetype m_index = 0;
319 QJniArray<VT> *m_array =
nullptr;
321 QJniArrayMutableIterator(qsizetype index, QJniArray<VT> *array)
322 : m_index(index), m_array(array)
327struct QJniArrayMutableValueRef {
329 QJniArrayMutableIterator<T> back = {-1,
nullptr};
331 operator T()
const {
return value; }
332 const T &operator*()
const {
return value; }
333 T &operator*() {
return value; }
335 const T *operator->()
const {
return &value; }
336 T *operator->() =
delete;
338 QJniArrayMutableValueRef &operator=(
const QJniArrayMutableValueRef &other)
340 return *
this = *other;
342 QJniArrayMutableValueRef &operator=(QJniArrayMutableValueRef &&other)
344 return *
this = std::move(*other);
347 QJniArrayMutableValueRef &operator=(
const T &v)
349 Q_ASSERT(back.m_array);
351 back.m_array->setValue(back.m_index, value);
354 QJniArrayMutableValueRef &operator=(T &&v)
356 Q_ASSERT(back.m_array);
357 value = std::move(v);
358 back.m_array->setValue(back.m_index, value);
366 template <
typename C,
typename =
void>
struct IsSequentialContainerHelper : std::false_type
368 static constexpr bool isForwardIterable =
false;
370 template <
typename C>
371 struct IsSequentialContainerHelper<C, std::void_t<
typename std::iterator_traits<
typename C::const_iterator>::iterator_category,
372 typename C::value_type,
373 decltype(std::size(std::declval<C>()))
377 static constexpr bool isForwardIterable = std::is_convertible_v<
378 typename std::iterator_traits<
typename C::const_iterator>::iterator_category,
379 std::forward_iterator_tag
383 struct IsSequentialContainerHelper<QByteArray,
void>
385 static constexpr bool isForwardIterable =
true;
388 template <
typename C,
typename =
void>
struct IsContiguousContainerHelper : std::false_type {};
389 template <
typename C>
390 struct IsContiguousContainerHelper<C, std::void_t<
decltype(std::data(std::declval<C>())),
391 decltype(std::size(std::declval<C>())),
392 typename C::value_type
394 > : std::true_type {};
396 template <
typename C,
typename =
void>
struct HasEmplaceBackTest : std::false_type {};
397 template <
typename C>
struct HasEmplaceBackTest<C,
398 std::void_t<
decltype(std::declval<C>().emplace_back(std::declval<
typename C::value_type>()))>
405 template <
typename C,
typename =
void>
406 struct ElementTypeHelper
408 static constexpr bool isObject =
false;
409 static constexpr bool isPrimitive =
false;
411 template <
typename C>
412 struct ElementTypeHelper<C, std::void_t<
typename C::value_type>>
414 using E =
typename C::value_type;
415 static constexpr bool isObject = QtJniTypes::isObjectType<E>();
416 static constexpr bool isPrimitive = QtJniTypes::isPrimitiveType<E>();
419 template <
typename CRef,
typename C = q20::remove_cvref_t<CRef>>
420 static constexpr bool isContiguousContainer = IsContiguousContainerHelper<C>::value;
422 template <
typename From,
typename To>
423 using if_convertible = std::enable_if_t<QtPrivate::AreArgumentsConvertibleWithoutNarrowingBase<From, To>::value,
bool>;
424 template <
typename From,
typename To>
425 using unless_convertible = std::enable_if_t<!QtPrivate::AreArgumentsConvertibleWithoutNarrowingBase<From, To>::value,
bool>;
428 template <
typename E>
struct ToContainerHelper {
using type = QList<E>; };
429 template <>
struct ToContainerHelper<jstring> {
using type = QStringList; };
430 template <>
struct ToContainerHelper<jbyte> {
using type = QByteArray; };
431 template <>
struct ToContainerHelper<
char> {
using type = QByteArray; };
433 template <
typename E>
434 using ToContainerType =
typename ToContainerHelper<E>::type;
436 template <
typename E,
typename CRef,
typename C = q20::remove_cvref_t<CRef>>
437 static constexpr bool isCompatibleTargetContainer =
438 (QtPrivate::AreArgumentsConvertibleWithoutNarrowingBase<E,
typename C::value_type>::value
439 || QtPrivate::AreArgumentsConvertibleWithoutNarrowingBase<
typename ToContainerType<E>::value_type,
440 typename C::value_type>::value
441 || (std::is_base_of_v<QtJniTypes::JObjectBase, E> && std::is_same_v<
typename C::value_type, QString>))
442 && (qxp::is_detected_v<HasEmplaceBackTest, C>
443 || (isContiguousContainer<C> && ElementTypeHelper<C>::isPrimitive));
446 using size_type = jsize;
447 using difference_type = size_type;
449 operator QJniObject()
const {
return m_object; }
451 template <
typename T = jobject>
452 T object()
const {
return m_object.object<T>(); }
453 bool isValid()
const {
return m_object.isValid(); }
454 bool isEmpty()
const {
return size() == 0; }
456 size_type size()
const
458 if (jarray array = m_object.object<jarray>())
459 return jniEnv()->GetArrayLength(array);
468 template <
typename C>
469 using IsSequentialOrContiguous = std::bool_constant<
470 IsSequentialContainerHelper<C>::isForwardIterable
471 || (isContiguousContainer<C> && ElementTypeHelper<C>::isPrimitive)
473 template <
typename CRef,
typename C = q20::remove_cvref_t<CRef>>
474 static constexpr bool isCompatibleSourceContainer = std::conjunction_v<
475 std::negation<std::is_same<QString, C>>,
476 IsSequentialOrContiguous<C>,
477 std::negation<std::is_base_of<QJniArrayBase, C>>
480 template <
typename C>
481 using if_compatible_source_container = std::enable_if_t<isCompatibleSourceContainer<C>,
bool>;
482 template <
typename T,
typename C>
483 using if_compatible_target_container = std::enable_if_t<isCompatibleTargetContainer<T, C>,
bool>;
485 template <
typename Container, if_compatible_source_container<Container> =
true>
486 static auto fromContainer(Container &&container)
488 verifySize(std::size(container));
489 using ElementType =
typename std::remove_reference_t<Container>::value_type;
490 if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>,
491 std::remove_pointer_t<ElementType>>) {
492 return makeObjectArray(std::forward<Container>(container));
493 }
else if constexpr (std::disjunction_v<std::is_same<ElementType, QJniObject>,
494 std::is_same<ElementType, QString>,
495 std::is_base_of<QtJniTypes::JObjectBase, ElementType>
497 return QJniArray<ElementType>(makeObjectArray(std::forward<Container>(container)).arrayObject());
498 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jfloat>) {
499 return makeArray<jfloat>(std::forward<Container>(container), &JNIEnv::NewFloatArray,
500 &JNIEnv::SetFloatArrayRegion);
501 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jdouble>) {
502 return makeArray<jdouble>(std::forward<Container>(container), &JNIEnv::NewDoubleArray,
503 &JNIEnv::SetDoubleArrayRegion);
504 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jboolean>) {
505 return makeArray<jboolean>(std::forward<Container>(container), &JNIEnv::NewBooleanArray,
506 &JNIEnv::SetBooleanArrayRegion);
507 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jbyte>
508 || std::is_same_v<ElementType,
char>) {
509 return makeArray<jbyte>(std::forward<Container>(container), &JNIEnv::NewByteArray,
510 &JNIEnv::SetByteArrayRegion);
511 }
else if constexpr (std::disjunction_v<std::is_same<ElementType, jchar>,
512 std::is_same<ElementType, QChar>>) {
513 return makeArray<jchar>(std::forward<Container>(container), &JNIEnv::NewCharArray,
514 &JNIEnv::SetCharArrayRegion);
515 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jshort>) {
516 return makeArray<jshort>(std::forward<Container>(container), &JNIEnv::NewShortArray,
517 &JNIEnv::SetShortArrayRegion);
518 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jint>) {
519 return makeArray<jint>(std::forward<Container>(container), &JNIEnv::NewIntArray,
520 &JNIEnv::SetIntArrayRegion);
521 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jlong>) {
522 return makeArray<jlong>(std::forward<Container>(container), &JNIEnv::NewLongArray,
523 &JNIEnv::SetLongArrayRegion);
525 static_assert(QtPrivate::type_dependent_false<ElementType>(),
526 "Don't know how to make QJniArray for this element type");
531 QJniArrayBase() =
default;
532 ~QJniArrayBase() =
default;
534 explicit QJniArrayBase(
const QJniArrayBase &other) =
default;
535 explicit QJniArrayBase(QJniArrayBase &&other)
noexcept =
default;
536 QJniArrayBase &operator=(
const QJniArrayBase &other) =
default;
537 QJniArrayBase &operator=(QJniArrayBase &&other)
noexcept =
default;
539 explicit QJniArrayBase(jarray array)
540 : m_object(
static_cast<jobject>(array))
543 explicit QJniArrayBase(
const QJniObject &object)
546 explicit QJniArrayBase(QJniObject &&object)
noexcept
547 : m_object(std::move(object))
549 QJniArrayBase &operator=(
const QJniObject &object)
554 QJniArrayBase &operator=(QJniObject &&object)
noexcept
556 m_object = std::move(object);
560 JNIEnv *jniEnv()
const noexcept {
return QJniEnvironment::getJniEnv(); }
562 template <
typename ElementType,
typename List,
typename NewFn,
typename SetFn>
563 static auto makeArray(List &&list, NewFn &&newArray, SetFn &&setRegion);
564 template <
typename List>
565 static auto makeObjectArray(List &&list);
566 template <
typename ElementType>
567 static auto makeEmptyArray(size_type size)
569 auto env = QJniEnvironment();
570 if constexpr (std::disjunction_v<std::is_base_of<std::remove_pointer_t<jobject>,
571 std::remove_pointer_t<ElementType>>,
572 std::is_same<ElementType, QJniObject>,
573 std::is_same<ElementType, QString>,
574 std::is_base_of<QtJniTypes::JObjectBase, ElementType>
576 using ResultType =
decltype(QtJniTypes::Traits<ElementType>::convertToJni(
nullptr, {}));
577 const auto className = QtJniTypes::Traits<ResultType>::className();
578 jclass elementClass = env.findClass(className);
580 env.checkAndClearExceptions();
581 return jobjectArray(
nullptr);
583 return env->NewObjectArray(size, elementClass,
nullptr);
584 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jfloat>) {
585 return env->NewFloatArray(size);
586 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jdouble>) {
587 return env->NewDoubleArray(size);
588 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jboolean>) {
589 return env->NewBooleanArray(size);
590 }
else if constexpr (std::disjunction_v<std::is_same<ElementType, jbyte>,
591 std::is_same<ElementType,
char>>) {
592 return env->NewByteArray(size);
593 }
else if constexpr (std::disjunction_v<std::is_same<ElementType, jchar>,
594 std::is_same<ElementType, QChar>>) {
595 return env->NewCharArray(size);
596 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jshort>) {
597 return env->NewShortArray(size);
598 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jint>) {
599 return env->NewIntArray(size);
600 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jlong>) {
601 return env->NewLongArray(size);
603 static_assert(QtPrivate::type_dependent_false<ElementType>(),
604 "Don't know how to make QJniArray for this element type");
608 void swap(QJniArrayBase &other)
noexcept { m_object.swap(other.m_object); }
611 template <
typename container_size_type>
612 static void verifySize(container_size_type size)
614 if (!q20::in_range<size_type>(size))
615 qWarning(
"QJniArray::fromContainer: Container is too large for Java and will be truncated!");
622class QJniArray :
public QJniArrayBase
624 friend struct QJniArrayIterator<T>;
626 template <
typename C>
627 using CanReserveTest =
decltype(std::declval<C>().reserve(0));
628 template <
typename C>
629 static constexpr bool canReserve = qxp::is_detected_v<CanReserveTest, C>;
634 using value_type = T;
635 using iterator = QJniArrayMutableIterator<T>;
636 using reverse_iterator = std::reverse_iterator<iterator>;
637 using const_iterator = QJniArrayIterator<
const T>;
638 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
640 using reference =
typename iterator::reference;
641 using const_reference =
typename const_iterator::const_reference;
643 QJniArray() =
default;
644 explicit QJniArray(jarray array) : QJniArrayBase(array) {}
645 explicit QJniArray(
const QJniObject &object) : QJniArrayBase(object) {}
646 explicit QJniArray(QJniObject &&object)
noexcept : QJniArrayBase(std::move(object)) {}
648 template <
typename Other, if_convertible<Other, T> =
true>
649 QJniArray(
const QJniArray<Other> &other)
650 : QJniArrayBase(other)
653 template <
typename Other, if_convertible<Other, T> =
true>
654 QJniArray(QJniArray<Other> &&other)
noexcept
655 : QJniArrayBase(std::move(other))
658 template <
typename Other, if_convertible<Other, T> =
true>
659 QJniArray &operator=(
const QJniArray<Other> &other)
661 QJniArrayBase::operator=(QJniObject(other));
664 template <
typename Other, if_convertible<Other, T> =
true>
665 QJniArray &operator=(QJniArray<Other> &&other)
noexcept
667 QJniArray moved(std::move(other));
672 template <
typename Other, unless_convertible<Other, T> =
true>
673 QJniArray(
const QJniArray<Other> &other) =
delete;
674 template <
typename Other, unless_convertible<Other, T> =
true>
675 QJniArray(QJniArray<Other> &&other)
noexcept =
delete;
677 template <
typename Container, if_compatible_source_container<Container> =
true>
678 explicit QJniArray(Container &&container)
679 : QJniArrayBase(QJniArrayBase::fromContainer(std::forward<Container>(container)))
683 Q_IMPLICIT
inline QJniArray(std::initializer_list<T> list)
684 : QJniArrayBase(QJniArrayBase::fromContainer(list))
688 explicit QJniArray(size_type size)
689 : QJniArrayBase(makeEmptyArray<T>(size))
692 ~QJniArray() =
default;
694 auto arrayObject()
const
696 if constexpr (QtJniTypes::isObjectType<T>())
697 return object<jobjectArray>();
698 else if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>)
699 return object<jbyteArray>();
700 else if constexpr (QtJniTypes::sameTypeForJni<T, jchar>)
701 return object<jcharArray>();
702 else if constexpr (QtJniTypes::sameTypeForJni<T, jboolean>)
703 return object<jbooleanArray>();
704 else if constexpr (QtJniTypes::sameTypeForJni<T, jshort>)
705 return object<jshortArray>();
706 else if constexpr (QtJniTypes::sameTypeForJni<T, jint>)
707 return object<jintArray>();
708 else if constexpr (QtJniTypes::sameTypeForJni<T, jlong>)
709 return object<jlongArray>();
710 else if constexpr (QtJniTypes::sameTypeForJni<T, jfloat>)
711 return object<jfloatArray>();
712 else if constexpr (QtJniTypes::sameTypeForJni<T, jdouble>)
713 return object<jdoubleArray>();
715 return object<jarray>();
718 const_iterator begin()
const noexcept {
return {0,
this}; }
719 const_iterator constBegin()
const noexcept {
return begin(); }
720 const_iterator cbegin()
const noexcept {
return begin(); }
721 const_iterator end()
const noexcept {
return {size(),
this}; }
722 const_iterator constEnd()
const noexcept {
return {end()}; }
723 const_iterator cend()
const noexcept {
return {end()}; }
725 iterator begin()
noexcept {
return {0,
this}; }
726 iterator end()
noexcept {
return {size(),
this}; }
728 const_reverse_iterator rbegin()
const noexcept {
return const_reverse_iterator(end()); }
729 const_reverse_iterator rend()
const noexcept {
return const_reverse_iterator(begin()); }
730 const_reverse_iterator crbegin()
const noexcept {
return const_reverse_iterator(end()); }
731 const_reverse_iterator crend()
const noexcept {
return const_reverse_iterator(begin()); }
733 reverse_iterator rbegin()
noexcept {
return reverse_iterator(end()); }
734 reverse_iterator rend()
noexcept {
return reverse_iterator(begin()); }
736 const_reference operator[](size_type i)
const {
return at(i); }
737 reference operator[](size_type i) {
return reference{at(i), iterator{i,
this}}; }
738 const_reference at(size_type i)
const
740 JNIEnv *env = jniEnv();
741 if constexpr (QtJniTypes::isObjectType<T>()) {
742 jobject element = env->GetObjectArrayElement(object<jobjectArray>(), i);
743 if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>)
744 return static_cast<T>(element);
746 return QtJniTypes::Traits<T>::convertFromJni(QJniObject::fromLocalRef(element));
749 if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>)
750 env->GetByteArrayRegion(object<jbyteArray>(), i, 1, &res);
751 else if constexpr (QtJniTypes::sameTypeForJni<T, jchar>)
752 env->GetCharArrayRegion(object<jcharArray>(), i, 1, &res);
753 else if constexpr (QtJniTypes::sameTypeForJni<T, jboolean>)
754 env->GetBooleanArrayRegion(object<jbooleanArray>(), i, 1, &res);
755 else if constexpr (QtJniTypes::sameTypeForJni<T, jshort>)
756 env->GetShortArrayRegion(object<jshortArray>(), i, 1, &res);
757 else if constexpr (QtJniTypes::sameTypeForJni<T, jint>)
758 env->GetIntArrayRegion(object<jintArray>(), i, 1, &res);
759 else if constexpr (QtJniTypes::sameTypeForJni<T, jlong>)
760 env->GetLongArrayRegion(object<jlongArray>(), i, 1, &res);
761 else if constexpr (QtJniTypes::sameTypeForJni<T, jfloat>)
762 env->GetFloatArrayRegion(object<jfloatArray>(), i, 1, &res);
763 else if constexpr (QtJniTypes::sameTypeForJni<T, jdouble>)
764 env->GetDoubleArrayRegion(object<jdoubleArray>(), i, 1, &res);
769 void setValue(size_type i, const_reference &val)
771 JNIEnv *env = jniEnv();
773 if constexpr (QtJniTypes::isObjectType<T>()) {
774 QtJniTypes::Detail::LocalFrame<T> frame(env);
775 jobject element = frame.convertToJni(val);
776 env->SetObjectArrayElement(object<jobjectArray>(), i, element);
778 if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>)
779 env->SetByteArrayRegion(object<jbyteArray>(), i, 1, &val);
780 else if constexpr (QtJniTypes::sameTypeForJni<T, jchar>)
781 env->SetCharArrayRegion(object<jcharArray>(), i, 1, &val);
782 else if constexpr (QtJniTypes::sameTypeForJni<T, jboolean>)
783 env->SetBooleanArrayRegion(object<jbooleanArray>(), i, 1, &val);
784 else if constexpr (QtJniTypes::sameTypeForJni<T, jshort>)
785 env->SetShortArrayRegion(object<jshortArray>(), i, 1, &val);
786 else if constexpr (QtJniTypes::sameTypeForJni<T, jint>)
787 env->SetIntArrayRegion(object<jintArray>(), i, 1, &val);
788 else if constexpr (QtJniTypes::sameTypeForJni<T, jlong>)
789 env->SetLongArrayRegion(object<jlongArray>(), i, 1, &val);
790 else if constexpr (QtJniTypes::sameTypeForJni<T, jfloat>)
791 env->SetFloatArrayRegion(object<jfloatArray>(), i, 1, &val);
792 else if constexpr (QtJniTypes::sameTypeForJni<T, jdouble>)
793 env->SetDoubleArrayRegion(object<jdoubleArray>(), i, 1, &val);
797 template <
typename Container = ToContainerType<T>, if_compatible_target_container<T, Container> =
true>
798 Container toContainer(Container &&container = {})
const
800 const qsizetype sz = size();
802 return std::forward<Container>(container);
803 JNIEnv *env = jniEnv();
805 using ContainerType = q20::remove_cvref_t<Container>;
807 if constexpr (canReserve<ContainerType>)
808 container.reserve(sz);
809 if constexpr (std::is_same_v<
typename ContainerType::value_type, QString>) {
810 for (
auto element : *
this) {
811 if constexpr (std::is_same_v<
decltype(element), QString>) {
812 container.emplace_back(element);
813 }
else if constexpr (std::is_same_v<
decltype(element), jstring>) {
814 container.emplace_back(element ? QtJniTypes::Detail::toQString(element, env)
817 container.emplace_back(QJniObject(element).toString());
820 }
else if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>) {
821 for (
auto element : *
this)
822 container.emplace_back(element);
823 }
else if constexpr (isContiguousContainer<ContainerType>) {
824 container.resize(sz);
825 if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>) {
826 env->GetByteArrayRegion(object<jbyteArray>(),
828 reinterpret_cast<jbyte *>(container.data()));
829 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jchar>) {
830 env->GetCharArrayRegion(object<jcharArray>(),
831 0, sz, container.data());
832 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jboolean>) {
833 env->GetBooleanArrayRegion(object<jbooleanArray>(),
834 0, sz, container.data());
835 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jshort>) {
836 env->GetShortArrayRegion(object<jshortArray>(),
837 0, sz, container.data());
838 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jint>) {
839 env->GetIntArrayRegion(object<jintArray>(),
840 0, sz, container.data());
841 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jlong>) {
842 env->GetLongArrayRegion(object<jlongArray>(),
843 0, sz, container.data());
844 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jfloat>) {
845 env->GetFloatArrayRegion(object<jfloatArray>(),
846 0, sz, container.data());
847 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jdouble>) {
848 env->GetDoubleArrayRegion(object<jdoubleArray>(),
849 0, sz, container.data());
851 static_assert(QtPrivate::type_dependent_false<T>(),
852 "Don't know how to copy data from a QJniArray of this type");
856 container.emplace_back(e);
858 return std::forward<Container>(container);
866template <
typename Container, QJniArrayBase::if_compatible_source_container<Container> =
true>
867QJniArray(Container) -> QJniArray<
typename decltype(QJniArrayBase::fromContainer(std::declval<Container>()))::value_type>;
869template <
typename ElementType,
typename List,
typename NewFn,
typename SetFn>
870auto QJniArrayBase::makeArray(List &&list, NewFn &&newArray, SetFn &&setRegion)
872 const size_type length = size_type(std::size(list));
873 JNIEnv *env = QJniEnvironment::getJniEnv();
874 auto localArray = (env->*newArray)(length);
875 if (QJniEnvironment::checkAndClearExceptions(env)) {
877 env->DeleteLocalRef(localArray);
878 return QJniArray<ElementType>();
883 if constexpr (isContiguousContainer<List>) {
884 (env->*setRegion)(localArray, 0, length,
885 reinterpret_cast<
const ElementType *>(std::data(std::as_const(list))));
888 for (
const auto &e : std::as_const(list))
889 (env->*setRegion)(localArray, i++, 1,
reinterpret_cast<
const ElementType *>(&e));
892 return QJniArray<ElementType>(QJniObject::fromLocalRef(localArray));
895template <
typename List>
896auto QJniArrayBase::makeObjectArray(List &&list)
898 using ElementType =
typename q20::remove_cvref_t<List>::value_type;
899 using ResultType = QJniArray<
decltype(QtJniTypes::Traits<ElementType>::convertToJni(
nullptr,
902 if (std::size(list) == 0)
905 JNIEnv *env = QJniEnvironment::getJniEnv();
906 const size_type length = q26::saturate_cast<size_type>(std::size(list));
909 jclass elementClass =
nullptr;
910 if constexpr (std::disjunction_v<std::is_same<ElementType, QJniObject>,
911 std::is_base_of<QtJniTypes::JObjectBase, ElementType>>) {
912 elementClass = std::begin(list)->objectClass();
913 }
else if constexpr (std::is_same_v<ElementType, QString>) {
914 elementClass = QtAndroidPrivate::findClass(
"java/lang/String", env);
916 elementClass = env->GetObjectClass(*std::begin(list));
918 auto localArray = env->NewObjectArray(length, elementClass,
nullptr);
919 if (QJniEnvironment::checkAndClearExceptions(env)) {
921 env->DeleteLocalRef(localArray);
926 constexpr jint frameCapacity = 100;
928 for (
const auto &element : std::as_const(list)) {
929 if (i % frameCapacity == 0) {
931 env->PopLocalFrame(
nullptr);
932 if (env->PushLocalFrame(frameCapacity) != 0)
935 jobject object = QtJniTypes::Traits<ElementType>::convertToJni(env, element);
936 env->SetObjectArrayElement(localArray, i, object);
940 env->PopLocalFrame(
nullptr);
941 return ResultType(QJniObject::fromLocalRef(localArray));
946template <
typename T>
struct Traits<QJniArray<T>>
948 template <IfValidFieldType<T> =
true>
949 static constexpr auto signature()
951 return CTString(
"[") + Traits<T>::signature();
953 static auto convertToJni(JNIEnv *,
const QJniArray<T> &value)
955 return value.arrayObject();
957 static auto convertFromJni(QJniObject &&object)
959 return QJniArray<T>(std::move(object));
963template <
typename T>
struct Traits<QJniArrayMutableValueRef<T>> :
public Traits<T> {};
965template<
typename T>
struct Traits<T, std::enable_if_t<QJniArrayBase::isCompatibleSourceContainer<T>>>
968 using ElementType = std::conditional_t<std::is_same_v<T, QByteArray>,
969 jbyte,
typename T::value_type>;
971 template <
typename U = ElementType, IfValidFieldType<U> =
true>
972 static constexpr auto signature()
974 return CTString(
"[") + Traits<ElementType>::signature();
977 static auto convertToJni(JNIEnv *env,
const T &value)
979 using QJniArrayType =
decltype(QJniArrayBase::fromContainer(value));
980 using ArrayType =
decltype(std::declval<QJniArrayType>().arrayObject());
981 return static_cast<ArrayType>(env->NewLocalRef(QJniArray(value).arrayObject()));
984 static auto convertFromJni(QJniObject &&object)
987 using QJniArrayType =
decltype(QJniArrayBase::fromContainer(std::declval<T>()));
989 using ArrayType =
typename QJniArrayType::Type;
991 return QJniArray<ArrayType>(object.
template object<jarray>()).toContainer();
995template<
typename T>
struct Traits<T, std::enable_if_t<std::is_array_v<T>>>
997 using ElementType = std::remove_extent_t<T>;
999 template <
typename U = ElementType, IfValidFieldType<U> =
true>
1000 static constexpr auto signature()
1002 static_assert(!std::is_array_v<ElementType>,
1003 "Traits::signature() does not handle multi-dimensional arrays");
1004 return CTString(
"[") + Traits<U>::signature();
1007 static constexpr auto convertFromJni(QJniObject &&object)
1009 return QJniArray<ElementType>(std::move(object));