refactor: explode and get_complexity compile-time performance improved

This commit is contained in:
Mateusz Pusz
2024-06-13 14:39:19 +02:00
parent f63c4eec4a
commit 921aae23dc

View File

@@ -551,17 +551,17 @@ MP_UNITS_EXPORT_BEGIN
template<QuantitySpec Lhs, QuantitySpec Rhs> template<QuantitySpec Lhs, QuantitySpec Rhs>
[[nodiscard]] consteval QuantitySpec auto operator*(Lhs lhs, Rhs rhs) [[nodiscard]] consteval QuantitySpec auto operator*(Lhs lhs, Rhs rhs)
{ {
return detail::clone_kind_of<Lhs{}, Rhs{}>( return detail::clone_kind_of<Lhs{}, Rhs{}>(decltype(detail::expr_multiply<derived_quantity_spec, struct dimensionless,
detail::expr_multiply<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>( detail::type_list_of_quantity_spec_less>(
detail::remove_kind(lhs), detail::remove_kind(rhs))); detail::remove_kind(lhs), detail::remove_kind(rhs))){});
} }
template<QuantitySpec Lhs, QuantitySpec Rhs> template<QuantitySpec Lhs, QuantitySpec Rhs>
[[nodiscard]] consteval QuantitySpec auto operator/(Lhs lhs, Rhs rhs) [[nodiscard]] consteval QuantitySpec auto operator/(Lhs lhs, Rhs rhs)
{ {
return detail::clone_kind_of<Lhs{}, Rhs{}>( return detail::clone_kind_of<Lhs{}, Rhs{}>(
detail::expr_divide<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>( decltype(detail::expr_divide<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
detail::remove_kind(lhs), detail::remove_kind(rhs))); detail::remove_kind(lhs), detail::remove_kind(rhs))){});
} }
template<QuantitySpec Lhs, QuantitySpec Rhs> template<QuantitySpec Lhs, QuantitySpec Rhs>
@@ -570,7 +570,7 @@ template<QuantitySpec Lhs, QuantitySpec Rhs>
return is_same_v<Lhs, Rhs>; return is_same_v<Lhs, Rhs>;
} }
[[nodiscard]] consteval QuantitySpec auto inverse(QuantitySpec auto q) { return dimensionless / q; } [[nodiscard]] consteval QuantitySpec auto inverse(QuantitySpec auto q) { return decltype(dimensionless / q){}; }
/** /**
@@ -592,8 +592,8 @@ template<std::intmax_t Num, std::intmax_t Den = 1, QuantitySpec Q>
return q; return q;
else if constexpr (detail::DerivedQuantitySpec<Q>) else if constexpr (detail::DerivedQuantitySpec<Q>)
return detail::clone_kind_of<Q{}>( return detail::clone_kind_of<Q{}>(
detail::expr_pow<Num, Den, derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>( decltype(detail::expr_pow<Num, Den, derived_quantity_spec, struct dimensionless,
detail::remove_kind(q))); detail::type_list_of_quantity_spec_less>(detail::remove_kind(q))){});
else if constexpr (Den == 1) else if constexpr (Den == 1)
return detail::clone_kind_of<Q{}>(derived_quantity_spec<power<decltype(detail::remove_kind(Q{})), Num>>{}); return detail::clone_kind_of<Q{}>(derived_quantity_spec<power<decltype(detail::remove_kind(Q{})), Num>>{});
else else
@@ -608,7 +608,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, QuantitySpec Q>
* *
* @return QuantitySpec The result of computation * @return QuantitySpec The result of computation
*/ */
[[nodiscard]] consteval QuantitySpec auto sqrt(QuantitySpec auto q) { return pow<1, 2>(q); } [[nodiscard]] consteval QuantitySpec auto sqrt(QuantitySpec auto q) { return decltype(pow<1, 2>(q)){}; }
/** /**
@@ -618,44 +618,43 @@ template<std::intmax_t Num, std::intmax_t Den = 1, QuantitySpec Q>
* *
* @return QuantitySpec The result of computation * @return QuantitySpec The result of computation
*/ */
[[nodiscard]] consteval QuantitySpec auto cbrt(QuantitySpec auto q) { return pow<1, 3>(q); } [[nodiscard]] consteval QuantitySpec auto cbrt(QuantitySpec auto q) { return decltype(pow<1, 3>(q)){}; }
MP_UNITS_EXPORT_END MP_UNITS_EXPORT_END
namespace detail { namespace detail {
enum class specs_convertible_result : std::int8_t { no, cast, explicit_conversion, yes };
template<QuantitySpec Q> template<QuantitySpec Q>
[[nodiscard]] consteval int get_complexity(Q); [[nodiscard]] consteval auto get_complexity(Q);
template<typename... Ts> template<typename... Ts>
[[nodiscard]] consteval int get_complexity(type_list<Ts...>) [[nodiscard]] consteval auto get_complexity(type_list<Ts...>)
{ {
return (0 + ... + get_complexity(Ts{})); return std::integral_constant<int, (0 + ... + decltype(get_complexity(Ts{}))::value)>{};
} }
template<QuantitySpec Q, int... Ints> template<QuantitySpec Q, int... Ints>
[[nodiscard]] consteval int get_complexity(power<Q, Ints...>) [[nodiscard]] consteval auto get_complexity(power<Q, Ints...>)
{ {
return get_complexity(Q{}); return decltype(get_complexity(Q{})){};
} }
template<typename Q> template<typename Q>
[[nodiscard]] consteval int get_complexity(kind_of_<Q>) [[nodiscard]] consteval auto get_complexity(kind_of_<Q>)
{ {
return get_complexity(Q{}); return decltype(get_complexity(Q{})){};
} }
template<QuantitySpec Q> template<QuantitySpec Q>
[[nodiscard]] consteval int get_complexity(Q) [[nodiscard]] consteval auto get_complexity(Q)
{ {
if constexpr (detail::DerivedQuantitySpec<Q>) if constexpr (detail::DerivedQuantitySpec<Q>)
return get_complexity(typename Q::_num_{}) + get_complexity(typename Q::_den_{}); return std::integral_constant<int, decltype(get_complexity(typename Q::_num_{}))::value +
decltype(get_complexity(typename Q::_den_{}))::value>{};
else if constexpr (requires { Q::_equation_; }) else if constexpr (requires { Q::_equation_; })
return 1 + get_complexity(Q::_equation_); return std::integral_constant<int, 1 + decltype(get_complexity(Q::_equation_))::value>{};
else else
return 1; return std::integral_constant<int, 1>{};
} }
// dimension_one is always the last one // dimension_one is always the last one
@@ -672,8 +671,8 @@ template<Dimension D1, Dimension D2>
} }
template<QuantitySpec Lhs, QuantitySpec Rhs, bool lhs_eq = requires { Lhs::_equation_; }, template<QuantitySpec Lhs, QuantitySpec Rhs, bool lhs_eq = requires { Lhs::_equation_; },
bool rhs_eq = requires { Rhs::_equation_; }, ratio lhs_compl = get_complexity(Lhs{}), bool rhs_eq = requires { Rhs::_equation_; }, ratio lhs_compl = decltype(get_complexity(Lhs{}))::value,
ratio rhs_compl = get_complexity(Rhs{})> ratio rhs_compl = decltype(get_complexity(Rhs{}))::value>
struct ingredients_less : struct ingredients_less :
std::bool_constant<(lhs_compl > rhs_compl) || std::bool_constant<(lhs_compl > rhs_compl) ||
(lhs_compl == rhs_compl && ingredients_dimension_less(Lhs::dimension, Rhs::dimension)) || (lhs_compl == rhs_compl && ingredients_dimension_less(Lhs::dimension, Rhs::dimension)) ||
@@ -693,25 +692,21 @@ template<QuantitySpec Q>
return true; return true;
} }
template<QuantitySpec Q> enum class specs_convertible_result : std::int8_t { no, cast, explicit_conversion, yes };
template<QuantitySpec auto Q, specs_convertible_result Result>
struct explode_to_equation_result { struct explode_to_equation_result {
Q equation; static constexpr QuantitySpec auto equation = Q;
specs_convertible_result result; static constexpr specs_convertible_result result = Result;
}; };
#if MP_UNITS_COMP_CLANG
template<QuantitySpec Q>
explode_to_equation_result(Q, specs_convertible_result) -> explode_to_equation_result<Q>;
#endif
template<QuantitySpec Q> template<QuantitySpec Q>
requires requires { Q::_equation_; } requires requires { Q::_equation_; }
[[nodiscard]] consteval auto explode_to_equation(Q q) [[nodiscard]] consteval auto explode_to_equation(Q q)
{ {
return explode_to_equation_result{ return explode_to_equation_result<Q::_equation_,
Q::_equation_, defines_equation(q) ? specs_convertible_result::yes : specs_convertible_result::explicit_conversion}; (defines_equation(q) ? specs_convertible_result::yes
: specs_convertible_result::explicit_conversion)>{};
} }
template<QuantitySpec Q, int... Ints> template<QuantitySpec Q, int... Ints>
@@ -719,30 +714,23 @@ template<QuantitySpec Q, int... Ints>
[[nodiscard]] consteval auto explode_to_equation(power<Q, Ints...>) [[nodiscard]] consteval auto explode_to_equation(power<Q, Ints...>)
{ {
constexpr ratio exp = power<Q, Ints...>::exponent; constexpr ratio exp = power<Q, Ints...>::exponent;
return explode_to_equation_result{ return explode_to_equation_result<decltype(pow<exp.num, exp.den>(Q::_equation_)){},
pow<exp.num, exp.den>(Q::_equation_), (defines_equation(Q{}) ? specs_convertible_result::yes
defines_equation(Q{}) ? specs_convertible_result::yes : specs_convertible_result::explicit_conversion}; : specs_convertible_result::explicit_conversion)>{};
} }
template<QuantitySpec Q> template<QuantitySpec auto Q, specs_convertible_result Result = specs_convertible_result::yes>
struct explode_result { struct explode_result {
Q quantity; static constexpr QuantitySpec auto quantity = Q;
specs_convertible_result result = specs_convertible_result::yes; static constexpr specs_convertible_result result = Result;
template<typename T> template<auto T, specs_convertible_result Res>
[[nodiscard]] consteval explode_result common_convertibility_with(explode_to_equation_result<T> res) const [[nodiscard]] static consteval auto common_convertibility_with(explode_to_equation_result<T, Res> res)
{ {
return {quantity, min(result, res.result)}; return explode_result<quantity, min(result, res.result)>{};
} }
}; };
#if MP_UNITS_COMP_CLANG
template<QuantitySpec Q>
explode_result(Q) -> explode_result<Q>;
#endif
template<int Complexity, DerivedQuantitySpec Q> template<int Complexity, DerivedQuantitySpec Q>
[[nodiscard]] consteval auto explode(Q q); [[nodiscard]] consteval auto explode(Q q);
@@ -752,24 +740,25 @@ template<int Complexity, NamedQuantitySpec Q>
template<int Complexity, QuantitySpec Q, typename Num, typename... Nums, typename Den, typename... Dens> template<int Complexity, QuantitySpec Q, typename Num, typename... Nums, typename Den, typename... Dens>
[[nodiscard]] consteval auto explode(Q, type_list<Num, Nums...>, type_list<Den, Dens...>) [[nodiscard]] consteval auto explode(Q, type_list<Num, Nums...>, type_list<Den, Dens...>)
{ {
constexpr auto n = get_complexity(Num{}); constexpr auto n = decltype(get_complexity(Num{}))::value;
constexpr auto d = get_complexity(Den{}); constexpr auto d = decltype(get_complexity(Den{}))::value;
constexpr auto max_compl = n > d ? n : d; constexpr auto max_compl = n > d ? n : d;
if constexpr (max_compl == Complexity || ((n >= d && !requires { explode_to_equation(Num{}); }) || if constexpr (max_compl == Complexity || ((n >= d && !requires { explode_to_equation(Num{}); }) ||
(n < d && !requires { explode_to_equation(Den{}); }))) (n < d && !requires { explode_to_equation(Den{}); })))
return explode_result{(map_power(Num{}) * ... * map_power(Nums{})) / (map_power(Den{}) * ... * map_power(Dens{}))}; return explode_result<decltype(decltype((map_power(Num{}) * ... * map_power(Nums{}))){} /
decltype((map_power(Den{}) * ... * map_power(Dens{}))){}){}>{};
else { else {
if constexpr (n >= d) { if constexpr (n >= d) {
constexpr auto res = explode_to_equation(Num{}); constexpr auto res = decltype(explode_to_equation(Num{})){};
return explode<Complexity>((res.equation * ... * map_power(Nums{})) / return decltype(explode<Complexity>(
(map_power(Den{}) * ... * map_power(Dens{}))) decltype(decltype((res.equation * ... * map_power(Nums{}))){} /
.common_convertibility_with(res); decltype((map_power(Den{}) * ... * map_power(Dens{}))){}){}))::common_convertibility_with(res);
} else { } else {
constexpr auto res = explode_to_equation(Den{}); constexpr auto res = explode_to_equation(Den{});
return explode<Complexity>((map_power(Num{}) * ... * map_power(Nums{})) / return decltype(explode<Complexity>(
(res.equation * ... * map_power(Dens{}))) decltype(decltype((map_power(Num{}) * ... * map_power(Nums{}))){} /
.common_convertibility_with(res); decltype((res.equation * ... * map_power(Dens{}))){}){}))::common_convertibility_with(res);
} }
} }
} }
@@ -777,54 +766,56 @@ template<int Complexity, QuantitySpec Q, typename Num, typename... Nums, typenam
template<int Complexity, QuantitySpec Q, typename Num, typename... Nums> template<int Complexity, QuantitySpec Q, typename Num, typename... Nums>
[[nodiscard]] consteval auto explode(Q, type_list<Num, Nums...>, type_list<>) [[nodiscard]] consteval auto explode(Q, type_list<Num, Nums...>, type_list<>)
{ {
constexpr auto n = get_complexity(Num{}); constexpr auto n = decltype(get_complexity(Num{}))::value;
if constexpr (n == Complexity || !requires { explode_to_equation(Num{}); }) if constexpr (n == Complexity || !requires { explode_to_equation(Num{}); })
return explode_result{(map_power(Num{}) * ... * map_power(Nums{}))}; return explode_result<decltype((map_power(Num{}) * ... * map_power(Nums{}))){}>{};
else { else {
constexpr auto res = explode_to_equation(Num{}); constexpr auto res = decltype(explode_to_equation(Num{})){};
return explode<Complexity>((res.equation * ... * map_power(Nums{}))).common_convertibility_with(res); return decltype(explode<Complexity>(
decltype((res.equation * ... * map_power(Nums{}))){}))::common_convertibility_with(res);
} }
} }
template<int Complexity, QuantitySpec Q, typename Den, typename... Dens> template<int Complexity, QuantitySpec Q, typename Den, typename... Dens>
[[nodiscard]] consteval auto explode(Q, type_list<>, type_list<Den, Dens...>) [[nodiscard]] consteval auto explode(Q, type_list<>, type_list<Den, Dens...>)
{ {
constexpr auto d = get_complexity(Den{}); constexpr auto d = decltype(get_complexity(Den{}))::value;
if constexpr (d == Complexity || !requires { explode_to_equation(Den{}); }) if constexpr (d == Complexity || !requires { explode_to_equation(Den{}); })
return explode_result{dimensionless / (map_power(Den{}) * ... * map_power(Dens{}))}; return explode_result<decltype(dimensionless / decltype((map_power(Den{}) * ... * map_power(Dens{}))){}){}>{};
else { else {
constexpr auto res = explode_to_equation(Den{}); constexpr auto res = decltype(explode_to_equation(Den{})){};
return explode<Complexity>(dimensionless / (res.equation * ... * map_power(Dens{}))) return decltype(explode<Complexity>(
.common_convertibility_with(res); decltype(dimensionless /
decltype((res.equation * ... * map_power(Dens{}))){}){}))::common_convertibility_with(res);
} }
} }
template<int Complexity, QuantitySpec Q> template<int Complexity, QuantitySpec Q>
[[nodiscard]] consteval auto explode(Q, type_list<>, type_list<>) [[nodiscard]] consteval auto explode(Q, type_list<>, type_list<>)
{ {
return explode_result{dimensionless}; return explode_result<dimensionless>{};
} }
template<int Complexity, DerivedQuantitySpec Q> template<int Complexity, DerivedQuantitySpec Q>
[[nodiscard]] consteval auto explode(Q q) [[nodiscard]] consteval auto explode(Q q)
{ {
constexpr auto c = get_complexity(Q{}); constexpr auto c = decltype(get_complexity(Q{}))::value;
if constexpr (c > Complexity) if constexpr (c > Complexity)
return explode<Complexity>(q, type_list_sort<typename Q::_num_, type_list_of_ingredients_less>{}, return decltype(explode<Complexity>(q, type_list_sort<typename Q::_num_, type_list_of_ingredients_less>{},
type_list_sort<typename Q::_den_, type_list_of_ingredients_less>{}); type_list_sort<typename Q::_den_, type_list_of_ingredients_less>{})){};
else else
return explode_result{q}; return explode_result<Q{}>{};
} }
template<int Complexity, NamedQuantitySpec Q> template<int Complexity, NamedQuantitySpec Q>
[[nodiscard]] consteval auto explode(Q q) [[nodiscard]] consteval auto explode(Q)
{ {
constexpr auto c = get_complexity(Q{}); constexpr auto c = decltype(get_complexity(Q{}))::value;
if constexpr (c > Complexity && requires { Q::_equation_; }) { if constexpr (c > Complexity && requires { Q::_equation_; }) {
constexpr auto res = explode_to_equation(Q{}); constexpr auto res = decltype(explode_to_equation(Q{})){};
return explode<Complexity>(res.equation).common_convertibility_with(res); return decltype(explode<Complexity>(res.equation))::common_convertibility_with(res);
} else } else
return explode_result{q}; return explode_result<Q{}>{};
} }
template<typename NumFrom, typename... NumsFrom, typename DenFrom, typename... DensFrom, typename NumTo, template<typename NumFrom, typename... NumsFrom, typename DenFrom, typename... DensFrom, typename NumTo,
@@ -916,8 +907,8 @@ extract_results(bool, From = {}, To = {}, prepend_rest = {}, Elem = {}) -> extra
template<typename From, typename To> template<typename From, typename To>
[[nodiscard]] consteval auto extract_convertible_quantities(From, To) [[nodiscard]] consteval auto extract_convertible_quantities(From, To)
{ {
constexpr auto qfrom = map_power(From{}); constexpr auto qfrom = decltype(map_power(From{})){};
constexpr auto qto = map_power(To{}); constexpr auto qto = decltype(map_power(To{})){};
if constexpr (qfrom.dimension == qto.dimension) { if constexpr (qfrom.dimension == qto.dimension) {
if constexpr (is_specialization_of_power<From> && is_specialization_of_power<To>) { if constexpr (is_specialization_of_power<From> && is_specialization_of_power<To>) {
constexpr auto cr = common_ratio(From::exponent, To::exponent); constexpr auto cr = common_ratio(From::exponent, To::exponent);
@@ -1023,10 +1014,10 @@ template<typename NumFrom, typename... NumsFrom, typename DenFrom, typename... D
return process_extracted<process_entities::to, extT>(num_from, den_from, type_list<NumsTo...>{}, return process_extracted<process_entities::to, extT>(num_from, den_from, type_list<NumsTo...>{},
type_list<DensTo...>{}); type_list<DensTo...>{});
else { else {
constexpr auto num_from_compl = get_complexity(NumFrom{}); constexpr auto num_from_compl = decltype(get_complexity(NumFrom{}))::value;
constexpr auto den_from_compl = get_complexity(DenFrom{}); constexpr auto den_from_compl = decltype(get_complexity(DenFrom{}))::value;
constexpr auto num_to_compl = get_complexity(NumTo{}); constexpr auto num_to_compl = decltype(get_complexity(NumTo{}))::value;
constexpr auto den_to_compl = get_complexity(DenTo{}); constexpr auto den_to_compl = decltype(get_complexity(DenTo{}))::value;
constexpr auto max_compl = max({num_from_compl, num_to_compl, den_from_compl, den_to_compl}); constexpr auto max_compl = max({num_from_compl, num_to_compl, den_from_compl, den_to_compl});
if constexpr (max_compl > 1) { if constexpr (max_compl > 1) {
if constexpr (num_from_compl == max_compl) { if constexpr (num_from_compl == max_compl) {
@@ -1070,9 +1061,9 @@ template<typename DenFrom, typename... DensFrom, typename NumTo, typename... Num
return process_extracted<process_entities::to, extT>(num_from, den_from, type_list<NumsTo...>{}, return process_extracted<process_entities::to, extT>(num_from, den_from, type_list<NumsTo...>{},
type_list<DensTo...>{}); type_list<DensTo...>{});
else { else {
constexpr auto den_from_compl = get_complexity(DenFrom{}); constexpr auto den_from_compl = decltype(get_complexity(DenFrom{}))::value;
constexpr auto num_to_compl = get_complexity(NumTo{}); constexpr auto num_to_compl = decltype(get_complexity(NumTo{}))::value;
constexpr auto den_to_compl = get_complexity(DenTo{}); constexpr auto den_to_compl = decltype(get_complexity(DenTo{}))::value;
constexpr auto max_compl = max({num_to_compl, den_from_compl, den_to_compl}); constexpr auto max_compl = max({num_to_compl, den_from_compl, den_to_compl});
if constexpr (max_compl > 1) { if constexpr (max_compl > 1) {
if constexpr (den_from_compl == max_compl) { if constexpr (den_from_compl == max_compl) {
@@ -1109,9 +1100,9 @@ template<typename NumFrom, typename... NumsFrom, typename NumTo, typename... Num
return process_extracted<process_entities::to, extT>(num_from, den_from, type_list<NumsTo...>{}, return process_extracted<process_entities::to, extT>(num_from, den_from, type_list<NumsTo...>{},
type_list<DensTo...>{}); type_list<DensTo...>{});
else { else {
constexpr auto num_from_compl = get_complexity(NumFrom{}); constexpr auto num_from_compl = decltype(get_complexity(NumFrom{}))::value;
constexpr auto num_to_compl = get_complexity(NumTo{}); constexpr auto num_to_compl = decltype(get_complexity(NumTo{}))::value;
constexpr auto den_to_compl = get_complexity(DenTo{}); constexpr auto den_to_compl = decltype(get_complexity(DenTo{}))::value;
constexpr auto max_compl = max({num_from_compl, num_to_compl, den_to_compl}); constexpr auto max_compl = max({num_from_compl, num_to_compl, den_to_compl});
if constexpr (max_compl > 1) { if constexpr (max_compl > 1) {
if constexpr (num_from_compl == max_compl) { if constexpr (num_from_compl == max_compl) {
@@ -1149,9 +1140,9 @@ template<typename NumFrom, typename... NumsFrom, typename DenFrom, typename... D
return process_extracted<process_entities::from, extF>(type_list<NumsFrom...>{}, type_list<DensFrom...>{}, num_to, return process_extracted<process_entities::from, extF>(type_list<NumsFrom...>{}, type_list<DensFrom...>{}, num_to,
den_to); den_to);
else { else {
constexpr auto num_from_compl = get_complexity(NumFrom{}); constexpr auto num_from_compl = decltype(get_complexity(NumFrom{}))::value;
constexpr auto den_from_compl = get_complexity(DenFrom{}); constexpr auto den_from_compl = decltype(get_complexity(DenFrom{}))::value;
constexpr auto den_to_compl = get_complexity(DenTo{}); constexpr auto den_to_compl = decltype(get_complexity(DenTo{}))::value;
constexpr auto max_compl = max({num_from_compl, den_from_compl, den_to_compl}); constexpr auto max_compl = max({num_from_compl, den_from_compl, den_to_compl});
if constexpr (max_compl > 1) { if constexpr (max_compl > 1) {
if constexpr (num_from_compl == max_compl) { if constexpr (num_from_compl == max_compl) {
@@ -1189,9 +1180,9 @@ template<typename NumFrom, typename... NumsFrom, typename DenFrom, typename... D
return process_extracted<process_entities::from, extF>(type_list<NumsFrom...>{}, type_list<DensFrom...>{}, num_to, return process_extracted<process_entities::from, extF>(type_list<NumsFrom...>{}, type_list<DensFrom...>{}, num_to,
den_to); den_to);
else { else {
constexpr auto num_from_compl = get_complexity(NumFrom{}); constexpr auto num_from_compl = decltype(get_complexity(NumFrom{}))::value;
constexpr auto den_from_compl = get_complexity(DenFrom{}); constexpr auto den_from_compl = decltype(get_complexity(DenFrom{}))::value;
constexpr auto num_to_compl = get_complexity(NumTo{}); constexpr auto num_to_compl = decltype(get_complexity(NumTo{}))::value;
constexpr auto max_compl = max({num_from_compl, num_to_compl, den_from_compl}); constexpr auto max_compl = max({num_from_compl, num_to_compl, den_from_compl});
if constexpr (max_compl > 1) { if constexpr (max_compl > 1) {
if constexpr (num_from_compl == max_compl) { if constexpr (num_from_compl == max_compl) {
@@ -1225,8 +1216,8 @@ template<typename NumFrom, typename... NumsFrom, typename NumTo, typename... Num
return process_extracted<process_entities::numerators, ext>(type_list<NumsFrom...>{}, den_from, return process_extracted<process_entities::numerators, ext>(type_list<NumsFrom...>{}, den_from,
type_list<NumsTo...>{}, den_to); type_list<NumsTo...>{}, den_to);
} else { } else {
constexpr auto num_from_compl = get_complexity(NumFrom{}); constexpr auto num_from_compl = decltype(get_complexity(NumFrom{}))::value;
constexpr auto num_to_compl = get_complexity(NumTo{}); constexpr auto num_to_compl = decltype(get_complexity(NumTo{}))::value;
constexpr auto max_compl = max(num_from_compl, num_to_compl); constexpr auto max_compl = max(num_from_compl, num_to_compl);
if constexpr (max_compl > 1) { if constexpr (max_compl > 1) {
if constexpr (num_from_compl == max_compl) { if constexpr (num_from_compl == max_compl) {
@@ -1253,8 +1244,8 @@ template<typename DenFrom, typename... DensFrom, typename DenTo, typename... Den
return process_extracted<process_entities::denominators, ext>(num_from, type_list<DensFrom...>{}, num_to, return process_extracted<process_entities::denominators, ext>(num_from, type_list<DensFrom...>{}, num_to,
type_list<DensTo...>{}); type_list<DensTo...>{});
else { else {
constexpr auto den_from_compl = get_complexity(DenFrom{}); constexpr auto den_from_compl = decltype(get_complexity(DenFrom{}))::value;
constexpr auto den_to_compl = get_complexity(DenTo{}); constexpr auto den_to_compl = decltype(get_complexity(DenTo{}))::value;
constexpr auto max_compl = max(den_from_compl, den_to_compl); constexpr auto max_compl = max(den_from_compl, den_to_compl);
if constexpr (max_compl > 1) { if constexpr (max_compl > 1) {
if constexpr (den_from_compl == max_compl) { if constexpr (den_from_compl == max_compl) {
@@ -1371,14 +1362,14 @@ template<QuantitySpec From, QuantitySpec To>
return res == no ? no : yes; return res == no ? no : yes;
}; };
if constexpr ((NamedQuantitySpec<decltype(from_kind)> && NamedQuantitySpec<decltype(to_kind)>) || if constexpr ((NamedQuantitySpec<decltype(from_kind)> && NamedQuantitySpec<decltype(to_kind)>) ||
get_complexity(from_kind) == get_complexity(to_kind)) decltype(get_complexity(from_kind))::value == decltype(get_complexity(to_kind))::value)
return convertible_impl(from_kind, to_kind); return convertible_impl(from_kind, to_kind);
else if constexpr (get_complexity(from_kind) > get_complexity(to_kind)) else if constexpr (decltype(get_complexity(from_kind))::value > decltype(get_complexity(to_kind))::value)
return exploded_kind_result( return exploded_kind_result(convertible_impl(
convertible_impl(get_kind_tree_root(explode<get_complexity(to_kind)>(from_kind).quantity), to_kind)); get_kind_tree_root(explode<decltype(get_complexity(to_kind))::value>(from_kind).quantity), to_kind));
else else
return exploded_kind_result( return exploded_kind_result(convertible_impl(
convertible_impl(from_kind, get_kind_tree_root(explode<get_complexity(from_kind)>(to_kind).quantity))); from_kind, get_kind_tree_root(explode<decltype(get_complexity(from_kind))::value>(to_kind).quantity)));
} }
template<NamedQuantitySpec From, NamedQuantitySpec To> template<NamedQuantitySpec From, NamedQuantitySpec To>
@@ -1393,11 +1384,11 @@ template<NamedQuantitySpec From, NamedQuantitySpec To>
return no; return no;
} else if constexpr (get_kind(From{}) != get_kind(To{})) } else if constexpr (get_kind(From{}) != get_kind(To{}))
return no; return no;
else if constexpr (get_complexity(From{}) != get_complexity(To{})) { else if constexpr (decltype(get_complexity(From{}))::value != decltype(get_complexity(To{}))::value) {
if constexpr (get_complexity(From{}) > get_complexity(To{})) if constexpr (decltype(get_complexity(From{}))::value > decltype(get_complexity(To{}))::value)
return convertible_impl(explode<get_complexity(to)>(from).quantity, to); return convertible_impl(explode<decltype(get_complexity(to))::value>(from).quantity, to);
else { else {
auto res = explode<get_complexity(from)>(to); auto res = explode<decltype(get_complexity(from))::value>(to);
return min(res.result, convertible_impl(from, res.quantity)); return min(res.result, convertible_impl(from, res.quantity));
} }
} }
@@ -1422,7 +1413,7 @@ template<QuantitySpec From, QuantitySpec To>
} else if constexpr (DerivedQuantitySpec<From> && DerivedQuantitySpec<To>) { } else if constexpr (DerivedQuantitySpec<From> && DerivedQuantitySpec<To>) {
return are_ingredients_convertible(from, to); return are_ingredients_convertible(from, to);
} else if constexpr (DerivedQuantitySpec<From>) { } else if constexpr (DerivedQuantitySpec<From>) {
auto res = explode<get_complexity(to)>(from); auto res = explode<decltype(get_complexity(to))::value>(from);
if constexpr (NamedQuantitySpec<decltype(res.quantity)>) if constexpr (NamedQuantitySpec<decltype(res.quantity)>)
return convertible_impl(res.quantity, to); return convertible_impl(res.quantity, to);
else if constexpr (requires { to._equation_; }) { else if constexpr (requires { to._equation_; }) {
@@ -1431,7 +1422,7 @@ template<QuantitySpec From, QuantitySpec To>
} else } else
return are_ingredients_convertible(from, to); return are_ingredients_convertible(from, to);
} else if constexpr (DerivedQuantitySpec<To>) { } else if constexpr (DerivedQuantitySpec<To>) {
auto res = explode<get_complexity(from)>(to); auto res = explode<decltype(get_complexity(from))::value>(to);
if constexpr (NamedQuantitySpec<decltype(res.quantity)>) if constexpr (NamedQuantitySpec<decltype(res.quantity)>)
return min(res.result, convertible_impl(from, res.quantity)); return min(res.result, convertible_impl(from, res.quantity));
else if constexpr (requires { from._equation_; }) else if constexpr (requires { from._equation_; })
@@ -1508,8 +1499,8 @@ template<QuantitySpec Q>
} else if constexpr (requires { Q::_parent_; }) { } else if constexpr (requires { Q::_parent_; }) {
return get_kind_tree_root(Q::_parent_); return get_kind_tree_root(Q::_parent_);
} else if constexpr (detail::DerivedQuantitySpec<Q>) { } else if constexpr (detail::DerivedQuantitySpec<Q>) {
return detail::expr_map<detail::to_kind, derived_quantity_spec, struct dimensionless, return decltype(detail::expr_map<detail::to_kind, derived_quantity_spec, struct dimensionless,
detail::type_list_of_quantity_spec_less>(q); detail::type_list_of_quantity_spec_less>(q)){};
} else { } else {
// root quantity // root quantity
return q; return q;