Commit 60fcb55c authored by Volker Krause's avatar Volker Krause
Browse files

Factor out return value wrapper and reuse that for array iterators

parent ee63aab8
Pipeline #182361 passed with stage
in 1 minute and 43 seconds
......@@ -5,6 +5,7 @@
*/
#include <KAndroidExtras/JniArray>
#include <KAndroidExtras/JniProperty>
#include <KAndroidExtras/JniTypeTraits>
#include <KAndroidExtras/JavaTypes>
#include <KAndroidExtras/Uri>
......@@ -13,6 +14,16 @@
using namespace KAndroidExtras;
class TestClass
{
JNI_OBJECT(TestClass, android::content::Context)
public:
TestClass(const QAndroidJniObject &o) : m_handle(o) {}
JNI_PROPERTY(bool, myBoolProp)
private:
inline QAndroidJniObject handle() const { return m_handle; }
QAndroidJniObject m_handle;
};
class JniArrayTest : public QObject
{
Q_OBJECT
......@@ -63,7 +74,7 @@ private Q_SLOTS:
QVERIFY(i >= 0 && i < 3);
}
// complex types
// complex types without wrappers
const auto a2 = Jni::Array<java::lang::String>(array);
JNIEnv::m_arrayLength = 2;
QCOMPARE(a2.size(), 2);
......@@ -73,7 +84,21 @@ private Q_SLOTS:
for (const auto &i : a2) {
QVERIFY(i.isValid());
}
for (const QString &i : a2) {
QVERIFY(!i.isEmpty());
}
// complex type with custom wrapper
static_assert(Jni::is_object_wrapper<TestClass>::value);
JNIEnv::m_arrayLength = 1;
const auto a3 = Jni::Array<TestClass>(array);
QCOMPARE(a3.size(), 1);
QCOMPARE(std::distance(a3.begin(), a3.end()), 1);
const auto v = a3[0];
bool b = a3[0].myBoolProp;
for (const TestClass &i : a3) {
bool b = i.myBoolProp; // verifies this is of the correct type
}
#endif
}
};
......
......@@ -63,6 +63,7 @@ ecm_generate_headers(KAndroidExtras_jni_FORWARDING_HEADERS
JniArray
JniObject
JniMethod
JniReturnValue
JniProperty
JniSignature
JniTypes
......
......@@ -10,6 +10,7 @@
#include "jnimethod.h"
#include "jniobject.h"
#include "jniproperty.h"
#include "jnireturnvalue.h"
#include "jnisignature.h"
#include "jnitypes.h"
#include "jnitypetraits.h"
......@@ -7,6 +7,7 @@
#ifndef KANDROIDEXTRAS_JNIARRAY_H
#define KANDROIDEXTRAS_JNIARRAY_H
#include "jnireturnvalue.h"
#include "jnitypetraits.h"
#include <QAndroidJniEnvironment>
......@@ -194,10 +195,10 @@ public:
ArrayImpl(const ArrayImpl&) = default;
ArrayImpl(ArrayImpl&&) = default;
QAndroidJniObject operator[](jsize index) const
auto operator[](jsize index) const
{
QAndroidJniEnvironment env;
return QAndroidJniObject::fromLocalRef(env->GetObjectArrayElement(this->handle(), index));
return Internal::return_wrapper<T>::toReturnValue(QAndroidJniObject::fromLocalRef(env->GetObjectArrayElement(this->handle(), index)));
}
class const_iterator
......@@ -221,8 +222,7 @@ public:
bool operator==(const_iterator other) const { return i == other.i; }
bool operator!=(const_iterator other) const { return i != other.i; }
// TODO return type should be the same as for the method wrapper
QAndroidJniObject operator*() const {
auto operator*() const {
return c[i];
}
};
......
......@@ -8,6 +8,7 @@
#include "jniarray.h"
#include "jniobject.h"
#include "jnireturnvalue.h"
#include "jnitypetraits.h"
#include <QAndroidJniObject>
......@@ -79,33 +80,6 @@ namespace Internal {
template <typename T> inline constexpr T toFinalCallArgument(T value) { return value; }
inline jobject toFinalCallArgument(const QAndroidJniObject &value) { return value.object(); }
// return type conversion
template <typename RetT>
struct call_return {
static inline constexpr bool is_basic = Jni::is_basic_type<RetT>::value;
static inline constexpr bool is_convertible = !std::is_same_v<typename Jni::converter<RetT>::type, void>;
typedef std::conditional_t<is_basic, RetT, QAndroidJniObject> JniReturnT;
static inline constexpr auto toReturnValue(JniReturnT value)
{
if constexpr (is_convertible) {
return Jni::Object<RetT>(value);
} else {
return value;
}
}
};
template <typename RetT>
struct call_return<Jni::Array<RetT>> {
static inline auto toReturnValue(const QAndroidJniObject &value)
{
return Jni::Array<RetT>(value);
}
};
template <>
struct call_return<void> {};
// call wrapper
template <typename RetT, typename ...Sig>
struct invoker {
......@@ -123,7 +97,7 @@ namespace Internal {
if constexpr (Jni::is_basic_type<RetT>::value) {
return handle.callMethod<RetT>(name, signature, toFinalCallArgument(std::get<Index>(params))...);
} else {
return Internal::call_return<RetT>::toReturnValue(handle.callObjectMethod(name, signature, toFinalCallArgument(std::get<Index>(params))...));
return Internal::return_wrapper<RetT>::toReturnValue(handle.callObjectMethod(name, signature, toFinalCallArgument(std::get<Index>(params))...));
}
}
};
......@@ -135,7 +109,7 @@ namespace Internal {
if constexpr (Jni::is_basic_type<RetT>::value) {
return handle.callMethod<RetT>(name, signature);
} else {
return Internal::call_return<RetT>::toReturnValue(handle.callObjectMethod(name, signature));
return Internal::return_wrapper<RetT>::toReturnValue(handle.callObjectMethod(name, signature));
}
}
};
......@@ -157,7 +131,7 @@ namespace Internal {
if constexpr (Jni::is_basic_type<RetT>::value) {
return QAndroidJniObject::callStaticMethod<RetT>(className, name, signature, toFinalCallArgument(std::get<Index>(params))...);
} else {
return Internal::call_return<RetT>::toReturnValue(QAndroidJniObject::callStaticObjectMethod(className, name, signature, toFinalCallArgument(std::get<Index>(params))...));
return Internal::return_wrapper<RetT>::toReturnValue(QAndroidJniObject::callStaticObjectMethod(className, name, signature, toFinalCallArgument(std::get<Index>(params))...));
}
}
};
......@@ -169,7 +143,7 @@ namespace Internal {
if constexpr (Jni::is_basic_type<RetT>::value) {
return QAndroidJniObject::callStaticMethod<RetT>(className, name, signature);
} else {
return Internal::call_return<RetT>::toReturnValue(QAndroidJniObject::callStaticObjectMethod(className, name, signature));
return Internal::return_wrapper<RetT>::toReturnValue(QAndroidJniObject::callStaticObjectMethod(className, name, signature));
}
}
};
......
/*
SPDX-FileCopyrightText: 2021-2022 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef KANDROIDEXTRAS_JNIRETURNVALUE_H
#define KANDROIDEXTRAS_JNIRETURNVALUE_H
#include "jniobject.h"
#include "jnitypetraits.h"
#include <QAndroidJniObject>
namespace KAndroidExtras {
namespace Jni {
template <typename T> class Array;
}
///@cond internal
namespace Internal {
/** Return value wrapping helper. */
template <typename RetT, typename = std::void_t<>>
class return_wrapper {
static inline constexpr bool is_basic = Jni::is_basic_type<RetT>::value;
static inline constexpr bool is_convertible = !std::is_same_v<typename Jni::converter<RetT>::type, void>;
typedef std::conditional_t<is_basic, RetT, QAndroidJniObject> JniReturnT;
public:
static inline constexpr auto toReturnValue(JniReturnT value)
{
if constexpr (is_convertible) {
return Jni::Object<RetT>(value);
} else {
return value;
}
}
};
template <typename RetT>
class return_wrapper<RetT, std::void_t<typename RetT::_jni_ThisType>> {
public:
static inline auto toReturnValue(const QAndroidJniObject &value)
{
return RetT(value);
}
};
template <typename RetT>
class return_wrapper<Jni::Array<RetT>> {
public:
static inline auto toReturnValue(const QAndroidJniObject &value)
{
return Jni::Array<RetT>(value);
}
};
template <>
struct return_wrapper<void> {};
}
///@endcond
}
#endif
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment