JNI: clean up SFINAE constraints in QJniArray

Rename the predictate for checking whether a container type has the
required member functions and types to IfContiguousContainer (we
need size(), data(), and value_type members).
And since std::initializer_list always meets that criteria, remove the
constraint from the respective constructor.

Add an IfConvertible predicate to test whether the element type of
an existing array can be converted to the element type of the new
array.

Change-Id: I7e5ba31de9664088b027c277c068c948f2189238
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
(cherry picked from commit 468126d34a8c3a2fdd486768f935d13ebe565dd0)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Volker Hilsheimer 2024-06-05 14:46:31 +02:00 committed by Qt Cherry-pick Bot
parent a2b442fef8
commit 4ef415825c
2 changed files with 20 additions and 23 deletions

View File

@ -89,13 +89,13 @@ private:
class QT_TECH_PREVIEW_API QJniArrayBase class QT_TECH_PREVIEW_API QJniArrayBase
{ {
// for SFINAE'ing out the fromContainer named constructor // for SFINAE'ing out the fromContainer named constructor
template <typename Container, typename = void> struct CanConvertHelper : std::false_type {}; template <typename C, typename = void> struct IsContiguousContainerHelper : std::false_type {};
template <typename Container> template <typename C>
struct CanConvertHelper<Container, std::void_t<decltype(std::data(std::declval<Container>())), struct IsContiguousContainerHelper<C, std::void_t<decltype(std::data(std::declval<C>())),
decltype(std::size(std::declval<Container>())), decltype(std::size(std::declval<C>())),
typename Container::value_type typename C::value_type
> >
> : std::true_type {}; > : std::true_type {};
public: public:
using size_type = jsize; using size_type = jsize;
@ -114,13 +114,12 @@ public:
return 0; return 0;
} }
template <typename Container> template <typename C>
static constexpr bool canConvert = CanConvertHelper<q20::remove_cvref_t<Container>>::value; static constexpr bool isContiguousContainer = IsContiguousContainerHelper<q20::remove_cvref_t<C>>::value;
template <typename Container> template <typename C>
using IfCanConvert = std::enable_if_t<canConvert<Container>, bool>; using if_contiguous_container = std::enable_if_t<isContiguousContainer<C>, bool>;
template <typename Container
, IfCanConvert<Container> = true template <typename Container, if_contiguous_container<Container> = true>
>
static auto fromContainer(Container &&container) static auto fromContainer(Container &&container)
{ {
Q_ASSERT_X(size_t(std::size(container)) <= size_t((std::numeric_limits<size_type>::max)()), Q_ASSERT_X(size_t(std::size(container)) <= size_t((std::numeric_limits<size_type>::max)()),
@ -218,23 +217,21 @@ public:
QJniArray &operator=(const QJniArray &other) = default; QJniArray &operator=(const QJniArray &other) = default;
QJniArray &operator=(QJniArray &&other) noexcept = default; QJniArray &operator=(QJniArray &&other) noexcept = default;
template <typename Container template <typename Container, if_contiguous_container<Container> = true>
, IfCanConvert<Container> = true
>
explicit QJniArray(Container &&container) explicit QJniArray(Container &&container)
: QJniArrayBase(QJniArrayBase::fromContainer(std::forward<Container>(container))) : QJniArrayBase(QJniArrayBase::fromContainer(std::forward<Container>(container)))
{ {
} }
template <typename E = T
, IfCanConvert<std::initializer_list<E>> = true
>
Q_IMPLICIT inline QJniArray(std::initializer_list<T> list) Q_IMPLICIT inline QJniArray(std::initializer_list<T> list)
: QJniArrayBase(QJniArrayBase::fromContainer(list)) : QJniArrayBase(QJniArrayBase::fromContainer(list))
{ {
} }
template <typename Other, std::enable_if_t<std::is_convertible_v<Other, Type>, bool> = true> template <typename Other>
using if_convertible = std::enable_if_t<std::is_convertible_v<Other, T>, bool>;
template <typename Other, if_convertible<Other> = true>
QJniArray(QJniArray<Other> &&other) QJniArray(QJniArray<Other> &&other)
: QJniArrayBase(std::forward<QJniArray<Other>>(other)) : QJniArrayBase(std::forward<QJniArray<Other>>(other))
{ {

View File

@ -822,7 +822,7 @@ auto QJniObject::LocalFrame<Args...>::convertToJni(T &&value)
return newLocalRef<jstring>(QJniObject::fromString(value)); return newLocalRef<jstring>(QJniObject::fromString(value));
} else if constexpr (QtJniTypes::IsJniArray<Type>::value) { } else if constexpr (QtJniTypes::IsJniArray<Type>::value) {
return value.arrayObject(); return value.arrayObject();
} else if constexpr (QJniArrayBase::canConvert<T>) { } else if constexpr (QJniArrayBase::isContiguousContainer<T>) {
using QJniArrayType = decltype(QJniArrayBase::fromContainer(std::forward<T>(value))); using QJniArrayType = decltype(QJniArrayBase::fromContainer(std::forward<T>(value)));
using ArrayType = decltype(std::declval<QJniArrayType>().arrayObject()); using ArrayType = decltype(std::declval<QJniArrayType>().arrayObject());
return newLocalRef<ArrayType>(QJniArrayBase::fromContainer(std::forward<T>(value)).template object<jobject>()); return newLocalRef<ArrayType>(QJniArrayBase::fromContainer(std::forward<T>(value)).template object<jobject>());
@ -843,7 +843,7 @@ auto QJniObject::LocalFrame<Args...>::convertFromJni(QJniObject &&object)
return object.toString(); return object.toString();
} else if constexpr (QtJniTypes::IsJniArray<Type>::value) { } else if constexpr (QtJniTypes::IsJniArray<Type>::value) {
return T(std::move(object)); return T(std::move(object));
} else if constexpr (QJniArrayBase::canConvert<Type>) { } else if constexpr (QJniArrayBase::isContiguousContainer<Type>) {
// if we were to create a QJniArray from Type... // if we were to create a QJniArray from Type...
using QJniArrayType = decltype(QJniArrayBase::fromContainer(std::declval<Type>())); using QJniArrayType = decltype(QJniArrayBase::fromContainer(std::declval<Type>()));
// then that QJniArray would have elements of type // then that QJniArray would have elements of type