KASync

future.h
1 /*
2  SPDX-FileCopyrightText: 2014 Daniel Vrátil <[email protected]>
3  SPDX-FileCopyrightText: 2016 Daniel Vrátil <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #ifndef FUTURE_H
9 #define FUTURE_H
10 
11 #include "kasync_export.h"
12 
13 class QEventLoop;
14 
15 #include <type_traits>
16 
17 #include <QSharedDataPointer>
18 #include <QPointer>
19 #include <QVector>
20 #include <QEventLoop>
21 
22 namespace KAsync {
23 
24 //@cond PRIVATE
25 
26 class FutureWatcherBase;
27 template<typename T>
28 class FutureWatcher;
29 
30 namespace Private {
31 struct Execution;
32 class ExecutorBase;
33 
34 typedef QSharedPointer<Execution> ExecutionPtr;
35 } // namespace Private
36 
37 struct KASYNC_EXPORT Error
38 {
39  Error() : errorCode(0) {};
40  explicit Error(const char *message) : errorCode(1), errorMessage(QString::fromLatin1(message)) {}
41  Error(int code, const char *message) : errorCode(code), errorMessage(QString::fromLatin1(message)) {}
42  Error(int code, const QString &message) : errorCode(code), errorMessage(message) {}
43 
44  bool operator ==(const Error &other) const {
45  return (errorCode == other.errorCode) && (errorMessage == other.errorMessage);
46  }
47 
48  bool operator !=(const Error &other) const {
49  return !(*this == other);
50  }
51 
52  operator bool() const {
53  return (errorCode != 0);
54  }
55 
56  int errorCode;
58 private:
59  //Disable all implicit conversions except to bool, to avoid accidentally implicitly casting an error to a continuation argument.
60  //This becomes an issue if you forget to specify all template arguments, as the template argument deduction may employ a nonsensical implicit conversion from i.e. error to int. So as long as the Error object is used in the Job::then overload resolution no implicit conversions here.
61  //Of course this "solution" still breaks if you forget the template argument with a boolean parameter....
62  template <typename T>
63  operator T() const;
64 };
65 
66 class KASYNC_EXPORT FutureBase
67 {
68  friend struct KAsync::Private::Execution;
69  friend class FutureWatcherBase;
70 
71 public:
72  virtual ~FutureBase();
73 
74 
75  void setFinished();
76  bool isFinished() const;
77 
78  void setError(int code = 1, const QString &message = QString());
79  void setError(const Error &error);
80  void addError(const Error &error);
81  void clearErrors();
82  bool hasError() const;
83  int errorCode() const;
84  QString errorMessage() const;
85  QVector<Error> errors() const;
86 
87  void setProgress(qreal progress);
88  void setProgress(int processed, int total);
89 
90 protected:
91  class KASYNC_EXPORT PrivateBase : public QSharedData
92  {
93  public:
94  explicit PrivateBase(const KAsync::Private::ExecutionPtr &execution);
95  virtual ~PrivateBase();
96 
97  void releaseExecution();
98 
99  bool finished;
100  QVector<Error> errors;
101 
103  private:
105  };
106 
107  explicit FutureBase();
108  explicit FutureBase(FutureBase::PrivateBase *dd);
109  FutureBase(const FutureBase &other);
110  FutureBase &operator=(const FutureBase &other) = default;
111 
112  void addWatcher(KAsync::FutureWatcherBase *watcher);
113  void releaseExecution();
114 
115 protected:
117 };
118 
119 template<typename T>
120 class FutureWatcher;
121 
122 template<typename T>
123 class Future;
124 
125 template<typename T>
126 class FutureGeneric : public FutureBase
127 {
128  friend class FutureWatcher<T>;
129 
130 public:
131 
132  void waitForFinished() const
133  {
134  if (isFinished()) {
135  return;
136  }
137  FutureWatcher<T> watcher;
138  QEventLoop eventLoop;
140  &eventLoop, &QEventLoop::quit);
141  watcher.setFuture(*static_cast<const KAsync::Future<T>*>(this));
142  eventLoop.exec();
143  }
144 
145 protected:
146  //@cond PRIVATE
147  explicit FutureGeneric(const KAsync::Private::ExecutionPtr &execution)
148  : FutureBase(new Private(execution))
149  {}
150 
151  FutureGeneric(const FutureGeneric &) = default;
152  FutureGeneric &operator=(const FutureGeneric &) = default;
153 
154 protected:
155  class Private : public FutureBase::PrivateBase
156  {
157  public:
158  explicit Private(const KAsync::Private::ExecutionPtr &execution)
159  : FutureBase::PrivateBase(execution)
160  {}
161 
162  std::conditional_t<std::is_void<T>::value, int /* dummy */, T> value;
163  };
164 };
165 //@endcond
166 
167 
168 
169 /**
170  * @ingroup Future
171  *
172  * @brief Future is a promise that is used by Job to deliver result
173  * of an asynchronous execution.
174  *
175  * The Future is passed internally to each executed task, and the task can use
176  * it to report its progress, result and notify when it is finished.
177  *
178  * Users use Future they receive from calling Job::exec() to get access
179  * to the overall result of the execution. FutureWatcher&lt;T&gt; can be used
180  * to wait for the Future to finish in non-blocking manner.
181  *
182  * @see Future<void>
183  */
184 template<typename T>
185 class Future : public FutureGeneric<T>
186 {
187  //@cond PRIVATE
188  friend class KAsync::Private::ExecutorBase;
189 
190  template<typename T_>
191  friend class KAsync::FutureWatcher;
192  //@endcond
193 public:
194  /**
195  * @brief Constructor
196  */
197  explicit Future()
198  : FutureGeneric<T>(KAsync::Private::ExecutionPtr())
199  {}
200 
201  /**
202  * @brief Copy constructor
203  */
204  Future(const Future<T> &other)
205  : FutureGeneric<T>(other)
206  {}
207 
208  /**
209  * Set the result of the Future. This method is called by the task upon
210  * calculating the result. After setting the value, the caller must also
211  * call setFinished() to notify users that the result
212  * is available.
213  *
214  * @warning This method must only be called by the tasks inside Job,
215  * never by outside users.
216  *
217  * @param value The result value
218  */
219  void setValue(const T &value)
220  {
221  dataImpl()->value = value;
222  }
223 
224  /**
225  * Retrieve the result of the Future. Calling this method when the future has
226  * not yet finished (i.e. isFinished() returns false)
227  * returns undefined result.
228  */
229  T value() const
230  {
231  return dataImpl()->value;
232  }
233 
234  T *operator->()
235  {
236  return &(dataImpl()->value);
237  }
238 
239  const T *operator->() const
240  {
241  return &(dataImpl()->value);
242  }
243 
244  T &operator*()
245  {
246  return dataImpl()->value;
247  }
248 
249  const T &operator*() const
250  {
251  return dataImpl()->value;
252  }
253 
254 #ifdef ONLY_DOXYGEN
255  /**
256  * Will block until the Future has finished.
257  *
258  * @note Internally this method is using a nested QEventLoop, which can
259  * in some situation cause problems and deadlocks. It is recommended to use
260  * FutureWatcher.
261  *
262  * @see isFinished()
263  */
264  void waitForFinished() const;
265 
266  /**
267  * Marks the future as finished. This will cause all FutureWatcher&lt;T&gt;
268  * objects watching this particular instance to emit FutureWatcher::futureReady()
269  * signal, and will cause all callers currently blocked in Future::waitForFinished()
270  * method of this particular instance to resume.
271  *
272  * @warning This method must only be called by the tasks inside Job,
273  * never by outside users.
274  *
275  * @see isFinished()
276  */
277  void setFinished();
278 
279  /**
280  * Query whether the Future has already finished.
281  *
282  * @see setFinished()
283  */
284  bool isFinished() const;
285 
286  /**
287  * Used by tasks to report an error that happened during execution. If an
288  * error handler was provided to the task, it will be executed with the
289  * given arguments. Otherwise the error will be propagated to next task
290  * that has an error handler, or all the way up to user.
291  *
292  * This method also internally calls setFinished()
293  *
294  * @warning This method must only be called by the tasks inside Job,
295  * never by outside users.
296  *
297  * @param code Optional error code
298  * @param message Optional error message
299  *
300  * @see errorCode(), errorMessage()
301  */
302  void setError(int code = 1, const QString &message = QString());
303 
304  /**
305  * Returns error code set via setError() or 0 if no
306  * error has occurred.
307  *
308  * @see setError(), errorMessage()
309  */
310  int errorCode() const;
311 
312  /**
313  * Returns error message set via setError() or empty
314  * string if no error occurred.
315  *
316  * @see setError(), errorCode()
317  */
318  QString errorMessage() const;
319 
320  /**
321  * Sets progress of the task. All FutureWatcher instances watching
322  * this particular future will then emit FutureWatcher::futureProgress()
323  * signal.
324  *
325  * @param processed Already processed amount
326  * @param total Total amount to process
327  */
328  void setProgress(int processed, int total);
329 
330  /**
331  * Sets progress of the task.
332  *
333  * @param progress Progress
334  */
335  void setProgress(qreal progress);
336 
337 #endif // ONLY_DOXYGEN
338  void setResult(const T &value)
339  {
340  dataImpl()->value = value;
341  FutureBase::setFinished();
342  }
343 
344 protected:
345  //@cond PRIVATE
346  Future(const KAsync::Private::ExecutionPtr &execution)
347  : FutureGeneric<T>(execution)
348  {}
349  //@endcond
350 
351 private:
352  inline auto dataImpl()
353  {
354  return static_cast<typename FutureGeneric<T>::Private*>(this->d.data());
355  }
356 
357  inline auto dataImpl() const
358  {
359  return static_cast<typename FutureGeneric<T>::Private*>(this->d.data());
360  }
361 };
362 
363 /**
364  * @ingroup Future
365  *
366  * @brief A specialization of Future&lt;T&gt; for tasks that have no (void)
367  * result.
368  *
369  * Unlike the generic Future&lt;T&gt; this specialization does not have
370  * setValue() and value() methods to set/retrieve result.
371  *
372  * @see Future
373  */
374 template<>
375 class Future<void> : public FutureGeneric<void>
376 {
377  friend class KAsync::Private::ExecutorBase;
378 
379 public:
380  /**
381  * @brief Constructor
382  */
384  : FutureGeneric<void>(KAsync::Private::ExecutionPtr())
385  {}
386 
387 protected:
388  //@cond PRIVATE
389  Future(const KAsync::Private::ExecutionPtr &execution)
390  : FutureGeneric<void>(execution)
391  {}
392  //@endcond
393 };
394 
395 
396 
397 
398 //@cond PRIVATE
399 class KASYNC_EXPORT FutureWatcherBase : public QObject
400 {
401  Q_OBJECT
402 
403  friend class FutureBase;
404 
405 Q_SIGNALS:
406  void futureReady();
407  void futureProgress(qreal progress);
408 
409 protected:
410  FutureWatcherBase(QObject *parent = nullptr);
411 
412  virtual ~FutureWatcherBase();
413 
414  void futureReadyCallback();
415  void futureProgressCallback(qreal progress);
416 
417  void setFutureImpl(const KAsync::FutureBase &future);
418 
419 protected:
420  class Private {
421  public:
422  KAsync::FutureBase future;
423  };
424 
425  Private * const d;
426 
427 private:
428  Q_DISABLE_COPY(FutureWatcherBase)
429 };
430 //@endcond
431 
432 
433 /**
434  * @ingroup Future
435  *
436  * @brief The FutureWatcher allows monitoring of Job results using
437  * signals and slots.
438  *
439  * FutureWatcher is returned by Job upon execution. User can then
440  * connect to its futureReady() and futureProgress() signals to be notified
441  * about progress of the asynchronous job. When futureReady() signal is emitted,
442  * the result of the job is available in Future::value().
443  */
444 template<typename T>
445 class FutureWatcher : public FutureWatcherBase
446 {
447  //@cond PRIVATE
448  friend class KAsync::FutureGeneric<T>;
449  //@endcond
450 
451 public:
452  /**
453  * Constructs a new FutureWatcher that can watch for status of Future&lt;T&gt;
454  */
455  FutureWatcher(QObject *parent = nullptr)
456  : FutureWatcherBase(parent)
457  {}
458 
459  ~FutureWatcher()
460  {}
461 
462  /**
463  * Set future to watch.
464  *
465  * @param future Future object to watch
466  */
467  void setFuture(const KAsync::Future<T> &future)
468  {
469  setFutureImpl(*static_cast<const KAsync::FutureBase*>(&future));
470  }
471 
472  /**
473  * Returns currently watched future.
474  */
476  {
477  return *static_cast<KAsync::Future<T>*>(&d->future);
478  }
479 
480 #ifdef ONLY_DOXYGEN
481 Q_SIGNALS:
482  /**
483  * The signal is emitted when the execution has finished and the result
484  * can be collected.
485  *
486  * @see Future::setFinished(), Future::setError()
487  */
488  void futureReady();
489 
490  /**
491  * The signal is emitted when progress of the execution changes. This has
492  * to be explicitly supported by the job being executed, otherwise the
493  * signal is not emitted.
494  *
495  * @see Future::setProgress()
496  */
497  void futureProgress(qreal progress);
498 #endif
499 
500 private:
501  Q_DISABLE_COPY(FutureWatcher<T>)
502 };
503 
504 } // namespace Async
505 
506 KASYNC_EXPORT QDebug& operator<<(QDebug &dbg, const KAsync::Error &error);
507 
508 #endif // FUTURE_H
void quit()
T value() const
Retrieve the result of the Future.
Definition: future.h:229
void setFuture(const KAsync::Future< T > &future)
Set future to watch.
Definition: future.h:467
FutureWatcher(QObject *parent=nullptr)
Constructs a new FutureWatcher that can watch for status of Future<T>.
Definition: future.h:455
void setValue(const T &value)
Set the result of the Future.
Definition: future.h:219
Future(const Future< T > &other)
Copy constructor.
Definition: future.h:204
int exec(QEventLoop::ProcessEventsFlags flags)
KCALUTILS_EXPORT QString errorMessage(const KCalendarCore::Exception &exception)
QDataStream & operator<<(QDataStream &out, const KDateTime::Spec &spec)
Future is a promise that is used by Job to deliver result of an asynchronous execution.
Definition: future.h:185
Future()
Constructor.
Definition: future.h:197
Definition: async.h:59
bool hasError()
KAsync::Future< T > future() const
Returns currently watched future.
Definition: future.h:475
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
The FutureWatcher allows monitoring of Job results using signals and slots.
Definition: future.h:445
Future()
Constructor.
Definition: future.h:383
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Apr 11 2021 23:07:13 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.