From 6e8ca7267846625be8ed2a8694d1d59fe121e8e5 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 18 Oct 2022 17:45:32 +0200 Subject: [PATCH] refactor: dimensions design cleanup --- src/core/include/units/dimension.h | 44 +++++++--- src/core/include/units/magnitude.h | 15 ++-- src/core/include/units/quantity.h | 4 +- src/core/include/units/quantity_cast.h | 7 +- src/core/include/units/reference.h | 16 ++-- test/unit_test/static/dimension_test.cpp | 102 +++++++++++++++++------ 6 files changed, 133 insertions(+), 55 deletions(-) diff --git a/src/core/include/units/dimension.h b/src/core/include/units/dimension.h index d8d5f7b6..6aa81a26 100644 --- a/src/core/include/units/dimension.h +++ b/src/core/include/units/dimension.h @@ -104,19 +104,41 @@ using type_list_of_base_dimension_less = expr_less; template inline constexpr bool is_one_dim = false; +template +inline constexpr bool is_power_of_dim = + requires { + requires is_specialization_of_power && (BaseDimension || is_one_dim); + }; + +template +inline constexpr bool is_per_of_dims = false; + +template +inline constexpr bool is_per_of_dims> = + (... && (BaseDimension || is_one_dim || is_power_of_dim)); + } // namespace detail -// TODO add checking for `per` and power elements as well template concept DimensionSpec = - BaseDimension || detail::is_one_dim || is_specialization_of || detail::is_specialization_of_power; + BaseDimension || detail::is_one_dim || detail::is_power_of_dim || detail::is_per_of_dims; + +template +struct derived_dimension; + +namespace detail { + +template +struct derived_dimension_impl : detail::expr_fractions, Ds...> { + using _type_ = derived_dimension; // exposition only +}; + +} // namespace detail // User should not instantiate this type!!! // It should not be exported from the module template -struct derived_dimension : detail::expr_fractions, Ds...> { - using type = derived_dimension; -}; +struct derived_dimension : detail::derived_dimension_impl {}; namespace detail { @@ -154,7 +176,7 @@ struct dim_type_impl { template struct dim_type_impl { - using type = T::type; + using type = T::_type_; }; template @@ -189,11 +211,11 @@ template return is_same_v; } -template -[[nodiscard]] consteval bool equivalent(D1, D2) -{ - return is_same_v, detail::dim_type>; -} +// template +// [[nodiscard]] consteval bool equivalent(D1, D2) +// { +// return is_same_v, detail::dim_type>; +// } template [[nodiscard]] consteval bool convertible(D1, D2) diff --git a/src/core/include/units/magnitude.h b/src/core/include/units/magnitude.h index f81da0c5..c45c40a9 100644 --- a/src/core/include/units/magnitude.h +++ b/src/core/include/units/magnitude.h @@ -514,15 +514,12 @@ inline constexpr struct mag_pi : magnitude> { //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Magnitude equality implementation. -// template -// constexpr bool operator==(magnitude, magnitude) -// { -// if constexpr (sizeof...(LeftBPs) == sizeof...(RightBPs)) { -// return ((LeftBPs == RightBPs) && ...); -// } else { -// return false; -// } -// } +template +[[nodiscard]] consteval bool operator==(M1, M2) +{ + return std::is_same_v; +} + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Magnitude rational powers implementation. diff --git a/src/core/include/units/quantity.h b/src/core/include/units/quantity.h index 39cbf51b..afcb74de 100644 --- a/src/core/include/units/quantity.h +++ b/src/core/include/units/quantity.h @@ -69,8 +69,8 @@ concept harmonic_ = // exposition only template concept quantity_convertible_to_ = // exposition only - Quantity && Quantity && convertible(QFrom::dimension, QTo::dimension) && - convertible(QFrom::unit, QTo::unit) && scalable_with_ && + Quantity && Quantity && + convertible(QFrom::reference, QTo::reference) && scalable_with_ && (floating_point_ || (!floating_point_ && harmonic_)); template diff --git a/src/core/include/units/quantity_cast.h b/src/core/include/units/quantity_cast.h index bf4da51b..59df535b 100644 --- a/src/core/include/units/quantity_cast.h +++ b/src/core/include/units/quantity_cast.h @@ -99,11 +99,10 @@ namespace detail { * @tparam To a target quantity type to cast to */ template Rep> - requires(convertible(R, To::reference)) + requires(convertible(To::reference, R)) [[nodiscard]] constexpr auto quantity_cast(const quantity& q) { - // TODO implement same unit magnitude check - if constexpr (std::same_as) { + if constexpr (R.unit == To::unit) { return To(static_cast(q.number())); } else { // using traits = detail::cast_traits; @@ -202,7 +201,7 @@ template Rep> // requires(std::constructible_from>) [[nodiscard]] constexpr auto quantity_cast(const quantity& q) { - return To(static_cast(q.number())); + return quantity_cast>(q); } // /** diff --git a/src/core/include/units/reference.h b/src/core/include/units/reference.h index 30dd479a..1b89a09c 100644 --- a/src/core/include/units/reference.h +++ b/src/core/include/units/reference.h @@ -136,11 +136,11 @@ template void /*Use `q * (1 * r)` rather than `q * r`.*/ operator*(Quantity auto, Reference auto) = delete; -template -[[nodiscard]] consteval bool equivalent(R1, R2) -{ - return equivalent(R1::dimension, R2::dimension) && equivalent(R1::unit, R2::unit); -} +// template +// [[nodiscard]] consteval bool equivalent(R1, R2) +// { +// return equivalent(R1::dimension, R2::dimension) && R1::unit == R2::unit; +// } template [[nodiscard]] consteval bool convertible(R1, R2) @@ -148,6 +148,12 @@ template return convertible(R1::dimension, R2::dimension) && convertible(R1::unit, R2::unit); } +// template +// [[nodiscard]] consteval bool castable(R1, R2) +// { +// return equivalent(R1::dimension, R2::dimension) && convertible(R1::unit, R2::unit); +// } + template struct system_reference { diff --git a/test/unit_test/static/dimension_test.cpp b/test/unit_test/static/dimension_test.cpp index d3dde201..526c0136 100644 --- a/test/unit_test/static/dimension_test.cpp +++ b/test/unit_test/static/dimension_test.cpp @@ -22,10 +22,10 @@ #include -using namespace units; - namespace { +using namespace units; + template inline constexpr bool is_of_type = std::is_same_v, T>; @@ -34,6 +34,7 @@ using one_dim_ = struct one_dim; // clang-format off inline constexpr struct length_dim_ : base_dimension<"L"> {} length_dim; inline constexpr struct time_dim_ : base_dimension<"T"> {} time_dim; +inline constexpr struct mass_dim_ : base_dimension<"M"> {} mass_dim; inline constexpr struct frequency_dim_ : decltype(1 / time_dim) {} frequency_dim; inline constexpr struct action_dim_ : decltype(1 / time_dim) {} action_dim; @@ -42,6 +43,15 @@ inline constexpr struct volume_dim_ : decltype(area_dim * length_dim) {} volume_ inline constexpr struct speed_dim_ : decltype(length_dim / time_dim) {} speed_dim; inline constexpr struct velocity_dim_ : speed_dim_ {} velocity_dim; inline constexpr struct acceleration_dim_ : decltype(speed_dim / time_dim) {} acceleration_dim; +inline constexpr struct force_dim_ : decltype(mass_dim * acceleration_dim) {} force_dim; +inline constexpr struct moment_of_force_dim_ : decltype(length_dim * force_dim) {} moment_of_force_dim; +inline constexpr struct torque_dim_ : decltype(moment_of_force_dim) {} torque_dim; +inline constexpr struct pressure_dim_ : decltype(force_dim / area_dim) {} pressure_dim; +inline constexpr struct stress_dim_ : decltype(pressure_dim) {} stress_dim; +inline constexpr struct strain_dim_ : decltype(stress_dim / stress_dim) {} strain_dim; +inline constexpr struct power_dim_ : decltype(force_dim * speed_dim) {} power_dim; +inline constexpr struct efficiency_dim_ : decltype(power_dim / power_dim) {} efficiency_dim; +inline constexpr struct energy_dim_ : decltype(force_dim * length_dim) {} energy_dim; // clang-format on // concepts verification @@ -102,11 +112,15 @@ static_assert( static_assert(is_of_type<1 / (speed_dim * speed_dim) * length_dim, derived_dimension, per>>); -// comparisons of equivalent dimensions +// comparisons of the same dimensions +static_assert(length_dim == length_dim); +static_assert(speed_dim == speed_dim); + +// comparisons of equivalent dimensions (named vs unnamed/derived) static_assert(length_dim / length_dim == one_dim); static_assert(1 / time_dim != frequency_dim); -static_assert(equivalent(1 / time_dim, frequency_dim)); +// static_assert(equivalent(1 / time_dim, frequency_dim)); static_assert(convertible(1 / time_dim, frequency_dim)); static_assert(1 / frequency_dim == time_dim); static_assert(frequency_dim * time_dim == one_dim); @@ -114,7 +128,7 @@ static_assert(std::is_same_v, frequency_dim_>); static_assert(length_dim * length_dim != area_dim); -static_assert(equivalent(length_dim * length_dim, area_dim)); +// static_assert(equivalent(length_dim * length_dim, area_dim)); static_assert(convertible(length_dim * length_dim, area_dim)); static_assert(length_dim * length_dim != volume_dim); static_assert(area_dim / length_dim == length_dim); @@ -122,20 +136,20 @@ static_assert(std::is_same_v, area_dim_>); static_assert(length_dim * length_dim * length_dim != volume_dim); -static_assert(equivalent(length_dim * length_dim * length_dim, volume_dim)); +// static_assert(equivalent(length_dim * length_dim * length_dim, volume_dim)); static_assert(area_dim * length_dim != volume_dim); -static_assert(equivalent(area_dim * length_dim, volume_dim)); +// static_assert(equivalent(area_dim * length_dim, volume_dim)); static_assert(volume_dim / length_dim != area_dim); -static_assert(equivalent(volume_dim / length_dim, area_dim)); +// static_assert(equivalent(volume_dim / length_dim, area_dim)); static_assert(volume_dim / length_dim / length_dim == length_dim); static_assert(area_dim * area_dim / length_dim != volume_dim); -static_assert(equivalent(area_dim * area_dim / length_dim, volume_dim)); +// static_assert(equivalent(area_dim * area_dim / length_dim, volume_dim)); static_assert(area_dim * (area_dim / length_dim) != volume_dim); -static_assert(equivalent(area_dim * (area_dim / length_dim), volume_dim)); +// static_assert(equivalent(area_dim * (area_dim / length_dim), volume_dim)); static_assert(volume_dim / (length_dim * length_dim) == length_dim); static_assert(length_dim / time_dim != speed_dim); -static_assert(equivalent(length_dim / time_dim, speed_dim)); +// static_assert(equivalent(length_dim / time_dim, speed_dim)); static_assert(length_dim * time_dim != speed_dim); static_assert(length_dim / time_dim / time_dim != speed_dim); static_assert(length_dim / speed_dim == time_dim); @@ -146,32 +160,72 @@ static_assert(std::is_same_v); static_assert(length_dim / time_dim / time_dim != acceleration_dim); -static_assert(equivalent(length_dim / time_dim / time_dim, acceleration_dim)); +// static_assert(equivalent(length_dim / time_dim / time_dim, acceleration_dim)); static_assert(length_dim / (time_dim * time_dim) != acceleration_dim); -static_assert(equivalent(length_dim / (time_dim * time_dim), acceleration_dim)); +// static_assert(equivalent(length_dim / (time_dim * time_dim), acceleration_dim)); static_assert(speed_dim / time_dim != acceleration_dim); -static_assert(equivalent(speed_dim / time_dim, acceleration_dim)); +// static_assert(equivalent(speed_dim / time_dim, acceleration_dim)); static_assert(speed_dim / acceleration_dim == time_dim); static_assert(acceleration_dim * time_dim != speed_dim); -static_assert(equivalent(acceleration_dim * time_dim, speed_dim)); +// static_assert(equivalent(acceleration_dim * time_dim, speed_dim)); static_assert(acceleration_dim * (time_dim * time_dim) == length_dim); static_assert(acceleration_dim / speed_dim != frequency_dim); -static_assert(equivalent(acceleration_dim / speed_dim, frequency_dim)); +// static_assert(equivalent(acceleration_dim / speed_dim, frequency_dim)); -static_assert(frequency_dim != action_dim); -static_assert(equivalent(frequency_dim, action_dim)); -static_assert(!convertible(frequency_dim, action_dim)); +// comparison of convertible named dimensions +static_assert(velocity_dim != speed_dim); +// static_assert(equivalent(velocity_dim, speed_dim)); +static_assert(convertible(speed_dim, velocity_dim)); +static_assert(std::is_same_v, velocity_dim_>); +static_assert(std::is_same_v, velocity_dim_>); + +// comparisons of equivalent but not convertible dimensions +static_assert(energy_dim != torque_dim); +// static_assert(equivalent(energy_dim, torque_dim)); +static_assert(!convertible(energy_dim, torque_dim)); + +static_assert(force_dim * length_dim != energy_dim); +static_assert(force_dim * length_dim != torque_dim); +// static_assert(equivalent(force_dim * length_dim, energy_dim)); +// static_assert(equivalent(force_dim * length_dim, torque_dim)); +static_assert(convertible(force_dim * length_dim, energy_dim)); +static_assert(convertible(force_dim * length_dim, torque_dim)); template concept no_common_type = requires { requires !requires { typename std::common_type_t; }; requires !requires { typename std::common_type_t; }; }; +static_assert(no_common_type); + +static_assert(frequency_dim != action_dim); +// static_assert(equivalent(frequency_dim, action_dim)); +static_assert(!convertible(frequency_dim, action_dim)); static_assert(no_common_type); -static_assert(velocity_dim != speed_dim); -static_assert(equivalent(velocity_dim, speed_dim)); -static_assert(convertible(speed_dim, velocity_dim)); -static_assert(std::is_same_v, velocity_dim_>); -static_assert(std::is_same_v, velocity_dim_>); +// Dimensionless +// static_assert(equivalent(power_dim / power_dim, efficiency_dim)); +static_assert(convertible(power_dim / power_dim, efficiency_dim)); +static_assert(power_dim / power_dim != efficiency_dim); +static_assert(one_dim != efficiency_dim); + +// static_assert(equivalent(efficiency_dim, strain_dim)); +static_assert(!convertible(efficiency_dim, strain_dim)); +static_assert(efficiency_dim != strain_dim); + +static_assert(stress_dim / stress_dim != strain_dim); +static_assert(stress_dim / stress_dim != efficiency_dim); +// static_assert(equivalent(stress_dim / stress_dim, strain_dim)); +// static_assert(equivalent(stress_dim / stress_dim, efficiency_dim)); +static_assert(convertible(stress_dim / stress_dim, strain_dim)); +static_assert(convertible(stress_dim / stress_dim, efficiency_dim)); + +// comparison of not equivalent dimensions +static_assert(length_dim != time_dim); +// static_assert(!equivalent(length_dim, time_dim)); +static_assert(!convertible(length_dim, time_dim)); + +static_assert(acceleration_dim != speed_dim); +// static_assert(!equivalent(acceleration_dim, speed_dim)); +static_assert(!convertible(acceleration_dim, speed_dim)); } // namespace