diff --git a/src/corelib/kernel/qjniarray.h b/src/corelib/kernel/qjniarray.h index f63433253da..7dbd3d475d2 100644 --- a/src/corelib/kernel/qjniarray.h +++ b/src/corelib/kernel/qjniarray.h @@ -181,6 +181,13 @@ class QJniArrayBase > > : std::true_type {}; + template struct HasEmplaceBackTest : std::false_type {}; + template struct HasEmplaceBackTest().emplace_back(std::declval()))> + > : std::true_type + {}; + + protected: // these are used in QJniArray template @@ -205,6 +212,24 @@ protected: template using unless_convertible = std::enable_if_t::value, bool>; + // helpers for toContainer + template struct ToContainerHelper { using type = QList; }; + template <> struct ToContainerHelper { using type = QStringList; }; + template <> struct ToContainerHelper { using type = QByteArray; }; + template <> struct ToContainerHelper { using type = QByteArray; }; + + template + using ToContainerType = typename ToContainerHelper::type; + + template > + static constexpr bool isCompatibleTargetContainer = + (QtPrivate::AreArgumentsConvertibleWithoutNarrowingBase::value + || QtPrivate::AreArgumentsConvertibleWithoutNarrowingBase::value_type, + typename C::value_type>::value + || (std::is_base_of_v && std::is_same_v)) + && (qxp::is_detected_v + || (isContiguousContainer && ElementTypeHelper::isPrimitive)); + public: using size_type = jsize; using difference_type = size_type; @@ -236,6 +261,8 @@ public: template using if_compatible_source_container = std::enable_if_t, bool>; + template + using if_compatible_target_container = std::enable_if_t, bool>; template = true> static auto fromContainer(Container &&container) @@ -332,13 +359,10 @@ class QJniArray : public QJniArrayBase { friend struct QJniArrayIterator; - template struct ToContainerHelper { using type = QList; }; - template <> struct ToContainerHelper { using type = QStringList; }; - template <> struct ToContainerHelper { using type = QByteArray; }; - template <> struct ToContainerHelper { using type = QByteArray; }; - - template - using ToContainerType = typename ToContainerHelper::type; + template + using CanReserveTest = decltype(std::declval().reserve(0)); + template + static constexpr bool canReserve = qxp::is_detected_v; public: using Type = T; @@ -480,7 +504,7 @@ public: } } - template > + template , if_compatible_target_container = true> Container toContainer(Container &&container = {}) const { const qsizetype sz = size(); @@ -490,7 +514,8 @@ public: using ContainerType = q20::remove_cvref_t; - container.reserve(sz); + if constexpr (canReserve) + container.reserve(sz); if constexpr (std::is_same_v) { for (auto element : *this) { if constexpr (std::is_same_v) diff --git a/src/corelib/kernel/qjniarray.qdoc b/src/corelib/kernel/qjniarray.qdoc index 727f60e6497..633586a1db1 100644 --- a/src/corelib/kernel/qjniarray.qdoc +++ b/src/corelib/kernel/qjniarray.qdoc @@ -410,7 +410,7 @@ */ /*! - \fn template template Container QJniArray::toContainer(Container &&container) const + \fn template template > Container QJniArray::toContainer(Container &&container) const \return a container populated with the data in the wrapped Java array. diff --git a/tests/auto/corelib/kernel/qjniarray/tst_qjniarray.cpp b/tests/auto/corelib/kernel/qjniarray/tst_qjniarray.cpp index 61637abf972..ead87713371 100644 --- a/tests/auto/corelib/kernel/qjniarray/tst_qjniarray.cpp +++ b/tests/auto/corelib/kernel/qjniarray/tst_qjniarray.cpp @@ -367,6 +367,29 @@ void tst_QJniArray::ordering() QCOMPARE_GT(arrayEnd, arrayBegin); } +template +using ToContainerTest = decltype(std::declval>().toContainer(std::declval())); + +template +static constexpr bool hasToContainer = qxp::is_detected_v; + +static_assert(hasToContainer>); +static_assert(hasToContainer>); + +static_assert(hasToContainer); +static_assert(hasToContainer); +static_assert(hasToContainer); +static_assert(hasToContainer>); +static_assert(hasToContainer>); +// different types but doesn't narrow +static_assert(hasToContainer>); +static_assert(hasToContainer>); +// would narrow +static_assert(!hasToContainer>); +static_assert(!hasToContainer>); +// incompatible types +static_assert(!hasToContainer); + void tst_QJniArray::toContainer() { std::vector charVector{u'a', u'b', u'c'}; @@ -377,6 +400,10 @@ void tst_QJniArray::toContainer() QCOMPARE(vector, charVector); QCOMPARE(charArray.toContainer>(), charVector); + + // non-contiguous container of primitive elements + std::list charList = charArray.toContainer>(); + QCOMPARE(charList.size(), charVector.size()); } void tst_QJniArray::pointerToValue()