parent
689bb150c6
commit
f668ff6b7a
@ -0,0 +1,97 @@ |
||||
#include <coroutine> |
||||
#include <cstdint> |
||||
#include <exception> |
||||
#include <fmt/core.h> |
||||
|
||||
|
||||
template<typename T> |
||||
struct Generator { |
||||
struct promise_type; |
||||
using handle_type = std::coroutine_handle<promise_type>; |
||||
|
||||
struct promise_type { |
||||
T value_; |
||||
std::exception_ptr exception_; |
||||
|
||||
Generator get_return_object() { |
||||
return Generator(handle_type::from_promise(*this)); |
||||
} |
||||
std::suspend_always initial_suspend() { return {}; } |
||||
std::suspend_always final_suspend() noexcept { return {}; } |
||||
void unhandled_exception() { exception_ = std::current_exception(); } |
||||
|
||||
template<std::convertible_to<T> From> |
||||
std::suspend_always yield_value(From&& from) { |
||||
value_ = std::forward<From>(from); |
||||
return {}; |
||||
} |
||||
void return_void() {} |
||||
}; |
||||
|
||||
handle_type h_; |
||||
|
||||
Generator(handle_type h) : h_(h) {} |
||||
~Generator() { h_.destroy(); } |
||||
explicit operator bool() { |
||||
fill(); |
||||
return !h_.done(); |
||||
} |
||||
|
||||
T operator()() { |
||||
fill(); |
||||
full_ = false; |
||||
return std::move(h_.promise().value_); |
||||
} |
||||
|
||||
private: |
||||
bool full_ = false; |
||||
|
||||
void fill() { |
||||
if(!full_) { |
||||
h_(); |
||||
if(h_.promise().exception_) { |
||||
std::rethrow_exception(h_.promise().exception_); |
||||
} |
||||
|
||||
full_ = true; |
||||
} |
||||
} |
||||
}; |
||||
|
||||
Generator<std::uint64_t> |
||||
fib(unsigned n) { |
||||
if(n == 0) co_return; |
||||
if(n > 94) { |
||||
throw std::runtime_error("Too big"); |
||||
} |
||||
|
||||
if(n == 1) co_return; |
||||
|
||||
co_yield 1; |
||||
|
||||
if(n == 2) co_return; |
||||
|
||||
std::uint64_t a = 0; |
||||
std::uint64_t b = 1; |
||||
for(unsigned i = 2; i < n; ++i) { |
||||
std::uint64_t s = a + b; |
||||
co_yield s; |
||||
a = b; |
||||
b = s; |
||||
} |
||||
} |
||||
|
||||
int main() { |
||||
try { |
||||
auto gen = fib(50); |
||||
for(int j = 0; gen; ++j) { |
||||
fmt::println("fib({})={}", j, gen()); |
||||
} |
||||
} catch(const std::exception& ex) { |
||||
fmt::println("Exception: {}", ex.what()); |
||||
} catch(...) { |
||||
fmt::println("Unknown exception"); |
||||
} |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,4 @@ |
||||
[ |
||||
{"test": 0}, |
||||
{"test": 1} |
||||
] |
Loading…
Reference in new issue