Skip to content

Commit

Permalink
aoc_lib: move num_digits and powi into util/math.hpp
Browse files Browse the repository at this point in the history
I can use these for day 7 too.
  • Loading branch information
yut23 committed Dec 14, 2024
1 parent f9dc417 commit f40a91b
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 91 deletions.
66 changes: 14 additions & 52 deletions 2024/src/day11.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@
#ifndef DAY11_HPP_UOIOTEZD
#define DAY11_HPP_UOIOTEZD

#include "lib.hpp" // for DEBUG
#include <algorithm> // for count_if
#include <array> // for array
#include <cstddef> // for size_t
#include <cstdint> // for int64_t
#include <functional> // for plus
#include <iostream> // for istream, ostream, cerr
#include <numeric> // for transform_reduce
#include <string> // for string, to_string, stoi
#include <variant> // for variant, get, holds_alternative, visit
#include <vector> // for vector
#include "lib.hpp" // for DEBUG
#include "util/math.hpp" // for num_digits, powi
#include <algorithm> // for count_if
#include <array> // for array
#include <cstddef> // for size_t
#include <cstdint> // for int64_t
#include <functional> // for plus
#include <iostream> // for istream, ostream, cerr
#include <numeric> // for transform_reduce
#include <variant> // for variant, get, holds_alternative, visit
#include <vector> // for vector

namespace aoc::day11 {

Expand Down Expand Up @@ -167,45 +167,6 @@ void HistoryData::set_stone(Stone &stone, stone_value_t value) const {
}
}

template <typename IntegerT,
int max_digits = std::numeric_limits<IntegerT>::digits10>
constexpr std::array<IntegerT, max_digits> gen_powers_of_10() {
std::array<IntegerT, max_digits> arr;
IntegerT x = 1;
for (std::size_t i = 0; i < max_digits; ++i) {
x *= 10;
arr[i] = x;
}
return arr;
}

template <std::integral IntegerT>
int num_digits(IntegerT value) {
constexpr auto POWERS = gen_powers_of_10<IntegerT>();
return std::distance(
POWERS.begin(),
std::upper_bound(POWERS.begin(), POWERS.end(), value)) +
1;
}

template <typename IntegerT>
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();
Expand All @@ -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<stone_value_t>(10, ndigits / 2);
stone_value_t modulus =
math::powi<stone_value_t>(10, ndigits / 2);
stone = history.get_stone(value / modulus);
stones.push_back(history.get_stone(value % modulus));
} else {
Expand Down
57 changes: 21 additions & 36 deletions 2024/src/test11.cpp → aoc_lib/src/test_math.cpp
Original file line number Diff line number Diff line change
@@ -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 <cstddef> // for size_t
#include <string> // for string
#include <cstddef> // for size_t
#include <cstdint> // for int64_t, uint64_t
#include <iostream> // for cout
#include <string> // for string
// IWYU pragma: no_include <typeinfo> // for type_info (util::demangle)

namespace aoc::day11::test {
namespace aoc::math::test {

template <typename IntegerT>
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<IntegerT>();
constexpr auto POWERS_OF_10 = aoc::math::gen_powers_of_10<IntegerT>();
std::size_t size = POWERS_OF_10.size();
IntegerT max = std::numeric_limits<IntegerT>::max();
int i = 0;
Expand Down Expand Up @@ -51,29 +54,11 @@ std::size_t test_powers_of_10() {
return test.num_failed();
}

template <typename IntegerT>
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 <class IntegerT>
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<IntegerT>);
unit_test::PureTest test("aoc::math::num_digits<" + type_name + ">",
&aoc::math::num_digits<IntegerT>);

test(1, 1);
for (unsigned int i = 0; i <= std::numeric_limits<IntegerT>::digits10;
Expand All @@ -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<int>();
failed_count += aoc::day11::test::test_powers_of_10<unsigned int>();
failed_count += aoc::day11::test::test_powers_of_10<std::int64_t>();
failed_count += aoc::day11::test::test_powers_of_10<std::uint64_t>();
failed_count += aoc::day11::test::test_num_digits<int>();
failed_count += aoc::day11::test::test_num_digits<unsigned int>();
failed_count += aoc::day11::test::test_num_digits<std::int64_t>();
failed_count += aoc::day11::test::test_num_digits<std::uint64_t>();
failed_count += aoc::math::test::test_powers_of_10<int>();
failed_count += aoc::math::test::test_powers_of_10<unsigned int>();
failed_count += aoc::math::test::test_powers_of_10<std::int64_t>();
failed_count += aoc::math::test::test_powers_of_10<std::uint64_t>();
failed_count += aoc::math::test::test_num_digits<int>();
failed_count += aoc::math::test::test_num_digits<unsigned int>();
failed_count += aoc::math::test::test_num_digits<std::int64_t>();
failed_count += aoc::math::test::test_num_digits<std::uint64_t>();
return unit_test::fix_exit_code(failed_count);
}
3 changes: 2 additions & 1 deletion aoc_lib/src/test_pretty_print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <sstream> // for ostringstream

namespace pretty_print::test {
Expand Down
2 changes: 1 addition & 1 deletion aoc_lib/src/test_unit_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <compare> // for strong_ordering
#include <cstddef> // for size_t
Expand Down
62 changes: 62 additions & 0 deletions aoc_lib/src/util/math.hpp
Original file line number Diff line number Diff line change
@@ -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 <algorithm> // for upper_bound
#include <array> // for array
#include <concepts> // for integral
#include <cstddef> // for size_t
#include <iterator> // for distance // IWYU pragma: keep
#include <limits> // for numeric_limits

namespace aoc::math {

template <typename IntegerT,
int max_digits = std::numeric_limits<IntegerT>::digits10>
constexpr std::array<IntegerT, max_digits> gen_powers_of_10() {
std::array<IntegerT, max_digits> arr;
IntegerT x = 1;
for (std::size_t i = 0; i < max_digits; ++i) {
x *= 10;
arr[i] = x;
}
return arr;
}

template <std::integral IntegerT>
int num_digits(IntegerT value) {
constexpr auto POWERS = gen_powers_of_10<IntegerT>();
return std::distance(
POWERS.begin(),
std::upper_bound(POWERS.begin(), POWERS.end(), value)) +
1;
}

template <typename IntegerT>
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 */
2 changes: 1 addition & 1 deletion tools/cpp/iwyu
Original file line number Diff line number Diff line change
Expand Up @@ -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[@]}"

0 comments on commit f40a91b

Please sign in to comment.