Created
November 18, 2018 18:13
-
-
Save RedBeard0531/0d3e56d72bf22dec9aa5be886b360c22 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template <typename T> | |
struct semi_lazy { | |
struct promise_type { | |
std::optional<T> val; | |
std::function<void()> defer; | |
suspend_never initial_suspend() { return {}; } | |
suspend_always final_suspend() { return {}; } | |
void return_value(T v) { | |
val.emplace(std::move(v)); | |
} | |
semi_lazy get_return_object() { | |
return semi_lazy(this); | |
} | |
void unhandled_exception() { | |
//throw; | |
} | |
template<typename U> | |
auto await_transform(lazy<U> sub) { | |
struct SubSub { | |
promise_type* p; | |
lazy<U> sub; | |
std::optional<decltype(sub.operator co_await())> awaitable; | |
bool await_ready() { return false; } | |
void await_suspend(coroutine_handle<> h) { | |
p->defer = [this, h] { | |
awaitable.emplace(sub.operator co_await()); | |
awaitable->await_suspend(h); | |
}; | |
} | |
U await_resume() { | |
return awaitable->await_resume(); | |
} | |
void operator=(SubSub&&) = delete; | |
}; | |
return SubSub{this, std::move(sub)}; | |
} | |
}; | |
auto operator co_await() { | |
struct Awaitable { | |
promise_type* p; | |
bool await_ready() { | |
return bool(p->val); | |
} | |
auto await_suspend(coroutine_handle<> h) { | |
p->defer(); | |
// TODO this assumes task<> completes syncronously when awaited. | |
// Good enough for prototype, but would need to actually stash | |
// the handles for a real impl. | |
coroutine_handle<promise_type>::from_promise(*p).resume(); | |
return false; | |
} | |
T&& await_resume() { | |
return std::move(*p->val); | |
} | |
}; | |
return Awaitable{p}; | |
} | |
semi_lazy(semi_lazy&& source) : p(std::exchange(source.p, nullptr)) {} | |
promise_type* p; | |
semi_lazy(promise_type* p) :p(p) {} | |
~semi_lazy() { | |
if (p) coroutine_handle<promise_type>::from_promise(*p).destroy(); | |
} | |
}; | |
struct Key{}; | |
struct Result{}; | |
std::optional<Result> cache_lookup(Key); | |
lazy<Result> fetch_to_cache(Key); | |
semi_lazy<Result> cached_fetch(Key k) { | |
if (auto r = cache_lookup(k)) | |
co_return *r; | |
co_return co_await fetch_to_cache(k); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment