diff --git a/src/include/units/base_dimension.h b/src/include/units/base_dimension.h index 6fbde960..3e6b03a7 100644 --- a/src/include/units/base_dimension.h +++ b/src/include/units/base_dimension.h @@ -24,7 +24,6 @@ #include #include -#include #include namespace units { @@ -46,7 +45,7 @@ namespace units { */ template struct base_dimension { - using base_type = base_dimension; + using base_type_workaround = base_dimension; // TODO Replace with is_derived_from_instantiation when fixed static constexpr auto name = Name; using coherent_unit = U; }; @@ -63,7 +62,7 @@ inline constexpr bool is_base_dimension> = true; } // namespace detail template -concept BaseDimension = detail::is_base_dimension; +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 diff --git a/src/include/units/bits/customization_points.h b/src/include/units/bits/customization_points.h deleted file mode 100644 index acc33c3d..00000000 --- a/src/include/units/bits/customization_points.h +++ /dev/null @@ -1,115 +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 { - - // treat_as_floating_point - - template // TODO Conceptify that - inline constexpr bool treat_as_floating_point = std::is_floating_point_v; - - // isnan - namespace isnan_impl { - - // non-ADL lookup block - void isnan(); // undefined - - template - inline constexpr bool has_customization = false; - - template - requires requires(const T& t) { - { isnan(t) } -> bool; - } - inline constexpr bool has_customization = true; - - struct fn { - template - constexpr bool operator()(const T&) const - { - return false; - } - - template - requires treat_as_floating_point - constexpr bool operator()(const T& value) const - { - return std::isnan(value); - } - - template - requires treat_as_floating_point && has_customization - constexpr bool operator()(const T& value) const - { - return isnan(value); // uses ADL - } - }; - } - - inline constexpr isnan_impl::fn isnan{}; - - // isfinite - namespace isfinite_impl { - - // non-ADL lookup block - void isfinite(); // undefined - - template - inline constexpr bool has_customization = false; - - template - requires requires(const T& t) { - { isfinite(t) } -> bool; - } - inline constexpr bool has_customization = true; - - struct fn { - template - constexpr bool operator()(const T&) const - { - return true; - } - - 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{}; - -} diff --git a/src/include/units/bits/concepts.h b/src/include/units/concepts.h similarity index 97% rename from src/include/units/bits/concepts.h rename to src/include/units/concepts.h index 44b07f31..fcc16f35 100644 --- a/src/include/units/bits/concepts.h +++ b/src/include/units/concepts.h @@ -24,7 +24,7 @@ #include #include -#include +#include #include namespace units { diff --git a/src/include/units/customization_points.h b/src/include/units/customization_points.h new file mode 100644 index 00000000..9613d554 --- /dev/null +++ b/src/include/units/customization_points.h @@ -0,0 +1,115 @@ +// 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 { + + // treat_as_floating_point + + template // TODO Conceptify that + inline constexpr bool treat_as_floating_point = std::is_floating_point_v; + + // // isnan + // namespace isnan_impl { + + // // non-ADL lookup block + // void isnan(); // undefined + + // template + // inline constexpr bool has_customization = false; + + // template + // requires requires(const T& t) { + // { isnan(t) } -> bool; + // } + // inline constexpr bool has_customization = true; + + // struct fn { + // template + // constexpr bool operator()(const T&) const + // { + // return false; + // } + + // template + // requires treat_as_floating_point + // constexpr bool operator()(const T& value) const + // { + // return std::isnan(value); + // } + + // template + // requires treat_as_floating_point && has_customization + // constexpr bool operator()(const T& value) const + // { + // return isnan(value); // uses ADL + // } + // }; + // } + + // inline constexpr isnan_impl::fn isnan{}; + + // // isfinite + // namespace isfinite_impl { + + // // non-ADL lookup block + // void isfinite(); // undefined + + // template + // inline constexpr bool has_customization = false; + + // template + // requires requires(const T& t) { + // { isfinite(t) } -> bool; + // } + // inline constexpr bool has_customization = true; + + // struct fn { + // template + // constexpr bool operator()(const T&) const + // { + // return true; + // } + + // 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{}; + +} diff --git a/src/include/units/derived_dimension.h b/src/include/units/derived_dimension.h index 848ab4e0..78f109ec 100644 --- a/src/include/units/derived_dimension.h +++ b/src/include/units/derived_dimension.h @@ -277,10 +277,14 @@ struct dim_invert_impl> { using type = downcast...>>; }; +template +struct dim_invert_impl : dim_invert_impl> { +}; + } // namespace detail template -using dim_invert = detail::dim_invert_impl>::type; +using dim_invert = detail::dim_invert_impl::type; // dimension_multiply namespace detail { @@ -377,7 +381,7 @@ struct dimension_pow_impl; template struct dimension_pow_impl { - using type = derived_dimension>; + using type = downcast>>; }; template @@ -387,7 +391,7 @@ struct dimension_pow_impl, N> { template struct dimension_pow_impl { - using type = dimension_pow_impl; + using type = dimension_pow_impl, N>; }; template diff --git a/src/include/units/dimensions/area.h b/src/include/units/dimensions/area.h deleted file mode 100644 index 1a8e8830..00000000 --- a/src/include/units/dimensions/area.h +++ /dev/null @@ -1,64 +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 { - - struct area : derived_dimension> {}; - - template - concept Area = QuantityOf; - - struct square_metre : coherent_derived_unit {}; - struct square_millimetre : deduced_derived_unit {}; - struct square_centimetre : deduced_derived_unit {}; - struct square_kilometre : deduced_derived_unit {}; - struct square_foot : deduced_derived_unit {}; - - inline namespace literals { - - // sq_m - constexpr auto operator""sq_m(unsigned long long l) { return quantity(l); } - constexpr auto operator""sq_m(long double l) { return quantity(l); } - - // sq_mm - constexpr auto operator""sq_mm(unsigned long long l) { return quantity(l); } - constexpr auto operator""sq_mm(long double l) { return quantity(l); } - - // sq_cm - constexpr auto operator""sq_cm(unsigned long long l) { return quantity(l); } - constexpr auto operator""sq_cm(long double l) { return quantity(l); } - - // sq_km - constexpr auto operator""sq_km(unsigned long long l) { return quantity(l); } - constexpr auto operator""sq_km(long double l) { return quantity(l); } - - // sq_ft - constexpr auto operator""sq_ft(unsigned long long l) { return quantity(l); } - constexpr auto operator""sq_ft(long double l) { return quantity(l); } - - } // namespace literals - -} // namespace units diff --git a/src/include/units/dimensions/frequency.h b/src/include/units/dimensions/frequency.h deleted file mode 100644 index 3594a22b..00000000 --- a/src/include/units/dimensions/frequency.h +++ /dev/null @@ -1,71 +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 - -namespace units { - - struct frequency : derived_dimension> {}; - - template - concept Frequency = QuantityOf; - - struct hertz : named_coherent_derived_unit {}; - struct millihertz : prefixed_derived_unit {}; - struct kilohertz : prefixed_derived_unit {}; - struct megahertz : prefixed_derived_unit {}; - struct gigahertz : prefixed_derived_unit {}; - struct terahertz : prefixed_derived_unit {}; - - inline namespace literals { - - // Hz - constexpr auto operator""Hz(unsigned long long l) { return quantity(l); } - constexpr auto operator""Hz(long double l) { return quantity(l); } - - // mHz - constexpr auto operator""mHz(unsigned long long l) { return quantity(l); } - constexpr auto operator""mHz(long double l) { return quantity(l); } - - // kHz - constexpr auto operator""kHz(unsigned long long l) { return quantity(l); } - constexpr auto operator""kHz(long double l) { return quantity(l); } - - // MHz - constexpr auto operator""MHz(unsigned long long l) { return quantity(l); } - constexpr auto operator""MHz(long double l) { return quantity(l); } - - // GHz - constexpr auto operator""GHz(unsigned long long l) { return quantity(l); } - constexpr auto operator""GHz(long double l) { return quantity(l); } - - // THz - constexpr auto operator""THz(unsigned long long l) { return quantity(l); } - constexpr auto operator""THz(long double l) { return quantity(l); } - - } // namespace literals - -} // namespace units diff --git a/src/include/units/dimensions/length.h b/src/include/units/dimensions/length.h deleted file mode 100644 index d5ebb34a..00000000 --- a/src/include/units/dimensions/length.h +++ /dev/null @@ -1,88 +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 - -namespace units { - - struct length : derived_dimension> {}; - - template - concept Length = QuantityOf; - - // SI units - struct metre : named_coherent_derived_unit {}; - struct millimetre : prefixed_derived_unit {}; - struct centimetre : prefixed_derived_unit {}; - struct kilometre : prefixed_derived_unit {}; - - inline namespace literals { - - // m - constexpr auto operator""m(unsigned long long l) { return quantity(l); } - constexpr auto operator""m(long double l) { return quantity(l); } - - // mm - constexpr auto operator""mm(unsigned long long l) { return quantity(l); } - constexpr auto operator""mm(long double l) { return quantity(l); } - - // cm - constexpr auto operator""cm(unsigned long long l) { return quantity(l); } - constexpr auto operator""cm(long double l) { return quantity(l); } - - // km - constexpr auto operator""km(unsigned long long l) { return quantity(l); } - constexpr auto operator""km(long double l) { return quantity(l); } - - } // namespace literals - - // US customary units - struct yard : named_scaled_derived_unit> {}; - struct foot : named_scaled_derived_unit>> {}; - struct inch : named_scaled_derived_unit>> {}; - struct mile : named_scaled_derived_unit, yard::ratio>> {}; - - inline namespace literals { - - // yd - constexpr auto operator""yd(unsigned long long l) { return quantity(l); } - constexpr auto operator""yd(long double l) { return quantity(l); } - - // ft - constexpr auto operator""ft(unsigned long long l) { return quantity(l); } - constexpr auto operator""ft(long double l) { return quantity(l); } - - // in - constexpr auto operator""in(unsigned long long l) { return quantity(l); } - constexpr auto operator""in(long double l) { return quantity(l); } - - // mi - constexpr auto operator""mi(unsigned long long l) { return quantity(l); } - constexpr auto operator""mi(long double l) { return quantity(l); } - - } // namespace literals - -} // namespace units diff --git a/src/include/units/dimensions/physical.h b/src/include/units/dimensions/physical.h new file mode 100644 index 00000000..d92228a1 --- /dev/null +++ b/src/include/units/dimensions/physical.h @@ -0,0 +1,124 @@ +// 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 { + + // base dimension + + template + struct base_dimension { + static constexpr auto name = Name; + }; + + template + concept BaseDimension = true; + + // base dimension + + template> + struct base_unit { + static constexpr auto symbol = Symbol; + using dimension = Dim; + using prefix_type = PT; + using ratio = R; + }; + + template + concept BaseUnit = true; + + template + concept BaseUnitOf = BaseUnit && BaseDimension && std::same_as; + + + + namespace physical { + + // base dimensions + struct base_dim_length : base_dimension<"length"> {}; + struct base_dim_mass : base_dimension<"mass"> {}; + struct base_dim_time : base_dimension<"time"> {}; + struct base_dim_current : base_dimension<"current"> {}; + struct base_dim_temperature : base_dimension<"temperature"> {}; + struct base_dim_substance : base_dimension<"substance"> {}; + struct base_dim_luminous_intensity : base_dimension<"luminous intensity"> {}; + + + // dimensions + template L> + struct length : derived_dimension> {}; + + template M> + struct mass : derived_dimension> {}; + + template T> + struct time : derived_dimension> {}; + + template L, UnitOf T> + struct velocity : derived_dimension, exp> {}; + + template L, UnitOf T> + struct acceleration : derived_dimension, exp> {}; + + template M, UnitOf A> + struct force : derived_dimension, exp> {}; + + } // physical + + // SI + namespace si { + struct si_prefix; + + // length + struct metre : base_unit<"m", base_dim_length, si_prefix> {}; + struct length : physical::length {}; + + // mass + struct kilogram : base_unit<"kg", base_dim_mass, si_prefix> {}; + struct mass : physical::mass {}; + + // time + struct second : base_unit<"s", base_dim_time, si_prefix> {}; + struct time : physical::time {}; + + struct nanosecond : prefixed_derived_unit {}; + struct microsecond : prefixed_derived_unit {}; + struct millisecond : prefixed_derived_unit {}; + struct minute : named_derived_unit> {}; + struct hour : named_derived_unit> {}; + + // velocity + struct velocity : physical::velocity; + + // acceleration + struct acceleration : physical::acceleration; + + // acceleration + struct acceleration : physical::acceleration; + + } + +} // namespace units diff --git a/src/include/units/dimensions/si_base_dimensions.h b/src/include/units/dimensions/si_base_dimensions.h deleted file mode 100644 index ef2ea824..00000000 --- a/src/include/units/dimensions/si_base_dimensions.h +++ /dev/null @@ -1,37 +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 { - - struct base_dim_length : base_dimension<"length", "m"> {}; - struct base_dim_mass : base_dimension<"mass", "kg"> {}; - struct base_dim_time : base_dimension<"time", "s"> {}; - struct base_dim_current : base_dimension<"current", "A"> {}; - struct base_dim_temperature : base_dimension<"temperature", "K"> {}; - struct base_dim_substance : base_dimension<"substance", "mol"> {}; - struct base_dim_luminous_intensity : base_dimension<"luminous intensity", "cd"> {}; - -} // namespace units diff --git a/src/include/units/dimensions/time.h b/src/include/units/dimensions/time.h deleted file mode 100644 index 3c60e384..00000000 --- a/src/include/units/dimensions/time.h +++ /dev/null @@ -1,71 +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 - -namespace units { - - struct time : derived_dimension> {}; - - template - concept Time = QuantityOf; - - struct second : named_coherent_derived_unit {}; - struct nanosecond : prefixed_derived_unit {}; - struct microsecond : prefixed_derived_unit {}; - struct millisecond : prefixed_derived_unit {}; - struct minute : named_scaled_derived_unit> {}; - struct hour : named_scaled_derived_unit> {}; - - inline namespace literals { - - // ns - constexpr auto operator""ns(unsigned long long l) { return quantity(l); } - constexpr auto operator""ns(long double l) { return quantity(l); } - - // us - constexpr auto operator""us(unsigned long long l) { return quantity(l); } - constexpr auto operator""us(long double l) { return quantity(l); } - - // ms - constexpr auto operator""ms(unsigned long long l) { return quantity(l); } - constexpr auto operator""ms(long double l) { return quantity(l); } - - // s - constexpr auto operator""s(unsigned long long l) { return quantity(l); } - constexpr auto operator""s(long double l) { return quantity(l); } - - // min - constexpr auto operator""min(unsigned long long l) { return quantity(l); } - constexpr auto operator""min(long double l) { return quantity(l); } - - // h - constexpr auto operator""h(unsigned long long l) { return quantity(l); } - constexpr auto operator""h(long double l) { return quantity(l); } - - } // namespace literals - -} // namespace units diff --git a/src/include/units/dimensions/velocity.h b/src/include/units/dimensions/velocity.h deleted file mode 100644 index e583fba9..00000000 --- a/src/include/units/dimensions/velocity.h +++ /dev/null @@ -1,55 +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 { - - struct velocity : derived_dimension, exp> {}; - - template - concept Velocity = QuantityOf; - - struct metre_per_second : coherent_derived_unit {}; - struct kilometre_per_hour : deduced_derived_unit {}; - struct mile_per_hour : deduced_derived_unit {}; - - inline namespace literals { - - // mps - constexpr auto operator""mps(unsigned long long l) { return quantity(l); } - constexpr auto operator""mps(long double l) { return quantity(l); } - - // kmph - constexpr auto operator""kmph(unsigned long long l) { return quantity(l); } - constexpr auto operator""kmph(long double l) { return quantity(l); } - - // mph - constexpr auto operator""mph(unsigned long long l) { return quantity(l); } - constexpr auto operator""mph(long double l) { return quantity(l); } - - } // namespace literals - -} // namespace units diff --git a/src/include/units/math.h b/src/include/units/math.h index 1fd79d17..be9274cd 100644 --- a/src/include/units/math.h +++ b/src/include/units/math.h @@ -27,27 +27,27 @@ namespace units { - template + template requires N == 0 - inline Rep AUTO pow(const quantity&) noexcept + inline Rep AUTO pow(const quantity&) noexcept { return 1; } - template - inline Quantity AUTO pow(const quantity& q) noexcept + template + inline Quantity AUTO pow(const quantity& q) noexcept { - using dim = dimension_pow; + using dim = dimension_pow; using r = ratio_pow; - return quantity>, Rep>(static_cast(std::pow(q.count(), N))); + return quantity>, Rep>(static_cast(std::pow(q.count(), N))); } - template - inline Quantity AUTO sqrt(const quantity& q) noexcept + template + inline Quantity AUTO sqrt(const quantity& q) noexcept { using dim = dimension_sqrt; using r = ratio_sqrt; - return quantity>, Rep>(static_cast(std::sqrt(q.count()))); + return quantity>, Rep>(static_cast(std::sqrt(q.count()))); } } // namespace units diff --git a/src/include/units/physical/dimensions.h b/src/include/units/physical/dimensions.h new file mode 100644 index 00000000..7945dc8b --- /dev/null +++ b/src/include/units/physical/dimensions.h @@ -0,0 +1,151 @@ +// 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 { + +inline namespace physical { + +template typename DimTemplate> +concept DimensionOf = (Dimension || BaseDimension) && is_derived_from_instantiation; + +template typename DimTemplate> +concept QuantityOf = Quantity && is_derived_from_instantiation; + +// ------------------------ base dimensions ----------------------------- + +// length +template +struct dim_length : base_dimension<"length", U> {}; + +template +concept Length = QuantityOf; + +// mass +template +struct dim_mass : base_dimension<"mass", U> {}; + +template +concept Mass = QuantityOf; + +// time +template +struct dim_time : base_dimension<"time", U> {}; + +template +concept Time = QuantityOf; + +// current +template +struct dim_current : base_dimension<"current", U> {}; + +template +concept Current = QuantityOf; + +// temperature +template +struct dim_temperature : base_dimension<"temperature", U> {}; + +template +concept Temperature = QuantityOf; + +// substance +template +struct dim_substance : base_dimension<"substance", U> {}; + +template +concept Substance = QuantityOf; + +// luminous intensity +template +struct dim_luminous_intensity : base_dimension<"luminous intensity", U> {}; + +template +concept LuminousIntensity = QuantityOf; + +// ------------------------ derived dimensions ----------------------------- + +// frequency +template T> +struct dim_frequency : derived_dimension> {}; + +template +concept Frequency = QuantityOf; + +// area +template L> +struct dim_area : derived_dimension> {}; + +template +concept Area = QuantityOf; + +// velocity +template L, DimensionOf T> +struct dim_velocity : derived_dimension, exp> {}; + +template +concept Velocity = QuantityOf; + +// acceleration +template L, DimensionOf T> +struct dim_acceleration : derived_dimension, exp> {}; + +template +concept Acceleration = QuantityOf; + +// force +template M, DimensionOf A> +struct dim_force : derived_dimension, exp> {}; + +template +concept Force = QuantityOf; + +// energy +template F, DimensionOf L> +struct dim_energy : derived_dimension, exp> {}; + +template +concept Energy = QuantityOf; + +// power +template E, DimensionOf T> +struct dim_power : derived_dimension, exp> {}; + +template +concept Power = QuantityOf; + +// pressure +template F, DimensionOf A> +struct dim_pressure : derived_dimension, exp> {}; + +template +concept Pressure = QuantityOf; + +} // namespace physical + +} // namespace units diff --git a/src/include/units/physical/si/area.h b/src/include/units/physical/si/area.h new file mode 100644 index 00000000..52a915ed --- /dev/null +++ b/src/include/units/physical/si/area.h @@ -0,0 +1,65 @@ +// 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::si { + +struct square_metre : unit {}; +struct dim_area : physical::dim_area {}; + +struct square_millimetre : deduced_unit {}; +struct square_centimetre : deduced_unit {}; +struct square_kilometre : deduced_unit {}; +struct square_foot : deduced_unit {}; + +template +using area = quantity; + +inline namespace literals { + +// sq_m +constexpr auto operator"" sq_m(unsigned long long l) { return area(l); } +constexpr auto operator"" sq_m(long double l) { return area(l); } + +// sq_mm +constexpr auto operator"" sq_mm(unsigned long long l) { return area(l); } +constexpr auto operator"" sq_mm(long double l) { return area(l); } + +// sq_cm +constexpr auto operator"" sq_cm(unsigned long long l) { return area(l); } +constexpr auto operator"" sq_cm(long double l) { return area(l); } + +// sq_km +constexpr auto operator"" sq_km(unsigned long long l) { return area(l); } +constexpr auto operator"" sq_km(long double l) { return area(l); } + +// sq_ft +constexpr auto operator"" sq_ft(unsigned long long l) { return area(l); } +constexpr auto operator"" sq_ft(long double l) { return area(l); } + +} // namespace literals + +} // namespace units::si diff --git a/src/include/units/physical/si/frequency.h b/src/include/units/physical/si/frequency.h new file mode 100644 index 00000000..902641d2 --- /dev/null +++ b/src/include/units/physical/si/frequency.h @@ -0,0 +1,70 @@ +// 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::si { + +struct hertz : named_unit {}; +struct millihertz : prefixed_unit {}; +struct kilohertz : prefixed_unit {}; +struct megahertz : prefixed_unit {}; +struct gigahertz : prefixed_unit {}; +struct terahertz : prefixed_unit {}; + +struct dim_frequency : physical::dim_frequency {}; + +template +using frequency = quantity; + +inline namespace literals { + +// Hz +constexpr auto operator"" Hz(unsigned long long l) { return frequency(l); } +constexpr auto operator"" Hz(long double l) { return frequency(l); } + +// mHz +constexpr auto operator"" mHz(unsigned long long l) { return frequency(l); } +constexpr auto operator"" mHz(long double l) { return frequency(l); } + +// kHz +constexpr auto operator"" kHz(unsigned long long l) { return frequency(l); } +constexpr auto operator"" kHz(long double l) { return frequency(l); } + +// MHz +constexpr auto operator"" MHz(unsigned long long l) { return frequency(l); } +constexpr auto operator"" MHz(long double l) { return frequency(l); } + +// GHz +constexpr auto operator"" GHz(unsigned long long l) { return frequency(l); } +constexpr auto operator"" GHz(long double l) { return frequency(l); } + +// THz +constexpr auto operator"" THz(unsigned long long l) { return frequency(l); } +constexpr auto operator"" THz(long double l) { return frequency(l); } + +} // namespace literals + +} // namespace units::si diff --git a/src/include/units/physical/si/length.h b/src/include/units/physical/si/length.h new file mode 100644 index 00000000..bd9c27df --- /dev/null +++ b/src/include/units/physical/si/length.h @@ -0,0 +1,86 @@ +// 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::si { + +struct metre : named_unit {}; +struct millimetre : prefixed_unit {}; +struct centimetre : prefixed_unit {}; +struct kilometre : prefixed_unit {}; + +struct dim_length : physical::dim_length {}; + +template +using length = quantity; + +inline namespace literals { + +// m +constexpr auto operator"" m(unsigned long long l) { return length(l); } +constexpr auto operator"" m(long double l) { return length(l); } + +// mm +constexpr auto operator"" mm(unsigned long long l) { return length(l); } +constexpr auto operator"" mm(long double l) { return length(l); } + +// cm +constexpr auto operator"" cm(unsigned long long l) { return length(l); } +constexpr auto operator"" cm(long double l) { return length(l); } + +// km +constexpr auto operator"" km(unsigned long long l) { return length(l); } +constexpr auto operator"" km(long double l) { return length(l); } + +} // namespace literals + +// US customary units +struct yard : scaled_unit, metre> {}; +struct foot : scaled_unit, yard> {}; +struct inch : scaled_unit, foot> {}; +struct mile : scaled_unit, yard> {}; + +inline namespace literals { + +// yd +constexpr auto operator"" yd(unsigned long long l) { return length(l); } +constexpr auto operator"" yd(long double l) { return length(l); } + +// ft +constexpr auto operator"" ft(unsigned long long l) { return length(l); } +constexpr auto operator"" ft(long double l) { return length(l); } + +// in +constexpr auto operator"" in(unsigned long long l) { return length(l); } +constexpr auto operator"" in(long double l) { return length(l); } + +// mi +constexpr auto operator"" mi(unsigned long long l) { return length(l); } +constexpr auto operator"" mi(long double l) { return length(l); } + +} // namespace literals + +} // namespace units::si diff --git a/src/include/units/physical/si/time.h b/src/include/units/physical/si/time.h new file mode 100644 index 00000000..0e1b409e --- /dev/null +++ b/src/include/units/physical/si/time.h @@ -0,0 +1,70 @@ +// 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::si { + +struct second : named_unit {}; +struct nanosecond : prefixed_unit {}; +struct microsecond : prefixed_unit {}; +struct millisecond : prefixed_unit {}; +struct minute : scaled_unit, second> {}; +struct hour : scaled_unit, second> {}; + +struct dim_time : physical::dim_time {}; + +template +using time = quantity; + +inline namespace literals { + +// ns +constexpr auto operator""ns(unsigned long long l) { return time(l); } +constexpr auto operator""ns(long double l) { return time(l); } + +// us +constexpr auto operator""us(unsigned long long l) { return time(l); } +constexpr auto operator""us(long double l) { return time(l); } + +// ms +constexpr auto operator""ms(unsigned long long l) { return time(l); } +constexpr auto operator""ms(long double l) { return time(l); } + +// s +constexpr auto operator""s(unsigned long long l) { return time(l); } +constexpr auto operator""s(long double l) { return time(l); } + +// min +constexpr auto operator""min(unsigned long long l) { return time(l); } +constexpr auto operator""min(long double l) { return time(l); } + +// h +constexpr auto operator""h(unsigned long long l) { return time(l); } +constexpr auto operator""h(long double l) { return time(l); } + +} // namespace literals + +} // namespace units::si diff --git a/src/include/units/physical/si/velocity.h b/src/include/units/physical/si/velocity.h new file mode 100644 index 00000000..bb551919 --- /dev/null +++ b/src/include/units/physical/si/velocity.h @@ -0,0 +1,56 @@ +// 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 + +namespace units::si { + +struct metre_per_second : unit {}; +struct dim_velocity : physical::dim_velocity {}; + +struct kilometre_per_hour : deduced_unit {}; +struct mile_per_hour : deduced_unit {}; + +template +using velocity = quantity; + +inline namespace literals { + +// mps +constexpr auto operator"" mps(unsigned long long l) { return velocity(l); } +constexpr auto operator"" mps(long double l) { return velocity(l); } + +// kmph +constexpr auto operator"" kmph(unsigned long long l) { return velocity(l); } +constexpr auto operator"" kmph(long double l) { return velocity(l); } + +// mph +constexpr auto operator"" mph(unsigned long long l) { return velocity(l); } +constexpr auto operator"" mph(long double l) { return velocity(l); } + +} // namespace literals + +} // namespace units::si diff --git a/src/include/units/quantity.h b/src/include/units/quantity.h index b80ecc83..7b62210b 100644 --- a/src/include/units/quantity.h +++ b/src/include/units/quantity.h @@ -22,518 +22,578 @@ #pragma once -#include +#include #include #include #include namespace units { - // is_quantity - namespace detail { +// Quantity +namespace detail { - template - inline constexpr bool is_quantity = false; +template +inline constexpr bool is_quantity = false; - // partial specialization below after the first quantity forward declaration +// partial specialization below after the first quantity forward declaration - } // namespace detail +} // namespace detail - template - concept Quantity = detail::is_quantity; +template +concept Quantity = detail::is_quantity; - template - concept QuantityOf = Quantity && Dimension && same_dim; +// QuantityOf +template +concept QuantityOf = Quantity && Dimension && same_dim; - // Scalar - template - concept Scalar = - (!Quantity) && - std::regular && - std::totally_ordered && - detail::basic_arithmetic; +// Scalar +template +concept Scalar = (!Quantity) && std::regular && std::totally_ordered && detail::basic_arithmetic; - template - class quantity; +template U, Scalar Rep> +class quantity; - namespace detail { +namespace detail { - template - inline constexpr bool is_quantity> = true; +template +inline constexpr bool is_quantity> = true; - } // namespace detail +} // namespace detail - // common_quantity - namespace detail { +// common_quantity +namespace detail { - template - struct common_quantity_impl; +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; +}; - template - requires same_dim - struct common_quantity_impl, quantity, Rep> { - using type = - quantity>>, - Rep>; - }; +template +struct common_quantity_impl, quantity, Rep> { + using type = quantity< + D, downcast>>, + Rep>; +}; - } // namespace detail +} // namespace detail - template> - using common_quantity = detail::common_quantity_impl::type; +template> +using common_quantity = detail::common_quantity_impl::type; - // quantity_cast +// quantity_cast +namespace detail { - 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))); - } - }; - - } // namespace detail - - template - [[nodiscard]] constexpr auto quantity_cast(const quantity& q) - requires same_dim && - detail::basic_arithmetic> +template +struct quantity_cast_impl { + template + static constexpr To cast(const Q& q) { - using c_ratio = ratio_divide; - using c_rep = std::common_type_t; - using ret_dim = downcast; - using ret_unit = downcast>; - using ret = quantity; - using cast = detail::quantity_cast_impl; - return cast::cast(q); - } - - template - [[nodiscard]] constexpr auto quantity_cast(const quantity& q) - requires same_dim && - detail::basic_arithmetic> - { - return quantity_cast>(q); - } - - template - [[nodiscard]] constexpr auto quantity_cast(const quantity& q) - requires same_dim - { - return quantity_cast>(q); - } - - template - [[nodiscard]] constexpr auto quantity_cast(const quantity& q) - requires detail::basic_arithmetic> - { - return quantity_cast>(q); - } - - // quantity_values - - template - struct quantity_values { - static constexpr Rep zero() noexcept { return Rep(0); } - static constexpr Rep one() noexcept { return Rep(1); } - static constexpr Rep max() noexcept { return std::numeric_limits::max(); } - static constexpr Rep min() noexcept { return std::numeric_limits::lowest(); } - }; - - - // quantity - - template - class quantity { - Rep value_; - - public: - using unit = U; - using rep = Rep; - using dimension = U::dimension; - - quantity() = default; - quantity(const quantity&) = default; - quantity(quantity&&) = default; - - template - requires detail::safe_convertible - constexpr explicit quantity(const Value& v): value_{static_cast(v)} - { + 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 - requires same_dim && - detail::safe_convertible && - detail::safe_divisible - constexpr quantity(const Q2& q): value_{quantity_cast(q).count()} - { +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))); } + } +}; - quantity& operator=(const quantity&) = default; - quantity& operator=(quantity&&) = default; - - [[nodiscard]] constexpr rep count() const noexcept { return value_; } - - template - [[nodiscard]] static constexpr quantity zero() noexcept - requires requires { quantity_values::zero(); } - // requires requires { quantity_values::zero(); } // TODO gated by gcc-9 (fixed in gcc-10) - { - return quantity(quantity_values::zero()); - } - - template - [[nodiscard]] static constexpr quantity one() noexcept - requires requires { quantity_values::one(); } -// requires requires { quantity_values::one(); } // TODO gated by gcc-9 (fixed in gcc-10) - { - return quantity(quantity_values::one()); - } - - template - [[nodiscard]] static constexpr quantity min() noexcept - requires requires { quantity_values::min(); } -// requires requires { quantity_values::min(); } // TODO gated by gcc-9 (fixed in gcc-10) - { - return quantity(quantity_values::min()); - } - - template - [[nodiscard]] static constexpr quantity max() noexcept - requires requires { quantity_values::max(); } -// requires requires { quantity_values::max(); } // TODO gated by gcc-9 (fixed in gcc-10) - { - return quantity(quantity_values::max()); - } - - [[nodiscard]] constexpr quantity operator+() const { return *this; } - - template - [[nodiscard]] constexpr quantity operator-() const - requires std::regular_invocable -// requires std::regular_invocable // TODO gated by gcc-9 (fixed in gcc-10) - { - return quantity(-count()); - } - - template - constexpr quantity& operator++() - requires requires(T v) { { ++v } -> SAME_AS(T&); } -// requires requires(rep v) { { ++v } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) - { - ++value_; - return *this; - } - - template - requires requires(T v) { { v++ } -> SAME_AS(T); } - constexpr quantity operator++(int) - // requires requires(rep v) { { v++ } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) - { return quantity(value_++); } - - template - requires requires(T v) { { --v } -> SAME_AS(T&); } - constexpr quantity& operator--() - // requires requires(rep v) { { --v } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) - { - --value_; - return *this; - } - - template - requires requires(T v) { { v-- } -> SAME_AS(T); } - constexpr quantity operator--(int) - // requires requires(rep v) { { v-- } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) - { return quantity(value_--); } - - template - requires requires(T v1, T v2) { { v1 += v2 } -> SAME_AS(T&); } - constexpr quantity& operator+=(const quantity& q) - // requires requires(rep v1, rep v2) { { v1 += v2 } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) - { - value_ += q.count(); - return *this; - } - - template - requires requires(T v1, T v2) { { v1 -= v2 } -> SAME_AS(T&); } - constexpr quantity& operator-=(const quantity& q) - // requires requires(rep v1, rep v2) { { v1 -= v2 } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) - { - value_ -= q.count(); - return *this; - } - - template - requires requires(T v1, T v2) { { v1 *= v2 } -> SAME_AS(T&); } - constexpr quantity& operator*=(const rep& rhs) - // requires requires(rep v1, rep v2) { { v1 *= v2 } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) - { - value_ *= rhs; - return *this; - } - - template - requires requires(T v1, T v2) { { v1 /= v2 } -> SAME_AS(T&); } - constexpr quantity& operator/=(const rep& rhs) - // requires requires(rep v1, rep v2) { { v1 /= v2 } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) - { - value_ /= rhs; - return *this; - } - - template - constexpr quantity& operator%=(const Value& rhs) - requires (!treat_as_floating_point) && - (!treat_as_floating_point) && - requires(T v1, Value v2) { { v1 %= v2 } -> SAME_AS(T&); } - // requires(rep v1, Value v2) { { v1 %= v2 } -> SAME_AS(rep&); } // TODO gated by gcc-9 (fixed in gcc-10) - { - value_ %= rhs; - return *this; - } - - template - constexpr quantity& operator%=(const quantity& q) - requires (!treat_as_floating_point) && - requires(T v1, T v2) { { v1 %= v2 } -> SAME_AS(T&); } - // requires(rep v1, rep v2) { { v1 %= v2 } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) - { - value_ %= q.count(); - return *this; - } - - template - friend std::basic_ostream& operator<<(std::basic_ostream& os, const quantity& q) - { - return os << q.count() << " " << detail::unit_text(); - } - }; - - template - [[nodiscard]] constexpr Quantity AUTO operator+(const quantity& lhs, const quantity& rhs) - requires same_dim && detail::basic_arithmetic +template +struct quantity_cast_impl { + template + static constexpr To cast(const Q& q) { - using common_rep = decltype(lhs.count() + rhs.count()); - using ret = common_quantity, quantity, common_rep>; - return ret(ret(lhs).count() + ret(rhs).count()); + return To(static_cast(static_cast(q.count()) * static_cast(CRatio::num))); + } +}; + +} // 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: + * + * using seconds = units::time; + * 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 = ratio_divide; + using c_rep = std::common_type_t; + using ret_unit = downcast>; + 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 both the target unit and representation to cast to. For example: + * + * auto q1 = units::quantity_cast(1ms); + * + * @tparam ToU a unit type to use for a target quantity + * @tparam ToRep a representation type to use for a target quantity + */ +template +[[nodiscard]] constexpr auto quantity_cast(const quantity& q) + requires UnitOf && + detail::basic_arithmetic> +{ + 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(); } +}; + +/** + * @brief A quantity + * + * Property of a phenomenon, body, or substance, where the property has a magnitude that can be + * expressed by means of a number and a measurement unit. + * + * @tparam D a dimension of the quantity (can be either a BaseDimension or a DerivedDimension) + * @tparam U a measurement unit of the quantity + * @tparam Rep a type to be used to represent values of a quantity + */ +template U, Scalar Rep = double> +class quantity { + Rep value_; + +public: + using dimension = D; + using unit = U; + using rep = Rep; + + quantity() = default; + quantity(const quantity&) = default; + quantity(quantity&&) = default; + + template + requires detail::safe_convertible + constexpr explicit quantity(const Value& v) : value_{static_cast(v)} {} + + template + requires same_dim && + detail::safe_convertible && + detail::safe_divisible + constexpr quantity(const Q2& q) : value_{quantity_cast(q).count()} {} + + quantity& operator=(const quantity&) = default; + quantity& operator=(quantity&&) = default; + + [[nodiscard]] constexpr rep count() const noexcept { return value_; } + + template + [[nodiscard]] static constexpr quantity zero() noexcept + requires requires { quantity_values::zero(); } + // requires requires { quantity_values::zero(); } // TODO gated by gcc-9 (fixed in gcc-10) + { + return quantity(quantity_values::zero()); } - template - [[nodiscard]] constexpr Quantity AUTO operator-(const quantity& lhs, const quantity& rhs) - requires same_dim && - detail::basic_arithmetic + template + [[nodiscard]] static constexpr quantity one() noexcept + requires requires { quantity_values::one(); } + // requires requires { quantity_values::one(); } // TODO gated by gcc-9 (fixed in gcc-10) { - using common_rep = decltype(lhs.count() - rhs.count()); - using ret = common_quantity, quantity, common_rep>; - return ret(ret(lhs).count() - ret(rhs).count()); + return quantity(quantity_values::one()); } - template - [[nodiscard]] constexpr Quantity AUTO operator*(const quantity& q, const Value& v) - requires std::magma + template + [[nodiscard]] static constexpr quantity min() noexcept + requires requires { quantity_values::min(); } + // requires requires { quantity_values::min(); } // TODO gated by gcc-9 (fixed in gcc-10) { - using common_rep = decltype(q.count() * v); - using ret = quantity; - return ret(q.count() * v); + return quantity(quantity_values::min()); } - template - [[nodiscard]] constexpr Quantity AUTO operator*(const Value& v, const quantity& q) - requires std::magma + template + [[nodiscard]] static constexpr quantity max() noexcept + requires requires { quantity_values::max(); } + // requires requires { quantity_values::max(); } // TODO gated by gcc-9 (fixed in gcc-10) { - return q * v; + return quantity(quantity_values::max()); } - template - [[nodiscard]] constexpr Scalar AUTO operator*(const quantity& lhs, const quantity& rhs) - requires same_dim> && - detail::basic_arithmetic + [[nodiscard]] constexpr quantity operator+() const { return *this; } + + template + [[nodiscard]] constexpr quantity operator-() const + requires std::regular_invocable + // requires std::regular_invocable // TODO gated by gcc-9 (fixed in gcc-10) { - using common_rep = decltype(lhs.count() * rhs.count()); - using ratio = ratio_multiply; - return common_rep(lhs.count()) * common_rep(rhs.count()) * common_rep(ratio::num) / common_rep(ratio::den); + return quantity(-count()); } - template - [[nodiscard]] constexpr Quantity AUTO operator*(const quantity& lhs, const quantity& rhs) - requires (!same_dim>) && - (treat_as_floating_point || - (std::ratio_multiply::den == 1)) && - detail::basic_arithmetic + template + constexpr quantity& operator++() + requires requires(T v) { { ++v } -> SAME_AS(T&); } + // requires requires(rep v) { { ++v } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) { - using dim = dimension_multiply; - using common_rep = decltype(lhs.count() * rhs.count()); - using ret = quantity>>, common_rep>; - return ret(lhs.count() * rhs.count()); + ++value_; + return *this; } - template - [[nodiscard]] constexpr Quantity AUTO operator/(const Value& v, const quantity& q) - requires std::magma + template + requires requires(T v) { { v++ } -> SAME_AS(T); } + constexpr quantity operator++(int) + // requires requires(rep v) { { v++ } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) { - Expects(q != std::remove_cvref_t(0)); - - using dim = dim_invert; - using common_rep = decltype(v / q.count()); - using ret = quantity>>, common_rep>; - return ret(v / q.count()); + return quantity(value_++); } - template - [[nodiscard]] constexpr Quantity AUTO operator/(const quantity& q, const Value& v) - requires std::magma + template + requires requires(T v) { { --v } -> SAME_AS(T&); } + constexpr quantity& operator--() + // requires requires(rep v) { { --v } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) { - Expects(v != Value{0}); - - using common_rep = decltype(q.count() / v); - using ret = quantity; - return ret(q.count() / v); + --value_; + return *this; } - template - [[nodiscard]] constexpr Scalar AUTO operator/(const quantity& lhs, const quantity& rhs) - requires same_dim && - detail::basic_arithmetic + template + requires requires(T v) { { v-- } -> SAME_AS(T); } + constexpr quantity operator--(int) + // requires requires(rep v) { { v-- } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) { - Expects(rhs != std::remove_cvref_t(0)); - - using common_rep = decltype(lhs.count() / rhs.count()); - using cq = common_quantity, quantity, common_rep>; - return cq(lhs).count() / cq(rhs).count(); + return quantity(value_--); } - template - [[nodiscard]] constexpr Quantity AUTO operator/(const quantity& lhs, const quantity& rhs) - requires (!same_dim) && - (treat_as_floating_point || - (ratio_divide::den == 1)) && - detail::basic_arithmetic + template + requires requires(T v1, T v2) { { v1 += v2 } -> SAME_AS(T&); } + constexpr quantity& operator+=(const quantity& q) + // requires requires(rep v1, rep v2) { { v1 += v2 } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) { - Expects(rhs != std::remove_cvref_t(0)); - - using common_rep = decltype(lhs.count() / rhs.count()); - using dim = dimension_divide; - using ret = quantity>>, common_rep>; - return ret(lhs.count() / rhs.count()); + value_ += q.count(); + return *this; } - template - [[nodiscard]] constexpr Quantity AUTO operator%(const quantity& q, const Value& v) - requires (!treat_as_floating_point) && (!treat_as_floating_point) && - std::magma + template + requires requires(T v1, T v2) { { v1 -= v2 } -> SAME_AS(T&); } + constexpr quantity& operator-=(const quantity& q) + // requires requires(rep v1, rep v2) { { v1 -= v2 } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) { - using common_rep = decltype(q.count() % v); - using ret = quantity; - return ret(q.count() % v); + value_ -= q.count(); + return *this; } - template - [[nodiscard]] constexpr Quantity AUTO operator%(const quantity& lhs, const quantity& rhs) - requires (!treat_as_floating_point) && (!treat_as_floating_point) && - std::magma + template + requires requires(T v1, T v2) { { v1 *= v2 } -> SAME_AS(T&); } + constexpr quantity& operator*=(const rep& rhs) + // requires requires(rep v1, rep v2) { { v1 *= v2 } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) { - using common_rep = decltype(lhs.count() % rhs.count()); - using ret = common_quantity, quantity, common_rep>; - return ret(ret(lhs).count() % ret(rhs).count()); + value_ *= rhs; + return *this; } - template - [[nodiscard]] constexpr bool operator==(const quantity& lhs, const quantity& rhs) - requires same_dim && - detail::basic_arithmetic && std::equality_comparable_with + template + requires requires(T v1, T v2) { { v1 /= v2 } -> SAME_AS(T&); } + constexpr quantity& operator/=(const rep& rhs) + // requires requires(rep v1, rep v2) { { v1 /= v2 } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) { - using cq = common_quantity, quantity>; - return cq(lhs).count() == cq(rhs).count(); + value_ /= rhs; + return *this; } - template - [[nodiscard]] constexpr bool operator!=(const quantity& lhs, const quantity& rhs) - requires same_dim && - detail::basic_arithmetic && std::equality_comparable_with + template + constexpr quantity& operator%=(const Value& rhs) + requires (!treat_as_floating_point) && + (!treat_as_floating_point) && + requires(T v1, Value v2) { { v1 %= v2 } -> SAME_AS(T&); } + // requires(rep v1, Value v2) { { v1 %= v2 } -> SAME_AS(rep&); } // TODO gated by gcc-9 (fixed in gcc-10) { - return !(lhs == rhs); + value_ %= rhs; + return *this; } - template - [[nodiscard]] constexpr bool operator<(const quantity& lhs, const quantity& rhs) - requires same_dim && - detail::basic_arithmetic && std::totally_ordered_with + template + constexpr quantity& operator%=(const quantity& q) + requires (!treat_as_floating_point) && + requires(T v1, T v2) { { v1 %= v2 } -> SAME_AS(T&); } + // requires(rep v1, rep v2) { { v1 %= v2 } -> std::same_as; } // TODO gated by gcc-9 (fixed in gcc-10) { - using cq = common_quantity, quantity>; - return cq(lhs).count() < cq(rhs).count(); + value_ %= q.count(); + return *this; } - template - [[nodiscard]] constexpr bool operator<=(const quantity& lhs, const quantity& rhs) - requires same_dim && - detail::basic_arithmetic && std::totally_ordered_with + template + friend std::basic_ostream& operator<<(std::basic_ostream& os, const quantity& q) { - return !(rhs < lhs); + return os; // << q.count() << " " << detail::unit_text(); } +}; - template - [[nodiscard]] constexpr bool operator>(const quantity& lhs, const quantity& rhs) - requires same_dim && - detail::basic_arithmetic && std::totally_ordered_with - { - return rhs < lhs; - } +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 bool operator>=(const quantity& lhs, const quantity& rhs) - requires same_dim && - detail::basic_arithmetic && std::totally_ordered_with - { - return !(lhs < rhs); - } +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) + requires std::magma +{ + using common_rep = decltype(q.count() * v); + using ret = quantity; + return ret(q.count() * v); +} + +template +[[nodiscard]] constexpr Quantity AUTO operator*(const Value& v, const quantity& q) + requires std::magma +{ + return q * v; +} + +template +[[nodiscard]] constexpr Scalar AUTO operator*(const quantity& lhs, const quantity& rhs) + requires same_dim>&& detail::basic_arithmetic +{ + using common_rep = decltype(lhs.count() * rhs.count()); + using ratio = ratio_multiply; + return common_rep(lhs.count()) * common_rep(rhs.count()) * common_rep(ratio::num) / common_rep(ratio::den); +} + +template +[[nodiscard]] constexpr Quantity AUTO operator*(const quantity& lhs, const quantity& rhs) + requires (!same_dim>) && + (treat_as_floating_point || + (std::ratio_multiply::den == 1)) && + detail::basic_arithmetic +{ + using dim = dimension_multiply; + using ratio = ratio_multiply; + using unit = downcast>; + using common_rep = decltype(lhs.count() * rhs.count()); + using ret = quantity; + return ret(lhs.count() * rhs.count()); +} + +template +[[nodiscard]] constexpr Quantity AUTO operator/(const Value& v, const quantity& q) + requires std::magma +{ + Expects(q != std::remove_cvref_t(0)); + + using dim = dim_invert; + using ratio = ratio; + using unit = downcast>; + using common_rep = decltype(v / q.count()); + using ret = quantity; + return ret(v / q.count()); +} + +template +[[nodiscard]] constexpr Quantity AUTO operator/(const quantity& q, const Value& v) + requires std::magma +{ + Expects(v != Value{0}); + + using common_rep = decltype(q.count() / v); + using ret = quantity; + return ret(q.count() / v); +} + +template +[[nodiscard]] constexpr Scalar AUTO operator/(const quantity& lhs, const quantity& rhs) + requires detail::basic_arithmetic +{ + Expects(rhs != std::remove_cvref_t(0)); + + using common_rep = decltype(lhs.count() / rhs.count()); + using cq = common_quantity, quantity, common_rep>; + return cq(lhs).count() / cq(rhs).count(); +} + +template +[[nodiscard]] constexpr Quantity AUTO operator/(const quantity& lhs, const quantity& rhs) + requires (treat_as_floating_point || + (ratio_divide::den == 1)) && + detail::basic_arithmetic +{ + Expects(rhs != std::remove_cvref_t(0)); + + using common_rep = decltype(lhs.count() / rhs.count()); + using dim = dimension_divide; + using unit = downcast>>; + using ret = quantity; + return ret(lhs.count() / rhs.count()); +} + +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()); +} + +template +[[nodiscard]] constexpr bool operator==(const quantity& lhs, const quantity& rhs) + requires detail::basic_arithmetic && + std::equality_comparable_with +{ + using cq = common_quantity, quantity>; + return cq(lhs).count() == cq(rhs).count(); +} + +template +[[nodiscard]] constexpr bool operator!=(const quantity& lhs, const quantity& rhs) + requires detail::basic_arithmetic && + std::equality_comparable_with +{ + return !(lhs == rhs); +} + +template +[[nodiscard]] constexpr bool operator<(const quantity& lhs, const quantity& rhs) + requires detail::basic_arithmetic && + std::totally_ordered_with +{ + using cq = common_quantity, quantity>; + return cq(lhs).count() < cq(rhs).count(); +} + +template +[[nodiscard]] constexpr bool operator<=(const quantity& lhs, const quantity& rhs) + requires detail::basic_arithmetic && + std::totally_ordered_with +{ + return !(rhs < lhs); +} + +template +[[nodiscard]] constexpr bool operator>(const quantity& lhs, const quantity& rhs) + requires detail::basic_arithmetic && + std::totally_ordered_with +{ + return rhs < lhs; +} + +template +[[nodiscard]] constexpr bool operator>=(const quantity& lhs, const quantity& rhs) + requires detail::basic_arithmetic && + std::totally_ordered_with +{ + return !(lhs < rhs); +} } // namespace units diff --git a/src/include/units/unit.h b/src/include/units/unit.h index 8c50c259..09ab02f8 100644 --- a/src/include/units/unit.h +++ b/src/include/units/unit.h @@ -42,6 +42,13 @@ struct reference_unit : downcast_base> { } // namespace detail +// UnitOf +template +concept UnitOf = + Unit && + Dimension && + std::same_as; + namespace detail { // same_reference_units @@ -49,8 +56,7 @@ template inline constexpr bool same_reference_units = false; template -inline constexpr bool same_reference_units, Us...> = - (std::same_as && ...); +inline constexpr bool same_reference_units, Us...> = (UnitOf && ...); // deduced_unit template diff --git a/test/unit_test/static/CMakeLists.txt b/test/unit_test/static/CMakeLists.txt index b0017fbc..0eb0c108 100644 --- a/test/unit_test/static/CMakeLists.txt +++ b/test/unit_test/static/CMakeLists.txt @@ -27,7 +27,7 @@ add_library(unit_tests_static # fixed_string_test.cpp # math_test.cpp # new_design.cpp -# quantity_test.cpp + quantity_test.cpp ratio_test.cpp # si_test.cpp type_list_test.cpp diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index a0d55d13..ff029a5f 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -20,299 +20,319 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -#include "units/dimensions/velocity.h" -#include "units/dimensions/frequency.h" -#include "units/dimensions/area.h" #include "units/math.h" -#include +#include "units/physical/si/area.h" +#include "units/physical/si/frequency.h" +#include "units/physical/si/velocity.h" #include +#include using namespace units; namespace { - template - class my_value { - T value_{}; - public: - my_value() = default; - constexpr my_value(T v) : value_(std::move(v)) {} - [[nodiscard]] constexpr my_value operator-() const { return my_value(-value_); } +template +class my_value { + T value_{}; - [[nodiscard]] friend constexpr my_value operator+(my_value lhs, my_value rhs) { return my_value(lhs.value_ + rhs.value_); } - [[nodiscard]] friend constexpr my_value operator-(my_value lhs, my_value rhs) { return my_value(lhs.value_ - rhs.value_); } - [[nodiscard]] friend constexpr my_value operator*(my_value lhs, my_value rhs) { return my_value(lhs.value_ * rhs.value_); } - [[nodiscard]] friend constexpr my_value operator/(my_value lhs, my_value rhs) { return my_value(lhs.value_ / rhs.value_); } +public: + my_value() = default; + constexpr my_value(T v) : value_(std::move(v)) {} - [[nodiscard]] friend constexpr bool operator==(my_value lhs, my_value rhs) { return lhs.value_ == rhs.value_; } - [[nodiscard]] friend constexpr bool operator!=(my_value lhs, my_value rhs) { return !(lhs == rhs); } - [[nodiscard]] friend constexpr bool operator<(my_value lhs, my_value rhs) { return lhs.value_ < rhs.value_; } - [[nodiscard]] friend constexpr bool operator>(my_value lhs, my_value rhs) { return rhs < lhs; } - [[nodiscard]] friend constexpr bool operator<=(my_value lhs, my_value rhs) { return !(rhs < lhs); } - [[nodiscard]] friend constexpr bool operator>=(my_value lhs, my_value rhs) { return !(lhs < rhs); } + // constexpr my_value& operator+=(my_value other) { value_ += other.value_; return *this; } + // constexpr my_value& operator-=(my_value other) { value_ -= other.value_; return *this; } + // constexpr my_value& operator*=(my_value other) { value_ *= other.value_; return *this; } + // constexpr my_value& operator/=(my_value other) { value_ /= other.value_; return *this; } - constexpr operator const T&() const & { return value_; } - }; + [[nodiscard]] constexpr my_value operator-() const { return my_value(-value_); } + + [[nodiscard]] friend constexpr my_value operator+(my_value lhs, my_value rhs) { + return my_value(lhs.value_ + rhs.value_); + } + [[nodiscard]] friend constexpr my_value operator-(my_value lhs, my_value rhs) { + return my_value(lhs.value_ - rhs.value_); + } + [[nodiscard]] friend constexpr my_value operator*(my_value lhs, my_value rhs) { + return my_value(lhs.value_ * rhs.value_); + } + [[nodiscard]] friend constexpr my_value operator/(my_value lhs, my_value rhs) { + return my_value(lhs.value_ / rhs.value_); + } + + [[nodiscard]] friend constexpr bool operator==(my_value lhs, my_value rhs) { return lhs.value_ == rhs.value_; } + [[nodiscard]] friend constexpr bool operator!=(my_value lhs, my_value rhs) { return !(lhs == rhs); } + [[nodiscard]] friend constexpr bool operator<(my_value lhs, my_value rhs) { return lhs.value_ < rhs.value_; } + [[nodiscard]] friend constexpr bool operator>(my_value lhs, my_value rhs) { return rhs < lhs; } + [[nodiscard]] friend constexpr bool operator<=(my_value lhs, my_value rhs) { return !(rhs < lhs); } + [[nodiscard]] friend constexpr bool operator>=(my_value lhs, my_value rhs) { return !(lhs < rhs); } + + constexpr operator const T&() const& { return value_; } +}; } // namespace namespace units { - template - inline constexpr bool treat_as_floating_point> = std::is_floating_point_v; +template +inline constexpr bool treat_as_floating_point> = std::is_floating_point_v; - template - struct quantity_values> { - static constexpr my_value zero() { return my_value(0); } - static constexpr my_value max() { return std::numeric_limits::max(); } - static constexpr my_value min() { return std::numeric_limits::lowest(); } - }; +template +struct quantity_values> { + static constexpr my_value zero() { return my_value(0); } + static constexpr my_value max() { return std::numeric_limits::max(); } + static constexpr my_value min() { return std::numeric_limits::lowest(); } +}; } // namespace units namespace std { - template - struct common_type, my_value> : std::type_identity>> { - }; +template +struct common_type, my_value> : std::type_identity>> {}; - template - struct common_type, U> : common_type { - }; +template +struct common_type, U> : common_type {}; - template - struct common_type> : common_type { - }; +template +struct common_type> : common_type {}; } // namespace std namespace { - static_assert(units::Scalar>); - static_assert(std::convertible_to, float>); - static_assert(std::convertible_to>); +static_assert(units::Scalar>); +static_assert(std::convertible_to, float>); +static_assert(std::convertible_to>); - using namespace units; +using namespace units; +using namespace units::si; - // class invariants +// class invariants - // constexpr quantity q; // should a static_assert - // constexpr quantity> error(0m); // should trigger a static_assert - // constexpr quantity error(0); // should trigger a static_assert - // constexpr quantity>, int> error(0); // should trigger a static_assert +// constexpr quantity q(1); // should not compile +// constexpr quantity> error(0m); // should trigger a static_assert +// constexpr quantity error(0); // should trigger a static_assert +// constexpr quantity>, int> error(0); // should trigger a static_assert - // member types +// member types - static_assert(std::is_same_v::rep, int>); - static_assert(std::is_same_v::rep, double>); - static_assert(std::is_same_v::unit, metre>); - static_assert(std::is_same_v::unit, kilometre>); +static_assert(std::is_same_v::rep, int>); +static_assert(std::is_same_v::rep, double>); +static_assert(std::is_same_v::unit, metre>); +static_assert(std::is_same_v::unit, kilometre>); - // constructors +// constructors - using my_int = my_value; - using my_double = my_value; +using my_int = my_value; +using my_double = my_value; - static_assert(quantity().count() == 0); - constexpr quantity km{1000}; - static_assert(km.count() == 1000); - static_assert(quantity(km).count() == km.count()); +static_assert(length().count() == 0); +constexpr length km{1000}; +static_assert(km.count() == 1000); +static_assert(length(km).count() == km.count()); - static_assert(quantity(1).count() == 1); - static_assert(quantity(my_value(1)).count() == 1); - static_assert(quantity(1).count() == my_int{1}); - // static_assert(quantity(1.0).count() == 1); // should not compile - // static_assert(quantity(my_value(1.0)).count() == 1); // should not compile - // static_assert(quantity(1.0).count() == 1); // should not compile - static_assert(quantity(1.0).count() == 1.0); - static_assert(quantity(my_value(1.0)).count() == 1.0); - static_assert(quantity(1).count() == 1.0); - static_assert(quantity(my_value(1)).count() == 1.0); - static_assert(quantity(3.14).count() == 3.14); - static_assert(quantity(1.0).count() == my_double{1.0}); - static_assert(quantity(1).count() == my_double{1.0}); - static_assert(quantity(3.14).count() == my_double{3.14}); +static_assert(length(1).count() == 1); +static_assert(length(my_value(1)).count() == 1); +static_assert(length(1).count() == my_int{1}); +// static_assert(length(1.0).count() == 1); // should not compile +// static_assert(length(my_value(1.0)).count() == 1); // should not compile +// static_assert(length(1.0).count() == 1); // should not compile +static_assert(length(1.0).count() == 1.0); +static_assert(length(my_value(1.0)).count() == 1.0); +static_assert(length(1).count() == 1.0); +static_assert(length(my_value(1)).count() == 1.0); +static_assert(length(3.14).count() == 3.14); +static_assert(length(1.0).count() == my_double{1.0}); +static_assert(length(1).count() == my_double{1.0}); +static_assert(length(3.14).count() == my_double{3.14}); - static_assert(quantity(km).count() == 1000); - // static_assert(quantity(quantity(3.14)).count() == 3); // should not compile - static_assert(quantity(quantity_cast>(3.14m)).count() == 3); - // static_assert(quantity(quantity(1000.0)).count() == 1000); // should not compile - // static_assert(quantity(1000.0m).count() == 1000); // should not compile - static_assert(quantity(1000.0m).count() == 1000.0); - static_assert(quantity(quantity(1000.0)).count() == 1000.0); - static_assert(quantity(1000.0m).count() == my_double{1000.0}); - static_assert(quantity(km).count() == 1000.0); - static_assert(quantity(km).count() == my_double{1000.0}); - static_assert(quantity(1km).count() == 1000); - // static_assert(quantity(1_s).count() == 1); // should not compile - // static_assert(quantity(1010m).count() == 1); // should not compile - static_assert(quantity(quantity_cast>(1010m)).count() == 1); +static_assert(length(km).count() == 1000); +// static_assert(length(length(3.14)).count() == 3); // should not compile +static_assert(length(quantity_cast>(3.14m)).count() == 3); +// static_assert(length(length(1000.0)).count() == 1000); // should not compile +// static_assert(length(1000.0m).count() == 1000); // should not compile +static_assert(length(1000.0m).count() == 1000.0); +static_assert(length(length(1000.0)).count() == 1000.0); +static_assert(length(1000.0m).count() == my_double{1000.0}); +static_assert(length(km).count() == 1000.0); +static_assert(length(km).count() == my_double{1000.0}); +static_assert(length(1km).count() == 1000); +// static_assert(length(1_s).count() == 1); // should not compile +// static_assert(length(1010m).count() == 1); // should not compile +static_assert(length(quantity_cast>(1010m)).count() == 1); - // assignment operator +// assignment operator - static_assert([]() { - quantity l1(1), l2(2); - return l2 = l1; - }().count() == 1); +static_assert([]() { + length l1(1), l2(2); + return l2 = l1; +}() + .count() == 1); - // static member functions +// static member functions - static_assert(quantity::zero().count() == 0); - static_assert(quantity::min().count() == std::numeric_limits::lowest()); - static_assert(quantity::max().count() == std::numeric_limits::max()); - static_assert(quantity::zero().count() == 0.0); - static_assert(quantity::min().count() == std::numeric_limits::lowest()); - static_assert(quantity::max().count() == std::numeric_limits::max()); - static_assert(quantity::zero().count() == my_int{0}); - static_assert(quantity::min().count() == my_int{std::numeric_limits::lowest()}); - static_assert(quantity::max().count() == my_int{std::numeric_limits::max()}); - static_assert(quantity::zero().count() == my_double{0.0}); - static_assert(quantity::min().count() == my_double{std::numeric_limits::lowest()}); - static_assert(quantity::max().count() == my_double{std::numeric_limits::max()}); +static_assert(length::zero().count() == 0); +static_assert(length::min().count() == std::numeric_limits::lowest()); +static_assert(length::max().count() == std::numeric_limits::max()); +static_assert(length::zero().count() == 0.0); +static_assert(length::min().count() == std::numeric_limits::lowest()); +static_assert(length::max().count() == std::numeric_limits::max()); +static_assert(length::zero().count() == my_int{0}); +static_assert(length::min().count() == my_int{std::numeric_limits::lowest()}); +static_assert(length::max().count() == my_int{std::numeric_limits::max()}); +static_assert(length::zero().count() == my_double{0.0}); +static_assert(length::min().count() == my_double{std::numeric_limits::lowest()}); +static_assert(length::max().count() == my_double{std::numeric_limits::max()}); - // unary member operators +// unary member operators - static_assert((+km).count() == 1000); - static_assert((-km).count() == -1000); - static_assert((+(-km)).count() == -1000); - static_assert((-(-km)).count() == 1000); +static_assert((+km).count() == 1000); +static_assert((-km).count() == -1000); +static_assert((+(-km)).count() == -1000); +static_assert((-(-km)).count() == 1000); - // binary member operators +// binary member operators - static_assert([](auto v) { - auto vv = v++; - return std::make_pair(v, vv); - }(km) == std::make_pair(quantity(1001), quantity(1000))); - static_assert([](auto v) { - auto vv = ++v; - return std::make_pair(v, vv); - }(km) == std::make_pair(quantity(1001), quantity(1001))); - static_assert([](auto v) { - auto vv = v--; - return std::make_pair(v, vv); - }(km) == std::make_pair(quantity(999), quantity(1000))); - static_assert([](auto v) { - auto vv = --v; - return std::make_pair(v, vv); - }(km) == std::make_pair(quantity(999), quantity(999))); +static_assert([](auto v) { + auto vv = v++; + return std::make_pair(v, vv); +}(km) == std::make_pair(length(1001), length(1000))); +static_assert([](auto v) { + auto vv = ++v; + return std::make_pair(v, vv); +}(km) == std::make_pair(length(1001), length(1001))); +static_assert([](auto v) { + auto vv = v--; + return std::make_pair(v, vv); +}(km) == std::make_pair(length(999), length(1000))); +static_assert([](auto v) { + auto vv = --v; + return std::make_pair(v, vv); +}(km) == std::make_pair(length(999), length(999))); - // compound assignment +// compound assignment - static_assert((1m += 1m).count() == 2); - static_assert((2m -= 1m).count() == 1); - static_assert((1m *= 2).count() == 2); - static_assert((2m /= 2).count() == 1); - static_assert((7m %= 2).count() == 1); - static_assert((7m %= 2m).count() == 1); +static_assert((1m += 1m).count() == 2); +static_assert((2m -= 1m).count() == 1); +static_assert((1m *= 2).count() == 2); +static_assert((2m /= 2).count() == 1); +static_assert((7m %= 2).count() == 1); +static_assert((7m %= 2m).count() == 1); // static_assert((7.m %= 2.).count() == 1); // should not compile // static_assert((7.m %= 2).count() == 1); // should not compile // static_assert((7m %= 2.).count() == 1); // should not compile - static_assert((7m %= 2m).count() == 1); +static_assert((7m %= 2m).count() == 1); // static_assert((7.m %= 2.m).count() == 1); // should not compile // static_assert((7.m %= 2m).count() == 1); // should not compile // static_assert((7m %= 2.m).count() == 1); // should not compile - // non-member arithmetic operators +// non-member arithmetic operators - static_assert(std::is_same_v() + quantity()), quantity>); - static_assert(std::is_same_v() + quantity()), quantity>); - static_assert(std::is_same_v() + quantity()), quantity>); - static_assert(std::is_same_v() - quantity()), quantity>); - static_assert(std::is_same_v() - quantity()), quantity>); - static_assert(std::is_same_v() * 1.0), quantity>); - static_assert(std::is_same_v()), quantity>); - static_assert(std::is_same_v() * quantity()), quantity>); - static_assert(std::is_same_v()), quantity>); - static_assert(std::is_same_v() / 1.0), quantity>); - static_assert(std::is_same_v() / quantity()), double>); - static_assert(std::is_same_v() / quantity()), double>); - static_assert(std::is_same_v() / quantity()), quantity>); - static_assert(std::is_same_v() % short(1)), quantity>); - static_assert(std::is_same_v() % quantity(1)), quantity>); +static_assert(std::is_same_v() + length()), length>); +static_assert(std::is_same_v() + length()), length>); +static_assert( + std::is_same_v() + length()), length>); +static_assert(std::is_same_v() - length()), length>); +static_assert( + std::is_same_v() - length()), length>); +static_assert(std::is_same_v() * 1.0), length>); +static_assert(std::is_same_v()), length>); +static_assert( + std::is_same_v() * si::time()), length>); +static_assert(std::is_same_v()), frequency>); +static_assert(std::is_same_v()), si::time>); +static_assert(std::is_same_v() / 1.0), length>); +static_assert(std::is_same_v() / length()), double>); +static_assert(std::is_same_v() / length()), double>); +static_assert( + std::is_same_v() / si::time()), velocity>); +static_assert(std::is_same_v() % short(1)), length>); +static_assert(std::is_same_v() % length(1)), length>); - static_assert((1m + km).count() == 1001); - static_assert((1m + 1km).count() == 1001); - static_assert((km - 1m).count() == 999); - static_assert((1km - 1m).count() == 999); - static_assert((2m * 2).count() == 4); - static_assert((3 * 3m).count() == 9); - static_assert((4m / 2).count() == 2); - static_assert(4m / 2m == 2); - static_assert(4km / 2000m == 2); - static_assert((7m % 2).count() == 1); - static_assert((7m % 2m).count() == 1); - static_assert((7km % 2000m).count() == 1000); +static_assert((1m + km).count() == 1001); +static_assert((1m + 1km).count() == 1001); +static_assert((km - 1m).count() == 999); +static_assert((1km - 1m).count() == 999); +static_assert((2m * 2).count() == 4); +static_assert((3 * 3m).count() == 9); +static_assert((4m / 2).count() == 2); +static_assert(4m / 2m == 2); +static_assert(4km / 2000m == 2); +static_assert((7m % 2).count() == 1); +static_assert((7m % 2m).count() == 1); +static_assert((7km % 2000m).count() == 1000); - // comparators +// comparators - static_assert(2m + 1m == 3m); - static_assert(!(2m + 2m == 3m)); - static_assert(2m + 2m != 3m); - static_assert(!(2m + 2m != 4m)); - static_assert(2m > 1m); - static_assert(!(1m > 1m)); - static_assert(1m < 2m); - static_assert(!(2m < 2m)); - static_assert(2m >= 1m); - static_assert(2m >= 2m); - static_assert(!(2m >= 3m)); - static_assert(1m <= 2m); - static_assert(2m <= 2m); - static_assert(!(3m <= 2m)); +static_assert(2m + 1m == 3m); +static_assert(!(2m + 2m == 3m)); +static_assert(2m + 2m != 3m); +static_assert(!(2m + 2m != 4m)); +static_assert(2m > 1m); +static_assert(!(1m > 1m)); +static_assert(1m < 2m); +static_assert(!(2m < 2m)); +static_assert(2m >= 1m); +static_assert(2m >= 2m); +static_assert(!(2m >= 3m)); +static_assert(1m <= 2m); +static_assert(2m <= 2m); +static_assert(!(3m <= 2m)); - static_assert(3m == 3.0m); - static_assert(3m != 3.14m); - static_assert(2m > 1.0m); - static_assert(1.0m < 2m); - static_assert(2.0m >= 1m); - static_assert(1m <= 2.0m); +static_assert(3m == 3.0m); +static_assert(3m != 3.14m); +static_assert(2m > 1.0m); +static_assert(1.0m < 2m); +static_assert(2.0m >= 1m); +static_assert(1m <= 2.0m); - static_assert(1000m == 1km); - static_assert(1001m != 1km); - static_assert(1001m > 1km); - static_assert(999m < 1km); - static_assert(1000m >= 1km); - static_assert(1000m <= 1km); +static_assert(1000m == 1km); +static_assert(1001m != 1km); +static_assert(1001m > 1km); +static_assert(999m < 1km); +static_assert(1000m >= 1km); +static_assert(1000m <= 1km); - // is_quantity +// is_quantity - static_assert(Quantity>); +static_assert(Quantity>); - // common_quantity +// common_quantity - static_assert(std::is_same_v, quantity>, quantity>); - static_assert(std::is_same_v, quantity>, quantity>); - static_assert(std::is_same_v, quantity>, quantity>); +static_assert(std::is_same_v, length>, length>); +static_assert( + std::is_same_v, length>, length>); +static_assert(std::is_same_v, length>, + length>); - // quantity_cast +// quantity_cast - static_assert(std::is_same_v>>(2km))::unit, metre>); - static_assert(std::is_same_v>, ratio<1>>>(2km))::unit, metre>); +static_assert(std::is_same_v>>(2km))::unit, metre>); - // static_assert(quantity_cast(2km).count() == 2000); // should not compile - static_assert(quantity_cast>(2km).count() == 2000); - static_assert(quantity_cast>(2000m).count() == 2); +// static_assert(quantity_cast(2km).count() == 2000); // should not compile +static_assert(quantity_cast>(2km).count() == 2000); +static_assert(quantity_cast>(2000m).count() == 2); - // time +// time - // static_assert(1s == 1m); // should not compile - static_assert(1h == 3600s); +// static_assert(1s == 1m); // should not compile +static_assert(1h == 3600s); - // length +// length - static_assert(1km == 1000m); - static_assert(1km + 1m == 1001m); - static_assert(10km / 5km == 2); - static_assert(10km / 2 == 5km); +static_assert(1km == 1000m); +static_assert(1km + 1m == 1001m); +static_assert(10km / 5km == 2); +static_assert(10km / 2 == 5km); - // velocity +// velocity - static_assert(10m / 5s == 2mps); - static_assert(10 / 5s * 1m == 2mps); - static_assert(1km / 1s == 1000mps); - static_assert(2kmph * 2h == 4km); - static_assert(2km / 2kmph == 1h); +static_assert(10m / 5s == 2mps); +static_assert(10 / 5s * 1m == 2mps); +static_assert(1km / 1s == 1000mps); +static_assert(2kmph * 2h == 4km); +static_assert(2km / 2kmph == 1h); - static_assert(std::is_same_v(2m)), decltype(4sq_m)>); +static_assert(std::is_same_v(2m)), decltype(4sq_m)>); } // namespace