diff --git a/example/measurement.cpp b/example/measurement.cpp index db7163a5..3ef98288 100644 --- a/example/measurement.cpp +++ b/example/measurement.cpp @@ -21,6 +21,7 @@ // SOFTWARE. #include +#include #include namespace { diff --git a/src/include/units/base_dimension.h b/src/include/units/base_dimension.h index bdf19e77..0f1e5309 100644 --- a/src/include/units/base_dimension.h +++ b/src/include/units/base_dimension.h @@ -23,7 +23,7 @@ #pragma once #include -#include +#include #include namespace units { @@ -54,29 +54,6 @@ struct base_dimension { using base_unit = U; }; -// BaseDimension -namespace detail { - -#if __GNUC__ == 9 && __GNUC_MINOR__ < 2 - -template -inline constexpr bool is_base_dimension = true; - -#else - -template -inline constexpr bool is_base_dimension = false; - -template -inline constexpr bool is_base_dimension> = true; - -#endif - -} // namespace detail - -template -concept BaseDimension = detail::is_base_dimension; - // base_dimension_less // TODO Remove the below when https://bugs.llvm.org/show_bug.cgi?id=32208 is fixed // clang-format off diff --git a/src/include/units/bits/common_quantity.h b/src/include/units/bits/common_quantity.h new file mode 100644 index 00000000..0a1b4da0 --- /dev/null +++ b/src/include/units/bits/common_quantity.h @@ -0,0 +1,66 @@ +// 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 + +namespace units { + +template U, Scalar Rep> +class quantity; + +namespace detail { + +template +struct common_quantity_impl; + +template +struct common_quantity_impl, quantity, Rep> { + using type = quantity; +}; + +template +struct common_quantity_impl, quantity, Rep> { + using type = quantity>, Rep>; +}; + +template + requires same_unit_reference, dimension_unit>::value +struct common_quantity_impl, quantity, Rep> { + using type = quantity>, Rep>; +}; + +template +struct common_quantity_impl, quantity, Rep> { + using ratio1 = ratio_multiply; + using ratio2 = ratio_multiply; + using type = quantity>, Rep>; +}; + +} // namespace detail + +template> + requires equivalent_dim +using common_quantity = detail::common_quantity_impl::type; + +} // namespace units diff --git a/src/include/units/bits/concepts.h b/src/include/units/bits/concepts.h deleted file mode 100644 index b43d4524..00000000 --- a/src/include/units/bits/concepts.h +++ /dev/null @@ -1,53 +0,0 @@ -// 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 -#include -#include - -namespace units { - - namespace detail { - - template - concept basic_arithmetic = // exposition only - std::magma && - std::magma && - std::magma && - std::magma; - - template - concept safe_convertible = // exposition only - std::convertible_to && - (treat_as_floating_point || (!treat_as_floating_point)); - - template - concept safe_divisible = // exposition only - treat_as_floating_point || - ratio_divide::den == 1; - - } - -} // namespace units diff --git a/src/include/units/bits/deduced_unit.h b/src/include/units/bits/deduced_unit.h index 6f170aa5..7d846b45 100644 --- a/src/include/units/bits/deduced_unit.h +++ b/src/include/units/bits/deduced_unit.h @@ -22,7 +22,6 @@ #pragma once -#include #include namespace units::detail { diff --git a/src/include/units/concepts.h b/src/include/units/concepts.h new file mode 100644 index 00000000..9f6184f6 --- /dev/null +++ b/src/include/units/concepts.h @@ -0,0 +1,181 @@ +// 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 +#include +#include +#include +#include + +namespace units { + +namespace detail { + +template +concept basic_arithmetic = // exposition only + std::magma && + std::magma && + std::magma && + std::magma; + +} // namespace detail + +// PrefixType +struct prefix_type; + +template +concept PrefixType = std::derived_from; + +// Prefix +// TODO gcc:92150 +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92150 +// namespace detail { + +// template +// inline constexpr bool is_prefix = false; + +// template +// inline constexpr bool is_prefix> = true; + +// } // namespace detail + +template +// concept Prefix = detail::is_prefix; +concept Prefix = true; + + +namespace detail { + +template +inline constexpr bool is_ratio = false; + +} // namespace detail + +template +concept Ratio = detail::is_ratio; + + +// UnitRatio +template +concept UnitRatio = Ratio && (R::num * R::den > 0); + +// Unit +template +struct scaled_unit; + +template +concept Unit = is_derived_from_instantiation; + +// BaseDimension +template +struct base_dimension; + +namespace detail { + +#if __GNUC__ == 9 && __GNUC_MINOR__ < 2 + +template +inline constexpr bool is_base_dimension = true; + +#else + +template +inline constexpr bool is_base_dimension = false; + +template +inline constexpr bool is_base_dimension> = true; + +#endif + +} // namespace detail + +template +concept BaseDimension = detail::is_base_dimension; // TODO Replace with is_derived_from_instantiation when fixed + +// Exponent +namespace detail { + +template +inline constexpr bool is_exp = false; + +} // namespace detail + +template +concept Exponent = detail::is_exp; + +// DerivedDimension +template +struct derived_dimension; + +template +concept DerivedDimension = std::is_empty_v && is_instantiation, derived_dimension>; + +// Dimension +template +concept Dimension = BaseDimension || DerivedDimension; + +// UnitOf +namespace detail { + +template +struct dimension_unit_impl; + +template +struct dimension_unit_impl { + using type = D::base_unit; +}; + +template +struct dimension_unit_impl { + using type = D::coherent_unit; +}; + +} // namespace detail + +template +using dimension_unit = detail::dimension_unit_impl::type; + +template +concept UnitOf = + Unit && + Dimension && + std::same_as::reference>; + +// Quantity +namespace detail { + +template +inline constexpr bool is_quantity = false; + +} // namespace detail + +template +concept Quantity = detail::is_quantity; + +// Scalar +template +concept Scalar = (!Quantity) && std::regular && std::totally_ordered && detail::basic_arithmetic; + +} // namespace units diff --git a/src/include/units/customization_points.h b/src/include/units/customization_points.h index 9613d554..0e8b70bd 100644 --- a/src/include/units/customization_points.h +++ b/src/include/units/customization_points.h @@ -22,94 +22,120 @@ #pragma once +#include #include -#include namespace units { - // treat_as_floating_point +/** + * @brief Specifies if a value of a type should be treated as a floating-point value + * + * This type trait should be specialized for a custom representation type to specify + * that values fo this type should be treated by the library as a floating-point ones + * which will enable implicit conversions between quantities. + * + * @tparam Rep a representation type for which a type trait is defined + */ +template +inline constexpr bool treat_as_floating_point = std::is_floating_point_v; - template // TODO Conceptify that - inline constexpr bool treat_as_floating_point = std::is_floating_point_v; +/** + * @brief A type trait that defines zero, one, min, and max for a representation type + * + * The zero, one, min, and max member functions in units::quantity forward their work to + * these methods. This type can be specialized if the representation Rep requires a specific + * implementation to return these quantity objects. + * + * @tparam Rep a representation type for which a type trait is defined + */ +template +struct quantity_values { + static constexpr Rep zero() noexcept { return Rep(0); } + static constexpr Rep one() noexcept { return Rep(1); } + static constexpr Rep min() noexcept { return std::numeric_limits::lowest(); } + static constexpr Rep max() noexcept { return std::numeric_limits::max(); } +}; - // // isnan - // namespace isnan_impl { - // // non-ADL lookup block - // void isnan(); // undefined - // template - // inline constexpr bool has_customization = false; +// // isnan +// namespace isnan_impl { - // template - // requires requires(const T& t) { - // { isnan(t) } -> bool; - // } - // inline constexpr bool has_customization = true; +// // non-ADL lookup block +// void isnan(); // undefined - // struct fn { - // template - // constexpr bool operator()(const T&) const - // { - // return false; - // } +// template +// inline constexpr bool has_customization = false; - // template - // requires treat_as_floating_point - // constexpr bool operator()(const T& value) const - // { - // return std::isnan(value); - // } +// template +// requires requires(const T& t) { +// { isnan(t) } -> bool; +// } +// inline constexpr bool has_customization = true; - // template - // requires treat_as_floating_point && has_customization - // constexpr bool operator()(const T& value) const - // { - // return isnan(value); // uses ADL - // } - // }; - // } +// struct fn { +// template +// constexpr bool operator()(const T&) const +// { +// return false; +// } - // inline constexpr isnan_impl::fn isnan{}; +// template +// requires treat_as_floating_point +// constexpr bool operator()(const T& value) const +// { +// return std::isnan(value); +// } - // // isfinite - // namespace isfinite_impl { +// template +// requires treat_as_floating_point && has_customization +// constexpr bool operator()(const T& value) const +// { +// return isnan(value); // uses ADL +// } +// }; +// } - // // non-ADL lookup block - // void isfinite(); // undefined +// inline constexpr isnan_impl::fn isnan{}; - // template - // inline constexpr bool has_customization = false; +// // isfinite +// namespace isfinite_impl { - // template - // requires requires(const T& t) { - // { isfinite(t) } -> bool; - // } - // inline constexpr bool has_customization = true; +// // non-ADL lookup block +// void isfinite(); // undefined - // struct fn { - // template - // constexpr bool operator()(const T&) const - // { - // return true; - // } +// template +// inline constexpr bool has_customization = false; - // template - // requires treat_as_floating_point - // constexpr bool operator()(const T& value) const - // { - // return std::isfinite(value); - // } +// template +// requires requires(const T& t) { +// { isfinite(t) } -> bool; +// } +// inline constexpr bool has_customization = true; - // template - // requires treat_as_floating_point && has_customization - // constexpr bool operator()(const T& value) const - // { - // return isfinite(value); // uses ADL - // } - // }; - // } +// struct fn { +// template +// constexpr bool operator()(const T&) const +// { +// return true; +// } - // inline constexpr isfinite_impl::fn isfinite{}; +// template +// requires treat_as_floating_point +// constexpr bool operator()(const T& value) const +// { +// return std::isfinite(value); +// } -} +// template +// requires treat_as_floating_point && has_customization +// constexpr bool operator()(const T& value) const +// { +// return isfinite(value); // uses ADL +// } +// }; +// } + +// inline constexpr isfinite_impl::fn isfinite{}; + +} // namespace units diff --git a/src/include/units/derived_dimension.h b/src/include/units/derived_dimension.h index a0846a81..73870a26 100644 --- a/src/include/units/derived_dimension.h +++ b/src/include/units/derived_dimension.h @@ -31,19 +31,6 @@ namespace units { -// Exponent -namespace detail { - -template -inline constexpr bool is_exp = false; - -// partial specialization for an exp type provided below - -} // namespace detail - -template -concept Exponent = detail::is_exp; - /** * @brief A derived dimension * @@ -79,14 +66,6 @@ struct derived_dimension<> : downcast_base> {}; template struct derived_dimension : downcast_base> {}; // TODO rename to 'dimension'? -// DerivedDimension -template -concept DerivedDimension = std::is_empty_v && is_instantiation, derived_dimension>; - -// Dimension -template -concept Dimension = BaseDimension || DerivedDimension; - /** * @brief A power of factor corresponding to the dimension of a quantity * diff --git a/src/include/units/prefix.h b/src/include/units/prefix.h index 2117178d..eaded432 100644 --- a/src/include/units/prefix.h +++ b/src/include/units/prefix.h @@ -35,9 +35,6 @@ namespace units { */ struct prefix_type {}; -template -concept PrefixType = std::derived_from; - /** * @brief No prefix possible for the unit * @@ -72,25 +69,9 @@ struct prefix_base : downcast_base> { * @tparam R factor to be used to scale a unit */ template - requires(!std::same_as) + requires (!std::same_as) struct prefix : downcast_child>> { static constexpr auto symbol = Symbol; }; -// TODO gcc:92150 -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92150 -// namespace detail { - -// template -// inline constexpr bool is_prefix = false; - -// template -// inline constexpr bool is_prefix> = true; - -// } // namespace detail - -template -// concept Prefix = detail::is_prefix; -concept Prefix = true; - } // namespace units diff --git a/src/include/units/quantity.h b/src/include/units/quantity.h index c87e9175..acbc276b 100644 --- a/src/include/units/quantity.h +++ b/src/include/units/quantity.h @@ -22,255 +22,32 @@ #pragma once -#include +#include #include #include +#include #if __GNUC__ >= 10 #include #endif -#include #include namespace units { -// Quantity namespace detail { -template -inline constexpr bool is_quantity = false; +template +concept safe_convertible = // exposition only + std::convertible_to && + (treat_as_floating_point || (!treat_as_floating_point)); -// partial specialization below after the first quantity forward declaration +template +concept safe_divisible = // exposition only + treat_as_floating_point || + ratio_divide::den == 1; -} // namespace detail - -template -concept Quantity = detail::is_quantity; - -// QuantityOf -template -concept QuantityOf = Quantity && Dimension && equivalent_dim; - -// Scalar -template -concept Scalar = (!Quantity) && std::regular && std::totally_ordered && detail::basic_arithmetic; - -template U, Scalar Rep> -class quantity; - -namespace detail { - -template -inline constexpr bool is_quantity> = true; - -} // namespace detail - -// common_quantity -namespace detail { - -template -struct common_quantity_impl; - -template -struct common_quantity_impl, quantity, Rep> { - using type = quantity; -}; - -template -struct common_quantity_impl, quantity, Rep> { - using type = quantity>, Rep>; -}; - -template - requires same_unit_reference, dimension_unit>::value -struct common_quantity_impl, quantity, Rep> { - using type = quantity>, Rep>; -}; - -template -struct common_quantity_impl, quantity, Rep> { - using ratio1 = ratio_multiply; - using ratio2 = ratio_multiply; - using type = quantity>, Rep>; -}; - -} // namespace detail - -template> - requires equivalent_dim -using common_quantity = detail::common_quantity_impl::type; - -// quantity_cast -namespace detail { - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - if constexpr (treat_as_floating_point) { - return To(static_cast(static_cast(q.count()) * - (static_cast(CRatio::num) / static_cast(CRatio::den)))); - } else { - return To(static_cast(static_cast(q.count()) * static_cast(CRatio::num) / - static_cast(CRatio::den))); - } - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - return To(static_cast(q.count())); - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - if constexpr (treat_as_floating_point) { - return To(static_cast(static_cast(q.count()) * (CRep{1} / static_cast(CRatio::den)))); - } else { - return To(static_cast(static_cast(q.count()) / static_cast(CRatio::den))); - } - } -}; - -template -struct quantity_cast_impl { - template - static constexpr To cast(const Q& q) - { - return To(static_cast(static_cast(q.count()) * static_cast(CRatio::num))); - } -}; - -template -struct cast_ratio; - -template -struct cast_ratio { - using type = ratio_divide; -}; - -template - requires same_unit_reference::value -struct cast_ratio { - using type = ratio_divide; -}; - -template -struct cast_ratio { - using from_ratio = ratio_multiply; - using to_ratio = ratio_multiply; - using type = ratio_divide; -}; - -} // namespace detail - -/** - * @brief Explcit cast of a quantity - * - * Implicit conversions between quantities of different types are allowed only for "safe" - * (i.e. non-truncating) conversion. In such cases an explicit cast have to be used. - * - * This cast gets the target quantity type to cast to. For example: - * - * auto q1 = units::quantity_cast>(1ms); - * - * @tparam To a target quantity type to cast to - */ -template -[[nodiscard]] constexpr auto quantity_cast(const quantity& q) - requires QuantityOf && - detail::basic_arithmetic> -{ - using c_ratio = detail::cast_ratio::type; - using c_rep = std::common_type_t; - using ret_unit = downcast_unit; - using ret = quantity; - using cast = detail::quantity_cast_impl; - return cast::cast(q); -} - -/** - * @brief Explcit cast of a quantity - * - * Implicit conversions between quantities of different types are allowed only for "safe" - * (i.e. non-truncating) conversion. In such cases an explicit cast have to be used. - * - * This cast gets only the target dimension to cast to. For example: - * - * auto q1 = units::quantity_cast(200Gal); - * - * @tparam ToD a dimension type to use for a target quantity - */ -template -[[nodiscard]] constexpr auto quantity_cast(const quantity& q) - requires equivalent_dim -{ - return quantity_cast>(q); -} - -/** - * @brief Explcit cast of a quantity - * - * Implicit conversions between quantities of different types are allowed only for "safe" - * (i.e. non-truncating) conversion. In such cases an explicit cast have to be used. - * - * This cast gets only the target unit to cast to. For example: - * - * auto q1 = units::quantity_cast(1ms); - * - * @tparam ToU a unit type to use for a target quantity - */ -template -[[nodiscard]] constexpr auto quantity_cast(const quantity& q) - requires UnitOf -{ - return quantity_cast>(q); -} - -/** - * @brief Explcit cast of a quantity - * - * Implicit conversions between quantities of different types are allowed only for "safe" - * (i.e. non-truncating) conversion. In such cases an explicit cast have to be used. - * - * This cast gets only representation to cast to. For example: - * - * auto q1 = units::quantity_cast(1ms); - * - * @tparam ToRep a representation type to use for a target quantity - */ -template -[[nodiscard]] constexpr auto quantity_cast(const quantity& q) - requires detail::basic_arithmetic> -{ - return quantity_cast>(q); -} - -/** - * @brief A type trait that defines zero, one, min, and max for a representation type - * - * The zero, one, min, and max member functions in units::quantity forward their work to - * these methods. This type can be specialized if the representation Rep requires a specific - * implementation to return these quantity objects. - * - * @tparam Rep a representation type for which a type trait is defined - */ -template -struct quantity_values { - static constexpr Rep zero() noexcept { return Rep(0); } - static constexpr Rep one() noexcept { return Rep(1); } - static constexpr Rep min() noexcept { return std::numeric_limits::lowest(); } - static constexpr Rep max() noexcept { return std::numeric_limits::max(); } -}; +} // namespace detail /** * @brief A quantity @@ -443,46 +220,6 @@ public: return *this; } - template - [[nodiscard]] friend constexpr Quantity AUTO operator+(const quantity& lhs, const quantity& rhs) - requires detail::basic_arithmetic - { - using common_rep = decltype(lhs.count() + rhs.count()); - using ret = common_quantity, common_rep>; - return ret(ret(lhs).count() + ret(rhs).count()); - } - - template - [[nodiscard]] friend constexpr Quantity AUTO operator-(const quantity& lhs, const quantity& rhs) - requires detail::basic_arithmetic - { - using common_rep = decltype(lhs.count() - rhs.count()); - using ret = common_quantity, common_rep>; - return ret(ret(lhs).count() - ret(rhs).count()); - } - - template - [[nodiscard]] friend constexpr Quantity AUTO operator%(const quantity& q, const Value& v) - requires (!treat_as_floating_point) && - (!treat_as_floating_point) && - std::magma - { - using common_rep = decltype(q.count() % v); - using ret = quantity; - return ret(q.count() % v); - } - - template - [[nodiscard]] friend constexpr Quantity AUTO operator%(const quantity& lhs, const quantity& rhs) - requires (!treat_as_floating_point) && - (!treat_as_floating_point) && - std::magma - { - using common_rep = decltype(lhs.count() % rhs.count()); - using ret = common_quantity, common_rep>; - return ret(ret(lhs).count() % ret(rhs).count()); - } - #if __GNUC__ >= 10 template @@ -573,7 +310,23 @@ public: } }; -// TODO make hidden friends when moved to gcc-10 +template +[[nodiscard]] constexpr Quantity AUTO operator+(const quantity& lhs, const quantity& rhs) + requires detail::basic_arithmetic +{ + using common_rep = decltype(lhs.count() + rhs.count()); + using ret = common_quantity, quantity, common_rep>; + return ret(ret(lhs).count() + ret(rhs).count()); +} + +template +[[nodiscard]] constexpr Quantity AUTO operator-(const quantity& lhs, const quantity& rhs) + requires detail::basic_arithmetic +{ + using common_rep = decltype(lhs.count() - rhs.count()); + using ret = common_quantity, quantity, common_rep>; + return ret(ret(lhs).count() - ret(rhs).count()); +} template [[nodiscard]] constexpr Quantity AUTO operator*(const quantity& q, const Value& v) @@ -614,7 +367,7 @@ template +template [[nodiscard]] constexpr Quantity AUTO operator/(const Value& v, const quantity& q) requires std::magma { @@ -666,4 +419,33 @@ template +[[nodiscard]] constexpr Quantity AUTO operator%(const quantity& q, const Value& v) + requires (!treat_as_floating_point) && + (!treat_as_floating_point) && + std::magma +{ + using common_rep = decltype(q.count() % v); + using ret = quantity; + return ret(q.count() % v); +} + +template +[[nodiscard]] constexpr Quantity AUTO operator%(const quantity& lhs, const quantity& rhs) + requires (!treat_as_floating_point) && + (!treat_as_floating_point) && + std::magma +{ + using common_rep = decltype(lhs.count() % rhs.count()); + using ret = common_quantity, quantity, common_rep>; + return ret(ret(lhs).count() % ret(rhs).count()); +} + +namespace detail { + +template +inline constexpr bool is_quantity> = true; + +} // namespace detail + } // namespace units diff --git a/src/include/units/quantity_cast.h b/src/include/units/quantity_cast.h new file mode 100644 index 00000000..c84548ac --- /dev/null +++ b/src/include/units/quantity_cast.h @@ -0,0 +1,188 @@ +// 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 + +namespace units { + +// QuantityOf +template +concept QuantityOf = Quantity && Dimension && equivalent_dim; + +// quantity_cast +namespace detail { + +template +struct quantity_cast_impl { + template + static constexpr To cast(const Q& q) + { + if constexpr (treat_as_floating_point) { + return To(static_cast(static_cast(q.count()) * + (static_cast(CRatio::num) / static_cast(CRatio::den)))); + } else { + return To(static_cast(static_cast(q.count()) * static_cast(CRatio::num) / + static_cast(CRatio::den))); + } + } +}; + +template +struct quantity_cast_impl { + template + static constexpr To cast(const Q& q) + { + return To(static_cast(q.count())); + } +}; + +template +struct quantity_cast_impl { + template + static constexpr To cast(const Q& q) + { + if constexpr (treat_as_floating_point) { + return To(static_cast(static_cast(q.count()) * (CRep{1} / static_cast(CRatio::den)))); + } else { + return To(static_cast(static_cast(q.count()) / static_cast(CRatio::den))); + } + } +}; + +template +struct quantity_cast_impl { + template + static constexpr To cast(const Q& q) + { + return To(static_cast(static_cast(q.count()) * static_cast(CRatio::num))); + } +}; + +template +struct cast_ratio; + +template +struct cast_ratio { + using type = ratio_divide; +}; + +template + requires same_unit_reference::value +struct cast_ratio { + using type = ratio_divide; +}; + +template +struct cast_ratio { + using from_ratio = ratio_multiply; + using to_ratio = ratio_multiply; + using type = ratio_divide; +}; + +} // namespace detail + +/** + * @brief Explcit cast of a quantity + * + * Implicit conversions between quantities of different types are allowed only for "safe" + * (i.e. non-truncating) conversion. In such cases an explicit cast have to be used. + * + * This cast gets the target quantity type to cast to. For example: + * + * auto q1 = units::quantity_cast>(1ms); + * + * @tparam To a target quantity type to cast to + */ +template +[[nodiscard]] constexpr auto quantity_cast(const quantity& q) + requires QuantityOf && + detail::basic_arithmetic> +{ + using c_ratio = detail::cast_ratio::type; + using c_rep = std::common_type_t; + using ret_unit = downcast_unit; + using ret = quantity; + using cast = detail::quantity_cast_impl; + return cast::cast(q); +} + +/** + * @brief Explcit cast of a quantity + * + * Implicit conversions between quantities of different types are allowed only for "safe" + * (i.e. non-truncating) conversion. In such cases an explicit cast have to be used. + * + * This cast gets only the target dimension to cast to. For example: + * + * auto q1 = units::quantity_cast(200Gal); + * + * @tparam ToD a dimension type to use for a target quantity + */ +template +[[nodiscard]] constexpr auto quantity_cast(const quantity& q) + requires equivalent_dim +{ + return quantity_cast>(q); +} + +/** + * @brief Explcit cast of a quantity + * + * Implicit conversions between quantities of different types are allowed only for "safe" + * (i.e. non-truncating) conversion. In such cases an explicit cast have to be used. + * + * This cast gets only the target unit to cast to. For example: + * + * auto q1 = units::quantity_cast(1ms); + * + * @tparam ToU a unit type to use for a target quantity + */ +template +[[nodiscard]] constexpr auto quantity_cast(const quantity& q) + requires UnitOf +{ + return quantity_cast>(q); +} + +/** + * @brief Explcit cast of a quantity + * + * Implicit conversions between quantities of different types are allowed only for "safe" + * (i.e. non-truncating) conversion. In such cases an explicit cast have to be used. + * + * This cast gets only representation to cast to. For example: + * + * auto q1 = units::quantity_cast(1ms); + * + * @tparam ToRep a representation type to use for a target quantity + */ +template +[[nodiscard]] constexpr auto quantity_cast(const quantity& q) + requires detail::basic_arithmetic> +{ + return quantity_cast>(q); +} + +} // namespace units diff --git a/src/include/units/ratio.h b/src/include/units/ratio.h index 6e0700a0..6ad15cef 100644 --- a/src/include/units/ratio.h +++ b/src/include/units/ratio.h @@ -23,6 +23,7 @@ #pragma once #include +#include #include #include #include @@ -51,21 +52,13 @@ struct ratio { using type = ratio; }; -// is_ratio - namespace detail { -template -inline constexpr bool is_ratio = false; - template inline constexpr bool is_ratio> = true; } // namespace detail -template -concept Ratio = detail::is_ratio; - // ratio_add // TODO implement ratio_add diff --git a/src/include/units/unit.h b/src/include/units/unit.h index f0875a95..cc7973d8 100644 --- a/src/include/units/unit.h +++ b/src/include/units/unit.h @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/src/include/units/unit_concept.h b/src/include/units/unit_concept.h deleted file mode 100644 index 9e250657..00000000 --- a/src/include/units/unit_concept.h +++ /dev/null @@ -1,41 +0,0 @@ -// 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 - -namespace units { - -// UnitRatio -template -concept UnitRatio = Ratio && (R::num * R::den > 0); - -template -struct scaled_unit; - -// Unit -template -concept Unit = is_derived_from_instantiation; - -} // namespace units diff --git a/src/include/units/unit_of_concept.h b/src/include/units/unit_of_concept.h deleted file mode 100644 index c39a4016..00000000 --- a/src/include/units/unit_of_concept.h +++ /dev/null @@ -1,56 +0,0 @@ -// 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 - -namespace units { - -namespace detail { - -template -struct dimension_unit_impl; - -template -struct dimension_unit_impl { - using type = D::base_unit; -}; - -template -struct dimension_unit_impl { - using type = D::coherent_unit; -}; - -} // namespace detail - -template -using dimension_unit = detail::dimension_unit_impl::type; - -// UnitOf -template -concept UnitOf = - Unit && - Dimension && - std::same_as::reference>; - -} // namespace units