refactor: get_kind() now returns kind_of

This commit is contained in:
Mateusz Pusz
2024-02-13 20:23:03 +01:00
parent f16ac802b3
commit 202c1d10da
2 changed files with 51 additions and 39 deletions

View File

@@ -130,7 +130,7 @@ concept QuantitySpec =
detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T> || detail::QuantityKindSpec<T>; detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T> || detail::QuantityKindSpec<T>;
template<QuantitySpec Q> template<QuantitySpec Q>
[[nodiscard]] consteval QuantitySpec auto get_kind(Q q); [[nodiscard]] consteval detail::QuantityKindSpec auto get_kind(Q q);
namespace detail { namespace detail {
@@ -138,7 +138,7 @@ template<auto To, auto From>
concept NestedQuantityKindSpecOf = concept NestedQuantityKindSpecOf =
QuantitySpec<std::remove_const_t<decltype(From)>> && QuantitySpec<std::remove_const_t<decltype(To)>> && QuantitySpec<std::remove_const_t<decltype(From)>> && QuantitySpec<std::remove_const_t<decltype(To)>> &&
get_kind(From) != get_kind(To) && get_kind(From) != get_kind(To) &&
std::derived_from<std::remove_cvref_t<decltype(To)>, std::remove_cvref_t<decltype(get_kind(From))>>; std::derived_from<std::remove_cvref_t<decltype(To)>, std::remove_cvref_t<decltype(get_kind(From)._quantity_spec_)>>;
} }

View File

@@ -444,11 +444,15 @@ namespace detail {
template<typename T> template<typename T>
concept QuantitySpecWithNoSpecifiers = detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T>; concept QuantitySpecWithNoSpecifiers = detail::NamedQuantitySpec<T> || detail::IntermediateDerivedQuantitySpec<T>;
template<QuantitySpec Q>
[[nodiscard]] consteval QuantitySpec auto get_kind_tree_root(Q q);
} // namespace detail } // namespace detail
#ifdef __cpp_explicit_this_parameter #ifdef __cpp_explicit_this_parameter
template<auto Q> template<auto Q>
requires(detail::QuantitySpecWithNoSpecifiers<std::remove_const_t<decltype(Q)>>) && (get_kind(Q) == Q) requires(detail::QuantitySpecWithNoSpecifiers<std::remove_const_t<decltype(Q)>>) &&
(detail::detail::get_kind_tree_root(Q) == Q)
struct kind_of_<Q> : std::remove_const_t<decltype(Q)> { struct kind_of_<Q> : std::remove_const_t<decltype(Q)> {
static constexpr auto _quantity_spec_ = Q; static constexpr auto _quantity_spec_ = Q;
}; };
@@ -456,10 +460,11 @@ struct kind_of_<Q> : std::remove_const_t<decltype(Q)> {
#if MP_UNITS_COMP_CLANG #if MP_UNITS_COMP_CLANG
template<auto Q> template<auto Q>
requires detail::QuantitySpecWithNoSpecifiers<std::remove_cvref_t<decltype(Q)>> && (get_kind(Q) == Q) requires detail::QuantitySpecWithNoSpecifiers<std::remove_cvref_t<decltype(Q)>> &&
(detail::get_kind_tree_root(Q) == Q)
#else #else
template<detail::QuantitySpecWithNoSpecifiers auto Q> template<detail::QuantitySpecWithNoSpecifiers auto Q>
requires(get_kind(Q) == Q) requires(detail::get_kind_tree_root(Q) == Q)
#endif #endif
struct kind_of_<Q> : quantity_spec<kind_of_<Q>, Q> { struct kind_of_<Q> : quantity_spec<kind_of_<Q>, Q> {
static constexpr auto _quantity_spec_ = Q; static constexpr auto _quantity_spec_ = Q;
@@ -467,7 +472,7 @@ struct kind_of_<Q> : quantity_spec<kind_of_<Q>, Q> {
#endif #endif
template<detail::QuantitySpecWithNoSpecifiers auto Q> template<detail::QuantitySpecWithNoSpecifiers auto Q>
requires(get_kind(Q) == Q) requires(detail::get_kind_tree_root(Q) == Q)
inline constexpr kind_of_<Q> kind_of; inline constexpr kind_of_<Q> kind_of;
namespace detail { namespace detail {
@@ -484,6 +489,15 @@ template<QuantitySpec auto... From, QuantitySpec Q>
return q; return q;
} }
template<QuantitySpec Q>
[[nodiscard]] consteval auto remove_kind(Q q)
{
if constexpr (detail::QuantityKindSpec<Q>)
return Q::_quantity_spec_;
else
return q;
}
} // namespace detail } // namespace detail
// Operators // Operators
@@ -493,7 +507,7 @@ template<QuantitySpec Lhs, QuantitySpec Rhs>
{ {
return detail::clone_kind_of<Lhs{}, Rhs{}>( return detail::clone_kind_of<Lhs{}, Rhs{}>(
detail::expr_multiply<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>( detail::expr_multiply<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
remove_kind(lhs), remove_kind(rhs))); detail::remove_kind(lhs), detail::remove_kind(rhs)));
} }
template<QuantitySpec Lhs, QuantitySpec Rhs> template<QuantitySpec Lhs, QuantitySpec Rhs>
@@ -501,7 +515,7 @@ template<QuantitySpec Lhs, QuantitySpec 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>( detail::expr_divide<derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
remove_kind(lhs), remove_kind(rhs))); detail::remove_kind(lhs), detail::remove_kind(rhs)));
} }
template<QuantitySpec Lhs, QuantitySpec Rhs> template<QuantitySpec Lhs, QuantitySpec Rhs>
@@ -538,13 +552,13 @@ template<std::intmax_t Num, std::intmax_t Den = 1, QuantitySpec Q>
else if constexpr (detail::IntermediateDerivedQuantitySpec<Q>) else if constexpr (detail::IntermediateDerivedQuantitySpec<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>( detail::expr_pow<Num, Den, derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
remove_kind(q))); detail::remove_kind(q)));
else if constexpr (Den == 1) else if constexpr (Den == 1)
return detail::clone_kind_of<Q{}>( return detail::clone_kind_of<Q{}>(
derived_quantity_spec<power<std::remove_const_t<decltype(remove_kind(Q{}))>, Num>>{}); derived_quantity_spec<power<std::remove_const_t<decltype(detail::remove_kind(Q{}))>, Num>>{});
else else
return detail::clone_kind_of<Q{}>( return detail::clone_kind_of<Q{}>(
derived_quantity_spec<power<std::remove_const_t<decltype(remove_kind(Q{}))>, Num, Den>>{}); derived_quantity_spec<power<std::remove_const_t<decltype(detail::remove_kind(Q{}))>, Num, Den>>{});
} }
@@ -1315,8 +1329,8 @@ template<QuantitySpec From, QuantitySpec To>
else if constexpr (From{} == To{}) else if constexpr (From{} == To{})
return yes; return yes;
else if constexpr (QuantityKindSpec<From> || QuantityKindSpec<To>) { else if constexpr (QuantityKindSpec<From> || QuantityKindSpec<To>) {
constexpr auto from_kind = get_kind(From{}); constexpr auto from_kind = get_kind_tree_root(From{});
constexpr auto to_kind = get_kind(To{}); constexpr auto to_kind = get_kind_tree_root(To{});
constexpr auto exploded_kind_result = [](specs_convertible_result res) { constexpr auto exploded_kind_result = [](specs_convertible_result res) {
using enum specs_convertible_result; using enum specs_convertible_result;
return res == no ? no : yes; return res == no ? no : yes;
@@ -1327,11 +1341,11 @@ template<QuantitySpec From, QuantitySpec To>
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 (get_complexity(from_kind) > get_complexity(to_kind))
return exploded_kind_result( return exploded_kind_result(
convertible_impl(get_kind(explode<get_complexity(to_kind)>(from_kind).quantity), to_kind)); convertible_impl(get_kind_tree_root(explode<get_complexity(to_kind)>(from_kind).quantity), to_kind));
else else
return exploded_kind_result( return exploded_kind_result(
convertible_impl(from_kind, get_kind(explode<get_complexity(from_kind)>(to_kind).quantity))); convertible_impl(from_kind, get_kind_tree_root(explode<get_complexity(from_kind)>(to_kind).quantity)));
} else if constexpr (NestedQuantityKindSpecOf<get_kind(To{}), from> && get_kind(To{}) == To{}) } else if constexpr (NestedQuantityKindSpecOf<get_kind_tree_root(To{}), from> && get_kind_tree_root(To{}) == To{})
return yes; return yes;
else if constexpr (NamedQuantitySpec<From> && NamedQuantitySpec<To>) { else if constexpr (NamedQuantitySpec<From> && NamedQuantitySpec<To>) {
if constexpr (have_common_base(From{}, To{})) { if constexpr (have_common_base(From{}, To{})) {
@@ -1401,8 +1415,8 @@ template<QuantitySpec QS1, QuantitySpec QS2>
namespace detail { namespace detail {
template<QuantitySpec Q> template<QuantitySpec Q>
requires requires(Q q) { get_kind(q); } requires requires(Q q) { get_kind_tree_root(q); }
using to_kind = std::remove_const_t<decltype(get_kind(Q{}))>; using to_kind = std::remove_const_t<decltype(get_kind_tree_root(Q{}))>;
#ifdef __cpp_explicit_this_parameter #ifdef __cpp_explicit_this_parameter
template<NamedQuantitySpec auto QS, auto... Args> template<NamedQuantitySpec auto QS, auto... Args>
@@ -1415,19 +1429,8 @@ template<typename Self, NamedQuantitySpec auto QS, auto... Args>
return contains<struct is_kind, Args...>(); return contains<struct is_kind, Args...>();
} }
} // namespace detail
template<QuantitySpec Q> template<QuantitySpec Q>
[[nodiscard]] consteval auto remove_kind(Q q) [[nodiscard]] consteval QuantitySpec auto get_kind_tree_root(Q q)
{
if constexpr (detail::QuantityKindSpec<Q>)
return Q::_quantity_spec_;
else
return q;
}
template<QuantitySpec Q>
[[nodiscard]] consteval QuantitySpec auto get_kind(Q q)
{ {
auto defined_as_kind = []<typename QQ>(QQ qq) { auto defined_as_kind = []<typename QQ>(QQ qq) {
if constexpr (requires { detail::defined_as_kind(qq); }) if constexpr (requires { detail::defined_as_kind(qq); })
@@ -1441,7 +1444,7 @@ template<QuantitySpec Q>
} else if constexpr (defined_as_kind(Q{})) { } else if constexpr (defined_as_kind(Q{})) {
return q; return q;
} else if constexpr (requires { Q::_parent_; }) { } else if constexpr (requires { Q::_parent_; }) {
return get_kind(Q::_parent_); return get_kind_tree_root(Q::_parent_);
} else if constexpr (detail::IntermediateDerivedQuantitySpec<Q>) { } else if constexpr (detail::IntermediateDerivedQuantitySpec<Q>) {
return detail::expr_map<detail::to_kind, derived_quantity_spec, struct dimensionless, return 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);
@@ -1451,20 +1454,29 @@ template<QuantitySpec Q>
} }
} }
} // namespace detail
template<QuantitySpec Q>
[[nodiscard]] consteval detail::QuantityKindSpec auto get_kind(Q q)
{
return kind_of<detail::get_kind_tree_root(q)>;
}
[[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q) { return q; } [[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q) { return q; }
template<QuantitySpec Q1, QuantitySpec Q2> template<QuantitySpec Q1, QuantitySpec Q2>
[[nodiscard]] consteval QuantitySpec auto common_quantity_spec(Q1 q1, Q2 q2) [[nodiscard]] consteval QuantitySpec auto common_quantity_spec(Q1 q1, Q2 q2)
requires(implicitly_convertible(get_kind(q1), get_kind(q2)) || implicitly_convertible(get_kind(q2), get_kind(q1))) requires(implicitly_convertible(get_kind_tree_root(q1), get_kind_tree_root(q2)) ||
implicitly_convertible(get_kind_tree_root(q2), get_kind_tree_root(q1)))
{ {
using QQ1 = std::remove_const_t<decltype(remove_kind(q1))>; using QQ1 = std::remove_const_t<decltype(detail::remove_kind(q1))>;
using QQ2 = std::remove_const_t<decltype(remove_kind(q2))>; using QQ2 = std::remove_const_t<decltype(detail::remove_kind(q2))>;
if constexpr (is_same_v<Q1, Q2>) if constexpr (is_same_v<Q1, Q2>)
return q1; return q1;
else if constexpr (detail::NestedQuantityKindSpecOf<Q1{}, Q2{}>) else if constexpr (detail::NestedQuantityKindSpecOf<Q1{}, Q2{}>)
return remove_kind(q1); return detail::remove_kind(q1);
else if constexpr (detail::NestedQuantityKindSpecOf<Q2{}, Q1{}>) else if constexpr (detail::NestedQuantityKindSpecOf<Q2{}, Q1{}>)
return remove_kind(q2); return detail::remove_kind(q2);
else if constexpr ((detail::QuantityKindSpec<Q1> && !detail::QuantityKindSpec<Q2>) || else if constexpr ((detail::QuantityKindSpec<Q1> && !detail::QuantityKindSpec<Q2>) ||
(detail::IntermediateDerivedQuantitySpec<QQ1> && detail::NamedQuantitySpec<QQ2> && (detail::IntermediateDerivedQuantitySpec<QQ1> && detail::NamedQuantitySpec<QQ2> &&
implicitly_convertible(Q1{}, Q2{}))) implicitly_convertible(Q1{}, Q2{})))
@@ -1479,10 +1491,10 @@ template<QuantitySpec Q1, QuantitySpec Q2>
return q2; return q2;
else if constexpr (implicitly_convertible(Q2{}, Q1{})) else if constexpr (implicitly_convertible(Q2{}, Q1{}))
return q1; return q1;
else if constexpr (implicitly_convertible(get_kind(Q1{}), get_kind(Q2{}))) else if constexpr (implicitly_convertible(get_kind_tree_root(Q1{}), get_kind_tree_root(Q2{})))
return get_kind(q2); return get_kind_tree_root(q2);
else else
return get_kind(q1); return get_kind_tree_root(q1);
} }
[[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q1, QuantitySpec auto q2, [[nodiscard]] consteval QuantitySpec auto common_quantity_spec(QuantitySpec auto q1, QuantitySpec auto q2,