Use clang-format for code style consistency

Based on the WebKit preset and following 'most' of the Qt guidelines, except a few rules that work better for promise continuation lambdas. Requires clang-format 11.
This commit is contained in:
Simon Brunel 2020-03-21 14:23:40 +01:00
parent b99e468c84
commit d43657fbd5
40 changed files with 1534 additions and 1223 deletions

66
.clang-format Normal file
View File

@ -0,0 +1,66 @@
---
Language: Cpp
Standard: Cpp11
BasedOnStyle: WebKit
AlignAfterOpenBracket: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: Empty
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterStruct: true
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Custom
BreakInheritanceList: BeforeComma
BreakConstructorInitializers: BeforeColon
ColumnLimit: 100
CommentPragmas: "^!|^:"
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
Cpp11BracedListStyle: true
FixNamespaceComments: true
ForEachMacros:
- BOOST_FOREACH
- foreach
- forever
- Q_FOREACH
- Q_FOREVER
- QBENCHMARK
- QBENCHMARK_ONCE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<Q.*>'
Priority: 2
SortPriority: 0
- Regex: '^<.*\.h>'
Priority: 3
SortPriority: 0
- Regex: '^<.*>'
Priority: 4
SortPriority: 0
- Regex: '.*'
Priority: 1
SortPriority: 0
IndentPPDirectives: AfterHash
NamespaceIndentation: None
PenaltyReturnTypeOnItsOwnLine: 10
SpaceAfterTemplateKeyword: false
SpaceBeforeCpp11BracedList: false
...

View File

@ -19,27 +19,36 @@
namespace QtPromise { namespace QtPromise {
template <typename T> template<typename T>
class QPromiseBase class QPromiseBase
{ {
public: public:
using Type = T; using Type = T;
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 1, int>::type = 0> template<typename F,
typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 1, int>::type = 0>
inline QPromiseBase(F resolver); inline QPromiseBase(F resolver);
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 2, int>::type = 0> template<typename F,
typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 2, int>::type = 0>
inline QPromiseBase(F resolver); inline QPromiseBase(F resolver);
QPromiseBase(const QPromiseBase<T>& other): m_d{other.m_d} {} QPromiseBase(const QPromiseBase<T>& other) : m_d{other.m_d} { }
QPromiseBase(const QPromise<T>& other): m_d{other.m_d} {} QPromiseBase(const QPromise<T>& other) : m_d{other.m_d} { }
QPromiseBase(QPromiseBase<T>&& other) Q_DECL_NOEXCEPT { swap(other); } QPromiseBase(QPromiseBase<T>&& other) Q_DECL_NOEXCEPT { swap(other); }
virtual ~QPromiseBase() { } virtual ~QPromiseBase() { }
QPromiseBase<T>& operator=(const QPromiseBase<T>& other) { m_d = other.m_d; return *this;} QPromiseBase<T>& operator=(const QPromiseBase<T>& other)
{
m_d = other.m_d;
return *this;
}
QPromiseBase<T>& operator=(QPromiseBase<T>&& other) Q_DECL_NOEXCEPT QPromiseBase<T>& operator=(QPromiseBase<T>&& other) Q_DECL_NOEXCEPT
{ QPromiseBase<T>(std::move(other)).swap(*this); return *this; } {
QPromiseBase<T>(std::move(other)).swap(*this);
return *this;
}
bool operator==(const QPromiseBase<T>& other) const { return (m_d == other.m_d); } bool operator==(const QPromiseBase<T>& other) const { return (m_d == other.m_d); }
bool operator!=(const QPromiseBase<T>& other) const { return (m_d != other.m_d); } bool operator!=(const QPromiseBase<T>& other) const { return (m_d != other.m_d); }
@ -50,31 +59,31 @@ public:
bool isRejected() const { return m_d->isRejected(); } bool isRejected() const { return m_d->isRejected(); }
bool isPending() const { return m_d->isPending(); } bool isPending() const { return m_d->isPending(); }
template <typename TFulfilled, typename TRejected> template<typename TFulfilled, typename TRejected>
inline typename QtPromisePrivate::PromiseHandler<T, TFulfilled>::Promise inline typename QtPromisePrivate::PromiseHandler<T, TFulfilled>::Promise
then(const TFulfilled& fulfilled, const TRejected& rejected) const; then(const TFulfilled& fulfilled, const TRejected& rejected) const;
template <typename TFulfilled> template<typename TFulfilled>
inline typename QtPromisePrivate::PromiseHandler<T, TFulfilled>::Promise inline typename QtPromisePrivate::PromiseHandler<T, TFulfilled>::Promise
then(TFulfilled&& fulfilled) const; then(TFulfilled&& fulfilled) const;
template <typename TRejected> template<typename TRejected>
inline typename QtPromisePrivate::PromiseHandler<T, std::nullptr_t>::Promise inline typename QtPromisePrivate::PromiseHandler<T, std::nullptr_t>::Promise
fail(TRejected&& rejected) const; fail(TRejected&& rejected) const;
template <typename THandler> template<typename THandler>
inline QPromise<T> finally(THandler handler) const; inline QPromise<T> finally(THandler handler) const;
template <typename THandler> template<typename THandler>
inline QPromise<T> tap(THandler handler) const; inline QPromise<T> tap(THandler handler) const;
template <typename THandler> template<typename THandler>
inline QPromise<T> tapFail(THandler handler) const; inline QPromise<T> tapFail(THandler handler) const;
template <typename E = QPromiseTimeoutException> template<typename E = QPromiseTimeoutException>
inline QPromise<T> timeout(int msec, E&& error = E{}) const; inline QPromise<T> timeout(int msec, E&& error = E{}) const;
template <typename E = QPromiseTimeoutException> template<typename E = QPromiseTimeoutException>
inline QPromise<T> timeout(std::chrono::milliseconds msec, E&& error = E{}) const; inline QPromise<T> timeout(std::chrono::milliseconds msec, E&& error = E{}) const;
inline QPromise<T> delay(int msec) const; inline QPromise<T> delay(int msec) const;
@ -83,7 +92,7 @@ public:
inline QPromise<T> wait() const; inline QPromise<T> wait() const;
public: // STATIC public: // STATIC
template <typename E> template<typename E>
inline static QPromise<T> reject(E&& error); inline static QPromise<T> reject(E&& error);
protected: protected:
@ -94,39 +103,35 @@ protected:
QExplicitlySharedDataPointer<QtPromisePrivate::PromiseData<T>> m_d; QExplicitlySharedDataPointer<QtPromisePrivate::PromiseData<T>> m_d;
}; };
template <typename T> template<typename T>
class QPromise : public QPromiseBase<T> class QPromise : public QPromiseBase<T>
{ {
public: 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> template<typename Functor>
inline QPromise<T> inline QPromise<T> each(Functor fn);
each(Functor fn);
template <typename Functor> template<typename Functor>
inline QPromise<T> inline QPromise<T> filter(Functor fn);
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> template<typename Functor, typename Input>
inline typename QtPromisePrivate::PromiseDeduce<Input>::Type inline typename QtPromisePrivate::PromiseDeduce<Input>::Type reduce(Functor fn, Input initial);
reduce(Functor fn, Input initial);
template <typename Functor, typename U = T> template<typename Functor, typename U = T>
inline typename QtPromisePrivate::PromiseDeduce<typename U::value_type>::Type inline typename QtPromisePrivate::PromiseDeduce<typename U::value_type>::Type
reduce(Functor fn); reduce(Functor fn);
public: // STATIC public: // STATIC
// DEPRECATED (remove at version 1) // DEPRECATED (remove at version 1)
template <template <typename, typename...> class Sequence = QVector, typename ...Args> template<template<typename, typename...> class Sequence = QVector, typename... Args>
Q_DECL_DEPRECATED_X("Use QtPromise::all instead") static inline QPromise<QVector<T>> Q_DECL_DEPRECATED_X("Use QtPromise::all instead")
all(const Sequence<QPromise<T>, Args...>& promises); static inline QPromise<QVector<T>> all(const Sequence<QPromise<T>, Args...>& promises);
inline static QPromise<T> resolve(const T& value); inline static QPromise<T> resolve(const T& value);
inline static QPromise<T> resolve(T&& value); inline static QPromise<T> resolve(T&& value);
@ -135,19 +140,19 @@ private:
friend class QPromiseBase<T>; friend class QPromiseBase<T>;
}; };
template <> template<>
class QPromise<void> : public QPromiseBase<void> class QPromise<void> : public QPromiseBase<void>
{ {
public: public:
template <typename F> template<typename F>
QPromise(F&& resolver): QPromiseBase<void>(std::forward<F>(resolver)) { } QPromise(F&& resolver) : QPromiseBase<void>(std::forward<F>(resolver))
{ }
public: // STATIC public: // STATIC
// DEPRECATED (remove at version 1) // DEPRECATED (remove at version 1)
template <template <typename, typename...> class Sequence = QVector, typename ...Args> template<template<typename, typename...> class Sequence = QVector, typename... Args>
Q_DECL_DEPRECATED_X("Use QtPromise::all instead") static inline QPromise<void> Q_DECL_DEPRECATED_X("Use QtPromise::all instead")
all(const Sequence<QPromise<void>, Args...>& promises); static inline QPromise<void> all(const Sequence<QPromise<void>, Args...>& promises);
inline static QPromise<void> resolve(); inline static QPromise<void> resolve();

View File

@ -14,10 +14,9 @@
namespace QtPromise { namespace QtPromise {
template <typename T> template<typename T>
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 1, int>::type> template<typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 1, int>::type>
inline QPromiseBase<T>::QPromiseBase(F callback) inline QPromiseBase<T>::QPromiseBase(F callback) : m_d{new QtPromisePrivate::PromiseData<T>{}}
: m_d{new QtPromisePrivate::PromiseData<T>{}}
{ {
QtPromisePrivate::PromiseResolver<T> resolver{*this}; QtPromisePrivate::PromiseResolver<T> resolver{*this};
@ -28,10 +27,9 @@ inline QPromiseBase<T>::QPromiseBase(F callback)
} }
} }
template <typename T> template<typename T>
template <typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 2, int>::type> template<typename F, typename std::enable_if<QtPromisePrivate::ArgsOf<F>::count == 2, int>::type>
inline QPromiseBase<T>::QPromiseBase(F callback) inline QPromiseBase<T>::QPromiseBase(F callback) : m_d{new QtPromisePrivate::PromiseData<T>{}}
: m_d{new QtPromisePrivate::PromiseData<T>{}}
{ {
QtPromisePrivate::PromiseResolver<T> resolver{*this}; QtPromisePrivate::PromiseResolver<T> resolver{*this};
@ -42,16 +40,15 @@ inline QPromiseBase<T>::QPromiseBase(F callback)
} }
} }
template <typename T> template<typename T>
template <typename TFulfilled, typename TRejected> template<typename TFulfilled, typename TRejected>
inline typename QtPromisePrivate::PromiseHandler<T, TFulfilled>::Promise inline typename QtPromisePrivate::PromiseHandler<T, TFulfilled>::Promise
QPromiseBase<T>::then(const TFulfilled& fulfilled, const TRejected& rejected) const QPromiseBase<T>::then(const TFulfilled& fulfilled, const TRejected& rejected) const
{ {
using namespace QtPromisePrivate; using namespace QtPromisePrivate;
using PromiseType = typename PromiseHandler<T, TFulfilled>::Promise; using PromiseType = typename PromiseHandler<T, TFulfilled>::Promise;
PromiseType next([&]( PromiseType next([&](const QPromiseResolve<typename PromiseType::Type>& resolve,
const QPromiseResolve<typename PromiseType::Type>& resolve,
const QPromiseReject<typename PromiseType::Type>& reject) { const QPromiseReject<typename PromiseType::Type>& reject) {
m_d->addHandler(PromiseHandler<T, TFulfilled>::create(fulfilled, resolve, reject)); m_d->addHandler(PromiseHandler<T, TFulfilled>::create(fulfilled, resolve, reject));
m_d->addCatcher(PromiseCatcher<T, TRejected>::create(rejected, resolve, reject)); m_d->addCatcher(PromiseCatcher<T, TRejected>::create(rejected, resolve, reject));
@ -64,24 +61,24 @@ QPromiseBase<T>::then(const TFulfilled& fulfilled, const TRejected& rejected) co
return next; return next;
} }
template <typename T> template<typename T>
template <typename TFulfilled> template<typename TFulfilled>
inline typename QtPromisePrivate::PromiseHandler<T, TFulfilled>::Promise inline typename QtPromisePrivate::PromiseHandler<T, TFulfilled>::Promise
QPromiseBase<T>::then(TFulfilled&& fulfilled) const QPromiseBase<T>::then(TFulfilled&& fulfilled) const
{ {
return then(std::forward<TFulfilled>(fulfilled), nullptr); return then(std::forward<TFulfilled>(fulfilled), nullptr);
} }
template <typename T> template<typename T>
template <typename TRejected> template<typename TRejected>
inline typename QtPromisePrivate::PromiseHandler<T, std::nullptr_t>::Promise inline typename QtPromisePrivate::PromiseHandler<T, std::nullptr_t>::Promise
QPromiseBase<T>::fail(TRejected&& rejected) const QPromiseBase<T>::fail(TRejected&& rejected) const
{ {
return then(nullptr, std::forward<TRejected>(rejected)); return then(nullptr, std::forward<TRejected>(rejected));
} }
template <typename T> template<typename T>
template <typename THandler> template<typename THandler>
inline QPromise<T> QPromiseBase<T>::finally(THandler handler) const inline QPromise<T> QPromiseBase<T>::finally(THandler handler) const
{ {
QPromise<T> p = *this; QPromise<T> p = *this;
@ -90,8 +87,8 @@ inline QPromise<T> QPromiseBase<T>::finally(THandler handler) const
}); });
} }
template <typename T> template<typename T>
template <typename THandler> template<typename THandler>
inline QPromise<T> QPromiseBase<T>::tap(THandler handler) const inline QPromise<T> QPromiseBase<T>::tap(THandler handler) const
{ {
QPromise<T> p = *this; QPromise<T> p = *this;
@ -100,25 +97,22 @@ inline QPromise<T> QPromiseBase<T>::tap(THandler handler) const
}); });
} }
template <typename T> template<typename T>
template <typename THandler> template<typename THandler>
inline QPromise<T> QPromiseBase<T>::tapFail(THandler handler) const inline QPromise<T> QPromiseBase<T>::tapFail(THandler handler) const
{ {
QPromise<T> p = *this; QPromise<T> p = *this;
return p.then([](){}, handler).then([=]() { return p.then([]() {}, handler).then([=]() {
return p; return p;
}); });
} }
template <typename T> template<typename T>
template <typename E> template<typename E>
inline QPromise<T> QPromiseBase<T>::timeout(int msec, E&& error) const inline QPromise<T> QPromiseBase<T>::timeout(int msec, E&& error) const
{ {
QPromise<T> p = *this; QPromise<T> p = *this;
return QPromise<T>{[&]( return QPromise<T>{[&](const QPromiseResolve<T>& resolve, const QPromiseReject<T>& reject) {
const QPromiseResolve<T>& resolve,
const QPromiseReject<T>& reject) {
QTimer::singleShot(msec, [=]() { QTimer::singleShot(msec, [=]() {
// we don't need to verify the current promise state, reject() // we don't need to verify the current promise state, reject()
// takes care of checking if the promise is already resolved, // takes care of checking if the promise is already resolved,
@ -130,14 +124,14 @@ inline QPromise<T> QPromiseBase<T>::timeout(int msec, E&& error) const
}}; }};
} }
template <typename T> template<typename T>
template <typename E> template<typename E>
inline QPromise<T> QPromiseBase<T>::timeout(std::chrono::milliseconds msec, E&& error) const inline QPromise<T> QPromiseBase<T>::timeout(std::chrono::milliseconds msec, E&& error) const
{ {
return timeout(static_cast<int>(msec.count()), std::forward<E>(error)); return timeout(static_cast<int>(msec.count()), std::forward<E>(error));
} }
template <typename T> template<typename T>
inline QPromise<T> QPromiseBase<T>::delay(int msec) const inline QPromise<T> QPromiseBase<T>::delay(int msec) const
{ {
return tap([=]() { return tap([=]() {
@ -153,7 +147,7 @@ inline QPromise<T> QPromiseBase<T>::delay(std::chrono::milliseconds msec) const
return delay(static_cast<int>(msec.count())); return delay(static_cast<int>(msec.count()));
} }
template <typename T> template<typename T>
inline QPromise<T> QPromiseBase<T>::wait() const inline QPromise<T> QPromiseBase<T>::wait() const
{ {
// @TODO wait timeout + global timeout // @TODO wait timeout + global timeout
@ -165,8 +159,8 @@ inline QPromise<T> QPromiseBase<T>::wait() const
return *this; return *this;
} }
template <typename T> template<typename T>
template <typename E> template<typename E>
inline QPromise<T> QPromiseBase<T>::reject(E&& error) inline QPromise<T> QPromiseBase<T>::reject(E&& error)
{ {
return QPromise<T>{[&](const QPromiseResolve<T>&, const QPromiseReject<T>& reject) { return QPromise<T>{[&](const QPromiseResolve<T>&, const QPromiseReject<T>& reject) {
@ -174,8 +168,8 @@ inline QPromise<T> QPromiseBase<T>::reject(E&& error)
}}; }};
} }
template <typename T> template<typename T>
template <typename Functor> template<typename Functor>
inline QPromise<T> QPromise<T>::each(Functor fn) inline QPromise<T> QPromise<T>::each(Functor fn)
{ {
return this->tap([=](const T& values) { return this->tap([=](const T& values) {
@ -183,9 +177,7 @@ inline QPromise<T> QPromise<T>::each(Functor fn)
std::vector<QPromise<void>> promises; std::vector<QPromise<void>> promises;
for (const auto& v : values) { for (const auto& v : values) {
promises.push_back( promises.push_back(QtPromise::attempt(fn, v, i).then([]() {
QtPromise::attempt(fn, v, i)
.then([]() {
// Cast to void in case fn returns a non promise value. // Cast to void in case fn returns a non promise value.
// TODO remove when implicit cast is implemented. // TODO remove when implicit cast is implemented.
})); }));
@ -197,8 +189,8 @@ inline QPromise<T> QPromise<T>::each(Functor fn)
}); });
} }
template <typename T> template<typename T>
template <typename Functor> template<typename Functor>
inline QPromise<T> QPromise<T>::filter(Functor fn) inline QPromise<T> QPromise<T>::filter(Functor fn)
{ {
return this->then([=](const T& values) { return this->then([=](const T& values) {
@ -206,8 +198,8 @@ inline QPromise<T> QPromise<T>::filter(Functor 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
QPromise<T>::map(Functor fn) QPromise<T>::map(Functor fn)
{ {
@ -216,8 +208,8 @@ QPromise<T>::map(Functor fn)
}); });
} }
template <typename T> template<typename T>
template <typename Functor, typename Input> template<typename Functor, typename Input>
inline typename QtPromisePrivate::PromiseDeduce<Input>::Type inline typename QtPromisePrivate::PromiseDeduce<Input>::Type
QPromise<T>::reduce(Functor fn, Input initial) QPromise<T>::reduce(Functor fn, Input initial)
{ {
@ -226,8 +218,8 @@ QPromise<T>::reduce(Functor fn, Input initial)
}); });
} }
template <typename T> template<typename T>
template <typename Functor, typename U> template<typename Functor, typename U>
inline typename QtPromisePrivate::PromiseDeduce<typename U::value_type>::Type inline typename QtPromisePrivate::PromiseDeduce<typename U::value_type>::Type
QPromise<T>::reduce(Functor fn) QPromise<T>::reduce(Functor fn)
{ {
@ -236,14 +228,14 @@ QPromise<T>::reduce(Functor 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)
{ {
return QtPromise::all(promises); return QtPromise::all(promises);
} }
template <typename T> template<typename T>
inline QPromise<T> QPromise<T>::resolve(const T& value) inline QPromise<T> QPromise<T>::resolve(const T& value)
{ {
return QPromise<T>{[&](const QPromiseResolve<T>& resolve) { return QPromise<T>{[&](const QPromiseResolve<T>& resolve) {
@ -251,7 +243,7 @@ inline QPromise<T> QPromise<T>::resolve(const T& value)
}}; }};
} }
template <typename T> template<typename T>
inline QPromise<T> QPromise<T>::resolve(T&& value) inline QPromise<T> QPromise<T>::resolve(T&& value)
{ {
return QPromise<T>{[&](const QPromiseResolve<T>& resolve) { return QPromise<T>{[&](const QPromiseResolve<T>& resolve) {
@ -259,7 +251,7 @@ inline QPromise<T> QPromise<T>::resolve(T&& value)
}}; }};
} }
template <template <typename, typename...> class Sequence, typename ...Args> template<template<typename, typename...> class Sequence, typename... Args>
inline QPromise<void> QPromise<void>::all(const Sequence<QPromise<void>, Args...>& promises) inline QPromise<void> QPromise<void>::all(const Sequence<QPromise<void>, Args...>& promises)
{ {
return QtPromise::all(promises); return QtPromise::all(promises);

View File

@ -21,13 +21,13 @@
namespace QtPromise { namespace QtPromise {
template <typename T> template<typename T>
class QPromise; class QPromise;
template <typename T> template<typename T>
class QPromiseResolve; class QPromiseResolve;
template <typename T> template<typename T>
class QPromiseReject; class QPromiseReject;
} // namespace QtPromise } // namespace QtPromise
@ -35,7 +35,7 @@ class QPromiseReject;
namespace QtPromisePrivate { namespace QtPromisePrivate {
// https://stackoverflow.com/a/21653558 // https://stackoverflow.com/a/21653558
template <typename F> template<typename F>
static void qtpromise_defer(F&& f, const QPointer<QThread>& thread) static void qtpromise_defer(F&& f, const QPointer<QThread>& thread)
{ {
using FType = typename std::decay<F>::type; using FType = typename std::decay<F>::type;
@ -69,14 +69,14 @@ static void qtpromise_defer(F&& f, const QPointer<QThread>& thread)
QCoreApplication::postEvent(target, new Event{std::forward<F>(f)}); QCoreApplication::postEvent(target, new Event{std::forward<F>(f)});
} }
template <typename F> template<typename F>
static void qtpromise_defer(F&& f) static void qtpromise_defer(F&& f)
{ {
Q_ASSERT(QThread::currentThread()); Q_ASSERT(QThread::currentThread());
qtpromise_defer(std::forward<F>(f), QThread::currentThread()); qtpromise_defer(std::forward<F>(f), QThread::currentThread());
} }
template <typename T> template<typename T>
class PromiseValue class PromiseValue
{ {
public: public:
@ -93,7 +93,7 @@ private:
class PromiseError class PromiseError
{ {
public: public:
template <typename T> template<typename T>
PromiseError(const T& value) PromiseError(const T& value)
{ {
try { try {
@ -113,104 +113,98 @@ private:
std::exception_ptr m_data; std::exception_ptr m_data;
}; };
template <typename T> template<typename T>
struct PromiseDeduce struct PromiseDeduce
{ {
using Type = QtPromise::QPromise<T>; using Type = QtPromise::QPromise<T>;
}; };
template <typename T> template<typename T>
struct PromiseDeduce<T&> struct PromiseDeduce<T&> : public PromiseDeduce<T>
: public PromiseDeduce<T>
{ }; { };
template <typename T> template<typename T>
struct PromiseDeduce<const T> struct PromiseDeduce<const T> : public PromiseDeduce<T>
: public PromiseDeduce<T>
{ }; { };
template <typename T> template<typename T>
struct PromiseDeduce<const volatile T> struct PromiseDeduce<const volatile T> : public PromiseDeduce<T>
: public PromiseDeduce<T>
{ }; { };
template <typename T> template<typename T>
struct PromiseDeduce<QtPromise::QPromise<T>> struct PromiseDeduce<QtPromise::QPromise<T>> : public PromiseDeduce<T>
: public PromiseDeduce<T>
{ }; { };
template <typename Functor, typename... Args> template<typename Functor, typename... Args>
struct PromiseFunctor struct PromiseFunctor
{ {
using ResultType = typename std::result_of<Functor(Args...)>::type; using ResultType = typename std::result_of<Functor(Args...)>::type;
using PromiseType = typename PromiseDeduce<ResultType>::Type; using PromiseType = typename PromiseDeduce<ResultType>::Type;
}; };
template <typename T> template<typename T>
struct PromiseFulfill struct PromiseFulfill
{ {
template <typename V, typename TResolve, typename TReject> template<typename V, typename TResolve, typename TReject>
static void call(V&& value, const TResolve& resolve, const TReject&) static void call(V&& value, const TResolve& resolve, const TReject&)
{ {
resolve(std::forward<V>(value)); resolve(std::forward<V>(value));
} }
}; };
template <typename T> template<typename T>
struct PromiseFulfill<QtPromise::QPromise<T>> struct PromiseFulfill<QtPromise::QPromise<T>>
{ {
template <typename TResolve, typename TReject> template<typename TResolve, typename TReject>
static void call( static void
const QtPromise::QPromise<T>& promise, call(const QtPromise::QPromise<T>& promise, const TResolve& resolve, const TReject& reject)
const TResolve& resolve,
const TReject& reject)
{ {
if (promise.isFulfilled()) { if (promise.isFulfilled()) {
resolve(promise.m_d->value()); resolve(promise.m_d->value());
} else if (promise.isRejected()) { } else if (promise.isRejected()) {
reject(promise.m_d->error()); reject(promise.m_d->error());
} else { } else {
promise.then([=]() { promise.then(
[=]() {
resolve(promise.m_d->value()); resolve(promise.m_d->value());
}, [=]() { // catch all },
[=]() { // catch all
reject(promise.m_d->error()); reject(promise.m_d->error());
}); });
} }
} }
}; };
template <> template<>
struct PromiseFulfill<QtPromise::QPromise<void>> struct PromiseFulfill<QtPromise::QPromise<void>>
{ {
template <typename TPromise, typename TResolve, typename TReject> template<typename TPromise, typename TResolve, typename TReject>
static void call( static void call(const TPromise& promise, const TResolve& resolve, const TReject& reject)
const TPromise& promise,
const TResolve& resolve,
const TReject& reject)
{ {
if (promise.isFulfilled()) { if (promise.isFulfilled()) {
resolve(); resolve();
} else if (promise.isRejected()) { } else if (promise.isRejected()) {
reject(promise.m_d->error()); reject(promise.m_d->error());
} else { } else {
promise.then([=]() { promise.then(
[=]() {
resolve(); resolve();
}, [=]() { // catch all },
[=]() { // catch all
reject(promise.m_d->error()); reject(promise.m_d->error());
}); });
} }
} }
}; };
template <typename Result> template<typename Result>
struct PromiseDispatch struct PromiseDispatch
{ {
template <typename Resolve, typename Reject, typename Functor, typename... Args> template<typename Resolve, typename Reject, typename Functor, typename... Args>
static void call(const Resolve& resolve, const Reject& reject, Functor fn, Args&&... args) static void call(const Resolve& resolve, const Reject& reject, Functor fn, Args&&... args)
{ {
try { try {
PromiseFulfill<Unqualified<Result>>::call( PromiseFulfill<Unqualified<Result>>::call(fn(std::forward<Args>(args)...),
fn(std::forward<Args>(args)...),
resolve, resolve,
reject); reject);
} catch (...) { } catch (...) {
@ -219,10 +213,10 @@ struct PromiseDispatch
} }
}; };
template <> template<>
struct PromiseDispatch<void> struct PromiseDispatch<void>
{ {
template <typename Resolve, typename Reject, typename Functor, typename... Args> template<typename Resolve, typename Reject, typename Functor, typename... Args>
static void call(const Resolve& resolve, const Reject& reject, Functor fn, Args&&... args) static void call(const Resolve& resolve, const Reject& reject, Functor fn, Args&&... args)
{ {
try { try {
@ -234,17 +228,15 @@ struct PromiseDispatch<void>
} }
}; };
template <typename T, typename THandler, typename TArg = typename ArgsOf<THandler>::first> template<typename T, typename THandler, typename TArg = typename ArgsOf<THandler>::first>
struct PromiseHandler struct PromiseHandler
{ {
using ResType = typename std::result_of<THandler(T)>::type; using ResType = typename std::result_of<THandler(T)>::type;
using Promise = typename PromiseDeduce<ResType>::Type; using Promise = typename PromiseDeduce<ResType>::Type;
template <typename TResolve, typename TReject> template<typename TResolve, typename TReject>
static std::function<void(const T&)> create( static std::function<void(const T&)>
const THandler& handler, create(const THandler& handler, const TResolve& resolve, const TReject& reject)
const TResolve& resolve,
const TReject& reject)
{ {
return [=](const T& value) { return [=](const T& value) {
PromiseDispatch<ResType>::call(resolve, reject, handler, value); PromiseDispatch<ResType>::call(resolve, reject, handler, value);
@ -252,17 +244,15 @@ struct PromiseHandler
} }
}; };
template <typename T, typename THandler> template<typename T, typename THandler>
struct PromiseHandler<T, THandler, void> struct PromiseHandler<T, THandler, void>
{ {
using ResType = typename std::result_of<THandler()>::type; using ResType = typename std::result_of<THandler()>::type;
using Promise = typename PromiseDeduce<ResType>::Type; using Promise = typename PromiseDeduce<ResType>::Type;
template <typename TResolve, typename TReject> template<typename TResolve, typename TReject>
static std::function<void(const T&)> create( static std::function<void(const T&)>
const THandler& handler, create(const THandler& handler, const TResolve& resolve, const TReject& reject)
const TResolve& resolve,
const TReject& reject)
{ {
return [=](const T&) { return [=](const T&) {
PromiseDispatch<ResType>::call(resolve, reject, handler); PromiseDispatch<ResType>::call(resolve, reject, handler);
@ -270,17 +260,15 @@ struct PromiseHandler<T, THandler, void>
} }
}; };
template <typename THandler> template<typename THandler>
struct PromiseHandler<void, THandler, void> struct PromiseHandler<void, THandler, void>
{ {
using ResType = typename std::result_of<THandler()>::type; using ResType = typename std::result_of<THandler()>::type;
using Promise = typename PromiseDeduce<ResType>::Type; using Promise = typename PromiseDeduce<ResType>::Type;
template <typename TResolve, typename TReject> template<typename TResolve, typename TReject>
static std::function<void()> create( static std::function<void()>
const THandler& handler, create(const THandler& handler, const TResolve& resolve, const TReject& reject)
const TResolve& resolve,
const TReject& reject)
{ {
return [=]() { return [=]() {
PromiseDispatch<ResType>::call(resolve, reject, handler); PromiseDispatch<ResType>::call(resolve, reject, handler);
@ -288,16 +276,14 @@ struct PromiseHandler<void, THandler, void>
} }
}; };
template <typename T> template<typename T>
struct PromiseHandler<T, std::nullptr_t, void> struct PromiseHandler<T, std::nullptr_t, void>
{ {
using Promise = QtPromise::QPromise<T>; using Promise = QtPromise::QPromise<T>;
template <typename TResolve, typename TReject> template<typename TResolve, typename TReject>
static std::function<void(const T&)> create( static std::function<void(const T&)>
std::nullptr_t, create(std::nullptr_t, const TResolve& resolve, const TReject& reject)
const TResolve& resolve,
const TReject& reject)
{ {
return [=](const T& value) { return [=](const T& value) {
// 2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled, // 2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled,
@ -307,16 +293,13 @@ struct PromiseHandler<T, std::nullptr_t, void>
} }
}; };
template <> template<>
struct PromiseHandler<void, std::nullptr_t, void> struct PromiseHandler<void, std::nullptr_t, void>
{ {
using Promise = QtPromise::QPromise<void>; using Promise = QtPromise::QPromise<void>;
template <typename TResolve, typename TReject> template<typename TResolve, typename TReject>
static std::function<void()> create( static std::function<void()> create(std::nullptr_t, const TResolve& resolve, const TReject&)
std::nullptr_t,
const TResolve& resolve,
const TReject&)
{ {
return [=]() { return [=]() {
// 2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled, // 2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled,
@ -326,16 +309,14 @@ struct PromiseHandler<void, std::nullptr_t, void>
} }
}; };
template <typename T, typename THandler, typename TArg = typename ArgsOf<THandler>::first> template<typename T, typename THandler, typename TArg = typename ArgsOf<THandler>::first>
struct PromiseCatcher struct PromiseCatcher
{ {
using ResType = typename std::result_of<THandler(TArg)>::type; using ResType = typename std::result_of<THandler(TArg)>::type;
template <typename TResolve, typename TReject> template<typename TResolve, typename TReject>
static std::function<void(const PromiseError&)> create( static std::function<void(const PromiseError&)>
const THandler& handler, create(const THandler& handler, const TResolve& resolve, const TReject& reject)
const TResolve& resolve,
const TReject& reject)
{ {
return [=](const PromiseError& error) { return [=](const PromiseError& error) {
try { try {
@ -349,16 +330,14 @@ struct PromiseCatcher
} }
}; };
template <typename T, typename THandler> template<typename T, typename THandler>
struct PromiseCatcher<T, THandler, void> struct PromiseCatcher<T, THandler, void>
{ {
using ResType = typename std::result_of<THandler()>::type; using ResType = typename std::result_of<THandler()>::type;
template <typename TResolve, typename TReject> template<typename TResolve, typename TReject>
static std::function<void(const PromiseError&)> create( static std::function<void(const PromiseError&)>
const THandler& handler, create(const THandler& handler, const TResolve& resolve, const TReject& reject)
const TResolve& resolve,
const TReject& reject)
{ {
return [=](const PromiseError& error) { return [=](const PromiseError& error) {
try { try {
@ -370,14 +349,12 @@ struct PromiseCatcher<T, THandler, void>
} }
}; };
template <typename T> template<typename T>
struct PromiseCatcher<T, std::nullptr_t, void> struct PromiseCatcher<T, std::nullptr_t, void>
{ {
template <typename TResolve, typename TReject> template<typename TResolve, typename TReject>
static std::function<void(const PromiseError&)> create( static std::function<void(const PromiseError&)>
std::nullptr_t, create(std::nullptr_t, const TResolve&, const TReject& reject)
const TResolve&,
const TReject& reject)
{ {
return [=](const PromiseError& error) { return [=](const PromiseError& error) {
// 2.2.7.4. If onRejected is not a function and promise1 is rejected, // 2.2.7.4. If onRejected is not a function and promise1 is rejected,
@ -387,11 +364,11 @@ struct PromiseCatcher<T, std::nullptr_t, void>
} }
}; };
template <typename T, typename F> template<typename T, typename F>
struct PromiseMapper struct PromiseMapper
{ }; { };
template <typename T, typename F, template <typename, typename...> class Sequence, typename ...Args> template<typename T, typename F, template<typename, typename...> class Sequence, typename... Args>
struct PromiseMapper<Sequence<T, Args...>, F> struct PromiseMapper<Sequence<T, Args...>, F>
{ {
using ReturnType = typename std::result_of<F(T, int)>::type; using ReturnType = typename std::result_of<F(T, int)>::type;
@ -399,26 +376,20 @@ struct PromiseMapper<Sequence<T, Args...>, F>
using PromiseType = QtPromise::QPromise<ResultType>; using PromiseType = QtPromise::QPromise<ResultType>;
}; };
template <typename T> class PromiseData; template<typename T>
class PromiseData;
template <typename T, typename F> template<typename T, typename F>
class PromiseDataBase : public QSharedData class PromiseDataBase : public QSharedData
{ {
public: public:
using Handler = std::pair<QPointer<QThread>, std::function<F>>; using Handler = std::pair<QPointer<QThread>, std::function<F>>;
using Catcher = std::pair<QPointer<QThread>, std::function<void(const PromiseError&)>>; using Catcher = std::pair<QPointer<QThread>, std::function<void(const PromiseError&)>>;
virtual ~PromiseDataBase() {} virtual ~PromiseDataBase() { }
bool isFulfilled() const bool isFulfilled() const { return !isPending() && m_error.isNull(); }
{ bool isRejected() const { return !isPending() && !m_error.isNull(); }
return !isPending() && m_error.isNull();
}
bool isRejected() const
{
return !isPending() && !m_error.isNull();
}
bool isPending() const bool isPending() const
{ {
@ -438,7 +409,7 @@ public:
m_catchers.append({QThread::currentThread(), std::move(catcher)}); m_catchers.append({QThread::currentThread(), std::move(catcher)});
} }
template <typename E> template<typename E>
void reject(E&& error) void reject(E&& error)
{ {
Q_ASSERT(isPending()); Q_ASSERT(isPending());
@ -479,11 +450,13 @@ public:
PromiseError error = m_error; PromiseError error = m_error;
Q_ASSERT(!error.isNull()); Q_ASSERT(!error.isNull());
for (const auto& catcher: catchers) { for (const auto& catcher : catchers) {
const auto& fn = catcher.second; const auto& fn = catcher.second;
qtpromise_defer([=]() { qtpromise_defer(
[=]() {
fn(error); fn(error);
}, catcher.first); },
catcher.first);
} }
} }
@ -506,13 +479,13 @@ private:
PromiseError m_error; PromiseError m_error;
}; };
template <typename T> template<typename T>
class PromiseData : public PromiseDataBase<T, void(const T&)> class PromiseData : public PromiseDataBase<T, void(const T&)>
{ {
using Handler = typename PromiseDataBase<T, void(const T&)>::Handler; using Handler = typename PromiseDataBase<T, void(const T&)>::Handler;
public: public:
template <typename V> template<typename V>
void resolve(V&& value) void resolve(V&& value)
{ {
Q_ASSERT(this->isPending()); Q_ASSERT(this->isPending());
@ -532,11 +505,13 @@ public:
PromiseValue<T> value = m_value; PromiseValue<T> value = m_value;
Q_ASSERT(!value.isNull()); Q_ASSERT(!value.isNull());
for (const auto& handler: handlers) { for (const auto& handler : handlers) {
const auto& fn = handler.second; const auto& fn = handler.second;
qtpromise_defer([=]() { qtpromise_defer(
[=]() {
fn(value.data()); fn(value.data());
}, handler.first); },
handler.first);
} }
} }
@ -544,21 +519,18 @@ private:
PromiseValue<T> m_value; PromiseValue<T> m_value;
}; };
template <> template<>
class PromiseData<void> : public PromiseDataBase<void, void()> class PromiseData<void> : public PromiseDataBase<void, void()>
{ {
using Handler = PromiseDataBase<void, void()>::Handler; using Handler = PromiseDataBase<void, void()>::Handler;
public: public:
void resolve() void resolve() { setSettled(); }
{
setSettled();
}
protected: protected:
void notify(const QVector<Handler>& handlers) Q_DECL_OVERRIDE void notify(const QVector<Handler>& handlers) Q_DECL_OVERRIDE
{ {
for (const auto& handler: handlers) { for (const auto& handler : handlers) {
qtpromise_defer(handler.second, handler.first); qtpromise_defer(handler.second, handler.first);
} }
} }
@ -566,7 +538,7 @@ protected:
struct PromiseInspect struct PromiseInspect
{ {
template <typename T> template<typename T>
static inline PromiseData<T>* get(const QtPromise::QPromise<T>& p) static inline PromiseData<T>* get(const QtPromise::QPromise<T>& p)
{ {
return p.m_d.data(); return p.m_d.data();

View File

@ -31,15 +31,17 @@ private:
{ {
QVector<QMetaObject::Connection> connections; QVector<QMetaObject::Connection> connections;
~Data() { ~Data()
{
if (!connections.empty()) { if (!connections.empty()) {
qWarning("QPromiseConnections: destroyed with unhandled connections."); qWarning("QPromiseConnections: destroyed with unhandled connections.");
disconnect(); disconnect();
} }
} }
void disconnect() { void disconnect()
for (const auto& connection: connections) { {
for (const auto& connection : connections) {
QObject::disconnect(connection); QObject::disconnect(connection);
} }
connections.clear(); connections.clear();

View File

@ -15,16 +15,14 @@
namespace QtPromisePrivate { namespace QtPromisePrivate {
template <typename T> template<typename T>
struct PromiseDeduce<QFuture<T>> struct PromiseDeduce<QFuture<T>> : public PromiseDeduce<T>
: public PromiseDeduce<T>
{ }; { };
template <typename T> template<typename T>
struct PromiseFulfill<QFuture<T>> struct PromiseFulfill<QFuture<T>>
{ {
static void call( static void call(const QFuture<T>& future,
const QFuture<T>& future,
const QtPromise::QPromiseResolve<T>& resolve, const QtPromise::QPromiseResolve<T>& resolve,
const QtPromise::QPromiseReject<T>& reject) const QtPromise::QPromiseReject<T>& reject)
{ {
@ -55,11 +53,10 @@ struct PromiseFulfill<QFuture<T>>
} }
}; };
template <> template<>
struct PromiseFulfill<QFuture<void>> struct PromiseFulfill<QFuture<void>>
{ {
static void call( static void call(const QFuture<void>& future,
const QFuture<void>& future,
const QtPromise::QPromiseResolve<void>& resolve, const QtPromise::QPromiseResolve<void>& resolve,
const QtPromise::QPromiseReject<void>& reject) const QtPromise::QPromiseReject<void>& reject)
{ {

View File

@ -13,21 +13,25 @@
#include <array> #include <array>
#include <functional> #include <functional>
namespace QtPromisePrivate namespace QtPromisePrivate {
{
// https://rmf.io/cxx11/even-more-traits#unqualified_types // https://rmf.io/cxx11/even-more-traits#unqualified_types
template <typename T> template<typename T>
using Unqualified = typename std::remove_cv<typename std::remove_reference<T>::type>::type; using Unqualified = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
/*! /*!
* \struct HasCallOperator * \struct HasCallOperator
* http://stackoverflow.com/a/5117641 * http://stackoverflow.com/a/5117641
*/ */
template <typename T> template<typename T>
struct HasCallOperator struct HasCallOperator
{ {
template <typename U> static char check(decltype(&U::operator(), char(0))); template<typename U>
template <typename U> static char (&check(...))[2]; static char check(decltype(&U::operator(), char(0)));
template<typename U>
static char (&check(...))[2];
static const bool value = (sizeof(check<T>(0)) == 1); static const bool value = (sizeof(check<T>(0)) == 1);
}; };
@ -36,7 +40,7 @@ struct HasCallOperator
* http://stackoverflow.com/a/7943765 * http://stackoverflow.com/a/7943765
* http://stackoverflow.com/a/27885283 * http://stackoverflow.com/a/27885283
*/ */
template <typename... Args> template<typename... Args>
struct ArgsTraits struct ArgsTraits
{ {
using types = std::tuple<Args...>; using types = std::tuple<Args...>;
@ -44,7 +48,7 @@ struct ArgsTraits
static const size_t count = std::tuple_size<types>::value; static const size_t count = std::tuple_size<types>::value;
}; };
template <> template<>
struct ArgsTraits<> struct ArgsTraits<>
{ {
using types = std::tuple<>; using types = std::tuple<>;
@ -53,56 +57,56 @@ struct ArgsTraits<>
}; };
// Fallback implementation (type not supported). // Fallback implementation (type not supported).
template <typename T, typename Enabled = void> template<typename T, typename Enabled = void>
struct ArgsOf struct ArgsOf
{ }; { };
// Partial specialization for null function. // Partial specialization for null function.
template <> template<>
struct ArgsOf<std::nullptr_t> : public ArgsTraits<> struct ArgsOf<std::nullptr_t> : public ArgsTraits<>
{ }; { };
// Partial specialization for type with a non-overloaded operator(). // Partial specialization for type with a non-overloaded operator().
// This applies to lambda, std::function but not to std::bind result. // This applies to lambda, std::function but not to std::bind result.
template <typename T> template<typename T>
struct ArgsOf<T, typename std::enable_if<HasCallOperator<T>::value>::type> struct ArgsOf<T, typename std::enable_if<HasCallOperator<T>::value>::type>
: public ArgsOf<decltype(&T::operator())> : public ArgsOf<decltype(&T::operator())>
{ }; { };
// Partial specialization to remove reference and rvalue (e.g. lambda, std::function, etc.). // Partial specialization to remove reference and rvalue (e.g. lambda, std::function, etc.).
template <typename T> template<typename T>
struct ArgsOf<T&> : public ArgsOf<T> struct ArgsOf<T&> : public ArgsOf<T>
{ }; { };
template <typename T> template<typename T>
struct ArgsOf<T&&> : public ArgsOf<T> struct ArgsOf<T&&> : public ArgsOf<T>
{ }; { };
// Partial specialization for function type. // Partial specialization for function type.
template <typename R, typename... Args> template<typename R, typename... Args>
struct ArgsOf<R(Args...)> : public ArgsTraits<Args...> struct ArgsOf<R(Args...)> : public ArgsTraits<Args...>
{ }; { };
// Partial specialization for function pointer. // Partial specialization for function pointer.
template <typename R, typename... Args> template<typename R, typename... Args>
struct ArgsOf<R(*)(Args...)> : public ArgsTraits<Args...> struct ArgsOf<R (*)(Args...)> : public ArgsTraits<Args...>
{ }; { };
// Partial specialization for pointer-to-member-function (i.e. operator()'s). // Partial specialization for pointer-to-member-function (i.e. operator()'s).
template <typename R, typename T, typename... Args> template<typename R, typename T, typename... Args>
struct ArgsOf<R(T::*)(Args...)> : public ArgsTraits<Args...> struct ArgsOf<R (T::*)(Args...)> : public ArgsTraits<Args...>
{ }; { };
template <typename R, typename T, typename... Args> template<typename R, typename T, typename... Args>
struct ArgsOf<R(T::*)(Args...) const> : public ArgsTraits<Args...> struct ArgsOf<R (T::*)(Args...) const> : public ArgsTraits<Args...>
{ }; { };
template <typename R, typename T, typename... Args> template<typename R, typename T, typename... Args>
struct ArgsOf<R(T::*)(Args...) volatile> : public ArgsTraits<Args...> struct ArgsOf<R (T::*)(Args...) volatile> : public ArgsTraits<Args...>
{ }; { };
template <typename R, typename T, typename... Args> template<typename R, typename T, typename... Args>
struct ArgsOf<R(T::*)(Args...) const volatile> : public ArgsTraits<Args...> struct ArgsOf<R (T::*)(Args...) const volatile> : public ArgsTraits<Args...>
{ }; { };
} // namespace QtPromisePrivate } // namespace QtPromisePrivate

View File

@ -13,9 +13,8 @@
namespace QtPromise { namespace QtPromise {
template <typename T> template<typename T>
static inline typename QtPromisePrivate::PromiseDeduce<T>::Type static inline typename QtPromisePrivate::PromiseDeduce<T>::Type resolve(T&& value)
resolve(T&& value)
{ {
using namespace QtPromisePrivate; using namespace QtPromisePrivate;
using PromiseType = typename PromiseDeduce<T>::Type; using PromiseType = typename PromiseDeduce<T>::Type;
@ -24,52 +23,48 @@ resolve(T&& value)
using RejectType = QPromiseReject<ValueType>; using RejectType = QPromiseReject<ValueType>;
return PromiseType{[&](ResolveType&& resolve, RejectType&& reject) { return PromiseType{[&](ResolveType&& resolve, RejectType&& reject) {
PromiseFulfill<Unqualified<T>>::call( PromiseFulfill<Unqualified<T>>::call(std::forward<T>(value),
std::forward<T>(value),
std::forward<ResolveType>(resolve), std::forward<ResolveType>(resolve),
std::forward<RejectType>(reject)); std::forward<RejectType>(reject));
}}; }};
} }
template <typename T> template<typename T>
static inline QPromise<T> static inline QPromise<T> resolve(QPromise<T> value)
resolve(QPromise<T> value)
{ {
return std::move(value); return std::move(value);
} }
static inline QPromise<void> static inline QPromise<void> resolve()
resolve()
{ {
return QPromise<void>{[](const QPromiseResolve<void>& resolve) { return QPromise<void>{[](const QPromiseResolve<void>& resolve) {
resolve(); resolve();
}}; }};
} }
template <typename T, template <typename, typename...> class Sequence = QVector, typename ...Args> template<typename T, template<typename, typename...> class Sequence = QVector, typename... Args>
static inline QPromise<QVector<T>> static inline QPromise<QVector<T>> all(const Sequence<QPromise<T>, Args...>& promises)
all(const Sequence<QPromise<T>, Args...>& promises)
{ {
const int count = static_cast<int>(promises.size()); const int count = static_cast<int>(promises.size());
if (count == 0) { if (count == 0) {
return QtPromise::resolve(QVector<T>{}); return QtPromise::resolve(QVector<T>{});
} }
return QPromise<QVector<T>>{[=]( return QPromise<QVector<T>>{
const QPromiseResolve<QVector<T>>& resolve, [=](const QPromiseResolve<QVector<T>>& resolve, const QPromiseReject<QVector<T>>& reject) {
const QPromiseReject<QVector<T>>& reject) {
auto remaining = QSharedPointer<int>::create(count); auto remaining = QSharedPointer<int>::create(count);
auto results = QSharedPointer<QVector<T>>::create(count); auto results = QSharedPointer<QVector<T>>::create(count);
int i = 0; int i = 0;
for (const auto& promise: promises) { for (const auto& promise : promises) {
promise.then([=](const T& res) mutable { promise.then(
[=](const T& res) mutable {
(*results)[i] = res; (*results)[i] = res;
if (--(*remaining) == 0) { if (--(*remaining) == 0) {
resolve(*results); resolve(*results);
} }
}, [=]() mutable { },
[=]() mutable {
if (*remaining != -1) { if (*remaining != -1) {
*remaining = -1; *remaining = -1;
reject(std::current_exception()); reject(std::current_exception());
@ -81,27 +76,26 @@ all(const Sequence<QPromise<T>, Args...>& promises)
}}; }};
} }
template <template <typename, typename...> class Sequence = QVector, typename ...Args> template<template<typename, typename...> class Sequence = QVector, typename... Args>
static inline QPromise<void> static inline QPromise<void> all(const Sequence<QPromise<void>, Args...>& promises)
all(const Sequence<QPromise<void>, Args...>& promises)
{ {
const int count = static_cast<int>(promises.size()); const int count = static_cast<int>(promises.size());
if (count == 0) { if (count == 0) {
return QtPromise::resolve(); return QtPromise::resolve();
} }
return QPromise<void>{[=]( return QPromise<void>{
const QPromiseResolve<void>& resolve, [=](const QPromiseResolve<void>& resolve, const QPromiseReject<void>& reject) {
const QPromiseReject<void>& reject) {
auto remaining = QSharedPointer<int>::create(count); auto remaining = QSharedPointer<int>::create(count);
for (const auto& promise: promises) { for (const auto& promise : promises) {
promise.then([=]() { promise.then(
[=]() {
if (--(*remaining) == 0) { if (--(*remaining) == 0) {
resolve(); resolve();
} }
}, [=]() { },
[=]() {
if (*remaining != -1) { if (*remaining != -1) {
*remaining = -1; *remaining = -1;
reject(std::current_exception()); reject(std::current_exception());
@ -111,7 +105,7 @@ all(const Sequence<QPromise<void>, Args...>& promises)
}}; }};
} }
template <typename Functor, typename... Args> template<typename Functor, typename... Args>
static inline typename QtPromisePrivate::PromiseFunctor<Functor, Args...>::PromiseType static inline typename QtPromisePrivate::PromiseFunctor<Functor, Args...>::PromiseType
attempt(Functor&& fn, Args&&... args) attempt(Functor&& fn, Args&&... args)
{ {
@ -127,40 +121,36 @@ attempt(Functor&& fn, Args&&... args)
using ResolveType = QPromiseResolve<ValueType>; using ResolveType = QPromiseResolve<ValueType>;
using RejectType = QPromiseReject<ValueType>; using RejectType = QPromiseReject<ValueType>;
return PromiseType{ return PromiseType{[&](ResolveType&& resolve, RejectType&& reject) {
[&](ResolveType&& resolve, RejectType&& reject) { PromiseDispatch<typename FunctorType::ResultType>::call(std::forward<ResolveType>(resolve),
PromiseDispatch<typename FunctorType::ResultType>::call(
std::forward<ResolveType>(resolve),
std::forward<RejectType>(reject), std::forward<RejectType>(reject),
std::forward<Functor>(fn), std::forward<Functor>(fn),
std::forward<Args>(args)...); std::forward<Args>(args)...);
}}; }};
} }
template <typename Sender, typename Signal> template<typename Sender, typename Signal>
static inline typename QtPromisePrivate::PromiseFromSignal<Signal> static inline typename QtPromisePrivate::PromiseFromSignal<Signal>
connect(const Sender* sender, Signal signal) connect(const Sender* sender, Signal signal)
{ {
using namespace QtPromisePrivate; using namespace QtPromisePrivate;
using T = typename PromiseFromSignal<Signal>::Type; using T = typename PromiseFromSignal<Signal>::Type;
return QPromise<T>{ return QPromise<T>{[&](const QPromiseResolve<T>& resolve, const QPromiseReject<T>& reject) {
[&](const QPromiseResolve<T>& resolve, const QPromiseReject<T>& reject) {
QPromiseConnections connections; QPromiseConnections connections;
connectSignalToResolver(connections, resolve, sender, signal); connectSignalToResolver(connections, resolve, sender, signal);
connectDestroyedToReject(connections, reject, sender); connectDestroyedToReject(connections, reject, sender);
}}; }};
} }
template <typename FSender, typename FSignal, typename RSender, typename RSignal> template<typename FSender, typename FSignal, typename RSender, typename RSignal>
static inline typename QtPromisePrivate::PromiseFromSignal<FSignal> static inline typename QtPromisePrivate::PromiseFromSignal<FSignal>
connect(const FSender* fsender, FSignal fsignal, const RSender* rsender, RSignal rsignal) connect(const FSender* fsender, FSignal fsignal, const RSender* rsender, RSignal rsignal)
{ {
using namespace QtPromisePrivate; using namespace QtPromisePrivate;
using T = typename PromiseFromSignal<FSignal>::Type; using T = typename PromiseFromSignal<FSignal>::Type;
return QPromise<T>{ return QPromise<T>{[&](const QPromiseResolve<T>& resolve, const QPromiseReject<T>& reject) {
[&](const QPromiseResolve<T>& resolve, const QPromiseReject<T>& reject) {
QPromiseConnections connections; QPromiseConnections connections;
connectSignalToResolver(connections, resolve, fsender, fsignal); connectSignalToResolver(connections, resolve, fsender, fsignal);
connectSignalToResolver(connections, reject, rsender, rsignal); connectSignalToResolver(connections, reject, rsender, rsignal);
@ -168,21 +158,20 @@ connect(const FSender* fsender, FSignal fsignal, const RSender* rsender, RSignal
}}; }};
} }
template <typename Sender, typename FSignal, typename RSignal> template<typename Sender, typename FSignal, typename RSignal>
static inline typename QtPromisePrivate::PromiseFromSignal<FSignal> static inline typename QtPromisePrivate::PromiseFromSignal<FSignal>
connect(const Sender* sender, FSignal fsignal, RSignal rsignal) connect(const Sender* sender, FSignal fsignal, RSignal rsignal)
{ {
return connect(sender, fsignal, sender, rsignal); return connect(sender, fsignal, sender, rsignal);
} }
template <typename Sequence, typename Functor> template<typename Sequence, typename Functor>
static inline QPromise<Sequence> static inline QPromise<Sequence> each(const Sequence& values, Functor&& fn)
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));
} }
template <typename Sequence, typename Functor> template<typename Sequence, typename Functor>
static inline typename QtPromisePrivate::PromiseMapper<Sequence, Functor>::PromiseType static inline typename QtPromisePrivate::PromiseMapper<Sequence, Functor>::PromiseType
map(const Sequence& values, Functor fn) map(const Sequence& values, Functor fn)
{ {
@ -195,9 +184,8 @@ map(const Sequence& values, Functor fn)
std::vector<QPromise<ResType>> promises; std::vector<QPromise<ResType>> promises;
for (const auto& v : values) { for (const auto& v : values) {
promises.push_back(QPromise<ResType>{[&]( promises.push_back(QPromise<ResType>{
const QPromiseResolve<ResType>& resolve, [&](const QPromiseResolve<ResType>& resolve, const QPromiseReject<ResType>& reject) {
const QPromiseReject<ResType>& reject) {
PromiseFulfill<RetType>::call(fn(v, i), resolve, reject); PromiseFulfill<RetType>::call(fn(v, i), resolve, reject);
}}); }});
@ -207,12 +195,10 @@ map(const Sequence& values, Functor fn)
return QtPromise::all(promises); return QtPromise::all(promises);
} }
template <typename Sequence, typename Functor> template<typename Sequence, typename Functor>
static inline QPromise<Sequence> static inline QPromise<Sequence> filter(const Sequence& values, Functor fn)
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) {
Sequence filtered; Sequence filtered;
auto filter = filters.begin(); auto filter = filters.begin();
@ -228,7 +214,11 @@ filter(const Sequence& values, Functor fn)
}); });
} }
template <typename T, template <typename...> class Sequence = QVector, typename Reducer, typename Input, typename ...Args> template<typename T,
template<typename...> class Sequence = QVector,
typename Reducer,
typename Input,
typename... Args>
static inline typename QtPromisePrivate::PromiseDeduce<Input>::Type static inline typename QtPromisePrivate::PromiseDeduce<Input>::Type
reduce(const Sequence<T, Args...>& values, Reducer fn, Input initial) reduce(const Sequence<T, Args...>& values, Reducer fn, Input initial)
{ {
@ -253,7 +243,10 @@ reduce(const Sequence<T, Args...>& values, Reducer fn, Input initial)
return promise; return promise;
} }
template <typename T, template <typename...> class Sequence = QVector, typename Reducer, typename ...Args> template<typename T,
template<typename...> class Sequence = QVector,
typename Reducer,
typename... Args>
static inline typename QtPromisePrivate::PromiseDeduce<T>::Type static inline typename QtPromisePrivate::PromiseDeduce<T>::Type
reduce(const Sequence<T, Args...>& values, Reducer fn) reduce(const Sequence<T, Args...>& values, Reducer fn)
{ {
@ -283,19 +276,17 @@ reduce(const Sequence<T, Args...>& values, Reducer fn)
// DEPRECATIONS (remove at version 1) // DEPRECATIONS (remove at version 1)
template <typename... Args> template<typename... Args>
Q_DECL_DEPRECATED_X("Use QtPromise::resolve instead") Q_DECL_DEPRECATED_X("Use QtPromise::resolve instead")
static inline auto static inline auto qPromise(Args&&... args)
qPromise(Args&&... args)
-> decltype(QtPromise::resolve(std::forward<Args>(args)...)) -> decltype(QtPromise::resolve(std::forward<Args>(args)...))
{ {
return QtPromise::resolve(std::forward<Args>(args)...); return QtPromise::resolve(std::forward<Args>(args)...);
} }
template <typename... Args> template<typename... Args>
Q_DECL_DEPRECATED_X("Use QtPromise::all instead") Q_DECL_DEPRECATED_X("Use QtPromise::all instead")
static inline auto static inline auto qPromiseAll(Args&&... args)
qPromiseAll(Args&&... args)
-> decltype(QtPromise::all(std::forward<Args>(args)...)) -> decltype(QtPromise::all(std::forward<Args>(args)...))
{ {
return QtPromise::all(std::forward<Args>(args)...); return QtPromise::all(std::forward<Args>(args)...);

View File

@ -16,14 +16,13 @@ namespace QtPromisePrivate {
// TODO: Suppress QPrivateSignal trailing private signal args // TODO: Suppress QPrivateSignal trailing private signal args
// TODO: Support deducing tuple from args (might require MSVC2017) // TODO: Support deducing tuple from args (might require MSVC2017)
template <typename Signal> template<typename Signal>
using PromiseFromSignal = typename QtPromise::QPromise<Unqualified<typename ArgsOf<Signal>::first>>; using PromiseFromSignal = typename QtPromise::QPromise<Unqualified<typename ArgsOf<Signal>::first>>;
// Connect signal() to QPromiseResolve // Connect signal() to QPromiseResolve
template <typename Sender, typename Signal> template<typename Sender, typename Signal>
typename std::enable_if<(ArgsOf<Signal>::count == 0)>::type typename std::enable_if<(ArgsOf<Signal>::count == 0)>::type
connectSignalToResolver( connectSignalToResolver(const QtPromise::QPromiseConnections& connections,
const QtPromise::QPromiseConnections& connections,
const QtPromise::QPromiseResolve<void>& resolve, const QtPromise::QPromiseResolve<void>& resolve,
const Sender* sender, const Sender* sender,
Signal signal) Signal signal)
@ -35,10 +34,9 @@ connectSignalToResolver(
} }
// Connect signal() to QPromiseReject // Connect signal() to QPromiseReject
template <typename T, typename Sender, typename Signal> template<typename T, typename Sender, typename Signal>
typename std::enable_if<(ArgsOf<Signal>::count == 0)>::type typename std::enable_if<(ArgsOf<Signal>::count == 0)>::type
connectSignalToResolver( connectSignalToResolver(const QtPromise::QPromiseConnections& connections,
const QtPromise::QPromiseConnections& connections,
const QtPromise::QPromiseReject<T>& reject, const QtPromise::QPromiseReject<T>& reject,
const Sender* sender, const Sender* sender,
Signal signal) Signal signal)
@ -50,10 +48,9 @@ connectSignalToResolver(
} }
// Connect signal(args...) to QPromiseResolve // Connect signal(args...) to QPromiseResolve
template <typename T, typename Sender, typename Signal> template<typename T, typename Sender, typename Signal>
typename std::enable_if<(ArgsOf<Signal>::count >= 1)>::type typename std::enable_if<(ArgsOf<Signal>::count >= 1)>::type
connectSignalToResolver( connectSignalToResolver(const QtPromise::QPromiseConnections& connections,
const QtPromise::QPromiseConnections& connections,
const QtPromise::QPromiseResolve<T>& resolve, const QtPromise::QPromiseResolve<T>& resolve,
const Sender* sender, const Sender* sender,
Signal signal) Signal signal)
@ -65,10 +62,9 @@ connectSignalToResolver(
} }
// Connect signal(args...) to QPromiseReject // Connect signal(args...) to QPromiseReject
template <typename T, typename Sender, typename Signal> template<typename T, typename Sender, typename Signal>
typename std::enable_if<(ArgsOf<Signal>::count >= 1)>::type typename std::enable_if<(ArgsOf<Signal>::count >= 1)>::type
connectSignalToResolver( connectSignalToResolver(const QtPromise::QPromiseConnections& connections,
const QtPromise::QPromiseConnections& connections,
const QtPromise::QPromiseReject<T>& reject, const QtPromise::QPromiseReject<T>& reject,
const Sender* sender, const Sender* sender,
Signal signal) Signal signal)
@ -81,9 +77,8 @@ connectSignalToResolver(
} }
// Connect QObject::destroyed signal to QPromiseReject // Connect QObject::destroyed signal to QPromiseReject
template <typename T, typename Sender> template<typename T, typename Sender>
void connectDestroyedToReject( void connectDestroyedToReject(const QtPromise::QPromiseConnections& connections,
const QtPromise::QPromiseConnections& connections,
const QtPromise::QPromiseReject<T>& reject, const QtPromise::QPromiseReject<T>& reject,
const Sender* sender) const Sender* sender)
{ {

View File

@ -14,23 +14,23 @@
namespace QtPromise { namespace QtPromise {
template <typename T> class QPromise; template<typename T>
class QPromise;
} // namespace QtPromise } // namespace QtPromise
namespace QtPromisePrivate { namespace QtPromisePrivate {
template <typename T> template<typename T>
class PromiseResolver class PromiseResolver
{ {
public: public:
PromiseResolver(QtPromise::QPromise<T> promise) PromiseResolver(QtPromise::QPromise<T> promise) : m_d{new Data{}}
: m_d{new Data{}}
{ {
m_d->promise = new QtPromise::QPromise<T>{std::move(promise)}; m_d->promise = new QtPromise::QPromise<T>{std::move(promise)};
} }
template <typename E> template<typename E>
void reject(E&& error) void reject(E&& error)
{ {
auto promise = m_d->promise; auto promise = m_d->promise;
@ -53,7 +53,7 @@ public:
} }
} }
template <typename V> template<typename V>
void resolve(V&& value) void resolve(V&& value)
{ {
auto promise = m_d->promise; auto promise = m_d->promise;
@ -93,51 +93,43 @@ private:
} }
}; };
} // QtPromisePrivate } // namespace QtPromisePrivate
namespace QtPromise { namespace QtPromise {
template <class T> template<class T>
class QPromiseResolve class QPromiseResolve
{ {
public: public:
QPromiseResolve(QtPromisePrivate::PromiseResolver<T> resolver) QPromiseResolve(QtPromisePrivate::PromiseResolver<T> resolver) : m_resolver{std::move(resolver)}
: m_resolver{std::move(resolver)}
{ } { }
template <typename V> template<typename V>
void operator()(V&& value) const void operator()(V&& value) const
{ {
m_resolver.resolve(std::forward<V>(value)); m_resolver.resolve(std::forward<V>(value));
} }
void operator()() const void operator()() const { m_resolver.resolve(); }
{
m_resolver.resolve();
}
private: private:
mutable QtPromisePrivate::PromiseResolver<T> m_resolver; mutable QtPromisePrivate::PromiseResolver<T> m_resolver;
}; };
template <class T> template<class T>
class QPromiseReject class QPromiseReject
{ {
public: public:
QPromiseReject(QtPromisePrivate::PromiseResolver<T> resolver) QPromiseReject(QtPromisePrivate::PromiseResolver<T> resolver) : m_resolver{std::move(resolver)}
: m_resolver{std::move(resolver)}
{ } { }
template <typename E> template<typename E>
void operator()(E&& error) const void operator()(E&& error) const
{ {
m_resolver.reject(std::forward<E>(error)); m_resolver.reject(std::forward<E>(error));
} }
void operator()() const void operator()() const { m_resolver.reject(); }
{
m_resolver.reject();
}
private: private:
mutable QtPromisePrivate::PromiseResolver<T> m_resolver; mutable QtPromisePrivate::PromiseResolver<T> m_resolver;

View File

@ -11,11 +11,11 @@
#include <QtTest> #include <QtTest>
#ifdef Q_CC_MSVC #ifdef Q_CC_MSVC
// MSVC calls the copy constructor on std::current_exception AND std::rethrow_exception // MSVC calls the copy constructor on std::current_exception AND std::rethrow_exception
// https://stackoverflow.com/a/31820854 // https://stackoverflow.com/a/31820854
#define EXCEPT_CALL_COPY_CTOR 1 # define EXCEPT_CALL_COPY_CTOR 1
#else #else
#define EXCEPT_CALL_COPY_CTOR 0 # define EXCEPT_CALL_COPY_CTOR 0
#endif #endif
using namespace QtPromise; using namespace QtPromise;
@ -86,9 +86,11 @@ void tst_benchmark::valueThen()
{ // should not copy value on continutation if fulfilled { // should not copy value on continutation if fulfilled
int value = -1; int value = -1;
Data::logs().reset(); Data::logs().reset();
QPromise<Data>::resolve(Data{42}).then([&](const Data& res) { QPromise<Data>::resolve(Data{42})
.then([&](const Data& res) {
value = res.value(); value = res.value();
}).wait(); })
.wait();
QCOMPARE(Data::logs().ctor, 1); QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 0); QCOMPARE(Data::logs().copy, 0);
@ -100,11 +102,15 @@ void tst_benchmark::valueThen()
int value = -1; int value = -1;
QString error; QString error;
Data::logs().reset(); Data::logs().reset();
QPromise<Data>::reject(QString{"foo"}).then([&](const Data& res) { QPromise<Data>::reject(QString{"foo"})
.then(
[&](const Data& res) {
value = res.value(); value = res.value();
}, [&](const QString& err) { },
[&](const QString& err) {
error = err; error = err;
}).wait(); })
.wait();
QCOMPARE(Data::logs().ctor, 0); QCOMPARE(Data::logs().ctor, 0);
QCOMPARE(Data::logs().copy, 0); QCOMPARE(Data::logs().copy, 0);
@ -116,11 +122,14 @@ void tst_benchmark::valueThen()
{ // should move the returned value when fulfilled { // should move the returned value when fulfilled
int value = -1; int value = -1;
Data::logs().reset(); Data::logs().reset();
QPromise<int>::resolve(42).then([&](int res) { QPromise<int>::resolve(42)
return Data{res+2}; .then([&](int res) {
}).then([&](const Data& res) { return Data{res + 2};
})
.then([&](const Data& res) {
value = res.value(); value = res.value();
}).wait(); })
.wait();
QCOMPARE(Data::logs().ctor, 1); QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 0); QCOMPARE(Data::logs().copy, 0);
@ -130,10 +139,12 @@ void tst_benchmark::valueThen()
} }
{ // should not create any data if handler throws { // should not create any data if handler throws
Data::logs().reset(); Data::logs().reset();
QPromise<int>::resolve(42).then([&](int res) { QPromise<int>::resolve(42)
.then([&](int res) {
throw QString{"foo"}; throw QString{"foo"};
return Data{res+2}; return Data{res + 2};
}).wait(); })
.wait();
QCOMPARE(Data::logs().ctor, 0); QCOMPARE(Data::logs().ctor, 0);
QCOMPARE(Data::logs().copy, 0); QCOMPARE(Data::logs().copy, 0);
@ -147,11 +158,14 @@ void tst_benchmark::valueDelayed()
{ // should not copy the value on continutation if fulfilled { // should not copy the value on continutation if fulfilled
int value = -1; int value = -1;
Data::logs().reset(); Data::logs().reset();
QPromise<int>::resolve(42).then([&](int res) { QPromise<int>::resolve(42)
.then([&](int res) {
return QPromise<Data>::resolve(Data{res + 1}); return QPromise<Data>::resolve(Data{res + 1});
}).then([&](const Data& res) { })
.then([&](const Data& res) {
value = res.value(); value = res.value();
}).wait(); })
.wait();
QCOMPARE(Data::logs().ctor, 1); QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 0); QCOMPARE(Data::logs().copy, 0);
@ -161,9 +175,11 @@ void tst_benchmark::valueDelayed()
} }
{ // should not create value on continutation if rejected { // should not create value on continutation if rejected
Data::logs().reset(); Data::logs().reset();
QPromise<int>::resolve(42).then([&]() { QPromise<int>::resolve(42)
.then([&]() {
return QPromise<Data>::reject(QString{"foo"}); return QPromise<Data>::reject(QString{"foo"});
}).wait(); })
.wait();
QCOMPARE(Data::logs().ctor, 0); QCOMPARE(Data::logs().ctor, 0);
QCOMPARE(Data::logs().copy, 0); QCOMPARE(Data::logs().copy, 0);
@ -177,9 +193,11 @@ void tst_benchmark::valueFinally()
{ // should not copy the value on continutation if fulfilled { // should not copy the value on continutation if fulfilled
int value = -1; int value = -1;
Data::logs().reset(); Data::logs().reset();
QPromise<Data>::resolve(Data{42}).finally([&]() { QPromise<Data>::resolve(Data{42})
.finally([&]() {
value = 42; value = 42;
}).wait(); })
.wait();
QCOMPARE(Data::logs().ctor, 1); QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 0); QCOMPARE(Data::logs().copy, 0);
@ -190,9 +208,11 @@ void tst_benchmark::valueFinally()
{ // should not create value on continutation if rejected { // should not create value on continutation if rejected
int value = -1; int value = -1;
Data::logs().reset(); Data::logs().reset();
QPromise<Data>::reject(QString{"foo"}).finally([&]() { QPromise<Data>::reject(QString{"foo"})
.finally([&]() {
value = 42; value = 42;
}).wait(); })
.wait();
QCOMPARE(Data::logs().ctor, 0); QCOMPARE(Data::logs().ctor, 0);
QCOMPARE(Data::logs().copy, 0); QCOMPARE(Data::logs().copy, 0);
@ -207,9 +227,11 @@ void tst_benchmark::valueTap()
{ // should not copy the value on continutation if fulfilled { // should not copy the value on continutation if fulfilled
int value = -1; int value = -1;
Data::logs().reset(); Data::logs().reset();
QPromise<Data>::resolve(Data{42}).tap([&](const Data& res) { QPromise<Data>::resolve(Data{42})
.tap([&](const Data& res) {
value = res.value(); value = res.value();
}).wait(); })
.wait();
QCOMPARE(Data::logs().ctor, 1); QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 0); QCOMPARE(Data::logs().copy, 0);
@ -220,9 +242,11 @@ void tst_benchmark::valueTap()
{ // should not create value on continutation if rejected { // should not create value on continutation if rejected
int value = -1; int value = -1;
Data::logs().reset(); Data::logs().reset();
QPromise<Data>::reject(QString{"foo"}).tap([&](const Data& res) { QPromise<Data>::reject(QString{"foo"})
.tap([&](const Data& res) {
value = res.value(); value = res.value();
}).wait(); })
.wait();
QCOMPARE(Data::logs().ctor, 0); QCOMPARE(Data::logs().ctor, 0);
QCOMPARE(Data::logs().copy, 0); QCOMPARE(Data::logs().copy, 0);
@ -264,12 +288,15 @@ void tst_benchmark::errorThen()
{ // should not copy error on continutation if rejected { // should not copy error on continutation if rejected
int value = -1; int value = -1;
Data::logs().reset(); Data::logs().reset();
QPromise<void>::reject(Data{42}).fail([&](const Data& res) { QPromise<void>::reject(Data{42})
.fail([&](const Data& res) {
value = res.value(); value = res.value();
}).wait(); })
.wait();
QCOMPARE(Data::logs().ctor, 1); QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 1 + 2 * EXCEPT_CALL_COPY_CTOR); // (initial) copy value in std::exception_ptr QCOMPARE(Data::logs().copy,
1 + 2 * EXCEPT_CALL_COPY_CTOR); // (initial) copy value in std::exception_ptr
QCOMPARE(Data::logs().move, 0); QCOMPARE(Data::logs().move, 0);
QCOMPARE(Data::logs().refs, 0); QCOMPARE(Data::logs().refs, 0);
QCOMPARE(value, 42); QCOMPARE(value, 42);
@ -277,14 +304,18 @@ void tst_benchmark::errorThen()
{ // should not copy error on continutation if rethrown { // should not copy error on continutation if rethrown
int value = -1; int value = -1;
Data::logs().reset(); Data::logs().reset();
QPromise<void>::reject(Data{42}).fail([](const Data&) { QPromise<void>::reject(Data{42})
.fail([](const Data&) {
throw; throw;
}).fail([&](const Data& res) { })
.fail([&](const Data& res) {
value = res.value(); value = res.value();
}).wait(); })
.wait();
QCOMPARE(Data::logs().ctor, 1); QCOMPARE(Data::logs().ctor, 1);
QCOMPARE(Data::logs().copy, 1 + 4 * EXCEPT_CALL_COPY_CTOR); // (initial) copy value in std::exception_ptr QCOMPARE(Data::logs().copy,
1 + 4 * EXCEPT_CALL_COPY_CTOR); // (initial) copy value in std::exception_ptr
QCOMPARE(Data::logs().move, 0); QCOMPARE(Data::logs().move, 0);
QCOMPARE(Data::logs().refs, 0); QCOMPARE(Data::logs().refs, 0);
QCOMPARE(value, 42); QCOMPARE(value, 42);

View File

@ -175,7 +175,7 @@ void tst_deprecations_helpers_qpromise::stdSharedPtr()
void tst_deprecations_helpers_qpromise::typedPromise() void tst_deprecations_helpers_qpromise::typedPromise()
{ {
auto resolver = [](const QPromiseResolve<int>& resolve) { auto resolver = [](const QPromiseResolve<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
resolve(42); resolve(42);
}); });
}; };
@ -202,7 +202,7 @@ void tst_deprecations_helpers_qpromise::typedPromise()
void tst_deprecations_helpers_qpromise::voidPromise() void tst_deprecations_helpers_qpromise::voidPromise()
{ {
auto resolver = [](const QPromiseResolve<void>& resolve) { auto resolver = [](const QPromiseResolve<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
resolve(); resolve();
}); });
}; };
@ -228,7 +228,9 @@ void tst_deprecations_helpers_qpromise::voidPromise()
void tst_deprecations_helpers_qpromise::typedFuture() void tst_deprecations_helpers_qpromise::typedFuture()
{ {
auto fn = [](){ return 42; }; auto fn = []() {
return 42;
};
QFuture<int> v0 = QtConcurrent::run(fn); QFuture<int> v0 = QtConcurrent::run(fn);
const QFuture<int> v1 = v0; const QFuture<int> v1 = v0;
@ -250,7 +252,7 @@ void tst_deprecations_helpers_qpromise::typedFuture()
void tst_deprecations_helpers_qpromise::voidFuture() void tst_deprecations_helpers_qpromise::voidFuture()
{ {
auto fn = [](){ }; auto fn = []() {};
QFuture<void> v0 = QtConcurrent::run(fn); QFuture<void> v0 = QtConcurrent::run(fn);
const QFuture<void> v1 = v0; const QFuture<void> v1 = v0;

View File

@ -33,18 +33,14 @@ QTEST_MAIN(tst_deprecations_helpers_qpromiseall)
namespace { namespace {
template <class Sequence> template<class Sequence>
struct SequenceTester struct SequenceTester
{ {
Q_STATIC_ASSERT((std::is_same<typename Sequence::value_type, QPromise<int>>::value)); Q_STATIC_ASSERT((std::is_same<typename Sequence::value_type, QPromise<int>>::value));
static void exec() static void exec()
{ {
Sequence promises{ Sequence promises{QtPromise::resolve(42), QtPromise::resolve(43), QtPromise::resolve(44)};
QtPromise::resolve(42),
QtPromise::resolve(43),
QtPromise::resolve(44)
};
promises.push_back(QtPromise::resolve(45)); promises.push_back(QtPromise::resolve(45));
promises.insert(++promises.begin(), QtPromise::resolve(46)); promises.insert(++promises.begin(), QtPromise::resolve(46));
@ -58,16 +54,14 @@ struct SequenceTester
} }
}; };
template <template <typename, typename...> class Sequence, typename ...Args> template<template<typename, typename...> class Sequence, typename... Args>
struct SequenceTester<Sequence<QPromise<void>, Args...>> struct SequenceTester<Sequence<QPromise<void>, Args...>>
{ {
static void exec() static void exec()
{ {
Sequence<QPromise<void>, Args...> promises{ Sequence<QPromise<void>, Args...> promises{QtPromise::resolve(),
QtPromise::resolve(), QtPromise::resolve(),
QtPromise::resolve(), QtPromise::resolve()};
QtPromise::resolve()
};
promises.push_back(QtPromise::resolve()); promises.push_back(QtPromise::resolve());
promises.insert(++promises.begin(), QtPromise::resolve()); promises.insert(++promises.begin(), QtPromise::resolve());
@ -106,7 +100,7 @@ void tst_deprecations_helpers_qpromiseall::allPromisesSucceed()
auto p0 = QtPromise::resolve(42); auto p0 = QtPromise::resolve(42);
auto p1 = QtPromise::resolve(44); auto p1 = QtPromise::resolve(44);
auto p2 = QPromise<int>{[](const QPromiseResolve<int>& resolve) { auto p2 = QPromise<int>{[](const QPromiseResolve<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
resolve(43); resolve(43);
}); });
}}; }};
@ -127,7 +121,7 @@ void tst_deprecations_helpers_qpromiseall::allPromisesSucceed_void()
auto p0 = QtPromise::resolve(); auto p0 = QtPromise::resolve();
auto p1 = QtPromise::resolve(); auto p1 = QtPromise::resolve();
auto p2 = QPromise<void>{[](const QPromiseResolve<void>& resolve) { auto p2 = QPromise<void>{[](const QPromiseResolve<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
resolve(); resolve();
}); });
}}; }};
@ -148,7 +142,7 @@ void tst_deprecations_helpers_qpromiseall::atLeastOnePromiseReject()
auto p0 = QtPromise::resolve(42); auto p0 = QtPromise::resolve(42);
auto p1 = QtPromise::resolve(44); auto p1 = QtPromise::resolve(44);
auto p2 = QPromise<int>{[](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) { auto p2 = QPromise<int>{[](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
reject(QString{"foo"}); reject(QString{"foo"});
}); });
}}; }};
@ -169,7 +163,7 @@ void tst_deprecations_helpers_qpromiseall::atLeastOnePromiseReject_void()
auto p0 = QtPromise::resolve(); auto p0 = QtPromise::resolve();
auto p1 = QtPromise::resolve(); auto p1 = QtPromise::resolve();
auto p2 = QPromise<void>{[](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) { auto p2 = QPromise<void>{[](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
reject(QString{"foo"}); reject(QString{"foo"});
}); });
}}; }};
@ -210,7 +204,7 @@ void tst_deprecations_helpers_qpromiseall::preserveOrder()
void tst_deprecations_helpers_qpromiseall::sequenceTypes() void tst_deprecations_helpers_qpromiseall::sequenceTypes()
{ {
SequenceTester<QList<QPromise<int>>>::exec(); SequenceTester<QList<QPromise<int>>>::exec();
//SequenceTester<QVector<QPromise<int>>>::exec(); // SequenceTester<QVector<QPromise<int>>>::exec();
SequenceTester<std::list<QPromise<int>>>::exec(); SequenceTester<std::list<QPromise<int>>>::exec();
SequenceTester<std::vector<QPromise<int>>>::exec(); SequenceTester<std::vector<QPromise<int>>>::exec();
} }
@ -218,7 +212,7 @@ void tst_deprecations_helpers_qpromiseall::sequenceTypes()
void tst_deprecations_helpers_qpromiseall::sequenceTypes_void() void tst_deprecations_helpers_qpromiseall::sequenceTypes_void()
{ {
SequenceTester<QList<QPromise<void>>>::exec(); SequenceTester<QList<QPromise<void>>>::exec();
//SequenceTester<QVector<QPromise<void>>>::exec(); // SequenceTester<QVector<QPromise<void>>>::exec();
SequenceTester<std::list<QPromise<void>>>::exec(); SequenceTester<std::list<QPromise<void>>>::exec();
SequenceTester<std::vector<QPromise<void>>>::exec(); SequenceTester<std::vector<QPromise<void>>>::exec();
} }

View File

@ -33,18 +33,14 @@ QTEST_MAIN(tst_deprecations_qpromise_all)
namespace { namespace {
template <class Sequence> template<class Sequence>
struct SequenceTester struct SequenceTester
{ {
Q_STATIC_ASSERT((std::is_same<typename Sequence::value_type, QPromise<int>>::value)); Q_STATIC_ASSERT((std::is_same<typename Sequence::value_type, QPromise<int>>::value));
static void exec() static void exec()
{ {
Sequence promises{ Sequence promises{QtPromise::resolve(42), QtPromise::resolve(43), QtPromise::resolve(44)};
QtPromise::resolve(42),
QtPromise::resolve(43),
QtPromise::resolve(44)
};
promises.push_back(QtPromise::resolve(45)); promises.push_back(QtPromise::resolve(45));
promises.insert(++promises.begin(), QtPromise::resolve(46)); promises.insert(++promises.begin(), QtPromise::resolve(46));
@ -59,16 +55,14 @@ struct SequenceTester
} }
}; };
template <template <typename, typename...> class Sequence, typename ...Args> template<template<typename, typename...> class Sequence, typename... Args>
struct SequenceTester<Sequence<QPromise<void>, Args...>> struct SequenceTester<Sequence<QPromise<void>, Args...>>
{ {
static void exec() static void exec()
{ {
Sequence<QPromise<void>, Args...> promises{ Sequence<QPromise<void>, Args...> promises{QtPromise::resolve(),
QtPromise::resolve(), QtPromise::resolve(),
QtPromise::resolve(), QtPromise::resolve()};
QtPromise::resolve()
};
promises.push_back(QtPromise::resolve()); promises.push_back(QtPromise::resolve());
promises.insert(++promises.begin(), QtPromise::resolve()); promises.insert(++promises.begin(), QtPromise::resolve());
@ -110,7 +104,7 @@ void tst_deprecations_qpromise_all::allPromisesSucceed()
auto p0 = QtPromise::resolve(42); auto p0 = QtPromise::resolve(42);
auto p1 = QtPromise::resolve(44); auto p1 = QtPromise::resolve(44);
auto p2 = QPromise<int>{[](const QPromiseResolve<int>& resolve) { auto p2 = QPromise<int>{[](const QPromiseResolve<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
resolve(43); resolve(43);
}); });
}}; }};
@ -132,7 +126,7 @@ void tst_deprecations_qpromise_all::allPromisesSucceed_void()
auto p0 = QtPromise::resolve(); auto p0 = QtPromise::resolve();
auto p1 = QtPromise::resolve(); auto p1 = QtPromise::resolve();
auto p2 = QPromise<void>{[](const QPromiseResolve<void>& resolve) { auto p2 = QPromise<void>{[](const QPromiseResolve<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
resolve(); resolve();
}); });
}}; }};
@ -154,7 +148,7 @@ void tst_deprecations_qpromise_all::atLeastOnePromiseReject()
auto p0 = QtPromise::resolve(42); auto p0 = QtPromise::resolve(42);
auto p1 = QtPromise::resolve(44); auto p1 = QtPromise::resolve(44);
auto p2 = QPromise<int>{[](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) { auto p2 = QPromise<int>{[](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
reject(QString{"foo"}); reject(QString{"foo"});
}); });
}}; }};
@ -176,7 +170,7 @@ void tst_deprecations_qpromise_all::atLeastOnePromiseReject_void()
auto p0 = QtPromise::resolve(); auto p0 = QtPromise::resolve();
auto p1 = QtPromise::resolve(); auto p1 = QtPromise::resolve();
auto p2 = QPromise<void>{[](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) { auto p2 = QPromise<void>{[](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
reject(QString{"foo"}); reject(QString{"foo"});
}); });
}}; }};
@ -219,7 +213,7 @@ void tst_deprecations_qpromise_all::preserveOrder()
void tst_deprecations_qpromise_all::sequenceTypes() void tst_deprecations_qpromise_all::sequenceTypes()
{ {
SequenceTester<QList<QPromise<int>>>::exec(); SequenceTester<QList<QPromise<int>>>::exec();
//SequenceTester<QVector<QPromise<int>>>::exec(); // SequenceTester<QVector<QPromise<int>>>::exec();
SequenceTester<std::list<QPromise<int>>>::exec(); SequenceTester<std::list<QPromise<int>>>::exec();
SequenceTester<std::vector<QPromise<int>>>::exec(); SequenceTester<std::vector<QPromise<int>>>::exec();
} }
@ -227,7 +221,7 @@ void tst_deprecations_qpromise_all::sequenceTypes()
void tst_deprecations_qpromise_all::sequenceTypes_void() void tst_deprecations_qpromise_all::sequenceTypes_void()
{ {
SequenceTester<QList<QPromise<void>>>::exec(); SequenceTester<QList<QPromise<void>>>::exec();
//SequenceTester<QVector<QPromise<void>>>::exec(); // SequenceTester<QVector<QPromise<void>>>::exec();
SequenceTester<std::list<QPromise<void>>>::exec(); SequenceTester<std::list<QPromise<void>>>::exec();
SequenceTester<std::vector<QPromise<void>>>::exec(); SequenceTester<std::vector<QPromise<void>>>::exec();
} }

View File

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

View File

@ -37,9 +37,7 @@ private Q_SLOTS:
class MyException : public QException class MyException : public QException
{ {
public: public:
MyException(const QString& error) MyException(const QString& error) : m_error{error} { }
: m_error{error}
{ }
const QString& error() const { return m_error; } const QString& error() const { return m_error; }
@ -74,7 +72,7 @@ void tst_future::fulfilled()
void tst_future::fulfilled_void() void tst_future::fulfilled_void()
{ {
int result = -1; int result = -1;
auto p = QtPromise::resolve(QtConcurrent::run([]() { })); auto p = QtPromise::resolve(QtConcurrent::run([]() {}));
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<void>>::value));
QCOMPARE(p.isPending(), true); QCOMPARE(p.isPending(), true);
@ -141,10 +139,12 @@ void tst_future::unhandled()
p.fail([&](const QString& err) { p.fail([&](const QString& err) {
error += err; error += err;
return -1; return -1;
}).fail([&](const QUnhandledException&) { })
.fail([&](const QUnhandledException&) {
error += "bar"; error += "bar";
return -1; return -1;
}).wait(); })
.wait();
QCOMPARE(p.isRejected(), true); QCOMPARE(p.isRejected(), true);
QCOMPARE(error, QString{"bar"}); QCOMPARE(error, QString{"bar"});
@ -162,9 +162,11 @@ void tst_future::unhandled_void()
p.fail([&](const QString& err) { p.fail([&](const QString& err) {
error += err; error += err;
}).fail([&](const QUnhandledException&) { })
.fail([&](const QUnhandledException&) {
error += "bar"; error += "bar";
}).wait(); })
.wait();
QCOMPARE(p.isRejected(), true); QCOMPARE(p.isRejected(), true);
QCOMPARE(error, QString{"bar"}); QCOMPARE(error, QString{"bar"});
@ -231,9 +233,11 @@ void tst_future::then()
QCOMPARE(input.isFulfilled(), true); QCOMPARE(input.isFulfilled(), true);
QCOMPARE(output.isPending(), true); QCOMPARE(output.isPending(), true);
output.then([&](const QString& res) { output
.then([&](const QString& res) {
result = res; result = res;
}).wait(); })
.wait();
QCOMPARE(output.isFulfilled(), true); QCOMPARE(output.isFulfilled(), true);
QCOMPARE(result, QString{"foo42"}); QCOMPARE(result, QString{"foo42"});
@ -252,9 +256,11 @@ void tst_future::then_void()
QCOMPARE(input.isFulfilled(), true); QCOMPARE(input.isFulfilled(), true);
QCOMPARE(output.isPending(), true); QCOMPARE(output.isPending(), true);
output.then([&]() { output
.then([&]() {
result += "bar"; result += "bar";
}).wait(); })
.wait();
QCOMPARE(input.isFulfilled(), true); QCOMPARE(input.isFulfilled(), true);
QCOMPARE(result, QString{"foobar"}); QCOMPARE(result, QString{"foobar"});
@ -265,17 +271,21 @@ void tst_future::fail()
QString result; QString result;
auto input = QPromise<QString>::reject(MyException{"bar"}); auto input = QPromise<QString>::reject(MyException{"bar"});
auto output = input.fail([](const MyException& e) { auto output = input.fail([](const MyException& e) {
return QtConcurrent::run([](const QString& error) { return QtConcurrent::run(
[](const QString& error) {
return QString{"foo%1"}.arg(error); return QString{"foo%1"}.arg(error);
}, e.error()); },
e.error());
}); });
QCOMPARE(input.isRejected(), true); QCOMPARE(input.isRejected(), true);
QCOMPARE(output.isPending(), true); QCOMPARE(output.isPending(), true);
output.then([&](const QString& res) { output
.then([&](const QString& res) {
result = res; result = res;
}).wait(); })
.wait();
QCOMPARE(output.isFulfilled(), true); QCOMPARE(output.isFulfilled(), true);
QCOMPARE(result, QString{"foobar"}); QCOMPARE(result, QString{"foobar"});
@ -286,17 +296,21 @@ void tst_future::fail_void()
QString result; QString result;
auto input = QPromise<void>::reject(MyException{"bar"}); auto input = QPromise<void>::reject(MyException{"bar"});
auto output = input.fail([&](const MyException& e) { auto output = input.fail([&](const MyException& e) {
return QtConcurrent::run([&](const QString& error) { return QtConcurrent::run(
[&](const QString& error) {
result = error; result = error;
}, e.error()); },
e.error());
}); });
QCOMPARE(input.isRejected(), true); QCOMPARE(input.isRejected(), true);
QCOMPARE(output.isPending(), true); QCOMPARE(output.isPending(), true);
output.then([&]() { output
.then([&]() {
result = result.prepend("foo"); result = result.prepend("foo");
}).wait(); })
.wait();
QCOMPARE(output.isFulfilled(), true); QCOMPARE(output.isFulfilled(), true);
QCOMPARE(result, QString{"foobar"}); QCOMPARE(result, QString{"foobar"});
@ -317,9 +331,11 @@ void tst_future::finally()
QCOMPARE(output.isPending(), true); QCOMPARE(output.isPending(), true);
int value = -1; int value = -1;
output.then([&](int res) { output
.then([&](int res) {
value = res; value = res;
}).wait(); })
.wait();
QCOMPARE(output.isFulfilled(), true); QCOMPARE(output.isFulfilled(), true);
QCOMPARE(value, 42); QCOMPARE(value, 42);
@ -340,10 +356,12 @@ void tst_future::finallyRejected()
QCOMPARE(output.isPending(), true); QCOMPARE(output.isPending(), true);
QString error; QString error;
output.fail([&](const MyException& e) { output
.fail([&](const MyException& e) {
error = e.error(); error = e.error();
return -1; return -1;
}).wait(); })
.wait();
QCOMPARE(output.isRejected(), true); QCOMPARE(output.isRejected(), true);
QCOMPARE(error, QString{"foo"}); QCOMPARE(error, QString{"foo"});

View File

@ -33,18 +33,14 @@ QTEST_MAIN(tst_helpers_all)
namespace { namespace {
template <class Sequence> template<class Sequence>
struct SequenceTester struct SequenceTester
{ {
Q_STATIC_ASSERT((std::is_same<typename Sequence::value_type, QPromise<int>>::value)); Q_STATIC_ASSERT((std::is_same<typename Sequence::value_type, QPromise<int>>::value));
static void exec() static void exec()
{ {
Sequence promises{ Sequence promises{QtPromise::resolve(42), QtPromise::resolve(43), QtPromise::resolve(44)};
QtPromise::resolve(42),
QtPromise::resolve(43),
QtPromise::resolve(44)
};
promises.push_back(QtPromise::resolve(45)); promises.push_back(QtPromise::resolve(45));
promises.insert(++promises.begin(), QtPromise::resolve(46)); promises.insert(++promises.begin(), QtPromise::resolve(46));
@ -58,16 +54,14 @@ struct SequenceTester
} }
}; };
template <template <typename, typename...> class Sequence, typename ...Args> template<template<typename, typename...> class Sequence, typename... Args>
struct SequenceTester<Sequence<QPromise<void>, Args...>> struct SequenceTester<Sequence<QPromise<void>, Args...>>
{ {
static void exec() static void exec()
{ {
Sequence<QPromise<void>, Args...> promises{ Sequence<QPromise<void>, Args...> promises{QtPromise::resolve(),
QtPromise::resolve(), QtPromise::resolve(),
QtPromise::resolve(), QtPromise::resolve()};
QtPromise::resolve()
};
promises.push_back(QtPromise::resolve()); promises.push_back(QtPromise::resolve());
promises.insert(++promises.begin(), QtPromise::resolve()); promises.insert(++promises.begin(), QtPromise::resolve());
@ -106,7 +100,7 @@ void tst_helpers_all::allPromisesSucceed()
auto p0 = QtPromise::resolve(42); auto p0 = QtPromise::resolve(42);
auto p1 = QtPromise::resolve(44); auto p1 = QtPromise::resolve(44);
auto p2 = QPromise<int>{[](const QPromiseResolve<int>& resolve) { auto p2 = QPromise<int>{[](const QPromiseResolve<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
resolve(43); resolve(43);
}); });
}}; }};
@ -127,7 +121,7 @@ void tst_helpers_all::allPromisesSucceed_void()
auto p0 = QtPromise::resolve(); auto p0 = QtPromise::resolve();
auto p1 = QtPromise::resolve(); auto p1 = QtPromise::resolve();
auto p2 = QPromise<void>{[](const QPromiseResolve<void>& resolve) { auto p2 = QPromise<void>{[](const QPromiseResolve<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
resolve(); resolve();
}); });
}}; }};
@ -148,7 +142,7 @@ void tst_helpers_all::atLeastOnePromiseReject()
auto p0 = QtPromise::resolve(42); auto p0 = QtPromise::resolve(42);
auto p1 = QtPromise::resolve(44); auto p1 = QtPromise::resolve(44);
auto p2 = QPromise<int>{[](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) { auto p2 = QPromise<int>{[](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
reject(QString{"foo"}); reject(QString{"foo"});
}); });
}}; }};
@ -169,7 +163,7 @@ void tst_helpers_all::atLeastOnePromiseReject_void()
auto p0 = QtPromise::resolve(); auto p0 = QtPromise::resolve();
auto p1 = QtPromise::resolve(); auto p1 = QtPromise::resolve();
auto p2 = QPromise<void>{[](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) { auto p2 = QPromise<void>{[](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
reject(QString{"foo"}); reject(QString{"foo"});
}); });
}}; }};
@ -210,7 +204,7 @@ void tst_helpers_all::preserveOrder()
void tst_helpers_all::sequenceTypes() void tst_helpers_all::sequenceTypes()
{ {
SequenceTester<QList<QPromise<int>>>::exec(); SequenceTester<QList<QPromise<int>>>::exec();
//SequenceTester<QVector<QPromise<int>>>::exec(); // SequenceTester<QVector<QPromise<int>>>::exec();
SequenceTester<std::list<QPromise<int>>>::exec(); SequenceTester<std::list<QPromise<int>>>::exec();
SequenceTester<std::vector<QPromise<int>>>::exec(); SequenceTester<std::vector<QPromise<int>>>::exec();
} }
@ -218,7 +212,7 @@ void tst_helpers_all::sequenceTypes()
void tst_helpers_all::sequenceTypes_void() void tst_helpers_all::sequenceTypes_void()
{ {
SequenceTester<QList<QPromise<void>>>::exec(); SequenceTester<QList<QPromise<void>>>::exec();
//SequenceTester<QVector<QPromise<void>>>::exec(); // SequenceTester<QVector<QPromise<void>>>::exec();
SequenceTester<std::list<QPromise<void>>>::exec(); SequenceTester<std::list<QPromise<void>>>::exec();
SequenceTester<std::vector<QPromise<void>>>::exec(); SequenceTester<std::vector<QPromise<void>>>::exec();
} }

View File

@ -91,9 +91,12 @@ void tst_helpers_attempt::functorThrows()
void tst_helpers_attempt::callWithParams() void tst_helpers_attempt::callWithParams()
{ {
auto p = QtPromise::attempt([&](int i, const QString& s) { auto p = QtPromise::attempt(
[&](int i, const QString& s) {
return QString{"%1:%2"}.arg(i).arg(s); return QString{"%1:%2"}.arg(i).arg(s);
}, 42, "foo"); },
42,
"foo");
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QString>>::value));
QCOMPARE(p.isFulfilled(), true); QCOMPARE(p.isFulfilled(), true);

View File

@ -32,7 +32,7 @@ QTEST_MAIN(tst_helpers_each)
namespace { namespace {
template <class Sequence> template<class Sequence>
struct SequenceTester struct SequenceTester
{ {
static void exec() static void exec()
@ -108,9 +108,8 @@ void tst_helpers_each::delayedFulfilled()
void tst_helpers_each::delayedRejected() void tst_helpers_each::delayedRejected()
{ {
auto p = QtPromise::each(QVector<int>{42, 43, 44}, [](int v, ...) { auto p = QtPromise::each(QVector<int>{42, 43, 44}, [](int v, ...) {
return QPromise<int>{[&]( return QPromise<int>{
const QPromiseResolve<int>& resolve, [&](const QPromiseResolve<int>& resolve, const QPromiseReject<int>& reject) {
const QPromiseReject<int>& reject) {
QtPromisePrivate::qtpromise_defer([=]() { QtPromisePrivate::qtpromise_defer([=]() {
if (v == 43) { if (v == 43) {
reject(QString{"foo"}); reject(QString{"foo"});

View File

@ -33,7 +33,7 @@ QTEST_MAIN(tst_helpers_filter)
namespace { namespace {
template <class Sequence> template<class Sequence>
struct SequenceTester struct SequenceTester
{ {
static void exec() static void exec()
@ -87,9 +87,8 @@ void tst_helpers_filter::delayedFulfilled()
void tst_helpers_filter::delayedRejected() void tst_helpers_filter::delayedRejected()
{ {
auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) { auto p = QtPromise::filter(QVector<int>{42, 43, 44}, [](int v, ...) {
return QPromise<bool>{[&]( return QPromise<bool>{
const QPromiseResolve<bool>& resolve, [&](const QPromiseResolve<bool>& resolve, const QPromiseReject<bool>& reject) {
const QPromiseReject<bool>& reject) {
QtPromisePrivate::qtpromise_defer([=]() { QtPromisePrivate::qtpromise_defer([=]() {
if (v == 44) { if (v == 44) {
reject(QString{"foo"}); reject(QString{"foo"});

View File

@ -33,7 +33,7 @@ QTEST_MAIN(tst_helpers_map)
namespace { namespace {
template <class Sequence> template<class Sequence>
struct SequenceTester struct SequenceTester
{ {
static void exec() static void exec()
@ -96,9 +96,8 @@ void tst_helpers_map::delayedFulfilled()
void tst_helpers_map::delayedRejected() void tst_helpers_map::delayedRejected()
{ {
auto p = QtPromise::map(QVector<int>{42, 43, 44}, [](int v, ...) { auto p = QtPromise::map(QVector<int>{42, 43, 44}, [](int v, ...) {
return QPromise<int>{[&]( return QPromise<int>{
const QPromiseResolve<int>& resolve, [&](const QPromiseResolve<int>& resolve, const QPromiseReject<int>& reject) {
const QPromiseReject<int>& reject) {
QtPromisePrivate::qtpromise_defer([=]() { QtPromisePrivate::qtpromise_defer([=]() {
if (v == 43) { if (v == 43) {
reject(QString{"foo"}); reject(QString{"foo"});

View File

@ -34,16 +34,14 @@ QTEST_MAIN(tst_helpers_reduce)
namespace { namespace {
template <class Sequence> template<class Sequence>
struct SequenceTester struct SequenceTester
{ {
static void exec() static void exec()
{ {
Sequence inputs{ Sequence inputs{QtPromise::resolve(4).delay(400),
QtPromise::resolve(4).delay(400),
QtPromise::resolve(6).delay(300), QtPromise::resolve(6).delay(300),
QtPromise::resolve(8).delay(200) QtPromise::resolve(8).delay(200)};
};
QVector<int> v0; QVector<int> v0;
QVector<int> v1; QVector<int> v1;
@ -51,10 +49,13 @@ struct SequenceTester
v0 << acc << cur << idx; v0 << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}); });
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) { auto p1 = QtPromise::reduce(
inputs,
[&](int acc, int cur, int idx) {
v1 << acc << cur << idx; v1 << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}, QtPromise::resolve(2).delay(100)); },
QtPromise::resolve(2).delay(100));
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value)); 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(p1), QPromise<int>>::value));
@ -74,10 +75,13 @@ void tst_helpers_reduce::emptySequence()
{ {
bool called = false; bool called = false;
auto p = QtPromise::reduce(QVector<int>{}, [&](...) { auto p = QtPromise::reduce(
QVector<int>{},
[&](...) {
called = true; called = true;
return 43; return 43;
}, 42); },
42);
// NOTE(SB): reduce() on an empty sequence without an initial value is an error! // NOTE(SB): reduce() on an empty sequence without an initial value is an error!
@ -97,10 +101,13 @@ void tst_helpers_reduce::regularValues()
v0 << acc << cur << idx; v0 << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}); });
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) { auto p1 = QtPromise::reduce(
inputs,
[&](int acc, int cur, int idx) {
v1 << acc << cur << idx; v1 << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}, 2); },
2);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value)); 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(p1), QPromise<int>>::value));
@ -115,11 +122,9 @@ void tst_helpers_reduce::regularValues()
void tst_helpers_reduce::promiseValues() void tst_helpers_reduce::promiseValues()
{ {
QVector<QPromise<int>> inputs{ QVector<QPromise<int>> inputs{QtPromise::resolve(4).delay(400),
QtPromise::resolve(4).delay(400),
QtPromise::resolve(6).delay(300), QtPromise::resolve(6).delay(300),
QtPromise::resolve(8).delay(200) QtPromise::resolve(8).delay(200)};
};
QVector<int> v0; QVector<int> v0;
QVector<int> v1; QVector<int> v1;
@ -127,10 +132,13 @@ void tst_helpers_reduce::promiseValues()
v0 << acc << cur << idx; v0 << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}); });
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) { auto p1 = QtPromise::reduce(
inputs,
[&](int acc, int cur, int idx) {
v1 << acc << cur << idx; v1 << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}, 2); },
2);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value)); 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(p1), QPromise<int>>::value));
@ -147,9 +155,12 @@ void tst_helpers_reduce::convertResultType()
{ {
QVector<int> inputs{4, 6, 8}; QVector<int> inputs{4, 6, 8};
auto p = QtPromise::reduce(inputs, [&](const QString& acc, int cur, int idx) { auto p = QtPromise::reduce(
inputs,
[&](const QString& acc, int cur, int idx) {
return QString{"%1:%2:%3"}.arg(acc).arg(cur).arg(idx); return QString{"%1:%2:%3"}.arg(acc).arg(cur).arg(idx);
}, QString{"foo"}); },
QString{"foo"});
// NOTE(SB): when no initial value is given, the result type is the sequence type. // NOTE(SB): when no initial value is given, the result type is the sequence type.
@ -163,10 +174,13 @@ void tst_helpers_reduce::delayedInitialValue()
{ {
QVector<int> values; QVector<int> values;
auto p = QtPromise::reduce(QVector<int>{4, 6, 8}, [&](int acc, int cur, int idx) { auto p = QtPromise::reduce(
QVector<int>{4, 6, 8},
[&](int acc, int cur, int idx) {
values << acc << cur << idx; values << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}, QtPromise::resolve(2).delay(100)); },
QtPromise::resolve(2).delay(100));
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
@ -185,10 +199,13 @@ void tst_helpers_reduce::delayedFulfilled()
v0 << acc << cur << idx; v0 << acc << cur << idx;
return QtPromise::resolve(acc + cur + idx).delay(100); return QtPromise::resolve(acc + cur + idx).delay(100);
}); });
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) { auto p1 = QtPromise::reduce(
inputs,
[&](int acc, int cur, int idx) {
v1 << acc << cur << idx; v1 << acc << cur << idx;
return QtPromise::resolve(acc + cur + idx).delay(100); return QtPromise::resolve(acc + cur + idx).delay(100);
}, 2); },
2);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value)); 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(p1), QPromise<int>>::value));
@ -214,13 +231,16 @@ void tst_helpers_reduce::delayedRejected()
} }
return QtPromise::resolve(acc + cur + idx); return QtPromise::resolve(acc + cur + idx);
}); });
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) { auto p1 = QtPromise::reduce(
inputs,
[&](int acc, int cur, int idx) {
v1 << acc << cur << idx; v1 << acc << cur << idx;
if (cur == 6) { if (cur == 6) {
return QPromise<int>::reject(QString{"bar"}); return QPromise<int>::reject(QString{"bar"});
} }
return QtPromise::resolve(acc + cur + idx); return QtPromise::resolve(acc + cur + idx);
}, 2); },
2);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value)); 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(p1), QPromise<int>>::value));
@ -246,13 +266,16 @@ void tst_helpers_reduce::functorThrows()
} }
return acc + cur + idx; return acc + cur + idx;
}); });
auto p1 = QtPromise::reduce(inputs, [&](int acc, int cur, int idx) { auto p1 = QtPromise::reduce(
inputs,
[&](int acc, int cur, int idx) {
v1 << acc << cur << idx; v1 << acc << cur << idx;
if (cur == 6) { if (cur == 6) {
throw QString{"bar"}; throw QString{"bar"};
} }
return acc + cur + idx; return acc + cur + idx;
}, 2); },
2);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value)); 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(p1), QPromise<int>>::value));

View File

@ -8,8 +8,8 @@
#include "../shared/data.h" #include "../shared/data.h"
#include "../shared/utils.h" #include "../shared/utils.h"
#include <QtPromise>
#include <QtConcurrent> #include <QtConcurrent>
#include <QtPromise>
#include <QtTest> #include <QtTest>
#include <memory> #include <memory>
@ -175,7 +175,7 @@ void tst_helpers_resolve::stdSharedPtr()
void tst_helpers_resolve::typedPromise() void tst_helpers_resolve::typedPromise()
{ {
auto resolver = [](const QPromiseResolve<int>& resolve) { auto resolver = [](const QPromiseResolve<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
resolve(42); resolve(42);
}); });
}; };
@ -202,7 +202,7 @@ void tst_helpers_resolve::typedPromise()
void tst_helpers_resolve::voidPromise() void tst_helpers_resolve::voidPromise()
{ {
auto resolver = [](const QPromiseResolve<void>& resolve) { auto resolver = [](const QPromiseResolve<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=](){ QtPromisePrivate::qtpromise_defer([=]() {
resolve(); resolve();
}); });
}; };
@ -228,7 +228,9 @@ void tst_helpers_resolve::voidPromise()
void tst_helpers_resolve::typedFuture() void tst_helpers_resolve::typedFuture()
{ {
auto fn = [](){ return 42; }; auto fn = []() {
return 42;
};
QFuture<int> v0 = QtConcurrent::run(fn); QFuture<int> v0 = QtConcurrent::run(fn);
const QFuture<int> v1 = v0; const QFuture<int> v1 = v0;
@ -250,7 +252,7 @@ void tst_helpers_resolve::typedFuture()
void tst_helpers_resolve::voidFuture() void tst_helpers_resolve::voidFuture()
{ {
auto fn = [](){ }; auto fn = []() {};
QFuture<void> v0 = QtConcurrent::run(fn); QFuture<void> v0 = QtConcurrent::run(fn);
const QFuture<void> v1 = v0; const QFuture<void> v1 = v0;

View File

@ -45,25 +45,70 @@ namespace {
const float kRes = 0.42f; const float kRes = 0.42f;
float fnNoArg() { return kRes; } float fnNoArg()
float fnOneArg(float v) { return v; } {
float fnManyArgs(const float& v0, int, char*) { return v0; } return kRes;
}
float fnOneArg(float v)
{
return v;
}
float fnManyArgs(const float& v0, int, char*)
{
return v0;
}
struct OpNoArg { float operator()() { return kRes; } }; struct OpNoArg
struct OpOneArg { float operator()(float v) { return v; } }; {
struct OpManyArgs { float operator()(const float& v, int, char*) { return v; } }; float operator()() { return kRes; }
};
struct OpOneArg
{
float operator()(float v) { return v; }
};
struct OpManyArgs
{
float operator()(const float& v, int, char*) { return v; }
};
struct OpCNoArg { float operator()() const { return kRes; } }; struct OpCNoArg
struct OpCOneArg { float operator()(float v) const { return v; } }; {
struct OpCManyArgs { float operator()(const float& v, int, char*) const { return v; } }; float operator()() const { return kRes; }
};
struct OpCOneArg
{
float operator()(float v) const { return v; }
};
struct OpCManyArgs
{
float operator()(const float& v, int, char*) const { return v; }
};
struct OpVNoArg { float operator()() volatile { return kRes; } }; struct OpVNoArg
struct OpVOneArg { float operator()(float v) volatile { return v; } }; {
struct OpVManyArgs { float operator()(const float& v, int, char*) volatile { return v; } }; float operator()() volatile { return kRes; }
};
struct OpVOneArg
{
float operator()(float v) volatile { return v; }
};
struct OpVManyArgs
{
float operator()(const float& v, int, char*) volatile { return v; }
};
struct OpCVNoArg { float operator()() const volatile { return kRes; } }; struct OpCVNoArg
struct OpCVOneArg { float operator()(float v) const volatile { return v; } }; {
struct OpCVManyArgs { float operator()(const float& v, int, char*) const volatile { return v; } }; float operator()() const volatile { return kRes; }
};
struct OpCVOneArg
{
float operator()(float v) const volatile { return v; }
};
struct OpCVManyArgs
{
float operator()(const float& v, int, char*) const volatile { return v; }
};
} // namespace } // namespace

View File

@ -270,11 +270,11 @@ void tst_qpromise_construct::connectAndResolve()
std::weak_ptr<int> wptr; std::weak_ptr<int> wptr;
{ {
auto p = QPromise<std::shared_ptr<int>>{[&]( auto p =
const QPromiseResolve<std::shared_ptr<int>>& resolve, QPromise<std::shared_ptr<int>>{[&](const QPromiseResolve<std::shared_ptr<int>>& resolve,
const QPromiseReject<std::shared_ptr<int>>& reject) { const QPromiseReject<std::shared_ptr<int>>& reject) {
connect(object.data(),
connect(object.data(), &QObject::objectNameChanged, &QObject::objectNameChanged,
[=, &wptr](const QString& name) { [=, &wptr](const QString& name) {
auto sptr = std::make_shared<int>(42); auto sptr = std::make_shared<int>(42);
@ -307,12 +307,9 @@ void tst_qpromise_construct::connectAndReject()
std::weak_ptr<int> wptr; std::weak_ptr<int> wptr;
{ {
auto p = QPromise<int>{[&]( auto p = QPromise<int>{[&](const QPromiseResolve<int>& resolve,
const QPromiseResolve<int>& resolve,
const QPromiseReject<int>& reject) { const QPromiseReject<int>& reject) {
connect(object.data(), &QObject::objectNameChanged, [=, &wptr](const QString& name) {
connect(object.data(), &QObject::objectNameChanged,
[=, &wptr](const QString& name) {
auto sptr = std::make_shared<int>(42); auto sptr = std::make_shared<int>(42);
wptr = sptr; wptr = sptr;

View File

@ -32,36 +32,34 @@ QTEST_MAIN(tst_qpromise_each)
namespace { namespace {
template <class Sequence> template<class Sequence>
struct SequenceTester struct SequenceTester
{ {
static void exec() static void exec()
{ {
QVector<int> values; QVector<int> values;
auto p = QtPromise::resolve(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; values << i << v;
}).each([&](int v, ...) { })
.each([&](int v, ...) {
values << v; values << v;
return QString{"foo"}; return QString{"foo"};
}).each([&](int v, ...) { })
.each([&](int v, ...) {
values << v + 1; values << v + 1;
return QtPromise::resolve(QString{"foo"}).then([&](){ return QtPromise::resolve(QString{"foo"}).then([&]() {
values << -1; values << -1;
}); });
}).each([&](int v, ...) { })
.each([&](int v, ...) {
values << v + 2; values << v + 2;
}); });
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Sequence>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<Sequence>>::value));
QCOMPARE(waitForValue(p, Sequence{}), (Sequence{42, 43, 44})); QCOMPARE(waitForValue(p, Sequence{}), (Sequence{42, 43, 44}));
QVector<int> expected{ QVector<int> expected{0, 42, 1, 43, 2, 44, 42, 43, 44, 43, 44, 45, -1, -1, -1, 44, 45, 46};
0, 42, 1, 43, 2, 44,
42, 43, 44,
43, 44, 45,
-1, -1, -1,
44, 45, 46
};
QCOMPARE(values, expected); QCOMPARE(values, expected);
} }
}; };
@ -124,9 +122,8 @@ void tst_qpromise_each::delayedFulfilled()
void tst_qpromise_each::delayedRejected() void tst_qpromise_each::delayedRejected()
{ {
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).each([](int v, ...) { auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).each([](int v, ...) {
return QPromise<int>{[&]( return QPromise<int>{
const QPromiseResolve<int>& resolve, [&](const QPromiseResolve<int>& resolve, const QPromiseReject<int>& reject) {
const QPromiseReject<int>& reject) {
QtPromisePrivate::qtpromise_defer([=]() { QtPromisePrivate::qtpromise_defer([=]() {
if (v == 44) { if (v == 44) {
reject(QString{"foo"}); reject(QString{"foo"});

View File

@ -36,18 +36,28 @@ const QString kErr{"0.42"};
const float kRes = 0.42f; const float kRes = 0.42f;
const float kFail = -1.f; const float kFail = -1.f;
float fnNoArg() { return kErr.toFloat(); } float fnNoArg()
float fnArgByVal(QString e) { return e.toFloat(); } {
float fnArgByRef(const QString& e) { return e.toFloat(); } return kErr.toFloat();
}
float fnArgByVal(QString e)
{
return e.toFloat();
}
float fnArgByRef(const QString& e)
{
return e.toFloat();
}
class Klass { class Klass
{
public: // STATICS public: // STATICS
static float kFnNoArg() { return kErr.toFloat(); } static float kFnNoArg() { return kErr.toFloat(); }
static float kFnArgByVal(QString e) { return e.toFloat(); } static float kFnArgByVal(QString e) { return e.toFloat(); }
static float kFnArgByRef(const QString& e) { return e.toFloat(); } static float kFnArgByRef(const QString& e) { return e.toFloat(); }
public: public:
Klass(float v) : m_v{v} {} Klass(float v) : m_v{v} { }
float fnNoArg() const { return m_v; } float fnNoArg() const { return m_v; }
float fnArgByVal(QString v) const { return v.toFloat() + m_v; } float fnArgByVal(QString v) const { return v.toFloat() + m_v; }
@ -68,13 +78,16 @@ void tst_qpromise_fail::sameType()
p.fail([&](const std::domain_error& e) { p.fail([&](const std::domain_error& e) {
error += QString{e.what()} + "0"; error += QString{e.what()} + "0";
return -1; return -1;
}).fail([&](const std::out_of_range& e) { })
.fail([&](const std::out_of_range& e) {
error += QString{e.what()} + "1"; error += QString{e.what()} + "1";
return -1; return -1;
}).fail([&](const std::exception& e) { })
.fail([&](const std::exception& e) {
error += QString{e.what()} + "2"; error += QString{e.what()} + "2";
return -1; return -1;
}).wait(); })
.wait();
QCOMPARE(error, QString{"foo1"}); QCOMPARE(error, QString{"foo1"});
} }
@ -88,13 +101,16 @@ void tst_qpromise_fail::baseClass()
p.fail([&](const std::runtime_error& e) { p.fail([&](const std::runtime_error& e) {
error += QString{e.what()} + "0"; error += QString{e.what()} + "0";
return -1; return -1;
}).fail([&](const std::logic_error& e) { })
.fail([&](const std::logic_error& e) {
error += QString{e.what()} + "1"; error += QString{e.what()} + "1";
return -1; return -1;
}).fail([&](const std::exception& e) { })
.fail([&](const std::exception& e) {
error += QString{e.what()} + "2"; error += QString{e.what()} + "2";
return -1; return -1;
}).wait(); })
.wait();
QCOMPARE(error, QString{"foo1"}); QCOMPARE(error, QString{"foo1"});
} }
@ -107,13 +123,16 @@ void tst_qpromise_fail::catchAll()
p.fail([&](const std::runtime_error& e) { p.fail([&](const std::runtime_error& e) {
error += QString{e.what()} + "0"; error += QString{e.what()} + "0";
return -1; return -1;
}).fail([&]() { })
.fail([&]() {
error += "bar"; error += "bar";
return -1; return -1;
}).fail([&](const std::exception& e) { })
.fail([&](const std::exception& e) {
error += QString{e.what()} + "2"; error += QString{e.what()} + "2";
return -1; return -1;
}).wait(); })
.wait();
QCOMPARE(error, QString{"bar"}); QCOMPARE(error, QString{"bar"});
} }
@ -172,7 +191,8 @@ void tst_qpromise_fail::stdFunctionHandlers()
{ // rvalue. { // rvalue.
auto p0 = QPromise<float>::reject(kErr).fail(std::function<float()>{fnNoArg}); auto p0 = QPromise<float>::reject(kErr).fail(std::function<float()>{fnNoArg});
auto p1 = QPromise<float>::reject(kErr).fail(std::function<float(QString)>{fnArgByVal}); auto p1 = QPromise<float>::reject(kErr).fail(std::function<float(QString)>{fnArgByVal});
auto p2 = QPromise<float>::reject(kErr).fail(std::function<float(const QString&)>{fnArgByRef}); auto p2 =
QPromise<float>::reject(kErr).fail(std::function<float(const QString&)>{fnArgByRef});
QCOMPARE(waitForValue(p0, kFail), kRes); QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes); QCOMPARE(waitForValue(p1, kFail), kRes);
@ -190,7 +210,8 @@ void tst_qpromise_fail::stdBindHandlers()
const std::function<float()> bindNoArg = std::bind(&Klass::fnNoArg, &obj); const std::function<float()> bindNoArg = std::bind(&Klass::fnNoArg, &obj);
const std::function<float(QString)> bindArgByVal = std::bind(&Klass::fnArgByVal, &obj, _1); const std::function<float(QString)> bindArgByVal = std::bind(&Klass::fnArgByVal, &obj, _1);
const std::function<float(const QString&)> bindArgByRef = std::bind(&Klass::fnArgByRef, &obj, _1); const std::function<float(const QString&)> bindArgByRef =
std::bind(&Klass::fnArgByRef, &obj, _1);
auto p0 = QPromise<float>::reject(kErr).fail(bindNoArg); auto p0 = QPromise<float>::reject(kErr).fail(bindNoArg);
auto p1 = QPromise<float>::reject(kErr).fail(bindArgByVal); auto p1 = QPromise<float>::reject(kErr).fail(bindArgByVal);
@ -204,9 +225,15 @@ void tst_qpromise_fail::stdBindHandlers()
void tst_qpromise_fail::lambdaHandlers() void tst_qpromise_fail::lambdaHandlers()
{ {
{ // lvalue. { // lvalue.
auto lambdaNoArg = []() { return kRes; }; auto lambdaNoArg = []() {
auto lambdaArgByVal = [](QString v) { return v.toFloat(); }; return kRes;
auto lambdaArgByRef = [](const QString& v) { return v.toFloat(); }; };
auto lambdaArgByVal = [](QString v) {
return v.toFloat();
};
auto lambdaArgByRef = [](const QString& v) {
return v.toFloat();
};
auto p0 = QPromise<float>::reject(kErr).fail(lambdaNoArg); auto p0 = QPromise<float>::reject(kErr).fail(lambdaNoArg);
auto p1 = QPromise<float>::reject(kErr).fail(lambdaArgByVal); auto p1 = QPromise<float>::reject(kErr).fail(lambdaArgByVal);
@ -217,9 +244,15 @@ void tst_qpromise_fail::lambdaHandlers()
QCOMPARE(waitForValue(p2, kFail), kRes); QCOMPARE(waitForValue(p2, kFail), kRes);
} }
{ // const lvalue. { // const lvalue.
const auto lambdaNoArg = []() { return kRes; }; const auto lambdaNoArg = []() {
const auto lambdaArgByVal = [](QString v) { return v.toFloat(); }; return kRes;
const auto lambdaArgByRef = [](const QString& v) { return v.toFloat(); }; };
const auto lambdaArgByVal = [](QString v) {
return v.toFloat();
};
const auto lambdaArgByRef = [](const QString& v) {
return v.toFloat();
};
auto p0 = QPromise<float>::reject(kErr).fail(lambdaNoArg); auto p0 = QPromise<float>::reject(kErr).fail(lambdaNoArg);
auto p1 = QPromise<float>::reject(kErr).fail(lambdaArgByVal); auto p1 = QPromise<float>::reject(kErr).fail(lambdaArgByVal);
@ -230,9 +263,15 @@ void tst_qpromise_fail::lambdaHandlers()
QCOMPARE(waitForValue(p2, kFail), kRes); QCOMPARE(waitForValue(p2, kFail), kRes);
} }
{ // rvalue. { // rvalue.
auto p0 = QPromise<float>::reject(kErr).fail([]() { return kRes; }); auto p0 = QPromise<float>::reject(kErr).fail([]() {
auto p1 = QPromise<float>::reject(kErr).fail([](QString v) { return v.toFloat(); }); return kRes;
auto p2 = QPromise<float>::reject(kErr).fail([](const QString& v) { return v.toFloat(); }); });
auto p1 = QPromise<float>::reject(kErr).fail([](QString v) {
return v.toFloat();
});
auto p2 = QPromise<float>::reject(kErr).fail([](const QString& v) {
return v.toFloat();
});
QCOMPARE(waitForValue(p0, kFail), kRes); QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes); QCOMPARE(waitForValue(p1, kFail), kRes);

View File

@ -33,18 +33,19 @@ QTEST_MAIN(tst_qpromise_filter)
namespace { namespace {
template <class Sequence> template<class Sequence>
struct SequenceTester struct SequenceTester
{ {
static void exec() static void exec()
{ {
auto p = QtPromise::resolve(Sequence{ auto p = QtPromise::resolve(Sequence{42, 43, 44, 45, 46, 47, 48, 49, 50, 51})
42, 43, 44, 45, 46, 47, 48, 49, 50, 51 .filter([](int v, ...) {
}).filter([](int v, ...) {
return v > 42 && v < 51; return v > 42 && v < 51;
}).filter([](int, int i) { })
.filter([](int, int i) {
return QPromise<bool>::resolve(i % 2 == 0); return QPromise<bool>::resolve(i % 2 == 0);
}).filter([](int v, ...) { })
.filter([](int v, ...) {
return v != 45; return v != 45;
}); });
@ -92,9 +93,8 @@ void tst_qpromise_filter::delayedFulfilled()
void tst_qpromise_filter::delayedRejected() void tst_qpromise_filter::delayedRejected()
{ {
auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).filter([](int v, ...) { auto p = QPromise<QVector<int>>::resolve({42, 43, 44}).filter([](int v, ...) {
return QPromise<bool>{[&]( return QPromise<bool>{
const QPromiseResolve<bool>& resolve, [&](const QPromiseResolve<bool>& resolve, const QPromiseReject<bool>& reject) {
const QPromiseReject<bool>& reject) {
QtPromisePrivate::qtpromise_defer([=]() { QtPromisePrivate::qtpromise_defer([=]() {
if (v == 43) { if (v == 43) {
reject(QString{"foo"}); reject(QString{"foo"});

View File

@ -33,23 +33,28 @@ QTEST_MAIN(tst_qpromise_map)
namespace { namespace {
template <class Sequence> template<class Sequence>
struct SequenceTester struct SequenceTester
{ {
static void exec() static void exec()
{ {
auto p = QtPromise::resolve(Sequence{42, 43, 44}).map([](int v, ...) { auto p = QtPromise::resolve(Sequence{42, 43, 44})
.map([](int v, ...) {
return QString::number(v + 1); return QString::number(v + 1);
}).map([](const QString& v, int i) { })
.map([](const QString& v, int i) {
return QtPromise::resolve(QString{"%1:%2"}.arg(i).arg(v)); return QtPromise::resolve(QString{"%1:%2"}.arg(i).arg(v));
}).map([](const QString& v, ...) { })
.map([](const QString& v, ...) {
return QtPromise::resolve((v + "!").toUtf8()); return QtPromise::resolve((v + "!").toUtf8());
}).map([](const QByteArray& v, ...) { })
.map([](const QByteArray& v, ...) {
return QString::fromUtf8(v); return QString::fromUtf8(v);
}); });
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<QString>>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<QVector<QString>>>::value));
QCOMPARE(waitForValue(p, QVector<QString>{}), (QVector<QString>{"0:43!", "1:44!", "2:45!"})); QCOMPARE(waitForValue(p, QVector<QString>{}),
(QVector<QString>{"0:43!", "1:44!", "2:45!"}));
} }
}; };
@ -102,9 +107,8 @@ void tst_qpromise_map::delayedFulfilled()
void tst_qpromise_map::delayedRejected() void tst_qpromise_map::delayedRejected()
{ {
auto p = QtPromise::resolve(QVector<int>{42, 43, 44}).map([](int v, ...) { auto p = QtPromise::resolve(QVector<int>{42, 43, 44}).map([](int v, ...) {
return QPromise<int>{[&]( return QPromise<int>{
const QPromiseResolve<int>& resolve, [&](const QPromiseResolve<int>& resolve, const QPromiseReject<int>& reject) {
const QPromiseReject<int>& reject) {
QtPromisePrivate::qtpromise_defer([=]() { QtPromisePrivate::qtpromise_defer([=]() {
if (v == 43) { if (v == 43) {
reject(QString{"foo"}); reject(QString{"foo"});

View File

@ -204,7 +204,7 @@ void tst_qpromise_operators::notEqualTo_void()
void tst_qpromise_operators::chaining() void tst_qpromise_operators::chaining()
{ {
auto p = QPromise<int>::resolve(1); auto p = QPromise<int>::resolve(1);
for (int i=0; i<4; ++i) { for (int i = 0; i < 4; ++i) {
p = p.then([](int res) { p = p.then([](int res) {
return QPromise<int>::resolve(res * 2); return QPromise<int>::resolve(res * 2);
}); });
@ -220,7 +220,7 @@ void tst_qpromise_operators::chaining_void()
auto p = QPromise<void>::resolve(); auto p = QPromise<void>::resolve();
for (int i=0; i<4; ++i) { for (int i = 0; i < 4; ++i) {
p = p.then([i, &values]() { p = p.then([i, &values]() {
values.append(i * 2); values.append(i * 2);
return QPromise<void>::resolve(); return QPromise<void>::resolve();

View File

@ -34,16 +34,14 @@ QTEST_MAIN(tst_qpromise_reduce)
namespace { namespace {
template <class Sequence> template<class Sequence>
struct SequenceTester struct SequenceTester
{ {
static void exec() static void exec()
{ {
Sequence inputs{ Sequence inputs{QtPromise::resolve(4).delay(400),
QtPromise::resolve(4).delay(400),
QtPromise::resolve(6).delay(300), QtPromise::resolve(6).delay(300),
QtPromise::resolve(8).delay(200) QtPromise::resolve(8).delay(200)};
};
QVector<int> v0; QVector<int> v0;
QVector<int> v1; QVector<int> v1;
@ -51,10 +49,12 @@ struct SequenceTester
v0 << acc << cur << idx; v0 << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}); });
auto p1 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) { auto p1 = QtPromise::resolve(inputs).reduce(
[&](int acc, int cur, int idx) {
v1 << acc << cur << idx; v1 << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}, QtPromise::resolve(2).delay(100)); },
QtPromise::resolve(2).delay(100));
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value)); 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(p1), QPromise<int>>::value));
@ -74,10 +74,13 @@ void tst_qpromise_reduce::emptySequence()
{ {
bool called = false; bool called = false;
auto p = QtPromise::resolve(QVector<int>{}).reduce([&](...) { auto p = QtPromise::resolve(QVector<int>{})
.reduce(
[&](...) {
called = true; called = true;
return 43; return 43;
}, 42); },
42);
// NOTE(SB): reduce() on an empty sequence without an initial value is an error! // NOTE(SB): reduce() on an empty sequence without an initial value is an error!
@ -97,10 +100,12 @@ void tst_qpromise_reduce::regularValues()
v0 << acc << cur << idx; v0 << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}); });
auto p1 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) { auto p1 = QtPromise::resolve(inputs).reduce(
[&](int acc, int cur, int idx) {
v1 << acc << cur << idx; v1 << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}, 2); },
2);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value)); 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(p1), QPromise<int>>::value));
@ -115,11 +120,9 @@ void tst_qpromise_reduce::regularValues()
void tst_qpromise_reduce::promiseValues() void tst_qpromise_reduce::promiseValues()
{ {
QVector<QPromise<int>> inputs{ QVector<QPromise<int>> inputs{QtPromise::resolve(4).delay(400),
QtPromise::resolve(4).delay(400),
QtPromise::resolve(6).delay(300), QtPromise::resolve(6).delay(300),
QtPromise::resolve(8).delay(200) QtPromise::resolve(8).delay(200)};
};
QVector<int> v0; QVector<int> v0;
QVector<int> v1; QVector<int> v1;
@ -127,10 +130,12 @@ void tst_qpromise_reduce::promiseValues()
v0 << acc << cur << idx; v0 << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}); });
auto p1 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) { auto p1 = QtPromise::resolve(inputs).reduce(
[&](int acc, int cur, int idx) {
v1 << acc << cur << idx; v1 << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}, 2); },
2);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value)); 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(p1), QPromise<int>>::value));
@ -147,9 +152,11 @@ void tst_qpromise_reduce::convertResultType()
{ {
QVector<int> inputs{4, 6, 8}; QVector<int> inputs{4, 6, 8};
auto p = QtPromise::resolve(inputs).reduce([&](const QString& acc, int cur, int idx) { auto p = QtPromise::resolve(inputs).reduce(
[&](const QString& acc, int cur, int idx) {
return QString{"%1:%2:%3"}.arg(acc).arg(cur).arg(idx); return QString{"%1:%2:%3"}.arg(acc).arg(cur).arg(idx);
}, QString{"foo"}); },
QString{"foo"});
// NOTE(SB): when no initial value is given, the result type is the sequence type. // NOTE(SB): when no initial value is given, the result type is the sequence type.
@ -163,10 +170,13 @@ void tst_qpromise_reduce::delayedInitialValue()
{ {
QVector<int> values; QVector<int> values;
auto p = QtPromise::resolve(QVector<int>{4, 6, 8}).reduce([&](int acc, int cur, int idx) { auto p = QtPromise::resolve(QVector<int>{4, 6, 8})
.reduce(
[&](int acc, int cur, int idx) {
values << acc << cur << idx; values << acc << cur << idx;
return acc + cur + idx; return acc + cur + idx;
}, QtPromise::resolve(2).delay(100)); },
QtPromise::resolve(2).delay(100));
Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p), QPromise<int>>::value));
@ -185,10 +195,12 @@ void tst_qpromise_reduce::delayedFulfilled()
v0 << acc << cur << idx; v0 << acc << cur << idx;
return QtPromise::resolve(acc + cur + idx).delay(100); return QtPromise::resolve(acc + cur + idx).delay(100);
}); });
auto p1 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) { auto p1 = QtPromise::resolve(inputs).reduce(
[&](int acc, int cur, int idx) {
v1 << acc << cur << idx; v1 << acc << cur << idx;
return QtPromise::resolve(acc + cur + idx).delay(100); return QtPromise::resolve(acc + cur + idx).delay(100);
}, 2); },
2);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value)); 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(p1), QPromise<int>>::value));
@ -214,13 +226,15 @@ void tst_qpromise_reduce::delayedRejected()
} }
return QtPromise::resolve(acc + cur + idx); return QtPromise::resolve(acc + cur + idx);
}); });
auto p1 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) { auto p1 = QtPromise::resolve(inputs).reduce(
[&](int acc, int cur, int idx) {
v1 << acc << cur << idx; v1 << acc << cur << idx;
if (cur == 6) { if (cur == 6) {
return QPromise<int>::reject(QString{"bar"}); return QPromise<int>::reject(QString{"bar"});
} }
return QtPromise::resolve(acc + cur + idx); return QtPromise::resolve(acc + cur + idx);
}, 2); },
2);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value)); 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(p1), QPromise<int>>::value));
@ -246,13 +260,15 @@ void tst_qpromise_reduce::functorThrows()
} }
return acc + cur + idx; return acc + cur + idx;
}); });
auto p1 = QtPromise::resolve(inputs).reduce([&](int acc, int cur, int idx) { auto p1 = QtPromise::resolve(inputs).reduce(
[&](int acc, int cur, int idx) {
v1 << acc << cur << idx; v1 << acc << cur << idx;
if (cur == 6) { if (cur == 6) {
throw QString{"bar"}; throw QString{"bar"};
} }
return acc + cur + idx; return acc + cur + idx;
}, 2); },
2);
Q_STATIC_ASSERT((std::is_same<decltype(p0), QPromise<int>>::value)); 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(p1), QPromise<int>>::value));

View File

@ -58,13 +58,11 @@ void tst_qpromise_tapfail::rejected()
{ {
QStringList errors; QStringList errors;
auto p0 = QPromise<int>::reject(QString{"foo"}) auto p0 = QPromise<int>::reject(QString{"foo"}).tapFail([&](const QString& err) {
.tapFail([&](const QString& err) {
errors << "1:" + err; errors << "1:" + err;
}); });
auto p1 = p0 auto p1 = p0.fail([&](const QString& err) {
.fail([&](const QString& err) {
errors << "2:" + err; errors << "2:" + err;
return 43; return 43;
}); });
@ -80,13 +78,11 @@ void tst_qpromise_tapfail::rejected_void()
{ {
QStringList errors; QStringList errors;
auto p0 = QPromise<void>::reject(QString{"foo"}) auto p0 = QPromise<void>::reject(QString{"foo"}).tapFail([&](const QString& err) {
.tapFail([&](const QString& err) {
errors << "1:" + err; errors << "1:" + err;
}); });
auto p1 = p0 auto p1 = p0.fail([&](const QString& err) {
.fail([&](const QString& err) {
errors << "2:" + err; errors << "2:" + err;
}); });
@ -99,8 +95,7 @@ void tst_qpromise_tapfail::rejected_void()
void tst_qpromise_tapfail::throws() void tst_qpromise_tapfail::throws()
{ {
auto p = QPromise<int>::reject(QString{"foo"}) auto p = QPromise<int>::reject(QString{"foo"}).tapFail([&]() {
.tapFail([&]() {
throw QString{"bar"}; throw QString{"bar"};
}); });
@ -110,8 +105,7 @@ void tst_qpromise_tapfail::throws()
void tst_qpromise_tapfail::throws_void() void tst_qpromise_tapfail::throws_void()
{ {
auto p = QPromise<void>::reject(QString{"foo"}) auto p = QPromise<void>::reject(QString{"foo"}).tapFail([&]() {
.tapFail([&]() {
throw QString{"bar"}; throw QString{"bar"};
}); });
@ -122,8 +116,7 @@ void tst_qpromise_tapfail::throws_void()
void tst_qpromise_tapfail::delayedResolved() void tst_qpromise_tapfail::delayedResolved()
{ {
QVector<int> values; QVector<int> values;
auto p = QPromise<int>::reject(QString{"foo"}) auto p = QPromise<int>::reject(QString{"foo"}).tapFail([&]() {
.tapFail([&]() {
QPromise<void> p{[&](const QPromiseResolve<void>& resolve) { QPromise<void> p{[&](const QPromiseResolve<void>& resolve) {
QtPromisePrivate::qtpromise_defer([=, &values]() { QtPromisePrivate::qtpromise_defer([=, &values]() {
values << 3; values << 3;
@ -142,11 +135,8 @@ void tst_qpromise_tapfail::delayedResolved()
void tst_qpromise_tapfail::delayedRejected() void tst_qpromise_tapfail::delayedRejected()
{ {
QVector<int> values; QVector<int> values;
auto p = QPromise<int>::reject(QString{"foo"}) auto p = QPromise<int>::reject(QString{"foo"}).tapFail([&]() {
.tapFail([&]() { QPromise<void> p{[&](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
QPromise<void> p{[&](
const QPromiseResolve<void>&,
const QPromiseReject<void>& reject){
QtPromisePrivate::qtpromise_defer([=, &values]() { QtPromisePrivate::qtpromise_defer([=, &values]() {
values << 3; values << 3;
reject(QString{"bar"}); reject(QString{"bar"});

View File

@ -39,18 +39,28 @@ namespace {
const float kRes = 0.42f; const float kRes = 0.42f;
const float kFail = -1.f; const float kFail = -1.f;
float fnNoArg() { return kRes; } float fnNoArg()
float fnArgByVal(float v) { return v; } {
float fnArgByRef(const float& v) { return v; } return kRes;
}
float fnArgByVal(float v)
{
return v;
}
float fnArgByRef(const float& v)
{
return v;
}
class Klass { class Klass
{
public: // STATICS public: // STATICS
static float kFnNoArg() { return kRes; } static float kFnNoArg() { return kRes; }
static float kFnArgByVal(float v) { return v; } static float kFnArgByVal(float v) { return v; }
static float kFnArgByRef(const float& v) { return v; } static float kFnArgByRef(const float& v) { return v; }
public: public:
Klass(float v) : m_v{v} {} Klass(float v) : m_v{v} { }
float fnNoArg() const { return m_v; } float fnNoArg() const { return m_v; }
float fnArgByVal(float v) const { return v + m_v; } float fnArgByVal(float v) const { return v + m_v; }
@ -69,14 +79,17 @@ void tst_qpromise_then::resolveSync()
auto input = QPromise<int>::resolve(42); auto input = QPromise<int>::resolve(42);
auto output = input.then([&](int res) { auto output = input.then([&](int res) {
values << res; values << res;
return QString::number(res+1); return QString::number(res + 1);
}); });
output.then([&](const QString& res) { output
.then([&](const QString& res) {
values << res; values << res;
}).then([&]() { })
.then([&]() {
values << 44; values << 44;
}).wait(); })
.wait();
QCOMPARE(values, (QVariantList{42, QString{"43"}, 44})); QCOMPARE(values, (QVariantList{42, QString{"43"}, 44}));
QCOMPARE(input.isFulfilled(), true); QCOMPARE(input.isFulfilled(), true);
@ -107,11 +120,14 @@ void tst_qpromise_then::rejectSync()
}); });
QString error; QString error;
output.then([&](int res) { output
.then([&](int res) {
error += "bar" + QString::number(res); error += "bar" + QString::number(res);
}).fail([&](const QString& err) { })
.fail([&](const QString& err) {
error += err; error += err;
}).wait(); })
.wait();
QCOMPARE(error, QString{"foo42"}); QCOMPARE(error, QString{"foo42"});
QCOMPARE(input.isFulfilled(), true); QCOMPARE(input.isFulfilled(), true);
@ -121,7 +137,8 @@ void tst_qpromise_then::rejectSync()
void tst_qpromise_then::rejectAsync() void tst_qpromise_then::rejectAsync()
{ {
auto p = QPromise<int>::resolve(42).then([](int res) { auto p = QPromise<int>::resolve(42).then([](int res) {
return QPromise<void>{[=](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) { return QPromise<void>{
[=](const QPromiseResolve<void>&, const QPromiseReject<void>& reject) {
QtPromisePrivate::qtpromise_defer([=]() { QtPromisePrivate::qtpromise_defer([=]() {
reject(QString{"foo%1"}.arg(res)); reject(QString{"foo%1"}.arg(res));
}); });
@ -248,9 +265,15 @@ void tst_qpromise_then::stdBindHandlers()
void tst_qpromise_then::lambdaHandlers() void tst_qpromise_then::lambdaHandlers()
{ {
{ // lvalue. { // lvalue.
auto lambdaNoArg = []() { return kRes; }; auto lambdaNoArg = []() {
auto lambdaArgByVal = [](float v) { return v; }; return kRes;
auto lambdaArgByRef = [](const float& v) { return v; }; };
auto lambdaArgByVal = [](float v) {
return v;
};
auto lambdaArgByRef = [](const float& v) {
return v;
};
auto p0 = QtPromise::resolve().then(lambdaNoArg); auto p0 = QtPromise::resolve().then(lambdaNoArg);
auto p1 = QtPromise::resolve(kRes).then(lambdaArgByVal); auto p1 = QtPromise::resolve(kRes).then(lambdaArgByVal);
@ -261,9 +284,15 @@ void tst_qpromise_then::lambdaHandlers()
QCOMPARE(waitForValue(p2, kFail), kRes); QCOMPARE(waitForValue(p2, kFail), kRes);
} }
{ // const lvalue. { // const lvalue.
const auto lambdaNoArg = []() { return kRes; }; const auto lambdaNoArg = []() {
const auto lambdaArgByVal = [](float v) { return v; }; return kRes;
const auto lambdaArgByRef = [](const float& v) { return v; }; };
const auto lambdaArgByVal = [](float v) {
return v;
};
const auto lambdaArgByRef = [](const float& v) {
return v;
};
auto p0 = QtPromise::resolve().then(lambdaNoArg); auto p0 = QtPromise::resolve().then(lambdaNoArg);
auto p1 = QtPromise::resolve(kRes).then(lambdaArgByVal); auto p1 = QtPromise::resolve(kRes).then(lambdaArgByVal);
@ -274,9 +303,15 @@ void tst_qpromise_then::lambdaHandlers()
QCOMPARE(waitForValue(p2, kFail), kRes); QCOMPARE(waitForValue(p2, kFail), kRes);
} }
{ // rvalue. { // rvalue.
auto p0 = QtPromise::resolve().then([]() { return kRes; }); auto p0 = QtPromise::resolve().then([]() {
auto p1 = QtPromise::resolve(kRes).then([](float v) { return v; }); return kRes;
auto p2 = QtPromise::resolve(kRes).then([](const float& v) { return v; }); });
auto p1 = QtPromise::resolve(kRes).then([](float v) {
return v;
});
auto p2 = QtPromise::resolve(kRes).then([](const float& v) {
return v;
});
QCOMPARE(waitForValue(p0, kFail), kRes); QCOMPARE(waitForValue(p0, kFail), kRes);
QCOMPARE(waitForValue(p1, kFail), kRes); QCOMPARE(waitForValue(p1, kFail), kRes);

View File

@ -42,7 +42,8 @@ void tst_qpromise_timeout::fulfilled()
QTimer::singleShot(1000, [=]() { QTimer::singleShot(1000, [=]() {
resolve(42); resolve(42);
}); });
}}.timeout(2000).finally([&]() { }}.timeout(2000)
.finally([&]() {
elapsed = timer.elapsed(); elapsed = timer.elapsed();
}); });
@ -62,11 +63,11 @@ void tst_qpromise_timeout::rejected()
QTimer::singleShot(1000, [=]() { QTimer::singleShot(1000, [=]() {
reject(QString{"foo"}); reject(QString{"foo"});
}); });
}}.timeout(2000).finally([&]() { }}.timeout(2000)
.finally([&]() {
elapsed = timer.elapsed(); elapsed = timer.elapsed();
}); });
QCOMPARE(waitForError(p, QString{}), QString{"foo"}); QCOMPARE(waitForError(p, QString{}), QString{"foo"});
QCOMPARE(p.isRejected(), true); QCOMPARE(p.isRejected(), true);
QVERIFY(elapsed < 2000); QVERIFY(elapsed < 2000);
@ -84,7 +85,8 @@ void tst_qpromise_timeout::timeout()
QTimer::singleShot(4000, [=]() { QTimer::singleShot(4000, [=]() {
resolve(42); resolve(42);
}); });
}}.timeout(2000).finally([&]() { }}.timeout(2000)
.finally([&]() {
elapsed = timer.elapsed(); elapsed = timer.elapsed();
}); });
@ -115,7 +117,8 @@ void tst_qpromise_timeout::fulfilledStdChrono()
QTimer::singleShot(1000, [=]() { QTimer::singleShot(1000, [=]() {
resolve(42); resolve(42);
}); });
}}.timeout(std::chrono::seconds{2}).finally([&]() { }}.timeout(std::chrono::seconds{2})
.finally([&]() {
elapsed = timer.elapsed(); elapsed = timer.elapsed();
}); });
@ -135,11 +138,11 @@ void tst_qpromise_timeout::rejectedStdChrono()
QTimer::singleShot(1000, [=]() { QTimer::singleShot(1000, [=]() {
reject(QString{"foo"}); reject(QString{"foo"});
}); });
}}.timeout(std::chrono::seconds{2}).finally([&]() { }}.timeout(std::chrono::seconds{2})
.finally([&]() {
elapsed = timer.elapsed(); elapsed = timer.elapsed();
}); });
QCOMPARE(waitForError(p, QString{}), QString{"foo"}); QCOMPARE(waitForError(p, QString{}), QString{"foo"});
QCOMPARE(p.isRejected(), true); QCOMPARE(p.isRejected(), true);
QVERIFY(elapsed < 2000); QVERIFY(elapsed < 2000);
@ -157,7 +160,8 @@ void tst_qpromise_timeout::timeoutStdChrono()
QTimer::singleShot(4000, [=]() { QTimer::singleShot(4000, [=]() {
resolve(42); resolve(42);
}); });
}}.timeout(std::chrono::seconds{2}).finally([&]() { }}.timeout(std::chrono::seconds{2})
.finally([&]() {
elapsed = timer.elapsed(); elapsed = timer.elapsed();
}); });

View File

@ -44,7 +44,9 @@ void tst_requirements::statePending()
// 2.1.1.1. may transition to either the fulfilled state // 2.1.1.1. may transition to either the fulfilled state
{ {
QPromise<int> p{[&](const QPromiseResolve<int>& resolve) { QPromise<int> p{[&](const QPromiseResolve<int>& resolve) {
QtPromisePrivate::qtpromise_defer([=]() { resolve(42); }); QtPromisePrivate::qtpromise_defer([=]() {
resolve(42);
});
}}; }};
QVERIFY(p.isPending()); QVERIFY(p.isPending());
@ -61,7 +63,9 @@ void tst_requirements::statePending()
// 2.1.1.1. ... or the rejected state // 2.1.1.1. ... or the rejected state
{ {
QPromise<int> p{[&](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) { QPromise<int> p{[&](const QPromiseResolve<int>&, const QPromiseReject<int>& reject) {
QtPromisePrivate::qtpromise_defer([=]() { reject(QString{"foo"}); }); QtPromisePrivate::qtpromise_defer([=]() {
reject(QString{"foo"});
});
}}; }};
QVERIFY(p.isPending()); QVERIFY(p.isPending());
@ -82,9 +86,7 @@ void tst_requirements::stateFulfilled()
int value = -1; int value = -1;
// 2.1.2. When fulfilled, a promise: // 2.1.2. When fulfilled, a promise:
QPromise<int> p{[]( QPromise<int> p{[](const QPromiseResolve<int>& resolve, const QPromiseReject<int>& reject) {
const QPromiseResolve<int>& resolve,
const QPromiseReject<int>& reject) {
QtPromisePrivate::qtpromise_defer([=]() { QtPromisePrivate::qtpromise_defer([=]() {
// 2.1.2.2. must have a value, which must not change. // 2.1.2.2. must have a value, which must not change.
resolve(42); resolve(42);
@ -97,11 +99,14 @@ void tst_requirements::stateFulfilled()
QVERIFY(p.isPending()); QVERIFY(p.isPending());
p.then([&](int res) { p.then(
[&](int res) {
value = res; value = res;
}, [&](const QString& err) { },
[&](const QString& err) {
error = err; error = err;
}).wait(); })
.wait();
QVERIFY(p.isFulfilled()); QVERIFY(p.isFulfilled());
QVERIFY(!p.isRejected()); QVERIFY(!p.isRejected());
@ -115,9 +120,7 @@ void tst_requirements::stateRejected()
int value = -1; int value = -1;
// 2.1.3 When rejected, a promise: // 2.1.3 When rejected, a promise:
QPromise<int> p{[]( QPromise<int> p{[](const QPromiseResolve<int>& resolve, const QPromiseReject<int>& reject) {
const QPromiseResolve<int>& resolve,
const QPromiseReject<int>& reject) {
QtPromisePrivate::qtpromise_defer([=]() { QtPromisePrivate::qtpromise_defer([=]() {
// 2.1.3.2. must have a reason, which must not change. // 2.1.3.2. must have a reason, which must not change.
reject(QString{"foo"}); reject(QString{"foo"});
@ -130,11 +133,14 @@ void tst_requirements::stateRejected()
QVERIFY(p.isPending()); QVERIFY(p.isPending());
p.then([&](int res) { p.then(
[&](int res) {
value = res; value = res;
}, [&](const QString& err) { },
[&](const QString& err) {
error = err; error = err;
}).wait(); })
.wait();
QVERIFY(!p.isFulfilled()); QVERIFY(!p.isFulfilled());
QVERIFY(p.isRejected()); QVERIFY(p.isRejected());
@ -148,10 +154,15 @@ void tst_requirements::thenArguments()
{ {
QString error; QString error;
int value = -1; int value = -1;
QPromise<int>::resolve(42).then( QPromise<int>::resolve(42)
[&](int res) { value = res; }, .then(
[&](const QString& err) { error = err; } [&](int res) {
).wait(); value = res;
},
[&](const QString& err) {
error = err;
})
.wait();
QVERIFY(error.isEmpty()); QVERIFY(error.isEmpty());
QCOMPARE(value, 42); QCOMPARE(value, 42);
@ -159,10 +170,15 @@ void tst_requirements::thenArguments()
{ {
QString error; QString error;
int value = -1; int value = -1;
QPromise<int>::reject(QString{"foo"}).then( QPromise<int>::reject(QString{"foo"})
[&](int res) { value = res; }, .then(
[&](const QString& err){ error = err; } [&](int res) {
).wait(); value = res;
},
[&](const QString& err) {
error = err;
})
.wait();
QCOMPARE(error, QString{"foo"}); QCOMPARE(error, QString{"foo"});
QCOMPARE(value, -1); QCOMPARE(value, -1);
@ -171,10 +187,13 @@ void tst_requirements::thenArguments()
// 2.2.1. onFulfilled is an optional arguments: // 2.2.1. onFulfilled is an optional arguments:
{ {
QString error; QString error;
QPromise<int>::reject(QString{"foo"}).then( QPromise<int>::reject(QString{"foo"})
nullptr, .then(nullptr,
[&](const QString& err){ error = err; return 42; } [&](const QString& err) {
).wait(); error = err;
return 42;
})
.wait();
QCOMPARE(error, QString{"foo"}); QCOMPARE(error, QString{"foo"});
} }
@ -182,9 +201,11 @@ void tst_requirements::thenArguments()
// 2.2.1. onRejected is an optional arguments: // 2.2.1. onRejected is an optional arguments:
{ {
int value = -1; int value = -1;
QPromise<int>::resolve(42).then( QPromise<int>::resolve(42)
[&value](int res) { value = res; } .then([&value](int res) {
).wait(); value = res;
})
.wait();
QCOMPARE(value, 42); QCOMPARE(value, 42);
} }
@ -206,7 +227,9 @@ void tst_requirements::thenOnFulfilled()
}); });
}}; }};
auto p1 = p0.then([&](int res) { values << res; }); auto p1 = p0.then([&](int res) {
values << res;
});
// 2.2.2.2. it must not be called before promise is fulfilled. // 2.2.2.2. it must not be called before promise is fulfilled.
QVERIFY(p0.isPending()); QVERIFY(p0.isPending());
@ -234,7 +257,9 @@ void tst_requirements::thenOnRejected()
}); });
}}; }};
auto p1 = p0.then(nullptr, [&](const QString& err) { errors << err; }); auto p1 = p0.then(nullptr, [&](const QString& err) {
errors << err;
});
// 2.2.3.2. it must not be called before promise is rejected. // 2.2.3.2. it must not be called before promise is rejected.
QVERIFY(p0.isPending()); QVERIFY(p0.isPending());
@ -260,7 +285,9 @@ void tst_requirements::thenAsynchronous()
auto p0 = QPromise<int>::resolve(42); auto p0 = QPromise<int>::resolve(42);
QVERIFY(p0.isFulfilled()); QVERIFY(p0.isFulfilled());
auto p1 = p0.then([&](int res){ value = res; }); auto p1 = p0.then([&](int res) {
value = res;
});
QVERIFY(p1.isPending()); QVERIFY(p1.isPending());
QCOMPARE(value, -1); QCOMPARE(value, -1);
@ -283,11 +310,16 @@ void tst_requirements::thenMultipleCalls()
}); });
}}; }};
QtPromise::all(QVector<QPromise<void>>{ QtPromise::all(QVector<QPromise<void>>{p.then([&](int r) {
p.then([&](int r) { values << r + 1; }), values << r + 1;
p.then([&](int r) { values << r + 2; }), }),
p.then([&](int r) { values << r + 3; }) p.then([&](int r) {
}).wait(); values << r + 2;
}),
p.then([&](int r) {
values << r + 3;
})})
.wait();
QCOMPARE(values, (QVector<int>{43, 44, 45})); QCOMPARE(values, (QVector<int>{43, 44, 45}));
} }
@ -302,11 +334,22 @@ void tst_requirements::thenMultipleCalls()
}); });
}}; }};
QtPromise::all(QVector<QPromise<int>>{ QtPromise::all(QVector<QPromise<int>>{p.then(nullptr,
p.then(nullptr, [&](int r) { values << r + 1; return r + 1; }), [&](int r) {
p.then(nullptr, [&](int r) { values << r + 2; return r + 2; }), values << r + 1;
p.then(nullptr, [&](int r) { values << r + 3; return r + 3; }) return r + 1;
}).wait(); }),
p.then(nullptr,
[&](int r) {
values << r + 2;
return r + 2;
}),
p.then(nullptr,
[&](int r) {
values << r + 3;
return r + 3;
})})
.wait();
QCOMPARE(values, (QVector<int>{9, 10, 11})); QCOMPARE(values, (QVector<int>{9, 10, 11}));
} }
@ -316,7 +359,9 @@ void tst_requirements::thenHandlers()
{ {
// 2.2.7. then must return a promise: p2 = p1.then(onFulfilled, onRejected); // 2.2.7. then must return a promise: p2 = p1.then(onFulfilled, onRejected);
{ {
auto handler = [](){ return 42; }; auto handler = []() {
return 42;
};
auto p1 = QPromise<int>::resolve(42); auto p1 = QPromise<int>::resolve(42);
Q_STATIC_ASSERT((std::is_same<decltype(p1.then(handler, nullptr)), QPromise<int>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p1.then(handler, nullptr)), QPromise<int>>::value));
Q_STATIC_ASSERT((std::is_same<decltype(p1.then(nullptr, handler)), QPromise<int>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p1.then(nullptr, handler)), QPromise<int>>::value));
@ -331,8 +376,12 @@ void tst_requirements::thenHandlers()
{ {
QString reason; QString reason;
auto p1 = QPromise<int>::resolve(42); auto p1 = QPromise<int>::resolve(42);
auto p2 = p1.then([](){ throw QString{"foo"}; }); auto p2 = p1.then([]() {
p2.then(nullptr, [&](const QString& e) { reason = e; }).wait(); throw QString{"foo"};
});
p2.then(nullptr, [&](const QString& e) {
reason = e;
}).wait();
QVERIFY(p1.isFulfilled()); QVERIFY(p1.isFulfilled());
QVERIFY(p2.isRejected()); QVERIFY(p2.isRejected());
@ -341,8 +390,14 @@ void tst_requirements::thenHandlers()
{ {
QString reason; QString reason;
auto p1 = QPromise<int>::reject(QString{"foo"}); auto p1 = QPromise<int>::reject(QString{"foo"});
auto p2 = p1.then(nullptr, [](){ throw QString{"bar"}; return 42; }); auto p2 = p1.then(nullptr, []() {
p2.then(nullptr, [&](const QString& e) { reason = e; return 0; }).wait(); throw QString{"bar"};
return 42;
});
p2.then(nullptr, [&](const QString& e) {
reason = e;
return 0;
}).wait();
QVERIFY(p1.isRejected()); QVERIFY(p1.isRejected());
QVERIFY(p2.isRejected()); QVERIFY(p2.isRejected());
@ -354,9 +409,13 @@ void tst_requirements::thenHandlers()
{ {
QString value; QString value;
auto p1 = QPromise<QString>::resolve("42"); auto p1 = QPromise<QString>::resolve("42");
auto p2 = p1.then(nullptr, [](){ return QString{}; }); auto p2 = p1.then(nullptr, []() {
return QString{};
});
Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<QString>>::value)); Q_STATIC_ASSERT((std::is_same<decltype(p2), QPromise<QString>>::value));
p2.then([&](const QString& e) { value = e; }).wait(); p2.then([&](const QString& e) {
value = e;
}).wait();
QVERIFY(p1.isFulfilled()); QVERIFY(p1.isFulfilled());
QVERIFY(p2.isFulfilled()); QVERIFY(p2.isFulfilled());

View File

@ -10,13 +10,15 @@
#include <utility> #include <utility>
struct Logs { struct Logs
{
int ctor = 0; int ctor = 0;
int copy = 0; int copy = 0;
int move = 0; int move = 0;
int refs = 0; int refs = 0;
void reset() { void reset()
{
ctor = 0; ctor = 0;
copy = 0; copy = 0;
move = 0; move = 0;
@ -26,21 +28,45 @@ struct Logs {
struct Logger struct Logger
{ {
Logger() { logs().ctor++; logs().refs++; } Logger()
Logger(const Logger&) { logs().copy++; logs().refs++; } {
Logger(Logger&&) { logs().move++; logs().refs++; } logs().ctor++;
logs().refs++;
}
Logger(const Logger&)
{
logs().copy++;
logs().refs++;
}
Logger(Logger&&)
{
logs().move++;
logs().refs++;
}
~Logger() { logs().refs--; } ~Logger() { logs().refs--; }
Logger& operator=(const Logger&) { logs().copy++; return *this; } Logger& operator=(const Logger&)
Logger& operator=(Logger&&) { logs().move++; return *this; } {
logs().copy++;
return *this;
}
Logger& operator=(Logger&&)
{
logs().move++;
return *this;
}
public: // STATICS public: // STATICS
static Logs& logs() { static Logs logs; return logs; } static Logs& logs()
{
static Logs logs;
return logs;
}
}; };
struct Data : public Logger struct Data : public Logger
{ {
Data(int v) : Logger{}, m_value{v} {} Data(int v) : Logger{}, m_value{v} { }
int value() const { return m_value; } int value() const { return m_value; }
// MSVC 2013 doesn't support implicit generation of the move constructor and // MSVC 2013 doesn't support implicit generation of the move constructor and
@ -48,15 +74,9 @@ struct Data : public Logger
// constructor and operator also need to be explicitly defined (error C2280). // constructor and operator also need to be explicitly defined (error C2280).
// https://stackoverflow.com/a/26581337 // https://stackoverflow.com/a/26581337
Data(const Data& other) Data(const Data& other) : Logger{other}, m_value{other.m_value} { }
: Logger{other}
, m_value{other.m_value}
{ }
Data(Data&& other) : Logger{std::forward<Data>(other)} Data(Data&& other) : Logger{std::forward<Data>(other)} { std::swap(m_value, other.m_value); }
{
std::swap(m_value, other.m_value);
}
Data& operator=(const Data& other) Data& operator=(const Data& other)
{ {

View File

@ -10,54 +10,65 @@
#include <QtPromise> #include <QtPromise>
template <typename T> template<typename T>
static inline T waitForValue(const QtPromise::QPromise<T>& promise, const T& initial) static inline T waitForValue(const QtPromise::QPromise<T>& promise, const T& initial)
{ {
T value(initial); T value(initial);
promise.then([&](const T& res) { promise
.then([&](const T& res) {
value = res; value = res;
}).wait(); })
.wait();
return value; return value;
} }
template <typename T> template<typename T>
static inline T waitForValue(const QtPromise::QPromise<void>& promise, const T& initial, const T& expected) static inline T
waitForValue(const QtPromise::QPromise<void>& promise, const T& initial, const T& expected)
{ {
T value(initial); T value(initial);
promise.then([&]() { promise
.then([&]() {
value = expected; value = expected;
}).wait(); })
.wait();
return value; return value;
} }
template <typename T, typename E> template<typename T, typename E>
static inline E waitForError(const QtPromise::QPromise<T>& promise, const E& initial) static inline E waitForError(const QtPromise::QPromise<T>& promise, const E& initial)
{ {
E error(initial); E error(initial);
promise.fail([&](const E& err) { promise
.fail([&](const E& err) {
error = err; error = err;
return T(); return T();
}).wait(); })
.wait();
return error; return error;
} }
template <typename E> template<typename E>
static inline E waitForError(const QtPromise::QPromise<void>& promise, const E& initial) static inline E waitForError(const QtPromise::QPromise<void>& promise, const E& initial)
{ {
E error(initial); E error(initial);
promise.fail([&](const E& err) { promise
.fail([&](const E& err) {
error = err; error = err;
}).wait(); })
.wait();
return error; return error;
} }
template <typename E, typename T> template<typename E, typename T>
static inline bool waitForRejected(const T& promise) static inline bool waitForRejected(const T& promise)
{ {
bool result = false; bool result = false;
promise.tapFail([&](const E&) { promise
.tapFail([&](const E&) {
result = true; result = true;
}).wait(); })
.wait();
return result; return result;
} }

View File

@ -40,10 +40,12 @@ void tst_thread::resolve()
source = QThread::currentThread(); source = QThread::currentThread();
resolve(42); resolve(42);
}); });
}}.then([&](int res) { }}
.then([&](int res) {
target = QThread::currentThread(); target = QThread::currentThread();
value = res; value = res;
}).wait(); })
.wait();
QVERIFY(source != nullptr); QVERIFY(source != nullptr);
QVERIFY(source != target); QVERIFY(source != target);
@ -62,10 +64,12 @@ void tst_thread::resolve_void()
source = QThread::currentThread(); source = QThread::currentThread();
resolve(); resolve();
}); });
}}.then([&]() { }}
.then([&]() {
target = QThread::currentThread(); target = QThread::currentThread();
value = 43; value = 43;
}).wait(); })
.wait();
QVERIFY(source != nullptr); QVERIFY(source != nullptr);
QVERIFY(source != target); QVERIFY(source != target);
@ -84,11 +88,13 @@ void tst_thread::reject()
source = QThread::currentThread(); source = QThread::currentThread();
reject(QString{"foo"}); reject(QString{"foo"});
}); });
}}.fail([&](const QString& err) { }}
.fail([&](const QString& err) {
target = QThread::currentThread(); target = QThread::currentThread();
error = err; error = err;
return -1; return -1;
}).wait(); })
.wait();
QVERIFY(source != nullptr); QVERIFY(source != nullptr);
QVERIFY(source != target); QVERIFY(source != target);
@ -106,12 +112,15 @@ void tst_thread::then()
int value = -1; int value = -1;
QThread* target = nullptr; QThread* target = nullptr;
QtPromise::resolve(QtConcurrent::run([&](const QPromise<int>& p) { QtPromise::resolve(QtConcurrent::run(
[&](const QPromise<int>& p) {
p.then([&](int res) { p.then([&](int res) {
target = QThread::currentThread(); target = QThread::currentThread();
value = res; value = res;
}).wait(); }).wait();
}, p)).wait(); },
p))
.wait();
QVERIFY(target != nullptr); QVERIFY(target != nullptr);
QVERIFY(source != target); QVERIFY(source != target);
@ -129,12 +138,15 @@ void tst_thread::then_void()
int value = -1; int value = -1;
QThread* target = nullptr; QThread* target = nullptr;
QtPromise::resolve(QtConcurrent::run([&](const QPromise<void>& p) { QtPromise::resolve(QtConcurrent::run(
[&](const QPromise<void>& p) {
p.then([&]() { p.then([&]() {
target = QThread::currentThread(); target = QThread::currentThread();
value = 43; value = 43;
}).wait(); }).wait();
}, p)).wait(); },
p))
.wait();
QVERIFY(target != nullptr); QVERIFY(target != nullptr);
QVERIFY(source != target); QVERIFY(source != target);
@ -152,13 +164,16 @@ void tst_thread::fail()
QString error; QString error;
QThread* target = nullptr; QThread* target = nullptr;
QtPromise::resolve(QtConcurrent::run([&](const QPromise<int>& p) { QtPromise::resolve(QtConcurrent::run(
[&](const QPromise<int>& p) {
p.fail([&](const QString& err) { p.fail([&](const QString& err) {
target = QThread::currentThread(); target = QThread::currentThread();
error = err; error = err;
return -1; return -1;
}).wait(); }).wait();
}, p)).wait(); },
p))
.wait();
QVERIFY(target != nullptr); QVERIFY(target != nullptr);
QVERIFY(source != target); QVERIFY(source != target);
@ -176,12 +191,15 @@ void tst_thread::finally()
int value = -1; int value = -1;
QThread* target = nullptr; QThread* target = nullptr;
QtPromise::resolve(QtConcurrent::run([&](const QPromise<int>& p) { QtPromise::resolve(QtConcurrent::run(
[&](const QPromise<int>& p) {
p.finally([&]() { p.finally([&]() {
target = QThread::currentThread(); target = QThread::currentThread();
value = 43; value = 43;
}).wait(); }).wait();
}, p)).wait(); },
p))
.wait();
QVERIFY(target != nullptr); QVERIFY(target != nullptr);
QVERIFY(source != target); QVERIFY(source != target);