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<T> 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<T> 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<T> for tasks that have no (void) 0367 * result. 0368 * 0369 * Unlike the generic Future<T> 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<T> 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