Rename qPromise() helper to QtPromise::resolve()

For consistency with other helpers, deprecate `qPromise()` in favor of `QtPromise::resolve()` but also add support for calling this helper with lvalue. Add extra unit tests to make sure that rvalue is not copied.
This commit is contained in:
Simon Brunel 2019-02-25 20:03:19 +01:00
parent 1f30224578
commit 963ec621e1
34 changed files with 880 additions and 253 deletions

View File

@ -51,7 +51,7 @@ module.exports = {
'qtpromise/helpers/each',
'qtpromise/helpers/filter',
'qtpromise/helpers/map',
'qtpromise/helpers/qpromise',
'qtpromise/helpers/resolve',
'qtpromise/helpers/qpromiseall'
]
},

View File

@ -31,7 +31,7 @@
* [`QtPromise::each`](helpers/each.md)
* [`QtPromise::filter`](helpers/filter.md)
* [`QtPromise::map`](helpers/map.md)
* [`qPromise`](helpers/qpromise.md)
* [`QtPromise::resolve`](helpers/resolve.md)
* [`qPromiseAll`](helpers/qpromiseall.md)
## Exceptions
@ -39,3 +39,7 @@
* [`QPromiseCanceledException`](exceptions/canceled.md)
* [`QPromiseTimeoutException`](exceptions/timeout.md)
* [`QPromiseUndefinedException`](exceptions/undefined.md)
## Deprecations
* `QtPromise::qPromise`: use [`QtPromise::resolve`](helpers/resolve.md) instead (since 0.5.0)

View File

@ -9,7 +9,7 @@ title: QPromiseCanceledException
This exception is thrown for promise created from a [`QFuture`](../qtconcurrent.md) which has been canceled (e.g. using [`QFuture::cancel()`](http://doc.qt.io/qt-5/qfuture.html#cancel)), for example:
```cpp
auto output = qPromise(future)
auto output = QtPromise::resolve(future)
.fail([](const QPromiseCanceledException&) {
// `future` has been canceled!
});

View File

@ -56,7 +56,7 @@ The following method `uncompress` data in a separate thread and returns a [promi
```cpp
QPromise<Entries> uncompress(const QByteArray& data)
{
return qPromise(QtConcurrent::run([](const QByteArray& data) {
return QtPromise::resolve(QtConcurrent::run([](const QByteArray& data) {
Entries entries;
// {...} uncompress data and parse content.

View File

@ -1,21 +0,0 @@
---
title: qPromise
---
# qPromise
*Since: 0.1.0*
```
qPromise(T value) -> QPromise<R>
```
Similar to the [`QPromise<T>::resolve`](../qpromise/resolve.md) static method, creates a promise resolved from a given `value` without the extra typing:
```cpp
auto promise = qPromise(); // QPromise<void>
auto promise = qPromise(42); // QPromise<int>
auto promise = qPromise(QString("foo")); // QPromise<QString>
```
This method also allows to convert `QFuture<T>` to `QPromise<T>` delayed until the `QFuture` is finished ([read more](../qtconcurrent.md#convert)).

View File

@ -0,0 +1,21 @@
---
title: resolve
---
# QtPromise::resolve
*Since: 0.5.0*
```
QtPromise::resolve(T value) -> QPromise<R>
```
Similar to the [`QPromise<T>::resolve`](../qpromise/resolve.md) static method, creates a promise resolved from a given `value` but without the extra typing:
```cpp
auto promise = QtPromise::resolve(); // QPromise<void>
auto promise = QtPromise::resolve(42); // QPromise<int>
auto promise = QtPromise::resolve(QString("foo")); // QPromise<QString>
```
This method also allows to convert `QFuture<T>` to `QPromise<T>`, delayed until the `QFuture` is finished ([read more](../qtconcurrent.md#convert)).

View File

@ -25,4 +25,4 @@ QPromise<int> compute(const QString& type)
}
```
See also: [`qPromise`](../helpers/qpromise.md)
See also: [`QtPromise::resolve`](../helpers/resolve.md)

View File

@ -15,7 +15,7 @@ This method holds the execution of the remaining code until the `input` promise
```cpp
int result = -1;
QPromise<int> input = qPromise(QtConcurrent::run([]() {
QPromise<int> input = QtPromise::resolve(QtConcurrent::run([]() {
return 42;
})).tap([&](int res) {
result = res;

View File

@ -4,7 +4,7 @@ QtPromise integrates with [QtConcurrent](https://doc.qt.io/qt-5/qtconcurrent-ind
## <a name="qtconcurrent-convert"></a> Convert
Converting `QFuture<T>` to `QPromise<T>` is done using the [`qPromise`](helpers/qpromise.md) helper:
Converting `QFuture<T>` to `QPromise<T>` is done using the [`QtPromise::resolve`](helpers/resolve.md) helper:
```cpp
QFuture<int> future = QtConcurrent::run([]() {
@ -12,13 +12,13 @@ QFuture<int> future = QtConcurrent::run([]() {
return 42;
});
QPromise<int> promise = qPromise(future);
QPromise<int> promise = QtPromise::resolve(future);
```
or simply:
```cpp
auto promise = qPromise(QtConcurrent::run([]() {
auto promise = QtPromise::resolve(QtConcurrent::run([]() {
// {...}
}));
```

View File

@ -279,9 +279,7 @@ inline QPromise<void> QPromise<void>::all(const Sequence<QPromise<void>, Args...
inline QPromise<void> QPromise<void>::resolve()
{
return QPromise<void>([](const QPromiseResolve<void>& resolve) {
resolve();
});
return QtPromise::resolve();
}
} // namespace QtPromise

View File

@ -110,9 +110,24 @@ private:
template <typename T>
struct PromiseDeduce
{
using Type = QtPromise::QPromise<Unqualified<T>>;
using Type = QtPromise::QPromise<T>;
};
template <typename T>
struct PromiseDeduce<T&>
: public PromiseDeduce<T>
{ };
template <typename T>
struct PromiseDeduce<const T>
: public PromiseDeduce<T>
{ };
template <typename T>
struct PromiseDeduce<const volatile T>
: public PromiseDeduce<T>
{ };
template <typename T>
struct PromiseDeduce<QtPromise::QPromise<T>>
: public PromiseDeduce<T>
@ -128,22 +143,21 @@ struct PromiseFunctor
template <typename T>
struct PromiseFulfill
{
static void call(
T&& value,
const QtPromise::QPromiseResolve<T>& resolve,
const QtPromise::QPromiseReject<T>&)
template <typename V, typename TResolve, typename TReject>
static void call(V&& value, const TResolve& resolve, const TReject&)
{
resolve(std::move(value));
resolve(std::forward<V>(value));
}
};
template <typename T>
struct PromiseFulfill<QtPromise::QPromise<T>>
{
template <typename TResolve, typename TReject>
static void call(
const QtPromise::QPromise<T>& promise,
const QtPromise::QPromiseResolve<T>& resolve,
const QtPromise::QPromiseReject<T>& reject)
const TResolve& resolve,
const TReject& reject)
{
if (promise.isFulfilled()) {
resolve(promise.m_d->value());

View File

@ -7,21 +7,34 @@
namespace QtPromise {
template <typename T>
static inline typename QtPromisePrivate::PromiseDeduce<T>::Type qPromise(T&& value)
static inline typename QtPromisePrivate::PromiseDeduce<T>::Type
resolve(T&& value)
{
using namespace QtPromisePrivate;
using Promise = typename PromiseDeduce<T>::Type;
return Promise([&](
const QPromiseResolve<typename Promise::Type>& resolve,
const QPromiseReject<typename Promise::Type>& reject) {
PromiseFulfill<T>::call(std::forward<T>(value), resolve, reject);
using PromiseType = typename PromiseDeduce<T>::Type;
using ValueType = typename PromiseType::Type;
using ResolveType = QPromiseResolve<ValueType>;
using RejectType = QPromiseReject<ValueType>;
return PromiseType([&](ResolveType&& resolve, RejectType&& reject) {
PromiseFulfill<Unqualified<T>>::call(
std::forward<T>(value),
std::forward<ResolveType>(resolve),
std::forward<RejectType>(reject));
});
}
static inline QPromise<void> qPromise()
template <typename T>
static inline QPromise<T>
resolve(QPromise<T> value)
{
return QPromise<void>([](
const QPromiseResolve<void>& resolve) {
return std::move(value);
}
static inline QPromise<void>
resolve()
{
return QPromise<void>([](const QPromiseResolve<void>& resolve) {
resolve();
});
}
@ -153,6 +166,17 @@ static inline QPromise<Sequence> filter(const Sequence& values, Functor fn)
});
}
// DEPRECATIONS (remove at version 1)
template <typename... Args>
Q_DECL_DEPRECATED_X("Use QtPromise::resolve instead")
static inline auto
qPromise(Args&&... args)
-> decltype(QtPromise::resolve(std::forward<Args>(args)...))
{
return QtPromise::resolve(std::forward<Args>(args)...);
}
} // namespace QtPromise
#endif // QTPROMISE_QPROMISEHELPERS_H

View File

@ -1,3 +1,5 @@
#include "../shared/data.h"
// QtPromise
#include <QtPromise>
@ -20,7 +22,6 @@ class tst_benchmark : public QObject
private Q_SLOTS:
void valueResolve();
void valueResolveStatic();
void valueReject();
void valueThen();
void valueFinally();
@ -34,72 +35,6 @@ private Q_SLOTS:
QTEST_MAIN(tst_benchmark)
#include "tst_benchmark.moc"
struct Logs {
int ctor = 0;
int copy = 0;
int move = 0;
int refs = 0;
void reset() {
ctor = 0;
copy = 0;
move = 0;
refs = 0;
}
};
struct Logger
{
Logger() { logs().ctor++; logs().refs++; }
Logger(const Logger&) { logs().copy++; logs().refs++; }
Logger(Logger&&) { logs().move++; logs().refs++; }
~Logger() { logs().refs--; }
Logger& operator=(const Logger&) { logs().copy++; return *this; }
Logger& operator=(Logger&&) { logs().move++; return *this; }
public: // STATICS
static Logs& logs() { static Logs logs; return logs; }
};
struct Data : public Logger
{
Data(int v): Logger(), m_value(v) {}
int value() const { return m_value; }
// MSVC 2013 doesn't support implicit generation of the move constructor and
// operator, so we need to explicitly define these methods and thus the copy
// constructor and operator also need to be explicitly defined (error C2280).
// https://stackoverflow.com/a/26581337
Data(const Data& other)
: Logger(other)
, m_value(other.m_value)
{ }
Data(Data&& other) : Logger(std::forward<Data>(other))
{
qSwap(m_value, other.m_value);
}
Data& operator=(const Data& other)
{
Logger::operator=(other);
m_value = other.m_value;
return *this;
}
Data& operator=(Data&& other)
{
Logger::operator=(std::forward<Data>(other));
qSwap(m_value, other.m_value);
return *this;
}
private:
int m_value;
};
void tst_benchmark::valueResolve()
{
{ // should move the value when resolved by rvalue
@ -127,31 +62,6 @@ void tst_benchmark::valueResolve()
}
}
void tst_benchmark::valueResolveStatic()
{
{ // should move the value when resolved by rvalue
Data::logs().reset();
QPromise<Data>::resolve(Data(42)).wait();
QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 0);
QCOMPARE(Data::logs().move, 1); // move value to the promise data
QCOMPARE(Data::logs().refs, 0);
}
{ // should create one copy of the value when resolved by lvalue
{
Data::logs().reset();
Data value(42);
QPromise<Data>::resolve(value).wait();
}
QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 1); // copy value to the promise data
QCOMPARE(Data::logs().move, 0);
QCOMPARE(Data::logs().refs, 0);
}
}
void tst_benchmark::valueReject()
{
{ // should not create any data if rejected

View File

@ -0,0 +1,5 @@
include(../qtpromise.pri)
DEFINES -= QT_DEPRECATED_WARNINGS
gcc:QMAKE_CXXFLAGS += -Wno-deprecated-declarations
msvc:QMAKE_CXXFLAGS -= -wd4996

View File

@ -0,0 +1,3 @@
TEMPLATE = subdirs
SUBDIRS += \
helpers

View File

@ -0,0 +1,3 @@
TEMPLATE = subdirs
SUBDIRS += \
qpromise

View File

@ -0,0 +1,5 @@
QT += concurrent
TARGET = tst_deprecations_helpers_qpromise
SOURCES += $$PWD/tst_qpromise.cpp
include(../../deprecations.pri)

View File

@ -0,0 +1,268 @@
#include "../../../shared/data.h"
#include "../../../shared/utils.h"
// QtPromise
#include <QtPromise>
// Qt
#include <QtConcurrent>
#include <QtTest>
// STL
#include <memory>
using namespace QtPromise;
class tst_deprecations_helpers_qpromise : public QObject
{
Q_OBJECT
private Q_SLOTS:
void value();
void noValue();
void moveRValue();
void copyLValue();
void qtSharedPtr();
void stdSharedPtr();
void typedPromise();
void voidPromise();
void typedFuture();
void voidFuture();
};
QTEST_MAIN(tst_deprecations_helpers_qpromise)
#include "tst_qpromise.moc"
void tst_deprecations_helpers_qpromise::value()
{
int v0 = 42;
const int v1 = 42;
auto p0 = qPromise(42);
auto p1 = qPromise(v0);
auto p2 = qPromise(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
for (const auto& p : {p0, p1, p2}) {
QCOMPARE(p.isFulfilled(), true);
}
for (const auto& p : {p0, p1, p2}) {
QCOMPARE(waitForValue(p, -1), 42);
}
}
void tst_deprecations_helpers_qpromise::noValue()
{
auto p = qPromise();
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
QCOMPARE(p.isFulfilled(), true);
QCOMPARE(waitForValue(p, -1, 42), 42);
}
void tst_deprecations_helpers_qpromise::moveRValue()
{
Data::logs().reset();
{
auto p = qPromise(Data(42)).wait();
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Data>>::value));
}
QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 0);
QCOMPARE(Data::logs().move, 1);
QCOMPARE(Data::logs().refs, 0);
}
void tst_deprecations_helpers_qpromise::copyLValue()
{
Data::logs().reset();
{
Data value(42);
auto p = qPromise(value).wait();
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Data>>::value));
}
QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 1);
QCOMPARE(Data::logs().move, 0);
QCOMPARE(Data::logs().refs, 0);
}
// https://github.com/simonbrunel/qtpromise/issues/6
void tst_deprecations_helpers_qpromise::qtSharedPtr()
{
Data::logs().reset();
QWeakPointer<Data> wptr;
{
QSharedPointer<Data> sptr0(new Data(42));
const QSharedPointer<Data> sptr1 = sptr0;
auto p0 = qPromise(QSharedPointer<Data>(new Data(42)));
auto p1 = qPromise(sptr0);
auto p2 = qPromise(sptr1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<QSharedPointer<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<QSharedPointer<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<QSharedPointer<Data>>>::value));
QCOMPARE(waitForValue(p1, QSharedPointer<Data>()), sptr0);
QCOMPARE(waitForValue(p2, QSharedPointer<Data>()), sptr1);
wptr = sptr0;
QCOMPARE(wptr.isNull(), false);
QCOMPARE(Data::logs().refs, 2);
}
QCOMPARE(wptr.isNull(), true);
QCOMPARE(Data::logs().ctor, 2);
QCOMPARE(Data::logs().copy, 0);
QCOMPARE(Data::logs().move, 0);
QCOMPARE(Data::logs().refs, 0);
}
// https://github.com/simonbrunel/qtpromise/issues/6
void tst_deprecations_helpers_qpromise::stdSharedPtr()
{
Data::logs().reset();
std::weak_ptr<Data> wptr;
{
std::shared_ptr<Data> sptr0(new Data(42));
const std::shared_ptr<Data> sptr1 = sptr0;
auto p0 = qPromise(std::shared_ptr<Data>(new Data(42)));
auto p1 = qPromise(sptr0);
auto p2 = qPromise(sptr1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<std::shared_ptr<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<std::shared_ptr<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<std::shared_ptr<Data>>>::value));
QCOMPARE(waitForValue(p1, std::shared_ptr<Data>()), sptr0);
QCOMPARE(waitForValue(p2, std::shared_ptr<Data>()), sptr1);
wptr = sptr0;
QCOMPARE(wptr.use_count(), 4l);
QCOMPARE(Data::logs().refs, 2);
}
QCOMPARE(wptr.use_count(), 0l);
QCOMPARE(Data::logs().ctor, 2);
QCOMPARE(Data::logs().copy, 0);
QCOMPARE(Data::logs().move, 0);
QCOMPARE(Data::logs().refs, 0);
}
void tst_deprecations_helpers_qpromise::typedPromise()
{
auto resolver = [](const QPromiseResolve<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){
resolve(42);
});
};
QPromise<int> v0(resolver);
const QPromise<int> v1 = v0;
auto p0 = qPromise(QPromise<int>(resolver));
auto p1 = qPromise(v0);
auto p2 = qPromise(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(promise.isPending(), true);
}
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(waitForValue(promise, -1), 42);
}
}
void tst_deprecations_helpers_qpromise::voidPromise()
{
auto resolver = [](const QPromiseResolve<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){
resolve();
});
};
QPromise<void> v0(resolver);
const QPromise<void> v1 = v0;
auto p0 = qPromise(QPromise<void>(resolver));
auto p1 = qPromise(v0);
auto p2 = qPromise(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<void>>::value));
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(promise.isPending(), true);
}
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(waitForValue(promise, -1, 42), 42);
}
}
void tst_deprecations_helpers_qpromise::typedFuture()
{
auto fn = [](){ return 42; };
QFuture<int> v0 = QtConcurrent::run(fn);
const QFuture<int> v1 = v0;
auto p0 = qPromise(QtConcurrent::run(fn));
auto p1 = qPromise(v0);
auto p2 = qPromise(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(promise.isPending(), true);
}
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(waitForValue(promise, -1), 42);
}
}
void tst_deprecations_helpers_qpromise::voidFuture()
{
auto fn = [](){ };
QFuture<void> v0 = QtConcurrent::run(fn);
const QFuture<void> v1 = v0;
auto p0 = qPromise(QtConcurrent::run(fn));
auto p1 = qPromise(v0);
auto p2 = qPromise(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<void>>::value));
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(promise.isPending(), true);
}
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(waitForValue(promise, -1, 42), 42);
}
}

View File

@ -29,7 +29,7 @@ namespace {
template <class E>
void verify()
{
auto p = qPromise(QtConcurrent::run([]() { throw E(); }));
auto p = QtPromise::resolve(QtConcurrent::run([]() { throw E(); }));
QCOMPARE(p.isPending(), true);
QCOMPARE(waitForRejected<E>(p), true);
QCOMPARE(p.isRejected(), true);

View File

@ -52,7 +52,7 @@ QTEST_MAIN(tst_future)
void tst_future::fulfilled()
{
int result = -1;
auto p = qPromise(QtConcurrent::run([]() {
auto p = QtPromise::resolve(QtConcurrent::run([]() {
return 42;
}));
@ -70,7 +70,7 @@ void tst_future::fulfilled()
void tst_future::fulfilled_void()
{
int result = -1;
auto p = qPromise(QtConcurrent::run([]() { }));
auto p = QtPromise::resolve(QtConcurrent::run([]() { }));
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
QCOMPARE(p.isPending(), true);
@ -86,7 +86,7 @@ void tst_future::fulfilled_void()
void tst_future::rejected()
{
QString error;
auto p = qPromise(QtConcurrent::run([]() {
auto p = QtPromise::resolve(QtConcurrent::run([]() {
throw MyException("foo");
return 42;
}));
@ -106,7 +106,7 @@ void tst_future::rejected()
void tst_future::rejected_void()
{
QString error;
auto p = qPromise(QtConcurrent::run([]() {
auto p = QtPromise::resolve(QtConcurrent::run([]() {
throw MyException("foo");
}));
@ -125,7 +125,7 @@ void tst_future::rejected_void()
void tst_future::unhandled()
{
QString error;
auto p = qPromise(QtConcurrent::run([]() {
auto p = QtPromise::resolve(QtConcurrent::run([]() {
throw QString("foo");
return 42;
}));
@ -149,7 +149,7 @@ void tst_future::unhandled()
void tst_future::unhandled_void()
{
QString error;
auto p = qPromise(QtConcurrent::run([]() {
auto p = QtPromise::resolve(QtConcurrent::run([]() {
throw QString("foo");
}));
@ -169,7 +169,7 @@ void tst_future::unhandled_void()
void tst_future::canceled()
{
QString error;
auto p = qPromise(QFuture<int>()); // Constructs an empty, canceled future.
auto p = QtPromise::resolve(QFuture<int>()); // Constructs an empty, canceled future.
QCOMPARE(p.isPending(), true);
@ -185,7 +185,7 @@ void tst_future::canceled()
void tst_future::canceled_void()
{
QString error;
auto p = qPromise(QFuture<void>()); // Constructs an empty, canceled future.
auto p = QtPromise::resolve(QFuture<void>()); // Constructs an empty, canceled future.
QCOMPARE(p.isPending(), true);
@ -200,7 +200,7 @@ void tst_future::canceled_void()
void tst_future::canceledFromThread()
{
QString error;
auto p = qPromise(QtConcurrent::run([]() {
auto p = QtPromise::resolve(QtConcurrent::run([]() {
throw QPromiseCanceledException();
}));
@ -217,7 +217,7 @@ void tst_future::canceledFromThread()
void tst_future::then()
{
QString result;
auto input = qPromise(42);
auto input = QtPromise::resolve(42);
auto output = input.then([](int res) {
return QtConcurrent::run([=]() {
return QString("foo%1").arg(res);
@ -238,7 +238,7 @@ void tst_future::then()
void tst_future::then_void()
{
QString result;
auto input = qPromise();
auto input = QtPromise::resolve();
auto output = input.then([&]() {
return QtConcurrent::run([&]() {
result = "foo";
@ -300,7 +300,7 @@ void tst_future::fail_void()
void tst_future::finally()
{
auto input = qPromise(42);
auto input = QtPromise::resolve(42);
auto output = input.finally([]() {
return QtConcurrent::run([]() {
return QString("foo");
@ -323,7 +323,7 @@ void tst_future::finally()
void tst_future::finallyRejected()
{
auto input = qPromise(42);
auto input = QtPromise::resolve(42);
auto output = input.finally([]() {
return QtConcurrent::run([]() {
throw MyException("foo");

View File

@ -37,13 +37,13 @@ struct SequenceTester
static void exec()
{
Sequence promises{
QtPromise::qPromise(42),
QtPromise::qPromise(43),
QtPromise::qPromise(44)
QtPromise::resolve(42),
QtPromise::resolve(43),
QtPromise::resolve(44)
};
promises.push_back(QtPromise::qPromise(45));
promises.insert(++promises.begin(), QtPromise::qPromise(46));
promises.push_back(QtPromise::resolve(45));
promises.insert(++promises.begin(), QtPromise::resolve(46));
promises.pop_back();
auto p = QtPromise::qPromiseAll(promises);
@ -60,13 +60,13 @@ struct SequenceTester<Sequence<QPromise<void>, Args...>>
static void exec()
{
Sequence<QPromise<void>, Args...> promises{
QtPromise::qPromise(),
QtPromise::qPromise(),
QtPromise::qPromise()
QtPromise::resolve(),
QtPromise::resolve(),
QtPromise::resolve()
};
promises.push_back(QtPromise::qPromise());
promises.insert(++promises.begin(), QtPromise::qPromise());
promises.push_back(QtPromise::resolve());
promises.insert(++promises.begin(), QtPromise::resolve());
promises.pop_back();
auto p = QtPromise::qPromiseAll(promises);
@ -99,8 +99,8 @@ void tst_helpers_all::emptySequence_void()
void tst_helpers_all::allPromisesSucceed()
{
auto p0 = QtPromise::qPromise(42);
auto p1 = QtPromise::qPromise(44);
auto p0 = QtPromise::resolve(42);
auto p1 = QtPromise::resolve(44);
auto p2 = QPromise<int>([](const QPromiseResolve<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){
resolve(43);
@ -120,8 +120,8 @@ void tst_helpers_all::allPromisesSucceed()
void tst_helpers_all::allPromisesSucceed_void()
{
auto p0 = QtPromise::qPromise();
auto p1 = QtPromise::qPromise();
auto p0 = QtPromise::resolve();
auto p1 = QtPromise::resolve();
auto p2 = QPromise<void>([](const QPromiseResolve<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){
resolve();
@ -141,8 +141,8 @@ void tst_helpers_all::allPromisesSucceed_void()
void tst_helpers_all::atLeastOnePromiseReject()
{
auto p0 = QtPromise::qPromise(42);
auto p1 = QtPromise::qPromise(44);
auto p0 = QtPromise::resolve(42);
auto p1 = QtPromise::resolve(44);
auto p2 = QPromise<int>([](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
QtPromisePrivate::qtpromise_defer([=](){
reject(QString("foo"));
@ -162,8 +162,8 @@ void tst_helpers_all::atLeastOnePromiseReject()
void tst_helpers_all::atLeastOnePromiseReject_void()
{
auto p0 = QtPromise::qPromise();
auto p1 = QtPromise::qPromise();
auto p0 = QtPromise::resolve();
auto p1 = QtPromise::resolve();
auto p2 = QPromise<void>([](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
QtPromisePrivate::qtpromise_defer([=](){
reject(QString("foo"));
@ -183,9 +183,9 @@ void tst_helpers_all::atLeastOnePromiseReject_void()
void tst_helpers_all::preserveOrder()
{
auto p0 = QtPromise::qPromise(42).delay(500);
auto p1 = QtPromise::qPromise(43).delay(100);
auto p2 = QtPromise::qPromise(44).delay(250);
auto p0 = QtPromise::resolve(42).delay(500);
auto p1 = QtPromise::resolve(43).delay(100);
auto p2 = QtPromise::resolve(44).delay(250);
auto p = QtPromise::qPromiseAll(QVector<QPromise<int>>{p0, p1, p2});

View File

@ -64,7 +64,7 @@ void tst_helpers_attempt::futureResult()
void tst_helpers_attempt::promiseResult()
{
auto p = QtPromise::attempt([]() {
return QtPromise::qPromise(42).delay(200);
return QtPromise::resolve(42).delay(200);
});
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));

View File

@ -1,3 +1,4 @@
QT += concurrent
TARGET = tst_helpers_resolve
SOURCES += $$PWD/tst_resolve.cpp

View File

@ -1,9 +1,11 @@
#include "../../shared/data.h"
#include "../../shared/utils.h"
// QtPromise
#include <QtPromise>
// Qt
#include <QtConcurrent>
#include <QtTest>
// STL
@ -16,109 +18,251 @@ class tst_helpers_resolve : public QObject
Q_OBJECT
private Q_SLOTS:
void resolveWithValue();
void resolveWithNoValue();
void resolveWithTypedPromise();
void resolveWithVoidPromise();
void resolveWithQSharedPtr();
void resolveWithStdSharedPtr();
void value();
void noValue();
void moveRValue();
void copyLValue();
void qtSharedPtr();
void stdSharedPtr();
void typedPromise();
void voidPromise();
void typedFuture();
void voidFuture();
};
QTEST_MAIN(tst_helpers_resolve)
#include "tst_resolve.moc"
void tst_helpers_resolve::resolveWithValue()
void tst_helpers_resolve::value()
{
const int value = 42;
auto p0 = QPromise<int>::resolve(value);
auto p1 = QPromise<int>::resolve(43);
int v0 = 42;
const int v1 = 42;
auto p0 = QtPromise::resolve(42);
auto p1 = QtPromise::resolve(v0);
auto p2 = QtPromise::resolve(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
QCOMPARE(p0.isFulfilled(), true);
QCOMPARE(p1.isFulfilled(), true);
QCOMPARE(waitForValue(p0, -1), 42);
QCOMPARE(waitForValue(p1, -1), 43);
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
for (const auto& p : {p0, p1, p2}) {
QCOMPARE(p.isFulfilled(), true);
}
for (const auto& p : {p0, p1, p2}) {
QCOMPARE(waitForValue(p, -1), 42);
}
}
void tst_helpers_resolve::resolveWithNoValue()
void tst_helpers_resolve::noValue()
{
auto p = QPromise<void>::resolve();
auto p = QtPromise::resolve();
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
QCOMPARE(p.isFulfilled(), true);
QCOMPARE(waitForValue(p, -1, 42), 42);
}
void tst_helpers_resolve::resolveWithTypedPromise()
void tst_helpers_resolve::moveRValue()
{
auto p = QtPromise::qPromise(
QPromise<QString>([](const QPromiseResolve<QString>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){
resolve("foo");
});
}));
Data::logs().reset();
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
{
auto p = QtPromise::resolve(Data(42)).wait();
QCOMPARE(p.isPending(), true);
QCOMPARE(waitForValue(p, QString()), QString("foo"));
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Data>>::value));
}
QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 0);
QCOMPARE(Data::logs().move, 1);
QCOMPARE(Data::logs().refs, 0);
}
void tst_helpers_resolve::resolveWithVoidPromise()
void tst_helpers_resolve::copyLValue()
{
int check;
auto p = QtPromise::qPromise(
QPromise<void>([&](const QPromiseResolve<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=, &check](){
check = 8;
resolve();
});
}));
Data::logs().reset();
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
{
Data value(42);
auto p = QtPromise::resolve(value).wait();
QCOMPARE(p.isPending(), true);
QCOMPARE(waitForValue(p, -1, 42), 42);
QCOMPARE(check, 8);
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Data>>::value));
}
QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 1);
QCOMPARE(Data::logs().move, 0);
QCOMPARE(Data::logs().refs, 0);
}
// https://github.com/simonbrunel/qtpromise/issues/6
void tst_helpers_resolve::resolveWithQSharedPtr()
void tst_helpers_resolve::qtSharedPtr()
{
QWeakPointer<int> wptr;
Data::logs().reset();
QWeakPointer<Data> wptr;
{
QSharedPointer<int> sptr(new int(42));
auto p = QPromise<QSharedPointer<int>>::resolve(sptr);
QSharedPointer<Data> sptr0(new Data(42));
const QSharedPointer<Data> sptr1 = sptr0;
QCOMPARE(waitForValue(p, QSharedPointer<int>()), sptr);
auto p0 = QtPromise::resolve(QSharedPointer<Data>(new Data(42)));
auto p1 = QtPromise::resolve(sptr0);
auto p2 = QtPromise::resolve(sptr1);
wptr = sptr;
sptr.reset();
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<QSharedPointer<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<QSharedPointer<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<QSharedPointer<Data>>>::value));
QCOMPARE(wptr.isNull(), false); // "p" still holds a reference
QCOMPARE(waitForValue(p1, QSharedPointer<Data>()), sptr0);
QCOMPARE(waitForValue(p2, QSharedPointer<Data>()), sptr1);
wptr = sptr0;
QCOMPARE(wptr.isNull(), false);
QCOMPARE(Data::logs().refs, 2);
}
QCOMPARE(wptr.isNull(), true);
QCOMPARE(Data::logs().ctor, 2);
QCOMPARE(Data::logs().copy, 0);
QCOMPARE(Data::logs().move, 0);
QCOMPARE(Data::logs().refs, 0);
}
// https://github.com/simonbrunel/qtpromise/issues/6
void tst_helpers_resolve::resolveWithStdSharedPtr()
void tst_helpers_resolve::stdSharedPtr()
{
std::weak_ptr<int> wptr;
Data::logs().reset();
std::weak_ptr<Data> wptr;
{
std::shared_ptr<int> sptr(new int(42));
auto p = QPromise<std::shared_ptr<int>>::resolve(sptr);
std::shared_ptr<Data> sptr0(new Data(42));
const std::shared_ptr<Data> sptr1 = sptr0;
QCOMPARE(waitForValue(p, std::shared_ptr<int>()), sptr);
auto p0 = QtPromise::resolve(std::shared_ptr<Data>(new Data(42)));
auto p1 = QtPromise::resolve(sptr0);
auto p2 = QtPromise::resolve(sptr1);
wptr = sptr;
sptr.reset();
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<std::shared_ptr<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<std::shared_ptr<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<std::shared_ptr<Data>>>::value));
QCOMPARE(wptr.use_count(), 1l); // "p" still holds a reference
QCOMPARE(waitForValue(p1, std::shared_ptr<Data>()), sptr0);
QCOMPARE(waitForValue(p2, std::shared_ptr<Data>()), sptr1);
wptr = sptr0;
QCOMPARE(wptr.use_count(), 4l);
QCOMPARE(Data::logs().refs, 2);
}
QCOMPARE(wptr.use_count(), 0l);
QCOMPARE(Data::logs().ctor, 2);
QCOMPARE(Data::logs().copy, 0);
QCOMPARE(Data::logs().move, 0);
QCOMPARE(Data::logs().refs, 0);
}
void tst_helpers_resolve::typedPromise()
{
auto resolver = [](const QPromiseResolve<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){
resolve(42);
});
};
QPromise<int> v0(resolver);
const QPromise<int> v1 = v0;
auto p0 = QtPromise::resolve(QPromise<int>(resolver));
auto p1 = QtPromise::resolve(v0);
auto p2 = QtPromise::resolve(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(promise.isPending(), true);
}
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(waitForValue(promise, -1), 42);
}
}
void tst_helpers_resolve::voidPromise()
{
auto resolver = [](const QPromiseResolve<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){
resolve();
});
};
QPromise<void> v0(resolver);
const QPromise<void> v1 = v0;
auto p0 = QtPromise::resolve(QPromise<void>(resolver));
auto p1 = QtPromise::resolve(v0);
auto p2 = QtPromise::resolve(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<void>>::value));
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(promise.isPending(), true);
}
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(waitForValue(promise, -1, 42), 42);
}
}
void tst_helpers_resolve::typedFuture()
{
auto fn = [](){ return 42; };
QFuture<int> v0 = QtConcurrent::run(fn);
const QFuture<int> v1 = v0;
auto p0 = QtPromise::resolve(QtConcurrent::run(fn));
auto p1 = QtPromise::resolve(v0);
auto p2 = QtPromise::resolve(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(promise.isPending(), true);
}
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(waitForValue(promise, -1), 42);
}
}
void tst_helpers_resolve::voidFuture()
{
auto fn = [](){ };
QFuture<void> v0 = QtConcurrent::run(fn);
const QFuture<void> v1 = v0;
auto p0 = QtPromise::resolve(QtConcurrent::run(fn));
auto p1 = QtPromise::resolve(v0);
auto p2 = QtPromise::resolve(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<void>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<void>>::value));
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(promise.isPending(), true);
}
for (const auto& promise : {p0, p1, p2}) {
QCOMPARE(waitForValue(promise, -1, 42), 42);
}
}

View File

@ -34,14 +34,14 @@ struct SequenceTester
static void exec()
{
QVector<int> values;
auto p = QtPromise::qPromise(Sequence{42, 43, 44}).each([&](int v, int i) {
auto p = QtPromise::resolve(Sequence{42, 43, 44}).each([&](int v, int i) {
values << i << v;
}).each([&](int v, ...) {
values << v;
return QString("foo");
}).each([&](int v, ...) {
values << v + 1;
return QPromise<QString>::resolve(QString("foo")).then([&](){
return QtPromise::resolve(QString("foo")).then([&](){
values << -1;
});
}).each([&](int v, ...) {

View File

@ -33,7 +33,7 @@ struct SequenceTester
{
static void exec()
{
auto p = QtPromise::qPromise(Sequence{
auto p = QtPromise::resolve(Sequence{
42, 43, 44, 45, 46, 47, 48, 49, 50, 51
}).filter([](int v, ...) {
return v > 42 && v < 51;

View File

@ -34,12 +34,12 @@ struct SequenceTester
{
static void exec()
{
auto p = QtPromise::qPromise(Sequence{42, 43, 44}).map([](int v, ...) {
auto p = QtPromise::resolve(Sequence{42, 43, 44}).map([](int v, ...) {
return QString::number(v + 1);
}).map([](const QString& v, int i) {
return QtPromise::qPromise(QString("%1:%2").arg(i).arg(v));
return QtPromise::resolve(QString("%1:%2").arg(i).arg(v));
}).map([](const QString& v, ...) {
return QtPromise::qPromise((v + "!").toUtf8());
return QtPromise::resolve((v + "!").toUtf8());
}).map([](const QByteArray& v, ...) {
return QString::fromUtf8(v);
});
@ -53,7 +53,7 @@ struct SequenceTester
void tst_qpromise_map::emptySequence()
{
auto p = QtPromise::qPromise(QVector<int>{}).map([](int v, ...) {
auto p = QtPromise::resolve(QVector<int>{}).map([](int v, ...) {
return v + 1;
});
@ -63,7 +63,7 @@ void tst_qpromise_map::emptySequence()
void tst_qpromise_map::modifyValues()
{
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
auto p = QtPromise::resolve(QVector<int>{42, 43, 44}).map([](int v, ...) {
return v + 1;
});
@ -73,7 +73,7 @@ void tst_qpromise_map::modifyValues()
void tst_qpromise_map::convertValues()
{
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
auto p = QtPromise::resolve(QVector<int>{42, 43, 44}).map([](int v, ...) {
return QString::number(v + 1);
});
@ -83,7 +83,7 @@ void tst_qpromise_map::convertValues()
void tst_qpromise_map::delayedFulfilled()
{
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
auto p = QtPromise::resolve(QVector<int>{42, 43, 44}).map([](int v, ...) {
return QPromise<int>([&](const QPromiseResolve<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=]() {
resolve(v + 1);
@ -97,7 +97,7 @@ void tst_qpromise_map::delayedFulfilled()
void tst_qpromise_map::delayedRejected()
{
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
auto p = QtPromise::resolve(QVector<int>{42, 43, 44}).map([](int v, ...) {
return QPromise<int>([&](
const QPromiseResolve<int>& resolve,
const QPromiseReject<int>& reject) {
@ -116,7 +116,7 @@ void tst_qpromise_map::delayedRejected()
void tst_qpromise_map::functorThrows()
{
auto p = QtPromise::qPromise(QVector<int>{42, 43, 44}).map([](int v, ...) {
auto p = QtPromise::resolve(QVector<int>{42, 43, 44}).map([](int v, ...) {
if (v == 43) {
throw QString("foo");
}
@ -129,7 +129,7 @@ void tst_qpromise_map::functorThrows()
void tst_qpromise_map::functorArguments()
{
auto p1 = QtPromise::qPromise(QVector<int>{42, 42, 42}).map([](int v, int i) {
auto p1 = QtPromise::resolve(QVector<int>{42, 42, 42}).map([](int v, int i) {
return v * i;
});
@ -139,8 +139,8 @@ void tst_qpromise_map::functorArguments()
void tst_qpromise_map::preserveOrder()
{
auto p = QtPromise::qPromise(QVector<int>{250, 500, 100}).map([](int v, ...) {
return QtPromise::qPromise(v + 1).delay(v);
auto p = QtPromise::resolve(QVector<int>{250, 500, 100}).map([](int v, ...) {
return QtPromise::resolve(v + 1).delay(v);
});
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<int>>>::value));

View File

@ -8,6 +8,7 @@ SUBDIRS += \
finally \
map \
operators \
resolve \
tap \
tapfail \
then \

View File

@ -0,0 +1,4 @@
TARGET = tst_qpromise_resolve
SOURCES += $$PWD/tst_resolve.cpp
include(../../qtpromise.pri)

View File

@ -0,0 +1,165 @@
#include "../../shared/data.h"
#include "../../shared/utils.h"
// QtPromise
#include <QtPromise>
// Qt
#include <QtTest>
// STL
#include <memory>
using namespace QtPromise;
class tst_qpromise_resolve : public QObject
{
Q_OBJECT
private Q_SLOTS:
void value();
void noValue();
void moveRValue();
void copyLValue();
void qtSharedPtr();
void stdSharedPtr();
};
QTEST_MAIN(tst_qpromise_resolve)
#include "tst_resolve.moc"
void tst_qpromise_resolve::value()
{
int v0 = 42;
const int v1 = 42;
auto p0 = QPromise<int>::resolve(42);
auto p1 = QPromise<int>::resolve(v0);
auto p2 = QPromise<int>::resolve(v1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<int>>::value));
for (const auto& p : {p0, p1, p2}) {
QCOMPARE(p.isFulfilled(), true);
}
for (const auto& p : {p0, p1, p2}) {
QCOMPARE(waitForValue(p, -1), 42);
}
}
void tst_qpromise_resolve::noValue()
{
auto p = QPromise<void>::resolve();
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
QCOMPARE(p.isFulfilled(), true);
QCOMPARE(waitForValue(p, -1, 42), 42);
}
void tst_qpromise_resolve::moveRValue()
{
Data::logs().reset();
{
auto p = QtPromise::resolve(Data(42)).wait();
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Data>>::value));
}
QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 0);
QCOMPARE(Data::logs().move, 1);
QCOMPARE(Data::logs().refs, 0);
}
void tst_qpromise_resolve::copyLValue()
{
Data::logs().reset();
{
Data value(42);
auto p = QtPromise::resolve(value).wait();
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Data>>::value));
}
QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 1);
QCOMPARE(Data::logs().move, 0);
QCOMPARE(Data::logs().refs, 0);
}
// https://github.com/simonbrunel/qtpromise/issues/6
void tst_qpromise_resolve::qtSharedPtr()
{
Data::logs().reset();
QWeakPointer<Data> wptr;
{
QSharedPointer<Data> sptr0(new Data(42));
const QSharedPointer<Data> sptr1 = sptr0;
auto p0 = QPromise<QSharedPointer<Data>>::resolve(QSharedPointer<Data>(new Data(42)));
auto p1 = QPromise<QSharedPointer<Data>>::resolve(sptr0);
auto p2 = QPromise<QSharedPointer<Data>>::resolve(sptr1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<QSharedPointer<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<QSharedPointer<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<QSharedPointer<Data>>>::value));
QCOMPARE(waitForValue(p1, QSharedPointer<Data>()), sptr0);
QCOMPARE(waitForValue(p2, QSharedPointer<Data>()), sptr1);
wptr = sptr0;
QCOMPARE(wptr.isNull(), false);
QCOMPARE(Data::logs().refs, 2);
}
QCOMPARE(wptr.isNull(), true);
QCOMPARE(Data::logs().ctor, 2);
QCOMPARE(Data::logs().copy, 0);
QCOMPARE(Data::logs().move, 0);
QCOMPARE(Data::logs().refs, 0);
}
// https://github.com/simonbrunel/qtpromise/issues/6
void tst_qpromise_resolve::stdSharedPtr()
{
Data::logs().reset();
std::weak_ptr<Data> wptr;
{
std::shared_ptr<Data> sptr0(new Data(42));
const std::shared_ptr<Data> sptr1 = sptr0;
auto p0 = QPromise<std::shared_ptr<Data>>::resolve(std::shared_ptr<Data>(new Data(42)));
auto p1 = QPromise<std::shared_ptr<Data>>::resolve(sptr0);
auto p2 = QPromise<std::shared_ptr<Data>>::resolve(sptr1);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<std::shared_ptr<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1), QPromise<std::shared_ptr<Data>>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<std::shared_ptr<Data>>>::value));
QCOMPARE(waitForValue(p1, std::shared_ptr<Data>()), sptr0);
QCOMPARE(waitForValue(p2, std::shared_ptr<Data>()), sptr1);
wptr = sptr0;
QCOMPARE(wptr.use_count(), 4l);
QCOMPARE(Data::logs().refs, 2);
}
QCOMPARE(wptr.use_count(), 0l);
QCOMPARE(Data::logs().ctor, 2);
QCOMPARE(Data::logs().copy, 0);
QCOMPARE(Data::logs().move, 0);
QCOMPARE(Data::logs().refs, 0);
}

View File

@ -8,7 +8,7 @@ DEFINES += QT_DEPRECATED_WARNINGS
# Additional warnings and make all warnings into errors
# https://github.com/simonbrunel/qtpromise/issues/10
gcc:QMAKE_CXXFLAGS += -Werror -Wold-style-cast
msvc:QMAKE_CXXFLAGS -= -WX
msvc:QMAKE_CXXFLAGS += -WX
coverage {
gcc {
@ -21,6 +21,7 @@ coverage {
}
HEADERS += \
$$PWD/shared/data.h \
$$PWD/shared/object.h \
$$PWD/shared/utils.h

View File

@ -1,6 +1,7 @@
TEMPLATE = subdirs
SUBDIRS += \
benchmark \
deprecations \
exceptions \
future \
helpers \

View File

@ -0,0 +1,76 @@
#ifndef QTPROMISE_TESTS_AUTO_SHARED_DATA_H
#define QTPROMISE_TESTS_AUTO_SHARED_DATA_H
// STL
#include <utility>
struct Logs {
int ctor = 0;
int copy = 0;
int move = 0;
int refs = 0;
void reset() {
ctor = 0;
copy = 0;
move = 0;
refs = 0;
}
};
struct Logger
{
Logger() { logs().ctor++; logs().refs++; }
Logger(const Logger&) { logs().copy++; logs().refs++; }
Logger(Logger&&) { logs().move++; logs().refs++; }
~Logger() { logs().refs--; }
Logger& operator=(const Logger&) { logs().copy++; return *this; }
Logger& operator=(Logger&&) { logs().move++; return *this; }
public: // STATICS
static Logs& logs() { static Logs logs; return logs; }
};
struct Data : public Logger
{
Data(int v) : Logger(), m_value(v) {}
int value() const { return m_value; }
// MSVC 2013 doesn't support implicit generation of the move constructor and
// operator, so we need to explicitly define these methods and thus the copy
// constructor and operator also need to be explicitly defined (error C2280).
// https://stackoverflow.com/a/26581337
Data(const Data& other)
: Logger(other)
, m_value(other.m_value)
{ }
Data(Data&& other) : Logger(std::forward<Data>(other))
{
std::swap(m_value, other.m_value);
}
Data& operator=(const Data& other)
{
Logger::operator=(other);
m_value = other.m_value;
return *this;
}
Data& operator=(Data&& other)
{
Logger::operator=(std::forward<Data>(other));
std::swap(m_value, other.m_value);
return *this;
}
bool operator==(const Data& other) const { return (m_value == other.m_value); }
bool operator!=(const Data& other) const { return (m_value != other.m_value); }
private:
int m_value;
};
#endif // QTPROMISE_TESTS_AUTO_SHARED_DATA_H

View File

@ -102,7 +102,7 @@ void tst_thread::then()
int value = -1;
QThread* target = nullptr;
qPromise(QtConcurrent::run([&](const QPromise<int>& p) {
QtPromise::resolve(QtConcurrent::run([&](const QPromise<int>& p) {
p.then([&](int res) {
target = QThread::currentThread();
value = res;
@ -125,7 +125,7 @@ void tst_thread::then_void()
int value = -1;
QThread* target = nullptr;
qPromise(QtConcurrent::run([&](const QPromise<void>& p) {
QtPromise::resolve(QtConcurrent::run([&](const QPromise<void>& p) {
p.then([&]() {
target = QThread::currentThread();
value = 43;
@ -148,7 +148,7 @@ void tst_thread::fail()
QString error;
QThread* target = nullptr;
qPromise(QtConcurrent::run([&](const QPromise<int>& p) {
QtPromise::resolve(QtConcurrent::run([&](const QPromise<int>& p) {
p.fail([&](const QString& err) {
target = QThread::currentThread();
error = err;
@ -172,7 +172,7 @@ void tst_thread::finally()
int value = -1;
QThread* target = nullptr;
qPromise(QtConcurrent::run([&](const QPromise<int>& p) {
QtPromise::resolve(QtConcurrent::run([&](const QPromise<int>& p) {
p.finally([&]() {
target = QThread::currentThread();
value = 43;