mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2025-07-05 16:55:23 +08:00
Initial implementation
This commit is contained in:
107
src/qtpromise/qpromise.h
Normal file
107
src/qtpromise/qpromise.h
Normal file
@ -0,0 +1,107 @@
|
||||
#ifndef _QTPROMISE_QPROMISE_H
|
||||
#define _QTPROMISE_QPROMISE_H
|
||||
|
||||
// QPromise
|
||||
#include "qpromise_p.h"
|
||||
#include "qpromiseglobal.h"
|
||||
|
||||
// Qt
|
||||
#include <QExplicitlySharedDataPointer>
|
||||
#include <QVariant>
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
using namespace QtPromisePrivate;
|
||||
|
||||
template <typename T>
|
||||
class QPromiseBase
|
||||
{
|
||||
public:
|
||||
using Type = T;
|
||||
|
||||
QPromiseBase() : m_d(new QPromiseData<T>()) { }
|
||||
virtual ~QPromiseBase() { }
|
||||
|
||||
bool isFulfilled() const { return m_d->resolved && !m_d->rejected; }
|
||||
bool isRejected() const { return m_d->resolved && m_d->rejected; }
|
||||
bool isPending() const { return !m_d->resolved; }
|
||||
|
||||
template <typename TFulfilled, typename TRejected = std::nullptr_t>
|
||||
inline auto then(TFulfilled fulfilled, TRejected rejected = nullptr)
|
||||
-> typename QPromiseHandler<T, TFulfilled>::Promise;
|
||||
|
||||
template <typename TRejected>
|
||||
inline auto fail(TRejected rejected)
|
||||
-> typename QPromiseHandler<T, std::nullptr_t>::Promise;
|
||||
|
||||
template <typename TError>
|
||||
inline QPromise<T> reject(const TError& error);
|
||||
|
||||
inline QPromise<T> wait() const;
|
||||
|
||||
protected:
|
||||
QExplicitlySharedDataPointer<QPromiseData<T> > m_d;
|
||||
|
||||
virtual void notify(const typename QPromiseData<T>::HandlerList& handlers) const = 0;
|
||||
|
||||
inline void dispatch();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class QPromise: public QPromiseBase<T>
|
||||
{
|
||||
public:
|
||||
QPromise() : QPromiseBase<T>() {}
|
||||
|
||||
template <typename THandler>
|
||||
inline QPromise<T> finally(THandler handler);
|
||||
|
||||
inline QPromise<T> fulfill(const T& value);
|
||||
|
||||
public: // STATIC
|
||||
inline static QPromise<QVector<T> > all(const QVector<QPromise<T> >& promises);
|
||||
|
||||
protected:
|
||||
inline void notify(const typename QPromiseData<T>::HandlerList& handlers) const Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
friend class QPromiseBase<T>;
|
||||
|
||||
QPromise(const QPromiseBase<T>& p) : QPromiseBase<T>(p) { }
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
class QPromise<void>: public QPromiseBase<void>
|
||||
{
|
||||
public:
|
||||
QPromise(): QPromiseBase<void>() {}
|
||||
|
||||
template <typename THandler>
|
||||
inline QPromise<void> finally(THandler handler);
|
||||
|
||||
inline QPromise<void> fulfill();
|
||||
|
||||
public: // STATIC
|
||||
inline static QPromise<void> all(const QVector<QPromise<void> >& promises);
|
||||
|
||||
protected:
|
||||
inline void notify(const typename QPromiseData<void>::HandlerList& handlers) const Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
friend class QPromiseBase<void>;
|
||||
|
||||
QPromise(const QPromiseBase<void>& p) : QPromiseBase<void>(p) { }
|
||||
};
|
||||
|
||||
using QVariantPromise = QtPromise::QPromise<QVariant>;
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
Q_DECLARE_TYPEINFO(QtPromise::QVariantPromise, Q_MOVABLE_TYPE);
|
||||
Q_DECLARE_METATYPE(QtPromise::QVariantPromise)
|
||||
|
||||
#include "qpromise.inl"
|
||||
#include "qpromise_qfuture.inl"
|
||||
|
||||
#endif // ifndef _QTPROMISE_QPROMISE_H
|
228
src/qtpromise/qpromise.inl
Normal file
228
src/qtpromise/qpromise.inl
Normal file
@ -0,0 +1,228 @@
|
||||
// Qt
|
||||
#include <QCoreApplication>
|
||||
#include <QSharedPointer>
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
template <typename T>
|
||||
template <typename TFulfilled, typename TRejected>
|
||||
inline auto QPromiseBase<T>::then(TFulfilled fulfilled, TRejected rejected)
|
||||
-> typename QPromiseHandler<T, TFulfilled>::Promise
|
||||
{
|
||||
typename QPromiseHandler<T, TFulfilled>::Promise next;
|
||||
|
||||
m_d->handlers << QPromiseHandler<T, TFulfilled>::create(next, fulfilled);
|
||||
m_d->catchers << QPromiseCatcher<T, TRejected>::create(next, rejected);
|
||||
|
||||
if (m_d->resolved) {
|
||||
dispatch();
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename TRejected>
|
||||
inline auto QPromiseBase<T>::fail(TRejected rejected)
|
||||
-> typename QPromiseHandler<T, std::nullptr_t>::Promise
|
||||
{
|
||||
return then(nullptr, rejected);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename TError>
|
||||
inline QPromise<T> QPromiseBase<T>::reject(const TError& error)
|
||||
{
|
||||
if (!m_d->resolved) {
|
||||
m_d->error = QtPromisePrivate::to_exception_ptr(error);
|
||||
m_d->rejected = true;
|
||||
m_d->resolved = true;
|
||||
dispatch();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline QPromise<T> QPromiseBase<T>::wait() const
|
||||
{
|
||||
// @TODO wait timeout + global timeout
|
||||
while (!m_d->resolved) {
|
||||
QCoreApplication::processEvents(QEventLoop::AllEvents);
|
||||
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void QPromiseBase<T>::dispatch()
|
||||
{
|
||||
Q_ASSERT(m_d->resolved);
|
||||
|
||||
typename QPromiseData<T>::HandlerList handlers;
|
||||
typename QPromiseData<T>::CatcherList catchers;
|
||||
|
||||
handlers.swap(m_d->handlers);
|
||||
catchers.swap(m_d->catchers);
|
||||
|
||||
if (m_d->rejected) {
|
||||
const std::exception_ptr error = m_d->error;
|
||||
qtpromise_defer([catchers, error]() {
|
||||
for (auto catcher: catchers) {
|
||||
catcher(error);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
notify(handlers);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename THandler>
|
||||
inline QPromise<T> QPromise<T>::finally(THandler handler)
|
||||
{
|
||||
return this->then([=](const T& res) {
|
||||
return QPromise<void>().fulfill().then(handler).then([=](){
|
||||
return res;
|
||||
});
|
||||
}, [=]() {
|
||||
const auto exception = std::current_exception();
|
||||
return QPromise<void>().fulfill().then(handler).then([=](){
|
||||
std::rethrow_exception(exception);
|
||||
return T();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline QPromise<T> QPromise<T>::fulfill(const T& value)
|
||||
{
|
||||
if (!this->m_d->resolved) {
|
||||
this->m_d->rejected = false;
|
||||
this->m_d->resolved = true;
|
||||
this->m_d->value = value;
|
||||
this->dispatch();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline QPromise<QVector<T> > QPromise<T>::all(const QVector<QPromise<T> >& promises)
|
||||
{
|
||||
QPromise<QVector<T> > next;
|
||||
|
||||
const int count = promises.size();
|
||||
if (count == 0) {
|
||||
return next.fulfill({});
|
||||
}
|
||||
|
||||
QSharedPointer<int> remaining(new int(count));
|
||||
QSharedPointer<QVector<T> > results(new QVector<T>(count));
|
||||
|
||||
for (int i=0; i<count; ++i) {
|
||||
QPromise<T>(promises[i]).then([=](const T& res) mutable {
|
||||
if (next.isPending()) {
|
||||
(*results)[i] = res;
|
||||
if (--(*remaining) == 0) {
|
||||
next.fulfill(*results);
|
||||
}
|
||||
}
|
||||
}, [=]() mutable {
|
||||
if (next.isPending()) {
|
||||
next.reject(std::current_exception());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void QPromise<T>::notify(const typename QPromiseData<T>::HandlerList& handlers) const
|
||||
{
|
||||
const T value = this->m_d->value;
|
||||
qtpromise_defer([handlers, value]() {
|
||||
for (auto handler: handlers) {
|
||||
handler(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <typename THandler>
|
||||
inline QPromise<void> QPromise<void>::finally(THandler handler)
|
||||
{
|
||||
return this->then([=]() {
|
||||
return QPromise<void>().fulfill().then(handler).then([](){});
|
||||
}, [=]() {
|
||||
const auto exception = std::current_exception();
|
||||
return QPromise<void>().fulfill().then(handler).then([=](){
|
||||
std::rethrow_exception(exception);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
inline QPromise<void> QPromise<void>::fulfill()
|
||||
{
|
||||
if (!m_d->resolved) {
|
||||
m_d->rejected = false;
|
||||
m_d->resolved = true;
|
||||
dispatch();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline QPromise<void> QPromise<void>::all(const QVector<QPromise<void> >& promises)
|
||||
{
|
||||
QPromise<void> next;
|
||||
|
||||
QSharedPointer<int> remaining(new int(promises.size()));
|
||||
|
||||
for (const auto& promise: promises) {
|
||||
QPromise<void>(promise).then([=]() mutable {
|
||||
if (next.isPending()) {
|
||||
if (--(*remaining) == 0) {
|
||||
next.fulfill();
|
||||
}
|
||||
}
|
||||
}, [=]() mutable {
|
||||
if (next.isPending()) {
|
||||
next.reject(std::current_exception());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
inline void QPromise<void>::notify(const typename QPromiseData<void>::HandlerList& handlers) const
|
||||
{
|
||||
qtpromise_defer([handlers]() {
|
||||
for (const auto& handler: handlers) {
|
||||
handler();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
template <typename T>
|
||||
QPromise<T> qPromise(const T& value)
|
||||
{
|
||||
return QPromise<T>().fulfill(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
QPromise<QVector<T> > qPromiseAll(const QVector<QPromise<T> >& promises)
|
||||
{
|
||||
return QPromise<T>::all(promises);
|
||||
}
|
||||
|
||||
QPromise<void> qPromiseAll(const QVector<QPromise<void> >& promises)
|
||||
{
|
||||
return QPromise<void>::all(promises);
|
||||
}
|
||||
|
||||
} // namespace QtPromise
|
318
src/qtpromise/qpromise_p.h
Normal file
318
src/qtpromise/qpromise_p.h
Normal file
@ -0,0 +1,318 @@
|
||||
#ifndef _QTPROMISE_QPROMISE_P_H
|
||||
#define _QTPROMISE_QPROMISE_P_H
|
||||
|
||||
// QPromise
|
||||
#include "qpromiseglobal.h"
|
||||
|
||||
// Qt
|
||||
#include <QCoreApplication>
|
||||
#include <QTimer>
|
||||
#include <QSharedData>
|
||||
#include <QVector>
|
||||
|
||||
// STL
|
||||
#include <functional>
|
||||
|
||||
namespace QtPromise {
|
||||
template <typename T = void>
|
||||
class QPromise;
|
||||
}
|
||||
|
||||
namespace QtPromisePrivate {
|
||||
|
||||
using namespace QtPromise;
|
||||
|
||||
template <typename F>
|
||||
inline void qtpromise_defer(F f)
|
||||
{
|
||||
QTimer::singleShot(0, f);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct QPromiseDeduce
|
||||
{
|
||||
using Type = QPromise<Unqualified<T> >;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct QPromiseDeduce<QPromise<T> >
|
||||
: public QPromiseDeduce<T>
|
||||
{ };
|
||||
|
||||
template <typename T, typename TPromise = typename QPromiseDeduce<T>::Type>
|
||||
struct QPromiseFulfill
|
||||
{
|
||||
static void call(TPromise next, const T& value)
|
||||
{
|
||||
next.fulfill(value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct QPromiseFulfill<QPromise<T>, QPromise<T> >
|
||||
{
|
||||
static void call(QPromise<T> next, QPromise<T> promise)
|
||||
{
|
||||
promise.then(
|
||||
[=](const T& value) mutable {
|
||||
next.fulfill(value);
|
||||
},
|
||||
[=]() mutable {
|
||||
next.reject(std::current_exception());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct QPromiseFulfill<QPromise<void>, QPromise<void> >
|
||||
{
|
||||
template <typename TPromise>
|
||||
static void call(TPromise next, TPromise promise)
|
||||
{
|
||||
promise.then(
|
||||
[=]() mutable {
|
||||
next.fulfill();
|
||||
},
|
||||
[=]() mutable {
|
||||
next.reject(std::current_exception());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename TRes>
|
||||
struct QPromiseDispatch
|
||||
{
|
||||
using Promise = typename QPromiseDeduce<TRes>::Type;
|
||||
using ResType = Unqualified<TRes>;
|
||||
|
||||
template <typename TPromise, typename THandler>
|
||||
static void call(TPromise next, THandler handler, const T& value)
|
||||
{
|
||||
ResType res;
|
||||
try {
|
||||
res = handler(value);
|
||||
} catch (...) {
|
||||
next.reject(std::current_exception());
|
||||
return;
|
||||
}
|
||||
QPromiseFulfill<ResType>::call(next, res);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct QPromiseDispatch<T, void>
|
||||
{
|
||||
using Promise = QPromise<void>;
|
||||
|
||||
template <typename TPromise, typename THandler>
|
||||
static void call(TPromise next, THandler handler, const T& value)
|
||||
{
|
||||
try {
|
||||
handler(value);
|
||||
} catch (...) {
|
||||
next.reject(std::current_exception());
|
||||
return;
|
||||
}
|
||||
next.fulfill();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TRes>
|
||||
struct QPromiseDispatch<void, TRes>
|
||||
{
|
||||
using Promise = typename QPromiseDeduce<TRes>::Type;
|
||||
using ResType = Unqualified<TRes>;
|
||||
|
||||
template <typename TPromise, typename THandler>
|
||||
static void call(TPromise next, THandler handler)
|
||||
{
|
||||
ResType res;
|
||||
try {
|
||||
res = handler();
|
||||
} catch (...) {
|
||||
next.reject(std::current_exception());
|
||||
return;
|
||||
}
|
||||
QPromiseFulfill<ResType>::call(next, res);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct QPromiseDispatch<void, void>
|
||||
{
|
||||
using Promise = QPromise<void>;
|
||||
|
||||
template <typename TPromise, typename THandler>
|
||||
static void call(TPromise next, THandler handler)
|
||||
{
|
||||
try {
|
||||
handler();
|
||||
} catch (...) {
|
||||
next.reject(std::current_exception());
|
||||
return;
|
||||
}
|
||||
next.fulfill();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename THandler, typename TArg = typename ArgsOf<THandler>::first>
|
||||
struct QPromiseHandler
|
||||
{
|
||||
using ResType = typename std::result_of<THandler(T)>::type;
|
||||
using Promise = typename QPromiseDispatch<T, ResType>::Promise;
|
||||
|
||||
static std::function<void(T)> create(const Promise& next, THandler handler)
|
||||
{
|
||||
return [=](const T& value) mutable {
|
||||
QPromiseDispatch<T, ResType>::call(next, handler, value);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename THandler>
|
||||
struct QPromiseHandler<T, THandler, void>
|
||||
{
|
||||
using ResType = typename std::result_of<THandler()>::type;
|
||||
using Promise = typename QPromiseDispatch<T, ResType>::Promise;
|
||||
|
||||
static std::function<void(T)> create(const Promise& next, THandler handler)
|
||||
{
|
||||
return [=](const T&) mutable {
|
||||
QPromiseDispatch<void, ResType>::call(next, handler);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename THandler>
|
||||
struct QPromiseHandler<void, THandler, void>
|
||||
{
|
||||
using ResType = typename std::result_of<THandler()>::type;
|
||||
using Promise = typename QPromiseDispatch<void, ResType>::Promise;
|
||||
|
||||
static std::function<void()> create(const Promise& next, THandler handler)
|
||||
{
|
||||
return [=]() {
|
||||
QPromiseDispatch<void, ResType>::call(next, handler);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct QPromiseHandler<T, std::nullptr_t, void>
|
||||
{
|
||||
using Promise = QPromise<T>;
|
||||
|
||||
static std::function<void(T)> create(const Promise& next, std::nullptr_t)
|
||||
{
|
||||
return [next](const T& value) mutable {
|
||||
// 2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled,
|
||||
// promise2 must be fulfilled with the same value as promise1.
|
||||
QPromiseFulfill<T>::call(next, value);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct QPromiseHandler<void, std::nullptr_t, void>
|
||||
{
|
||||
using Promise = QPromise<void>;
|
||||
|
||||
template <typename TPromise>
|
||||
static std::function<void()> create(const TPromise& next, std::nullptr_t)
|
||||
{
|
||||
return [=]() mutable {
|
||||
// 2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled,
|
||||
// promise2 must be fulfilled with the same value as promise1.
|
||||
TPromise(next).fulfill();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename THandler, typename TArg = typename ArgsOf<THandler>::first>
|
||||
struct QPromiseCatcher
|
||||
{
|
||||
using Type = std::function<void(std::exception_ptr)>;
|
||||
using ResType = typename std::result_of<THandler(TArg)>::type;
|
||||
|
||||
template <typename TPromise>
|
||||
static Type create(const TPromise& next, THandler handler)
|
||||
{
|
||||
return [=](const std::exception_ptr& eptr) mutable {
|
||||
try {
|
||||
std::rethrow_exception(eptr);
|
||||
} catch (const TArg& error) {
|
||||
QPromiseDispatch<TArg, ResType>::call(next, handler, error);
|
||||
} catch(...) {
|
||||
TPromise(next).reject(std::current_exception());
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename THandler>
|
||||
struct QPromiseCatcher<T, THandler, void>
|
||||
{
|
||||
using Type = std::function<void(std::exception_ptr)>;
|
||||
using ResType = typename std::result_of<THandler()>::type;
|
||||
|
||||
template <typename TPromise>
|
||||
static Type create(const TPromise& next, THandler handler)
|
||||
{
|
||||
return [=](const std::exception_ptr& eptr) mutable {
|
||||
try {
|
||||
std::rethrow_exception(eptr);
|
||||
} catch (...) {
|
||||
QPromiseDispatch<void, ResType>::call(next, handler);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct QPromiseCatcher<T, std::nullptr_t, void>
|
||||
{
|
||||
using Type = std::function<void(std::exception_ptr)>;
|
||||
|
||||
template <typename TPromise>
|
||||
static Type create(const TPromise& next, std::nullptr_t)
|
||||
{
|
||||
return [=](const std::exception_ptr& eptr) mutable {
|
||||
// 2.2.7.4. If onRejected is not a function and promise1 is rejected,
|
||||
// promise2 must be rejected with the same reason as promise1
|
||||
TPromise(next).reject(eptr);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct QPromiseDataBase: public QSharedData
|
||||
{
|
||||
using ErrorType = std::exception_ptr;
|
||||
using CatcherList = QVector<std::function<void(ErrorType)> >;
|
||||
|
||||
bool resolved;
|
||||
bool rejected;
|
||||
ErrorType error;
|
||||
CatcherList catchers;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct QPromiseData: QPromiseDataBase<T>
|
||||
{
|
||||
using HandlerList = QVector<std::function<void(T)> >;
|
||||
|
||||
HandlerList handlers;
|
||||
T value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct QPromiseData<void>: QPromiseDataBase<void>
|
||||
{
|
||||
using HandlerList = QVector<std::function<void()> >;
|
||||
|
||||
HandlerList handlers;
|
||||
};
|
||||
|
||||
} // namespace QtPromise
|
||||
|
||||
#endif // ifndef _QTPROMISE_QPROMISE_H
|
79
src/qtpromise/qpromise_qfuture.inl
Normal file
79
src/qtpromise/qpromise_qfuture.inl
Normal file
@ -0,0 +1,79 @@
|
||||
#include <QFutureWatcher>
|
||||
#include <QFuture>
|
||||
|
||||
namespace QtPromisePrivate {
|
||||
|
||||
template <typename T>
|
||||
struct QPromiseDeduce<QFuture<T> >
|
||||
: public QPromiseDeduce<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct QPromiseFulfill<QFuture<T>, QPromise<T> >
|
||||
{
|
||||
static void call(QPromise<T> next, const QFuture<T>& future)
|
||||
{
|
||||
using Watcher = QFutureWatcher<T>;
|
||||
|
||||
Watcher* watcher = new Watcher();
|
||||
QObject::connect(
|
||||
watcher, &Watcher::finished,
|
||||
[next, watcher]() mutable {
|
||||
T res;
|
||||
try {
|
||||
res = watcher->result();
|
||||
} catch(...) {
|
||||
next.reject(std::current_exception());
|
||||
}
|
||||
|
||||
watcher->deleteLater();
|
||||
if (next.isPending()) {
|
||||
QPromiseFulfill<T>::call(next, res);
|
||||
}
|
||||
});
|
||||
|
||||
watcher->setFuture(future);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct QPromiseFulfill<QFuture<void>, QPromise<void> >
|
||||
{
|
||||
static void call(QPromise<void> next, const QFuture<void>& future)
|
||||
{
|
||||
using Watcher = QFutureWatcher<void>;
|
||||
|
||||
Watcher* watcher = new Watcher();
|
||||
QObject::connect(
|
||||
watcher, &Watcher::finished,
|
||||
[next, watcher]() mutable {
|
||||
try {
|
||||
// let's rethrown possibe exception
|
||||
watcher->waitForFinished();
|
||||
} catch(...) {
|
||||
next.reject(std::current_exception());
|
||||
}
|
||||
|
||||
watcher->deleteLater();
|
||||
if (next.isPending()) {
|
||||
next.fulfill();
|
||||
}
|
||||
});
|
||||
|
||||
watcher->setFuture(future);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace QtPromisePrivate
|
||||
|
||||
namespace QtPromise {
|
||||
|
||||
template <typename T>
|
||||
QPromise<T> qPromise(const QFuture<T>& future)
|
||||
{
|
||||
QPromise<T> next;
|
||||
QPromiseFulfill<QFuture<T> >::call(next, future);
|
||||
return next;
|
||||
}
|
||||
|
||||
} // namespace QtPromise
|
124
src/qtpromise/qpromiseglobal.h
Normal file
124
src/qtpromise/qpromiseglobal.h
Normal file
@ -0,0 +1,124 @@
|
||||
#ifndef _QTPROMISE_QPROMISEGLOBAL_H
|
||||
#define _QTPROMISE_QPROMISEGLOBAL_H
|
||||
|
||||
// QtCore
|
||||
#include <QtGlobal>
|
||||
|
||||
// STL
|
||||
#include <functional>
|
||||
|
||||
namespace QtPromisePrivate
|
||||
{
|
||||
// https://rmf.io/cxx11/even-more-traits#unqualified_types
|
||||
template <typename T>
|
||||
using Unqualified = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||
|
||||
/*!
|
||||
* \struct ArgsOf
|
||||
* http://stackoverflow.com/a/7943765
|
||||
* http://stackoverflow.com/a/27885283
|
||||
*/
|
||||
template <typename... Args>
|
||||
struct ArgsTraits
|
||||
{
|
||||
using types = std::tuple<Args...>;
|
||||
using first = typename std::tuple_element<0, types>::type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ArgsTraits<>
|
||||
{
|
||||
using types = std::tuple<>;
|
||||
using first = void;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf : public ArgsOf<decltype(&T::operator())>
|
||||
{ };
|
||||
|
||||
template <>
|
||||
struct ArgsOf<std::nullptr_t> : public ArgsTraits<>
|
||||
{ };
|
||||
|
||||
template <typename TReturn, typename... Args>
|
||||
struct ArgsOf<TReturn(Args...)> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename TReturn, typename... Args>
|
||||
struct ArgsOf<TReturn(*)(Args...)> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename T, typename TReturn, typename... Args>
|
||||
struct ArgsOf<TReturn(T::*)(Args...)> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename T, typename TReturn, typename... Args>
|
||||
struct ArgsOf<TReturn(T::*)(Args...) const> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename T, typename TReturn, typename... Args>
|
||||
struct ArgsOf<TReturn(T::*)(Args...) volatile> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename T, typename TReturn, typename... Args>
|
||||
struct ArgsOf<TReturn(T::*)(Args...) const volatile> : public ArgsTraits<Args...>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<std::function<T> > : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<T&> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<const T&> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<volatile T&> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<const volatile T&> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<T&&> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<const T&&> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<volatile T&&> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
template <typename T>
|
||||
struct ArgsOf<const volatile T&&> : public ArgsOf<T>
|
||||
{ };
|
||||
|
||||
/*!
|
||||
* \fn to_exception_ptr
|
||||
*/
|
||||
template <typename T>
|
||||
std::exception_ptr to_exception_ptr(const T& value)
|
||||
{
|
||||
try {
|
||||
throw value;
|
||||
} catch(...) {
|
||||
return std::current_exception();
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
std::exception_ptr to_exception_ptr(const std::exception_ptr& value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace QtPromisePrivate
|
||||
|
||||
#endif // ifndef _QTPROMISE_QPROMISEGLOBAL_H
|
6
src/qtpromise/qtpromise.pri
Normal file
6
src/qtpromise/qtpromise.pri
Normal file
@ -0,0 +1,6 @@
|
||||
HEADERS += \
|
||||
$$PWD/qpromise.h \
|
||||
$$PWD/qpromise.inl \
|
||||
$$PWD/qpromise_p.h \
|
||||
$$PWD/qpromise_qfuture.inl \
|
||||
$$PWD/qpromiseglobal.h
|
5
src/qtpromise/qtpromise.pro
Normal file
5
src/qtpromise/qtpromise.pro
Normal file
@ -0,0 +1,5 @@
|
||||
TEMPLATE = lib
|
||||
CONFIG += c++11 qt thread warn_on
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
include(qtpromise.pri)
|
2
src/src.pro
Normal file
2
src/src.pro
Normal file
@ -0,0 +1,2 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = qtpromise
|
Reference in New Issue
Block a user