add Future::Completer::RunAfter()

This commit is contained in:
falsycat 2023-10-05 15:08:56 +09:00
parent ff529a521a
commit 81f9bda412
2 changed files with 76 additions and 1 deletions

View File

@ -5,6 +5,7 @@
#include <exception>
#include <functional>
#include <memory>
#include <tuple>
#include <utility>
#include <variant>
#include <vector>
@ -258,7 +259,8 @@ class Future<T>::Completer final {
}
public:
Completer& Attach(const std::shared_ptr<void>& ptr) {
template <typename V>
Completer& Attach(const std::shared_ptr<V>& ptr) {
internal_->Listen([ptr](auto&) {});
return *this;
}
@ -300,6 +302,40 @@ class Future<T>::Completer final {
return *this;
}
private:
template <typename V, FutureLike Fu, typename... Args>
static void RunAfter_Each(
const std::shared_ptr<V>& ptr, Fu fu, Args&&... args) {
fu.Attach(ptr);
RunAfter_Each(ptr, std::forward<Args>(args)...);
}
static void RunAfter_Each(const std::shared_ptr<void>&) noexcept { }
public:
template <typename F, typename... Args>
Completer& RunAfter(F&& f, Args&&... args) {
struct A final {
public:
using Tuple = std::tuple<std::remove_reference_t<Args>...>;
public:
A(const Completer& self, F&& f, Tuple&& args) noexcept
: self_(self), f_(std::move(f)), args_(std::move(args)) { }
~A() noexcept {
self_.Run([this]() { return std::apply(f_, args_); });
}
private:
Completer self_;
F f_;
Tuple args_;
};
RunAfter_Each(
std::make_shared<A>(*this, std::move(f), std::make_tuple(args...)),
std::forward<Args>(args)...);
return *this;
}
public:
Future<T> future() const noexcept {
assert(nullptr != internal_);

View File

@ -421,6 +421,45 @@ TEST(FutureCompleter, RunAsyncWithThrow) {
[](auto&) -> int32_t { throw nf7::Exception {"helloworld"}; });
}
TEST(FutureCompleter, RunAfterWithArgsImmediately) {
nf7::Future<int32_t> fu1 {1};
nf7::Future<int32_t> fu2 {2};
nf7::Future<int32_t> fu3 {3};
auto fu = nf7::Future<int32_t>::Completer {}
.RunAfter(
[](auto& a, auto& b, auto& c) {
return a.value()+b.value()+c.value();
}, fu1, fu2, fu3)
.future();
ASSERT_TRUE(fu.done());
EXPECT_EQ(fu.value(), int32_t {6});
}
TEST(FutureCompleter, RunAfterWithArgsLazy) {
nf7::Future<int32_t> fu1 {1};
nf7::Future<int32_t>::Completer comp2;
nf7::Future<int32_t> fu3 {3};
auto fu = nf7::Future<int32_t>::Completer {}
.RunAfter(
[](auto& a, auto& b, auto& c) {
return a.value()+b.value()+c.value();
}, fu1, comp2.future(), fu3)
.future();
EXPECT_TRUE(fu.yet());
comp2.Complete(100);
ASSERT_TRUE(fu.done());
EXPECT_EQ(fu.value(), 104);
}
TEST(FutureCompleter, RunAfterWithoutTargets) {
auto fu = nf7::Future<int32_t>::Completer {}
.RunAfter([]() { return 666; })
.future();
ASSERT_TRUE(fu.done());
EXPECT_EQ(fu.value(), int32_t {666});
}
#if !defined(NDEBUG)
TEST(Future, DeathByListenInCallback) {