mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2024-11-21 18:24:29 +08:00
Implement QPromise<Sequence<T>>::filter(filterer)
Add a new method that iterates over all the promise values (i.e. `Sequence<T>`) and filters the sequence to another using the given `filterer` function. If `filterer` returns `true`, a copy of the item is put in the `output` sequence, otherwise, the item will not appear in `output`. Also provide a static helper to directly filter values (`QtPromise::filter(values, filterer)`).
This commit is contained in:
parent
69c07855f4
commit
4fa7a37750
@ -6,6 +6,7 @@
|
|||||||
* [QPromise](qtpromise/qpromise/constructor.md)
|
* [QPromise](qtpromise/qpromise/constructor.md)
|
||||||
* [.delay](qtpromise/qpromise/delay.md)
|
* [.delay](qtpromise/qpromise/delay.md)
|
||||||
* [.fail](qtpromise/qpromise/fail.md)
|
* [.fail](qtpromise/qpromise/fail.md)
|
||||||
|
* [.filter](qtpromise/qpromise/filter.md)
|
||||||
* [.finally](qtpromise/qpromise/finally.md)
|
* [.finally](qtpromise/qpromise/finally.md)
|
||||||
* [.isFulfilled](qtpromise/qpromise/isfulfilled.md)
|
* [.isFulfilled](qtpromise/qpromise/isfulfilled.md)
|
||||||
* [.isPending](qtpromise/qpromise/ispending.md)
|
* [.isPending](qtpromise/qpromise/ispending.md)
|
||||||
@ -21,4 +22,5 @@
|
|||||||
* [::resolve (static)](qtpromise/qpromise/resolve.md)
|
* [::resolve (static)](qtpromise/qpromise/resolve.md)
|
||||||
* [qPromise](qtpromise/helpers/qpromise.md)
|
* [qPromise](qtpromise/helpers/qpromise.md)
|
||||||
* [qPromiseAll](qtpromise/helpers/qpromiseall.md)
|
* [qPromiseAll](qtpromise/helpers/qpromiseall.md)
|
||||||
|
* [QtPromise::filter](qtpromise/helpers/filter.md)
|
||||||
* [QtPromise::map](qtpromise/helpers/map.md)
|
* [QtPromise::map](qtpromise/helpers/map.md)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
* [`QPromise<T>::QPromise`](qpromise/constructor.md)
|
* [`QPromise<T>::QPromise`](qpromise/constructor.md)
|
||||||
* [`QPromise<T>::delay`](qpromise/delay.md)
|
* [`QPromise<T>::delay`](qpromise/delay.md)
|
||||||
* [`QPromise<T>::fail`](qpromise/fail.md)
|
* [`QPromise<T>::fail`](qpromise/fail.md)
|
||||||
|
* [`QPromise<T>::filter`](qpromise/filter.md)
|
||||||
* [`QPromise<T>::finally`](qpromise/finally.md)
|
* [`QPromise<T>::finally`](qpromise/finally.md)
|
||||||
* [`QPromise<T>::isFulfilled`](qpromise/isfulfilled.md)
|
* [`QPromise<T>::isFulfilled`](qpromise/isfulfilled.md)
|
||||||
* [`QPromise<T>::isPending`](qpromise/ispending.md)
|
* [`QPromise<T>::isPending`](qpromise/ispending.md)
|
||||||
@ -26,4 +27,5 @@
|
|||||||
|
|
||||||
* [`qPromise`](helpers/qpromise.md)
|
* [`qPromise`](helpers/qpromise.md)
|
||||||
* [`qPromiseAll`](helpers/qpromiseall.md)
|
* [`qPromiseAll`](helpers/qpromiseall.md)
|
||||||
|
* [`QtPromise::filter`](helpers/filter.md)
|
||||||
* [`QtPromise::map`](helpers/map.md)
|
* [`QtPromise::map`](helpers/map.md)
|
||||||
|
44
docs/qtpromise/helpers/filter.md
Normal file
44
docs/qtpromise/helpers/filter.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
## `QtPromise::filter`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QtPromise::filter(Sequence<T> values, Filterer filterer) -> QPromise<Sequence<T>>
|
||||||
|
|
||||||
|
// With:
|
||||||
|
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||||
|
// - Filterer: Function(T value, int index) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Iterates over `values` and [filters the sequence](https://en.wikipedia.org/wiki/Filter_%28higher-order_function%29)
|
||||||
|
to another using the given `filterer` function. If `filterer` returns `true`, a copy of the item
|
||||||
|
is put in the `output` sequence, otherwise, the item will not appear in `output`. If `filterer`
|
||||||
|
throws, `output` is rejected with the new exception.
|
||||||
|
|
||||||
|
If `filterer` returns a promise (or `QFuture`), the `output` promise is delayed until all the
|
||||||
|
promises are resolved. If any of the promises fail, `output` immediately rejects with the error
|
||||||
|
of the promise that rejected, whether or not the other promises are resolved.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto output = QtPromise::filter(QVector{
|
||||||
|
QUrl("http://a..."),
|
||||||
|
QUrl("http://b..."),
|
||||||
|
QUrl("http://c...")
|
||||||
|
}, [](const QUrl& url, ...) {
|
||||||
|
return QPromise<bool>([&](auto resolve, auto reject) {
|
||||||
|
// resolve(true) if 'url' is reachable, else resolve(false)
|
||||||
|
// {...}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 'output' resolves as soon as all promises returned by
|
||||||
|
// 'filterer' are fulfilled or at least one is rejected.
|
||||||
|
|
||||||
|
// 'output' type: QPromise<QVector<QUrl>>
|
||||||
|
output.then([](const QVector<QUrl>& res) {
|
||||||
|
// 'res' contains only reachable URLs
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note:** the order of the output sequence values is guarantee to be the same as the original
|
||||||
|
sequence, regardless of completion order of the promises returned by `filterer`.
|
||||||
|
|
||||||
|
See also: [`QPromise<T>::filter`](../qpromise/filter.md)
|
45
docs/qtpromise/qpromise/filter.md
Normal file
45
docs/qtpromise/qpromise/filter.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
## `QPromise<Sequence<T>>::filter`
|
||||||
|
|
||||||
|
> **Important:** applies only to promise with sequence value.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QPromise<Sequence<T>>::filter(Filter filterer) -> QPromise<Sequence<T>>
|
||||||
|
|
||||||
|
// With:
|
||||||
|
// - Sequence: STL compatible container (e.g. QVector, etc.)
|
||||||
|
// - Filterer: Function(T value, int index) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Iterates over all the promise values (i.e. `Sequence<T>`) and [filters the sequence](https://en.wikipedia.org/wiki/Filter_%28higher-order_function%29)
|
||||||
|
to another using the given `filterer` function. If `filterer` returns `true`, a copy of the item
|
||||||
|
is put in the `output` sequence, otherwise, the item will not appear in `output`. If `filterer`
|
||||||
|
throws, `output` is rejected with the new exception.
|
||||||
|
|
||||||
|
If `filterer` returns a promise (or `QFuture`), the `output` promise is delayed until all the
|
||||||
|
promises are resolved. If any of the promises fail, `output` immediately rejects with the error
|
||||||
|
of the promise that rejected, whether or not the other promises are resolved.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
QPromise<QList<QUrl>> input = {...}
|
||||||
|
|
||||||
|
auto output = input.filter([](const QUrl& url, ...) {
|
||||||
|
return url.isValid(); // Keep only valid URLs
|
||||||
|
}).filter([](const QUrl& url, ...) {
|
||||||
|
return QPromise<bool>([&](auto resolve, auto reject) {
|
||||||
|
// resolve(true) if `url` is reachable, else resolve(false)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 'output' resolves as soon as all promises returned by
|
||||||
|
// 'filterer' are fulfilled or at least one is rejected.
|
||||||
|
|
||||||
|
// 'output' type: QPromise<QList<QUrl>>
|
||||||
|
output.then([](const QList<QUrl>& res) {
|
||||||
|
// 'res' contains only reachable URLs
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note:** the order of the output sequence values is guarantee to be the same as the original
|
||||||
|
sequence, regardless of completion order of the promises returned by `filterer`.
|
||||||
|
|
||||||
|
See also: [`QtPromise::filter`](../helpers/filter.md)
|
@ -88,6 +88,9 @@ public:
|
|||||||
template <typename F>
|
template <typename F>
|
||||||
QPromise(F&& resolver): QPromiseBase<T>(std::forward<F>(resolver)) { }
|
QPromise(F&& resolver): QPromiseBase<T>(std::forward<F>(resolver)) { }
|
||||||
|
|
||||||
|
template <typename Functor>
|
||||||
|
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);
|
||||||
|
@ -155,6 +155,15 @@ inline QPromise<T> QPromiseBase<T>::reject(E&& error)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
template <typename Functor>
|
||||||
|
inline QPromise<T> QPromise<T>::filter(Functor fn)
|
||||||
|
{
|
||||||
|
return this->then([=](const T& values) {
|
||||||
|
return QtPromise::filter(values, fn);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
template <typename Functor>
|
template <typename Functor>
|
||||||
inline typename QtPromisePrivate::PromiseMapper<T, Functor>::PromiseType
|
inline typename QtPromisePrivate::PromiseMapper<T, Functor>::PromiseType
|
||||||
|
@ -63,6 +63,26 @@ map(const Sequence& values, Functor fn)
|
|||||||
return QPromise<ResType>::all(promises);
|
return QPromise<ResType>::all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Sequence, typename Functor>
|
||||||
|
static inline QPromise<Sequence> filter(const Sequence& values, Functor fn)
|
||||||
|
{
|
||||||
|
return QtPromise::map(values, fn)
|
||||||
|
.then([=](const QVector<bool>& filters) {
|
||||||
|
Sequence filtered;
|
||||||
|
|
||||||
|
auto filter = filters.begin();
|
||||||
|
for (auto& value : values) {
|
||||||
|
if (*filter) {
|
||||||
|
filtered.push_back(std::move(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
filter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace QtPromise
|
} // namespace QtPromise
|
||||||
|
|
||||||
#endif // QTPROMISE_QPROMISEHELPERS_H
|
#endif // QTPROMISE_QPROMISEHELPERS_H
|
||||||
|
4
tests/auto/qtpromise/helpers/filter/filter.pro
Normal file
4
tests/auto/qtpromise/helpers/filter/filter.pro
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
TARGET = tst_helpers_filter
|
||||||
|
SOURCES += $$PWD/tst_filter.cpp
|
||||||
|
|
||||||
|
include(../../qtpromise.pri)
|
147
tests/auto/qtpromise/helpers/filter/tst_filter.cpp
Normal file
147
tests/auto/qtpromise/helpers/filter/tst_filter.cpp
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
// Tests
|
||||||
|
#include "../../shared/utils.h"
|
||||||
|
|
||||||
|
// QtPromise
|
||||||
|
#include <QtPromise>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
using namespace QtPromise;
|
||||||
|
|
||||||
|
class tst_helpers_filter : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void emptySequence();
|
||||||
|
void filterValues();
|
||||||
|
void delayedFulfilled();
|
||||||
|
void delayedRejected();
|
||||||
|
void functorThrows();
|
||||||
|
void functorArguments();
|
||||||
|
void preserveOrder();
|
||||||
|
void sequenceTypes();
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_MAIN(tst_helpers_filter)
|
||||||
|
#include "tst_filter.moc"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <class Sequence>
|
||||||
|
struct SequenceTester
|
||||||
|
{
|
||||||
|
static void exec()
|
||||||
|
{
|
||||||
|
auto inputs = Sequence{42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
|
||||||
|
auto p = QtPromise::filter(inputs, [](int v, ...) {
|
||||||
|
return v % 3 == 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Sequence>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, Sequence()), Sequence({42, 45, 48, 51}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
#include <QtConcurrent/QtConcurrent>
|
||||||
|
|
||||||
|
void tst_helpers_filter::emptySequence()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::filter(QVector<int>{}, [](int v, ...) {
|
||||||
|
return v % 2 == 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_filter::filterValues()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||||
|
return v % 2 == 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_filter::delayedFulfilled()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||||
|
return QPromise<bool>([&](const QPromiseResolve<bool>& resolve) {
|
||||||
|
QtPromisePrivate::qtpromise_defer([=]() {
|
||||||
|
resolve(v % 2 == 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_filter::delayedRejected()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||||
|
return QPromise<bool>([&](
|
||||||
|
const QPromiseResolve<bool>& resolve,
|
||||||
|
const QPromiseReject<bool>& reject) {
|
||||||
|
QtPromisePrivate::qtpromise_defer([=]() {
|
||||||
|
if (v == 44) {
|
||||||
|
reject(QString("foo"));
|
||||||
|
}
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_filter::functorThrows()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) {
|
||||||
|
if (v == 44) {
|
||||||
|
throw QString("foo");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_filter::functorArguments()
|
||||||
|
{
|
||||||
|
QMap<int, int> args;
|
||||||
|
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [&](int v, int i) {
|
||||||
|
args[v] = i;
|
||||||
|
return i % 2 == 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||||
|
QMap<int, int> expected{{42, 0}, {43, 1}, {44, 2}};
|
||||||
|
QCOMPARE(args, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_filter::preserveOrder()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::filter(QVector<int>{500, 100, 300, 250, 400}, [](int v, ...) {
|
||||||
|
return QPromise<bool>::resolve(v > 200).delay(v);
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({500, 300, 250, 400}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_helpers_filter::sequenceTypes()
|
||||||
|
{
|
||||||
|
SequenceTester<QList<int>>::exec();
|
||||||
|
SequenceTester<QVector<int>>::exec();
|
||||||
|
SequenceTester<std::list<int>>::exec();
|
||||||
|
SequenceTester<std::vector<int>>::exec();
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
TEMPLATE = subdirs
|
TEMPLATE = subdirs
|
||||||
SUBDIRS += \
|
SUBDIRS += \
|
||||||
all \
|
all \
|
||||||
|
filter \
|
||||||
map \
|
map \
|
||||||
reject \
|
reject \
|
||||||
resolve
|
resolve
|
||||||
|
4
tests/auto/qtpromise/qpromise/filter/filter.pro
Normal file
4
tests/auto/qtpromise/qpromise/filter/filter.pro
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
TARGET = tst_qpromise_filter
|
||||||
|
SOURCES += $$PWD/tst_filter.cpp
|
||||||
|
|
||||||
|
include(../../qtpromise.pri)
|
152
tests/auto/qtpromise/qpromise/filter/tst_filter.cpp
Normal file
152
tests/auto/qtpromise/qpromise/filter/tst_filter.cpp
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
// Tests
|
||||||
|
#include "../../shared/utils.h"
|
||||||
|
|
||||||
|
// QtPromise
|
||||||
|
#include <QtPromise>
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QtTest>
|
||||||
|
|
||||||
|
using namespace QtPromise;
|
||||||
|
|
||||||
|
class tst_qpromise_filter : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void emptySequence();
|
||||||
|
void filterValues();
|
||||||
|
void delayedFulfilled();
|
||||||
|
void delayedRejected();
|
||||||
|
void functorThrows();
|
||||||
|
void functorArguments();
|
||||||
|
void preserveOrder();
|
||||||
|
void sequenceTypes();
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_MAIN(tst_qpromise_filter)
|
||||||
|
#include "tst_filter.moc"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <class Sequence>
|
||||||
|
struct SequenceTester
|
||||||
|
{
|
||||||
|
static void exec()
|
||||||
|
{
|
||||||
|
auto p = QtPromise::qPromise(Sequence{
|
||||||
|
42, 43, 44, 45, 46, 47, 48, 49, 50, 51
|
||||||
|
}).filter([](int v, ...) {
|
||||||
|
return v > 42 && v < 51;
|
||||||
|
}).filter([](int, int i) {
|
||||||
|
return QPromise<bool>::resolve(i % 2 == 0);
|
||||||
|
}).filter([](int v, ...) {
|
||||||
|
return v != 45;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Sequence>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, Sequence()), Sequence({43, 47, 49}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // anonymous namespace
|
||||||
|
|
||||||
|
#include <QtConcurrent/QtConcurrent>
|
||||||
|
|
||||||
|
void tst_qpromise_filter::emptySequence()
|
||||||
|
{
|
||||||
|
auto p = QPromise<QVector<int>>::resolve({}).filter([](int v, ...) {
|
||||||
|
return v % 2 == 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_filter::filterValues()
|
||||||
|
{
|
||||||
|
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).filter([](int v, ...) {
|
||||||
|
return v % 2 == 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_filter::delayedFulfilled()
|
||||||
|
{
|
||||||
|
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).filter([](int v, ...) {
|
||||||
|
return QPromise<bool>([&](const QPromiseResolve<bool>& resolve) {
|
||||||
|
QtPromisePrivate::qtpromise_defer([=]() {
|
||||||
|
resolve(v % 2 == 0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_filter::delayedRejected()
|
||||||
|
{
|
||||||
|
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).filter([](int v, ...) {
|
||||||
|
return QPromise<bool>([&](
|
||||||
|
const QPromiseResolve<bool>& resolve,
|
||||||
|
const QPromiseReject<bool>& reject) {
|
||||||
|
QtPromisePrivate::qtpromise_defer([=]() {
|
||||||
|
if (v == 43) {
|
||||||
|
reject(QString("foo"));
|
||||||
|
}
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_filter::functorThrows()
|
||||||
|
{
|
||||||
|
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).filter([](int v, ...) {
|
||||||
|
if (v == 43) {
|
||||||
|
throw QString("foo");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForError(p, QString()), QString("foo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_filter::functorArguments()
|
||||||
|
{
|
||||||
|
QMap<int, int> args;
|
||||||
|
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).filter([&](int v, int i) {
|
||||||
|
args[v] = i;
|
||||||
|
return i % 2 == 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({42, 44}));
|
||||||
|
QMap<int, int> expected{{42, 0}, {43, 1}, {44, 2}};
|
||||||
|
QCOMPARE(args, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_filter::preserveOrder()
|
||||||
|
{
|
||||||
|
auto p = QPromise<QVector<int>>::resolve({250, 50, 100, 400, 300}).filter([](int v, ...) {
|
||||||
|
return QPromise<bool>::resolve(v > 200).delay(v);
|
||||||
|
});
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));
|
||||||
|
QCOMPARE(waitForValue(p, QVector<int>()), QVector<int>({250, 400, 300}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_qpromise_filter::sequenceTypes()
|
||||||
|
{
|
||||||
|
SequenceTester<QList<int>>::exec();
|
||||||
|
SequenceTester<QVector<int>>::exec();
|
||||||
|
SequenceTester<std::list<int>>::exec();
|
||||||
|
SequenceTester<std::vector<int>>::exec();
|
||||||
|
}
|
@ -3,6 +3,7 @@ SUBDIRS += \
|
|||||||
construct \
|
construct \
|
||||||
delay \
|
delay \
|
||||||
fail \
|
fail \
|
||||||
|
filter \
|
||||||
finally \
|
finally \
|
||||||
map \
|
map \
|
||||||
operators \
|
operators \
|
||||||
|
Loading…
Reference in New Issue
Block a user