1 /****************************************************************************
2 **
3 ** DQt - D bindings for the Qt Toolkit
4 **
5 ** GNU Lesser General Public License Usage
6 ** This file may be used under the terms of the GNU Lesser
7 ** General Public License version 3 as published by the Free Software
8 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
9 ** packaging of this file. Please review the following information to
10 ** ensure the GNU Lesser General Public License version 3 requirements
11 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
12 **
13 ****************************************************************************/
14 module qt.core.thread;
15 extern(C++):
16 
17 import core.stdc.config;
18 import qt.config;
19 import qt.core.coreapplication;
20 import qt.core.coreevent;
21 import qt.core.deadlinetimer;
22 import qt.core.namespace;
23 import qt.core.object;
24 import qt.helpers;
25 
26 // For QThread::create. The configure-time test just checks for the availability
27 // of std::future and std::async; for the C++17 codepath we perform some extra
28 // checks here (for std::invoke and C++14 lambdas).
29 /+ #if QT_CONFIG(cxx11_future)
30 #  if defined(__cpp_lib_invoke) && __cpp_lib_invoke >= 201411 \
31       && defined(__cpp_init_captures) && __cpp_init_captures >= 201304 \
32       && defined(__cpp_generic_lambdas) &&  __cpp_generic_lambdas >= 201304
33 #    define QTHREAD_HAS_VARIADIC_CREATE
34 #  endif
35 #endif +/
36 
37 
38 
39 extern(C++, class) struct QThreadData;
40 extern(C++, class) struct QThreadPrivate;
41 /+ class QAbstractEventDispatcher; +/
42 
43 class /+ Q_CORE_EXPORT +/ QThread : QObject
44 {
45     mixin(Q_OBJECT);
46 public:
47     static /+ Qt:: +/qt.core.namespace.HANDLE currentThreadId()/+ noexcept /+ Q_DECL_PURE_FUNCTION +/__attribute__((pure))+/;
48     static QThread currentThread();
49     static int idealThreadCount()/+ noexcept+/;
50     static void yieldCurrentThread();
51 
52     /+ explicit +/this(QObject parent = null);
53     ~this();
54 
55     enum Priority {
56         IdlePriority,
57 
58         LowestPriority,
59         LowPriority,
60         NormalPriority,
61         HighPriority,
62         HighestPriority,
63 
64         TimeCriticalPriority,
65 
66         InheritPriority
67     }
68 
69     final void setPriority(Priority priority);
70     final Priority priority() const;
71 
72     final bool isFinished() const;
73     final bool isRunning() const;
74 
75     final void requestInterruption();
76     final bool isInterruptionRequested() const;
77 
78     final void setStackSize(uint stackSize);
79     final uint stackSize() const;
80 
81     final void exit(int retcode = 0);
82 
83     final QAbstractEventDispatcher* eventDispatcher() const;
84     final void setEventDispatcher(QAbstractEventDispatcher* eventDispatcher);
85 
86     override bool event(QEvent event);
87     final int loopLevel() const;
88 
89 /+ #ifdef Q_CLANG_QDOC
90     template <typename Function, typename... Args>
91     static QThread *create(Function &&f, Args &&... args);
92     template <typename Function>
93     static QThread *create(Function &&f);
94 #else
95 #  if QT_CONFIG(cxx11_future)
96 #    ifdef QTHREAD_HAS_VARIADIC_CREATE +/
97     static if(defined!"QTHREAD_HAS_VARIADIC_CREATE")
98     {
99         /+ template <typename Function, typename... Args> +/
100         /+ static QThread *create(Function &&f, Args &&... args); +/
101     }
102     else
103     {
104     /+ #    else +/
105         /+ template <typename Function> +/
106         /+ static QThread *create(Function &&f); +/
107     }
108 /+ #    endif // QTHREAD_HAS_VARIADIC_CREATE
109 #  endif // QT_CONFIG(cxx11_future)
110 #endif +/ // Q_CLANG_QDOC
111 
112 public /+ Q_SLOTS +/:
113     @QSlot final void start(Priority = Priority.InheritPriority);
114     @QSlot final void terminate();
115     @QSlot final void quit();
116 
117 public:
118     final bool wait(QDeadlineTimer deadline = QDeadlineTimer(QDeadlineTimer.ForeverConstant.Forever));
119     // ### Qt6 inline this function
120     final bool wait(cpp_ulong  time);
121 
122     static void sleep(cpp_ulong );
123     static void msleep(cpp_ulong );
124     static void usleep(cpp_ulong );
125 
126 /+ Q_SIGNALS +/public:
127     @QSignal final void started(QPrivateSignal);
128     @QSignal final void finished(QPrivateSignal);
129 
130 protected:
131     /+ virtual +/ void run();
132     final int exec();
133 
134     static void setTerminationEnabled(bool enabled = true);
135 
136 protected:
137     this(ref QThreadPrivate dd, QObject parent = null);
138 
139 private:
140     /+ Q_DECLARE_PRIVATE(QThread) +/
141 
142 /+ #if QT_CONFIG(cxx11_future) +/
143     /+ static QThread *createThreadImpl(std::future<void> &&future); +/
144 /+ #endif +/
145 
146     /+ friend class QCoreApplication; +/
147     /+ friend class QThreadData; +/
148 }
149 
150 /+ #if QT_CONFIG(cxx11_future) +/
151 
152 /+ #if defined(QTHREAD_HAS_VARIADIC_CREATE) || defined(Q_CLANG_QDOC)
153 // C++17: std::thread's constructor complying call
154 template <typename Function, typename... Args>
155 QThread *QThread::create(Function &&f, Args &&... args)
156 {
157     using DecayedFunction = typename std::decay<Function>::type;
158     auto threadFunction =
159         [f = static_cast<DecayedFunction>(std::forward<Function>(f))](auto &&... largs) mutable -> void
160         {
161             (void)std::invoke(std::move(f), std::forward<decltype(largs)>(largs)...);
162         };
163 
164     return createThreadImpl(std::async(std::launch::deferred,
165                                        std::move(threadFunction),
166                                        std::forward<Args>(args)...));
167 }
168 #elif defined(__cpp_init_captures) && __cpp_init_captures >= 201304
169 // C++14: implementation for just one callable
170 template <typename Function>
171 QThread *QThread::create(Function &&f)
172 {
173     using DecayedFunction = typename std::decay<Function>::type;
174     auto threadFunction =
175         [f = static_cast<DecayedFunction>(std::forward<Function>(f))]() mutable -> void
176         {
177             (void)f();
178         };
179 
180     return createThreadImpl(std::async(std::launch::deferred, std::move(threadFunction)));
181 }
182 #else +/
183 static if(!defined!"QTHREAD_HAS_VARIADIC_CREATE")
184 {
185 // C++11: same as C++14, but with a workaround for not having generalized lambda captures
186 }
187 extern(C++, "QtPrivate") {
188 struct Callable(Function)
189 {
190     /+ explicit Callable(Function &&f)
191         : m_function(std::forward<Function>(f))
192     {
193     } +/
194 
195     // Apply the same semantics of a lambda closure type w.r.t. the special
196     // member functions, if possible: delete the copy assignment operator,
197     // bring back all the others as per the RO5 (cf. §8.1.5.1/11 [expr.prim.lambda.closure])
198     /+ ~Callable() = default; +/
199     /+ Callable(const Callable &) = default; +/
200     /+ Callable(Callable &&) = default; +/
201     /+ref Callable operator =(ref const(Callable) ) /+ = delete +/;+/
202     /+ Callable &operator=(Callable &&) = default; +/
203 
204     /+void operator ()()
205     {
206         cast(void)m_function();
207     }+/
208 
209     /+ typename std::decay<Function>::type +/decay.type m_function;
210 }
211 }
212 static if(!defined!"QTHREAD_HAS_VARIADIC_CREATE")
213 {
214  // namespace QtPrivate
215 
216 /+ template <typename Function>
217 QThread *QThread::create(Function &&f)
218 {
219     return createThreadImpl(std::async(std::launch::deferred, QtPrivate::Callable<Function>(std::forward<Function>(f))));
220 } +/
221 }
222 /+ #endif +/ // QTHREAD_HAS_VARIADIC_CREATE
223 
224 /+ #endif +/ // QT_CONFIG(cxx11_future)
225