summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/global
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@qt.io>2022-05-24 08:46:22 +0200
committerMarc Mutz <marc.mutz@qt.io>2022-06-02 12:54:55 +0200
commit29b65c98e720056e87334ce88a683969e57efd3d (patch)
tree104040975fcd1c9b220581fe1283e9d988e01f0f /tests/auto/corelib/global
parent4042596b72520878c6d418bac8f6fdd121c33520 (diff)
Short live qxp::function_ref!
This is an implementation of function_ref, which has been proposed for inclusion into C++23, but has not been accepted, yet, which is why we place it in namespace qxp (for eXPerimental) instead of q23. The implementation is based on wg21.link/P0792r9, which, at the time of writing, is the latest revision of the paper. It will be used in both QTestLib and qmldom. Fixes: QTBUG-103739 Change-Id: I52723eca28f7ac02ce7ce51928361d81ae5c92b1 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'tests/auto/corelib/global')
-rw-r--r--tests/auto/corelib/global/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/global/qxp/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/global/qxp/function_ref/CMakeLists.txt7
-rw-r--r--tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp234
4 files changed, 243 insertions, 0 deletions
diff --git a/tests/auto/corelib/global/CMakeLists.txt b/tests/auto/corelib/global/CMakeLists.txt
index fe63402288..e19eab18eb 100644
--- a/tests/auto/corelib/global/CMakeLists.txt
+++ b/tests/auto/corelib/global/CMakeLists.txt
@@ -21,3 +21,4 @@ add_subdirectory(qoperatingsystemversion)
if(WIN32)
add_subdirectory(qwinregistry)
endif()
+add_subdirectory(qxp)
diff --git a/tests/auto/corelib/global/qxp/CMakeLists.txt b/tests/auto/corelib/global/qxp/CMakeLists.txt
new file mode 100644
index 0000000000..f289a04701
--- /dev/null
+++ b/tests/auto/corelib/global/qxp/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(function_ref)
diff --git a/tests/auto/corelib/global/qxp/function_ref/CMakeLists.txt b/tests/auto/corelib/global/qxp/function_ref/CMakeLists.txt
new file mode 100644
index 0000000000..91c797c32f
--- /dev/null
+++ b/tests/auto/corelib/global/qxp/function_ref/CMakeLists.txt
@@ -0,0 +1,7 @@
+qt_internal_add_test(tst_qxp_function_ref
+ EXCEPTIONS
+ SOURCES
+ tst_qxp_function_ref.cpp
+ PUBLIC_LIBRARIES
+ Qt::Core
+)
diff --git a/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp b/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp
new file mode 100644
index 0000000000..b17ead436a
--- /dev/null
+++ b/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp
@@ -0,0 +1,234 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <QtCore/qxpfunctional.h>
+
+#include <QTest>
+
+#include <type_traits>
+
+// checking dependency q20::remove_cvref_t:
+#define CHECK(in, out) \
+ static_assert(std::is_same_v<q20::remove_cvref_t< in >, out >)
+CHECK(int, int);
+CHECK(const int, int);
+CHECK(int &, int);
+CHECK(const int &, int);
+CHECK(int &&, int);
+CHECK(const int &&, int);
+CHECK(int *, int *);
+CHECK(const int *, const int *);
+CHECK(int[4], int[4]);
+CHECK(const int (&)[4], int[4]);
+#undef CHECK
+
+template <typename T> constexpr inline bool
+is_noexcept_function_ref_helper_v = false;
+template <typename R, typename...Args> constexpr inline bool
+is_noexcept_function_ref_helper_v<qxp::function_ref<R(Args...) noexcept(true)>> = true;
+template <typename R, typename...Args> constexpr inline bool
+is_noexcept_function_ref_helper_v<qxp::function_ref<R(Args...) const noexcept(true)>> = true;
+
+template <typename T> constexpr inline bool
+is_noexcept_function_ref_v = is_noexcept_function_ref_helper_v<q20::remove_cvref_t<T>>;
+
+class tst_qxp_function_ref : public QObject
+{
+ Q_OBJECT
+public:
+ using QObject::QObject;
+
+private Q_SLOTS:
+ void basics();
+ void constOverloads();
+ void constExpr();
+ void ctad();
+};
+
+void tst_qxp_function_ref::basics()
+{
+ static_assert(std::is_trivially_copyable_v<qxp::function_ref<int(int)>>);
+ static_assert(std::is_trivially_copyable_v<qxp::function_ref<int()>>);
+ static_assert(std::is_trivially_copyable_v<qxp::function_ref<void()>>);
+
+ {
+ Q_CONSTINIT static int invoked = 0;
+ auto lambda = [](int i) noexcept { ++invoked; return i; };
+ const qxp::function_ref<int(int)> f = lambda;
+ QCOMPARE(invoked, 0);
+ QCOMPARE(f(42), 42);
+ QCOMPARE(invoked, 1);
+
+ const int fourtyTwo = 42;
+
+ const qxp::function_ref<int(int) noexcept> f2 = std::move(lambda);
+ QCOMPARE(invoked, 1);
+ QCOMPARE(f2(fourtyTwo), 42);
+ QCOMPARE(invoked, 2);
+
+ int (*fpr)(int) = lambda;
+
+ const qxp::function_ref f3 = fpr;
+ static_assert(!is_noexcept_function_ref_v<decltype(f3)>);
+ QCOMPARE(invoked, 2);
+ QCOMPARE(f3(42), 42);
+ QCOMPARE(invoked, 3);
+
+ int (*fpr2)(int) noexcept = lambda;
+
+ const qxp::function_ref f4 = fpr2;
+ static_assert(is_noexcept_function_ref_v<decltype(f4)>);
+ QCOMPARE(invoked, 3);
+ QCOMPARE(f4(42), 42);
+ QCOMPARE(invoked, 4);
+ }
+ {
+ Q_CONSTINIT static int invoked = 0;
+ auto lambda = [] { ++invoked; return 42; };
+ const qxp::function_ref<int()> f = lambda;
+ QCOMPARE(invoked, 0);
+ QCOMPARE(f(), 42);
+ QCOMPARE(invoked, 1);
+
+ const qxp::function_ref<int()> f2 = std::move(lambda);
+ QCOMPARE(invoked, 1);
+ QCOMPARE(f2(), 42);
+ QCOMPARE(invoked, 2);
+
+ int (*fpr)() = lambda;
+
+ const qxp::function_ref f3 = fpr;
+ static_assert(!is_noexcept_function_ref_v<decltype(f3)>);
+ QCOMPARE(invoked, 2);
+ QCOMPARE(f3(), 42);
+ QCOMPARE(invoked, 3);
+ }
+ {
+ Q_CONSTINIT static int invoked = 0;
+ auto lambda = [] { ++invoked; };
+ const qxp::function_ref<void()> f = lambda;
+ QCOMPARE(invoked, 0);
+ f();
+ QCOMPARE(invoked, 1);
+
+ const qxp::function_ref<void()> f2 = std::move(lambda);
+ QCOMPARE(invoked, 1);
+ f2();
+ QCOMPARE(invoked, 2);
+
+ void (*fpr)() = lambda;
+
+ const qxp::function_ref f3 = fpr;
+ QCOMPARE(invoked, 2);
+ f3();
+ QCOMPARE(invoked, 3);
+ }
+}
+
+void tst_qxp_function_ref::constOverloads()
+{
+ auto func_c = [](qxp::function_ref<int() const> callable)
+ {
+ return callable();
+ };
+ auto func_m = [](qxp::function_ref<int() /*mutable*/> callable)
+ {
+ return callable();
+ };
+
+ struct S
+ {
+ int operator()() { return 1; }
+ int operator()() const { return 2; }
+ };
+ S s;
+ QCOMPARE(func_c(s), 2);
+ QCOMPARE(func_m(s), 1);
+ const S cs;
+ QCOMPARE(func_c(cs), 2);
+#if 0
+ // this should not compile (and doesn't, but currently fails with an error in the impl,
+ // not by failing a constructor constaint → spec issue?).
+ QCOMPARE(func_m(cs), 2);
+#endif
+}
+
+void tst_qxp_function_ref::constExpr()
+{
+ Q_CONSTINIT static int invoked = 0;
+ {
+ Q_CONSTINIT static auto lambda = [] (int i) { ++invoked; return i; };
+ // the function object constructor is constexpr, so this should be constinit:
+ Q_CONSTINIT static qxp::function_ref<int(int)> f = lambda;
+
+ QCOMPARE(invoked, 0);
+ QCOMPARE(f(15), 15);
+ QCOMPARE(invoked, 1);
+ }
+ {
+ constexpr static auto lambda = [] (int i) { ++invoked; return i; };
+ // the function object constructor is constexpr, so this should be constinit:
+ Q_CONSTINIT static qxp::function_ref<int(int) const> f = lambda;
+
+ QCOMPARE(invoked, 1);
+ QCOMPARE(f(51), 51);
+ QCOMPARE(invoked, 2);
+
+#if 0 // ### should this work?:
+ Q_CONSTINIT static qxp::function_ref<int(int)> f2 = lambda;
+
+ QCOMPARE(invoked, 2);
+ QCOMPARE(f(150), 150);
+ QCOMPARE(invoked, 3);
+#endif
+
+ }
+}
+
+int i_f_i_nx(int i) noexcept { return i; }
+void v_f_i_nx(int) noexcept {}
+int i_f_v_nx() noexcept { return 42; }
+void v_f_v_nx() noexcept {}
+
+int i_f_i_ex(int i) { return i; }
+void v_f_i_ex(int) {}
+int i_f_v_ex() { return 42; }
+void v_f_v_ex() {}
+
+void tst_qxp_function_ref::ctad()
+{
+#define CHECK(fun, sig) \
+ do { \
+ qxp::function_ref f = fun; \
+ static_assert(std::is_same_v<decltype(f), \
+ qxp::function_ref<sig>>); \
+ qxp::function_ref f2 = &fun; \
+ static_assert(std::is_same_v<decltype(f2), \
+ qxp::function_ref<sig>>); \
+ } while (false)
+
+ CHECK(i_f_i_nx, int (int) noexcept);
+ CHECK(v_f_i_nx, void(int) noexcept);
+ CHECK(i_f_v_nx, int ( ) noexcept);
+ CHECK(v_f_v_nx, void( ) noexcept);
+
+ CHECK(i_f_i_ex, int (int));
+ CHECK(v_f_i_ex, void(int));
+ CHECK(i_f_v_ex, int ( ));
+ CHECK(v_f_v_ex, void( ));
+
+#undef CHECK
+
+#if 0 // no deduction guides for the non-function-pointer case, so no CTAD for lambdas
+ {
+ qxp::function_ref f = [](int i) -> int { return i; };
+ static_assert(std::is_same_v<decltype(f),
+ qxp::function_ref<int(int)>>);
+ }
+#endif
+}
+
+
+QTEST_APPLESS_MAIN(tst_qxp_function_ref);
+
+#include "tst_qxp_function_ref.moc"