// The MIT License (MIT) // // Copyright (c) 2018 Mateusz Pusz // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #pragma once #include #include // IWYU pragma: begin_exports #include #include #include #include #include #include // IWYU pragma: end_exports namespace units { namespace detail { template inline constexpr bool can_be_prefixed = false; } // namespace detail /** * @brief A common point for a hierarchy of units * * A unit is an entity defined and adopted by convention, with which any other quantity of * the same kind can be compared to express the ratio of the second quantity to the first * one as a number. * * All units of the same dimension can be convereted between each other. To allow this all of * them are expressed as different ratios of the same one proprietary chosen reference unit * (i.e. all length units are expressed in terms of meter, all mass units are expressed in * terms of gram, ...) * * @tparam M a Magnitude representing the (relative) size of this unit * @tparam U a unit to use as a reference for this dimension */ template struct scaled_unit : downcast_base> { static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = M; using reference = U; }; template using downcast_unit = downcast::reference>>; template struct same_unit_reference : is_same {}; /** * @brief A named unit * * Defines a named (in most cases coherent) unit that is then passed to a dimension definition. * A named unit may be composed with a prefix to create a prefixed_unit. * * @tparam Child inherited class type used by the downcasting facility (CRTP Idiom) * @tparam Symbol a short text representation of the unit */ template struct named_unit : downcast_dispatch(), Child>> { static constexpr auto symbol = Symbol; }; /** * @brief A named scaled unit * * Defines a new named unit that is a scaled version of another unit. * A named unit may be composed with a prefix to create a prefixed_unit. * * @tparam Child inherited class type used by the downcasting facility (CRTP Idiom) * @tparam Symbol a short text representation of the unit * @tparam M the Magnitude by which to scale U * @tparam U a reference unit to scale */ template struct named_scaled_unit : downcast_dispatch> { static constexpr auto symbol = Symbol; }; /** * @brief A prefixed unit * * Defines a new unit that is a scaled version of another unit by the provided prefix. It is * only possible to create such a unit if the given prefix type matches the one defined in a * reference unit. * * @tparam Child inherited class type used by the downcasting facility (CRTP Idiom) * @tparam P prefix to be appied to the reference unit * @tparam U reference unit */ template requires detail::can_be_prefixed struct prefixed_unit : downcast_dispatch> { static constexpr auto symbol = P::symbol + U::symbol; }; /** * @brief A coherent unit of a derived quantity * * Defines a new coherent unit of a derived quantity. It should be passed as a coherent unit * in the dimension's definition for such a quantity. * * @tparam Child inherited class type used by the downcasting facility (CRTP Idiom) */ template struct derived_unit : downcast_dispatch(), Child>> {}; /** * @brief A unit with a deduced ratio and symbol * * Defines a new unit with a deduced ratio and symbol based on the recipe from the provided * derived dimension. The number and order of provided units should match the recipe of the * derived dimension. All of the units provided should also be a named ones so it is possible * to create a deduced symbol text. * * @tparam Child inherited class type used by the downcasting facility (CRTP Idiom) * @tparam Dim a derived dimension recipe to use for deduction * @tparam U the unit of the first composite dimension from provided derived dimension's recipe * @tparam URest the units for the rest of dimensions from the recipe */ template requires detail::compatible_units struct derived_scaled_unit : downcast_dispatch> { static constexpr auto symbol = detail::derived_symbol_text(); }; /** * @brief An aliased named unit * * Defines a named alias for another unit. It is useful to assign alternative names and symbols * to the already predefined units (i.e. "tonne" for "megagram"). * A alias unit may be composed with a prefix to create a prefixed_alias_unit. * * @tparam U Unit for which an alias is defined * @tparam Symbol a short text representation of the unit */ template struct alias_unit : U { static constexpr auto symbol = Symbol; }; /** * @brief A prefixed alias unit * * Defines a new unit that is an alias for a scaled version of another unit by the provided * prefix. It is only possible to create such a unit if the given prefix type matches the one * defined in a reference unit. * * @tparam U Unit for which an alias is defined * @tparam P prefix to be appied to the reference unit * @tparam AU reference alias unit */ // TODO gcc bug: 95015 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95015 // template // requires (!AliasUnit) template requires detail::can_be_prefixed struct prefixed_alias_unit : U { static constexpr auto symbol = P::symbol + AU::symbol; }; /** * @brief Unknown coherent unit * * Used as a coherent unit of an unknown dimension. */ struct unknown_coherent_unit : derived_unit {}; namespace detail { template void is_named_impl(const volatile named_unit*); template void is_named_impl(const volatile named_scaled_unit*); template void is_named_impl(const volatile prefixed_unit*); template void is_named_impl(const volatile alias_unit*); template void is_named_impl(const volatile prefixed_alias_unit*); template inline constexpr bool is_named = requires(U * u) { is_named_impl(u); }; template void can_be_prefixed_impl(const volatile named_unit*); template void can_be_prefixed_impl(const volatile named_scaled_unit*); template void can_be_prefixed_impl(const volatile alias_unit*); template inline constexpr bool can_be_prefixed = requires(U * u) { can_be_prefixed_impl(u); }; template inline constexpr bool can_be_prefixed> = can_be_prefixed; } // namespace detail } // namespace units