CopperSpice API  1.9.1
QtConcurrentMap Class Reference

Header providing Concurrent Map and MapReduce. More...

Detailed Description

These functions are provided to support Concurrent Programming.

The QtConcurrent::map(), QtConcurrent::mapped() and QtConcurrent::mappedReduced() functions run computations in parallel on the items in a sequence such as a QList or a QVector. QtConcurrent::map() modifies a sequence in-place, QtConcurrent::mapped() returns a new sequence containing the modified content, and QtConcurrent::mappedReduced() returns a single result.

Each of the above functions has a blocking variant that returns the final result instead of a QFuture. You use them in the same way as the asynchronous variants.

QList<QImage> images = ...;
// each call blocks until the entire operation is finished
QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);

Note the result types above are not QFuture objects, but real result types (in this case, QList<QImage> and QImage).

Concurrent Map

QtConcurrent::mapped() takes an input sequence and a map function. This map function is then called for each item in the sequence, and a new sequence containing the return values from the map function is returned.

The map function must be of the form:

U function(const T &t);

T and U can be any type (and they can even be the same type), but T must match the type stored in the sequence. The function returns the modified or mapped content.

This example shows how to apply a scale function to all the items in a sequence:

QImage scaled(const QImage &image)
{
return image.scaled(100, 100);
}
QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, scaled);

The results of the map are made available through QFuture. Refer to the QFuture and QFutureWatcher documentation for more information on how to use QFuture. If you want to modify a sequence in-place, use QtConcurrent::map(). The map function must then be of the form.

U function(T &t);

The return value and return type of the map function are not used. Using QtConcurrent::map() is similar to using QtConcurrent::mapped().

void scale(QImage &image)
{
image = image.scaled(100, 100);
}
QList<QImage> images = ...;
QFuture<void> future = QtConcurrent::map(images, scale);

Since the sequence is modified in place, QtConcurrent::map() does not return any results via QFuture. However, you can still use QFuture and QFutureWatcher to monitor the status of the map.

Concurrent Map-Reduce

QtConcurrent::mappedReduced() is similar to QtConcurrent::mapped(), but instead of returning a sequence with the new results, the results are combined into a single value using a reduce function.

The reduce function must be of the form:

V function(T &result, const U &intermediate)

T is the type of the final result, U is the return type of the map function. The return value and return type of the reduce function are not used. Call QtConcurrent::mappedReduced() as shown.

void addToCollage(QImage &collage, const QImage &thumbnail)
{
QPainter p(&collage);
static QPoint offset = QPoint(0, 0);
p.drawImage(offset, thumbnail);
offset += ...;
}
QList<QImage> images = ...;
QFuture<QImage> collage = QtConcurrent::mappedReduced(images, scaled, addToCollage);

The reduce function will be called once for each result returned by the map function, and should merge the intermediate into the result variable. QtConcurrent::mappedReduced() guarantees that only one thread will call reduce at a time, so using a mutex to lock the result variable is not necessary. The QtConcurrent::ReduceOptions enum provides a way to control the order in which the reduction is done. If QtConcurrent::UnorderedReduce is used (the default), the order is undefined, while QtConcurrent::OrderedReduce ensures that the reduction is done in the order of the original sequence.

Using Iterators instead of Sequence

Each of the above functions has a variant that takes an iterator range instead of a sequence. You use them in the same way as the sequence variants:

QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images.constBegin(), images.constEnd(), scaled);
// map in-place only works on non-const iterators
QFuture<void> future = QtConcurrent::map(images.begin(), images.end(), scale);
QFuture<QImage> collage = QtConcurrent::mappedReduced(images.constBegin(), images.constEnd(), scaled, addToCollage);

Blocking Variants

Each of the above functions has a blocking variant that returns the final result instead of a QFuture. You use them in the same way as the asynchronous variants.

QList<QImage> images = ...;
// each call blocks until the entire operation is finished
QImage collage = QtConcurrent::blockingMappedReduced(images, scaled, addToCollage);

The result types above are not QFuture objects, but real result types (in this case, QList<QImage> and QImage).

Using Member Functions

QtConcurrent::map(), QtConcurrent::mapped(), and QtConcurrent::mappedReduced() accept pointers to member functions. The member function class type must match the type stored in the sequence.

// squeeze all strings in a QStringList
QStringList strings = ...;
QFuture<void> squeezedStrings = QtConcurrent::map(strings, &QString::squeeze);
// swap the rgb values of all pixels on a list of images
QList<QImage> images = ...;
// create a set of the lengths of all strings in a list
QStringList strings = ...;
QFuture<QSet<int> > wordLengths = QtConcurrent::mappedReduced(string, &QString::length, &QSet<int>::insert);

When using QtConcurrent::mappedReduced() you can mix the use of normal and member functions.

// can mix normal functions and member functions with QtConcurrent::mappedReduced()
// compute the average length of a list of strings
extern void computeAverage(int &average, int length);
QStringList strings = ...;
QFuture<int> averageWordLength = QtConcurrent::mappedReduced(strings, &QString::length, computeAverage);
// create a set of the color distribution of all images in a list
extern int colorDistribution(const QImage &string);
QList<QImage> images = ...;
QFuture<QSet<int> > totalColorDistribution = QtConcurrent::mappedReduced(images, colorDistribution, QSet<int>::insert);

Using Function Objects

QtConcurrent::map(), QtConcurrent::mapped(), and QtConcurrent::mappedReduced() accept function objects, which can be used to add state to a function call. The data type result_type must match the return type of the function call operator:

struct Scaled
{
Scaled(int size)
: m_size(size)
{ }
using result_type = QImage;
QImage operator()(const QImage &image)
{
return image.scaled(m_size, m_size);
}
int m_size;
};
QList<QImage> images = ...;
QFuture<QImage> thumbnails = QtConcurrent::mapped(images, Scaled(100));

Using a Lambda Expression

If you want to use a filter function which takes more than one argument use a lambda expression.

As an example, we will use QString::left(). Since QString::left() is a method it can not be used with QtConcurrent::mapped() directly. This is because QtConcurrent::mapped() expects a function which takes one argument.

QStringList strings{ "orange", "pear", "grape", "strawberry"};
QFuture<QStringList> value = QtConcurrent::mapped( strings, [](QString item){ return item.left(3); } );
See also
QtConcurrent::mapped()