diff --git a/src/core/include/mp-units/framework/dimension.h b/src/core/include/mp-units/framework/dimension.h index eed17936..cbd3609d 100644 --- a/src/core/include/mp-units/framework/dimension.h +++ b/src/core/include/mp-units/framework/dimension.h @@ -160,15 +160,15 @@ struct is_dimension_one : std::true_type {}; MP_UNITS_EXPORT template [[nodiscard]] consteval Dimension auto operator*(Lhs, Rhs) { - return detail::expr_multiply( + return detail::expr_multiply( Lhs{}, Rhs{}); } MP_UNITS_EXPORT template [[nodiscard]] consteval Dimension auto operator/(Lhs, Rhs) { - return detail::expr_divide( - Lhs{}, Rhs{}); + return detail::expr_divide(Lhs{}, + Rhs{}); } namespace detail { @@ -213,8 +213,8 @@ template else return derived_dimension>{}; } else - return detail::expr_pow(d); + return detail::expr_pow(d); } /** @@ -235,6 +235,7 @@ template */ [[nodiscard]] consteval Dimension auto cbrt(Dimension auto d) { return pow<1, 3>(d); } + struct dimension_symbol_formatting { text_encoding encoding = text_encoding::default_encoding; }; diff --git a/src/core/include/mp-units/framework/expression_template.h b/src/core/include/mp-units/framework/expression_template.h index 45b77ff3..0e1c0dc2 100644 --- a/src/core/include/mp-units/framework/expression_template.h +++ b/src/core/include/mp-units/framework/expression_template.h @@ -199,6 +199,80 @@ template using expr_consolidate = MP_UNITS_TYPENAME expr_consolidate_impl::type; +/** + * @brief Simplifies the expression template + * + * Analyzes provided numerator and denominator type lists and simplifies elements with the same type. + * If the same power exists in both list, this elements gets omitted. Otherwise, the power of its + * exponent gets subtracted according to numerator and denominator elements powers. + * + * @tparam NumList type list for expression numerator + * @tparam DenList type list for expression denominator + * @tparam Pred predicate to be used for elements comparisons + */ +template typename Pred> +struct expr_simplify; + +// when one of the lists is empty there is nothing to do +template typename Pred> + requires(type_list_size == 0) || (type_list_size == 0) +struct expr_simplify { + using num = NumList; + using den = DenList; +}; + +// in case when front elements are different progress to the next element +template typename Pred> +struct expr_simplify, type_list, Pred> { + using impl = conditional::value, expr_simplify, type_list, Pred>, + expr_simplify, type_list, Pred>>; + using num = conditional::value, type_list_push_front, typename impl::num>; + using den = conditional::value, typename impl::den, type_list_push_front>; +}; + +// in case two elements are of the same power such element gets omitted +template typename Pred> +struct expr_simplify, type_list, Pred> : + expr_simplify, type_list, Pred> {}; + +template +struct expr_simplify_power { + static constexpr ratio r = Num - Den; + using type = power_or_T; + using num = conditional<(r > 0), type_list, type_list<>>; + using den = conditional<(r < 0), type_list, type_list<>>; +}; + +// in case there are different powers for the same element simplify the power +template typename Pred> +struct expr_simplify, NRest...>, type_list, Pred> { + using impl = expr_simplify, type_list, Pred>; + using type = expr_simplify_power::exponent, ratio{1}>; + using num = type_list_join; + using den = type_list_join; +}; + +// in case there are different powers for the same element simplify the power +template typename Pred> +struct expr_simplify, type_list, DRest...>, Pred> { + using impl = expr_simplify, type_list, Pred>; + using type = expr_simplify_power::exponent>; + using num = type_list_join; + using den = type_list_join; +}; + +// in case there are different powers for the same element simplify the power +template typename Pred> + requires(!std::same_as, power>) +struct expr_simplify, NRest...>, type_list, DRest...>, Pred> { + using impl = expr_simplify, type_list, Pred>; + using type = expr_simplify_power::exponent, power::exponent>; + using num = type_list_join; + using den = type_list_join; +}; + + // expr_less template typename Pred> struct expr_less_impl : Pred, expr_type> {}; @@ -254,9 +328,9 @@ template typename OneType, typename List> template typename OneType, typename... Ts> struct expr_fractions : decltype(expr_fractions_impl>()) {}; -// make_expr +// expr_make_spec template typename To> -[[nodiscard]] consteval auto make_expr() +[[nodiscard]] consteval auto expr_make_spec_impl() { constexpr std::size_t num = type_list_size; constexpr std::size_t den = type_list_size; @@ -276,110 +350,19 @@ template typename Pred> -struct expr_simplify_impl; - -// when one of the lists is empty there is nothing to do -template typename Pred> - requires(type_list_size == 0) || (type_list_size == 0) -struct expr_simplify_impl { - using num = NumList; - using den = DenList; -}; - -// in case when front elements are different progress to the next element -template typename Pred> -struct expr_simplify_impl, type_list, Pred> { - using impl = - conditional::value, expr_simplify_impl, type_list, Pred>, - expr_simplify_impl, type_list, Pred>>; - using num = conditional::value, type_list_push_front, typename impl::num>; - using den = conditional::value, typename impl::den, type_list_push_front>; -}; - -// in case two elements are of the same power such element gets omitted -template typename Pred> -struct expr_simplify_impl, type_list, Pred> : - expr_simplify_impl, type_list, Pred> {}; - -template -struct expr_simplify_power { - static constexpr ratio r = Num - Den; - using type = power_or_T; - using num = conditional<(r > 0), type_list, type_list<>>; - using den = conditional<(r < 0), type_list, type_list<>>; -}; - -// in case there are different powers for the same element simplify the power -template typename Pred> -struct expr_simplify_impl, NRest...>, type_list, Pred> { - using impl = expr_simplify_impl, type_list, Pred>; - using type = expr_simplify_power::exponent, ratio{1}>; - using num = type_list_join; - using den = type_list_join; -}; - -// in case there are different powers for the same element simplify the power -template typename Pred> -struct expr_simplify_impl, type_list, DRest...>, Pred> { - using impl = expr_simplify_impl, type_list, Pred>; - using type = expr_simplify_power::exponent>; - using num = type_list_join; - using den = type_list_join; -}; - -// in case there are different powers for the same element simplify the power -template typename Pred> - requires(!std::same_as, power>) -struct expr_simplify_impl, NRest...>, type_list, DRest...>, Pred> { - using impl = expr_simplify_impl, type_list, Pred>; - using type = expr_simplify_power::exponent, power::exponent>; - using num = type_list_join; - using den = type_list_join; -}; - -template typename To, typename OneType, template typename Pred, typename T> -[[nodiscard]] consteval auto expr_simplify(T) -{ - if constexpr (is_specialization_of) { - using simple = expr_simplify_impl; - // the usage of `std::identity` below helps to resolve an using alias identifier to the actual - // type identifier in the clang compile-time errors - return std::identity{}(make_expr()); - } else - return T{}; -} - /** * @brief Creates an expression template spec based on provided numerator and denominator parts */ template typename Pred, - bool Simplify, template typename To> + template typename To> [[nodiscard]] consteval auto get_optimized_expression() { using num_list = expr_consolidate; using den_list = expr_consolidate; - if constexpr (Simplify) { - using simple = expr_simplify_impl; - // the usage of `std::identity` below helps to resolve an using alias identifier to the actual - // type identifier in the clang compile-time errors - return std::identity{}(make_expr()); - } else - // the usage of `std::identity` below helps to resolve an using alias identifier to the actual - // type identifier in the clang compile-time errors - return std::identity{}(make_expr()); + using simple = expr_simplify; + // the usage of `std::identity` below helps to resolve an using alias identifier to the actual + // type identifier in the clang compile-time errors + return std::identity{}(expr_make_spec_impl()); } /** @@ -388,12 +371,11 @@ template typename To, typename OneType, template typename Pred, bool Simplify, - typename Lhs, typename Rhs> +template typename To, typename OneType, template typename Pred, typename Lhs, + typename Rhs> [[nodiscard]] consteval auto expr_multiply(Lhs, Rhs) { if constexpr (is_same_v) { @@ -404,17 +386,17 @@ template typename To, typename OneType, template, type_list_merge_sorted, OneType, - Pred, Simplify, To>(); + Pred, To>(); } else if constexpr (is_specialization_of) { return get_optimized_expression, Pred>, - typename Lhs::_den_, OneType, Pred, Simplify, To>(); + typename Lhs::_den_, OneType, Pred, To>(); } else if constexpr (is_specialization_of) { return get_optimized_expression, Pred>, - typename Rhs::_den_, OneType, Pred, Simplify, To>(); + typename Rhs::_den_, OneType, Pred, To>(); } else { // two base dimensions return get_optimized_expression, type_list, Pred>, type_list<>, OneType, - Pred, Simplify, To>(); + Pred, To>(); } } @@ -424,12 +406,11 @@ template typename To, typename OneType, template typename To, typename OneType, template typename Pred, bool Simplify, - typename Lhs, typename Rhs> +template typename To, typename OneType, template typename Pred, typename Lhs, + typename Rhs> [[nodiscard]] consteval auto expr_divide(Lhs lhs, Rhs rhs) { if constexpr (is_same_v) { @@ -437,19 +418,18 @@ template typename To, typename OneType, template) { return lhs; } else if constexpr (is_same_v) { - return expr_divide(To<>{}, rhs); + return expr_divide(To<>{}, rhs); } else if constexpr (is_specialization_of && is_specialization_of) { // two derived entities return get_optimized_expression, type_list_merge_sorted, OneType, - Pred, Simplify, To>(); + Pred, To>(); } else if constexpr (is_specialization_of) { - return get_optimized_expression, Pred>, OneType, Pred, - Simplify, To>(); + return get_optimized_expression< + typename Lhs::_num_, type_list_merge_sorted, Pred>, OneType, Pred, To>(); } else if constexpr (is_specialization_of) { return get_optimized_expression, Pred>, - typename Rhs::_num_, OneType, Pred, Simplify, To>(); + typename Rhs::_num_, OneType, Pred, To>(); } else { // two named entities return To>{}; @@ -462,28 +442,26 @@ template typename To, typename OneType, template typename To, typename OneType, bool Simplify, typename T> +template typename To, typename OneType, typename T> [[nodiscard]] consteval auto expr_invert(T) { if constexpr (is_specialization_of) // the usage of `std::identity` below helps to resolve an using alias identifier to the actual // type identifier in the clang compile-time errors - return std::identity{}(make_expr()); + return std::identity{}(expr_make_spec_impl()); else return To>{}; } template typename To, typename OneType, - template typename Pred, bool Simplify, typename... Nums, typename... Dens> + template typename Pred, typename... Nums, typename... Dens> requires detail::non_zero [[nodiscard]] consteval auto expr_pow_impl(type_list, type_list) { return detail::get_optimized_expression...>, - type_list...>, OneType, Pred, Simplify, - To>(); + type_list...>, OneType, Pred, To>(); } @@ -495,15 +473,14 @@ template typename To * @tparam To destination type list to put the result to * @tparam OneType type that represents the value `1` * @tparam Pred binary less then predicate - * @tparam Simplify specifies whether the resulting expression should be immediately simplified * @tparam T Expression being the base of the operation */ template typename To, typename OneType, - template typename Pred, bool Simplify, typename T> + template typename Pred, typename T> requires detail::non_zero [[nodiscard]] consteval auto expr_pow(T) { - return expr_pow_impl(typename T::_num_{}, typename T::_den_{}); + return expr_pow_impl(typename T::_num_{}, typename T::_den_{}); } diff --git a/src/core/include/mp-units/framework/quantity_spec.h b/src/core/include/mp-units/framework/quantity_spec.h index 458592e3..3c24b88c 100644 --- a/src/core/include/mp-units/framework/quantity_spec.h +++ b/src/core/include/mp-units/framework/quantity_spec.h @@ -552,7 +552,7 @@ template [[nodiscard]] consteval QuantitySpec auto operator*(Lhs lhs, Rhs rhs) { return detail::clone_kind_of( - detail::expr_multiply( + detail::expr_multiply( detail::remove_kind(lhs), detail::remove_kind(rhs))); } @@ -560,15 +560,10 @@ template [[nodiscard]] consteval QuantitySpec auto operator/(Lhs lhs, Rhs rhs) { return detail::clone_kind_of( - detail::expr_divide( + detail::expr_divide( detail::remove_kind(lhs), detail::remove_kind(rhs))); } -[[nodiscard]] consteval QuantitySpec auto simplify(QuantitySpec auto q) -{ - return detail::expr_simplify(q); -} - template [[nodiscard]] consteval bool operator==(Lhs, Rhs) { @@ -597,8 +592,8 @@ template return q; else if constexpr (detail::DerivedQuantitySpec) return detail::clone_kind_of( - detail::expr_pow(detail::remove_kind(q))); + detail::expr_pow( + detail::remove_kind(q))); else if constexpr (Den == 1) return detail::clone_kind_of(derived_quantity_spec>{}); else diff --git a/src/core/include/mp-units/framework/unit.h b/src/core/include/mp-units/framework/unit.h index af0ed993..f32f4b40 100644 --- a/src/core/include/mp-units/framework/unit.h +++ b/src/core/include/mp-units/framework/unit.h @@ -481,7 +481,7 @@ template else if constexpr (detail::is_specialization_of_scaled_unit) return Rhs::mag * (lhs * Rhs::reference_unit); else - return detail::expr_multiply(lhs, rhs); + return detail::expr_multiply(lhs, rhs); } /** @@ -499,7 +499,7 @@ template else if constexpr (detail::is_specialization_of_scaled_unit) return mag<1> / Rhs::mag * (lhs / Rhs::reference_unit); else - return detail::expr_divide(lhs, rhs); + return detail::expr_divide(lhs, rhs); } [[nodiscard]] MP_UNITS_CONSTEVAL Unit auto inverse(Unit auto u) { return one / u; } @@ -559,7 +559,7 @@ template else if constexpr (detail::is_specialization_of_scaled_unit) return scaled_unit(U::mag), decltype(pow(U::reference_unit))>{}; else if constexpr (detail::is_specialization_of_derived_unit) - return detail::expr_pow(u); + return detail::expr_pow(u); else if constexpr (Den == 1) return derived_unit>{}; else