Clean-up the duplicate code in QFuture and QFutureWatcher

QFuture<void> and QFutureWatcher<void> are specialized to not contain
any of result fetching methods, but otherwise they share almost the same
implementation with QFuture<T> and QFutureWatcher<T> respectively.

This change unifies their implementations to get rid of unnecessary code
duplication.

Change-Id: I9494ddc58c6db192c66edb988105927da6d61a3b
Reviewed-by: Vitaly Fanaskov <vitaly.fanaskov@qt.io>
This commit is contained in:
Sona Kurazyan 2020-03-18 21:41:58 +01:00
parent 20eabb72de
commit 1005c86c61
3 changed files with 69 additions and 135 deletions

View File

@ -53,8 +53,6 @@ QT_BEGIN_NAMESPACE
template <typename T>
class QFutureWatcher;
template <>
class QFutureWatcher<void>;
template <typename T>
class QFuture
@ -63,13 +61,39 @@ public:
QFuture()
: d(QFutureInterface<T>::canceledResult())
{ }
template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>>
explicit QFuture(QFutureInterface<T> *p) // internal
: d(*p)
{ }
template<typename U = T, typename = QtPrivate::EnableForVoid<U>>
explicit QFuture(QFutureInterfaceBase *p) // internal
: d(*p)
{
}
#if !defined(Q_CC_XLC)
template<typename U, typename V = T, typename = QtPrivate::EnableForVoid<V>>
QFuture(const QFuture<U> &other) : d(other.d)
{
}
template<typename U, typename V = T, typename = QtPrivate::EnableForVoid<V>>
QFuture<void> &operator=(const QFuture<U> &other)
{
d = other.d;
return *this;
}
#endif
#if defined(Q_CLANG_QDOC)
~QFuture() { }
QFuture(const QFuture<T> &) { }
QFuture<T> & operator=(const QFuture<T> &) { }
// This is required to allow QDoc to find the declaration of operator T().
operator T() const;
#endif
bool operator==(const QFuture &other) const { return (d == other.d); }
@ -95,11 +119,20 @@ public:
QString progressText() const { return d.progressText(); }
void waitForFinished() { d.waitForFinished(); }
template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>>
inline T result() const;
template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>>
inline T resultAt(int index) const;
template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>>
bool isResultReadyAt(int resultIndex) const { return d.isResultReadyAt(resultIndex); }
operator T() const { return result(); }
// operator T()
template<typename U = T>
operator typename std::enable_if_t<!std::is_same_v<U, void>, U>() const { return result(); }
template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>>
QList<T> results() const { return d.results(); }
template<class Function>
@ -117,6 +150,9 @@ public:
class const_iterator
{
public:
static_assert(!std::is_same_v<T, void>,
"It isn't possible to define QFuture<void>::const_iterator");
typedef std::bidirectional_iterator_tag iterator_category;
typedef qptrdiff difference_type;
typedef T value_type;
@ -203,9 +239,16 @@ public:
friend class const_iterator;
typedef const_iterator ConstIterator;
template<class U = T, typename = QtPrivate::EnableForNonVoid<U>>
const_iterator begin() const { return const_iterator(this, 0); }
template<class U = T, typename = QtPrivate::EnableForNonVoid<U>>
const_iterator constBegin() const { return const_iterator(this, 0); }
template<class U = T, typename = QtPrivate::EnableForNonVoid<U>>
const_iterator end() const { return const_iterator(this, -1); }
template<class U = T, typename = QtPrivate::EnableForNonVoid<U>>
const_iterator constEnd() const { return const_iterator(this, -1); }
private:
@ -213,17 +256,21 @@ private:
public: // Warning: the d pointer is not documented and is considered private.
// TODO: make this private
mutable QFutureInterface<T> d;
using QFuturePrivate =
std::conditional_t<std::is_same_v<T, void>, QFutureInterfaceBase, QFutureInterface<T>>;
mutable QFuturePrivate d;
};
template <typename T>
template<typename T>
template<typename U, typename>
inline T QFuture<T>::result() const
{
d.waitForResult(0);
return d.resultReference(0);
}
template <typename T>
template<typename T>
template<typename U, typename>
inline T QFuture<T>::resultAt(int index) const
{
d.waitForResult(index);
@ -265,80 +312,6 @@ QFuture<typename QFuture<T>::template ResultType<Function>> QFuture<T>::then(QTh
return promise.future();
}
Q_DECLARE_SEQUENTIAL_ITERATOR(Future)
template <>
class QFuture<void>
{
public:
QFuture()
: d(QFutureInterface<void>::canceledResult())
{ }
explicit QFuture(QFutureInterfaceBase *p) // internal
: d(*p)
{ }
bool operator==(const QFuture &other) const { return (d == other.d); }
bool operator!=(const QFuture &other) const { return (d != other.d); }
#if !defined(Q_CC_XLC)
template <typename T>
QFuture(const QFuture<T> &other)
: d(other.d)
{ }
template <typename T>
QFuture<void> &operator=(const QFuture<T> &other)
{
d = other.d;
return *this;
}
#endif
void cancel() { d.cancel(); }
bool isCanceled() const { return d.isCanceled(); }
void setPaused(bool paused) { d.setPaused(paused); }
bool isPaused() const { return d.isPaused(); }
void pause() { setPaused(true); }
void resume() { setPaused(false); }
void togglePaused() { d.togglePaused(); }
bool isStarted() const { return d.isStarted(); }
bool isFinished() const { return d.isFinished(); }
bool isRunning() const { return d.isRunning(); }
int resultCount() const { return d.resultCount(); }
int progressValue() const { return d.progressValue(); }
int progressMinimum() const { return d.progressMinimum(); }
int progressMaximum() const { return d.progressMaximum(); }
QString progressText() const { return d.progressText(); }
void waitForFinished() { d.waitForFinished(); }
template<class Function>
using ResultType = typename QtPrivate::ResultTypeHelper<Function, void>::ResultType;
template<class Function>
QFuture<ResultType<Function>> then(Function &&function);
template<class Function>
QFuture<ResultType<Function>> then(QtFuture::Launch policy, Function &&function);
template<class Function>
QFuture<ResultType<Function>> then(QThreadPool *pool, Function &&function);
private:
friend class QFutureWatcher<void>;
#ifdef QFUTURE_TEST
public:
#endif
mutable QFutureInterfaceBase d;
template<typename Function, typename ResultType, typename ParentResultType>
friend class QtPrivate::Continuation;
};
inline QFuture<void> QFutureInterface<void>::future()
{
return QFuture<void>(this);
@ -350,31 +323,7 @@ QFuture<void> qToVoidFuture(const QFuture<T> &future)
return QFuture<void>(future.d);
}
template<class Function>
QFuture<QFuture<void>::ResultType<Function>> QFuture<void>::then(Function &&function)
{
return then(QtFuture::Launch::Sync, std::forward<Function>(function));
}
template<class Function>
QFuture<QFuture<void>::ResultType<Function>> QFuture<void>::then(QtFuture::Launch policy,
Function &&function)
{
QFutureInterface<ResultType<Function>> promise(QFutureInterfaceBase::State::Pending);
QtPrivate::Continuation<Function, ResultType<Function>, void>::create(
std::forward<Function>(function), this, promise, policy);
return promise.future();
}
template<class Function>
QFuture<QFuture<void>::ResultType<Function>> QFuture<void>::then(QThreadPool *pool,
Function &&function)
{
QFutureInterface<ResultType<Function>> promise(QFutureInterfaceBase::State::Pending);
QtPrivate::Continuation<Function, ResultType<Function>, void>::create(
std::forward<Function>(function), this, promise, pool);
return promise.future();
}
Q_DECLARE_SEQUENTIAL_ITERATOR(Future)
QT_END_NAMESPACE

View File

@ -66,6 +66,12 @@ enum class Launch { Sync, Async, Inherit };
namespace QtPrivate {
template<class T>
using EnableForVoid = std::enable_if_t<std::is_same_v<T, void>>;
template<class T>
using EnableForNonVoid = std::enable_if_t<!std::is_same_v<T, void>>;
template<typename F, typename Arg, typename Enable = void>
struct ResultTypeHelper
{

View File

@ -110,6 +110,12 @@ private:
virtual QFutureInterfaceBase &futureInterface() = 0;
};
namespace QtPrivate {
template<class T>
using EnableForNonVoid = std::enable_if_t<!std::is_same_v<T, void>>;
}
template <typename T>
class QFutureWatcher : public QFutureWatcherBase
{
@ -124,7 +130,10 @@ public:
QFuture<T> future() const
{ return m_future; }
template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>>
T result() const { return m_future.result(); }
template<typename U = T, typename = QtPrivate::EnableForNonVoid<U>>
T resultAt(int index) const { return m_future.resultAt(index); }
#ifdef Q_QDOC
@ -180,36 +189,6 @@ Q_INLINE_TEMPLATE void QFutureWatcher<T>::setFuture(const QFuture<T> &_future)
connectOutputInterface();
}
template <>
class QFutureWatcher<void> : public QFutureWatcherBase
{
public:
explicit QFutureWatcher(QObject *_parent = nullptr)
: QFutureWatcherBase(_parent)
{ }
~QFutureWatcher()
{ disconnectOutputInterface(); }
void setFuture(const QFuture<void> &future);
QFuture<void> future() const
{ return m_future; }
private:
QFuture<void> m_future;
const QFutureInterfaceBase &futureInterface() const override { return m_future.d; }
QFutureInterfaceBase &futureInterface() override { return m_future.d; }
};
Q_INLINE_TEMPLATE void QFutureWatcher<void>::setFuture(const QFuture<void> &_future)
{
if (_future == m_future)
return;
disconnectOutputInterface(true);
m_future = _future;
connectOutputInterface();
}
QT_END_NAMESPACE
#endif // QFUTUREWATCHER_H