diff --git a/src/core/include/units/magnitude.h b/src/core/include/units/magnitude.h index a46c336e..4eb640fb 100644 --- a/src/core/include/units/magnitude.h +++ b/src/core/include/units/magnitude.h @@ -134,69 +134,8 @@ constexpr auto inverse(BP bp) { return bp; } -// Implementation helpers for `magnitude<...>` constraints (below). +// A variety of implementation detail helpers. namespace detail { -constexpr bool is_valid_base_power(const BasePower auto &bp); - -template -constexpr bool strictly_increasing(Ts&&... ts); -} // namespace detail - -/** - * @brief A representation for positive real numbers which optimizes taking products and rational powers. - * - * Magnitudes can be treated as values. Each type encodes exactly one value. Users can multiply, divide, and compare - * for equality. - */ -template - requires requires { - (detail::is_valid_base_power(BPs) && ... && detail::strictly_increasing(BPs.get_base()...)); - } -struct magnitude {}; - -// Implementation for Magnitude concept (below). -namespace detail { -template -struct is_magnitude : std::false_type {}; -template -struct is_magnitude> : std::true_type {}; -} // namespace detail - -/** - * @brief Concept to detect whether T is a valid Magnitude. - */ -template -concept Magnitude = detail::is_magnitude::value; - -/** - * @brief Convert any positive integer to a Magnitude. - * - * This will be the main way end users create Magnitudes. They should rarely (if ever) create a magnitude<...> by - * manually adding base powers. - */ -template - requires requires { R.num > 0; } -constexpr Magnitude auto as_magnitude(); - -/** - * @brief A base to represent pi. - */ -struct pi_base { - static constexpr long double value = std::numbers::pi_v; -}; - -/** - * @brief A simple way to create a Magnitude representing a rational power of pi. - */ -template -constexpr auto pi_to_the() { return magnitude{Power}>{}; } - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// Implementation details below. -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace detail -{ // Find the smallest prime factor of `n`. constexpr std::intmax_t find_first_factor(std::intmax_t n) @@ -232,22 +171,11 @@ constexpr std::intmax_t remove_power(std::intmax_t base, std::intmax_t pow, std: // Helpers to perform prime factorization at compile time. template requires requires { N > 0; } -struct prime_factorization { - static constexpr int first_base = find_first_factor(N); - static constexpr std::intmax_t first_power = multiplicity(first_base, N); - static constexpr std::intmax_t remainder = remove_power(first_base, first_power, N); - - static constexpr auto value = magnitude{} - * prime_factorization::value; -}; +struct prime_factorization; template static constexpr auto prime_factorization_v = prime_factorization::value; -// Specialization for the prime factorization of 1 (base case). -template<> -struct prime_factorization<1> { static constexpr magnitude<> value{}; }; - // A way to check whether a number is prime at compile time. constexpr bool is_prime(std::intmax_t n) { return (n > 1) && (find_first_factor(n) == n); } @@ -289,6 +217,53 @@ constexpr bool strictly_increasing(Ts&&... ts) { } // namespace detail +/** + * @brief A representation for positive real numbers which optimizes taking products and rational powers. + * + * Magnitudes can be treated as values. Each type encodes exactly one value. Users can multiply, divide, and compare + * for equality. + */ +template + requires ((detail::is_valid_base_power(BPs) && ... && detail::strictly_increasing(BPs.get_base()...))) +struct magnitude {}; + +// Implementation for Magnitude concept (below). +namespace detail { +template +struct is_magnitude : std::false_type {}; +template +struct is_magnitude> : std::true_type {}; +} // namespace detail + +/** + * @brief Concept to detect whether T is a valid Magnitude. + */ +template +concept Magnitude = detail::is_magnitude::value; + +/** + * @brief Convert any positive integer to a Magnitude. + * + * This will be the main way end users create Magnitudes. They should rarely (if ever) create a magnitude<...> by + * manually adding base powers. + */ +template + requires requires { R.num > 0; } +constexpr Magnitude auto as_magnitude(); + +/** + * @brief A base to represent pi. + */ +struct pi_base { + static constexpr long double value = std::numbers::pi_v; +}; + +/** + * @brief A simple way to create a Magnitude representing a rational power of pi. + */ +template +constexpr auto pi_to_the() { return magnitude{Power}>{}; } + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Magnitude equality implementation. @@ -358,4 +333,23 @@ constexpr Magnitude auto as_magnitude() { return detail::prime_factorization_v / detail::prime_factorization_v; } +namespace detail +{ +// Default implementation. +template + requires requires { N > 0; } +struct prime_factorization { + static constexpr int first_base = find_first_factor(N); + static constexpr std::intmax_t first_power = multiplicity(first_base, N); + static constexpr std::intmax_t remainder = remove_power(first_base, first_power, N); + + static constexpr auto value = magnitude{} + * prime_factorization::value; +}; + +// Specialization for the prime factorization of 1 (base case). +template<> +struct prime_factorization<1> { static constexpr magnitude<> value{}; }; +} // namespace detail + } // namespace units::mag