Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

day 7 cleanup #23

Merged
merged 3 commits into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 2 additions & 57 deletions day_1/benchmark/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@
#include "../../shared/src/column_splitter.hpp"
#include "../../shared/src/parsing_rules.hpp"

static std::string createInput(size_t size) {
std::string input;
for (int i = 0; i < size; i++) {
input += std::to_string(rand() % size) + " " + std::to_string(rand() % size) + "\n";
}
return input;
}

static std::multiset<int64_t> createNewSet(size_t size) {
std::multiset<int64_t> newSet;
for (int i = 0; i < size; i++) {
Expand All @@ -39,7 +31,7 @@ BENCHMARK(BM_CalulculateDistance)
->Unit(benchmark::kMillisecond)
->UseRealTime()
->Threads(std::thread::hardware_concurrency())
->Iterations(10);
->Iterations(100);

static void BM_CalulculateSimilarity(benchmark::State & state) {
std::multiset<int64_t> leftList = createNewSet(10000);
Expand All @@ -54,53 +46,6 @@ BENCHMARK(BM_CalulculateSimilarity)
->Unit(benchmark::kMillisecond)
->UseRealTime()
->Threads(std::thread::hardware_concurrency())
->Iterations(20);

static void BM_ParseLinesInParrallel(benchmark::State & state) {
auto input = createInput(30000);

for (auto _ : state) {
state.PauseTiming();
auto result = aoc::splitter::columnbased::split<int64_t, 2>(input, aoc::parser::rules::parse_number<int64_t>,
std::execution::par_unseq);
state.ResumeTiming();

benchmark::DoNotOptimize(result);
benchmark::ClobberMemory();
}

state.SetItemsProcessed(state.iterations() * input.size());
}

BENCHMARK(BM_ParseLinesInParrallel)
->Unit(benchmark::kMillisecond)
->UseRealTime()
->Threads(std::thread::hardware_concurrency())
->Iterations(1);

static void BM_ParseLinesInSequence(benchmark::State & state) {
auto input = createInput(30000);
volatile size_t size = input.size();

for (auto _ : state) {
state.PauseTiming();
auto result = aoc::splitter::columnbased::split<int64_t, 2, std::multiset>(
input, aoc::parser::rules::parse_number<int64_t>, std::execution::seq);
state.ResumeTiming();
if (!result) {
state.SkipWithError("Parser error occurred");
break;
}
benchmark::DoNotOptimize(result);
benchmark::ClobberMemory();
}

state.SetItemsProcessed(state.iterations() * input.size());
}

BENCHMARK(BM_ParseLinesInSequence)
->Unit(benchmark::kMillisecond)
->Threads(std::thread::hardware_concurrency())
->Iterations(1);
->Iterations(100);

BENCHMARK_MAIN();
2 changes: 1 addition & 1 deletion day_1/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ auto main(int argc, char const ** argv) -> int {
}

auto tokens = aoc::splitter::columnbased::split<int64_t, 2, std::multiset>(
*input, aoc::parser::rules::parse_number<int64_t>, std::execution::par_unseq);
*input, aoc::parser::rules::parse_number<int64_t>, std::execution::par);
if (!tokens) [[unlikely]] {
std::println(stderr, "Failed to parse input: {}", tokens.error().message());
return aoc::EXIT_CODE_DATA_ERROR;
Expand Down
2 changes: 1 addition & 1 deletion day_2/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ auto main(int argc, char const ** argv) -> int {
}

std::expected<std::vector<std::vector<uint8_t>>, std::error_code> parsed = aoc::splitter::linebased::split<uint8_t>(
*input, aoc::parser::rules::parse_number<uint8_t>, std::execution::par_unseq);
*input, aoc::parser::rules::parse_number<uint8_t>, std::execution::par);
if (!parsed) [[unlikely]] {
std::println(stderr, "Failed to parse input: {}", parsed.error().message());
return aoc::EXIT_CODE_DATA_ERROR;
Expand Down
2 changes: 1 addition & 1 deletion day_5/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ auto main(int argc, char const ** argv) -> int {

std::expected<std::vector<std::vector<uint8_t>>, std::error_code> parsed_update_input =
aoc::splitter::linebased::split<uint8_t, std::vector>(updates_input, aoc::parser::rules::parse_number<uint8_t>,
std::execution::par_unseq, ',');
std::execution::par, ',');

if (!parsed_update_input) {
std::println(stderr, "Failed to parse updates: {}", parsed_update_input.error().message());
Expand Down
1 change: 0 additions & 1 deletion day_6/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
#include "../lib/grid_parser.hpp"
#include "../lib/puzzle_map.hpp"


auto main(int argc, char const ** argv) -> int {
std::expected<std::string, std::error_code> input = aoc::file_operations::read("input.txt");
if (!input) [[unlikely]] {
Expand Down
36 changes: 21 additions & 15 deletions day_7/lib/equation_operator.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <array>
#include <concepts>
#include <string_view>

#include "equation_result.hpp"
Expand All @@ -16,37 +17,42 @@ enum class operation_type {

/// Represents an operator that can be applied to equation results
/// @tparam T The numeric type used for calculations (defaults to size_t)
template <typename T = size_t> struct equation_operator_t {
template <typename T = size_t>
requires std::integral<T>
struct equation_operator_t {
operation_type type; ///< Type of the operation
std::string_view name; ///< String representation of the operator
equation_result<T> (*apply)(equation_result<T>, equation_result<T>); ///< Function implementing the operation
};
}; // namespace aoc::day_7

/// Available operators for type T
/// @tparam T The numeric type used for calculations
template <typename T = size_t>
requires std::integral<T>
inline constexpr equation_operator_t<T> equationOperators_t[] = {
{operation_type::add, " + ", [](equation_result<T> a, equation_result<T> b) { return a + b; }},
{operation_type::multiply, " * ", [](equation_result<T> a, equation_result<T> b) { return a * b; }},
{operation_type::concat, " || ", [](equation_result<T> a, equation_result<T> b) { return a | b; }}};

/// Size constant for basic operators (add, multiply)
/// @tparam T The numeric type used for calculations
template <typename T = size_t> inline constexpr size_t BASIC_OPERATORS_SIZE = 2;

/// Size constant for all operators (add, multiply, concat)
/// @tparam T The numeric type used for calculations
template <typename T = size_t> inline constexpr size_t ALL_OPERATORS_SIZE = 3;

/// Array type for storing operator pointers
/// @tparam T The numeric type used for calculations
template <typename T = size_t> using operator_array_t = std::array<equation_operator_t<T> const *, 3>;
template <typename T = size_t>
requires std::integral<T>
inline constexpr std::array<equation_operator_t<T> const *, 3> ALL_OPERATORS_T{
&equationOperators_t<T>[0], &equationOperators_t<T>[1], &equationOperators_t<T>[2]};

template <typename T = size_t>
inline constexpr operator_array_t<T> ALL_OPERATORS_T{&equationOperators_t<T>[0], &equationOperators_t<T>[1],
&equationOperators_t<T>[2]};
requires std::integral<T>
inline constexpr auto ALL_OPERATORS =
std::span<aoc::day_7::equation_operator_t<T> const * const, std::size(aoc::day_7::ALL_OPERATORS_T<T>)>{
aoc::day_7::ALL_OPERATORS_T<T>.data(), std::size(aoc::day_7::ALL_OPERATORS_T<T>)};

template <typename T = size_t>
requires std::integral<T>
inline constexpr auto BASIC_OPERATORS_T = std::array{ALL_OPERATORS_T<T>[0], ALL_OPERATORS_T<T>[1]};

template <typename T = size_t>
requires std::integral<T>
inline constexpr auto BASIC_OPERATORS =
std::span<aoc::day_7::equation_operator_t<T> const * const, std::size(aoc::day_7::BASIC_OPERATORS_T<T>)>{
aoc::day_7::BASIC_OPERATORS_T<T>.data(), std::size(aoc::day_7::BASIC_OPERATORS_T<T>)};

} // namespace aoc::day_7
6 changes: 5 additions & 1 deletion day_7/lib/equation_puzzle.hpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
#pragma once
#include "equation_result.hpp"

#include <concepts>
#include <cstdint>
#include <vector>


namespace aoc::day_7 {

/// Represents a puzzle consisting of a target result and a sequence of values
/// that need to be combined using operators to reach that result
/// @tparam T The numeric type used for the result value (defaults to size_t)
template <typename T = size_t> struct equation_puzzle {
template <typename T = size_t>
requires std::integral<T>
struct equation_puzzle {
equation_result<T> result; ///< The target result that needs to be achieved
std::vector<uint16_t> values; ///< The sequence of values that need to be combined
};
Expand Down
80 changes: 56 additions & 24 deletions day_7/lib/equation_puzzle_parser.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <algorithm>
#include <concepts>
#include <expected>
#include <ranges>
#include <string>
Expand All @@ -14,37 +15,68 @@

namespace aoc::day_7 {

/// @brief Parses a single puzzle from a string input
/// @tparam T The numeric type to use for puzzle results (defaults to size_t)
/// @param line String containing the puzzle in the format "result: value1 value2 ..."
/// @return Parsed equation puzzle
template <typename T = size_t>
requires std::integral<T>
[[nodiscard]] auto parsePuzzle(std::string_view line) -> equation_puzzle<T>;

/// Parses puzzles from a string input into equation puzzles
/// @tparam T The numeric type to use for puzzle results (defaults to size_t)
/// @param input String containing puzzles in the format "result: value1 value2 ..."
/// @return Vector of parsed equation puzzles
/// Each puzzle line should be in the format: "target_number: value1 value2 value3 ..."
/// Lines are separated by newlines, values are separated by spaces
template <typename T = size_t>
auto parsePuzzles(std::string_view input) -> std::vector<aoc::day_7::equation_puzzle<T>> {
return input | std::views::split('\n') | std::views::transform([](auto && line) {
if (line.back() == '\r') {
return std::string_view{line.begin(), line.end() - 1};
}
return std::string_view{line.begin(), line.end()};
}) |
std::views::filter([](auto && line) { return !line.empty(); }) | std::views::transform([](auto && line) {
auto colon_pos = line.find(':');
auto numberParser = aoc::parser::rules::parse_number<T>(std::string(line.substr(0, colon_pos)));
auto result = aoc::day_7::equation_result<T>{*numberParser};
auto values_range = line.substr(colon_pos + 1);

auto values = values_range | std::views::split(' ') | std::views::transform([](auto && value) {
return std::string_view{value.begin(), value.end()};
}) |
std::views::filter([](auto && value) { return !value.empty(); }) |
std::views::transform(
[](auto && value) { return static_cast<uint16_t>(std::stoul(std::string(value))); }) |
aoc::ranges::to<std::vector<uint16_t>>;

return equation_puzzle<T>{result, std::move(values)};
}) |
aoc::ranges::to<std::vector<equation_puzzle<T>>>;
requires std::integral<T>
[[nodiscard]] auto parsePuzzles(std::string_view input)
-> std::expected<std::vector<aoc::day_7::equation_puzzle<T>>, std::error_code>;

template <typename T>
requires std::integral<T>
[[nodiscard]] auto parsePuzzles(std::string_view input)
-> std::expected<std::vector<aoc::day_7::equation_puzzle<T>>, std::error_code> {
try {
return input | std::views::split('\n') | std::views::transform([](auto && line) {
if (line.back() == '\r') {
return std::string_view{line.begin(), line.end() - 1};
}
return std::string_view{line.begin(), line.end()};
}) |
std::views::filter([](auto && line) { return !line.empty(); }) |
std::views::transform([](auto && line) { return parsePuzzle<T>(line); }) |
aoc::ranges::to<std::vector<equation_puzzle<T>>>;
} catch (...) {
return std::unexpected(std::make_error_code(std::errc::invalid_argument));
}
}

template <typename T>
requires std::integral<T>
[[nodiscard]] auto parsePuzzle(std::string_view line) -> equation_puzzle<T> {
auto colon_pos = line.find(':');
std::expected<T, std::error_code> parsedExpectedResult =
aoc::parser::rules::parse_number<T>(std::string(line.substr(0, colon_pos)));
if (!parsedExpectedResult) {
throw std::invalid_argument("Failed to parse number");
}
return equation_puzzle<T>{equation_result<T>{*parsedExpectedResult},
std::move(line.substr(colon_pos + 1) | std::views::split(' ') |
std::views::transform([](auto && value) {
return std::string_view{value.begin(), value.end()};
}) |
std::views::filter([](auto && value) { return !value.empty(); }) |
std::views::transform([](auto && value) {
std::expected<uint16_t, std::error_code> parsedValue =
aoc::parser::rules::parse_number<uint16_t>(value);
if (!parsedValue) {
throw std::invalid_argument("Failed to parse number");
}
return *parsedValue;
}) |
aoc::ranges::to<std::vector<uint16_t>>)};
}

} // namespace aoc::day_7
Loading
Loading