|
|
|
|
@@ -19,6 +19,7 @@
|
|
|
|
|
#include "./future.hpp"
|
|
|
|
|
#include "./message_queue.hpp"
|
|
|
|
|
#include "../container/optional.hpp"
|
|
|
|
|
#include "../internal/common.hpp"
|
|
|
|
|
#include "../util/flag.hpp"
|
|
|
|
|
#include "../util/iterators.hpp"
|
|
|
|
|
#include "../util/traits.hpp"
|
|
|
|
|
@@ -68,28 +69,28 @@ private:
|
|
|
|
|
std::weak_ptr<struct TaskSharedState> state_;
|
|
|
|
|
public:
|
|
|
|
|
TaskHandle() = default;
|
|
|
|
|
explicit TaskHandle(std::weak_ptr<TaskSharedState> state) noexcept : state_(std::move(state)) {}
|
|
|
|
|
explicit TaskHandle(std::weak_ptr<TaskSharedState> state) MIJIN_NOEXCEPT : state_(std::move(state)) {}
|
|
|
|
|
TaskHandle(const TaskHandle&) = default;
|
|
|
|
|
TaskHandle(TaskHandle&&) = default;
|
|
|
|
|
|
|
|
|
|
TaskHandle& operator=(const TaskHandle&) = default;
|
|
|
|
|
TaskHandle& operator=(TaskHandle&&) = default;
|
|
|
|
|
|
|
|
|
|
bool operator==(const TaskHandle& other) const noexcept {
|
|
|
|
|
bool operator==(const TaskHandle& other) const MIJIN_NOEXCEPT {
|
|
|
|
|
return !state_.owner_before(other.state_) && !other.state_.owner_before(state_);
|
|
|
|
|
}
|
|
|
|
|
bool operator!=(const TaskHandle& other) const noexcept {
|
|
|
|
|
bool operator!=(const TaskHandle& other) const MIJIN_NOEXCEPT {
|
|
|
|
|
return !(*this == other);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] bool isValid() const noexcept
|
|
|
|
|
[[nodiscard]] bool isValid() const MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
return !state_.expired();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void cancel() const noexcept;
|
|
|
|
|
inline void cancel() const MIJIN_NOEXCEPT;
|
|
|
|
|
#if MIJIN_COROUTINE_ENABLE_DEBUG_INFO
|
|
|
|
|
inline Optional<Stacktrace> getCreationStack() const noexcept;
|
|
|
|
|
inline Optional<Stacktrace> getCreationStack() const MIJIN_NOEXCEPT;
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
struct TaskSharedState
|
|
|
|
|
@@ -110,11 +111,11 @@ struct TaskState
|
|
|
|
|
|
|
|
|
|
TaskState() = default;
|
|
|
|
|
TaskState(const TaskState&) = default;
|
|
|
|
|
TaskState(TaskState&&) noexcept = default;
|
|
|
|
|
inline TaskState(T _value, TaskStatus _status) noexcept : value(std::move(_value)), status(_status) {}
|
|
|
|
|
inline TaskState(std::exception_ptr _exception) noexcept : exception(std::move(_exception)), status(TaskStatus::FINISHED) {}
|
|
|
|
|
TaskState(TaskState&&) MIJIN_NOEXCEPT = default;
|
|
|
|
|
inline TaskState(T _value, TaskStatus _status) MIJIN_NOEXCEPT : value(std::move(_value)), status(_status) {}
|
|
|
|
|
inline TaskState(std::exception_ptr _exception) MIJIN_NOEXCEPT : exception(std::move(_exception)), status(TaskStatus::FINISHED) {}
|
|
|
|
|
TaskState& operator=(const TaskState&) = default;
|
|
|
|
|
TaskState& operator=(TaskState&&) noexcept = default;
|
|
|
|
|
TaskState& operator=(TaskState&&) MIJIN_NOEXCEPT = default;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
@@ -125,11 +126,11 @@ struct TaskState<void>
|
|
|
|
|
|
|
|
|
|
TaskState() = default;
|
|
|
|
|
TaskState(const TaskState&) = default;
|
|
|
|
|
TaskState(TaskState&&) noexcept = default;
|
|
|
|
|
inline TaskState(TaskStatus _status) noexcept : status(_status) {}
|
|
|
|
|
inline TaskState(std::exception_ptr _exception) noexcept : exception(std::move(_exception)), status(TaskStatus::FINISHED) {}
|
|
|
|
|
TaskState(TaskState&&) MIJIN_NOEXCEPT = default;
|
|
|
|
|
inline TaskState(TaskStatus _status) MIJIN_NOEXCEPT : status(_status) {}
|
|
|
|
|
inline TaskState(std::exception_ptr _exception) MIJIN_NOEXCEPT : exception(std::move(_exception)), status(TaskStatus::FINISHED) {}
|
|
|
|
|
TaskState& operator=(const TaskState&) = default;
|
|
|
|
|
TaskState& operator=(TaskState&&) noexcept = default;
|
|
|
|
|
TaskState& operator=(TaskState&&) MIJIN_NOEXCEPT = default;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
namespace impl
|
|
|
|
|
@@ -138,15 +139,15 @@ template<typename TReturn, typename TPromise>
|
|
|
|
|
struct TaskReturn
|
|
|
|
|
{
|
|
|
|
|
template<typename... TArgs>
|
|
|
|
|
constexpr void return_value(TArgs&&... args) noexcept {
|
|
|
|
|
constexpr void return_value(TArgs&&... args) MIJIN_NOEXCEPT {
|
|
|
|
|
(static_cast<TPromise&>(*this).state_) = TaskState<TReturn>(TReturn(std::forward<TArgs>(args)...), TaskStatus::FINISHED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr void return_value(TReturn value) noexcept {
|
|
|
|
|
constexpr void return_value(TReturn value) MIJIN_NOEXCEPT {
|
|
|
|
|
(static_cast<TPromise&>(*this).state_) = TaskState<TReturn>(TReturn(std::move(value)), TaskStatus::FINISHED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr void unhandled_exception() noexcept {
|
|
|
|
|
constexpr void unhandled_exception() MIJIN_NOEXCEPT {
|
|
|
|
|
(static_cast<TPromise&>(*this).state_) = TaskState<TReturn>(std::current_exception());
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
@@ -154,11 +155,11 @@ struct TaskReturn
|
|
|
|
|
template<typename TPromise>
|
|
|
|
|
struct TaskReturn<void, TPromise>
|
|
|
|
|
{
|
|
|
|
|
constexpr void return_void() noexcept {
|
|
|
|
|
constexpr void return_void() MIJIN_NOEXCEPT {
|
|
|
|
|
static_cast<TPromise&>(*this).state_.status = TaskStatus::FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
constexpr void unhandled_exception() noexcept {
|
|
|
|
|
constexpr void unhandled_exception() MIJIN_NOEXCEPT {
|
|
|
|
|
(static_cast<TPromise&>(*this).state_) = TaskState<void>(std::current_exception());
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
@@ -169,8 +170,8 @@ struct TaskAwaitableFuture
|
|
|
|
|
{
|
|
|
|
|
FuturePtr<TValue> future;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] constexpr bool await_ready() const noexcept { return future->ready(); }
|
|
|
|
|
constexpr void await_suspend(std::coroutine_handle<>) const noexcept {}
|
|
|
|
|
[[nodiscard]] constexpr bool await_ready() const MIJIN_NOEXCEPT { return future->ready(); }
|
|
|
|
|
constexpr void await_suspend(std::coroutine_handle<>) const MIJIN_NOEXCEPT {}
|
|
|
|
|
constexpr TValue await_resume() const
|
|
|
|
|
{
|
|
|
|
|
impl::throwIfCancelled();
|
|
|
|
|
@@ -188,8 +189,8 @@ struct TaskAwaitableSignal
|
|
|
|
|
{
|
|
|
|
|
std::shared_ptr<std::tuple<TArgs...>> data;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] constexpr bool await_ready() const noexcept { return false; }
|
|
|
|
|
constexpr void await_suspend(std::coroutine_handle<>) const noexcept {}
|
|
|
|
|
[[nodiscard]] constexpr bool await_ready() const MIJIN_NOEXCEPT { return false; }
|
|
|
|
|
constexpr void await_suspend(std::coroutine_handle<>) const MIJIN_NOEXCEPT {}
|
|
|
|
|
inline auto& await_resume() const
|
|
|
|
|
{
|
|
|
|
|
impl::throwIfCancelled();
|
|
|
|
|
@@ -202,8 +203,8 @@ struct TaskAwaitableSignal<TSingleArg>
|
|
|
|
|
{
|
|
|
|
|
std::shared_ptr<TSingleArg> data;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] constexpr bool await_ready() const noexcept { return false; }
|
|
|
|
|
constexpr void await_suspend(std::coroutine_handle<>) const noexcept {}
|
|
|
|
|
[[nodiscard]] constexpr bool await_ready() const MIJIN_NOEXCEPT { return false; }
|
|
|
|
|
constexpr void await_suspend(std::coroutine_handle<>) const MIJIN_NOEXCEPT {}
|
|
|
|
|
constexpr auto& await_resume() const
|
|
|
|
|
{
|
|
|
|
|
impl::throwIfCancelled();
|
|
|
|
|
@@ -214,8 +215,8 @@ struct TaskAwaitableSignal<TSingleArg>
|
|
|
|
|
template<>
|
|
|
|
|
struct TaskAwaitableSignal<>
|
|
|
|
|
{
|
|
|
|
|
[[nodiscard]] constexpr bool await_ready() const noexcept { return false; }
|
|
|
|
|
constexpr void await_suspend(std::coroutine_handle<>) const noexcept {}
|
|
|
|
|
[[nodiscard]] constexpr bool await_ready() const MIJIN_NOEXCEPT { return false; }
|
|
|
|
|
constexpr void await_suspend(std::coroutine_handle<>) const MIJIN_NOEXCEPT {}
|
|
|
|
|
inline void await_resume() const {
|
|
|
|
|
impl::throwIfCancelled();
|
|
|
|
|
}
|
|
|
|
|
@@ -223,8 +224,8 @@ struct TaskAwaitableSignal<>
|
|
|
|
|
|
|
|
|
|
struct TaskAwaitableSuspend
|
|
|
|
|
{
|
|
|
|
|
[[nodiscard]] constexpr bool await_ready() const noexcept { return false; }
|
|
|
|
|
constexpr void await_suspend(std::coroutine_handle<>) const noexcept {}
|
|
|
|
|
[[nodiscard]] constexpr bool await_ready() const MIJIN_NOEXCEPT { return false; }
|
|
|
|
|
constexpr void await_suspend(std::coroutine_handle<>) const MIJIN_NOEXCEPT {}
|
|
|
|
|
inline void await_resume() const {
|
|
|
|
|
impl::throwIfCancelled();
|
|
|
|
|
}
|
|
|
|
|
@@ -241,22 +242,22 @@ struct TaskPromise : impl::TaskReturn<typename TTraits::result_t, TaskPromise<TT
|
|
|
|
|
std::shared_ptr<TaskSharedState> sharedState_ = std::make_shared<TaskSharedState>();
|
|
|
|
|
TaskLoop* loop_ = nullptr;
|
|
|
|
|
|
|
|
|
|
constexpr task_t get_return_object() noexcept { return task_t(handle_t::from_promise(*this)); }
|
|
|
|
|
constexpr TaskAwaitableSuspend initial_suspend() noexcept { return {}; }
|
|
|
|
|
constexpr std::suspend_always final_suspend() noexcept { return {}; }
|
|
|
|
|
constexpr task_t get_return_object() MIJIN_NOEXCEPT { return task_t(handle_t::from_promise(*this)); }
|
|
|
|
|
constexpr TaskAwaitableSuspend initial_suspend() MIJIN_NOEXCEPT { return {}; }
|
|
|
|
|
constexpr std::suspend_always final_suspend() noexcept { return {}; } // note: this must always be noexcept, no matter what
|
|
|
|
|
|
|
|
|
|
// template<typename TValue>
|
|
|
|
|
// constexpr std::suspend_always yield_value(TValue value) noexcept {
|
|
|
|
|
// constexpr std::suspend_always yield_value(TValue value) MIJIN_NOEXCEPT {
|
|
|
|
|
// *state_ = TaskState<result_t>(std::move(value), TaskStatus::YIELDED);
|
|
|
|
|
// return {};
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// TODO: implement yielding (can't use futures for this)
|
|
|
|
|
|
|
|
|
|
// constexpr void unhandled_exception() noexcept {}
|
|
|
|
|
// constexpr void unhandled_exception() MIJIN_NOEXCEPT {}
|
|
|
|
|
|
|
|
|
|
template<typename TValue>
|
|
|
|
|
auto await_transform(FuturePtr<TValue> future) noexcept
|
|
|
|
|
auto await_transform(FuturePtr<TValue> future) MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
MIJIN_ASSERT(loop_ != nullptr, "Cannot await future outside of a loop!");
|
|
|
|
|
TaskAwaitableFuture<TValue> awaitable{future};
|
|
|
|
|
@@ -272,7 +273,7 @@ struct TaskPromise : impl::TaskReturn<typename TTraits::result_t, TaskPromise<TT
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename TResultOther>
|
|
|
|
|
auto await_transform(TaskBase<TResultOther> task) noexcept
|
|
|
|
|
auto await_transform(TaskBase<TResultOther> task) MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
MIJIN_ASSERT(loop_ != nullptr, "Cannot await another task outside of a loop!"); // NOLINT(clang-analyzer-core.UndefinedBinaryOperatorResult)
|
|
|
|
|
auto future = delayEvaluation<TResultOther>(loop_)->addTask(std::move(task), &sharedState_->subTask); // hackidyhack: delay evaluation of the type of loop_ as it is only forward-declared here
|
|
|
|
|
@@ -280,7 +281,7 @@ struct TaskPromise : impl::TaskReturn<typename TTraits::result_t, TaskPromise<TT
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename TFirstArg, typename TSecondArg, typename... TArgs>
|
|
|
|
|
auto await_transform(Signal<TFirstArg, TSecondArg, TArgs...>& signal) noexcept
|
|
|
|
|
auto await_transform(Signal<TFirstArg, TSecondArg, TArgs...>& signal) MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
auto data = std::make_shared<std::tuple<TFirstArg, TSecondArg, TArgs...>>();
|
|
|
|
|
signal.connect([this, data](TFirstArg arg0, TSecondArg arg1, TArgs... args) mutable
|
|
|
|
|
@@ -294,7 +295,7 @@ struct TaskPromise : impl::TaskReturn<typename TTraits::result_t, TaskPromise<TT
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename TFirstArg>
|
|
|
|
|
auto await_transform(Signal<TFirstArg>& signal) noexcept
|
|
|
|
|
auto await_transform(Signal<TFirstArg>& signal) MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
auto data = std::make_shared<TFirstArg>();
|
|
|
|
|
signal.connect([this, data](TFirstArg arg0) mutable
|
|
|
|
|
@@ -307,7 +308,7 @@ struct TaskPromise : impl::TaskReturn<typename TTraits::result_t, TaskPromise<TT
|
|
|
|
|
return awaitable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto await_transform(Signal<>& signal) noexcept
|
|
|
|
|
auto await_transform(Signal<>& signal) MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
signal.connect([this]()
|
|
|
|
|
{
|
|
|
|
|
@@ -318,17 +319,17 @@ struct TaskPromise : impl::TaskReturn<typename TTraits::result_t, TaskPromise<TT
|
|
|
|
|
return awaitable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::suspend_always await_transform(std::suspend_always) noexcept
|
|
|
|
|
std::suspend_always await_transform(std::suspend_always) MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
state_.status = TaskStatus::SUSPENDED;
|
|
|
|
|
return std::suspend_always();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::suspend_never await_transform(std::suspend_never) noexcept {
|
|
|
|
|
std::suspend_never await_transform(std::suspend_never) MIJIN_NOEXCEPT {
|
|
|
|
|
return std::suspend_never();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TaskAwaitableSuspend await_transform(TaskAwaitableSuspend) noexcept
|
|
|
|
|
TaskAwaitableSuspend await_transform(TaskAwaitableSuspend) MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
state_.status = TaskStatus::SUSPENDED;
|
|
|
|
|
return TaskAwaitableSuspend();
|
|
|
|
|
@@ -352,7 +353,7 @@ public:
|
|
|
|
|
private:
|
|
|
|
|
handle_t handle_;
|
|
|
|
|
public:
|
|
|
|
|
constexpr explicit TaskBase(handle_t handle) noexcept : handle_(handle) {
|
|
|
|
|
constexpr explicit TaskBase(handle_t handle) MIJIN_NOEXCEPT : handle_(handle) {
|
|
|
|
|
#if MIJIN_COROUTINE_ENABLE_DEBUG_INFO
|
|
|
|
|
if (Result<Stacktrace> stacktrace = captureStacktrace(2); stacktrace.isSuccess())
|
|
|
|
|
{
|
|
|
|
|
@@ -361,12 +362,12 @@ public:
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
TaskBase(const TaskBase&) = delete;
|
|
|
|
|
TaskBase(TaskBase&& other) noexcept : handle_(std::exchange(other.handle_, nullptr))
|
|
|
|
|
TaskBase(TaskBase&& other) MIJIN_NOEXCEPT : handle_(std::exchange(other.handle_, nullptr))
|
|
|
|
|
{}
|
|
|
|
|
~TaskBase() noexcept;
|
|
|
|
|
~TaskBase() MIJIN_NOEXCEPT;
|
|
|
|
|
public:
|
|
|
|
|
TaskBase& operator=(const TaskBase&) = delete;
|
|
|
|
|
TaskBase& operator=(TaskBase&& other) noexcept
|
|
|
|
|
TaskBase& operator=(TaskBase&& other) MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
if (handle_) {
|
|
|
|
|
handle_.destroy();
|
|
|
|
|
@@ -376,13 +377,13 @@ public:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]]
|
|
|
|
|
constexpr bool operator==(const TaskBase& other) const noexcept { return handle_ == other.handle_; }
|
|
|
|
|
constexpr bool operator==(const TaskBase& other) const MIJIN_NOEXCEPT { return handle_ == other.handle_; }
|
|
|
|
|
|
|
|
|
|
[[nodiscard]]
|
|
|
|
|
constexpr bool operator!=(const TaskBase& other) const noexcept { return handle_ != other.handle_; }
|
|
|
|
|
constexpr bool operator!=(const TaskBase& other) const MIJIN_NOEXCEPT { return handle_ != other.handle_; }
|
|
|
|
|
public:
|
|
|
|
|
[[nodiscard]]
|
|
|
|
|
constexpr TaskState<TResult>& state() noexcept
|
|
|
|
|
constexpr TaskState<TResult>& state() MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
return handle_.promise().state_;
|
|
|
|
|
}
|
|
|
|
|
@@ -392,19 +393,19 @@ public:
|
|
|
|
|
handle_.resume();
|
|
|
|
|
return state();
|
|
|
|
|
}
|
|
|
|
|
constexpr std::shared_ptr<TaskSharedState>& sharedState() noexcept
|
|
|
|
|
constexpr std::shared_ptr<TaskSharedState>& sharedState() MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
return handle_.promise().sharedState_;
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
[[nodiscard]]
|
|
|
|
|
constexpr handle_t handle() const noexcept { return handle_; }
|
|
|
|
|
constexpr handle_t handle() const MIJIN_NOEXCEPT { return handle_; }
|
|
|
|
|
[[nodiscard]]
|
|
|
|
|
constexpr TaskLoop* getLoop() noexcept
|
|
|
|
|
constexpr TaskLoop* getLoop() MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
return handle_.promise().loop_;
|
|
|
|
|
}
|
|
|
|
|
constexpr void setLoop(TaskLoop* loop) noexcept
|
|
|
|
|
constexpr void setLoop(TaskLoop* loop) MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
// MIJIN_ASSERT(handle_.promise().loop_ == nullptr
|
|
|
|
|
// || handle_.promise().loop_ == loop
|
|
|
|
|
@@ -423,14 +424,14 @@ class WrappedTaskBase
|
|
|
|
|
public:
|
|
|
|
|
virtual ~WrappedTaskBase() = default;
|
|
|
|
|
public:
|
|
|
|
|
virtual TaskStatus status() noexcept = 0;
|
|
|
|
|
virtual std::exception_ptr exception() noexcept = 0;
|
|
|
|
|
// virtual std::any result() noexcept = 0;
|
|
|
|
|
virtual TaskStatus status() MIJIN_NOEXCEPT = 0;
|
|
|
|
|
virtual std::exception_ptr exception() MIJIN_NOEXCEPT = 0;
|
|
|
|
|
// virtual std::any result() MIJIN_NOEXCEPT = 0;
|
|
|
|
|
virtual void resume() = 0;
|
|
|
|
|
virtual void* raw() noexcept = 0;
|
|
|
|
|
virtual std::coroutine_handle<> handle() noexcept = 0;
|
|
|
|
|
virtual void setLoop(TaskLoop* loop) noexcept = 0;
|
|
|
|
|
virtual std::shared_ptr<TaskSharedState>& sharedState() noexcept = 0;
|
|
|
|
|
virtual void* raw() MIJIN_NOEXCEPT = 0;
|
|
|
|
|
virtual std::coroutine_handle<> handle() MIJIN_NOEXCEPT = 0;
|
|
|
|
|
virtual void setLoop(TaskLoop* loop) MIJIN_NOEXCEPT = 0;
|
|
|
|
|
virtual std::shared_ptr<TaskSharedState>& sharedState() MIJIN_NOEXCEPT = 0;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] inline bool canResume() {
|
|
|
|
|
const TaskStatus stat = status();
|
|
|
|
|
@@ -444,16 +445,16 @@ class WrappedTask : public WrappedTaskBase
|
|
|
|
|
private:
|
|
|
|
|
TTask task_;
|
|
|
|
|
public:
|
|
|
|
|
constexpr explicit WrappedTask(TTask&& task) noexcept : task_(std::move(task)) {}
|
|
|
|
|
constexpr explicit WrappedTask(TTask&& task) MIJIN_NOEXCEPT : task_(std::move(task)) {}
|
|
|
|
|
WrappedTask(const WrappedTask&) = delete;
|
|
|
|
|
WrappedTask(WrappedTask&&) noexcept = default;
|
|
|
|
|
WrappedTask(WrappedTask&&) MIJIN_NOEXCEPT = default;
|
|
|
|
|
public:
|
|
|
|
|
WrappedTask& operator=(const WrappedTask&) = delete;
|
|
|
|
|
WrappedTask& operator=(WrappedTask&&) noexcept = default;
|
|
|
|
|
WrappedTask& operator=(WrappedTask&&) MIJIN_NOEXCEPT = default;
|
|
|
|
|
public:
|
|
|
|
|
TaskStatus status() noexcept override { return task_.state().status; }
|
|
|
|
|
std::exception_ptr exception() noexcept override { return task_.state().exception; }
|
|
|
|
|
// std::any result() noexcept override
|
|
|
|
|
TaskStatus status() MIJIN_NOEXCEPT override { return task_.state().status; }
|
|
|
|
|
std::exception_ptr exception() MIJIN_NOEXCEPT override { return task_.state().exception; }
|
|
|
|
|
// std::any result() MIJIN_NOEXCEPT
|
|
|
|
|
// {
|
|
|
|
|
// if constexpr (std::is_same_v<typename TTask::result_t, void>) {
|
|
|
|
|
// return {};
|
|
|
|
|
@@ -463,14 +464,14 @@ public:
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
void resume() override { task_.resume(); }
|
|
|
|
|
void* raw() noexcept override { return &task_; }
|
|
|
|
|
std::coroutine_handle<> handle() noexcept override { return task_.handle(); }
|
|
|
|
|
void setLoop(TaskLoop* loop) noexcept override { task_.setLoop(loop); }
|
|
|
|
|
virtual std::shared_ptr<TaskSharedState>& sharedState() noexcept override { return task_.sharedState(); }
|
|
|
|
|
void* raw() MIJIN_NOEXCEPT override { return &task_; }
|
|
|
|
|
std::coroutine_handle<> handle() MIJIN_NOEXCEPT override { return task_.handle(); }
|
|
|
|
|
void setLoop(TaskLoop* loop) MIJIN_NOEXCEPT override { task_.setLoop(loop); }
|
|
|
|
|
virtual std::shared_ptr<TaskSharedState>& sharedState() MIJIN_NOEXCEPT override { return task_.sharedState(); }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename TTask>
|
|
|
|
|
std::unique_ptr<WrappedTask<TTask>> wrapTask(TTask&& task) noexcept
|
|
|
|
|
std::unique_ptr<WrappedTask<TTask>> wrapTask(TTask&& task) MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
return std::make_unique<WrappedTask<TTask>>(std::forward<TTask>(task));
|
|
|
|
|
}
|
|
|
|
|
@@ -499,29 +500,29 @@ protected:
|
|
|
|
|
|
|
|
|
|
exception_handler_t uncaughtExceptionHandler_;
|
|
|
|
|
public:
|
|
|
|
|
TaskLoop() = default;
|
|
|
|
|
TaskLoop() MIJIN_NOEXCEPT = default;
|
|
|
|
|
TaskLoop(const TaskLoop&) = delete;
|
|
|
|
|
TaskLoop(TaskLoop&&) = delete;
|
|
|
|
|
virtual ~TaskLoop() = default;
|
|
|
|
|
virtual ~TaskLoop() MIJIN_NOEXCEPT = default;
|
|
|
|
|
|
|
|
|
|
TaskLoop& operator=(const TaskLoop&) = delete;
|
|
|
|
|
TaskLoop& operator=(TaskLoop&&) = delete;
|
|
|
|
|
|
|
|
|
|
void setUncaughtExceptionHandler(exception_handler_t handler) noexcept { uncaughtExceptionHandler_ = std::move(handler); }
|
|
|
|
|
void setUncaughtExceptionHandler(exception_handler_t handler) MIJIN_NOEXCEPT { uncaughtExceptionHandler_ = std::move(handler); }
|
|
|
|
|
|
|
|
|
|
template<typename TResult>
|
|
|
|
|
inline FuturePtr<TResult> addTask(TaskBase<TResult> task, TaskHandle* outHandle = nullptr) noexcept;
|
|
|
|
|
inline FuturePtr<TResult> addTask(TaskBase<TResult> task, TaskHandle* outHandle = nullptr) MIJIN_NOEXCEPT;
|
|
|
|
|
|
|
|
|
|
virtual void transferCurrentTask(TaskLoop& otherLoop) noexcept = 0;
|
|
|
|
|
virtual void addStoredTask(StoredTask&& storedTask) noexcept = 0;
|
|
|
|
|
virtual void transferCurrentTask(TaskLoop& otherLoop) MIJIN_NOEXCEPT = 0;
|
|
|
|
|
virtual void addStoredTask(StoredTask&& storedTask) MIJIN_NOEXCEPT = 0;
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] static TaskLoop& current() noexcept;
|
|
|
|
|
[[nodiscard]] static TaskLoop& current() MIJIN_NOEXCEPT;
|
|
|
|
|
protected:
|
|
|
|
|
inline TaskStatus tickTask(StoredTask& task);
|
|
|
|
|
protected:
|
|
|
|
|
static inline TaskLoop*& currentLoopStorage() noexcept;
|
|
|
|
|
static inline TaskLoop*& currentLoopStorage() MIJIN_NOEXCEPT;
|
|
|
|
|
template<typename TResult>
|
|
|
|
|
static inline void setFutureHelper(StoredTask& storedTask) noexcept;
|
|
|
|
|
static inline void setFutureHelper(StoredTask& storedTask) MIJIN_NOEXCEPT;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename TResult = void>
|
|
|
|
|
@@ -537,17 +538,17 @@ private:
|
|
|
|
|
std::thread::id threadId_;
|
|
|
|
|
|
|
|
|
|
public: // TaskLoop implementation
|
|
|
|
|
void transferCurrentTask(TaskLoop& otherLoop) noexcept override;
|
|
|
|
|
void addStoredTask(StoredTask&& storedTask) noexcept override;
|
|
|
|
|
void transferCurrentTask(TaskLoop& otherLoop) MIJIN_NOEXCEPT override;
|
|
|
|
|
void addStoredTask(StoredTask&& storedTask) MIJIN_NOEXCEPT override;
|
|
|
|
|
|
|
|
|
|
public: // public interface
|
|
|
|
|
[[nodiscard]] constexpr bool empty() const noexcept { return tasks_.empty() && newTasks_.empty(); }
|
|
|
|
|
[[nodiscard]] constexpr std::size_t getNumTasks() const noexcept { return tasks_.size() + newTasks_.size(); }
|
|
|
|
|
[[nodiscard]] std::size_t getActiveTasks() const noexcept;
|
|
|
|
|
[[nodiscard]] constexpr bool empty() const MIJIN_NOEXCEPT { return tasks_.empty() && newTasks_.empty(); }
|
|
|
|
|
[[nodiscard]] constexpr std::size_t getNumTasks() const MIJIN_NOEXCEPT { return tasks_.size() + newTasks_.size(); }
|
|
|
|
|
[[nodiscard]] std::size_t getActiveTasks() const MIJIN_NOEXCEPT;
|
|
|
|
|
inline CanContinue tick();
|
|
|
|
|
inline void runUntilDone(IgnoreWaiting ignoreWaiting = IgnoreWaiting::NO);
|
|
|
|
|
inline void cancelAllTasks() noexcept;
|
|
|
|
|
[[nodiscard]] inline std::vector<TaskHandle> getAllTasks() const noexcept;
|
|
|
|
|
inline void cancelAllTasks() MIJIN_NOEXCEPT;
|
|
|
|
|
[[nodiscard]] inline std::vector<TaskHandle> getAllTasks() const MIJIN_NOEXCEPT;
|
|
|
|
|
private:
|
|
|
|
|
inline void assertCorrectThread() { MIJIN_ASSERT(threadId_ == std::thread::id() || threadId_ == std::this_thread::get_id(), "Unsafe to TaskLoop from different thread!"); }
|
|
|
|
|
};
|
|
|
|
|
@@ -563,8 +564,8 @@ private:
|
|
|
|
|
std::vector<std::jthread> workerThreads_;
|
|
|
|
|
|
|
|
|
|
public: // TaskLoop implementation
|
|
|
|
|
void transferCurrentTask(TaskLoop& otherLoop) noexcept override;
|
|
|
|
|
void addStoredTask(StoredTask&& storedTask) noexcept override;
|
|
|
|
|
void transferCurrentTask(TaskLoop& otherLoop) MIJIN_NOEXCEPT override;
|
|
|
|
|
void addStoredTask(StoredTask&& storedTask) MIJIN_NOEXCEPT override;
|
|
|
|
|
|
|
|
|
|
public: // public interface
|
|
|
|
|
void start(std::size_t numWorkerThreads);
|
|
|
|
|
@@ -591,7 +592,7 @@ inline void throwIfCancelled()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TaskHandle::cancel() const noexcept
|
|
|
|
|
void TaskHandle::cancel() const MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
if (std::shared_ptr<TaskSharedState> state = state_.lock())
|
|
|
|
|
{
|
|
|
|
|
@@ -601,7 +602,7 @@ void TaskHandle::cancel() const noexcept
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if MIJIN_COROUTINE_ENABLE_DEBUG_INFO
|
|
|
|
|
Optional<Stacktrace> TaskHandle::getCreationStack() const noexcept
|
|
|
|
|
Optional<Stacktrace> TaskHandle::getCreationStack() const MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
if (std::shared_ptr<TaskSharedState> state = state_.lock())
|
|
|
|
|
{
|
|
|
|
|
@@ -612,7 +613,7 @@ Optional<Stacktrace> TaskHandle::getCreationStack() const noexcept
|
|
|
|
|
#endif // MIJIN_COROUTINE_ENABLE_DEBUG_INFO
|
|
|
|
|
|
|
|
|
|
template<typename TResult>
|
|
|
|
|
TaskBase<TResult>::~TaskBase() noexcept
|
|
|
|
|
TaskBase<TResult>::~TaskBase() MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
if (handle_)
|
|
|
|
|
{
|
|
|
|
|
@@ -621,7 +622,7 @@ TaskBase<TResult>::~TaskBase() noexcept
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename TResult>
|
|
|
|
|
inline FuturePtr<TResult> TaskLoop::addTask(TaskBase<TResult> task, TaskHandle* outHandle) noexcept
|
|
|
|
|
inline FuturePtr<TResult> TaskLoop::addTask(TaskBase<TResult> task, TaskHandle* outHandle) MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
MIJIN_ASSERT(!task.getLoop(), "Attempting to add task that already has a loop!");
|
|
|
|
|
task.setLoop(this);
|
|
|
|
|
@@ -685,20 +686,20 @@ inline TaskStatus TaskLoop::tickTask(StoredTask& task)
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* static */ inline auto TaskLoop::current() noexcept -> TaskLoop&
|
|
|
|
|
/* static */ inline auto TaskLoop::current() MIJIN_NOEXCEPT -> TaskLoop&
|
|
|
|
|
{
|
|
|
|
|
MIJIN_ASSERT(currentLoopStorage() != nullptr, "Attempting to fetch current loop while no coroutine is running!");
|
|
|
|
|
return *currentLoopStorage();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* static */ auto TaskLoop::currentLoopStorage() noexcept -> TaskLoop*&
|
|
|
|
|
/* static */ auto TaskLoop::currentLoopStorage() MIJIN_NOEXCEPT -> TaskLoop*&
|
|
|
|
|
{
|
|
|
|
|
static thread_local TaskLoop* storage = nullptr;
|
|
|
|
|
return storage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename TResult>
|
|
|
|
|
/* static */ inline void TaskLoop::setFutureHelper(StoredTask& storedTask) noexcept
|
|
|
|
|
/* static */ inline void TaskLoop::setFutureHelper(StoredTask& storedTask) MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
TaskBase<TResult>& task = *static_cast<TaskBase<TResult>*>(storedTask.task->raw());
|
|
|
|
|
auto future = std::any_cast<FuturePtr<TResult>>(storedTask.resultData);
|
|
|
|
|
@@ -801,7 +802,7 @@ inline void SimpleTaskLoop::runUntilDone(IgnoreWaiting ignoreWaiting)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void SimpleTaskLoop::cancelAllTasks() noexcept
|
|
|
|
|
inline void SimpleTaskLoop::cancelAllTasks() MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
for (StoredTask& task : mijin::chain(tasks_, newTasks_))
|
|
|
|
|
{
|
|
|
|
|
@@ -814,7 +815,7 @@ inline void SimpleTaskLoop::cancelAllTasks() noexcept
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline std::vector<TaskHandle> SimpleTaskLoop::getAllTasks() const noexcept
|
|
|
|
|
inline std::vector<TaskHandle> SimpleTaskLoop::getAllTasks() const MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
std::vector<TaskHandle> result;
|
|
|
|
|
for (const StoredTask& task : mijin::chain(tasks_, newTasks_))
|
|
|
|
|
@@ -848,7 +849,7 @@ Task<> c_allDone(const TCollection<FuturePtr<TType>, TTemplateArgs...>& futures)
|
|
|
|
|
} while (!allDone);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[nodiscard]] inline TaskHandle getCurrentTask() noexcept
|
|
|
|
|
[[nodiscard]] inline TaskHandle getCurrentTask() MIJIN_NOEXCEPT
|
|
|
|
|
{
|
|
|
|
|
MIJIN_ASSERT(impl::gCurrentTask != nullptr, "Attempt to call getCurrentTask() outside of task.");
|
|
|
|
|
return TaskHandle(impl::gCurrentTask->task->sharedState());
|
|
|
|
|
|