mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2024-11-22 02:34:30 +08:00
Implement QPromise<Sequence<T>>::reduce(reducer, initialValue)
Iterates over all the promise values (i.e. `Sequence<T>`) and reduces the sequence to a single value using the given `reducer` function and an optional `initialValue`. Also provide a static helper to directly reduce values (`QtPromise::reduce(values, reducer, initialValue)`).
This commit is contained in:
parent
cbf4cc7867
commit
e3f0f054af
@ -33,6 +33,7 @@ module.exports = {
|
|||||||
'qtpromise/qpromise/ispending',
|
'qtpromise/qpromise/ispending',
|
||||||
'qtpromise/qpromise/isrejected',
|
'qtpromise/qpromise/isrejected',
|
||||||
'qtpromise/qpromise/map',
|
'qtpromise/qpromise/map',
|
||||||
|
'qtpromise/qpromise/reduce',
|
||||||
'qtpromise/qpromise/tap',
|
'qtpromise/qpromise/tap',
|
||||||
'qtpromise/qpromise/tapfail',
|
'qtpromise/qpromise/tapfail',
|
||||||
'qtpromise/qpromise/then',
|
'qtpromise/qpromise/then',
|
||||||
@ -51,6 +52,7 @@ module.exports = {
|
|||||||
'qtpromise/helpers/each',
|
'qtpromise/helpers/each',
|
||||||
'qtpromise/helpers/filter',
|
'qtpromise/helpers/filter',
|
||||||
'qtpromise/helpers/map',
|
'qtpromise/helpers/map',
|
||||||
|
'qtpromise/helpers/reduce',
|
||||||
'qtpromise/helpers/resolve'
|
'qtpromise/helpers/resolve'
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
* [`QPromise<T>::isPending`](qpromise/ispending.md)
|
* [`QPromise<T>::isPending`](qpromise/ispending.md)
|
||||||
* [`QPromise<T>::isRejected`](qpromise/isrejected.md)
|
* [`QPromise<T>::isRejected`](qpromise/isrejected.md)
|
||||||
* [`QPromise<T>::map`](qpromise/map.md)
|
* [`QPromise<T>::map`](qpromise/map.md)
|
||||||
|
* [`QPromise<T>::reduce`](qpromise/reduce.md)
|
||||||
* [`QPromise<T>::tap`](qpromise/tap.md)
|
* [`QPromise<T>::tap`](qpromise/tap.md)
|
||||||
* [`QPromise<T>::tapFail`](qpromise/tapfail.md)
|
* [`QPromise<T>::tapFail`](qpromise/tapfail.md)
|
||||||
* [`QPromise<T>::then`](qpromise/then.md)
|
* [`QPromise<T>::then`](qpromise/then.md)
|
||||||
@ -31,6 +32,7 @@
|
|||||||
* [`QtPromise::each`](helpers/each.md)
|
* [`QtPromise::each`](helpers/each.md)
|
||||||
* [`QtPromise::filter`](helpers/filter.md)
|
* [`QtPromise::filter`](helpers/filter.md)
|
||||||
* [`QtPromise::map`](helpers/map.md)
|
* [`QtPromise::map`](helpers/map.md)
|
||||||
|
* [`QtPromise::reduce`](helpers/reduce.md)
|
||||||
* [`QtPromise::resolve`](helpers/resolve.md)
|
* [`QtPromise::resolve`](helpers/resolve.md)
|
||||||
|
|
||||||
## Exceptions
|
## Exceptions
|
||||||
|
48
docs/qtpromise/helpers/reduce.md
Normal file
48
docs/qtpromise/helpers/reduce.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
title: reduce
|
||||||
|
---
|
||||||
|
|
||||||
|
# QtPromise::reduce
|
||||||
|
|
||||||
|
*Since: 0.5.0*
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QPromise::reduce(Sequence<T|QPromise<T>> values, Reducer reducer) -> QPromise<T>
|
||||||
|
QPromise::reduce(Sequence<T|QPromise<T>> values, Reducer reducer, R|QPromise<R> initialValue) -> QPromise<R>
|
||||||
|
|
||||||
|
// With:
|
||||||
|
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||||
|
// - Reducer: Function(T|R accumulator, T item, int index) -> R|QPromise<R>
|
||||||
|
```
|
||||||
|
|
||||||
|
Iterates over `values` and [reduces the sequence to a single value](https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29) using the given `reducer` function and an optional `initialValue`. The type returned by `reducer` determines the type of the `output` promise. If `reducer` throws, `output` is rejected with the new exception.
|
||||||
|
|
||||||
|
If `reducer` returns a promise (or `QFuture`), then the result of the promise is awaited, before continuing with next iteration. If any promise in the `values` sequence is rejected or a promise returned by the `reducer` function is rejected, `output` immediately rejects with the error of the promise that rejected.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// Concatenate the content of the given files, read asynchronously
|
||||||
|
auto output = QtPromise::reduce(QList<QUrl>{
|
||||||
|
"file:f0.txt", // contains "foo"
|
||||||
|
"file:f1.txt", // contains "bar"
|
||||||
|
"file:f2.txt" // contains "42"
|
||||||
|
}, [](const QString& acc, const QString& cur, int idx) {
|
||||||
|
return readAsync(cur).then([=](const QString& res) {
|
||||||
|
return QString("%1;%2:%3").arg(acc).arg(idx).arg(res);
|
||||||
|
});
|
||||||
|
}, QString("index:text"));
|
||||||
|
|
||||||
|
// 'output' resolves as soon as all promises returned by
|
||||||
|
// 'reducer' are fulfilled or at least one is rejected.
|
||||||
|
|
||||||
|
// 'output' type: QPromise<QString>
|
||||||
|
output.then([](const QString& res) {
|
||||||
|
// res == "index:text;0:foo;1:bar;2:42"
|
||||||
|
// {...}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
::: warning IMPORTANT
|
||||||
|
The first time `reducer` is called, if no `initialValue` is provided, `accumulator` will be equal to the first value in the sequence, and `currentValue` to the second one (thus index will be `1`).
|
||||||
|
:::
|
||||||
|
|
||||||
|
See also: [`QPromise<T>::reduce`](../qpromise/reduce.md)
|
58
docs/qtpromise/qpromise/reduce.md
Normal file
58
docs/qtpromise/qpromise/reduce.md
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
title: .reduce
|
||||||
|
---
|
||||||
|
|
||||||
|
# QPromise::reduce
|
||||||
|
|
||||||
|
*Since: 0.5.0*
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QPromise<Sequence<T>>::reduce(Reducer reducer) -> QPromise<T>
|
||||||
|
QPromise<Sequence<T>>::reduce(Reducer reducer, R|QPromise<R> initialValue) -> QPromise<R>
|
||||||
|
|
||||||
|
// With:
|
||||||
|
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||||
|
// - Reducer: Function(T|R accumulator, T item, int index) -> R|QPromise<R>
|
||||||
|
```
|
||||||
|
|
||||||
|
::: warning IMPORTANT
|
||||||
|
This method only applies to promise with sequence value.
|
||||||
|
:::
|
||||||
|
|
||||||
|
Iterates over all the promise values (i.e. `Sequence<T>`) and [reduces the sequence to a single value](https://en.wikipedia.org/wiki/Fold_%28higher-order_function%29) using the given `reducer` function and an optional `initialValue`. The type returned by `reducer` determines the type of the `output` promise.
|
||||||
|
|
||||||
|
See [`QtPromise::reduce`](../helpers/reduce.md) for details, this method is provided for convenience and is similar to:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
promise.then([](const T& values) {
|
||||||
|
return QtPromise::reduce(values, reducer, initialValue);
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto input = QtPromise::resolve(QList<QUrl>{
|
||||||
|
"file:f0.txt", // contains "foo"
|
||||||
|
"file:f1.txt", // contains "bar"
|
||||||
|
"file:f2.txt" // contains "42"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Concatenate the content of the given files, read asynchronously
|
||||||
|
auto output = input.reduce([](const QString& acc, const QString& cur, int idx) {
|
||||||
|
return readAsync(cur).then([=](const QString& res) {
|
||||||
|
return QString("%1;%2:%3").arg(acc).arg(idx).arg(res);
|
||||||
|
});
|
||||||
|
}, QString("index:text"));
|
||||||
|
|
||||||
|
// 'output' resolves as soon as all promises returned by
|
||||||
|
// 'reducer' are fulfilled or at least one is rejected.
|
||||||
|
|
||||||
|
// 'output' type: QPromise<QString>
|
||||||
|
output.then([](const QString& res) {
|
||||||
|
// res == "index:text;0:foo;1:bar;2:42"
|
||||||
|
// {...}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
See also: [`QtPromise::reduce`](../helpers/reduce.md)
|
@ -46,7 +46,7 @@ The `output` promise is resolved when the `QFuture` is [finished](https://doc.qt
|
|||||||
|
|
||||||
## Error
|
## Error
|
||||||
|
|
||||||
Exceptions thrown from a QtConcurrent thread reject the associated promise with the exception as the reason. Note that if you throw an exception that is not a subclass of `QException`, the promise with be rejected with [`QUnhandledException`](https://doc.qt.io/qt-5/qunhandledexception.html#details) (this restriction only applies to exceptions thrown from a QtConcurrent thread, [read more](https://doc.qt.io/qt-5/qexception.html#details)).
|
Exceptions thrown from a QtConcurrent thread reject the associated promise with the exception as the reason. Note that if you throw an exception that is not a subclass of `QException`, the promise will be rejected with [`QUnhandledException`](https://doc.qt.io/qt-5/qunhandledexception.html#details) (this restriction only applies to exceptions thrown from a QtConcurrent thread, [read more](https://doc.qt.io/qt-5/qexception.html#details)).
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
QPromise<int> promise = ...
|
QPromise<int> promise = ...
|
||||||
|
@ -76,6 +76,7 @@ public: // STATIC
|
|||||||
protected:
|
protected:
|
||||||
friend struct QtPromisePrivate::PromiseFulfill<QPromise<T>>;
|
friend struct QtPromisePrivate::PromiseFulfill<QPromise<T>>;
|
||||||
friend class QtPromisePrivate::PromiseResolver<T>;
|
friend class QtPromisePrivate::PromiseResolver<T>;
|
||||||
|
friend struct QtPromisePrivate::PromiseInspect;
|
||||||
|
|
||||||
QExplicitlySharedDataPointer<QtPromisePrivate::PromiseData<T>> m_d;
|
QExplicitlySharedDataPointer<QtPromisePrivate::PromiseData<T>> m_d;
|
||||||
};
|
};
|
||||||
@ -88,15 +89,25 @@ public:
|
|||||||
QPromise(F&& resolver): QPromiseBase<T>(std::forward<F>(resolver)) { }
|
QPromise(F&& resolver): QPromiseBase<T>(std::forward<F>(resolver)) { }
|
||||||
|
|
||||||
template <typename Functor>
|
template <typename Functor>
|
||||||
inline QPromise<T> each(Functor fn);
|
inline QPromise<T>
|
||||||
|
each(Functor fn);
|
||||||
|
|
||||||
template <typename Functor>
|
template <typename Functor>
|
||||||
inline QPromise<T> filter(Functor fn);
|
inline QPromise<T>
|
||||||
|
filter(Functor fn);
|
||||||
|
|
||||||
template <typename Functor>
|
template <typename Functor>
|
||||||
inline typename QtPromisePrivate::PromiseMapper<T, Functor>::PromiseType
|
inline typename QtPromisePrivate::PromiseMapper<T, Functor>::PromiseType
|
||||||
map(Functor fn);
|
map(Functor fn);
|
||||||
|
|
||||||
|
template <typename Functor, typename Input>
|
||||||
|
inline typename QtPromisePrivate::PromiseDeduce<Input>::Type
|
||||||
|
reduce(Functor fn, Input initial);
|
||||||
|
|
||||||
|
template <typename Functor, typename U = T>
|
||||||
|
inline typename QtPromisePrivate::PromiseDeduce<typename U::value_type>::Type
|
||||||
|
reduce(Functor fn);
|
||||||
|
|
||||||
public: // STATIC
|
public: // STATIC
|
||||||
|
|
||||||
// DEPRECATED (remove at version 1)
|
// DEPRECATED (remove at version 1)
|
||||||
|
@ -197,6 +197,26 @@ QPromise<T>::map(Functor fn)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
template <typename Functor, typename Input>
|
||||||
|
inline typename QtPromisePrivate::PromiseDeduce<Input>::Type
|
||||||
|
QPromise<T>::reduce(Functor fn, Input initial)
|
||||||
|
{
|
||||||
|
return this->then([=](const T& values) {
|
||||||
|
return QtPromise::reduce(values, fn, initial);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
template <typename Functor, typename U>
|
||||||
|
inline typename QtPromisePrivate::PromiseDeduce<typename U::value_type>::Type
|
||||||
|
QPromise<T>::reduce(Functor fn)
|
||||||
|
{
|
||||||
|
return this->then([=](const T& values) {
|
||||||
|
return QtPromise::reduce(values, fn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
template <template <typename, typename...> class Sequence, typename ...Args>
|
template <template <typename, typename...> class Sequence, typename ...Args>
|
||||||
inline QPromise<QVector<T>> QPromise<T>::all(const Sequence<QPromise<T>, Args...>& promises)
|
inline QPromise<QVector<T>> QPromise<T>::all(const Sequence<QPromise<T>, Args...>& promises)
|
||||||
|
@ -558,6 +558,15 @@ protected:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace QtPromise
|
struct PromiseInspect
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
static inline PromiseData<T>* get(const QtPromise::QPromise<T>& p)
|
||||||
|
{
|
||||||
|
return p.m_d.data();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QtPromisePrivate
|
||||||
|
|
||||||
#endif // QTPROMISE_QPROMISE_H
|
#endif // QTPROMISE_QPROMISE_H
|
||||||
|
@ -169,7 +169,8 @@ connect(const Sender* sender, FSignal fsignal, RSignal rsignal)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Sequence, typename Functor>
|
template <typename Sequence, typename Functor>
|
||||||
static inline QPromise<Sequence> each(const Sequence& values, Functor&& fn)
|
static inline QPromise<Sequence>
|
||||||
|
each(const Sequence& values, Functor&& fn)
|
||||||
{
|
{
|
||||||
return QPromise<Sequence>::resolve(values).each(std::forward<Functor>(fn));
|
return QPromise<Sequence>::resolve(values).each(std::forward<Functor>(fn));
|
||||||
}
|
}
|
||||||
@ -200,7 +201,8 @@ map(const Sequence& values, Functor fn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Sequence, typename Functor>
|
template <typename Sequence, typename Functor>
|
||||||
static inline QPromise<Sequence> filter(const Sequence& values, Functor fn)
|
static inline QPromise<Sequence>
|
||||||
|
filter(const Sequence& values, Functor fn)
|
||||||
{
|
{
|
||||||
return QtPromise::map(values, fn)
|
return QtPromise::map(values, fn)
|
||||||
.then([=](const QVector<bool>& filters) {
|
.then([=](const QVector<bool>& filters) {
|
||||||
@ -219,6 +221,59 @@ static inline QPromise<Sequence> filter(const Sequence& values, Functor fn)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, template <typename...> class Sequence = QVector, typename Reducer, typename Input, typename ...Args>
|
||||||
|
static inline typename QtPromisePrivate::PromiseDeduce<Input>::Type
|
||||||
|
reduce(const Sequence<T, Args...>& values, Reducer fn, Input initial)
|
||||||
|
{
|
||||||
|
using namespace QtPromisePrivate;
|
||||||
|
using PromiseType = typename PromiseDeduce<T>::Type;
|
||||||
|
using ValueType = typename PromiseType::Type;
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
auto promise = QtPromise::resolve(std::move(initial));
|
||||||
|
for (const auto& value : values) {
|
||||||
|
auto input = QtPromise::resolve(value);
|
||||||
|
promise = promise.then([=]() {
|
||||||
|
return input.then([=](const ValueType& cur) {
|
||||||
|
return fn(PromiseInspect::get(promise)->value().data(), cur, idx);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, template <typename...> class Sequence = QVector, typename Reducer, typename ...Args>
|
||||||
|
static inline typename QtPromisePrivate::PromiseDeduce<T>::Type
|
||||||
|
reduce(const Sequence<T, Args...>& values, Reducer fn)
|
||||||
|
{
|
||||||
|
using namespace QtPromisePrivate;
|
||||||
|
using PromiseType = typename PromiseDeduce<T>::Type;
|
||||||
|
using ValueType = typename PromiseType::Type;
|
||||||
|
|
||||||
|
Q_ASSERT(values.size());
|
||||||
|
|
||||||
|
int idx = 1;
|
||||||
|
|
||||||
|
auto it = values.begin();
|
||||||
|
auto promise = QtPromise::resolve(*it);
|
||||||
|
for (++it; it != values.end(); ++it) {
|
||||||
|
auto input = QtPromise::resolve(*it);
|
||||||
|
promise = promise.then([=]() {
|
||||||
|
return input.then([=](const ValueType& cur) {
|
||||||
|
return fn(PromiseInspect::get(promise)->value().data(), cur, idx);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
// DEPRECATIONS (remove at version 1)
|
// DEPRECATIONS (remove at version 1)
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
|
@ -6,5 +6,6 @@ SUBDIRS += \
|
|||||||
each \
|
each \
|
||||||
filter \
|
filter \
|
||||||
map \
|
map \
|
||||||
|
reduce \
|
||||||
reject \
|
reject \
|
||||||
resolve
|
resolve
|
||||||
|
4
tests/auto/qtpromise/helpers/reduce/reduce.pro
Normal file
4
tests/auto/qtpromise/helpers/reduce/reduce.pro
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
TARGET = tst_helpers_reduce
|
||||||
|
SOURCES += $$PWD/tst_reduce.cpp
|
||||||
|
|
||||||
|
include(../../qtpromise.pri)
|
271
tests/auto/qtpromise/helpers/reduce/tst_reduce.cpp
Normal file
271
tests/auto/qtpromise/helpers/reduce/tst_reduce.cpp
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
#include "../../shared/data.h"
|
||||||
|
#include "../../shared/utils.h"
|
||||||
|
|
||||||
|
// QtPromise
|
||||||
|
#include <QtPromise>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
using namespace QtPromise;
|
||||||
|
|
||||||
|
class tst_helpers_reduce : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void emptySequence();
|
||||||
|
void regularValues();
|
||||||
|
void promiseValues();
|
||||||
|
void convertResultType();
|
||||||
|
void delayedInitialValue();
|
||||||
|
void delayedFulfilled();
|
||||||
|
void delayedRejected();
|
||||||
|
void functorThrows();
|
||||||
|
void sequenceTypes();
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_MAIN(tst_helpers_reduce)
|
||||||
|
#include "tst_reduce.moc"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <class Sequence>
|
||||||
|
struct SequenceTester
|
||||||
|
{
|
||||||
|
static void exec()
|
||||||
|
{
|
||||||
|
Sequence inputs{
|
||||||
|
QtPromise::resolve(4).delay(400),
|
||||||
|
QtPromise::resolve(6).delay(300),
|
||||||
|
QtPromise::resolve(8).delay(200)
|
||||||
|
};
|
||||||
|
QVector<int> v0;
|
||||||
|
QVector<int> v1;
|
||||||
|
|
||||||
|
auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||||
|
v0 << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
});
|
||||||
|
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||||
|
v1 << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
}, QtPromise::resolve(2).delay(100));
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p0.isPending(), true);
|
||||||
|
QCOMPARE(p1.isPending(), true);
|
||||||
|
QCOMPARE(waitForValue(p0, -1), 21);
|
||||||
|
QCOMPARE(waitForValue(p1, -1), 23);
|
||||||
|
QCOMPARE(v0, QVector<int>({4, 6, 1, 11, 8, 2}));
|
||||||
|
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
void tst_helpers_reduce::emptySequence()
|
||||||
|
{
|
||||||
|
bool called = false;
|
||||||
|
|
||||||
|
auto p = QtPromise::reduce(QVector<int>{}, [&](...) {
|
||||||
|
called = true;
|
||||||
|
return 43;
|
||||||
|
}, 42);
|
||||||
|
|
||||||
|
// NOTE(SB): reduce() on an empty sequence without an initial value is an error!
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, -1), 42);
|
||||||
|
QCOMPARE(called, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_reduce::regularValues()
|
||||||
|
{
|
||||||
|
QVector<int> inputs{4, 6, 8};
|
||||||
|
QVector<int> v0;
|
||||||
|
QVector<int> v1;
|
||||||
|
|
||||||
|
auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||||
|
v0 << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
});
|
||||||
|
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||||
|
v1 << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
}, 2);
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p0.isPending(), true);
|
||||||
|
QCOMPARE(p1.isPending(), true);
|
||||||
|
QCOMPARE(waitForValue(p0, -1), 21);
|
||||||
|
QCOMPARE(waitForValue(p1, -1), 23);
|
||||||
|
QCOMPARE(v0, QVector<int>({4, 6, 1, 11, 8, 2}));
|
||||||
|
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_reduce::promiseValues()
|
||||||
|
{
|
||||||
|
QVector<QPromise<int>> inputs{
|
||||||
|
QtPromise::resolve(4).delay(400),
|
||||||
|
QtPromise::resolve(6).delay(300),
|
||||||
|
QtPromise::resolve(8).delay(200)
|
||||||
|
};
|
||||||
|
QVector<int> v0;
|
||||||
|
QVector<int> v1;
|
||||||
|
|
||||||
|
auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||||
|
v0 << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
});
|
||||||
|
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||||
|
v1 << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
}, 2);
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p0.isPending(), true);
|
||||||
|
QCOMPARE(p1.isPending(), true);
|
||||||
|
QCOMPARE(waitForValue(p0, -1), 21);
|
||||||
|
QCOMPARE(waitForValue(p1, -1), 23);
|
||||||
|
QCOMPARE(v0, QVector<int>({4, 6, 1, 11, 8, 2}));
|
||||||
|
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_reduce::convertResultType()
|
||||||
|
{
|
||||||
|
QVector<int> inputs{4, 6, 8};
|
||||||
|
|
||||||
|
auto p = QtPromise::reduce(inputs, [&](const QString& acc, int cur, int idx) {
|
||||||
|
return QString("%1:%2:%3").arg(acc).arg(cur).arg(idx);
|
||||||
|
}, QString("foo"));
|
||||||
|
|
||||||
|
// NOTE(SB): when no initial value is given, the result type is the sequence type.
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p.isPending(), true);
|
||||||
|
QCOMPARE(waitForValue(p, QString()), QString("foo:4:0:6:1:8:2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_reduce::delayedInitialValue()
|
||||||
|
{
|
||||||
|
QVector<int> values;
|
||||||
|
|
||||||
|
auto p = QtPromise::reduce(QVector<int>{4, 6, 8}, [&](int acc, int cur, int idx) {
|
||||||
|
values << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
}, QtPromise::resolve(2).delay(100));
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p.isPending(), true);
|
||||||
|
QCOMPARE(waitForValue(p, -1), 23);
|
||||||
|
QCOMPARE(values, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_reduce::delayedFulfilled()
|
||||||
|
{
|
||||||
|
QVector<int> inputs{4, 6, 8};
|
||||||
|
QVector<int> v0;
|
||||||
|
QVector<int> v1;
|
||||||
|
|
||||||
|
auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||||
|
v0 << acc << cur << idx;
|
||||||
|
return QtPromise::resolve(acc + cur + idx).delay(100);
|
||||||
|
});
|
||||||
|
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||||
|
v1 << acc << cur << idx;
|
||||||
|
return QtPromise::resolve(acc + cur + idx).delay(100);
|
||||||
|
}, 2);
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p0.isPending(), true);
|
||||||
|
QCOMPARE(p1.isPending(), true);
|
||||||
|
QCOMPARE(waitForValue(p0, -1), 21);
|
||||||
|
QCOMPARE(waitForValue(p1, -1), 23);
|
||||||
|
QCOMPARE(v0, QVector<int>({4, 6, 1, 11, 8, 2}));
|
||||||
|
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_reduce::delayedRejected()
|
||||||
|
{
|
||||||
|
QVector<int> inputs{4, 6, 8};
|
||||||
|
QVector<int> v0;
|
||||||
|
QVector<int> v1;
|
||||||
|
|
||||||
|
auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||||
|
v0 << acc << cur << idx;
|
||||||
|
if (cur == 6) {
|
||||||
|
return QPromise<int>::reject(QString("foo"));
|
||||||
|
}
|
||||||
|
return QtPromise::resolve(acc + cur + idx);
|
||||||
|
});
|
||||||
|
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||||
|
v1 << acc << cur << idx;
|
||||||
|
if (cur == 6) {
|
||||||
|
return QPromise<int>::reject(QString("bar"));
|
||||||
|
}
|
||||||
|
return QtPromise::resolve(acc + cur + idx);
|
||||||
|
}, 2);
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p0.isPending(), true);
|
||||||
|
QCOMPARE(p1.isPending(), true);
|
||||||
|
QCOMPARE(waitForError(p0, QString()), QString("foo"));
|
||||||
|
QCOMPARE(waitForError(p1, QString()), QString("bar"));
|
||||||
|
QCOMPARE(v0, QVector<int>({4, 6, 1}));
|
||||||
|
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_reduce::functorThrows()
|
||||||
|
{
|
||||||
|
QVector<int> inputs{4, 6, 8};
|
||||||
|
QVector<int> v0;
|
||||||
|
QVector<int> v1;
|
||||||
|
|
||||||
|
auto p0 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||||
|
v0 << acc << cur << idx;
|
||||||
|
if (cur == 6) {
|
||||||
|
throw QString("foo");
|
||||||
|
}
|
||||||
|
return acc + cur + idx;
|
||||||
|
});
|
||||||
|
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) {
|
||||||
|
v1 << acc << cur << idx;
|
||||||
|
if (cur == 6) {
|
||||||
|
throw QString("bar");
|
||||||
|
}
|
||||||
|
return acc + cur + idx;
|
||||||
|
}, 2);
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p0.isPending(), true);
|
||||||
|
QCOMPARE(p1.isPending(), true);
|
||||||
|
QCOMPARE(waitForError(p0, QString()), QString("foo"));
|
||||||
|
QCOMPARE(waitForError(p1, QString()), QString("bar"));
|
||||||
|
QCOMPARE(v0, QVector<int>({4, 6, 1}));
|
||||||
|
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_reduce::sequenceTypes()
|
||||||
|
{
|
||||||
|
SequenceTester<QLinkedList<QPromise<int>>>::exec();
|
||||||
|
SequenceTester<QList<QPromise<int>>>::exec();
|
||||||
|
SequenceTester<QVector<QPromise<int>>>::exec();
|
||||||
|
SequenceTester<std::list<QPromise<int>>>::exec();
|
||||||
|
SequenceTester<std::vector<QPromise<int>>>::exec();
|
||||||
|
}
|
@ -8,6 +8,7 @@ SUBDIRS += \
|
|||||||
finally \
|
finally \
|
||||||
map \
|
map \
|
||||||
operators \
|
operators \
|
||||||
|
reduce \
|
||||||
resolve \
|
resolve \
|
||||||
tap \
|
tap \
|
||||||
tapfail \
|
tapfail \
|
||||||
|
4
tests/auto/qtpromise/qpromise/reduce/reduce.pro
Normal file
4
tests/auto/qtpromise/qpromise/reduce/reduce.pro
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
TARGET = tst_qpromise_reduce
|
||||||
|
SOURCES += $$PWD/tst_reduce.cpp
|
||||||
|
|
||||||
|
include(../../qtpromise.pri)
|
271
tests/auto/qtpromise/qpromise/reduce/tst_reduce.cpp
Normal file
271
tests/auto/qtpromise/qpromise/reduce/tst_reduce.cpp
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
#include "../../shared/data.h"
|
||||||
|
#include "../../shared/utils.h"
|
||||||
|
|
||||||
|
// QtPromise
|
||||||
|
#include <QtPromise>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
using namespace QtPromise;
|
||||||
|
|
||||||
|
class tst_qpromise_reduce : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void emptySequence();
|
||||||
|
void regularValues();
|
||||||
|
void promiseValues();
|
||||||
|
void convertResultType();
|
||||||
|
void delayedInitialValue();
|
||||||
|
void delayedFulfilled();
|
||||||
|
void delayedRejected();
|
||||||
|
void functorThrows();
|
||||||
|
void sequenceTypes();
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_MAIN(tst_qpromise_reduce)
|
||||||
|
#include "tst_reduce.moc"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <class Sequence>
|
||||||
|
struct SequenceTester
|
||||||
|
{
|
||||||
|
static void exec()
|
||||||
|
{
|
||||||
|
Sequence inputs{
|
||||||
|
QtPromise::resolve(4).delay(400),
|
||||||
|
QtPromise::resolve(6).delay(300),
|
||||||
|
QtPromise::resolve(8).delay(200)
|
||||||
|
};
|
||||||
|
QVector<int> v0;
|
||||||
|
QVector<int> v1;
|
||||||
|
|
||||||
|
auto p0 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) {
|
||||||
|
v0 << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
});
|
||||||
|
auto p1 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) {
|
||||||
|
v1 << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
}, QtPromise::resolve(2).delay(100));
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p0.isPending(), true);
|
||||||
|
QCOMPARE(p1.isPending(), true);
|
||||||
|
QCOMPARE(waitForValue(p0, -1), 21);
|
||||||
|
QCOMPARE(waitForValue(p1, -1), 23);
|
||||||
|
QCOMPARE(v0, QVector<int>({4, 6, 1, 11, 8, 2}));
|
||||||
|
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
void tst_qpromise_reduce::emptySequence()
|
||||||
|
{
|
||||||
|
bool called = false;
|
||||||
|
|
||||||
|
auto p = QtPromise::resolve(QVector<int>{}).reduce([&](...) {
|
||||||
|
called = true;
|
||||||
|
return 43;
|
||||||
|
}, 42);
|
||||||
|
|
||||||
|
// NOTE(SB): reduce() on an empty sequence without an initial value is an error!
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(waitForValue(p, -1), 42);
|
||||||
|
QCOMPARE(called, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_reduce::regularValues()
|
||||||
|
{
|
||||||
|
QVector<int> inputs{4, 6, 8};
|
||||||
|
QVector<int> v0;
|
||||||
|
QVector<int> v1;
|
||||||
|
|
||||||
|
auto p0 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) {
|
||||||
|
v0 << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
});
|
||||||
|
auto p1 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) {
|
||||||
|
v1 << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
}, 2);
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p0.isPending(), true);
|
||||||
|
QCOMPARE(p1.isPending(), true);
|
||||||
|
QCOMPARE(waitForValue(p0, -1), 21);
|
||||||
|
QCOMPARE(waitForValue(p1, -1), 23);
|
||||||
|
QCOMPARE(v0, QVector<int>({4, 6, 1, 11, 8, 2}));
|
||||||
|
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_reduce::promiseValues()
|
||||||
|
{
|
||||||
|
QVector<QPromise<int>> inputs{
|
||||||
|
QtPromise::resolve(4).delay(400),
|
||||||
|
QtPromise::resolve(6).delay(300),
|
||||||
|
QtPromise::resolve(8).delay(200)
|
||||||
|
};
|
||||||
|
QVector<int> v0;
|
||||||
|
QVector<int> v1;
|
||||||
|
|
||||||
|
auto p0 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) {
|
||||||
|
v0 << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
});
|
||||||
|
auto p1 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) {
|
||||||
|
v1 << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
}, 2);
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p0.isPending(), true);
|
||||||
|
QCOMPARE(p1.isPending(), true);
|
||||||
|
QCOMPARE(waitForValue(p0, -1), 21);
|
||||||
|
QCOMPARE(waitForValue(p1, -1), 23);
|
||||||
|
QCOMPARE(v0, QVector<int>({4, 6, 1, 11, 8, 2}));
|
||||||
|
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_reduce::convertResultType()
|
||||||
|
{
|
||||||
|
QVector<int> inputs{4, 6, 8};
|
||||||
|
|
||||||
|
auto p = QtPromise::resolve(inputs).reduce([&](const QString& acc, int cur, int idx) {
|
||||||
|
return QString("%1:%2:%3").arg(acc).arg(cur).arg(idx);
|
||||||
|
}, QString("foo"));
|
||||||
|
|
||||||
|
// NOTE(SB): when no initial value is given, the result type is the sequence type.
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p.isPending(), true);
|
||||||
|
QCOMPARE(waitForValue(p, QString()), QString("foo:4:0:6:1:8:2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_reduce::delayedInitialValue()
|
||||||
|
{
|
||||||
|
QVector<int> values;
|
||||||
|
|
||||||
|
auto p = QtPromise::resolve(QVector<int>{4, 6, 8}).reduce([&](int acc, int cur, int idx) {
|
||||||
|
values << acc << cur << idx;
|
||||||
|
return acc + cur + idx;
|
||||||
|
}, QtPromise::resolve(2).delay(100));
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p.isPending(), true);
|
||||||
|
QCOMPARE(waitForValue(p, -1), 23);
|
||||||
|
QCOMPARE(values, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_reduce::delayedFulfilled()
|
||||||
|
{
|
||||||
|
QVector<int> inputs{4, 6, 8};
|
||||||
|
QVector<int> v0;
|
||||||
|
QVector<int> v1;
|
||||||
|
|
||||||
|
auto p0 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) {
|
||||||
|
v0 << acc << cur << idx;
|
||||||
|
return QtPromise::resolve(acc + cur + idx).delay(100);
|
||||||
|
});
|
||||||
|
auto p1 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) {
|
||||||
|
v1 << acc << cur << idx;
|
||||||
|
return QtPromise::resolve(acc + cur + idx).delay(100);
|
||||||
|
}, 2);
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p0.isPending(), true);
|
||||||
|
QCOMPARE(p1.isPending(), true);
|
||||||
|
QCOMPARE(waitForValue(p0, -1), 21);
|
||||||
|
QCOMPARE(waitForValue(p1, -1), 23);
|
||||||
|
QCOMPARE(v0, QVector<int>({4, 6, 1, 11, 8, 2}));
|
||||||
|
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1, 13, 8, 2}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_reduce::delayedRejected()
|
||||||
|
{
|
||||||
|
QVector<int> inputs{4, 6, 8};
|
||||||
|
QVector<int> v0;
|
||||||
|
QVector<int> v1;
|
||||||
|
|
||||||
|
auto p0 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) {
|
||||||
|
v0 << acc << cur << idx;
|
||||||
|
if (cur == 6) {
|
||||||
|
return QPromise<int>::reject(QString("foo"));
|
||||||
|
}
|
||||||
|
return QtPromise::resolve(acc + cur + idx);
|
||||||
|
});
|
||||||
|
auto p1 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) {
|
||||||
|
v1 << acc << cur << idx;
|
||||||
|
if (cur == 6) {
|
||||||
|
return QPromise<int>::reject(QString("bar"));
|
||||||
|
}
|
||||||
|
return QtPromise::resolve(acc + cur + idx);
|
||||||
|
}, 2);
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p0.isPending(), true);
|
||||||
|
QCOMPARE(p1.isPending(), true);
|
||||||
|
QCOMPARE(waitForError(p0, QString()), QString("foo"));
|
||||||
|
QCOMPARE(waitForError(p1, QString()), QString("bar"));
|
||||||
|
QCOMPARE(v0, QVector<int>({4, 6, 1}));
|
||||||
|
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_reduce::functorThrows()
|
||||||
|
{
|
||||||
|
QVector<int> inputs{4, 6, 8};
|
||||||
|
QVector<int> v0;
|
||||||
|
QVector<int> v1;
|
||||||
|
|
||||||
|
auto p0 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) {
|
||||||
|
v0 << acc << cur << idx;
|
||||||
|
if (cur == 6) {
|
||||||
|
throw QString("foo");
|
||||||
|
}
|
||||||
|
return acc + cur + idx;
|
||||||
|
});
|
||||||
|
auto p1 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) {
|
||||||
|
v1 << acc << cur << idx;
|
||||||
|
if (cur == 6) {
|
||||||
|
throw QString("bar");
|
||||||
|
}
|
||||||
|
return acc + cur + idx;
|
||||||
|
}, 2);
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
|
||||||
|
|
||||||
|
QCOMPARE(p0.isPending(), true);
|
||||||
|
QCOMPARE(p1.isPending(), true);
|
||||||
|
QCOMPARE(waitForError(p0, QString()), QString("foo"));
|
||||||
|
QCOMPARE(waitForError(p1, QString()), QString("bar"));
|
||||||
|
QCOMPARE(v0, QVector<int>({4, 6, 1}));
|
||||||
|
QCOMPARE(v1, QVector<int>({2, 4, 0, 6, 6, 1}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_reduce::sequenceTypes()
|
||||||
|
{
|
||||||
|
SequenceTester<QLinkedList<QPromise<int>>>::exec();
|
||||||
|
SequenceTester<QList<QPromise<int>>>::exec();
|
||||||
|
SequenceTester<QVector<QPromise<int>>>::exec();
|
||||||
|
SequenceTester<std::list<QPromise<int>>>::exec();
|
||||||
|
SequenceTester<std::vector<QPromise<int>>>::exec();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user