restore nf7::Task once removed

This commit is contained in:
falsycat 2022-09-25 00:28:02 +09:00
parent 79f3cc9639
commit 09375ced9c
3 changed files with 107 additions and 4 deletions

View File

@ -103,6 +103,7 @@ target_sources(nf7
common/mutable_memento.hh
common/mutex.hh
common/native_file.hh
common/nfile_watcher.hh
common/node.hh
common/node_link_store.hh
common/node_root_lambda.hh
@ -111,6 +112,7 @@ target_sources(nf7
common/queue.hh
common/sequencer.hh
common/squashed_history.hh
common/task.hh
common/thread.hh
common/timed_queue.hh
common/util_algorithm.hh

View File

@ -18,6 +18,12 @@
namespace nf7 {
class CoroutineAbortException final : public nf7::Exception {
public:
using nf7::Exception::Exception;
};
// How To Use (factory side)
// 1. Create Future<T>::Promise. (T is a type of returned value)
// 2. Get Future<T> from Future<T>::Promise and Pass it to ones who want to get T.
@ -27,6 +33,7 @@ namespace nf7 {
// by Future::Then(), Future::ThenSub(), or co_await.
// T must not be void, use std::monostate instead
template <typename T>
class Future final {
@ -110,7 +117,7 @@ class Future final {
auto Wrap(const std::function<T()>& f) noexcept
try {
Return(f());
} catch (Exception&) {
} catch (...) {
Throw(std::current_exception());
}
@ -186,7 +193,7 @@ class Future final {
}
void Abort() noexcept {
h_.promise().Throw(
std::make_exception_ptr<nf7::Exception>({"coroutine aborted"}));
std::make_exception_ptr<CoroutineAbortException>({"coroutine aborted"}));
data_->aborted = true;
}
@ -283,7 +290,6 @@ class Future final {
std::unique_lock<std::mutex> k(data.mtx);
auto callee_ctx = data.ctx.lock();
assert(callee_ctx);
auto caller_data = caller.promise().data__();
auto caller_ctx = caller_data->ctx.lock();
@ -306,7 +312,7 @@ class Future final {
caller.resume();
}
}
auto await_resume() { return value(); }
auto& await_resume() { return value(); }
private:
std::optional<Imm> imm_;

95
common/task.hh Normal file
View File

@ -0,0 +1,95 @@
#pragma once
#include <memory>
#include <optional>
#include <utility>
#include "nf7.hh"
#include "common/future.hh"
namespace nf7 {
template <typename T>
class Task : public nf7::Context,
public std::enable_shared_from_this<Task<T>> {
public:
class Holder;
using Future = nf7::Future<T>;
using Coro = typename Future::Coro;
using nf7::Context::Context;
Task(const Task&) = delete;
Task(Task&&) = delete;
Task& operator=(const Task&) = delete;
Task& operator=(Task&&) = delete;
void Start() noexcept {
coro_ = Proc();
fu_ = coro_->Start(self());
}
void Abort() noexcept {
coro_->Abort();
}
auto self() noexcept {
return std::enable_shared_from_this<Task<T>>::shared_from_this();
}
std::optional<Future>& fu() noexcept { return *fu_; }
protected:
virtual Coro Proc() noexcept = 0;
private:
std::optional<Coro> coro_;
std::optional<Future> fu_;
};
// all operations are not thread-safe
template <typename T>
class Task<T>::Holder final {
public:
Holder() = default;
~Holder() noexcept {
Abort();
}
Holder(const Holder&) = delete;
Holder(Holder&&) = delete;
Holder& operator=(const Holder&) = delete;
Holder& operator=(Holder&&) = delete;
bool CleanUp() noexcept {
return !!std::exchange(fu_, std::nullopt);
}
void Abort() noexcept {
if (auto task = task_.lock()) {
task->Abort();
}
}
template <typename U, typename... Args>
nf7::Future<T> StartIf(Args&&... args) noexcept {
if (fu_) return *fu_;
auto task = std::make_shared<U>(std::forward<Args>(args)...);
task->Start();
task_ = task;
fu_ = task->fu();
return *fu_;
}
std::optional<nf7::Future<T>>& fu() noexcept { return fu_; }
const std::optional<nf7::Future<T>>& fu() const noexcept { return fu_; }
private:
std::weak_ptr<Task<T>> task_;
std::optional<nf7::Future<T>> fu_;
};
} // namespace nf7