From 4b1da89690ac6808621f2b71dde1a4e8c2670903 Mon Sep 17 00:00:00 2001 From: Grant Horner Date: Thu, 4 Dec 2025 22:12:32 -0500 Subject: [PATCH] refactor utils --- day1.cpp | 35 +++++++++++++++-------------------- day2.cpp | 27 ++++++++++----------------- day3.cpp | 21 +++++---------------- day4.cpp | 19 +++++++++---------- utils.h | 16 +++++++++++++++- 5 files changed, 54 insertions(+), 64 deletions(-) diff --git a/day1.cpp b/day1.cpp index 24b413b..0238ea3 100644 --- a/day1.cpp +++ b/day1.cpp @@ -5,11 +5,11 @@ #include #include #include -#include -#include #include "doctest.h" +#include "utils.h" +namespace day1 { enum Direction { L = 'L', R = 'R', @@ -27,15 +27,17 @@ Instruction parse_instruction(std::string_view line) { std::from_chars(&line[1], line.data() + line.size(), amount); return Instruction{direction, amount}; } +} template<> -struct std::formatter : std::formatter { - static auto format(const Instruction &i, std::format_context &ctx) { +struct std::formatter : std::formatter { + static auto format(const day1::Instruction &i, std::format_context &ctx) { return std::format_to(ctx.out(), "Instruction[direction: {}, amount: {}]", static_cast(i.direction), i.amount); } }; +namespace day1 { const std::string sample = "L68\n" "L30\n" @@ -79,9 +81,9 @@ uint32_t solve_first(const std::string &input) { uint32_t spins = 0; for (const auto instr: - std::views::split(input, '\n') - | std::views::transform([](auto s) { return std::string_view(s); }) - | std::views::filter([](const std::string_view s) { return !s.empty(); }) + std::views::split(std::string_view{input}, '\n') + | std::views::transform(utils::to_string_view) + | std::views::filter(utils::non_empty) | std::views::transform(parse_instruction) ) { if (spin(value, instr)) { @@ -96,11 +98,7 @@ uint32_t solve_first(const std::string &input) { TEST_SUITE_BEGIN("Day 1"); TEST_CASE("puzzle 1") { CHECK(solve_first(sample) == 3); - std::ifstream input("day1input.txt"); - CHECK(input.is_open()); - std::stringstream buffer; - buffer << input.rdbuf(); - CHECK(solve_first(buffer.str()) == 1158); + CHECK(solve_first(utils::read_file("day1input.txt")) == 1158); } uint32_t solve_second(const std::string &input) { @@ -108,9 +106,9 @@ uint32_t solve_second(const std::string &input) { uint32_t spins = 0; for (const auto instr: - std::views::split(input, '\n') - | std::views::transform([](auto s) { return std::string_view(s); }) - | std::views::filter([](const std::string_view s) { return !s.empty(); }) + std::views::split(std::string_view{input}, '\n') + | std::views::transform(utils::to_string_view) + | std::views::filter(utils::non_empty) | std::views::transform(parse_instruction) ) { spins += spin2(value, instr); @@ -122,11 +120,8 @@ uint32_t solve_second(const std::string &input) { TEST_CASE("puzzle 2") { CHECK(solve_second(sample) == 6); - std::ifstream input("day1input.txt"); - CHECK(input.is_open()); - std::stringstream buffer; - buffer << input.rdbuf(); - CHECK(solve_second(buffer.str()) == 6860); + CHECK(solve_second(utils::read_file("day1input.txt")) == 6860); } TEST_SUITE_END(); +} diff --git a/day2.cpp b/day2.cpp index c29e49b..769a90b 100644 --- a/day2.cpp +++ b/day2.cpp @@ -1,13 +1,12 @@ #include #include -#include -#include #include #include #include #include #include "doctest.h" +#include "utils.h" namespace day2 { const std::string sample = @@ -87,9 +86,9 @@ uint64_t sum_repetitions(const Range range) { uint64_t solve_first(std::string_view input) { uint64_t result = 0; for (const auto range: - std::views::split(input, ',') | std::views::transform([](auto s) { - return parse_range(std::string_view(s)); - })) { + std::views::split(input, ',') + | std::views::transform(utils::to_string_view) + | std::views::transform(parse_range)) { result += sum_repetitions(range); } @@ -129,9 +128,9 @@ uint64_t solve_second(std::string_view input) { buf.reserve(100); uint64_t result = 0; for (const auto range: - std::views::split(input, ',') | std::views::transform([](auto s) { - return parse_range(std::string_view(s)); - })) { + std::views::split(input, ',') + | std::views::transform(utils::to_string_view) + | std::views::transform(parse_range)) { result += sum_repetitions_2(range, buf); buf.clear(); } @@ -152,10 +151,7 @@ TEST_CASE("Solve first sample") { } TEST_CASE("Solve first input") { - std::ifstream fs("day2input.txt"); - std::stringstream ss{}; - ss << fs.rdbuf(); - CHECK(solve_first(ss.str()) == 21898734247); + CHECK(solve_first(utils::read_file("day2input.txt")) == 21898734247); } TEST_CASE("Find divisor works") { @@ -184,11 +180,8 @@ TEST_CASE("Solves second sample") { TEST_CASE( "Solves second input" * doctest::skip(true) - ) { - std::ifstream fs("day2input.txt"); - std::stringstream ss{}; - ss << fs.rdbuf(); - CHECK(solve_second(ss.view()) == 28915664389); +) { + CHECK(solve_second(utils::read_file("day2input.txt")) == 28915664389); } TEST_SUITE_END(); diff --git a/day3.cpp b/day3.cpp index ffcc9b1..2c4a747 100644 --- a/day3.cpp +++ b/day3.cpp @@ -4,9 +4,8 @@ #include #include -#include -#include #include "doctest.h" +#include "utils.h" namespace day3 { const std::string sample = "987654321111111\n" @@ -16,12 +15,8 @@ const std::string sample = "987654321111111\n" auto split_into_banks(const std::string_view input) { return std::views::split(input, '\n') - | std::views::filter([](const auto &s) { - return !s.empty(); - }) - | std::views::transform([](const auto &x) { - return std::string_view(x); - }); + | std::views::transform(utils::to_string_view) + | std::views::filter(utils::non_empty); } uint64_t solve(const std::string_view input, uint8_t num_batteries) { @@ -58,10 +53,7 @@ TEST_CASE("solve first sample") { } TEST_CASE("solve first puzzle") { - std::ifstream input("day3input.txt"); - std::stringstream buf; - buf << input.rdbuf(); - CHECK(solve(buf.view(),2) == 17095); + CHECK(solve(utils::read_file("day3input.txt"),2) == 17095); } TEST_CASE("solve second sample") { @@ -69,10 +61,7 @@ TEST_CASE("solve second sample") { } TEST_CASE("solve second input") { - std::ifstream input("day3input.txt"); - std::stringstream buf; - buf << input.rdbuf(); - CHECK(solve(buf.view(), 12) == 168794698570517); + CHECK(solve(utils::read_file("day3input.txt"), 12) == 168794698570517); } TEST_SUITE_END(); diff --git a/day4.cpp b/day4.cpp index 15edfd5..ab54f3e 100644 --- a/day4.cpp +++ b/day4.cpp @@ -27,8 +27,8 @@ enum class Point : char { Empty = '.', }; -template -std::array get_surrounding(const std::vector &lines, size_t x, size_t y) noexcept { +template +std::array get_surrounding(const std::vector &lines, const size_t x, const size_t y) noexcept { std::array points = {}; size_t i = 0; for (int dy = -1; dy < 2; ++dy) { @@ -48,16 +48,15 @@ std::array get_surrounding(const std::vector &lines, size_t x, size_ uint32_t solve_first(const std::string_view input) noexcept { const auto lines = std::string_view{input} | std::views::split('\n') - | std::views::transform(to_string_view) - | std::views::filter([](const auto s) { return !s.empty(); }) + | std::views::transform(utils::to_string_view) + | std::views::filter(utils::non_empty) | std::ranges::to(); uint32_t accessible = 0; for (size_t y = 0; y < lines.size(); ++y) { for (size_t x = 0; x < lines[0].size(); ++x) { - const auto c = lines[y][x]; - if (c != '@') continue; + if (lines[y][x] != '@') continue; size_t num_paper = 0; for (const char p: get_surrounding(lines, x, y)) { if (p == '@') { @@ -77,7 +76,7 @@ uint32_t solve_first(const std::string_view input) noexcept { return accessible; } -template +template std::vector > remove_paper(const std::vector &lines) { std::vector > removable = {}; @@ -110,7 +109,7 @@ uint32_t solve_second(const std::string_view input) { | std::views::transform([](const auto r) { return std::string(r.data(), r.size()); }) - | std::views::filter([](const auto &s) { return !s.empty(); }) + | std::views::filter(utils::non_empty) | std::ranges::to(); bool removed = false; uint32_t total_removed = 0; @@ -136,7 +135,7 @@ TEST_CASE("solves first sample") { } TEST_CASE("solves first puzzle") { - CHECK(solve_first(read_file("day4input.txt")) == 1626); + CHECK(solve_first(utils::read_file("day4input.txt")) == 1626); } @@ -145,7 +144,7 @@ TEST_CASE("solves second sample") { } TEST_CASE("solves second puzzle") { - CHECK(solve_second(read_file("day4input.txt")) == 9173); + CHECK(solve_second(utils::read_file("day4input.txt")) == 9173); } TEST_SUITE_END(); diff --git a/utils.h b/utils.h index 10ed4cc..201a430 100644 --- a/utils.h +++ b/utils.h @@ -7,13 +7,27 @@ #include #include -constexpr std::string_view to_string_view(const std::ranges::subrange cs) { +namespace utils { + +template +concept StringLike = requires(const T &t) +{ + { std::string_view{t} } -> std::convertible_to; + { t.size() } -> std::convertible_to; +}; + +constexpr std::string_view to_string_view(const std::ranges::subrange& cs) { return std::string_view{cs.data(), cs.size()}; } +constexpr bool non_empty(const std::string_view sv) { + return !sv.empty(); +} + inline std::string read_file(std::string_view path) { std::ifstream input(path.data()); std::stringstream buffer; buffer << input.rdbuf(); return buffer.str(); } +}