refactor: get_associated_quantity and quantity spec hierarchy traversing compile-times improved

This commit is contained in:
Mateusz Pusz
2024-06-13 12:29:12 +02:00
parent 5f67523a8a
commit f63c4eec4a
3 changed files with 39 additions and 35 deletions

View File

@@ -34,24 +34,25 @@ template<AssociatedUnit U>
template<typename U, auto... Vs> template<typename U, auto... Vs>
[[nodiscard]] consteval auto all_are_kinds(power<U, Vs...>) [[nodiscard]] consteval auto all_are_kinds(power<U, Vs...>)
{ {
return all_are_kinds(U{}); return decltype(all_are_kinds(U{})){};
} }
template<typename... Nums, typename... Dens> template<typename... Nums, typename... Dens>
[[nodiscard]] consteval bool all_are_kinds(type_list<Nums...>, type_list<Dens...>) [[nodiscard]] consteval auto all_are_kinds(type_list<Nums...>, type_list<Dens...>)
{ {
return (... && all_are_kinds(Nums{})) && (... && all_are_kinds(Dens{})); return std::bool_constant<((... && decltype(all_are_kinds(Nums{}))::value) &&
(... && decltype(all_are_kinds(Dens{}))::value))>{};
} }
template<AssociatedUnit U> template<AssociatedUnit U>
[[nodiscard]] consteval auto all_are_kinds(U) [[nodiscard]] consteval auto all_are_kinds(U)
{ {
if constexpr (requires { U::quantity_spec; }) if constexpr (requires { U::quantity_spec; })
return QuantityKindSpec<std::remove_const_t<decltype(U::quantity_spec)>>; return std::bool_constant<QuantityKindSpec<std::remove_const_t<decltype(U::quantity_spec)>>>{};
else if constexpr (requires { U::reference_unit; }) else if constexpr (requires { U::reference_unit; })
return all_are_kinds(U::reference_unit); return decltype(all_are_kinds(U::reference_unit)){};
else if constexpr (requires { typename U::_num_; }) { else if constexpr (requires { typename U::_num_; }) {
return all_are_kinds(typename U::_num_{}, typename U::_den_{}); return decltype(all_are_kinds(typename U::_num_{}, typename U::_den_{})){};
} }
} }
@@ -67,20 +68,21 @@ template<AssociatedUnit U>
if constexpr (requires { U::quantity_spec; }) if constexpr (requires { U::quantity_spec; })
return remove_kind(U::quantity_spec); return remove_kind(U::quantity_spec);
else if constexpr (requires { U::reference_unit; }) else if constexpr (requires { U::reference_unit; })
return get_associated_quantity_impl(U::reference_unit); return decltype(get_associated_quantity_impl(U::reference_unit)){};
else if constexpr (requires { typename U::_num_; }) { else if constexpr (requires { typename U::_num_; }) {
return expr_map<to_quantity_spec, derived_quantity_spec, struct dimensionless, type_list_of_quantity_spec_less>(u); return decltype(expr_map<to_quantity_spec, derived_quantity_spec, struct dimensionless,
type_list_of_quantity_spec_less>(u)){};
} }
} }
template<AssociatedUnit U> template<AssociatedUnit U>
[[nodiscard]] consteval auto get_associated_quantity(U u) [[nodiscard]] consteval auto get_associated_quantity(U u)
{ {
constexpr bool all_kinds = all_are_kinds(u); constexpr bool all_kinds = decltype(all_are_kinds(u)){};
if constexpr (all_kinds) if constexpr (all_kinds)
return kind_of<get_associated_quantity_impl(u)>; return kind_of<decltype(get_associated_quantity_impl(u)){}>;
else else
return get_associated_quantity_impl(u); return decltype(get_associated_quantity_impl(u)){};
} }
} // namespace mp_units::detail } // namespace mp_units::detail

View File

@@ -26,12 +26,12 @@
namespace mp_units::detail { namespace mp_units::detail {
[[nodiscard]] consteval std::size_t hierarchy_path_length(QuantitySpec auto q) [[nodiscard]] consteval auto hierarchy_path_length(QuantitySpec auto q)
{ {
if constexpr (requires { q._parent_; }) if constexpr (requires { q._parent_; })
return hierarchy_path_length(q._parent_) + 1; return std::integral_constant<std::size_t, decltype(hierarchy_path_length(q._parent_))::value + 1>{};
else else
return 1; return std::integral_constant<std::size_t, 1>{};
} }
template<std::size_t Offset> template<std::size_t Offset>
@@ -41,51 +41,53 @@ template<std::size_t Offset>
if constexpr (Offset == 0) if constexpr (Offset == 0)
return q; return q;
else if constexpr (requires { q._parent_; }) else if constexpr (requires { q._parent_; })
return hierarchy_path_advance<Offset - 1>(q._parent_); return decltype(hierarchy_path_advance<Offset - 1>(q._parent_)){};
} }
template<QuantitySpec A, QuantitySpec B> template<QuantitySpec A, QuantitySpec B>
[[nodiscard]] consteval bool have_common_base_in_hierarchy_of_equal_length(A a, B b) [[nodiscard]] consteval auto have_common_base_in_hierarchy_of_equal_length(A a, B b)
{ {
if constexpr (is_same_v<A, B>) if constexpr (is_same_v<A, B>)
return true; return std::true_type{};
else if constexpr (requires { a._parent_; }) else if constexpr (requires { a._parent_; })
return have_common_base_in_hierarchy_of_equal_length(a._parent_, b._parent_); return decltype(have_common_base_in_hierarchy_of_equal_length(a._parent_, b._parent_)){};
else else
return false; return std::false_type{};
} }
template<QuantitySpec A, QuantitySpec B> template<QuantitySpec A, QuantitySpec B>
[[nodiscard]] consteval auto have_common_base(A a, B b) [[nodiscard]] consteval auto have_common_base(A a, B b)
{ {
constexpr std::size_t a_length = hierarchy_path_length(A{}); constexpr std::size_t a_length = decltype(hierarchy_path_length(A{}))::value;
constexpr std::size_t b_length = hierarchy_path_length(B{}); constexpr std::size_t b_length = decltype(hierarchy_path_length(B{}))::value;
if constexpr (a_length > b_length) if constexpr (a_length > b_length)
return have_common_base_in_hierarchy_of_equal_length(hierarchy_path_advance<a_length - b_length>(a), b); return decltype(have_common_base_in_hierarchy_of_equal_length(
decltype(hierarchy_path_advance<a_length - b_length>(a)){}, b)){};
else else
return have_common_base_in_hierarchy_of_equal_length(a, hierarchy_path_advance<b_length - a_length>(b)); return decltype(have_common_base_in_hierarchy_of_equal_length(
a, decltype(hierarchy_path_advance<b_length - a_length>(b)){})){};
} }
template<QuantitySpec A, QuantitySpec B> template<QuantitySpec A, QuantitySpec B>
requires(have_common_base_in_hierarchy_of_equal_length(A{}, B{})) requires(decltype(have_common_base_in_hierarchy_of_equal_length(A{}, B{}))::value)
[[nodiscard]] consteval auto get_common_base_for_hierarchy_of_equal_length(A a, B b) [[nodiscard]] consteval QuantitySpec auto get_common_base_for_hierarchy_of_equal_length(A a, B b)
{ {
if constexpr (is_same_v<A, B>) if constexpr (is_same_v<A, B>)
return a; return a;
else else
return get_common_base_for_hierarchy_of_equal_length(a._parent_, b._parent_); return decltype(get_common_base_for_hierarchy_of_equal_length(a._parent_, b._parent_)){};
} }
template<QuantitySpec A, QuantitySpec B> template<QuantitySpec A, QuantitySpec B>
requires(have_common_base(A{}, B{})) requires(decltype(have_common_base(A{}, B{}))::value)
[[nodiscard]] consteval auto get_common_base(A a, B b) [[nodiscard]] consteval QuantitySpec auto get_common_base(A a, B b)
{ {
constexpr int a_length = hierarchy_path_length(A{}); constexpr std::size_t a_length = decltype(hierarchy_path_length(A{}))::value;
constexpr int b_length = hierarchy_path_length(B{}); constexpr std::size_t b_length = decltype(hierarchy_path_length(B{}))::value;
if constexpr (a_length > b_length) if constexpr (a_length > b_length)
return get_common_base_for_hierarchy_of_equal_length(hierarchy_path_advance<a_length - b_length>(a), b); return decltype(get_common_base_for_hierarchy_of_equal_length(hierarchy_path_advance<a_length - b_length>(a), b)){};
else else
return get_common_base_for_hierarchy_of_equal_length(a, hierarchy_path_advance<b_length - a_length>(b)); return decltype(get_common_base_for_hierarchy_of_equal_length(a, hierarchy_path_advance<b_length - a_length>(b))){};
} }
template<QuantitySpec Child, QuantitySpec Parent> template<QuantitySpec Child, QuantitySpec Parent>
@@ -94,8 +96,8 @@ template<QuantitySpec Child, QuantitySpec Parent>
if constexpr (Child{} == Parent{}) if constexpr (Child{} == Parent{})
return std::true_type{}; return std::true_type{};
else { else {
constexpr auto child_length = hierarchy_path_length(Child{}); constexpr std::size_t child_length = decltype(hierarchy_path_length(Child{}))::value;
constexpr auto parent_length = hierarchy_path_length(Parent{}); constexpr std::size_t parent_length = decltype(hierarchy_path_length(Parent{}))::value;
if constexpr (parent_length > child_length) if constexpr (parent_length > child_length)
return std::false_type{}; return std::false_type{};
else else

View File

@@ -46,7 +46,7 @@ MP_UNITS_EXPORT_BEGIN
[[nodiscard]] consteval QuantitySpec auto get_quantity_spec(AssociatedUnit auto u) [[nodiscard]] consteval QuantitySpec auto get_quantity_spec(AssociatedUnit auto u)
{ {
return detail::get_associated_quantity(u); return decltype(detail::get_associated_quantity(u)){};
} }
/** /**