From a45088b8595274d0d6efc9495d9a3d6d56bc05b0 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Fri, 23 Dec 2022 19:20:34 +0100 Subject: [PATCH] refactor: `quantity_point` refactored for V2 --- .../include/units/bits/quantity_concepts.h | 68 ++++++++ src/core/include/units/customization_points.h | 5 +- src/core/include/units/point_origin.h | 34 ---- src/core/include/units/quantity_point.h | 155 +++++++++--------- 4 files changed, 151 insertions(+), 111 deletions(-) delete mode 100644 src/core/include/units/point_origin.h diff --git a/src/core/include/units/bits/quantity_concepts.h b/src/core/include/units/bits/quantity_concepts.h index 502b5573..de6d7267 100644 --- a/src/core/include/units/bits/quantity_concepts.h +++ b/src/core/include/units/bits/quantity_concepts.h @@ -175,4 +175,72 @@ concept quantity_like = requires(T q) { } -> std::convertible_to::rep>; }; + +template +struct absolute_point_origin { + static constexpr QuantitySpec auto quantity_spec = Q; +}; + +namespace detail { + +template +inline constexpr bool is_quantity_point = false; + +template +void to_base_specialization_of_absolute_point_origin(const volatile absolute_point_origin*); + +template +inline constexpr bool is_derived_from_specialization_of_absolute_point_origin = + requires(T * t) { to_base_specialization_of_absolute_point_origin(t); }; + +} // namespace detail + +template +concept QuantityPoint = detail::is_quantity_point; + +template +concept point_origin = QuantityPoint || detail::is_derived_from_specialization_of_absolute_point_origin; + +template +concept point_origin_for = point_origin && QuantitySpec> && + detail::is_kind_of(Q, T::quantity_spec); + +template auto PO, RepresentationOf Rep> +class quantity_point; + +namespace detail { + +template +void to_base_specialization_of_quantity_point(const volatile quantity_point*); + +template + requires requires(T* t) { detail::to_base_specialization_of_quantity_point(t); } +inline constexpr bool is_quantity_point = true; + +} // namespace detail + +template +concept quantity_point_of = + QuantityPoint && + ((Dimension> && QP::dimension == V) || + (QuantitySpec> && detail::is_kind_of(QP::quantity_spec, V)) || + (Reference> && QP::reference == V) || + (point_origin> && + std::same_as, std::remove_const_t>)); + +template +concept quantity_point_like = requires(T q) { + quantity_point_like_traits::reference; + quantity_point_like_traits::point_origin; + typename quantity_point_like_traits::rep; + requires Reference::reference)>>; + requires point_origin::point_origin)>>; + requires RepresentationOf::rep, + quantity_point_like_traits::reference.quantity_spec.character>; + requires std::constructible_from< + typename quantity_point::reference, quantity_point_like_traits::point_origin, + typename quantity_point_like_traits::rep>::quantity_type, + decltype(quantity_point_like_traits::relative(q))>; +}; + } // namespace units diff --git a/src/core/include/units/customization_points.h b/src/core/include/units/customization_points.h index ad834d97..7df6b4f9 100644 --- a/src/core/include/units/customization_points.h +++ b/src/core/include/units/customization_points.h @@ -142,8 +142,9 @@ struct quantity_like_traits; /** * @brief Provides support for external quantity point-like types * - * The type trait should provide the following nested type aliases: @c origin, @c unit, @c rep, - * and a static member function @c relative(T) that will return the quantity-like value of the quantity point. + * The type trait should provide nested @c reference and @c origin objects, + * a type alias @c rep, and a static member function @c relative(T) that will return + * the quantity-like value of the quantity point. * * Usage example can be found in @c units/chrono.h header file. * diff --git a/src/core/include/units/point_origin.h b/src/core/include/units/point_origin.h deleted file mode 100644 index 581ccbfc..00000000 --- a/src/core/include/units/point_origin.h +++ /dev/null @@ -1,34 +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 { - -template -struct point_origin { - using dimension = D; -}; - -} // namespace units diff --git a/src/core/include/units/quantity_point.h b/src/core/include/units/quantity_point.h index bd3fa2fc..809e21bb 100644 --- a/src/core/include/units/quantity_point.h +++ b/src/core/include/units/quantity_point.h @@ -23,119 +23,133 @@ #pragma once -// IWYU pragma: begin_exports -#include +#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; -}; +namespace detail { + +[[nodiscard]] consteval point_origin auto get_absolute_point_origin(point_origin auto po) +{ + if constexpr (requires { po.absolute_point_origin; }) + return po.absolute_point_origin; + else + return po; +} + +template +using quantity_point_like_type = + quantity_point::reference, quantity_point_like_traits::point_origin, + typename quantity_point_like_traits::rep>; + +} // namespace detail /** * @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 R a reference of the quantity point providing all information about quantity properties + * @tparam PO a type that represents the origin point from which the quantity point is measured from * @tparam Rep a type to be used to represent values of a quantity point */ -template U, Representation Rep = double> +template auto PO = absolute_point_origin{}, + RepresentationOf 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{}; + // member types and values + static constexpr Reference auto reference = R; + static constexpr QuantitySpec auto quantity_spec = reference.quantity_spec; + static constexpr Dimension auto dimension = reference.dimension; + static constexpr Unit auto unit = reference.unit; + static constexpr point_origin auto absolute_point_origin = detail::get_absolute_point_origin(PO); + static constexpr point_origin auto point_origin = PO; + using rep = Rep; + using quantity_type = quantity; -private: - quantity_type q_{}; + quantity_type q_; // needs to be public for a structural type -public: + // static member functions + [[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()}; + } + + // construction, assignment, destruction 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)) + constexpr explicit quantity_point(T&& v) : q_(std::forward(v)) { } - template QP2> + 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)) + template + requires std::same_as::point_origin)>, + std::remove_const_t> && + std::convertible_to::quantity_type, quantity_type> + constexpr explicit quantity_point(const QP& qp) : + q_(typename detail::quantity_point_like_type::quantity_type{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_; } + // data access [[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(); } + [[nodiscard]] constexpr Quantity auto absolute() const noexcept { - return quantity_point(quantity_type::min()); - } - - [[nodiscard]] static constexpr quantity_point max() noexcept - requires requires { quantity_type::max(); } - { - return quantity_point(quantity_type::max()); + if constexpr (detail::is_derived_from_specialization_of_absolute_point_origin< + std::remove_const_t>) + return relative(); + else + return point_origin.absolute() + relative(); } + // member unary operators constexpr quantity_point& operator++() - requires requires(quantity_type q) { ++q; } + requires requires { ++q_; } { ++q_; return *this; } [[nodiscard]] constexpr quantity_point operator++(int) - requires requires(quantity_type q) { q++; } + requires requires { q_++; } { return quantity_point(q_++); } constexpr quantity_point& operator--() - requires requires(quantity_type q) { --q; } + requires requires { --q_; } { --q_; return *this; } [[nodiscard]] constexpr quantity_point operator--(int) - requires requires(quantity_type q) { q--; } + requires requires { q_--; } { return quantity_point(q_--); } @@ -148,7 +162,7 @@ public: } constexpr quantity_point& operator-=(const quantity_type& q) - requires requires(quantity_type q1, quantity_type q2) { q1 -= q2; } + requires requires { q_ -= q; } { q_ -= q; return *this; @@ -156,15 +170,13 @@ public: // 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); + return quantity_point(q); } template @@ -180,25 +192,24 @@ public: { const auto q = lhs.relative() - rhs; using q_type = decltype(q); - return quantity_point, typename q_type::unit, - typename q_type::rep>(q); + return quantity_point(q); } - template QP> + template QP> [[nodiscard]] friend constexpr Quantity auto operator-(const quantity_point& lhs, const QP& rhs) - requires requires(quantity_type q) { q - rhs.relative(); } + requires requires(quantity_type q) { q - rhs.absolute(); } { - return lhs.relative() - rhs.relative(); + return lhs.absolute() - rhs.absolute(); } - template QP> + 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> + template QP> requires std::equality_comparable_with [[nodiscard]] friend constexpr bool operator==(const quantity_point& lhs, const QP& rhs) { @@ -206,27 +217,21 @@ public: } }; +// CTAD template -explicit quantity_point(Rep) -> quantity_point, one, Rep>; +explicit quantity_point(Rep) -> quantity_point{}, Rep>; template -explicit quantity_point(Q) -> quantity_point, typename Q::unit, typename Q::rep>; +explicit quantity_point(Q) -> quantity_point{}, typename Q::rep>; -template +template explicit quantity_point(Q) - -> quantity_point::dimension>, typename quantity_like_traits::unit, + -> quantity_point::reference, absolute_point_origin::quantity_spec>{}, typename quantity_like_traits::rep>; -template +template explicit quantity_point(QP) - -> quantity_point::origin, typename quantity_point_like_traits::unit, + -> quantity_point::reference, quantity_point_like_traits::point_origin, typename quantity_point_like_traits::rep>; -namespace detail { - -template -inline constexpr bool is_quantity_point> = true; - -} // namespace detail - } // namespace units