From 3f4639639d5dd7f4ebc088965edda49dcabb1660 Mon Sep 17 00:00:00 2001 From: Victor Tran Date: Thu, 19 Dec 2019 00:50:21 +1100 Subject: [PATCH] tPromise improvements --- lib/lib.pro | 1 + lib/tpromise.cpp | 62 ++++++++++++++++++++ lib/tpromise.h | 144 ++++++++++++++++++++++++++++------------------- 3 files changed, 150 insertions(+), 57 deletions(-) create mode 100644 lib/tpromise.cpp diff --git a/lib/lib.pro b/lib/lib.pro index 8827beb..5d16d27 100644 --- a/lib/lib.pro +++ b/lib/lib.pro @@ -72,6 +72,7 @@ SOURCES += tvariantanimation.cpp \ tdatetimepicker/datetimepart.cpp \ tdatetimepicker/datetimepartbutton.cpp \ terrorflash.cpp \ + tpromise.cpp \ tpropertyanimation.cpp \ thelibsglobal.cpp \ ttoast.cpp \ diff --git a/lib/tpromise.cpp b/lib/tpromise.cpp new file mode 100644 index 0000000..a75d7b5 --- /dev/null +++ b/lib/tpromise.cpp @@ -0,0 +1,62 @@ +/**************************************** + * + * INSERT-PROJECT-NAME-HERE - INSERT-GENERIC-NAME-HERE + * Copyright (C) 2019 Victor Tran + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * *************************************/ + +#include "tpromise.h" + +template<> void tPromise::callNextFunction() +{ + if (d->resolvedValue.error != "") { + d->state = tPromisePrivate::Errored; + if (d->functionSetToRunAfterFailure) { + d->fnAfterFailure(d->resolvedValue.error); + } + } else { + d->state = tPromisePrivate::Resolved; + if (d->functionSetToRunAfterSuccess) { + d->fnAfterSuccess(); + } + } + + if (d->deleteAfter) this->deleteLater(); +} + +template<> tPromise* tPromise::runOnSameThread(typename tPromisePrivate::RunAsyncFunction functionToRun) +{ + tPromise* promise = new tPromise; + + typename tPromiseFunctions::SuccessFunction successFunction = [=]() { + promise->d->resolvedValue.error = ""; + QTimer::singleShot(0, [=] { + promise->callNextFunction(); + }); + }; + typename tPromiseFunctions::FailureFunction failureFunction = [=](QString error) { + promise->d->resolvedValue.error.swap(error); + QTimer::singleShot(0, [=] { + promise->callNextFunction(); + }); + + }; + functionToRun(successFunction, failureFunction); + + //Don't watch because this runs synchronously + + return promise; +} diff --git a/lib/tpromise.h b/lib/tpromise.h index c7db731..e0584bd 100644 --- a/lib/tpromise.h +++ b/lib/tpromise.h @@ -21,6 +21,17 @@ template<> struct tPromiseResults { QString error = ""; }; +template struct tPromiseFunctions +{ + using SuccessFunction = std::function; + using FailureFunction = std::function; +}; + +template<> struct tPromiseFunctions +{ + using SuccessFunction = std::function; + using FailureFunction = std::function; +}; template struct tPromisePrivate { enum State { @@ -29,11 +40,8 @@ template struct tPromisePrivate { Errored }; - using SuccessFunction = std::function; - using FailureFunction = std::function; - using RunFunction = std::function; - using RunAsyncFunction = std::function; + using RunAsyncFunction = std::function::SuccessFunction, typename tPromiseFunctions::FailureFunction)>; State state = Pending; bool functionSetToRunAfterSuccess = false; @@ -42,8 +50,8 @@ template struct tPromisePrivate { tPromiseResults resolvedValue; QFuture runFuture; - SuccessFunction fnAfterSuccess; - FailureFunction fnAfterFailure; + typename tPromiseFunctions::SuccessFunction fnAfterSuccess; + typename tPromiseFunctions::FailureFunction fnAfterFailure; void callSuccessFunction() { fnAfterSuccess(resolvedValue.result); @@ -61,11 +69,8 @@ template<> struct tPromisePrivate { Errored }; - using SuccessFunction = std::function; - using FailureFunction = std::function; - using RunFunction = std::function; - using RunAsyncFunction = std::function; + using RunAsyncFunction = std::function::SuccessFunction, tPromiseFunctions::FailureFunction)>; State state = Pending; bool functionSetToRunAfterSuccess = false; @@ -74,8 +79,8 @@ template<> struct tPromisePrivate { tPromiseResults resolvedValue; QFuture runFuture; - SuccessFunction fnAfterSuccess; - FailureFunction fnAfterFailure; + tPromiseFunctions::SuccessFunction fnAfterSuccess; + tPromiseFunctions::FailureFunction fnAfterFailure; void callSuccessFunction() { fnAfterSuccess(); @@ -93,8 +98,11 @@ template class tPromise explicit tPromise(typename tPromisePrivate::RunAsyncFunction functionToRun); ~tPromise(); - tPromise* then(typename tPromisePrivate::SuccessFunction functionToRunAfterSuccess); - tPromise* error(typename tPromisePrivate::FailureFunction functionToRunOnFailure); + static tPromise* runOnNewThread(typename tPromisePrivate::RunAsyncFunction functionToRun); + static tPromise* runOnSameThread(typename tPromisePrivate::RunAsyncFunction functionToRun); + + tPromise* then(typename tPromiseFunctions::SuccessFunction functionToRunAfterSuccess); + tPromise* error(typename tPromiseFunctions::FailureFunction functionToRunOnFailure); tPromiseResults await(); bool isResolved() { @@ -120,54 +128,40 @@ template class tPromise } private: + explicit tPromise(); tPromisePrivate* d; + void callNextFunction(); void watch(); }; +template void tPromise::callNextFunction() +{ + if (d->resolvedValue.error != "") { + d->state = tPromisePrivate::Errored; + if (d->functionSetToRunAfterFailure) { + d->fnAfterFailure(d->resolvedValue.error); + } + } else { + d->state = tPromisePrivate::Resolved; + if (d->functionSetToRunAfterSuccess) { + d->fnAfterSuccess(d->resolvedValue.result); + } + } + + if (d->deleteAfter) this->deleteLater(); +} + +template<> void tPromise::callNextFunction(); + + template inline void tPromise::watch() { QFutureWatcher* runFutureWatcher = new QFutureWatcher(); runFutureWatcher->setFuture(d->runFuture); QObject::connect(runFutureWatcher, &QFutureWatcher::finished, [=] { runFutureWatcher->deleteLater(); - - if (d->resolvedValue.error != "") { - d->state = tPromisePrivate::Errored; - if (d->functionSetToRunAfterFailure) { - d->fnAfterFailure(d->resolvedValue.error); - } - } else { - d->state = tPromisePrivate::Resolved; - if (d->functionSetToRunAfterSuccess) { - d->fnAfterSuccess(d->resolvedValue.result); - } - } - - if (d->deleteAfter) this->deleteLater(); - }); -} - -template<> inline void tPromise::watch() -{ - QFutureWatcher* runFutureWatcher = new QFutureWatcher(); - runFutureWatcher->setFuture(d->runFuture); - QObject::connect(runFutureWatcher, &QFutureWatcher::finished, [=] { - runFutureWatcher->deleteLater(); - - if (d->resolvedValue.error != "") { - d->state = tPromisePrivate::Errored; - if (d->functionSetToRunAfterFailure) { - d->fnAfterFailure(d->resolvedValue.error); - } - } else { - d->state = tPromisePrivate::Resolved; - if (d->functionSetToRunAfterSuccess) { - d->fnAfterSuccess(); - } - } - - if (d->deleteAfter) this->deleteLater(); + callNextFunction(); }); } @@ -199,12 +193,12 @@ template inline tPromise::tPromise(typename tPromisePrivate::R d->runFuture = QtConcurrent::run([=]() -> void { QEventLoop* loop = new QEventLoop; - typename tPromisePrivate::SuccessFunction successFunction = [=](T retVal) { + typename tPromiseFunctions::SuccessFunction successFunction = [=](T retVal) { d->resolvedValue.result = retVal; d->resolvedValue.error = ""; QTimer::singleShot(0, loop, &QEventLoop::quit); }; - typename tPromisePrivate::FailureFunction failureFunction = [=](QString error) { + typename tPromiseFunctions::FailureFunction failureFunction = [=](QString error) { d->resolvedValue.error.swap(error); QTimer::singleShot(0, loop, &QEventLoop::quit); }; @@ -224,11 +218,11 @@ template<> inline tPromise::tPromise(typename tPromisePrivate::RunAs d->runFuture = QtConcurrent::run([=]() -> void { QEventLoop* loop = new QEventLoop; - typename tPromisePrivate::SuccessFunction successFunction = [=]() { + typename tPromiseFunctions::SuccessFunction successFunction = [=]() { d->resolvedValue.error = ""; QTimer::singleShot(0, loop, &QEventLoop::quit); }; - typename tPromisePrivate::FailureFunction failureFunction = [=](QString error) { + typename tPromiseFunctions::FailureFunction failureFunction = [=](QString error) { d->resolvedValue.error.swap(error); QTimer::singleShot(0, loop, &QEventLoop::quit); }; @@ -247,7 +241,39 @@ template inline tPromise::~tPromise() delete d; } -template inline tPromise* tPromise::then(typename tPromisePrivate::SuccessFunction functionToRunAfterSuccess) { +template tPromise*tPromise::runOnNewThread(typename tPromisePrivate::RunAsyncFunction functionToRun) +{ + return new tPromise(functionToRun); +} + +template tPromise*tPromise::runOnSameThread(typename tPromisePrivate::RunAsyncFunction functionToRun) +{ + tPromise* promise = new tPromise; + + typename tPromiseFunctions::SuccessFunction successFunction = [=](T retVal) { + promise->d->resolvedValue.result = retVal; + promise->d->resolvedValue.error = ""; + QTimer::singleShot(0, [=] { + promise->callNextFunction(); + }); + }; + typename tPromiseFunctions::FailureFunction failureFunction = [=](QString error) { + promise->d->resolvedValue.error.swap(error); + QTimer::singleShot(0, [=] { + promise->callNextFunction(); + }); + + }; + functionToRun(successFunction, failureFunction); + + //Don't watch because this runs synchronously + + return promise; +} + +template<> tPromise* tPromise::runOnSameThread(typename tPromisePrivate::RunAsyncFunction functionToRun); + +template inline tPromise* tPromise::then(typename tPromiseFunctions::SuccessFunction functionToRunAfterSuccess) { Q_ASSERT(!d->functionSetToRunAfterSuccess); if (d->functionSetToRunAfterSuccess) return this; @@ -261,7 +287,7 @@ template inline tPromise* tPromise::then(typename tPromisePriv return this; } -template inline tPromise* tPromise::error(typename tPromisePrivate::FailureFunction functionToRunOnFailure) { +template inline tPromise* tPromise::error(typename tPromiseFunctions::FailureFunction functionToRunOnFailure) { Q_ASSERT(!d->functionSetToRunAfterFailure); if (d->functionSetToRunAfterFailure) return this; @@ -290,5 +316,9 @@ template inline tPromiseResults tPromise::await() { return retval; } +template tPromise::tPromise() +{ + d = new tPromisePrivate; +} #endif // TPROMISE_H