FutureWatcher.h 1.96 KB
Newer Older
Valentin Platzgummer's avatar
Valentin Platzgummer committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
#ifndef FUTUREWATCHER_H
#define FUTUREWATCHER_H

#include "FutureWatcherInterface.h"
#include <QTimer>
#include <future>

namespace nemo_interface {

//!
//! class similar to QFutureWatcher suitable for a std::future or
//! std::shared_future. \note For single thread use only.
//!
template <class T, template <class> class Future = std::future>
class FutureWatcher : public FutureWatcherInterface {
  enum class STATE { EMPTY, STARTED, FINISHED };

public:
  typedef Future<T> FutureType;

  explicit FutureWatcher(QObject *parent = nullptr)
      : FutureWatcherInterface(parent), _state(STATE::EMPTY) {
    _init();
  }

  FutureWatcher(const FutureType &f, QObject *parent = nullptr)
      : FutureWatcherInterface(parent), _future(f), _state(STATE::STARTED) {
    _init();
  }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
31 32 33 34
  FutureType future() const {
    Q_ASSERT(this->_state != STATE::EMPTY);
    return _future;
  }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
35 36 37 38 39 40 41 42

  void setFuture(const FutureType &future) {
    _future = future;
    _state = STATE::STARTED;
    _timer.start(1);
    emit started();
  }

Valentin Platzgummer's avatar
Valentin Platzgummer committed
43 44 45 46
  T result() {
    Q_ASSERT(this->_state != STATE::EMPTY);
    return _future.get();
  }
Valentin Platzgummer's avatar
Valentin Platzgummer committed
47 48

  virtual void waitForFinished() override {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
49
    Q_ASSERT(this->_state != STATE::EMPTY);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
50 51 52 53 54 55 56 57 58 59 60 61 62
    if (_state == STATE::STARTED) {
      _timer.stop();
      _future.wait();
      _state = STATE::FINISHED;
    }
  }

  virtual bool isStarted() override { return _state == STATE::STARTED; }

  virtual bool isFinished() override { return _state == STATE::FINISHED; }

private:
  void _onTimeout() {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
63
    Q_ASSERT(this->_state == STATE::STARTED);
Valentin Platzgummer's avatar
Valentin Platzgummer committed
64 65 66
    if (_state == STATE::STARTED) {
      auto status = _future.wait_for(std::chrono::seconds(0));
      if (status == std::future_status::ready) {
Valentin Platzgummer's avatar
Valentin Platzgummer committed
67
        _timer.stop();
Valentin Platzgummer's avatar
Valentin Platzgummer committed
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
        _state = STATE::FINISHED;
        emit finished();
      }
    }
  }

  void _init() {
    connect(&_timer, &QTimer::timeout, [this] { this->_onTimeout(); });
  }

  FutureType _future;
  QTimer _timer;
  STATE _state;
};
} // namespace nemo_interface
#endif // FUTUREWATCHER_H