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