Allocate progress related data on demand

Some of the data members related to progress reporting (min, max and
text) aren't used when user doesn't want manual progress reporting, so
the data for them can be allocated on demand, when the user explicitly
sets them. Note, that we still need to always create other related data
(current value and progress timer), since in the non-manual mode
progress is still reported by incrementing the current value each time
a new result is reported.

Task-number: QTBUG-92045
Change-Id: I1e5bd17de2613a6ea72ccff0029812f67686708b
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Andrei Golubev <andrei.golubev@qt.io>
This commit is contained in:
Sona Kurazyan 2021-06-08 16:52:00 +02:00
parent 6460c3c33d
commit 02f521a59c
2 changed files with 63 additions and 30 deletions

View File

@ -299,13 +299,13 @@ int QFutureInterfaceBase::progressValue() const
int QFutureInterfaceBase::progressMinimum() const int QFutureInterfaceBase::progressMinimum() const
{ {
const QMutexLocker lock(&d->m_mutex); const QMutexLocker lock(&d->m_mutex);
return d->m_progressMinimum; return d->m_progress ? d->m_progress->minimum : 0;
} }
int QFutureInterfaceBase::progressMaximum() const int QFutureInterfaceBase::progressMaximum() const
{ {
const QMutexLocker lock(&d->m_mutex); const QMutexLocker lock(&d->m_mutex);
return d->m_progressMaximum; return d->m_progress ? d->m_progress->maximum : 0;
} }
int QFutureInterfaceBase::resultCount() const int QFutureInterfaceBase::resultCount() const
@ -317,7 +317,7 @@ int QFutureInterfaceBase::resultCount() const
QString QFutureInterfaceBase::progressText() const QString QFutureInterfaceBase::progressText() const
{ {
QMutexLocker locker(&d->m_mutex); QMutexLocker locker(&d->m_mutex);
return d->m_progressText; return d->m_progress ? d->m_progress->text : QString();
} }
bool QFutureInterfaceBase::isProgressUpdateNeeded() const bool QFutureInterfaceBase::isProgressUpdateNeeded() const
@ -382,7 +382,7 @@ void QFutureInterfaceBase::reportFinished()
void QFutureInterfaceBase::setExpectedResultCount(int resultCount) void QFutureInterfaceBase::setExpectedResultCount(int resultCount)
{ {
if (d->manualProgress == false) if (d->m_progress)
setProgressRange(0, resultCount); setProgressRange(0, resultCount);
d->m_expectedResultCount = resultCount; d->m_expectedResultCount = resultCount;
} }
@ -455,8 +455,8 @@ void QFutureInterfaceBase::reportResultsReady(int beginIndex, int endIndex)
d->waitCondition.wakeAll(); d->waitCondition.wakeAll();
if (d->manualProgress == false) { if (!d->m_progress) {
if (d->internal_updateProgress(d->m_progressValue + endIndex - beginIndex) == false) { if (d->internal_updateProgressValue(d->m_progressValue + endIndex - beginIndex) == false) {
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady,
beginIndex, beginIndex,
endIndex)); endIndex));
@ -465,7 +465,7 @@ void QFutureInterfaceBase::reportResultsReady(int beginIndex, int endIndex)
d->sendCallOuts(QFutureCallOutEvent(QFutureCallOutEvent::Progress, d->sendCallOuts(QFutureCallOutEvent(QFutureCallOutEvent::Progress,
d->m_progressValue, d->m_progressValue,
d->m_progressText), QString()),
QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady, QFutureCallOutEvent(QFutureCallOutEvent::ResultsReady,
beginIndex, beginIndex,
endIndex)); endIndex));
@ -515,8 +515,10 @@ void QFutureInterfaceBase::setFilterMode(bool enable)
void QFutureInterfaceBase::setProgressRange(int minimum, int maximum) void QFutureInterfaceBase::setProgressRange(int minimum, int maximum)
{ {
QMutexLocker locker(&d->m_mutex); QMutexLocker locker(&d->m_mutex);
d->m_progressMinimum = minimum; if (!d->m_progress)
d->m_progressMaximum = qMax(minimum, maximum); d->m_progress.reset(new QFutureInterfaceBasePrivate::ProgressData());
d->m_progress->minimum = minimum;
d->m_progress->maximum = qMax(minimum, maximum);
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange, minimum, maximum)); d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange, minimum, maximum));
d->m_progressValue = minimum; d->m_progressValue = minimum;
} }
@ -536,12 +538,12 @@ void QFutureInterfaceBase::setProgressValueAndText(int progressValue,
const QString &progressText) const QString &progressText)
{ {
QMutexLocker locker(&d->m_mutex); QMutexLocker locker(&d->m_mutex);
if (d->manualProgress == false) if (!d->m_progress)
d->manualProgress = true; d->m_progress.reset(new QFutureInterfaceBasePrivate::ProgressData());
const bool useProgressRange = (d->m_progressMaximum != 0) || (d->m_progressMinimum != 0); const bool useProgressRange = (d->m_progress->maximum != 0) || (d->m_progress->minimum != 0);
if (useProgressRange if (useProgressRange
&& ((progressValue < d->m_progressMinimum) || (progressValue > d->m_progressMaximum))) { && ((progressValue < d->m_progress->minimum) || (progressValue > d->m_progress->maximum))) {
return; return;
} }
@ -554,7 +556,7 @@ void QFutureInterfaceBase::setProgressValueAndText(int progressValue,
if (d->internal_updateProgress(progressValue, progressText)) { if (d->internal_updateProgress(progressValue, progressText)) {
d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Progress, d->sendCallOut(QFutureCallOutEvent(QFutureCallOutEvent::Progress,
d->m_progressValue, d->m_progressValue,
d->m_progressText)); d->m_progress->text));
} }
} }
@ -613,8 +615,7 @@ bool QFutureInterfaceBase::derefT() const noexcept
void QFutureInterfaceBase::reset() void QFutureInterfaceBase::reset()
{ {
d->m_progressValue = 0; d->m_progressValue = 0;
d->m_progressMinimum = 0; d->m_progress.reset();
d->m_progressMaximum = 0;
d->setState(QFutureInterfaceBase::NoState); d->setState(QFutureInterfaceBase::NoState);
d->progressTime.invalidate(); d->progressTime.invalidate();
d->isValid = false; d->isValid = false;
@ -666,16 +667,34 @@ bool QFutureInterfaceBasePrivate::internal_waitForNextResult()
&& data.m_results.hasNextResult(); && data.m_results.hasNextResult();
} }
bool QFutureInterfaceBasePrivate::internal_updateProgressValue(int progress)
{
if (m_progressValue >= progress)
return false;
m_progressValue = progress;
if (progressTime.isValid() && m_progressValue != 0) // make sure the first and last steps are emitted.
if (progressTime.elapsed() < (1000 / MaxProgressEmitsPerSecond))
return false;
progressTime.start();
return true;
}
bool QFutureInterfaceBasePrivate::internal_updateProgress(int progress, bool QFutureInterfaceBasePrivate::internal_updateProgress(int progress,
const QString &progressText) const QString &progressText)
{ {
if (m_progressValue >= progress) if (m_progressValue >= progress)
return false; return false;
m_progressValue = progress; Q_ASSERT(m_progress);
m_progressText = progressText;
if (progressTime.isValid() && m_progressValue != m_progressMaximum) // make sure the first and last steps are emitted. m_progressValue = progress;
m_progress->text = progressText;
if (progressTime.isValid() && m_progressValue != m_progress->maximum) // make sure the first and last steps are emitted.
if (progressTime.elapsed() < (1000 / MaxProgressEmitsPerSecond)) if (progressTime.elapsed() < (1000 / MaxProgressEmitsPerSecond))
return false; return false;
@ -733,12 +752,21 @@ void QFutureInterfaceBasePrivate::connectOutputInterface(QFutureCallOutInterface
const auto currentState = state.loadRelaxed(); const auto currentState = state.loadRelaxed();
if (currentState & QFutureInterfaceBase::Started) { if (currentState & QFutureInterfaceBase::Started) {
interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Started)); interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Started));
if (m_progress) {
interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange, interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange,
m_progressMinimum, m_progress->minimum,
m_progressMaximum)); m_progress->maximum));
interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Progress, interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Progress,
m_progressValue, m_progressValue,
m_progressText)); m_progress->text));
} else {
interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::ProgressRange,
0,
0));
interface->postCallOutEvent(QFutureCallOutEvent(QFutureCallOutEvent::Progress,
m_progressValue,
QString()));
}
} }
if (!hasException) { if (!hasException) {

View File

@ -184,7 +184,6 @@ public:
}; };
Data data = { QtPrivate::ResultStoreBase() }; Data data = { QtPrivate::ResultStoreBase() };
QString m_progressText;
QRunnable *runnable = nullptr; QRunnable *runnable = nullptr;
QThreadPool *m_pool = nullptr; QThreadPool *m_pool = nullptr;
// Wrapper for continuation // Wrapper for continuation
@ -192,11 +191,17 @@ public:
RefCount refCount = 1; RefCount refCount = 1;
QAtomicInt state; // reads and writes can happen unprotected, both must be atomic QAtomicInt state; // reads and writes can happen unprotected, both must be atomic
int m_progressValue = 0; // TQ int m_progressValue = 0; // TQ
int m_progressMinimum = 0; // TQ struct ProgressData
int m_progressMaximum = 0; // TQ {
int minimum = 0; // TQ
int maximum = 0; // TQ
QString text;
};
QScopedPointer<ProgressData> m_progress;
int m_expectedResultCount = 0; int m_expectedResultCount = 0;
bool manualProgress = false; // only accessed from executing thread
bool launchAsync = false; bool launchAsync = false;
bool isValid = false; bool isValid = false;
bool hasException = false; bool hasException = false;
@ -209,6 +214,7 @@ public:
int internal_resultCount() const; int internal_resultCount() const;
bool internal_isResultReadyAt(int index) const; bool internal_isResultReadyAt(int index) const;
bool internal_waitForNextResult(); bool internal_waitForNextResult();
bool internal_updateProgressValue(int progress);
bool internal_updateProgress(int progress, const QString &progressText = QString()); bool internal_updateProgress(int progress, const QString &progressText = QString());
void internal_setThrottled(bool enable); void internal_setThrottled(bool enable);
void sendCallOut(const QFutureCallOutEvent &callOut); void sendCallOut(const QFutureCallOutEvent &callOut);
@ -217,7 +223,6 @@ public:
void disconnectOutputInterface(QFutureCallOutInterface *iface); void disconnectOutputInterface(QFutureCallOutInterface *iface);
void setState(QFutureInterfaceBase::State state); void setState(QFutureInterfaceBase::State state);
}; };
QT_END_NAMESPACE QT_END_NAMESPACE