refactor: type_name_less introduced and used as a default predicate for expression templates

This commit is contained in:
Mateusz Pusz
2024-11-26 10:09:28 +01:00
parent 360cf7d540
commit 3b14b588e9
6 changed files with 26 additions and 44 deletions

View File

@@ -80,7 +80,7 @@ template<AssociatedUnit U>
else if constexpr (requires { U::_reference_unit_; }) else if constexpr (requires { U::_reference_unit_; })
return determine_associated_quantity(U::_reference_unit_); return determine_associated_quantity(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 expr_map<to_quantity_spec, derived_quantity_spec, struct dimensionless>(u);
} }
} }

View File

@@ -10,6 +10,7 @@
import std; import std;
#else #else
#include <string_view> #include <string_view>
#include <type_traits>
#endif #endif
#endif #endif
@@ -37,6 +38,8 @@ template<typename T>
return name; return name;
} }
template<typename Lhs, typename Rhs>
struct type_name_less : std::bool_constant<type_name<Lhs>() < type_name<Rhs>()> {};
// This is typically used to deterministically chose one of the alternatives // This is typically used to deterministically chose one of the alternatives
// to guarantee the commutation of the operation (e.g., `a + b` should return // to guarantee the commutation of the operation (e.g., `a + b` should return

View File

@@ -29,7 +29,6 @@
#include <mp-units/compat_macros.h> #include <mp-units/compat_macros.h>
#include <mp-units/ext/fixed_string.h> #include <mp-units/ext/fixed_string.h>
#include <mp-units/ext/inplace_vector.h> #include <mp-units/ext/inplace_vector.h>
#include <mp-units/ext/type_name.h>
#include <mp-units/ext/type_traits.h> #include <mp-units/ext/type_traits.h>
#include <mp-units/framework/dimension_concepts.h> #include <mp-units/framework/dimension_concepts.h>
#include <mp-units/framework/expression_template.h> #include <mp-units/framework/expression_template.h>
@@ -59,12 +58,6 @@ MP_UNITS_EXPORT struct dimension_one;
namespace detail { namespace detail {
template<typename Lhs, typename Rhs>
struct base_dimension_less : std::bool_constant<type_name<Lhs>() < type_name<Rhs>()> {};
template<typename T1, typename T2>
using type_list_of_base_dimension_less = expr_less<T1, T2, base_dimension_less>;
template<typename... Expr> template<typename... Expr>
struct derived_dimension_impl : expr_fractions<dimension_one, Expr...> {}; struct derived_dimension_impl : expr_fractions<dimension_one, Expr...> {};
@@ -72,13 +65,13 @@ struct dimension_interface {
template<Dimension Lhs, Dimension Rhs> template<Dimension Lhs, Dimension Rhs>
[[nodiscard]] friend consteval Dimension auto operator*(Lhs, Rhs) [[nodiscard]] friend consteval Dimension auto operator*(Lhs, Rhs)
{ {
return expr_multiply<derived_dimension, struct dimension_one, type_list_of_base_dimension_less>(Lhs{}, Rhs{}); return expr_multiply<derived_dimension, struct dimension_one>(Lhs{}, Rhs{});
} }
template<Dimension Lhs, Dimension Rhs> template<Dimension Lhs, Dimension Rhs>
[[nodiscard]] friend consteval Dimension auto operator/(Lhs, Rhs) [[nodiscard]] friend consteval Dimension auto operator/(Lhs, Rhs)
{ {
return expr_divide<derived_dimension, struct dimension_one, type_list_of_base_dimension_less>(Lhs{}, Rhs{}); return expr_divide<derived_dimension, struct dimension_one>(Lhs{}, Rhs{});
} }
template<Dimension Lhs, Dimension Rhs> template<Dimension Lhs, Dimension Rhs>
@@ -197,8 +190,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Dimension D>
requires detail::non_zero<Den> requires detail::non_zero<Den>
[[nodiscard]] consteval Dimension auto pow(D d) [[nodiscard]] consteval Dimension auto pow(D d)
{ {
return detail::expr_pow<Num, Den, derived_dimension, struct dimension_one, detail::type_list_of_base_dimension_less>( return detail::expr_pow<Num, Den, derived_dimension, struct dimension_one>(d);
d);
} }
/** /**

View File

@@ -25,6 +25,7 @@
#include <mp-units/bits/math_concepts.h> #include <mp-units/bits/math_concepts.h>
#include <mp-units/bits/ratio.h> #include <mp-units/bits/ratio.h>
#include <mp-units/bits/type_list.h> #include <mp-units/bits/type_list.h>
#include <mp-units/ext/type_name.h>
#include <mp-units/ext/type_traits.h> #include <mp-units/ext/type_traits.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE #ifndef MP_UNITS_IN_MODULE_INTERFACE
@@ -302,6 +303,8 @@ struct expr_less_impl<T, power<T, Ints...>, Pred> : std::true_type {};
template<typename Lhs, typename Rhs, template<typename, typename, auto...> typename Pred> template<typename Lhs, typename Rhs, template<typename, typename, auto...> typename Pred>
using expr_less = expr_less_impl<Lhs, Rhs, Pred>; using expr_less = expr_less_impl<Lhs, Rhs, Pred>;
template<typename T1, typename T2>
using type_list_name_less = expr_less<T1, T2, type_name_less>;
// expr_fractions // expr_fractions
template<typename Num = type_list<>, typename Den = type_list<>> template<typename Num = type_list<>, typename Den = type_list<>>
@@ -387,8 +390,8 @@ template<typename NumList, typename DenList, SymbolicArg OneType, template<typen
* @tparam Lhs lhs of the operation * @tparam Lhs lhs of the operation
* @tparam Rhs rhs of the operation * @tparam Rhs rhs of the operation
*/ */
template<template<typename...> typename To, SymbolicArg OneType, template<typename, typename> typename Pred, template<template<typename...> typename To, SymbolicArg OneType,
typename Lhs, typename Rhs> template<typename, typename> typename Pred = type_list_name_less, typename Lhs, typename Rhs>
[[nodiscard]] MP_UNITS_CONSTEVAL auto expr_multiply(Lhs, Rhs) [[nodiscard]] MP_UNITS_CONSTEVAL auto expr_multiply(Lhs, Rhs)
{ {
if constexpr (is_same_v<Lhs, OneType>) { if constexpr (is_same_v<Lhs, OneType>) {
@@ -422,8 +425,8 @@ template<template<typename...> typename To, SymbolicArg OneType, template<typena
* @tparam Lhs lhs of the operation * @tparam Lhs lhs of the operation
* @tparam Rhs rhs of the operation * @tparam Rhs rhs of the operation
*/ */
template<template<typename...> typename To, SymbolicArg OneType, template<typename, typename> typename Pred, template<template<typename...> typename To, SymbolicArg OneType,
typename Lhs, typename Rhs> template<typename, typename> typename Pred = type_list_name_less, typename Lhs, typename Rhs>
[[nodiscard]] MP_UNITS_CONSTEVAL auto expr_divide(Lhs lhs, Rhs rhs) [[nodiscard]] MP_UNITS_CONSTEVAL auto expr_divide(Lhs lhs, Rhs rhs)
{ {
if constexpr (is_same_v<Lhs, Rhs>) { if constexpr (is_same_v<Lhs, Rhs>) {
@@ -489,7 +492,7 @@ template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To
* @tparam T Expression being the base of the operation * @tparam T Expression being the base of the operation
*/ */
template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To, SymbolicArg OneType, template<std::intmax_t Num, std::intmax_t Den, template<typename...> typename To, SymbolicArg OneType,
template<typename, typename> typename Pred, typename T> template<typename, typename> typename Pred = type_list_name_less, typename T>
requires detail::non_zero<Den> requires detail::non_zero<Den>
[[nodiscard]] consteval auto expr_pow(T v) [[nodiscard]] consteval auto expr_pow(T v)
{ {
@@ -552,7 +555,7 @@ template<template<typename> typename Proj, template<typename...> typename To, Sy
* @tparam T expression template to map from * @tparam T expression template to map from
*/ */
template<template<typename> typename Proj, template<typename...> typename To, SymbolicArg OneType, template<template<typename> typename Proj, template<typename...> typename To, SymbolicArg OneType,
template<typename, typename> typename Pred, typename T> template<typename, typename> typename Pred = type_list_name_less, typename T>
[[nodiscard]] consteval auto expr_map(T) [[nodiscard]] consteval auto expr_map(T)
{ {
if constexpr (type_list_size<typename T::_num_> + type_list_size<typename T::_den_> == 0) if constexpr (type_list_size<typename T::_num_> + type_list_size<typename T::_den_> == 0)

View File

@@ -106,12 +106,6 @@ template<auto... Args>
return ch; return ch;
} }
template<NamedQuantitySpec Lhs, NamedQuantitySpec Rhs>
struct quantity_spec_less : std::bool_constant<type_name<Lhs>() < type_name<Rhs>()> {};
template<typename T1, typename T2>
using type_list_of_quantity_spec_less = expr_less<T1, T2, quantity_spec_less>;
template<NamedQuantitySpec Q> template<NamedQuantitySpec Q>
requires requires { Q::dimension; } requires requires { Q::dimension; }
using to_dimension = MP_UNITS_NONCONST_TYPE(Q::dimension); using to_dimension = MP_UNITS_NONCONST_TYPE(Q::dimension);
@@ -127,16 +121,14 @@ struct quantity_spec_interface_base {
[[nodiscard]] friend consteval QuantitySpec auto operator*(Lhs lhs, Rhs rhs) [[nodiscard]] friend consteval QuantitySpec auto operator*(Lhs lhs, Rhs rhs)
{ {
return clone_kind_of<Lhs{}, Rhs{}>( return clone_kind_of<Lhs{}, Rhs{}>(
expr_multiply<derived_quantity_spec, struct dimensionless, type_list_of_quantity_spec_less>(remove_kind(lhs), expr_multiply<derived_quantity_spec, struct dimensionless>(remove_kind(lhs), remove_kind(rhs)));
remove_kind(rhs)));
} }
template<QuantitySpec Lhs, QuantitySpec Rhs> template<QuantitySpec Lhs, QuantitySpec Rhs>
[[nodiscard]] friend consteval QuantitySpec auto operator/(Lhs lhs, Rhs rhs) [[nodiscard]] friend consteval QuantitySpec auto operator/(Lhs lhs, Rhs rhs)
{ {
return clone_kind_of<Lhs{}, Rhs{}>( return clone_kind_of<Lhs{}, Rhs{}>(
expr_divide<derived_quantity_spec, struct dimensionless, type_list_of_quantity_spec_less>(remove_kind(lhs), expr_divide<derived_quantity_spec, struct dimensionless>(remove_kind(lhs), remove_kind(rhs)));
remove_kind(rhs)));
} }
template<QuantitySpec Lhs, QuantitySpec Rhs> template<QuantitySpec Lhs, QuantitySpec Rhs>
@@ -433,8 +425,7 @@ struct derived_quantity_spec_impl :
using _base_type_ = derived_quantity_spec_impl; using _base_type_ = derived_quantity_spec_impl;
using _base_ = expr_fractions<dimensionless, Expr...>; using _base_ = expr_fractions<dimensionless, Expr...>;
static constexpr Dimension auto dimension = static constexpr Dimension auto dimension = expr_map<to_dimension, derived_dimension, struct dimension_one>(_base_{});
expr_map<to_dimension, derived_dimension, struct dimension_one, type_list_of_base_dimension_less>(_base_{});
static constexpr quantity_character character = static constexpr quantity_character character =
derived_quantity_character(typename _base_::_num_{}, typename _base_::_den_{}); derived_quantity_character(typename _base_::_num_{}, typename _base_::_den_{});
}; };
@@ -563,8 +554,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, QuantitySpec Q>
[[nodiscard]] consteval QuantitySpec auto pow(Q q) [[nodiscard]] consteval QuantitySpec auto pow(Q 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::remove_kind(q)));
detail::remove_kind(q)));
} }
@@ -1526,7 +1516,7 @@ 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 (DerivedQuantitySpec<Q>) { } else if constexpr (DerivedQuantitySpec<Q>) {
return expr_map<to_kind, derived_quantity_spec, struct dimensionless, type_list_of_quantity_spec_less>(q); return expr_map<to_kind, derived_quantity_spec, struct dimensionless>(q);
} else { } else {
// root quantity // root quantity
return q; return q;

View File

@@ -152,12 +152,6 @@ struct derived_unit;
namespace detail { namespace detail {
template<Unit Lhs, Unit Rhs>
struct unit_less : std::bool_constant<type_name<Lhs>() < type_name<Rhs>()> {};
template<typename T1, typename T2>
using type_list_of_unit_less = expr_less<T1, T2, unit_less>;
struct unit_interface { struct unit_interface {
/** /**
* Multiplication by `1` returns the same unit, otherwise `scaled_unit` is being returned. * Multiplication by `1` returns the same unit, otherwise `scaled_unit` is being returned.
@@ -200,7 +194,7 @@ struct unit_interface {
template<Unit Lhs, Unit Rhs> template<Unit Lhs, Unit Rhs>
[[nodiscard]] friend MP_UNITS_CONSTEVAL Unit auto operator*(Lhs lhs, Rhs rhs) [[nodiscard]] friend MP_UNITS_CONSTEVAL Unit auto operator*(Lhs lhs, Rhs rhs)
{ {
return expr_multiply<derived_unit, struct one, type_list_of_unit_less>(lhs, rhs); return expr_multiply<derived_unit, struct one>(lhs, rhs);
} }
/** /**
@@ -211,7 +205,7 @@ struct unit_interface {
template<Unit Lhs, Unit Rhs> template<Unit Lhs, Unit Rhs>
[[nodiscard]] friend MP_UNITS_CONSTEVAL Unit auto operator/(Lhs lhs, Rhs rhs) [[nodiscard]] friend MP_UNITS_CONSTEVAL Unit auto operator/(Lhs lhs, Rhs rhs)
{ {
return expr_divide<derived_unit, struct one, type_list_of_unit_less>(lhs, rhs); return expr_divide<derived_unit, struct one>(lhs, rhs);
} }
template<Unit Lhs, Unit Rhs> template<Unit Lhs, Unit Rhs>
@@ -621,7 +615,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
requires detail::non_zero<Den> requires detail::non_zero<Den>
[[nodiscard]] consteval Unit auto pow(U u) [[nodiscard]] consteval Unit auto pow(U u)
{ {
return detail::expr_pow<Num, Den, derived_unit, struct one, detail::type_list_of_unit_less>(u); return detail::expr_pow<Num, Den, derived_unit, struct one>(u);
} }
/** /**
@@ -696,7 +690,7 @@ template<Unit U1, Unit U2>
else if constexpr (is_positive_integral_power(canonical_rhs.mag / canonical_lhs.mag)) else if constexpr (is_positive_integral_power(canonical_rhs.mag / canonical_lhs.mag))
return u1; return u1;
else { else {
if constexpr (detail::unit_less<U1, U2>::value) if constexpr (detail::type_name_less<U1, U2>::value)
return common_unit<U1, U2>{}; return common_unit<U1, U2>{};
else else
return common_unit<U2, U1>{}; return common_unit<U2, U1>{};
@@ -730,7 +724,7 @@ struct collapse_common_unit_impl<List, NewUnit, true> {
template<Unit NewUnit, Unit... Us> template<Unit NewUnit, Unit... Us>
using collapse_common_unit = type_list_unique< using collapse_common_unit = type_list_unique<
type_list_sort<typename collapse_common_unit_impl<type_list<>, NewUnit, false, Us...>::type, type_list_of_unit_less>>; type_list_sort<typename collapse_common_unit_impl<type_list<>, NewUnit, false, Us...>::type, type_list_name_less>>;
} // namespace detail } // namespace detail