// 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/velocity.h" #include #include using namespace units; namespace { template struct arithmetic_ops { // constexpr T& operator+=(T other) { value_ += other.value_; return *this; } // constexpr T& operator-=(T other) { value_ -= other.value_; return *this; } // constexpr T& operator*=(T other) { value_ *= other.value_; return *this; } // constexpr T& operator/=(T other) { value_ /= other.value_; return *this; } // [[nodiscard]] constexpr T operator-() const { return T(-value_); } [[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_); } [[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_); } [[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); } [[nodiscard]] friend constexpr bool operator<(T lhs, T rhs) { return lhs.value_ < rhs.value_; } [[nodiscard]] friend constexpr bool operator>(T lhs, T rhs) { return rhs < lhs; } [[nodiscard]] friend constexpr bool operator<=(T lhs, T rhs) { return !(rhs < lhs); } [[nodiscard]] friend constexpr bool operator>=(T lhs, T rhs) { return !(lhs < rhs); } }; template struct impl_constructible_impl_convertible : arithmetic_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 : arithmetic_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 : arithmetic_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 : arithmetic_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 struct quantity_values> { static constexpr impl_impl zero() { return impl_impl(0); } static constexpr impl_impl max() { return std::numeric_limits::max(); } static constexpr impl_impl min() { return std::numeric_limits::lowest(); } }; } // namespace units namespace std { // template // struct common_type, my_value> : std::type_identity>> {}; // template // struct common_type, U> : common_type {}; // template // struct common_type> : common_type {}; } // namespace std namespace { using namespace units::si; // constructors // Quantity from Scalar // int <- int static_assert(length(expl_impl(1)).count() == 1); // static_assert(length(impl_expl(1)).count() == 1); // should not compile (not convertible) static_assert(length(int(impl_expl(1))).count() == 1); // static_assert(length>(1).count() == expl_impl{1}); // should not compile (not convertible) 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(length(impl_expl(1.0)).count() == 1.0); // should not compile (not convertible) static_assert(length(double(impl_expl(1.0))).count() == 1.0); // static_assert(length>(1.0).count() == expl_impl{1.0}); // should not compile (not convertible) 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(length(impl_expl(1)).count() == 1.0); // should not compile (not convertible) static_assert(length(int(impl_expl(1))).count() == 1.0); // static_assert(length>(1).count() == expl_impl{1}); // should not compile (not convertible) static_assert(length>(expl_impl(1)).count() == expl_impl{1}); static_assert(length>(1).count() == impl_expl{1.0}); // int <- double // static_assert(length(expl_impl(1.0)).count() == 1); // should not compile (truncating conversion) // static_assert(length>(1.0).count() == impl_expl{1}); // should not compile (truncating conversion) // Quantity from other Quantity with different Rep // int <- int static_assert(length(length>(expl_impl(1))).count() == 1); // static_assert(length(length>(1)).count() == 1); // should not compile (not convertible) static_assert(length(quantity_cast(length>(1))).count() == 1); // static_assert(length>(length(1)).count() == expl_impl{1}); // should not compile (not convertible) 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(length(length>(1.0)).count() == 1.0); // should not compile (not convertible) static_assert(length(quantity_cast(length>(1.0))).count() == 1.0); // static_assert(length>(length(1.0).count() == expl_impl{1.0}); // should not compile (not convertible) 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(length(length>(1)).count() == 1.0); // should not compile (not convertible) static_assert(length(quantity_cast(length>(1))).count() == 1.0); // static_assert(length>(length(1)).count() == expl_impl{1}); // should not compile (not convertible) 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(length(length>(1.0)).count() == 1); // should not compile (truncating conversion) // static_assert(length>(length(1.0)).count() == impl_expl{1}); // should not compile (truncating conversion) // unit conversions static_assert(length>(length>(1)).count() == impl_expl(1000)); // static_assert(length>(length>(2000)).count() == impl_expl(2)); // should not compile (truncating conversion) static_assert(length>(quantity_cast(length>(2000))).count() == impl_expl(2)); static_assert(length>::zero().count() == impl_impl{0}); static_assert(length>::min().count() == impl_impl{std::numeric_limits::lowest()}); static_assert(length>::max().count() == impl_impl{std::numeric_limits::max()}); static_assert(length>::zero().count() == impl_impl{0.0}); static_assert(length>::min().count() == impl_impl{std::numeric_limits::lowest()}); static_assert(length>::max().count() == impl_impl{std::numeric_limits::max()}); } // namespace