extract generator code into library
This commit is contained in:
parent
4d884d7b1c
commit
9b4c881903
52
2022/14.cpp
52
2022/14.cpp
|
@ -1,5 +1,6 @@
|
||||||
#include <version>
|
#include <version>
|
||||||
|
|
||||||
|
#include <concepts>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
@ -7,14 +8,6 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#if __has_include(<coroutine>)
|
|
||||||
#include <coroutine>
|
|
||||||
namespace co = std;
|
|
||||||
#elif __has_include(<experimental/coroutine>)
|
|
||||||
#include <experimental/coroutine>
|
|
||||||
namespace co = std::experimental;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <boost/phoenix.hpp>
|
#include <boost/phoenix.hpp>
|
||||||
#include <boost/range/irange.hpp>
|
#include <boost/range/irange.hpp>
|
||||||
#include <boost/spirit/include/qi.hpp>
|
#include <boost/spirit/include/qi.hpp>
|
||||||
|
@ -23,6 +16,7 @@ namespace co = std::experimental;
|
||||||
|
|
||||||
#include <aocpp/Startup.hpp>
|
#include <aocpp/Startup.hpp>
|
||||||
#include <aocpp/Coord.hpp>
|
#include <aocpp/Coord.hpp>
|
||||||
|
#include <aocpp/Generator.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -103,35 +97,7 @@ auto FindBottom(Input const& input) -> std::int64_t
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CoordPromise;
|
auto SearchOrder(std::set<aocpp::Coord> & world, aocpp::Coord here) -> aocpp::Generator<aocpp::Coord>
|
||||||
|
|
||||||
struct CoordGenerator : co::coroutine_handle<CoordPromise> {
|
|
||||||
using promise_type = struct CoordPromise;
|
|
||||||
auto next() -> std::optional<aocpp::Coord>;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CoordPromise {
|
|
||||||
std::optional<aocpp::Coord> 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<aocpp::Coord> {
|
|
||||||
resume();
|
|
||||||
auto & p = promise();
|
|
||||||
if (p.e) {
|
|
||||||
std::rethrow_exception(p.e);
|
|
||||||
}
|
|
||||||
return p.output;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto SearchOrder(std::set<aocpp::Coord> & world, aocpp::Coord here) -> CoordGenerator
|
|
||||||
{
|
{
|
||||||
co_yield aocpp::Down(here);
|
co_yield aocpp::Down(here);
|
||||||
co_yield aocpp::Left(aocpp::Down(here));
|
co_yield aocpp::Left(aocpp::Down(here));
|
||||||
|
@ -143,15 +109,15 @@ auto Part1(std::int64_t bottom, std::set<aocpp::Coord> world) -> std::size_t
|
||||||
{
|
{
|
||||||
auto const starting_size = world.size();
|
auto const starting_size = world.size();
|
||||||
|
|
||||||
auto path = std::vector<CoordGenerator>{};
|
auto path = std::vector<aocpp::Generator<aocpp::Coord>>{};
|
||||||
path.reserve(bottom - TOP.y);
|
path.reserve(bottom - TOP.y);
|
||||||
path.push_back(SearchOrder(world, TOP));
|
path.push_back(SearchOrder(world, TOP));
|
||||||
|
|
||||||
while (!path.empty()) {
|
while (!path.empty()) {
|
||||||
if (auto next = path.back().next()) {
|
if (auto next = path.back()()) {
|
||||||
if (!world.contains(*next)) {
|
if (!world.contains(*next)) {
|
||||||
if (next->y == bottom) {
|
if (next->y == bottom) {
|
||||||
break;
|
return world.size() - starting_size;
|
||||||
}
|
}
|
||||||
path.push_back(SearchOrder(world, *next));
|
path.push_back(SearchOrder(world, *next));
|
||||||
}
|
}
|
||||||
|
@ -160,19 +126,19 @@ auto Part1(std::int64_t bottom, std::set<aocpp::Coord> 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<aocpp::Coord> world) -> std::size_t
|
auto Part2(std::int64_t bottom, std::set<aocpp::Coord> world) -> std::size_t
|
||||||
{
|
{
|
||||||
auto const starting_size = world.size();
|
auto const starting_size = world.size();
|
||||||
|
|
||||||
auto path = std::vector<CoordGenerator>{};
|
auto path = std::vector<aocpp::Generator<aocpp::Coord>>{};
|
||||||
path.reserve(2 + bottom - TOP.y);
|
path.reserve(2 + bottom - TOP.y);
|
||||||
path.push_back(SearchOrder(world, TOP));
|
path.push_back(SearchOrder(world, TOP));
|
||||||
|
|
||||||
while (!path.empty()) {
|
while (!path.empty()) {
|
||||||
if (auto next = path.back().next()) {
|
if (auto next = path.back()()) {
|
||||||
if (next->y - 2 != bottom && !world.contains(*next)) {
|
if (next->y - 2 != bottom && !world.contains(*next)) {
|
||||||
path.push_back(SearchOrder(world, *next));
|
path.push_back(SearchOrder(world, *next));
|
||||||
}
|
}
|
||||||
|
|
71
lib/include/aocpp/Generator.hpp
Normal file
71
lib/include/aocpp/Generator.hpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#ifndef AOCPP_GENERATOR_HPP_
|
||||||
|
#define AOCPP_GENERATOR_HPP_
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <optional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#if __has_include(<coroutine>)
|
||||||
|
#include <coroutine>
|
||||||
|
namespace co = std;
|
||||||
|
#elif __has_include(<experimental/coroutine>)
|
||||||
|
#include <experimental/coroutine>
|
||||||
|
namespace co = std::experimental;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace aocpp {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Generator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct promise_type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using handle_type = co::coroutine_handle<promise_type>;
|
||||||
|
handle_type h_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct promise_type
|
||||||
|
{
|
||||||
|
std::optional<T> 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 <std::convertible_to<T> From> // C++20 concept
|
||||||
|
std::suspend_always yield_value(From&& from)
|
||||||
|
{
|
||||||
|
value_ = std::forward<From>(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<T> operator()()
|
||||||
|
{
|
||||||
|
h_();
|
||||||
|
if (h_.promise().exception_) {
|
||||||
|
std::rethrow_exception(h_.promise().exception_);
|
||||||
|
}
|
||||||
|
return std::move(h_.promise().value_);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif // AOCPP_GENERATOR_HPP_
|
Loading…
Reference in New Issue
Block a user