From 44ceb56455c82df3e6b1c9a2fa373cac14a039f8 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Wed, 26 Feb 2020 10:40:02 +0100 Subject: QFuture - add ability to move results from QFuture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QFuture's original design pre-dates C++11 and its introduction of move semantics. QFuture is documented as requiring copy-constructible classes and uses copy operations for results (which in Qt's universe in general is relatively cheap, due to the use of COW/data sharing). QFuture::result(), QFuture::results(), QFuture::resultAt() return copies. Now that the year is 2020, it makes some sense to add support for move semantics and, in particular, move-only types, like std::unique_ptr (that cannot be obtained from QFuture using result etc.). Taking a result or results from a QFuture renders it invalid. This patch adds QFuture::takeResults(), takeResult() and isValid(). 'Taking' functions are 'enabled_if' for non-void types only to improve the compiler's diagnostic (which would otherwise spit some semi-articulate diagnostic). As a bonus a bug was found in the pre-existing code (after initially copy and pasted into the new function) - the one where we incorrectly report ready results in (rather obscure) filter mode. Fixes: QTBUG-81941 Fixes: QTBUG-83182 Change-Id: I8ccdfc50aa310a3a79eef2cdc55f5ea210f889c3 Reviewed-by: Edward Welbourne Reviewed-by: MÃ¥rten Nordheim --- src/corelib/thread/qfuture.qdoc | 98 ++++++++++++++++++++++++++++++++++------- 1 file changed, 82 insertions(+), 16 deletions(-) (limited to 'src/corelib/thread/qfuture.qdoc') diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc index 989ffa36c8..1519f20cf0 100644 --- a/src/corelib/thread/qfuture.qdoc +++ b/src/corelib/thread/qfuture.qdoc @@ -37,14 +37,17 @@ QFuture allows threads to be synchronized against one or more results which will be ready at a later point in time. The result can be of any type - that has a default constructor and a copy constructor. If a result is not - available at the time of calling the result(), resultAt(), or results() - functions, QFuture will wait until the result becomes available. You can - use the isResultReadyAt() function to determine if a result is ready or - not. For QFuture objects that report more than one result, the - resultCount() function returns the number of continuous results. This - means that it is always safe to iterate through the results from 0 to - resultCount(). + that has default, copy and possibly move constructors. If + a result is not available at the time of calling the result(), resultAt(), + results(), takeResult(), or takeResults() functions, QFuture + will wait until the result becomes available. You can use the isResultReadyAt() + function to determine if a result is ready or not. For QFuture objects that + report more than one result, the resultCount() function returns the number + of continuous results. This means that it is always safe to iterate through + the results from 0 to resultCount(). takeResult() and takeResults() + invalidate a future and any subsequent attempt to access result or results + from the future leads to undefined behavior. isValid() tells you if + results can be accessed. QFuture provides a \l{Java-style iterators}{Java-style iterator} (QFutureIterator) and an \l{STL-style iterators}{STL-style iterator} @@ -227,7 +230,7 @@ number of results stored might be different from this value, due to gaps in the result set. It is always safe to iterate through the results from 0 to resultCount(). - \sa result(), resultAt(), results() + \sa result(), resultAt(), results(), takeResult(), takeResults() */ /*! \fn template int QFuture::progressValue() const @@ -273,7 +276,10 @@ available, this function will block and wait for the result to become available. This is a convenience method for calling resultAt(0). - \sa resultAt(), results() + \note Calling result() leads to undefined behavior if isValid() + returns \c false for this QFuture. + + \sa resultAt(), results(), takeResult(), takeResults() */ /*! \fn template T QFuture::resultAt(int index) const @@ -282,7 +288,10 @@ immediately available, this function will block and wait for the result to become available. - \sa result(), results(), resultCount() + \note Calling resultAt() leads to undefined behavior if isValid() + returns \c false for this QFuture. + + \sa result(), results(), takeResult(), takeResults(), resultCount() */ /*! \fn template bool QFuture::isResultReadyAt(int index) const @@ -290,7 +299,10 @@ Returns \c true if the result at \a index is immediately available; otherwise returns \c false. - \sa resultAt(), resultCount() + \note Calling isResultReadyAt() leads to undefined behavior if isValid() + returns \c false for this QFuture. + + \sa resultAt(), resultCount(), takeResult(), takeResults() */ /*! \fn template QFuture::operator T() const @@ -300,15 +312,69 @@ available. This is a convenience method for calling result() or resultAt(0). - \sa result(), resultAt(), results() + \note Calling this function leads to undefined behavior if isValid() + returns \c false for this QFuture. + + \sa result(), resultAt(), results(), takeResult(), takeResults(), isValid() */ /*! \fn template QList QFuture::results() const - Returns all results from the future. If the results are not immediately - available, this function will block and wait for them to become available. + Returns all results from the future. If the results are not immediately available, + this function will block and wait for them to become available. + + \note Calling results() leads to undefined behavior if isValid() + returns \c false for this QFuture. + + \sa result(), resultAt(), takeResult(), takeResults(), resultCount(), isValid() +*/ + +/*! \fn template std::vector QFuture::takeResults() + + If isValid() returns \c false, calling this function leads to undefined behavior. + takeResults() takes all results from the QFuture object and invalidates it + (isValid() will return \c false for this future). If the results are + not immediately available, this function will block and wait for them to + become available. This function tries to use move semantics for the results + if available and falls back to copy construction if the type is not movable. + + \note QFuture in general allows sharing the results between different QFuture + objects (and potentially between different threads). takeResults() was introduced + to make QFuture also work with move-only types (like std::unique_ptr), so it + assumes that only one thread can move the results out of the future, and only + once. + + \sa takeResult(), result(), resultAt(), results(), resultCount(), isValid() +*/ + +/* \fn template std::vector QFuture::takeResult() + + Call this function only if isValid() returns \c true, otherwise + the behavior is undefined. This function takes the first result from + the QFuture object, for convenience when only one result is expected. + If there are any other results, they are discarded after taking the + first one (if such behavior is undesired, use takeResults() instead). + If the result is not immediately available, this function will block and + wait for the result to become available. The QFuture will try to use move + semantics if possible, and will fall back to copy construction if the type + is not movable. After the result was taken, isValid() will evaluate + as \c false. + + \note QFuture in general allows sharing the results between different QFuture + objects (and potentially between different threads). takeResult() was introduced + to make QFuture also work with move-only types (like std::unique_ptr), so it + assumes that only one thread can move the results out of the future, and + do it only once. + + \sa takeResults(), result(), results(), resultAt(), isValid() +*/ + +/* \fn template std::vector QFuture::isValid() const + + Returns true if a result or results can be accessed or taken from this + QFuture object. Returns false after the result was taken from the future. - \sa result(), resultAt(), resultCount() + \sa takeResults(), takeResult(), result(), results(), resultAt() */ /*! \fn template QFuture::const_iterator QFuture::begin() const -- cgit v1.2.3