8#include <QtCore/qlist.h>
10#if defined(Q_QDOC) || defined(Q_OS_ANDROID)
11#include <QtCore/qbytearray.h>
12#include <QtCore/qjniobject.h>
15#include <QtCore/q26numeric.h>
16#include <QtCore/q20type_traits.h>
17#include <QtCore/q20utility.h>
21using jarray = jobject;
26template <
typename T>
class QJniArray;
27template <
typename T>
struct QJniArrayMutableIterator;
30namespace QtAndroidPrivate
32 Q_CORE_EXPORT jclass findClass(
const char *className, JNIEnv *env);
36struct QJniArrayIterator
39 using VT = std::remove_const_t<T>;
40 friend class QJniArray<VT>;
41 friend struct QJniArrayMutableIterator<VT>;
45 struct QJniArrayValueRef {
47 const T *operator->()
const {
return &ref; }
51 QJniArrayIterator() =
default;
52 constexpr QJniArrayIterator(
const QJniArrayMutableIterator<VT> &other)
noexcept
53 : m_index(other.m_index), m_array(other.m_array)
55 constexpr QJniArrayIterator(QJniArrayMutableIterator<VT> &&other)
noexcept
56 : m_index(std::exchange(other.m_index, -1)), m_array(std::exchange(other.m_array,
nullptr))
59 constexpr QJniArrayIterator(
const QJniArrayIterator &other)
noexcept =
default;
60 constexpr QJniArrayIterator(QJniArrayIterator &&other)
noexcept =
default;
61 constexpr QJniArrayIterator &operator=(
const QJniArrayIterator &other)
noexcept =
default;
62 constexpr QJniArrayIterator &operator=(QJniArrayIterator &&other)
noexcept =
default;
64 using difference_type = jsize;
66 using pointer = QJniArrayValueRef;
68 using const_reference = reference;
69 using iterator_category = std::random_access_iterator_tag;
71 const_reference operator*()
const
73 return m_array->at(m_index);
76 QJniArrayValueRef operator->()
const
78 return {m_array->at(m_index)};
81 const_reference operator[](difference_type n)
const
83 return m_array->at(m_index + n);
86 friend QJniArrayIterator &operator++(QJniArrayIterator &that)
noexcept
91 friend QJniArrayIterator operator++(QJniArrayIterator &that,
int)
noexcept
97 friend QJniArrayIterator operator+(
const QJniArrayIterator &that, difference_type n)
noexcept
99 return {that.m_index + n, that.m_array};
101 friend QJniArrayIterator operator+(difference_type n,
const QJniArrayIterator &that)
noexcept
105 friend QJniArrayIterator &operator+=(QJniArrayIterator &that, difference_type n)
noexcept
110 friend QJniArrayIterator &operator--(QJniArrayIterator &that)
noexcept
115 friend QJniArrayIterator operator--(QJniArrayIterator &that,
int)
noexcept
121 friend QJniArrayIterator operator-(
const QJniArrayIterator &that, difference_type n)
noexcept
123 return {that.m_index - n, that.m_array};
125 friend QJniArrayIterator operator-(difference_type n,
const QJniArrayIterator &that)
noexcept
127 return {n - that.m_index, that.m_array};
129 friend QJniArrayIterator &operator-=(QJniArrayIterator &that, difference_type n)
noexcept
134 friend difference_type operator-(
const QJniArrayIterator &lhs,
const QJniArrayIterator &rhs)
136 Q_ASSERT(lhs.m_array == rhs.m_array);
137 return lhs.m_index - rhs.m_index;
139 void swap(QJniArrayIterator &other)
noexcept
141 std::swap(m_index, other.m_index);
142 qt_ptr_swap(m_array, other.m_array);
146 friend constexpr bool comparesEqual(
const QJniArrayIterator &lhs,
147 const QJniArrayIterator &rhs)
noexcept
149 Q_ASSERT(lhs.m_array == rhs.m_array);
150 return lhs.m_index == rhs.m_index;
152 friend constexpr Qt::strong_ordering compareThreeWay(
const QJniArrayIterator &lhs,
153 const QJniArrayIterator &rhs)
noexcept
155 Q_ASSERT(lhs.m_array == rhs.m_array);
156 return Qt::compareThreeWay(lhs.m_index, rhs.m_index);
158 Q_DECLARE_STRONGLY_ORDERED(QJniArrayIterator)
160 qsizetype m_index = 0;
161 const QJniArray<VT> *m_array =
nullptr;
163 QJniArrayIterator(qsizetype index,
const QJniArray<VT> *array)
164 : m_index(index), m_array(array)
169struct QJniArrayMutableValueRef;
172struct QJniArrayMutableIterator
175 friend struct QJniArrayIterator<
const T>;
176 friend struct QJniArrayMutableValueRef<T>;
179 constexpr QJniArrayMutableIterator()
noexcept =
default;
180 constexpr QJniArrayMutableIterator(
const QJniArrayIterator<
const T> &other)
noexcept
181 : m_index(other.m_index), m_array(other.m_array)
183 constexpr QJniArrayMutableIterator(QJniArrayIterator<
const T> &&other)
noexcept
184 : m_index(std::exchange(other.m_index, -1)), m_array(std::exchange(other.m_array,
nullptr))
187 constexpr QJniArrayMutableIterator(
const QJniArrayMutableIterator &other)
noexcept =
default;
188 constexpr QJniArrayMutableIterator(QJniArrayMutableIterator &&other)
noexcept =
default;
189 constexpr QJniArrayMutableIterator &operator=(
const QJniArrayMutableIterator &other)
noexcept =
default;
190 constexpr QJniArrayMutableIterator &operator=(QJniArrayMutableIterator &&other)
noexcept =
default;
192 using difference_type = jsize;
193 using value_type = T;
194 using pointer = QJniArrayMutableValueRef<T>;
195 using reference = QJniArrayMutableValueRef<T>;
196 using const_reference = T;
197 using iterator_category = std::random_access_iterator_tag;
199 const_reference operator*()
const
201 return m_array->at(m_index);
204 reference operator*()
206 return {m_array->at(m_index), *
this};
209 const pointer operator->()
const
211 return {m_array->at(m_index)};
216 return {m_array->at(m_index), *
this};
219 const_reference operator[](difference_type n)
const
221 return m_array->at(m_index + n);
223 reference operator[](difference_type n)
225 return {m_array->at(m_index + n), *
this};
228 friend QJniArrayMutableIterator &operator++(QJniArrayMutableIterator &that)
noexcept
233 friend QJniArrayMutableIterator operator++(QJniArrayMutableIterator &that,
int)
noexcept
239 friend QJniArrayMutableIterator operator+(
const QJniArrayMutableIterator &that, difference_type n)
noexcept
241 return {that.m_index + n, that.m_array};
243 friend QJniArrayMutableIterator operator+(difference_type n,
const QJniArrayMutableIterator &that)
noexcept
247 friend QJniArrayMutableIterator &operator+=(QJniArrayMutableIterator &that, difference_type n)
noexcept
252 friend QJniArrayMutableIterator &operator--(QJniArrayMutableIterator &that)
noexcept
257 friend QJniArrayMutableIterator operator--(QJniArrayMutableIterator &that,
int)
noexcept
263 friend QJniArrayMutableIterator operator-(
const QJniArrayMutableIterator &that, difference_type n)
noexcept
265 return {that.m_index - n, that.m_array};
267 friend QJniArrayMutableIterator operator-(difference_type n,
const QJniArrayMutableIterator &that)
noexcept
269 return {n - that.m_index, that.m_array};
271 friend QJniArrayMutableIterator &operator-=(QJniArrayMutableIterator &that, difference_type n)
noexcept
276 friend difference_type operator-(
const QJniArrayMutableIterator &lhs,
277 const QJniArrayMutableIterator &rhs)
279 Q_ASSERT(lhs.m_array == rhs.m_array);
280 return lhs.m_index - rhs.m_index;
282 void swap(QJniArrayMutableIterator &other)
noexcept
284 std::swap(m_index, other.m_index);
285 qt_ptr_swap(m_array, other.m_array);
289 friend constexpr bool comparesEqual(
const QJniArrayMutableIterator &lhs,
290 const QJniArrayMutableIterator &rhs)
292 Q_ASSERT(lhs.m_array == rhs.m_array);
293 return lhs.m_index == rhs.m_index;
295 friend constexpr bool comparesEqual(
const QJniArrayMutableIterator &lhs,
296 const QJniArrayIterator<
const T> &rhs)
298 Q_ASSERT(lhs.m_array == rhs.m_array);
299 return lhs.m_index == rhs.m_index;
301 friend constexpr Qt::strong_ordering compareThreeWay(
const QJniArrayMutableIterator &lhs,
302 const QJniArrayMutableIterator &rhs)
304 Q_ASSERT(lhs.m_array == rhs.m_array);
305 return Qt::compareThreeWay(lhs.m_index, rhs.m_index);
307 friend constexpr Qt::strong_ordering compareThreeWay(
const QJniArrayMutableIterator &lhs,
308 const QJniArrayIterator<
const T> &rhs)
310 Q_ASSERT(lhs.m_array == rhs.m_array);
311 return Qt::compareThreeWay(lhs.m_index, rhs.m_index);
313 Q_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT(QJniArrayMutableIterator)
314 Q_DECLARE_STRONGLY_ORDERED_NON_NOEXCEPT(QJniArrayMutableIterator, QJniArrayIterator<
const T>)
316 using VT = std::remove_const_t<T>;
317 friend class QJniArray<VT>;
319 qsizetype m_index = 0;
320 QJniArray<VT> *m_array =
nullptr;
322 QJniArrayMutableIterator(qsizetype index, QJniArray<VT> *array)
323 : m_index(index), m_array(array)
328struct QJniArrayMutableValueRef {
330 QJniArrayMutableIterator<T> back = {-1,
nullptr};
332 operator T()
const {
return value; }
333 const T &operator*()
const {
return value; }
334 T &operator*() {
return value; }
336 const T *operator->()
const {
return &value; }
337 T *operator->() =
delete;
339 QJniArrayMutableValueRef &operator=(
const QJniArrayMutableValueRef &other)
341 return *
this = *other;
343 QJniArrayMutableValueRef &operator=(QJniArrayMutableValueRef &&other)
345 return *
this = std::move(*other);
348 QJniArrayMutableValueRef &operator=(
const T &v)
350 Q_ASSERT(back.m_array);
352 back.m_array->setValue(back.m_index, value);
355 QJniArrayMutableValueRef &operator=(T &&v)
357 Q_ASSERT(back.m_array);
358 value = std::move(v);
359 back.m_array->setValue(back.m_index, value);
367 template <
typename C,
typename =
void>
struct IsSequentialContainerHelper : std::false_type
369 static constexpr bool isForwardIterable =
false;
371 template <
typename C>
372 struct IsSequentialContainerHelper<C, std::void_t<
typename std::iterator_traits<
typename C::const_iterator>::iterator_category,
373 typename C::value_type,
374 decltype(std::size(std::declval<C>()))
378 static constexpr bool isForwardIterable = std::is_convertible_v<
379 typename std::iterator_traits<
typename C::const_iterator>::iterator_category,
380 std::forward_iterator_tag
384 struct IsSequentialContainerHelper<QByteArray,
void>
386 static constexpr bool isForwardIterable =
true;
389 template <
typename C,
typename =
void>
struct IsContiguousContainerHelper : std::false_type {};
390 template <
typename C>
391 struct IsContiguousContainerHelper<C, std::void_t<
decltype(std::data(std::declval<C>())),
392 decltype(std::size(std::declval<C>())),
393 typename C::value_type
395 > : std::true_type {};
397 template <
typename C,
typename =
void>
struct HasEmplaceBackTest : std::false_type {};
398 template <
typename C>
struct HasEmplaceBackTest<C,
399 std::void_t<
decltype(std::declval<C>().emplace_back(std::declval<
typename C::value_type>()))>
406 template <
typename C,
typename =
void>
407 struct ElementTypeHelper
409 static constexpr bool isObject =
false;
410 static constexpr bool isPrimitive =
false;
412 template <
typename C>
413 struct ElementTypeHelper<C, std::void_t<
typename C::value_type>>
415 using E =
typename C::value_type;
416 static constexpr bool isObject = QtJniTypes::isObjectType<E>();
417 static constexpr bool isPrimitive = QtJniTypes::isPrimitiveType<E>();
420 template <
typename CRef,
typename C = q20::remove_cvref_t<CRef>>
421 static constexpr bool isContiguousContainer = IsContiguousContainerHelper<C>::value;
423 template <
typename From,
typename To>
424 using if_convertible = std::enable_if_t<QtPrivate::AreArgumentsConvertibleWithoutNarrowingBase<From, To>::value,
bool>;
425 template <
typename From,
typename To>
426 using unless_convertible = std::enable_if_t<!QtPrivate::AreArgumentsConvertibleWithoutNarrowingBase<From, To>::value,
bool>;
429 template <
typename E>
struct ToContainerHelper {
using type = QList<E>; };
430 template <>
struct ToContainerHelper<jstring> {
using type = QStringList; };
431 template <>
struct ToContainerHelper<jbyte> {
using type = QByteArray; };
432 template <>
struct ToContainerHelper<
char> {
using type = QByteArray; };
434 template <
typename E>
435 using ToContainerType =
typename ToContainerHelper<E>::type;
437 template <
typename E,
typename CRef,
typename C = q20::remove_cvref_t<CRef>>
438 static constexpr bool isCompatibleTargetContainer =
439 (QtPrivate::AreArgumentsConvertibleWithoutNarrowingBase<E,
typename C::value_type>::value
440 || QtPrivate::AreArgumentsConvertibleWithoutNarrowingBase<
typename ToContainerType<E>::value_type,
441 typename C::value_type>::value
442 || (std::is_base_of_v<QtJniTypes::JObjectBase, E> && std::is_same_v<
typename C::value_type, QString>))
443 && (qxp::is_detected_v<HasEmplaceBackTest, C>
444 || (isContiguousContainer<C> && ElementTypeHelper<C>::isPrimitive));
447 using size_type = jsize;
448 using difference_type = size_type;
450 operator QJniObject()
const {
return m_object; }
452 template <
typename T = jobject>
453 T object()
const {
return m_object.object<T>(); }
454 bool isValid()
const {
return m_object.isValid(); }
455 bool isEmpty()
const {
return size() == 0; }
457 size_type size()
const
459 if (jarray array = m_object.object<jarray>())
460 return jniEnv()->GetArrayLength(array);
469 template <
typename C>
470 using IsSequentialOrContiguous = std::bool_constant<
471 IsSequentialContainerHelper<C>::isForwardIterable
472 || (isContiguousContainer<C> && ElementTypeHelper<C>::isPrimitive)
474 template <
typename CRef,
typename C = q20::remove_cvref_t<CRef>>
475 static constexpr bool isCompatibleSourceContainer = std::conjunction_v<
476 std::negation<std::is_same<QString, C>>,
477 IsSequentialOrContiguous<C>,
478 std::negation<std::is_base_of<QJniArrayBase, C>>
481 template <
typename C>
482 using if_compatible_source_container = std::enable_if_t<isCompatibleSourceContainer<C>,
bool>;
483 template <
typename T,
typename C>
484 using if_compatible_target_container = std::enable_if_t<isCompatibleTargetContainer<T, C>,
bool>;
486 template <
typename Container, if_compatible_source_container<Container> =
true>
487 static auto fromContainer(Container &&container)
489 verifySize(std::size(container));
490 using ElementType =
typename std::remove_reference_t<Container>::value_type;
491 if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>,
492 std::remove_pointer_t<ElementType>>) {
493 return makeObjectArray(std::forward<Container>(container));
494 }
else if constexpr (std::disjunction_v<std::is_same<ElementType, QJniObject>,
495 std::is_same<ElementType, QString>,
496 std::is_base_of<QtJniTypes::JObjectBase, ElementType>
498 return QJniArray<ElementType>(makeObjectArray(std::forward<Container>(container)).arrayObject());
499 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jfloat>) {
500 return makeArray<jfloat>(std::forward<Container>(container), &JNIEnv::NewFloatArray,
501 &JNIEnv::SetFloatArrayRegion);
502 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jdouble>) {
503 return makeArray<jdouble>(std::forward<Container>(container), &JNIEnv::NewDoubleArray,
504 &JNIEnv::SetDoubleArrayRegion);
505 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jboolean>) {
506 return makeArray<jboolean>(std::forward<Container>(container), &JNIEnv::NewBooleanArray,
507 &JNIEnv::SetBooleanArrayRegion);
508 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jbyte>
509 || std::is_same_v<ElementType,
char>) {
510 return makeArray<jbyte>(std::forward<Container>(container), &JNIEnv::NewByteArray,
511 &JNIEnv::SetByteArrayRegion);
512 }
else if constexpr (std::disjunction_v<std::is_same<ElementType, jchar>,
513 std::is_same<ElementType, QChar>>) {
514 return makeArray<jchar>(std::forward<Container>(container), &JNIEnv::NewCharArray,
515 &JNIEnv::SetCharArrayRegion);
516 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jshort>) {
517 return makeArray<jshort>(std::forward<Container>(container), &JNIEnv::NewShortArray,
518 &JNIEnv::SetShortArrayRegion);
519 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jint>) {
520 return makeArray<jint>(std::forward<Container>(container), &JNIEnv::NewIntArray,
521 &JNIEnv::SetIntArrayRegion);
522 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jlong>) {
523 return makeArray<jlong>(std::forward<Container>(container), &JNIEnv::NewLongArray,
524 &JNIEnv::SetLongArrayRegion);
526 static_assert(QtPrivate::type_dependent_false<ElementType>(),
527 "Don't know how to make QJniArray for this element type");
532 QJniArrayBase() =
default;
533 ~QJniArrayBase() =
default;
535 explicit QJniArrayBase(
const QJniArrayBase &other) =
default;
536 explicit QJniArrayBase(QJniArrayBase &&other)
noexcept =
default;
537 QJniArrayBase &operator=(
const QJniArrayBase &other) =
default;
538 QJniArrayBase &operator=(QJniArrayBase &&other)
noexcept =
default;
540 explicit QJniArrayBase(jarray array)
541 : m_object(
static_cast<jobject>(array))
544 explicit QJniArrayBase(
const QJniObject &object)
547 explicit QJniArrayBase(QJniObject &&object)
noexcept
548 : m_object(std::move(object))
550 QJniArrayBase &operator=(
const QJniObject &object)
555 QJniArrayBase &operator=(QJniObject &&object)
noexcept
557 m_object = std::move(object);
561 JNIEnv *jniEnv()
const noexcept {
return QJniEnvironment::getJniEnv(); }
563 template <
typename ElementType,
typename List,
typename NewFn,
typename SetFn>
564 static auto makeArray(List &&list, NewFn &&newArray, SetFn &&setRegion);
565 template <
typename List>
566 static auto makeObjectArray(List &&list);
567 template <
typename ElementType>
568 static auto makeEmptyArray(size_type size)
570 auto env = QJniEnvironment();
571 if constexpr (std::disjunction_v<std::is_base_of<std::remove_pointer_t<jobject>,
572 std::remove_pointer_t<ElementType>>,
573 std::is_same<ElementType, QJniObject>,
574 std::is_same<ElementType, QString>,
575 std::is_base_of<QtJniTypes::JObjectBase, ElementType>
577 using ResultType =
decltype(QtJniTypes::Traits<ElementType>::convertToJni(
nullptr, {}));
578 const auto className = QtJniTypes::Traits<ResultType>::className();
579 jclass elementClass = env.findClass(className);
581 env.checkAndClearExceptions();
582 return jobjectArray(
nullptr);
584 return env->NewObjectArray(size, elementClass,
nullptr);
585 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jfloat>) {
586 return env->NewFloatArray(size);
587 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jdouble>) {
588 return env->NewDoubleArray(size);
589 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jboolean>) {
590 return env->NewBooleanArray(size);
591 }
else if constexpr (std::disjunction_v<std::is_same<ElementType, jbyte>,
592 std::is_same<ElementType,
char>>) {
593 return env->NewByteArray(size);
594 }
else if constexpr (std::disjunction_v<std::is_same<ElementType, jchar>,
595 std::is_same<ElementType, QChar>>) {
596 return env->NewCharArray(size);
597 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jshort>) {
598 return env->NewShortArray(size);
599 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jint>) {
600 return env->NewIntArray(size);
601 }
else if constexpr (QtJniTypes::sameTypeForJni<ElementType, jlong>) {
602 return env->NewLongArray(size);
604 static_assert(QtPrivate::type_dependent_false<ElementType>(),
605 "Don't know how to make QJniArray for this element type");
609 void swap(QJniArrayBase &other)
noexcept { m_object.swap(other.m_object); }
612 template <
typename container_size_type>
613 static void verifySize(container_size_type size)
615 if (!q20::in_range<size_type>(size))
616 qWarning(
"QJniArray::fromContainer: Container is too large for Java and will be truncated!");
623class QJniArray :
public QJniArrayBase
625 friend struct QJniArrayIterator<T>;
627 template <
typename C>
628 using CanReserveTest =
decltype(std::declval<C>().reserve(0));
629 template <
typename C>
630 static constexpr bool canReserve = qxp::is_detected_v<CanReserveTest, C>;
635 using value_type = T;
636 using iterator = QJniArrayMutableIterator<T>;
637 using reverse_iterator = std::reverse_iterator<iterator>;
638 using const_iterator = QJniArrayIterator<
const T>;
639 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
641 using reference =
typename iterator::reference;
642 using const_reference =
typename const_iterator::const_reference;
644 QJniArray() =
default;
645 explicit QJniArray(jarray array) : QJniArrayBase(array) {}
646 explicit QJniArray(
const QJniObject &object) : QJniArrayBase(object) {}
647 explicit QJniArray(QJniObject &&object)
noexcept : QJniArrayBase(std::move(object)) {}
649 template <
typename Other, if_convertible<Other, T> =
true>
650 QJniArray(
const QJniArray<Other> &other)
651 : QJniArrayBase(other)
654 template <
typename Other, if_convertible<Other, T> =
true>
655 QJniArray(QJniArray<Other> &&other)
noexcept
656 : QJniArrayBase(std::move(other))
659 template <
typename Other, if_convertible<Other, T> =
true>
660 QJniArray &operator=(
const QJniArray<Other> &other)
662 QJniArrayBase::operator=(QJniObject(other));
665 template <
typename Other, if_convertible<Other, T> =
true>
666 QJniArray &operator=(QJniArray<Other> &&other)
noexcept
668 QJniArray moved(std::move(other));
673 template <
typename Other, unless_convertible<Other, T> =
true>
674 QJniArray(
const QJniArray<Other> &other) =
delete;
675 template <
typename Other, unless_convertible<Other, T> =
true>
676 QJniArray(QJniArray<Other> &&other)
noexcept =
delete;
678 template <
typename Container, if_compatible_source_container<Container> =
true>
679 explicit QJniArray(Container &&container)
680 : QJniArrayBase(QJniArrayBase::fromContainer(std::forward<Container>(container)))
684 Q_IMPLICIT
inline QJniArray(std::initializer_list<T> list)
685 : QJniArrayBase(QJniArrayBase::fromContainer(list))
689 explicit QJniArray(size_type size)
690 : QJniArrayBase(makeEmptyArray<T>(size))
693 ~QJniArray() =
default;
695 auto arrayObject()
const
697 if constexpr (QtJniTypes::isObjectType<T>())
698 return object<jobjectArray>();
699 else if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>)
700 return object<jbyteArray>();
701 else if constexpr (QtJniTypes::sameTypeForJni<T, jchar>)
702 return object<jcharArray>();
703 else if constexpr (QtJniTypes::sameTypeForJni<T, jboolean>)
704 return object<jbooleanArray>();
705 else if constexpr (QtJniTypes::sameTypeForJni<T, jshort>)
706 return object<jshortArray>();
707 else if constexpr (QtJniTypes::sameTypeForJni<T, jint>)
708 return object<jintArray>();
709 else if constexpr (QtJniTypes::sameTypeForJni<T, jlong>)
710 return object<jlongArray>();
711 else if constexpr (QtJniTypes::sameTypeForJni<T, jfloat>)
712 return object<jfloatArray>();
713 else if constexpr (QtJniTypes::sameTypeForJni<T, jdouble>)
714 return object<jdoubleArray>();
716 return object<jarray>();
719 const_iterator begin()
const noexcept {
return {0,
this}; }
720 const_iterator constBegin()
const noexcept {
return begin(); }
721 const_iterator cbegin()
const noexcept {
return begin(); }
722 const_iterator end()
const noexcept {
return {size(),
this}; }
723 const_iterator constEnd()
const noexcept {
return {end()}; }
724 const_iterator cend()
const noexcept {
return {end()}; }
726 iterator begin()
noexcept {
return {0,
this}; }
727 iterator end()
noexcept {
return {size(),
this}; }
729 const_reverse_iterator rbegin()
const noexcept {
return const_reverse_iterator(end()); }
730 const_reverse_iterator rend()
const noexcept {
return const_reverse_iterator(begin()); }
731 const_reverse_iterator crbegin()
const noexcept {
return const_reverse_iterator(end()); }
732 const_reverse_iterator crend()
const noexcept {
return const_reverse_iterator(begin()); }
734 reverse_iterator rbegin()
noexcept {
return reverse_iterator(end()); }
735 reverse_iterator rend()
noexcept {
return reverse_iterator(begin()); }
737 const_reference operator[](size_type i)
const {
return at(i); }
738 reference operator[](size_type i) {
return reference{at(i), iterator{i,
this}}; }
739 const_reference at(size_type i)
const
741 JNIEnv *env = jniEnv();
742 if constexpr (QtJniTypes::isObjectType<T>()) {
743 jobject element = env->GetObjectArrayElement(object<jobjectArray>(), i);
744 if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>)
745 return static_cast<T>(element);
747 return QtJniTypes::Traits<T>::convertFromJni(QJniObject::fromLocalRef(element));
750 if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>)
751 env->GetByteArrayRegion(object<jbyteArray>(), i, 1, &res);
752 else if constexpr (QtJniTypes::sameTypeForJni<T, jchar>)
753 env->GetCharArrayRegion(object<jcharArray>(), i, 1, &res);
754 else if constexpr (QtJniTypes::sameTypeForJni<T, jboolean>)
755 env->GetBooleanArrayRegion(object<jbooleanArray>(), i, 1, &res);
756 else if constexpr (QtJniTypes::sameTypeForJni<T, jshort>)
757 env->GetShortArrayRegion(object<jshortArray>(), i, 1, &res);
758 else if constexpr (QtJniTypes::sameTypeForJni<T, jint>)
759 env->GetIntArrayRegion(object<jintArray>(), i, 1, &res);
760 else if constexpr (QtJniTypes::sameTypeForJni<T, jlong>)
761 env->GetLongArrayRegion(object<jlongArray>(), i, 1, &res);
762 else if constexpr (QtJniTypes::sameTypeForJni<T, jfloat>)
763 env->GetFloatArrayRegion(object<jfloatArray>(), i, 1, &res);
764 else if constexpr (QtJniTypes::sameTypeForJni<T, jdouble>)
765 env->GetDoubleArrayRegion(object<jdoubleArray>(), i, 1, &res);
770 void setValue(size_type i, const_reference &val)
772 JNIEnv *env = jniEnv();
774 if constexpr (QtJniTypes::isObjectType<T>()) {
775 QtJniTypes::Detail::LocalFrame<T> frame(env);
776 jobject element = frame.convertToJni(val);
777 env->SetObjectArrayElement(object<jobjectArray>(), i, element);
779 if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>)
780 env->SetByteArrayRegion(object<jbyteArray>(), i, 1, &val);
781 else if constexpr (QtJniTypes::sameTypeForJni<T, jchar>)
782 env->SetCharArrayRegion(object<jcharArray>(), i, 1, &val);
783 else if constexpr (QtJniTypes::sameTypeForJni<T, jboolean>)
784 env->SetBooleanArrayRegion(object<jbooleanArray>(), i, 1, &val);
785 else if constexpr (QtJniTypes::sameTypeForJni<T, jshort>)
786 env->SetShortArrayRegion(object<jshortArray>(), i, 1, &val);
787 else if constexpr (QtJniTypes::sameTypeForJni<T, jint>)
788 env->SetIntArrayRegion(object<jintArray>(), i, 1, &val);
789 else if constexpr (QtJniTypes::sameTypeForJni<T, jlong>)
790 env->SetLongArrayRegion(object<jlongArray>(), i, 1, &val);
791 else if constexpr (QtJniTypes::sameTypeForJni<T, jfloat>)
792 env->SetFloatArrayRegion(object<jfloatArray>(), i, 1, &val);
793 else if constexpr (QtJniTypes::sameTypeForJni<T, jdouble>)
794 env->SetDoubleArrayRegion(object<jdoubleArray>(), i, 1, &val);
798 template <
typename Container = ToContainerType<T>, if_compatible_target_container<T, Container> =
true>
799 Container toContainer(Container &&container = {})
const
801 const qsizetype sz = size();
803 return std::forward<Container>(container);
804 JNIEnv *env = jniEnv();
806 using ContainerType = q20::remove_cvref_t<Container>;
808 if constexpr (canReserve<ContainerType>)
809 container.reserve(sz);
810 if constexpr (std::is_same_v<
typename ContainerType::value_type, QString>) {
811 for (
auto element : *
this) {
812 if constexpr (std::is_same_v<
decltype(element), QString>) {
813 container.emplace_back(element);
814 }
else if constexpr (std::is_same_v<
decltype(element), jstring>) {
815 container.emplace_back(element ? QtJniTypes::Detail::toQString(element, env)
818 container.emplace_back(QJniObject(element).toString());
821 }
else if constexpr (std::is_base_of_v<std::remove_pointer_t<jobject>, std::remove_pointer_t<T>>) {
822 for (
auto element : *
this)
823 container.emplace_back(element);
824 }
else if constexpr (isContiguousContainer<ContainerType>) {
825 container.resize(sz);
826 if constexpr (QtJniTypes::sameTypeForJni<T, jbyte>) {
827 env->GetByteArrayRegion(object<jbyteArray>(),
829 reinterpret_cast<jbyte *>(container.data()));
830 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jchar>) {
831 env->GetCharArrayRegion(object<jcharArray>(),
832 0, sz, container.data());
833 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jboolean>) {
834 env->GetBooleanArrayRegion(object<jbooleanArray>(),
835 0, sz, container.data());
836 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jshort>) {
837 env->GetShortArrayRegion(object<jshortArray>(),
838 0, sz, container.data());
839 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jint>) {
840 env->GetIntArrayRegion(object<jintArray>(),
841 0, sz, container.data());
842 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jlong>) {
843 env->GetLongArrayRegion(object<jlongArray>(),
844 0, sz, container.data());
845 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jfloat>) {
846 env->GetFloatArrayRegion(object<jfloatArray>(),
847 0, sz, container.data());
848 }
else if constexpr (QtJniTypes::sameTypeForJni<T, jdouble>) {
849 env->GetDoubleArrayRegion(object<jdoubleArray>(),
850 0, sz, container.data());
852 static_assert(QtPrivate::type_dependent_false<T>(),
853 "Don't know how to copy data from a QJniArray of this type");
857 container.emplace_back(e);
859 return std::forward<Container>(container);
867template <
typename Container, QJniArrayBase::if_compatible_source_container<Container> =
true>
868QJniArray(Container) -> QJniArray<
typename decltype(QJniArrayBase::fromContainer(std::declval<Container>()))::value_type>;
870template <
typename ElementType,
typename List,
typename NewFn,
typename SetFn>
871auto QJniArrayBase::makeArray(List &&list, NewFn &&newArray, SetFn &&setRegion)
873 const size_type length = size_type(std::size(list));
874 JNIEnv *env = QJniEnvironment::getJniEnv();
875 auto localArray = (env->*newArray)(length);
876 if (env->ExceptionCheck()) {
878 env->DeleteLocalRef(localArray);
879 return QJniArray<ElementType>();
884 if constexpr (isContiguousContainer<List>) {
885 (env->*setRegion)(localArray, 0, length,
886 reinterpret_cast<
const ElementType *>(std::data(std::as_const(list))));
889 for (
const auto &e : std::as_const(list))
890 (env->*setRegion)(localArray, i++, 1,
reinterpret_cast<
const ElementType *>(&e));
893 return QJniArray<ElementType>(QJniObject::fromLocalRef(localArray));
896template <
typename List>
897auto QJniArrayBase::makeObjectArray(List &&list)
899 using ElementType =
typename q20::remove_cvref_t<List>::value_type;
900 using ResultType = QJniArray<
decltype(QtJniTypes::Traits<ElementType>::convertToJni(
nullptr,
903 if (std::size(list) == 0)
906 JNIEnv *env = QJniEnvironment::getJniEnv();
907 const size_type length = q26::saturate_cast<size_type>(std::size(list));
910 jclass elementClass =
nullptr;
911 if constexpr (std::disjunction_v<std::is_same<ElementType, QJniObject>,
912 std::is_base_of<QtJniTypes::JObjectBase, ElementType>>) {
913 elementClass = std::begin(list)->objectClass();
914 }
else if constexpr (std::is_same_v<ElementType, QString>) {
915 elementClass = QtAndroidPrivate::findClass(
"java/lang/String", env);
917 elementClass = env->GetObjectClass(*std::begin(list));
919 auto localArray = env->NewObjectArray(length, elementClass,
nullptr);
920 if (env->ExceptionCheck()) {
922 env->DeleteLocalRef(localArray);
927 constexpr jint frameCapacity = 100;
929 for (
const auto &element : std::as_const(list)) {
930 if (i % frameCapacity == 0) {
932 env->PopLocalFrame(
nullptr);
933 if (env->PushLocalFrame(frameCapacity) != 0)
936 jobject object = QtJniTypes::Traits<ElementType>::convertToJni(env, element);
937 env->SetObjectArrayElement(localArray, i, object);
941 env->PopLocalFrame(
nullptr);
942 return ResultType(QJniObject::fromLocalRef(localArray));
947template <
typename T>
struct Traits<QJniArray<T>>
949 template <IfValidFieldType<T> =
true>
950 static constexpr auto signature()
952 return CTString(
"[") + Traits<T>::signature();
954 static auto convertToJni(JNIEnv *,
const QJniArray<T> &value)
956 return value.arrayObject();
958 static auto convertFromJni(QJniObject &&object)
960 return QJniArray<T>(std::move(object));
964template <
typename T>
struct Traits<QJniArrayMutableValueRef<T>> :
public Traits<T> {};
966template<
typename T>
struct Traits<T, std::enable_if_t<QJniArrayBase::isCompatibleSourceContainer<T>>>
969 using ElementType = std::conditional_t<std::is_same_v<T, QByteArray>,
970 jbyte,
typename T::value_type>;
972 template <
typename U = ElementType, IfValidFieldType<U> =
true>
973 static constexpr auto signature()
975 return CTString(
"[") + Traits<ElementType>::signature();
978 static auto convertToJni(JNIEnv *env,
const T &value)
980 using QJniArrayType =
decltype(QJniArrayBase::fromContainer(value));
981 using ArrayType =
decltype(std::declval<QJniArrayType>().arrayObject());
982 return static_cast<ArrayType>(env->NewLocalRef(QJniArray(value).arrayObject()));
985 static auto convertFromJni(QJniObject &&object)
988 using QJniArrayType =
decltype(QJniArrayBase::fromContainer(std::declval<T>()));
990 using ArrayType =
typename QJniArrayType::Type;
992 return QJniArray<ArrayType>(object.
template object<jarray>()).toContainer();
996template<
typename T>
struct Traits<T, std::enable_if_t<std::is_array_v<T>>>
998 using ElementType = std::remove_extent_t<T>;
1000 template <
typename U = ElementType, IfValidFieldType<U> =
true>
1001 static constexpr auto signature()
1003 static_assert(!std::is_array_v<ElementType>,
1004 "Traits::signature() does not handle multi-dimensional arrays");
1005 return CTString(
"[") + Traits<U>::signature();
1008 static constexpr auto convertFromJni(QJniObject &&object)
1010 return QJniArray<ElementType>(std::move(object));