File indexing completed on 2024-12-08 12:44:38

0001 /*
0002     SPDX-FileCopyrightText: 2014 Daniel Vrátil <dvratil@redhat.com>
0003     SPDX-FileCopyrightText: 2016 Daniel Vrátil <dvratil@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #ifndef FUTURE_H
0009 #define FUTURE_H
0010 
0011 #include "kasync_export.h"
0012 
0013 class QEventLoop;
0014 
0015 #include <type_traits>
0016 
0017 #include <QSharedDataPointer>
0018 #include <QPointer>
0019 #include <QVector>
0020 #include <QEventLoop>
0021 
0022 namespace KAsync {
0023 
0024 //@cond PRIVATE
0025 
0026 class FutureWatcherBase;
0027 template<typename T>
0028 class FutureWatcher;
0029 
0030 namespace Private {
0031 struct Execution;
0032 class ExecutorBase;
0033 
0034 typedef QSharedPointer<Execution> ExecutionPtr;
0035 } // namespace Private
0036 
0037 struct KASYNC_EXPORT Error
0038 {
0039     Error() : errorCode(0) {};
0040     explicit Error(const char *message) : errorCode(1), errorMessage(QString::fromLatin1(message)) {}
0041     Error(int code, const char *message) : errorCode(code), errorMessage(QString::fromLatin1(message)) {}
0042     Error(int code, const QString &message) : errorCode(code), errorMessage(message) {}
0043 
0044     bool operator ==(const Error &other) const {
0045         return (errorCode == other.errorCode) && (errorMessage == other.errorMessage);
0046     }
0047 
0048     bool operator !=(const Error &other) const {
0049         return !(*this == other);
0050     }
0051 
0052     operator bool() const {
0053         return (errorCode != 0);
0054     }
0055 
0056     int errorCode;
0057     QString errorMessage;
0058 private:
0059     //Disable all implicit conversions except to bool, to avoid accidentally implicitly casting an error to a continuation argument.
0060     //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.
0061     //Of course this "solution" still breaks if you forget the template argument  with a boolean parameter....
0062     template <typename T>
0063     operator T() const;
0064 };
0065 
0066 class KASYNC_EXPORT FutureBase
0067 {
0068     friend struct KAsync::Private::Execution;
0069     friend class FutureWatcherBase;
0070 
0071 public:
0072     virtual ~FutureBase();
0073 
0074 
0075     void setFinished();
0076     bool isFinished() const;
0077 
0078     void setError(int code = 1, const QString &message = QString());
0079     void setError(const Error &error);
0080     void addError(const Error &error);
0081     void clearErrors();
0082     bool hasError() const;
0083     int errorCode() const;
0084     QString errorMessage() const;
0085     QVector<Error> errors() const;
0086 
0087     void setProgress(qreal progress);
0088     void setProgress(int processed, int total);
0089 
0090 protected:
0091     class KASYNC_EXPORT PrivateBase : public QSharedData
0092     {
0093     public:
0094         explicit PrivateBase(const KAsync::Private::ExecutionPtr &execution);
0095         virtual ~PrivateBase();
0096 
0097         void releaseExecution();
0098 
0099         bool finished;
0100         QVector<Error> errors;
0101 
0102         QVector<QPointer<FutureWatcherBase>> watchers;
0103     private:
0104         QWeakPointer<KAsync::Private::Execution> mExecution;
0105     };
0106 
0107     explicit FutureBase();
0108     explicit FutureBase(FutureBase::PrivateBase *dd);
0109     FutureBase(const FutureBase &other);
0110     FutureBase &operator=(const FutureBase &other) = default;
0111 
0112     void addWatcher(KAsync::FutureWatcherBase *watcher);
0113     void releaseExecution();
0114 
0115 protected:
0116     QExplicitlySharedDataPointer<PrivateBase> d;
0117 };
0118 
0119 template<typename T>
0120 class FutureWatcher;
0121 
0122 template<typename T>
0123 class Future;
0124 
0125 template<typename T>
0126 class FutureGeneric : public FutureBase
0127 {
0128     friend class FutureWatcher<T>;
0129 
0130 public:
0131 
0132     void waitForFinished() const
0133     {
0134         if (isFinished()) {
0135             return;
0136         }
0137         FutureWatcher<T> watcher;
0138         QEventLoop eventLoop;
0139         QObject::connect(&watcher, &KAsync::FutureWatcher<T>::futureReady,
0140                          &eventLoop, &QEventLoop::quit);
0141         watcher.setFuture(*static_cast<const KAsync::Future<T>*>(this));
0142         eventLoop.exec();
0143     }
0144 
0145 protected:
0146     //@cond PRIVATE
0147     explicit FutureGeneric(const KAsync::Private::ExecutionPtr &execution)
0148         : FutureBase(new Private(execution))
0149     {}
0150 
0151     FutureGeneric(const FutureGeneric &) = default;
0152     FutureGeneric &operator=(const FutureGeneric &) = default;
0153 
0154 protected:
0155     class Private : public FutureBase::PrivateBase
0156     {
0157     public:
0158         explicit Private(const KAsync::Private::ExecutionPtr &execution)
0159             : FutureBase::PrivateBase(execution)
0160         {}
0161 
0162         std::conditional_t<std::is_void<T>::value, int /* dummy */, T> value;
0163     };
0164 };
0165 //@endcond
0166 
0167 
0168 
0169 /**
0170  * @ingroup Future
0171  *
0172  * @brief Future is a promise that is used by Job to deliver result
0173  * of an asynchronous execution.
0174  *
0175  * The Future is passed internally to each executed task, and the task can use
0176  * it to report its progress, result and notify when it is finished.
0177  *
0178  * Users use Future they receive from calling Job::exec() to get access
0179  * to the overall result of the execution. FutureWatcher&lt;T&gt; can be used
0180  * to wait for the Future to finish in non-blocking manner.
0181  *
0182  * @see Future<void>
0183  */
0184 template<typename T>
0185 class Future : public FutureGeneric<T>
0186 {
0187     //@cond PRIVATE
0188     friend class KAsync::Private::ExecutorBase;
0189 
0190     template<typename T_>
0191     friend class KAsync::FutureWatcher;
0192     //@endcond
0193 public:
0194     /**
0195      * @brief Constructor
0196      */
0197     explicit Future()
0198         : FutureGeneric<T>(KAsync::Private::ExecutionPtr())
0199     {}
0200 
0201     /**
0202      * @brief Copy constructor
0203      */
0204     Future(const Future<T> &other)
0205         : FutureGeneric<T>(other)
0206     {}
0207 
0208     /**
0209      * Set the result of the Future. This method is called by the task upon
0210      * calculating the result. After setting the value, the caller must also
0211      * call setFinished() to notify users that the result
0212      * is available.
0213      *
0214      * @warning This method must only be called by the tasks inside Job,
0215      * never by outside users.
0216      *
0217      * @param value The result value
0218      */
0219     void setValue(const T &value)
0220     {
0221         dataImpl()->value = value;
0222     }
0223 
0224     /**
0225      * Retrieve the result of the Future. Calling this method when the future has
0226      * not yet finished (i.e. isFinished() returns false)
0227      * returns undefined result.
0228      */
0229     T value() const
0230     {
0231         return dataImpl()->value;
0232     }
0233 
0234     T *operator->()
0235     {
0236         return &(dataImpl()->value);
0237     }
0238 
0239     const T *operator->() const
0240     {
0241         return &(dataImpl()->value);
0242     }
0243 
0244     T &operator*()
0245     {
0246         return dataImpl()->value;
0247     }
0248 
0249     const T &operator*() const
0250     {
0251         return dataImpl()->value;
0252     }
0253 
0254 #ifdef ONLY_DOXYGEN
0255     /**
0256      * Will block until the Future has finished.
0257      *
0258      * @note Internally this method is using a nested QEventLoop, which can
0259      * in some situation cause problems and deadlocks. It is recommended to use
0260      * FutureWatcher.
0261      *
0262      * @see isFinished()
0263      */
0264     void waitForFinished() const;
0265 
0266     /**
0267      * Marks the future as finished. This will cause all FutureWatcher&lt;T&gt;
0268      * objects watching this particular instance to emit FutureWatcher::futureReady()
0269      * signal, and will cause all callers currently blocked in Future::waitForFinished()
0270      * method of this particular instance to resume.
0271      *
0272      * @warning This method must only be called by the tasks inside Job,
0273      * never by outside users.
0274      *
0275      * @see isFinished()
0276      */
0277     void setFinished();
0278 
0279     /**
0280      * Query whether the Future has already finished.
0281      *
0282      * @see setFinished()
0283      */
0284     bool isFinished() const;
0285 
0286     /**
0287      * Used by tasks to report an error that happened during execution. If an
0288      * error handler was provided to the task, it will be executed with the
0289      * given arguments. Otherwise the error will be propagated to next task
0290      * that has an error handler, or all the way up to user.
0291      *
0292      * This method also internally calls setFinished()
0293      *
0294      * @warning This method must only be called by the tasks inside Job,
0295      * never by outside users.
0296      *
0297      * @param code Optional error code
0298      * @param message Optional error message
0299      *
0300      * @see errorCode(), errorMessage()
0301      */
0302     void setError(int code = 1, const QString &message = QString());
0303 
0304     /**
0305      * Returns error code set via setError() or 0 if no
0306      * error has occurred.
0307      *
0308      * @see setError(), errorMessage()
0309      */
0310     int errorCode() const;
0311 
0312     /**
0313      * Returns error message set via setError() or empty
0314      * string if no error occurred.
0315      *
0316      * @see setError(), errorCode()
0317      */
0318     QString errorMessage() const;
0319 
0320     /**
0321      * Sets progress of the task. All FutureWatcher instances watching
0322      * this particular future will then emit FutureWatcher::futureProgress()
0323      * signal.
0324      *
0325      * @param processed Already processed amount
0326      * @param total Total amount to process
0327      */
0328     void setProgress(int processed, int total);
0329 
0330     /**
0331      * Sets progress of the task.
0332      *
0333      * @param progress Progress
0334      */
0335     void setProgress(qreal progress);
0336 
0337 #endif // ONLY_DOXYGEN
0338     void setResult(const T &value)
0339     {
0340         dataImpl()->value = value;
0341         FutureBase::setFinished();
0342     }
0343 
0344 protected:
0345     //@cond PRIVATE
0346     Future(const KAsync::Private::ExecutionPtr &execution)
0347         : FutureGeneric<T>(execution)
0348     {}
0349     //@endcond
0350 
0351 private:
0352     inline auto dataImpl()
0353     {
0354         return static_cast<typename FutureGeneric<T>::Private*>(this->d.data());
0355     }
0356 
0357     inline auto dataImpl() const
0358     {
0359         return static_cast<typename FutureGeneric<T>::Private*>(this->d.data());
0360     }
0361 };
0362 
0363 /**
0364  * @ingroup Future
0365  *
0366  * @brief A specialization of Future&lt;T&gt; for tasks that have no (void)
0367  * result.
0368  *
0369  * Unlike the generic Future&lt;T&gt; this specialization does not have
0370  * setValue() and value() methods to set/retrieve result.
0371  *
0372  * @see Future
0373  */
0374 template<>
0375 class Future<void> : public FutureGeneric<void>
0376 {
0377     friend class KAsync::Private::ExecutorBase;
0378 
0379 public:
0380     /**
0381      * @brief Constructor
0382      */
0383     Future()
0384         : FutureGeneric<void>(KAsync::Private::ExecutionPtr())
0385     {}
0386 
0387 protected:
0388     //@cond PRIVATE
0389     Future(const KAsync::Private::ExecutionPtr &execution)
0390         : FutureGeneric<void>(execution)
0391     {}
0392     //@endcond
0393 };
0394 
0395 
0396 
0397 
0398 //@cond PRIVATE
0399 class KASYNC_EXPORT FutureWatcherBase : public QObject
0400 {
0401     Q_OBJECT
0402 
0403     friend class FutureBase;
0404 
0405 Q_SIGNALS:
0406     void futureReady();
0407     void futureProgress(qreal progress);
0408 
0409 protected:
0410     FutureWatcherBase(QObject *parent = nullptr);
0411 
0412     virtual ~FutureWatcherBase();
0413 
0414     void futureReadyCallback();
0415     void futureProgressCallback(qreal progress);
0416 
0417     void setFutureImpl(const KAsync::FutureBase &future);
0418 
0419 protected:
0420     class Private {
0421     public:
0422         KAsync::FutureBase future;
0423     };
0424 
0425     Private * const d;
0426 
0427 private:
0428     Q_DISABLE_COPY(FutureWatcherBase)
0429 };
0430 //@endcond
0431 
0432 
0433 /**
0434  * @ingroup Future
0435  *
0436  * @brief The FutureWatcher allows monitoring of Job results using
0437  * signals and slots.
0438  *
0439  * FutureWatcher is returned by Job upon execution. User can then
0440  * connect to its futureReady() and futureProgress() signals to be notified
0441  * about progress of the asynchronous job. When futureReady() signal is emitted,
0442  * the result of the job is available in Future::value().
0443  */
0444 template<typename T>
0445 class FutureWatcher : public FutureWatcherBase
0446 {
0447     //@cond PRIVATE
0448     friend class KAsync::FutureGeneric<T>;
0449     //@endcond
0450 
0451 public:
0452     /**
0453      * Constructs a new FutureWatcher that can watch for status of Future&lt;T&gt;
0454      */
0455     FutureWatcher(QObject *parent = nullptr)
0456         : FutureWatcherBase(parent)
0457     {}
0458 
0459     ~FutureWatcher()
0460     {}
0461 
0462     /**
0463      * Set future to watch.
0464      *
0465      * @param future Future object to watch
0466      */
0467     void setFuture(const KAsync::Future<T> &future)
0468     {
0469         setFutureImpl(*static_cast<const KAsync::FutureBase*>(&future));
0470     }
0471 
0472     /**
0473      * Returns currently watched future.
0474      */
0475     KAsync::Future<T> future() const
0476     {
0477         return *static_cast<KAsync::Future<T>*>(&d->future);
0478     }
0479 
0480 #ifdef ONLY_DOXYGEN
0481 Q_SIGNALS:
0482     /**
0483      * The signal is emitted when the execution has finished and the result
0484      * can be collected.
0485      *
0486      * @see Future::setFinished(), Future::setError()
0487      */
0488     void futureReady();
0489 
0490     /**
0491      * The signal is emitted when progress of the execution changes. This has
0492      * to be explicitly supported by the job being executed, otherwise the
0493      * signal is not emitted.
0494      *
0495      * @see Future::setProgress()
0496      */
0497     void futureProgress(qreal progress);
0498 #endif
0499 
0500 private:
0501     FutureWatcher(const FutureWatcher<T> &) = delete;
0502     FutureWatcher &operator=(const FutureWatcher<T> &) = delete;
0503 };
0504 
0505 } // namespace Async
0506 
0507 KASYNC_EXPORT QDebug& operator<<(QDebug &dbg, const KAsync::Error &error);
0508 
0509 #endif // FUTURE_H