mirror of
https://github.com/simonbrunel/qtpromise.git
synced 2024-11-24 11:40:41 +08:00
Avoid value copy when fulfilled from promise
This commit is contained in:
parent
c4aab4ef36
commit
49a1d6a57b
@ -49,6 +49,7 @@ public: // STATIC
|
||||
inline static QPromise<T> reject(E&& error);
|
||||
|
||||
protected:
|
||||
friend struct QtPromisePrivate::PromiseFulfill<QPromise<T> >;
|
||||
friend class QPromiseResolve<T>;
|
||||
friend class QPromiseReject<T>;
|
||||
|
||||
|
@ -12,28 +12,18 @@ public:
|
||||
: m_promise(new QPromise<T>(std::move(p)))
|
||||
{ }
|
||||
|
||||
void operator()(const T& value) const
|
||||
template <typename V>
|
||||
void operator()(V&& value) const
|
||||
{
|
||||
resolve(value);
|
||||
}
|
||||
|
||||
void operator()(T&& value) const
|
||||
{
|
||||
resolve(std::move(value));
|
||||
Q_ASSERT(!m_promise.isNull());
|
||||
if (m_promise->isPending()) {
|
||||
m_promise->m_d->resolve(std::forward<V>(value));
|
||||
m_promise->m_d->dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QSharedPointer<QPromise<T> > m_promise;
|
||||
|
||||
template <typename U>
|
||||
void resolve(U&& value) const
|
||||
{
|
||||
Q_ASSERT(!m_promise.isNull());
|
||||
if (m_promise->isPending()) {
|
||||
m_promise->m_d->resolve(std::forward<U>(value));
|
||||
m_promise->m_d->dispatch();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
|
@ -79,13 +79,17 @@ struct PromiseFulfill<QtPromise::QPromise<T> >
|
||||
const QtPromise::QPromiseResolve<T>& resolve,
|
||||
const QtPromise::QPromiseReject<T>& reject)
|
||||
{
|
||||
promise.then(
|
||||
[=](const T& value) {
|
||||
resolve(value);
|
||||
},
|
||||
[=]() { // catch all
|
||||
reject(std::current_exception());
|
||||
if (promise.isFulfilled()) {
|
||||
resolve(promise.m_d->value());
|
||||
} else if (promise.isRejected()) {
|
||||
reject(promise.m_d->error());
|
||||
} else {
|
||||
promise.then([=]() {
|
||||
resolve(promise.m_d->value());
|
||||
}, [=]() { // catch all
|
||||
reject(promise.m_d->error());
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -98,13 +102,17 @@ struct PromiseFulfill<QtPromise::QPromise<void> >
|
||||
const TResolve& resolve,
|
||||
const TReject& reject)
|
||||
{
|
||||
promise.then(
|
||||
[=]() {
|
||||
if (promise.isFulfilled()) {
|
||||
resolve();
|
||||
} else if (promise.isRejected()) {
|
||||
reject(promise.m_d->error());
|
||||
} else {
|
||||
promise.then([=]() {
|
||||
resolve();
|
||||
},
|
||||
[=]() { // catch all
|
||||
reject(std::current_exception());
|
||||
}, [=]() { // catch all
|
||||
reject(promise.m_d->error());
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -377,6 +385,20 @@ public:
|
||||
setSettled();
|
||||
}
|
||||
|
||||
void reject(const QSharedPointer<Error>& error)
|
||||
{
|
||||
Q_ASSERT(isPending());
|
||||
Q_ASSERT(m_error.isNull());
|
||||
m_error = error;
|
||||
this->setSettled();
|
||||
}
|
||||
|
||||
const QSharedPointer<Error>& error() const
|
||||
{
|
||||
Q_ASSERT(isRejected());
|
||||
return m_error;
|
||||
}
|
||||
|
||||
void dispatch()
|
||||
{
|
||||
if (isPending()) {
|
||||
@ -438,6 +460,7 @@ class PromiseData : public PromiseDataBase<T, void(const T&)>
|
||||
public:
|
||||
void resolve(T&& value)
|
||||
{
|
||||
Q_ASSERT(this->isPending());
|
||||
Q_ASSERT(m_value.isNull());
|
||||
m_value.reset(new T(std::move(value)));
|
||||
this->setSettled();
|
||||
@ -445,11 +468,26 @@ public:
|
||||
|
||||
void resolve(const T& value)
|
||||
{
|
||||
Q_ASSERT(this->isPending());
|
||||
Q_ASSERT(m_value.isNull());
|
||||
m_value.reset(new T(value));
|
||||
this->setSettled();
|
||||
}
|
||||
|
||||
void resolve(const QSharedPointer<T>& value)
|
||||
{
|
||||
Q_ASSERT(this->isPending());
|
||||
Q_ASSERT(m_value.isNull());
|
||||
m_value = value;
|
||||
this->setSettled();
|
||||
}
|
||||
|
||||
const QSharedPointer<T>& value() const
|
||||
{
|
||||
Q_ASSERT(this->isFulfilled());
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void notify(const QVector<Handler>& handlers) Q_DECL_OVERRIDE
|
||||
{
|
||||
QSharedPointer<T> value(m_value);
|
||||
@ -473,7 +511,10 @@ class PromiseData<void> : public PromiseDataBase<void, void()>
|
||||
using Handler = typename PromiseDataBase<void, void()>::Handler;
|
||||
|
||||
public:
|
||||
void resolve() { setSettled(); }
|
||||
void resolve()
|
||||
{
|
||||
setSettled();
|
||||
}
|
||||
|
||||
protected:
|
||||
void notify(const QVector<Handler>& handlers) Q_DECL_OVERRIDE
|
||||
|
@ -14,6 +14,7 @@ private Q_SLOTS:
|
||||
void valueResolve();
|
||||
void valueReject();
|
||||
void valueThen();
|
||||
void valueDelayed();
|
||||
void errorReject();
|
||||
void errorThen();
|
||||
|
||||
@ -162,6 +163,36 @@ void tst_benchmark::valueThen()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_benchmark::valueDelayed()
|
||||
{
|
||||
{ // should not copy the value on continutation if fulfilled
|
||||
int value = -1;
|
||||
Data::logs().reset();
|
||||
QPromise<int>::resolve(42).then([&](int res) {
|
||||
return QPromise<Data>::resolve(Data(res + 1));
|
||||
}).then([&](const Data& res) {
|
||||
value = res.value();
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 1);
|
||||
QCOMPARE(Data::logs().copy, 0);
|
||||
QCOMPARE(Data::logs().move, 1); // move value to the input promise data
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
QCOMPARE(value, 43);
|
||||
}
|
||||
{ // should not create value on continutation if rejected
|
||||
Data::logs().reset();
|
||||
QPromise<int>::resolve(42).then([&]() {
|
||||
return QPromise<Data>::reject(QString("foo"));
|
||||
}).wait();
|
||||
|
||||
QCOMPARE(Data::logs().ctor, 0);
|
||||
QCOMPARE(Data::logs().copy, 0);
|
||||
QCOMPARE(Data::logs().move, 0);
|
||||
QCOMPARE(Data::logs().refs, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void tst_benchmark::errorReject()
|
||||
{
|
||||
{ // should create one copy of the error when rejected by rvalue
|
||||
|
Loading…
Reference in New Issue
Block a user