type inspection support on coroutines (with context as common base type)
parent
75e4ac1cb7
commit
959f319318
|
@ -14,6 +14,22 @@ int main() {
|
|||
for (int i: generator<int>{f}) {
|
||||
writefln("generated: %s", i);
|
||||
}
|
||||
|
||||
generator<int> x{f};
|
||||
/* coroutine_context exists as a base type for any coroutine */
|
||||
coroutine_context &ctx = x;
|
||||
|
||||
writefln(
|
||||
"generator is coroutine<int()>: %s",
|
||||
bool(ctx.coroutine<coroutine<int()>>())
|
||||
);
|
||||
writefln(
|
||||
"generator is generator<int>: %s",
|
||||
bool(ctx.coroutine<generator<int>>())
|
||||
);
|
||||
|
||||
generator<int> &gr = *ctx.coroutine<generator<int>>();
|
||||
writefln("value of cast back generator: %s", gr.value());
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -254,11 +254,11 @@ namespace detail {
|
|||
} /* namespace detail */
|
||||
|
||||
template<typename R, typename ...A>
|
||||
struct coroutine<R(A...)>: detail::coroutine_context {
|
||||
struct coroutine<R(A...)>: coroutine_context {
|
||||
private:
|
||||
using base_t = detail::coroutine_context;
|
||||
using base_t = coroutine_context;
|
||||
/* necessary so that context callback can access privates */
|
||||
friend struct detail::coroutine_context;
|
||||
friend struct coroutine_context;
|
||||
|
||||
template<typename RR, typename ...AA>
|
||||
struct yielder {
|
||||
|
@ -389,6 +389,20 @@ public:
|
|||
base_t::swap(other);
|
||||
}
|
||||
|
||||
std::type_info const &target_type() const {
|
||||
return p_stor.p_func.target_type();
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
F *target() { return p_stor.p_func.target(); }
|
||||
|
||||
template<typename F>
|
||||
F const *target() const { return p_stor.p_func.target(); }
|
||||
|
||||
std::type_info const &coroutine_type() const {
|
||||
return typeid(coroutine);
|
||||
}
|
||||
|
||||
private:
|
||||
void resume_call() {
|
||||
p_stor.call_helper(*this);
|
||||
|
@ -409,10 +423,10 @@ namespace detail {
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
struct generator: detail::coroutine_context {
|
||||
struct generator: coroutine_context {
|
||||
private:
|
||||
using base_t = detail::coroutine_context;
|
||||
friend struct detail::coroutine_context;
|
||||
using base_t = coroutine_context;
|
||||
friend struct coroutine_context;
|
||||
|
||||
template<typename U>
|
||||
struct yielder {
|
||||
|
@ -514,7 +528,7 @@ public:
|
|||
if (this->is_dead()) {
|
||||
throw coroutine_error{"dead generator"};
|
||||
}
|
||||
detail::coroutine_context::call();
|
||||
coroutine_context::call();
|
||||
}
|
||||
|
||||
T &value() {
|
||||
|
@ -545,7 +559,21 @@ public:
|
|||
using std::swap;
|
||||
swap(p_func, other.p_func);
|
||||
swap(p_result, other.p_result);
|
||||
detail::coroutine_context::swap(other);
|
||||
coroutine_context::swap(other);
|
||||
}
|
||||
|
||||
std::type_info const &target_type() const {
|
||||
return p_func.target_type();
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
F *target() { return p_func.target(); }
|
||||
|
||||
template<typename F>
|
||||
F const *target() const { return p_func.target(); }
|
||||
|
||||
std::type_info const &coroutine_type() const {
|
||||
return typeid(generator);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <exception>
|
||||
#include <utility>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "ostd/types.hh"
|
||||
#include "ostd/platform.hh"
|
||||
|
@ -16,30 +17,50 @@
|
|||
namespace ostd {
|
||||
namespace detail {
|
||||
|
||||
/* from boost.fcontext */
|
||||
using fcontext_t = void *;
|
||||
/* from boost.fcontext */
|
||||
using fcontext_t = void *;
|
||||
|
||||
struct transfer_t {
|
||||
fcontext_t ctx;
|
||||
void *data;
|
||||
};
|
||||
struct transfer_t {
|
||||
fcontext_t ctx;
|
||||
void *data;
|
||||
};
|
||||
|
||||
extern "C" OSTD_EXPORT
|
||||
transfer_t OSTD_CDECL ostd_jump_fcontext(
|
||||
fcontext_t const to, void *vp
|
||||
);
|
||||
extern "C" OSTD_EXPORT
|
||||
transfer_t OSTD_CDECL ostd_jump_fcontext(
|
||||
fcontext_t const to, void *vp
|
||||
);
|
||||
|
||||
extern "C" OSTD_EXPORT
|
||||
fcontext_t OSTD_CDECL ostd_make_fcontext(
|
||||
void *sp, size_t size, void (*fn)(transfer_t)
|
||||
);
|
||||
extern "C" OSTD_EXPORT
|
||||
fcontext_t OSTD_CDECL ostd_make_fcontext(
|
||||
void *sp, size_t size, void (*fn)(transfer_t)
|
||||
);
|
||||
|
||||
extern "C" OSTD_EXPORT
|
||||
transfer_t OSTD_CDECL ostd_ontop_fcontext(
|
||||
fcontext_t const to, void *vp, transfer_t (*fn)(transfer_t)
|
||||
);
|
||||
extern "C" OSTD_EXPORT
|
||||
transfer_t OSTD_CDECL ostd_ontop_fcontext(
|
||||
fcontext_t const to, void *vp, transfer_t (*fn)(transfer_t)
|
||||
);
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
struct coroutine_context {
|
||||
virtual std::type_info const &coroutine_type() const = 0;
|
||||
|
||||
template<typename T>
|
||||
T *coroutine() {
|
||||
if (coroutine_type() == typeid(T)) {
|
||||
return reinterpret_cast<T *>(this);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T const *coroutine() const {
|
||||
if (coroutine_type() == typeid(T)) {
|
||||
return reinterpret_cast<T const *>(this);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
coroutine_context() {}
|
||||
~coroutine_context() {
|
||||
|
@ -71,12 +92,12 @@ protected:
|
|||
}
|
||||
|
||||
void coro_jump() {
|
||||
p_coro = ostd_jump_fcontext(p_coro, this).ctx;
|
||||
p_coro = detail::ostd_jump_fcontext(p_coro, this).ctx;
|
||||
}
|
||||
|
||||
void yield_jump() {
|
||||
p_state = state::HOLD;
|
||||
p_orig = ostd_jump_fcontext(p_orig, nullptr).ctx;
|
||||
p_orig = detail::ostd_jump_fcontext(p_orig, nullptr).ctx;
|
||||
}
|
||||
|
||||
bool is_hold() const {
|
||||
|
@ -108,7 +129,7 @@ protected:
|
|||
size_t asize = p_stack.size -
|
||||
(static_cast<byte *>(p_stack.ptr) - static_cast<byte *>(sp));
|
||||
|
||||
p_coro = ostd_make_fcontext(sp, asize, &context_call<C, SA>);
|
||||
p_coro = detail::ostd_make_fcontext(sp, asize, &context_call<C, SA>);
|
||||
new (sp) SA(std::move(sa));
|
||||
}
|
||||
|
||||
|
@ -131,8 +152,8 @@ private:
|
|||
}
|
||||
|
||||
struct forced_unwind {
|
||||
fcontext_t ctx;
|
||||
forced_unwind(fcontext_t c): ctx(c) {}
|
||||
detail::fcontext_t ctx;
|
||||
forced_unwind(detail::fcontext_t c): ctx(c) {}
|
||||
};
|
||||
|
||||
enum class state {
|
||||
|
@ -154,9 +175,9 @@ private:
|
|||
coro_jump();
|
||||
return;
|
||||
}
|
||||
ostd_ontop_fcontext(
|
||||
detail::ostd_ontop_fcontext(
|
||||
std::exchange(p_coro, nullptr), nullptr,
|
||||
[](transfer_t t) -> transfer_t {
|
||||
[](detail::transfer_t t) -> detail::transfer_t {
|
||||
throw forced_unwind{t.ctx};
|
||||
}
|
||||
);
|
||||
|
@ -165,15 +186,17 @@ private:
|
|||
template<typename SA>
|
||||
void finish() {
|
||||
set_dead();
|
||||
ostd_ontop_fcontext(p_orig, this, [](transfer_t t) -> transfer_t {
|
||||
auto &self = *(static_cast<coroutine_context *>(t.data));
|
||||
auto &sa = *(static_cast<SA *>(self.get_stack_ptr<SA>()));
|
||||
SA dsa{std::move(sa)};
|
||||
/* in case it holds any state that needs destroying */
|
||||
sa.~SA();
|
||||
dsa.deallocate(self.p_stack);
|
||||
return { nullptr, nullptr };
|
||||
});
|
||||
detail::ostd_ontop_fcontext(
|
||||
p_orig, this, [](detail::transfer_t t) -> detail::transfer_t {
|
||||
auto &self = *(static_cast<coroutine_context *>(t.data));
|
||||
auto &sa = *(static_cast<SA *>(self.get_stack_ptr<SA>()));
|
||||
SA dsa{std::move(sa)};
|
||||
/* in case it holds any state that needs destroying */
|
||||
sa.~SA();
|
||||
dsa.deallocate(self.p_stack);
|
||||
return { nullptr, nullptr };
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
template<typename C, typename SA>
|
||||
|
@ -188,7 +211,7 @@ private:
|
|||
}
|
||||
try {
|
||||
self.resume_call();
|
||||
} catch (detail::coroutine_context::forced_unwind v) {
|
||||
} catch (coroutine_context::forced_unwind v) {
|
||||
/* forced_unwind is unique */
|
||||
self.p_orig = v.ctx;
|
||||
} catch (...) {
|
||||
|
@ -201,13 +224,12 @@ release:
|
|||
}
|
||||
|
||||
stack_context p_stack;
|
||||
fcontext_t p_coro;
|
||||
fcontext_t p_orig;
|
||||
detail::fcontext_t p_coro;
|
||||
detail::fcontext_t p_orig;
|
||||
std::exception_ptr p_except;
|
||||
state p_state = state::HOLD;
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
} /* namespace ostd */
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue