Last active
December 8, 2020 20:47
-
-
Save paxbun/891da6c3b4a098eea94053126ccd599b to your computer and use it in GitHub Desktop.
C++20 coroutine example
This file contains hidden or 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
#include <coroutine> | |
#include <iostream> | |
#include <optional> | |
size_t buffer[22]; | |
struct my_generator | |
{ | |
struct promise_type | |
{ | |
int yielded_value = 0; | |
static void* operator new(size_t mem) noexcept | |
{ | |
std::cout << "operator new(" << mem << "): " << buffer << std::endl; | |
if (mem > sizeof buffer) return nullptr; | |
return buffer; | |
} | |
static void operator delete(void* block, size_t mem) noexcept {} | |
auto get_return_object() | |
{ | |
return handle_type::from_promise(*this); | |
} | |
static my_generator get_return_object_on_allocation_failure() | |
{ | |
std::cout << "get_return_object_on_allocation_failure" << std::endl; | |
return my_generator {}; | |
} | |
auto initial_suspend() | |
{ | |
return std::suspend_always {}; | |
} | |
auto final_suspend() noexcept | |
{ | |
return std::suspend_always {}; | |
} | |
void return_value(int i) | |
{ | |
yielded_value = i; | |
} | |
auto yield_value(int i) | |
{ | |
yielded_value = i; | |
return std::suspend_always {}; | |
} | |
void unhandled_exception() | |
{ | |
std::terminate(); | |
} | |
}; | |
using handle_type = std::coroutine_handle<promise_type>; | |
handle_type handle; | |
my_generator(std::nullptr_t = nullptr) {} | |
my_generator(handle_type handle) : handle { handle } {} | |
my_generator(const my_generator&) = delete; | |
my_generator(my_generator&&) = delete; | |
~my_generator() | |
{ | |
if (handle) handle.destroy(); | |
} | |
bool has_next() | |
{ | |
return handle && !handle.done(); | |
} | |
int next() | |
{ | |
if (!handle.done()) | |
{ | |
handle.resume(); | |
auto& promise = handle.promise(); | |
return promise.yielded_value; | |
} | |
throw std::runtime_error("generator is closed"); | |
} | |
}; | |
my_generator fibonacci() | |
{ | |
int small = 0; | |
int big = 1; | |
std::cout << &small << std::endl << &big << std::endl; | |
co_yield 0; | |
co_yield 1; | |
while (true) | |
{ | |
int new_value = small + big; | |
co_yield new_value; | |
small = big; | |
big = new_value; | |
} | |
co_return small + big; | |
} | |
my_generator power_of_two() | |
{ | |
int rtn = 1; | |
std::cout << &rtn << std::endl; | |
for (int i = 0; i < 10; ++i) | |
{ | |
co_yield rtn; | |
rtn *= 2; | |
} | |
co_return rtn; | |
} | |
int main() | |
{ | |
my_generator generator = power_of_two(); | |
while (generator.has_next()) std::cout << generator.next() << std::endl; | |
my_generator generator2 = fibonacci(); | |
for (int i = 0; i < 20 && generator2.has_next(); ++i) | |
std::cout << generator2.next() << std::endl; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment