diff --git a/2022/14.cpp b/2022/14.cpp index bca1afd..b6fb0ef 100644 --- a/2022/14.cpp +++ b/2022/14.cpp @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -7,14 +8,6 @@ #include #include -#if __has_include() -#include -namespace co = std; -#elif __has_include() -#include -namespace co = std::experimental; -#endif - #include #include #include @@ -23,6 +16,7 @@ namespace co = std::experimental; #include #include +#include namespace { @@ -103,35 +97,7 @@ auto FindBottom(Input const& input) -> std::int64_t return result; } -struct CoordPromise; - -struct CoordGenerator : co::coroutine_handle { - using promise_type = struct CoordPromise; - auto next() -> std::optional; -}; - -struct CoordPromise { - std::optional output; - std::exception_ptr e; - - auto get_return_object() -> CoordGenerator { return { CoordGenerator::from_promise(*this)}; } - auto initial_suspend() noexcept -> co::suspend_always { return {}; } - auto final_suspend() noexcept -> co::suspend_never { return {}; } - auto return_void() { output.reset(); } - auto yield_value(aocpp::Coord coord) -> co::suspend_always { output = coord; return {}; } - auto unhandled_exception() -> void { e = std::current_exception(); } -}; - -auto CoordGenerator::next() -> std::optional { - resume(); - auto & p = promise(); - if (p.e) { - std::rethrow_exception(p.e); - } - return p.output; -} - -auto SearchOrder(std::set & world, aocpp::Coord here) -> CoordGenerator +auto SearchOrder(std::set & world, aocpp::Coord here) -> aocpp::Generator { co_yield aocpp::Down(here); co_yield aocpp::Left(aocpp::Down(here)); @@ -143,15 +109,15 @@ auto Part1(std::int64_t bottom, std::set world) -> std::size_t { auto const starting_size = world.size(); - auto path = std::vector{}; + auto path = std::vector>{}; path.reserve(bottom - TOP.y); path.push_back(SearchOrder(world, TOP)); while (!path.empty()) { - if (auto next = path.back().next()) { + if (auto next = path.back()()) { if (!world.contains(*next)) { if (next->y == bottom) { - break; + return world.size() - starting_size; } path.push_back(SearchOrder(world, *next)); } @@ -160,19 +126,19 @@ auto Part1(std::int64_t bottom, std::set world) -> std::size_t } } - return world.size() - starting_size; + throw std::runtime_error{"No solution for part 1"}; } auto Part2(std::int64_t bottom, std::set world) -> std::size_t { auto const starting_size = world.size(); - auto path = std::vector{}; + auto path = std::vector>{}; path.reserve(2 + bottom - TOP.y); path.push_back(SearchOrder(world, TOP)); while (!path.empty()) { - if (auto next = path.back().next()) { + if (auto next = path.back()()) { if (next->y - 2 != bottom && !world.contains(*next)) { path.push_back(SearchOrder(world, *next)); } diff --git a/lib/include/aocpp/Generator.hpp b/lib/include/aocpp/Generator.hpp new file mode 100644 index 0000000..3348708 --- /dev/null +++ b/lib/include/aocpp/Generator.hpp @@ -0,0 +1,71 @@ +#ifndef AOCPP_GENERATOR_HPP_ +#define AOCPP_GENERATOR_HPP_ + +#include +#include +#include + +#if __has_include() +#include +namespace co = std; +#elif __has_include() +#include +namespace co = std::experimental; +#endif + +namespace aocpp { + +template +class Generator +{ +public: + struct promise_type; + +private: + using handle_type = co::coroutine_handle; + handle_type h_; + +public: + struct promise_type + { + std::optional value_; + std::exception_ptr exception_; + + Generator get_return_object() + { + return Generator{handle_type::from_promise(*this)}; + } + co::suspend_always initial_suspend() { return {}; } + co::suspend_always final_suspend() noexcept { return {}; } + void unhandled_exception() { exception_ = std::current_exception(); } + + template From> // C++20 concept + std::suspend_always yield_value(From&& from) + { + value_ = std::forward(from); // caching the result in promise + return {}; + } + void return_void() { value_.reset(); } + }; + + public: + Generator() noexcept = default; + Generator(handle_type h) : h_(h) {} + Generator(Generator && g) : h_{g.h_} { g.h_ = nullptr; }; + Generator(Generator const& g) = delete; + Generator & operator=(Generator && rhs) = delete; + Generator & operator=(Generator const& rhs) = delete; + ~Generator() { if (h_) h_.destroy(); } + std::optional operator()() + { + h_(); + if (h_.promise().exception_) { + std::rethrow_exception(h_.promise().exception_); + } + return std::move(h_.promise().value_); + } +}; + +} // namespace + +#endif // AOCPP_GENERATOR_HPP_