diff --git a/2024/src/day11.hpp b/2024/src/day11.hpp index 806b09e..89956b4 100644 --- a/2024/src/day11.hpp +++ b/2024/src/day11.hpp @@ -8,17 +8,17 @@ #ifndef DAY11_HPP_UOIOTEZD #define DAY11_HPP_UOIOTEZD -#include "lib.hpp" // for DEBUG -#include // for count_if -#include // for array -#include // for size_t -#include // for int64_t -#include // for plus -#include // for istream, ostream, cerr -#include // for transform_reduce -#include // for string, to_string, stoi -#include // for variant, get, holds_alternative, visit -#include // for vector +#include "lib.hpp" // for DEBUG +#include "util/math.hpp" // for num_digits, powi +#include // for count_if +#include // for array +#include // for size_t +#include // for int64_t +#include // for plus +#include // for istream, ostream, cerr +#include // for transform_reduce +#include // for variant, get, holds_alternative, visit +#include // for vector namespace aoc::day11 { @@ -167,45 +167,6 @@ void HistoryData::set_stone(Stone &stone, stone_value_t value) const { } } -template ::digits10> -constexpr std::array gen_powers_of_10() { - std::array arr; - IntegerT x = 1; - for (std::size_t i = 0; i < max_digits; ++i) { - x *= 10; - arr[i] = x; - } - return arr; -} - -template -int num_digits(IntegerT value) { - constexpr auto POWERS = gen_powers_of_10(); - return std::distance( - POWERS.begin(), - std::upper_bound(POWERS.begin(), POWERS.end(), value)) + - 1; -} - -template -IntegerT powi(IntegerT base, unsigned int exponent) { - if (exponent == 0) { - return 1; - } else if (exponent == 1) { - return base; - } else if (exponent == 2) { - return base * base; - } else { - IntegerT tmp = powi(base, exponent / 2); - tmp *= tmp; - if (exponent % 2 == 1) { - tmp *= base; - } - return tmp; - } -} - // Main update routine. void StoneGroup::blink(const HistoryData &history) { std::size_t orig_size = stones.size(); @@ -219,9 +180,10 @@ void StoneGroup::blink(const HistoryData &history) { if (value == 0) { stone = history.get_stone(1); } else { - int ndigits = num_digits(value); + int ndigits = math::num_digits(value); if (ndigits % 2 == 0) { - stone_value_t modulus = powi(10, ndigits / 2); + stone_value_t modulus = + math::powi(10, ndigits / 2); stone = history.get_stone(value / modulus); stones.push_back(history.get_stone(value % modulus)); } else { diff --git a/2024/src/test11.cpp b/aoc_lib/src/test_math.cpp similarity index 60% rename from 2024/src/test11.cpp rename to aoc_lib/src/test_math.cpp index 3db2c3c..3c391a0 100644 --- a/2024/src/test11.cpp +++ b/aoc_lib/src/test_math.cpp @@ -1,29 +1,32 @@ /****************************************************************************** - * File: test11.cpp + * File: test_math.cpp * * Author: Eric T. Johnson (yut23) * Created: 2024-12-11 *****************************************************************************/ -#include "day11.hpp" // IWYU pragma: associated +#include "util/math.hpp" // IWYU pragma: associated + #include "unit_test/pretty_print.hpp" // for repr #include "unit_test/unit_test.hpp" #include "util/util.hpp" // for demangle -#include // for size_t -#include // for string +#include // for size_t +#include // for int64_t, uint64_t +#include // for cout +#include // for string // IWYU pragma: no_include // for type_info (util::demangle) -namespace aoc::day11::test { +namespace aoc::math::test { template std::size_t test_powers_of_10() { const std::string type_name = util::demangle(typeid(IntegerT).name()); unit_test::PureTest test( - "day11::test_powers_of_10<" + type_name + ">", + "aoc::math::gen_powers_of_10<" + type_name + ">", +[](IntegerT x) -> IntegerT { return x; }); - constexpr auto POWERS_OF_10 = gen_powers_of_10(); + constexpr auto POWERS_OF_10 = aoc::math::gen_powers_of_10(); std::size_t size = POWERS_OF_10.size(); IntegerT max = std::numeric_limits::max(); int i = 0; @@ -51,29 +54,11 @@ std::size_t test_powers_of_10() { return test.num_failed(); } -template -IntegerT powi(IntegerT base, unsigned int exponent) { - if (exponent == 0) { - return 1; - } else if (exponent == 1) { - return base; - } else if (exponent == 2) { - return base * base; - } else { - IntegerT tmp = powi(base, exponent / 2); - tmp *= tmp; - if (exponent % 2 == 1) { - tmp *= base; - } - return tmp; - } -} - template std::size_t test_num_digits() { const std::string type_name = util::demangle(typeid(IntegerT).name()); - unit_test::PureTest test("day11::test_num_digits<" + type_name + ">", - &aoc::day11::num_digits); + unit_test::PureTest test("aoc::math::num_digits<" + type_name + ">", + &aoc::math::num_digits); test(1, 1); for (unsigned int i = 0; i <= std::numeric_limits::digits10; @@ -91,17 +76,17 @@ std::size_t test_num_digits() { return test.done(), test.num_failed(); } -} // namespace aoc::day11::test +} // namespace aoc::math::test int main() { std::size_t failed_count = 0; - failed_count += aoc::day11::test::test_powers_of_10(); - failed_count += aoc::day11::test::test_powers_of_10(); - failed_count += aoc::day11::test::test_powers_of_10(); - failed_count += aoc::day11::test::test_powers_of_10(); - failed_count += aoc::day11::test::test_num_digits(); - failed_count += aoc::day11::test::test_num_digits(); - failed_count += aoc::day11::test::test_num_digits(); - failed_count += aoc::day11::test::test_num_digits(); + failed_count += aoc::math::test::test_powers_of_10(); + failed_count += aoc::math::test::test_powers_of_10(); + failed_count += aoc::math::test::test_powers_of_10(); + failed_count += aoc::math::test::test_powers_of_10(); + failed_count += aoc::math::test::test_num_digits(); + failed_count += aoc::math::test::test_num_digits(); + failed_count += aoc::math::test::test_num_digits(); + failed_count += aoc::math::test::test_num_digits(); return unit_test::fix_exit_code(failed_count); } diff --git a/aoc_lib/src/test_pretty_print.cpp b/aoc_lib/src/test_pretty_print.cpp index 6e4abea..91aa23f 100644 --- a/aoc_lib/src/test_pretty_print.cpp +++ b/aoc_lib/src/test_pretty_print.cpp @@ -6,9 +6,10 @@ * Description: Tests for the unit test pretty-printing code. *****************************************************************************/ +#include "unit_test/pretty_print.hpp" // IWYU pragma: associated + #include "unit_test/unit_test.hpp" -#include "unit_test/pretty_print.hpp" #include // for ostringstream namespace pretty_print::test { diff --git a/aoc_lib/src/test_unit_test.cpp b/aoc_lib/src/test_unit_test.cpp index e80548b..48e7134 100644 --- a/aoc_lib/src/test_unit_test.cpp +++ b/aoc_lib/src/test_unit_test.cpp @@ -6,7 +6,7 @@ * Description: Tests of the unit test framework itself. *****************************************************************************/ -#include "unit_test/unit_test.hpp" +#include "unit_test/unit_test.hpp" // IWYU pragma: associated #include // for strong_ordering #include // for size_t diff --git a/aoc_lib/src/util/math.hpp b/aoc_lib/src/util/math.hpp new file mode 100644 index 0000000..2193de9 --- /dev/null +++ b/aoc_lib/src/util/math.hpp @@ -0,0 +1,62 @@ +/****************************************************************************** + * File: math.hpp + * + * Author: Eric T. Johnson + * Created: 2024-12-13 + * Description: Shared math routines for Advent of Code. + *****************************************************************************/ + +#ifndef MATH_HPP_VHRQFHXN +#define MATH_HPP_VHRQFHXN + +#include // for upper_bound +#include // for array +#include // for integral +#include // for size_t +#include // for distance // IWYU pragma: keep +#include // for numeric_limits + +namespace aoc::math { + +template ::digits10> +constexpr std::array gen_powers_of_10() { + std::array arr; + IntegerT x = 1; + for (std::size_t i = 0; i < max_digits; ++i) { + x *= 10; + arr[i] = x; + } + return arr; +} + +template +int num_digits(IntegerT value) { + constexpr auto POWERS = gen_powers_of_10(); + return std::distance( + POWERS.begin(), + std::upper_bound(POWERS.begin(), POWERS.end(), value)) + + 1; +} + +template +IntegerT powi(IntegerT base, unsigned int exponent) { + if (exponent == 0) { + return 1; + } else if (exponent == 1) { + return base; + } else if (exponent == 2) { + return base * base; + } else { + IntegerT tmp = powi(base, exponent / 2); + tmp *= tmp; + if (exponent % 2 == 1) { + tmp *= base; + } + return tmp; + } +} + +} // namespace aoc::math + +#endif /* end of include guard: MATH_HPP_VHRQFHXN */ diff --git a/tools/cpp/iwyu b/tools/cpp/iwyu index 7905253..4c51777 100755 --- a/tools/cpp/iwyu +++ b/tools/cpp/iwyu @@ -45,4 +45,4 @@ done # add remaining arguments to include-what-you-use args iwyu_args+=("$@") -iwyu-tool -p "../compile_commands_$AOC_YEAR.json" "${tool_args[@]}" "${sources[@]}" -- --no-warnings -Xiwyu --quoted_includes_first -Xiwyu --max_line_length=300 -Xiwyu --mapping_file="$TOOLS_DIR/cpp/iwyu_mappings.imp" -resource-dir "$(clang -print-resource-dir)" "${iwyu_args[@]}" +iwyu-tool -p "../compile_commands.json" "${tool_args[@]}" "${sources[@]}" -- --no-warnings -Xiwyu --quoted_includes_first -Xiwyu --max_line_length=300 -Xiwyu --mapping_file="$TOOLS_DIR/cpp/iwyu_mappings.imp" -resource-dir "$(clang -print-resource-dir)" "${iwyu_args[@]}"