1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QRUNNABLE_H
5#define QRUNNABLE_H
6
7#include <QtCore/qcompilerdetection.h>
8#include <QtCore/qfunctionaltools_impl.h>
9#include <QtCore/qtclasshelpermacros.h>
10#include <QtCore/qtcoreexports.h>
11
12#include <functional>
13#include <type_traits>
14
15QT_BEGIN_NAMESPACE
16
17class Q_CORE_EXPORT QRunnable
18{
19 bool m_autoDelete = true;
20
21 Q_DISABLE_COPY(QRunnable)
22public:
23 virtual void run() = 0;
24
25 constexpr QRunnable() noexcept = default;
26 virtual ~QRunnable();
27#if QT_CORE_REMOVED_SINCE(6, 6)
28 static QRunnable *create(std::function<void()> functionToRun);
29#endif
30 template <typename Callable>
31 using if_callable = std::enable_if_t<std::is_invocable_r_v<void, Callable>, bool>;
32
33 template <typename Callable, if_callable<Callable> = true>
34 static QRunnable *create(Callable &&functionToRun);
35 static QRunnable *create(std::nullptr_t) = delete;
36
37 bool autoDelete() const { return m_autoDelete; }
38 void setAutoDelete(bool autoDelete) { m_autoDelete = autoDelete; }
39
40private:
41 static Q_DECL_COLD_FUNCTION QRunnable *warnNullCallable();
42 class QGenericRunnable;
43};
44
45class Q_CORE_EXPORT QRunnable::QGenericRunnable : public QRunnable
46{
47 // Type erasure, to only instantiate a non-virtual class per Callable:
48 class HelperBase
49 {
50 protected:
51 enum class Op {
52 Run,
53 Destroy,
54 };
55 using OpFn = void* (*)(Op, HelperBase *, void*);
56 OpFn fn;
57 protected:
58 constexpr explicit HelperBase(OpFn f) noexcept : fn(f) {}
59 ~HelperBase() = default;
60 public:
61 void run() { fn(Op::Run, this, nullptr); }
62 void destroy() { fn(Op::Destroy, this, nullptr); }
63 };
64
65 template <typename Callable>
66 class Helper : public HelperBase, private QtPrivate::CompactStorage<Callable>
67 {
68 using Storage = QtPrivate::CompactStorage<Callable>;
69 static void *impl(Op op, HelperBase *that, [[maybe_unused]] void *arg)
70 {
71 const auto _this = static_cast<Helper*>(that);
72 switch (op) {
73 case Op::Run: _this->object()(); break;
74 case Op::Destroy: delete _this; break;
75 }
76 return nullptr;
77 }
78 public:
79 template <typename UniCallable>
80 explicit Helper(UniCallable &&functionToRun) noexcept
81 : HelperBase(&impl),
82 Storage{std::forward<UniCallable>(functionToRun)}
83 {
84 }
85 };
86
87 HelperBase *runHelper;
88public:
89 template <typename Callable, if_callable<Callable> = true>
90 explicit QGenericRunnable(Callable &&c)
91 : runHelper(new Helper<std::decay_t<Callable>>(std::forward<Callable>(c)))
92 {
93 }
94 ~QGenericRunnable() override;
95
96 void run() override;
97};
98
99namespace QtPrivate {
100
101template <typename T>
102constexpr inline bool is_function_pointer_v = std::conjunction_v<
103 std::is_pointer<T>,
104 std::is_function<std::remove_pointer_t<T>>
105 >;
106template <typename T>
107constexpr inline bool is_std_function_v = false;
108template <typename T>
109constexpr inline bool is_std_function_v<std::function<T>> = true;
110
111} // namespace QtPrivate
112
113template <typename Callable, QRunnable::if_callable<Callable>>
114QRunnable *QRunnable::create(Callable &&functionToRun)
115{
116 using F = std::decay_t<Callable>;
117 constexpr bool is_std_function = QtPrivate::is_std_function_v<F>;
118 constexpr bool is_function_pointer = QtPrivate::is_function_pointer_v<F>;
119 if constexpr (is_std_function || is_function_pointer) {
120 bool is_null;
121 if constexpr (is_std_function) {
122 is_null = !functionToRun;
123 } else if constexpr (is_function_pointer) {
124 // shut up warnings about functions always having a non-null address:
125 const void *functionPtr = reinterpret_cast<void *>(functionToRun);
126 is_null = !functionPtr;
127 }
128 if (is_null)
129 return warnNullCallable();
130 }
131
132 return new QGenericRunnable(std::forward<Callable>(functionToRun));
133}
134
135QT_END_NAMESPACE
136
137#endif
138

source code of qtbase/src/corelib/thread/qrunnable.h