// 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 // IWYU pragma: begin_exports #include #include #include // IWYU pragma: end_exports #include #include namespace units { /** * @brief A statically unspecified quantity point origin * * An origin, unspecified in the type system, from which an absolute quantity is measured from. * * @tparam D a dimension of the quantity point (can be either a BaseDimension or a DerivedDimension) */ template struct dynamic_origin : point_origin { template using rebind = dynamic_origin; }; /** * @brief A quantity point * * An absolute quantity measured from an origin. * * @tparam O a type that represents the origin from which the quantity point is measured from * @tparam U a measurement unit of the quantity point * @tparam Rep a type to be used to represent values of a quantity point */ template U, Representation Rep = double> class quantity_point { public: using origin = O; using quantity_type = quantity; using dimension = typename quantity_type::dimension; using unit = typename quantity_type::unit; using rep = typename quantity_type::rep; static constexpr units::reference reference{}; private: quantity_type q_{}; public: quantity_point() = default; quantity_point(const quantity_point&) = default; quantity_point(quantity_point&&) = default; template requires std::constructible_from constexpr explicit quantity_point(T&& t) : q_(std::forward(t)) { } template QP2> requires std::convertible_to constexpr explicit(false) quantity_point(const QP2& qp) : q_(qp.relative()) { } template constexpr explicit quantity_point(const QP& qp) requires std::is_constructible_v::relative(qp))> && equivalent::origin> : q_(quantity_point_like_traits::relative(qp)) { } quantity_point& operator=(const quantity_point&) = default; quantity_point& operator=(quantity_point&&) = default; [[nodiscard]] constexpr quantity_type& relative() & noexcept { return q_; } [[nodiscard]] constexpr const quantity_type& relative() const& noexcept { return q_; } [[nodiscard]] constexpr quantity_type&& relative() && noexcept { return std::move(q_); } [[nodiscard]] constexpr const quantity_type&& relative() const&& noexcept { return std::move(q_); } [[nodiscard]] static constexpr quantity_point min() noexcept requires requires { quantity_type::min(); } { return quantity_point(quantity_type::min()); } [[nodiscard]] static constexpr quantity_point max() noexcept requires requires { quantity_type::max(); } { return quantity_point(quantity_type::max()); } constexpr quantity_point& operator++() requires requires(quantity_type q) { ++q; } { ++q_; return *this; } [[nodiscard]] constexpr quantity_point operator++(int) requires requires(quantity_type q) { q++; } { return quantity_point(q_++); } constexpr quantity_point& operator--() requires requires(quantity_type q) { --q; } { --q_; return *this; } [[nodiscard]] constexpr quantity_point operator--(int) requires requires(quantity_type q) { q--; } { return quantity_point(q_--); } constexpr quantity_point& operator+=(const quantity_type& q) requires requires { q_ += q; } { q_ += q; return *this; } constexpr quantity_point& operator-=(const quantity_type& q) requires requires(quantity_type q1, quantity_type q2) { q1 -= q2; } { q_ -= q; return *this; } // Hidden Friends // Below friend functions are to be found via argument-dependent lookup only template [[nodiscard]] friend constexpr QuantityPoint auto operator+(const quantity_point& lhs, const Q& rhs) requires requires(quantity_type q) { q + rhs; } { const auto q = lhs.relative() + rhs; using q_type = decltype(q); return quantity_point, typename q_type::unit, typename q_type::rep>(q); } template [[nodiscard]] friend constexpr QuantityPoint auto operator+(const Q& lhs, const quantity_point& rhs) requires requires { rhs + lhs; } { return rhs + lhs; } template [[nodiscard]] friend constexpr QuantityPoint auto operator-(const quantity_point& lhs, const Q& rhs) requires requires(quantity_type q) { q - rhs; } { const auto q = lhs.relative() - rhs; using q_type = decltype(q); return quantity_point, typename q_type::unit, typename q_type::rep>(q); } template QP> [[nodiscard]] friend constexpr Quantity auto operator-(const quantity_point& lhs, const QP& rhs) requires requires(quantity_type q) { q - rhs.relative(); } { return lhs.relative() - rhs.relative(); } template QP> requires std::three_way_comparable_with [[nodiscard]] friend constexpr auto operator<=>(const quantity_point& lhs, const QP& rhs) { return lhs.relative() <=> rhs.relative(); } template QP> requires std::equality_comparable_with [[nodiscard]] friend constexpr bool operator==(const quantity_point& lhs, const QP& rhs) { return lhs.relative() == rhs.relative(); } }; template explicit quantity_point(Rep) -> quantity_point, one, Rep>; template explicit quantity_point(Q) -> quantity_point, typename Q::unit, typename Q::rep>; template explicit quantity_point(Q) -> quantity_point::dimension>, typename quantity_like_traits::unit, typename quantity_like_traits::rep>; template explicit quantity_point(QP) -> quantity_point::origin, typename quantity_point_like_traits::unit, typename quantity_point_like_traits::rep>; namespace detail { template inline constexpr bool is_quantity_point> = true; } // namespace detail } // namespace units