// 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. #include "units/math.h" #include "units/physical/si/area.h" #include "units/physical/si/frequency.h" #include "units/physical/si/speed.h" #include #include #include using namespace units; namespace { template struct equality_ops { [[nodiscard]] friend constexpr bool operator==(T lhs, T rhs) { return lhs.value_ == rhs.value_; } [[nodiscard]] friend constexpr bool operator!=(T lhs, T rhs) { return !(lhs == rhs); } }; template struct scaling_ops { [[nodiscard]] friend constexpr T operator*(T lhs, T rhs) { return T(lhs.value_ * rhs.value_); } [[nodiscard]] friend constexpr T operator/(T lhs, T rhs) { return T(lhs.value_ / rhs.value_); } }; template struct scalar_ops : equality_ops, scaling_ops {}; template struct impl_constructible : scalar_ops> { T value_{}; impl_constructible() = default; constexpr impl_constructible(T v) : value_(std::move(v)) {} // no conversion to fundamental arithmetic types }; template using impl = impl_constructible; template struct expl_constructible : scalar_ops> { T value_{}; expl_constructible() = default; constexpr explicit expl_constructible(T v) : value_(std::move(v)) {} // no conversion to fundamental arithmetic types }; template using expl = expl_constructible; template struct impl_constructible_impl_convertible : scalar_ops> /*, int_scaling_ops> */ { T value_{}; impl_constructible_impl_convertible() = default; constexpr impl_constructible_impl_convertible(T v) : value_(std::move(v)) {} constexpr operator const T&() const& { return value_; } }; template using impl_impl = impl_constructible_impl_convertible; static_assert(std::convertible_to>); static_assert(std::convertible_to, float>); static_assert(units::Scalar>); template struct expl_constructible_impl_convertible : scalar_ops> { T value_{}; expl_constructible_impl_convertible() = default; constexpr explicit expl_constructible_impl_convertible(T v) : value_(std::move(v)) {} constexpr operator const T&() const& { return value_; } }; template using expl_impl = expl_constructible_impl_convertible; static_assert(!std::convertible_to>); static_assert(std::convertible_to, float>); static_assert(units::Scalar>); template struct impl_constructible_expl_convertible : scalar_ops> { T value_{}; impl_constructible_expl_convertible() = default; constexpr impl_constructible_expl_convertible(T v) : value_(std::move(v)) {} constexpr explicit operator const T&() const& { return value_; } }; template using impl_expl = impl_constructible_expl_convertible; static_assert(std::convertible_to>); static_assert(!std::convertible_to, float>); static_assert(units::Scalar>); template struct expl_constructible_expl_convertible : scalar_ops> { T value_{}; expl_constructible_expl_convertible() = default; constexpr explicit expl_constructible_expl_convertible(T v) : value_(std::move(v)) {} constexpr explicit operator const T&() const& { return value_; } }; template using expl_expl = expl_constructible_expl_convertible; static_assert(!std::convertible_to>); static_assert(!std::convertible_to, float>); static_assert(units::Scalar>); } // 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 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 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 impl zero() { return 0; } static constexpr impl max() { return std::numeric_limits::max(); } static constexpr impl min() { return std::numeric_limits::lowest(); } }; } // namespace units namespace { using namespace units::physical::si; // constructors // Quantity from Scalar // int <- int static_assert(length(expl_impl(1)).count() == 1); static_assert(!std::is_constructible_v, impl_expl>); static_assert(length(int(impl_expl(1))).count() == 1); static_assert(!std::is_constructible_v>, int>); static_assert(length>(expl_impl(1)).count() == expl_impl{1}); static_assert(length>(1).count() == impl_expl{1}); // double <- double static_assert(length(expl_impl(1.0)).count() == 1.0); static_assert(!std::is_constructible_v, impl_expl>); static_assert(length(double(impl_expl(1.0))).count() == 1.0); static_assert(!std::is_constructible_v>, double>); static_assert(length>(expl_impl(1.0)).count() == expl_impl{1.0}); static_assert(length>(1.0).count() == impl_expl{1.0}); // double <- int static_assert(length(expl_impl(1)).count() == 1.0); static_assert(!std::is_constructible_v, impl_expl>); static_assert(length(int(impl_expl(1))).count() == 1.0); static_assert(!std::is_constructible_v>, int>); static_assert(length>(expl_impl(1)).count() == expl_impl{1}); static_assert(length>(1).count() == impl_expl{1.0}); // int <- double static_assert(!std::is_constructible_v, expl_impl>); static_assert(!std::is_constructible_v>, double>); // Quantity from other Quantity with different Rep // int <- int static_assert(length(length>(expl_impl(1))).count() == 1); static_assert(!std::is_constructible_v, length>>); static_assert(length(quantity_cast(length>(1))).count() == 1); static_assert(!std::is_constructible_v>, length>); static_assert(length>(quantity_cast>(length(1))).count() == expl_impl{1}); static_assert(length>(length(1)).count() == impl_expl{1}); // double <- double static_assert(length(length>(expl_impl(1.0))).count() == 1.0); static_assert(!std::is_constructible_v, length>>); static_assert(length(quantity_cast(length>(1.0))).count() == 1.0); static_assert(!std::is_constructible_v>, length>); static_assert(length>(quantity_cast>(length(1.0))).count() == expl_impl{1.0}); static_assert(length>(length(1.0)).count() == impl_expl{1.0}); // double <- int static_assert(length(length>(expl_impl(1))).count() == 1.0); static_assert(!std::is_constructible_v, length>>); static_assert(length(quantity_cast(length>(1))).count() == 1.0); static_assert(!std::is_constructible_v>, length>); static_assert(length>(quantity_cast>(length(1))).count() == expl_impl{1}); static_assert(length>(length(1)).count() == impl_expl{1.0}); // int <- double static_assert(!std::is_constructible_v, length>>); static_assert(!std::is_constructible_v>, length>); // unit conversions static_assert(length>(length>(1)).count() == impl(1000)); static_assert(length>(length>(expl(1))).count() == expl(1000)); static_assert(length>(length>(1)).count() == impl_impl(1000)); static_assert(length>(length>(1)).count() == impl_expl(1000)); static_assert(length>(length>(expl_impl(1))).count() == expl_impl(1000)); static_assert(length>(length>(expl_expl(1))).count() == expl_expl(1000)); static_assert(!std::is_constructible_v>, length>>); static_assert(length>(quantity_cast(length>(2000))).count() == impl(2)); static_assert(!std::is_constructible_v>, length>>); static_assert(length>(quantity_cast(length>(expl(2000)))).count() == expl(2)); static_assert(!std::is_constructible_v>, length>>); static_assert(length>(quantity_cast(length>(2000))).count() == impl_impl(2)); static_assert(!std::is_constructible_v>, length>>); static_assert(length>(quantity_cast(length>(2000))).count() == impl_expl(2)); static_assert(!std::is_constructible_v>, length>>); static_assert(length>(quantity_cast(length>(expl_impl(2000)))).count() == expl_impl(2)); static_assert(!std::is_constructible_v>, length>>); static_assert(length>(quantity_cast(length>(expl_expl(2000)))).count() == expl_expl(2)); static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(72))).count() == impl(20)); static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(expl(72)))).count() == expl(20)); static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(72))).count() == impl_impl(20)); static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(72))).count() == impl_expl(20)); static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(expl_impl(72)))).count() == expl_impl(20)); static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(expl_expl(72)))).count() == expl_expl(20)); static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(20))).count() == impl(72)); static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(expl(20)))).count() == expl(72)); static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(20))).count() == impl_impl(72)); static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(20))).count() == impl_expl(72)); static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(expl_impl(20)))).count() == expl_impl(72)); static_assert(!std::is_constructible_v>, speed>>); static_assert(speed>(quantity_cast(speed>(expl_expl(20)))).count() == expl_expl(72)); } // namespace