Skip to content

Commit

Permalink
f
Browse files Browse the repository at this point in the history
  • Loading branch information
etorth committed Jan 18, 2025
1 parent d1e7849 commit 62ef5cf
Show file tree
Hide file tree
Showing 41 changed files with 384 additions and 505 deletions.
279 changes: 123 additions & 156 deletions common/src/corof.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#pragma once
#include <any>
#include <optional>
#include <coroutine>
#include <exception>
Expand All @@ -8,82 +7,124 @@

namespace corof
{
template<typename T> class eval_awaiter;
class [[nodiscard]] eval_poller
namespace _details
{
private:
class eval_poller_promise;
template<typename T> friend class eval_awaiter;
struct base_promise
{
base_promise *inner_promise = nullptr;
base_promise *outer_promise = nullptr;

public:
using promise_type = eval_poller_promise;
using handle_type = std::coroutine_handle<promise_type>;
virtual ~base_promise() = default;
virtual std::coroutine_handle<> get_handle() = 0;
};

private:
class eval_poller_promise final
struct eval_poller_base_promise: public base_promise
{
std::exception_ptr exceptr = nullptr;
auto initial_suspend() noexcept
{
// hiden its definition and expose by aliasing to promise_type
// this type is for compiler, user should never instantiate an eval_poller_promise object
return std::suspend_always{};
}

private:
friend class eval_poller;
template<typename T> friend class eval_awaiter;
auto final_suspend() noexcept
{
return std::suspend_always{};
}

private:
std::any m_value;
void unhandled_exception()
{
exceptr = std::current_exception();
}

void rethrow_if_unhandled_exception()
{
if(exceptr){
std::rethrow_exception(exceptr);
}
}
};

struct eval_poller_promise_with_void: public _details::eval_poller_base_promise
{
void return_void(){}
};

template<typename T> struct eval_poller_promise_with_type: public _details::eval_poller_base_promise
{
T value;
void return_value(T t)
{
value = std::move(t);
}
};
}

template<typename T = void> class [[nodiscard]] eval_poller
{
public:
struct promise_type: public std::conditional_t<std::is_void_v<T>, _details::eval_poller_promise_with_void, _details::eval_poller_promise_with_type<T>>
{
std::coroutine_handle<> get_handle() override
{
return std::coroutine_handle<promise_type>::from_promise(*this);
}

eval_poller get_return_object()
{
return eval_poller{std::coroutine_handle<promise_type>::from_promise(*this)};
}
};

private:
class [[nodiscard]] awaiter
{
private:
handle_type m_inner_handle;
handle_type m_outer_handle;
friend class eval_poller;

private:
std::exception_ptr m_exception = nullptr;
std::coroutine_handle<eval_poller::promise_type> m_handle;

private:
template<typename T> T &get_ref()
{
return std::any_cast<T &>(m_value);
}
explicit awaiter(std::coroutine_handle<eval_poller::promise_type> handle)
: m_handle(handle)
{}

public:
auto initial_suspend()
{
return std::suspend_always{};
}

auto final_suspend() noexcept
{
return std::suspend_always{};
}

template<typename T> void return_value(T t)
{
m_value = std::move(t);
}
awaiter ( awaiter &&) = delete;
awaiter (const awaiter &) = delete;
awaiter & operator = ( awaiter &&) = delete;
awaiter & operator = (const awaiter &) = delete;

eval_poller get_return_object()
public:
bool await_ready() noexcept
{
return {handle_type::from_promise(*this)};
return false;
}

void unhandled_exception()
public:
template<typename OuterPrimise> void await_suspend(std::coroutine_handle<OuterPrimise> h) noexcept
{
m_exception = std::current_exception();
/**/ h.promise().inner_promise = std::addressof(m_handle.promise());
m_handle.promise().outer_promise = std::addressof( h.promise());
}

void rethrow_if_unhandled_exception()
public:
auto await_resume()
{
if(m_exception){
std::rethrow_exception(m_exception);
if constexpr(std::is_void_v<T>){
return;
}
else{
return m_handle.promise().value;
}
}
};

private:
handle_type m_handle;
std::coroutine_handle<eval_poller::promise_type> m_handle;

public:
eval_poller(handle_type handle = nullptr)
explicit eval_poller(std::coroutine_handle<eval_poller::promise_type> handle = nullptr)
: m_handle(handle)
{}

Expand Down Expand Up @@ -122,116 +163,57 @@ namespace corof
bool poll()
{
fflassert(m_handle);
handle_type curr_handle = find_handle(m_handle);
if(curr_handle.done()){
if(!curr_handle.promise().m_outer_handle){
auto curr_promise = find_promise(std::addressof(m_handle.promise()));

if(curr_promise->get_handle().done()){
if(!curr_promise->outer_promise){
return true;
}

// jump out for one layer
// should I call destroy() for done handle?

const auto outer_handle = curr_handle.promise().m_outer_handle;
fflassert(!outer_handle.done());
auto outer_promise = curr_promise->outer_promise;

curr_handle = outer_handle;
curr_handle.promise().m_inner_handle = nullptr;
curr_promise = outer_promise;
curr_promise->inner_promise = nullptr;
}

// resume only once and return immediately
// after resume curr_handle can be in done state, next call to poll should unlink it

curr_handle.resume();
curr_promise->get_handle().resume();
return m_handle.done();
}

private:
static inline handle_type find_handle(handle_type start_handle)
static inline _details::base_promise *find_promise(_details::base_promise *promise)
{
fflassert(start_handle);
auto curr_handle = start_handle;
auto next_handle = start_handle.promise().m_inner_handle;
auto curr_promise = promise;
auto next_promise = promise->inner_promise;

while(curr_handle && next_handle){
curr_handle = next_handle;
next_handle = next_handle.promise().m_inner_handle;
while(curr_promise && next_promise){
curr_promise = next_promise;
next_promise = next_promise->inner_promise;
}
return curr_handle;
return curr_promise;
}

public:
template<typename T> decltype(auto) sync_eval();
template<typename T> [[nodiscard]] eval_awaiter<T> to_awaiter();
};

template<typename T> class [[nodiscard]] eval_awaiter
{
private:
friend class eval_poller;

private:
eval_poller::handle_type m_eval_handle;

private:
explicit eval_awaiter(eval_poller poller)
{
std::swap(m_eval_handle, poller.m_handle);
fflassert(m_eval_handle);
}

public:
eval_awaiter(eval_awaiter && other)
{
std::swap(m_eval_handle, other.m_eval_handle);
fflassert(m_eval_handle);
}

public:
eval_awaiter (const eval_awaiter &) = delete;
eval_awaiter & operator = (const eval_awaiter &) = delete;

public:
~eval_awaiter()
decltype(auto) sync_eval()
{
if(m_eval_handle){
m_eval_handle.destroy();
while(!poll()){
continue;
}
return awaiter(m_handle).await_resume();
}

public:
bool await_ready() noexcept
{
return false;
}

public:
bool await_suspend(eval_poller::handle_type handle) noexcept
{
/* */ handle.promise().m_inner_handle = m_eval_handle;
m_eval_handle.promise().m_outer_handle = handle;
return true;
}

public:
decltype(auto) await_resume()
awaiter operator co_await()
{
return m_eval_handle.promise().get_ref<T>();
return awaiter(m_handle);
}
};

template<typename T> decltype(auto) eval_poller::sync_eval()
{
while(!poll()){
continue;
}
return to_awaiter<T>().await_resume();
}

template<typename T> [[nodiscard]] eval_awaiter<T> eval_poller::to_awaiter()
{
fflassert(valid());
return eval_awaiter<T>(std::move(*this));
}
}

namespace corof
Expand All @@ -258,45 +240,30 @@ namespace corof
public:
auto operator co_await() noexcept
{
const auto fnwait = +[](corof::async_variable<T> *p) -> corof::eval_poller
return [](corof::async_variable<T> *p) -> corof::eval_poller<T>
{
while(!p->m_var.has_value()){
co_await std::suspend_always{};
}
co_return p->m_var.value();
};
return fnwait(this). template to_awaiter<T>();
}(this).operator co_await();
}
};

inline auto async_wait(uint64_t msec) noexcept
inline corof::eval_poller<size_t> async_wait(uint64_t msec)
{
const auto fnwait = +[](uint64_t msec) -> corof::eval_poller
{
size_t count = 0;
if(msec == 0){
size_t count = 0;
if(msec == 0){
co_await std::suspend_always{};
count++;
}
else{
hres_timer timer;
while(timer.diff_msec() < msec){
co_await std::suspend_always{};
count++;
}
else{
hres_timer timer;
while(timer.diff_msec() < msec){
co_await std::suspend_always{};
count++;
}
}
co_return count;
};
return fnwait(msec).to_awaiter<size_t>();
}

template<typename T> inline auto delay_value(uint64_t msec, T t) // how about variadic template argument
{
const auto fnwait = +[](uint64_t msec, T t) -> corof::eval_poller
{
co_await corof::async_wait(msec);
co_return t;
};
return fnwait(msec, std::move(t)). template to_awaiter<T>();
}
co_return count;
}
}
4 changes: 2 additions & 2 deletions server/src/monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ void Monster::trackAttackUID(uint64_t targetUID, std::function<void()> onOK, std
}, onError);
}

corof::eval_poller Monster::updateCoroFunc()
corof::eval_poller<> Monster::updateCoroFunc()
{
uint64_t targetUID = 0;
hres_timer targetActiveTimer;
Expand Down Expand Up @@ -506,7 +506,7 @@ corof::eval_poller Monster::updateCoroFunc()
}

goDie();
co_return true;
co_return;
}

bool Monster::update()
Expand Down
Loading

0 comments on commit 62ef5cf

Please sign in to comment.