From 3713e08a950eeef60a8245ad53a8d0429cfc4164 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Tue, 30 May 2023 12:04:07 +0200 Subject: [PATCH] refactor: library concepts cleanup --- .../mp-units/bits/dimension_concepts.h | 17 ++--- .../mp-units/bits/quantity_spec_concepts.h | 68 ++++++------------- .../mp-units/bits/representation_concepts.h | 19 +++--- .../include/mp-units/bits/unit_concepts.h | 60 +++++++++++++--- src/core/include/mp-units/dimension.h | 4 +- src/core/include/mp-units/quantity.h | 9 ++- src/core/include/mp-units/quantity_spec.h | 37 ++++++---- src/core/include/mp-units/unit.h | 23 ++----- 8 files changed, 122 insertions(+), 115 deletions(-) diff --git a/src/core/include/mp-units/bits/dimension_concepts.h b/src/core/include/mp-units/bits/dimension_concepts.h index 05868748..1bb908b2 100644 --- a/src/core/include/mp-units/bits/dimension_concepts.h +++ b/src/core/include/mp-units/bits/dimension_concepts.h @@ -42,18 +42,13 @@ inline constexpr bool is_specialization_of_base_dimension = false; template inline constexpr bool is_specialization_of_base_dimension> = true; -} // namespace detail - /** * @brief A concept matching all named base dimensions in the library. * * Satisfied by all dimension types derived from a specialization of `base_dimension`. */ template -concept BaseDimension = - requires(T* t) { detail::to_base_base_dimension(t); } && (!detail::is_specialization_of_base_dimension); - -namespace detail { +concept BaseDimension = requires(T* t) { to_base_base_dimension(t); } && (!is_specialization_of_base_dimension); template struct is_dimension_one : std::false_type {}; @@ -71,13 +66,13 @@ template inline constexpr bool is_per_of_dims> = (... && (BaseDimension || is_dimension_one::value || is_power_of_dim)); -} // namespace detail - template concept DerivedDimensionExpr = - BaseDimension || detail::is_dimension_one::value || detail::is_power_of_dim || detail::is_per_of_dims; + BaseDimension || is_dimension_one::value || is_power_of_dim || is_per_of_dims; -template +} // namespace detail + +template struct derived_dimension; namespace detail { @@ -99,6 +94,6 @@ concept DerivedDimension = is_derived_from_specialization_of` or `DerivedDimension` is `true`. */ template -concept Dimension = BaseDimension || detail::DerivedDimension; +concept Dimension = detail::BaseDimension || detail::DerivedDimension; } // namespace mp_units diff --git a/src/core/include/mp-units/bits/quantity_spec_concepts.h b/src/core/include/mp-units/bits/quantity_spec_concepts.h index 39d10265..1b5afa2a 100644 --- a/src/core/include/mp-units/bits/quantity_spec_concepts.h +++ b/src/core/include/mp-units/bits/quantity_spec_concepts.h @@ -34,8 +34,20 @@ template #endif struct quantity_spec; +template +struct kind_of_; + namespace detail { +template +inline constexpr bool is_specialization_of_kind_of = false; + +template +inline constexpr bool is_specialization_of_kind_of> = true; + +template +concept QuantityKindSpec = is_specialization_of_kind_of; + #ifdef __cpp_explicit_this_parameter template void to_base_specialization_of_quantity_spec(const volatile quantity_spec*); @@ -70,10 +82,8 @@ inline constexpr bool is_specialization_of_quantity_spec -concept NamedQuantitySpec = requires(T* t) { detail::to_base_specialization_of_quantity_spec(t); } && - (!detail::is_specialization_of_quantity_spec); - -} // namespace detail +concept NamedQuantitySpec = requires(T* t) { to_base_specialization_of_quantity_spec(t); } && + (!is_specialization_of_quantity_spec)&&(!QuantityKindSpec); /** * @brief Concept matching all named base quantity specification types @@ -82,10 +92,7 @@ concept NamedQuantitySpec = requires(T* t) { detail::to_base_specialization_of_q * as a template parameter. */ template -concept BaseQuantitySpec = - detail::NamedQuantitySpec && requires(T* t) { detail::to_base_specialization_of_base_quantity_spec(t); }; - -namespace detail { +concept BaseQuantitySpec = NamedQuantitySpec && requires(T* t) { to_base_specialization_of_base_quantity_spec(t); }; template struct is_dimensionless : std::false_type {}; @@ -103,15 +110,14 @@ template inline constexpr bool is_per_of_quantity_specs> = (... && (NamedQuantitySpec || is_dimensionless::value || is_power_of_quantity_spec)); -} // namespace detail - template concept IntermediateDerivedQuantitySpecExpr = detail::NamedQuantitySpec || detail::is_dimensionless::value || detail::is_power_of_quantity_spec || detail::is_per_of_quantity_specs; +} // namespace detail -template +template struct derived_quantity_spec; namespace detail { @@ -129,45 +135,9 @@ concept IntermediateDerivedQuantitySpec = is_specialization_of -concept QuantitySpec = detail::NamedQuantitySpec || detail::IntermediateDerivedQuantitySpec; - -namespace detail { template -inline constexpr bool is_quantity_spec_with_no_specifiers = false; +concept QuantitySpec = + detail::NamedQuantitySpec || detail::IntermediateDerivedQuantitySpec || detail::QuantityKindSpec; -template -concept QuantitySpecWithNoSpecifiers = is_quantity_spec_with_no_specifiers; - -} // namespace detail - -template -[[nodiscard]] consteval QuantitySpec auto get_kind(Q q); - -template - requires(get_kind(Q) == Q) -struct kind_of_; - -namespace detail { - -template -void to_base_specialization_of_kind_of(const volatile kind_of_*); - -template -inline constexpr bool is_derived_from_specialization_of_kind_of = - requires(T* t) { to_base_specialization_of_kind_of(t); }; - -} // namespace detail - -template -concept QuantityKindSpec = QuantitySpec && detail::is_derived_from_specialization_of_kind_of; - -namespace detail { - -template - requires QuantitySpec && (!QuantityKindSpec) -inline constexpr bool is_quantity_spec_with_no_specifiers = true; - -} // namespace detail } // namespace mp_units diff --git a/src/core/include/mp-units/bits/representation_concepts.h b/src/core/include/mp-units/bits/representation_concepts.h index d92f2663..3a6f440e 100644 --- a/src/core/include/mp-units/bits/representation_concepts.h +++ b/src/core/include/mp-units/bits/representation_concepts.h @@ -50,27 +50,30 @@ namespace mp_units { */ enum class quantity_character { scalar, vector, tensor }; +namespace detail { + template -concept common_type_with_ = // exposition only +concept CommonTypeWith = std::same_as, std::common_type_t> && std::constructible_from, T> && std::constructible_from, U>; template -concept scalable_number_ = // exposition only +concept ScalableNumber = std::regular_invocable, T, U> && std::regular_invocable, T, U>; template -concept castable_number_ = // exposition only - common_type_with_ && scalable_number_>; +concept CastableNumber = CommonTypeWith && ScalableNumber>; // TODO Fix it according to sudo_cast implementation template -concept scalable_ = // exposition only - castable_number_ || (requires { typename T::value_type; } && castable_number_ && - scalable_number_>); +concept Scalable = + CastableNumber || (requires { typename T::value_type; } && CastableNumber && + ScalableNumber>); + +} // namespace detail template -concept Representation = (is_scalar || is_vector || is_tensor)&&std::regular && scalable_; +concept Representation = (is_scalar || is_vector || is_tensor)&&std::regular && detail::Scalable; template concept RepresentationOf = Representation && ((Ch == quantity_character::scalar && is_scalar) || diff --git a/src/core/include/mp-units/bits/unit_concepts.h b/src/core/include/mp-units/bits/unit_concepts.h index 35f698ea..50fddbad 100644 --- a/src/core/include/mp-units/bits/unit_concepts.h +++ b/src/core/include/mp-units/bits/unit_concepts.h @@ -50,27 +50,42 @@ struct scaled_unit; template struct named_unit; +template + requires(!Symbol.empty()) +struct constant_unit; + namespace detail { template void to_base_specialization_of_named_unit(const volatile named_unit*); +template +inline constexpr bool is_derived_from_specialization_of_named_unit = + requires(T* t) { to_base_specialization_of_named_unit(t); }; + template inline constexpr bool is_specialization_of_named_unit = false; template inline constexpr bool is_specialization_of_named_unit> = true; -} // namespace detail +template +void to_base_specialization_of_constant_unit(const volatile constant_unit*); + +template +inline constexpr bool is_derived_from_specialization_of_constant_unit = + requires(T* t) { to_base_specialization_of_constant_unit(t); }; /** * @brief A concept matching all units with special names * - * Satisfied by all unit types derived from the specialization of `named_unit`. + * Satisfied by all unit types derived from the specialization of `named_unit` (but not constant units). */ template -concept NamedUnit = Unit && requires(T* t) { detail::to_base_specialization_of_named_unit(t); } && - (!detail::is_specialization_of_named_unit); +concept NamedUnit = Unit && detail::is_derived_from_specialization_of_named_unit && + (!detail::is_derived_from_specialization_of_constant_unit); + +} // namespace detail /** * @brief Prevents assignment of a prefix to specific units @@ -79,14 +94,14 @@ concept NamedUnit = Unit && requires(T* t) { detail::to_base_specialization_o * `hour` or `degree_Celsius`. For those a partial specialization with the value `false` should be * provided. */ -template -inline constexpr bool unit_can_be_prefixed = true; +template +inline constexpr bool unit_can_be_prefixed = detail::NamedUnit>; /** * @brief A concept to be used to define prefixes for a unit */ template -concept PrefixableUnit = NamedUnit && unit_can_be_prefixed; +concept PrefixableUnit = detail::NamedUnit && unit_can_be_prefixed; namespace detail { @@ -100,14 +115,18 @@ inline constexpr bool is_per_of_units = false; template inline constexpr bool is_per_of_units> = (... && (Unit || is_power_of_unit)); -} // namespace detail - template concept DerivedUnitExpr = Unit || detail::is_power_of_unit || detail::is_per_of_units; -template +} // namespace detail + +template struct derived_unit; +template + requires(!Symbol.empty()) +struct prefixed_unit; + namespace detail { template @@ -119,9 +138,28 @@ void is_unit_impl(const named_unit*); template void is_unit_impl(const derived_unit*); +template +inline constexpr bool is_specialization_of_unit = false; + +template +inline constexpr bool is_specialization_of_unit> = true; + +template +inline constexpr bool is_specialization_of_constant_unit = false; + +template +inline constexpr bool is_specialization_of_constant_unit> = true; + +template +inline constexpr bool is_specialization_of_prefixed_unit = false; + +template +inline constexpr bool is_specialization_of_prefixed_unit> = true; + template requires requires(T* t) { is_unit_impl(t); } -inline constexpr bool is_unit = true; +inline constexpr bool is_unit = !is_specialization_of_named_unit && !is_specialization_of_constant_unit && + !is_specialization_of_prefixed_unit; template [[nodiscard]] consteval bool has_associated_quantity(U); diff --git a/src/core/include/mp-units/dimension.h b/src/core/include/mp-units/dimension.h index 80a2bf2b..3798f199 100644 --- a/src/core/include/mp-units/dimension.h +++ b/src/core/include/mp-units/dimension.h @@ -114,7 +114,7 @@ using type_list_of_base_dimension_less = expr_less; * @note User should not instantiate this type! It is not exported from the C++ module. The library will * instantiate this type automatically based on the dimensional arithmetic equation provided by the user. */ -template +template struct derived_dimension : detail::expr_fractions {}; /** @@ -179,7 +179,7 @@ template requires detail::non_zero [[nodiscard]] consteval Dimension auto pow(D d) { - if constexpr (BaseDimension) { + if constexpr (detail::BaseDimension) { if constexpr (Den == 1) return derived_dimension>{}; else diff --git a/src/core/include/mp-units/quantity.h b/src/core/include/mp-units/quantity.h index 502ff497..e342964e 100644 --- a/src/core/include/mp-units/quantity.h +++ b/src/core/include/mp-units/quantity.h @@ -47,16 +47,15 @@ template using quantity_like_type = quantity::reference, typename quantity_like_traits::rep>; template -concept RepSafeConstructibleFrom = // exposition only +concept RepSafeConstructibleFrom = std::constructible_from && (treat_as_floating_point || !treat_as_floating_point); template -concept IntegralConversionFactor = // exposition only - Unit && Unit && - is_integral(get_canonical_unit(UFrom).mag / get_canonical_unit(UTo).mag); +concept IntegralConversionFactor = Unit && Unit && + is_integral(get_canonical_unit(UFrom).mag / get_canonical_unit(UTo).mag); template -concept QuantityConvertibleTo = // exposition only +concept QuantityConvertibleTo = Quantity && Quantity && implicitly_convertible(QFrom::quantity_spec, QTo::quantity_spec) && convertible(QFrom::unit, QTo::unit) && requires(QFrom q) { detail::sudo_cast(q); } && (treat_as_floating_point || diff --git a/src/core/include/mp-units/quantity_spec.h b/src/core/include/mp-units/quantity_spec.h index 1f5eb20e..5b2b487a 100644 --- a/src/core/include/mp-units/quantity_spec.h +++ b/src/core/include/mp-units/quantity_spec.h @@ -189,15 +189,15 @@ inline constexpr struct is_kind { * @tparam Args optionally a value of a `quantity_character` in case the base quantity should not be scalar */ #ifdef __cpp_explicit_this_parameter -template auto... Args> +template auto... Args> requires(... && !QuantitySpec>) struct quantity_spec : detail::quantity_spec_interface { #else -template auto... Args> +template auto... Args> requires(... && !QuantitySpec>) struct quantity_spec : detail::quantity_spec_interface { #endif - static constexpr BaseDimension auto dimension = Dim; + static constexpr detail::BaseDimension auto dimension = Dim; static constexpr quantity_character character = detail::quantity_character_init(quantity_character::scalar); }; @@ -405,7 +405,7 @@ struct quantity_spec : quantity_spec { * @note User should not instantiate this type! It is not exported from the C++ module. The library will * instantiate this type automatically based on the dimensional arithmetic equation provided by the user. */ -template +template struct derived_quantity_spec : detail::quantity_spec_interface>, detail::expr_fractions { @@ -426,18 +426,31 @@ struct derived_quantity_spec : */ QUANTITY_SPEC(dimensionless, derived_quantity_spec<>{}); +template +[[nodiscard]] consteval QuantitySpec auto get_kind(Q q); + /** * @brief Quantity kind specifier * * Specifies that the provided `Q` should be treated as a quantity kind. */ +template +struct kind_of_; + +namespace detail { + +template +concept QuantitySpecWithNoSpecifiers = detail::NamedQuantitySpec || detail::IntermediateDerivedQuantitySpec; + +} // namespace detail + template requires(get_kind(Q) == Q) #ifdef __cpp_explicit_this_parameter -struct kind_of_ : Q { +struct kind_of_ : Q { }; #else -struct kind_of_ : quantity_spec, Q> { +struct kind_of_ : quantity_spec, Q> { }; #endif @@ -492,13 +505,13 @@ template return is_same_v; } -template +template [[nodiscard]] consteval bool operator==(Lhs, Rhs) { return is_same_v; } -template +template [[nodiscard]] consteval bool operator==(Lhs, Rhs rhs) { return is_same_v>; @@ -1374,7 +1387,7 @@ template template [[nodiscard]] consteval auto remove_kind(Q q) { - if constexpr (QuantityKindSpec) { + if constexpr (detail::QuantityKindSpec) { if constexpr (requires { Q::_parent_; }) return Q::_parent_; else @@ -1393,7 +1406,7 @@ template return false; }; - if constexpr (QuantityKindSpec) { + if constexpr (detail::QuantityKindSpec) { return remove_kind(q); } else if constexpr (defined_as_kind(q)) { return q; @@ -1424,11 +1437,11 @@ template else if constexpr (get_kind(q1) != get_kind(q2) && std::derived_from, std::remove_const_t>) return remove_kind(q2); - else if constexpr ((QuantityKindSpec && !QuantityKindSpec) || + else if constexpr ((detail::QuantityKindSpec && !detail::QuantityKindSpec) || (detail::IntermediateDerivedQuantitySpec && detail::NamedQuantitySpec && implicitly_convertible(q1, q2))) return q2; - else if constexpr ((!QuantityKindSpec && QuantityKindSpec) || + else if constexpr ((!detail::QuantityKindSpec && detail::QuantityKindSpec) || (detail::NamedQuantitySpec && detail::IntermediateDerivedQuantitySpec && implicitly_convertible(q2, q1))) return q1; diff --git a/src/core/include/mp-units/unit.h b/src/core/include/mp-units/unit.h index d0c52dee..d51819ea 100644 --- a/src/core/include/mp-units/unit.h +++ b/src/core/include/mp-units/unit.h @@ -109,8 +109,8 @@ struct named_unit; * @tparam Symbol a short text representation of the unit * @tparam QuantitySpec a specification of a base quantity to be measured with this unit */ -template - requires(!Symbol.empty()) && BaseDimension> +template + requires(!Symbol.empty()) && detail::BaseDimension> struct named_unit { static constexpr auto symbol = Symbol; ///< Unique base unit identifier static constexpr auto quantity_spec = QS; @@ -155,7 +155,7 @@ struct named_unit : std::remove_const_t { * @tparam Unit a unit for which we provide a special name * @tparam QuantitySpec a specification of a quantity to be measured with this unit */ -template +template requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension) struct named_unit : std::remove_const_t { static constexpr auto symbol = Symbol; ///< Unique unit identifier @@ -197,17 +197,6 @@ template requires(!Symbol.empty()) struct constant_unit : named_unit<'[' + Symbol + ']', U> {}; -namespace detail { - -template -void to_base_specialization_of_constant_unit(const volatile constant_unit*); - -template -inline constexpr bool is_derived_from_specialization_of_constant_unit = - requires(T* t) { to_base_specialization_of_constant_unit(t); }; - -} // namespace detail - /** * @brief A prefixed unit * @@ -288,7 +277,7 @@ struct is_one : std::false_type {}; * @note User should not instantiate this type! It is not exported from the C++ module. The library will * instantiate this type automatically based on the unit arithmetic equation provided by the user. */ -template +template struct derived_unit : detail::expr_fractions {}; /** @@ -328,7 +317,7 @@ struct canonical_unit { U reference_unit; }; -template +template [[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit&); template @@ -350,7 +339,7 @@ template return canonical_unit{M * base.mag, base.reference_unit}; } -template +template [[nodiscard]] consteval auto get_canonical_unit_impl(T t, const named_unit&) { return canonical_unit{mag<1>, t};