From 6d39459cbcfe238ea679af8baec11563783e0804 Mon Sep 17 00:00:00 2001 From: Mateusz Pusz Date: Mon, 3 May 2021 19:44:50 +0200 Subject: [PATCH] perf: rvalue references support added for constructors and getters Resolves #275 --- docs/CHANGELOG.md | 1 + src/core/include/units/quantity.h | 12 ++++--- src/core/include/units/quantity_kind.h | 22 +++++++----- src/core/include/units/quantity_point.h | 38 +++++++++++--------- src/core/include/units/quantity_point_kind.h | 30 +++++++--------- test/unit_test/static/quantity_kind_test.cpp | 6 ++-- test/unit_test/static/quantity_test.cpp | 14 ++++---- 7 files changed, 68 insertions(+), 55 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index da20f0cd..2fc975f2 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -23,6 +23,7 @@ - perf: value initialization for quantity value removed (left with a default initialization) - perf: limited the `equivalent` trait usage - perf: limited the C++ Standard Library headers usage + - perf: rvalue references support added for constructors and getters - (!) fix: `exp()` has sense only for dimensionless quantities - (!) fix: `dim_torque` now properly divides by an angle (instead of multiply) + default unit name change - fix: quantity's operators fixed to behave like the underlying types do diff --git a/src/core/include/units/quantity.h b/src/core/include/units/quantity.h index 4ed10cf9..13c519ab 100644 --- a/src/core/include/units/quantity.h +++ b/src/core/include/units/quantity.h @@ -147,9 +147,10 @@ public: quantity(const quantity&) = default; quantity(quantity&&) = default; - template Value> - constexpr explicit(!(is_same_v && is_same_v)) - quantity(const Value& v) : number_(v) {} + template + requires safe_convertible_to_, rep> + constexpr explicit(!(std::same_as && std::same_as)) + quantity(Value&& v) : number_(std::forward(v)) {} template Q> constexpr explicit(false) quantity(const Q& q) : number_(quantity_cast(q).number()) {} @@ -162,7 +163,10 @@ public: quantity& operator=(quantity&&) = default; // data access - [[nodiscard]] constexpr rep number() const noexcept { return number_; } + [[nodiscard]] constexpr rep& number() & noexcept { return number_; } + [[nodiscard]] constexpr const rep& number() const & noexcept { return number_; } + [[nodiscard]] constexpr rep&& number() && noexcept { return std::move(number_); } + [[nodiscard]] constexpr const rep&& number() const && noexcept { return std::move(number_); } // member unary operators [[nodiscard]] constexpr Quantity auto operator+() const diff --git a/src/core/include/units/quantity_kind.h b/src/core/include/units/quantity_kind.h index c6891bd2..80a0c90a 100644 --- a/src/core/include/units/quantity_kind.h +++ b/src/core/include/units/quantity_kind.h @@ -93,22 +93,28 @@ public: quantity_kind(const quantity_kind&) = default; quantity_kind(quantity_kind&&) = default; - template Value> - requires is_same_v && std::is_constructible_v - constexpr explicit quantity_kind(const Value& v) : q_(v) {} + template + requires std::same_as && + safe_convertible_to_, rep> && + std::constructible_from + constexpr explicit quantity_kind(Value&& v) : q_(std::forward(v)) {} template - requires (Quantity || QuantityLike) && std::is_constructible_v - constexpr explicit quantity_kind(const Q& q) : q_{q} {} + requires (Quantity> || QuantityLike>) && + std::constructible_from + constexpr explicit quantity_kind(Q&& q) : q_(std::forward(q)) {} template QK2> - requires std::is_convertible_v - constexpr explicit(false) quantity_kind(const QK2& qk) : q_{qk.common()} {} + requires std::convertible_to + constexpr explicit(false) quantity_kind(const QK2& qk) : q_(qk.common()) {} quantity_kind& operator=(const quantity_kind&) = default; quantity_kind& operator=(quantity_kind&&) = default; - [[nodiscard]] constexpr quantity_type common() const noexcept { return q_; } + [[nodiscard]] constexpr quantity_type& common() & noexcept { return q_; } + [[nodiscard]] constexpr const quantity_type& common() const & noexcept { return q_; } + [[nodiscard]] constexpr quantity_type&& common() && noexcept { return std::move(q_); } + [[nodiscard]] constexpr const quantity_type&& common() const && noexcept { return std::move(q_); } [[nodiscard]] static constexpr quantity_kind zero() noexcept requires requires { quantity_type::zero(); } diff --git a/src/core/include/units/quantity_point.h b/src/core/include/units/quantity_point.h index dd1a276f..93c38615 100644 --- a/src/core/include/units/quantity_point.h +++ b/src/core/include/units/quantity_point.h @@ -59,29 +59,33 @@ public: quantity_point(const quantity_point&) = default; quantity_point(quantity_point&&) = default; - template Value> - requires is_same_v && std::is_constructible_v - constexpr explicit quantity_point(const Value& v) : q_(v) {} + template + requires std::same_as && + safe_convertible_to_, rep> && + std::constructible_from + constexpr explicit quantity_point(Value&& v) : q_(std::forward(v)) {} - constexpr explicit quantity_point(const quantity_type& q) : q_{q} {} + template + requires (Quantity> || QuantityLike>) && + std::constructible_from + constexpr explicit quantity_point(Q&& q) : q_(std::forward(q)) {} - template - requires std::is_constructible_v - constexpr explicit quantity_point(const Q& q) : q_{q} {} + template + 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))> - : q_{quantity_point_like_traits::relative(qp)} {} - - template - requires std::is_convertible_v - constexpr explicit(false) quantity_point(const QP2& qp) : q_{qp.relative()} {} + : 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() const noexcept { return q_; } + [[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(); } @@ -183,14 +187,16 @@ public: { return lhs.relative() == rhs.relative(); } - }; template -explicit(false) quantity_point(Rep) -> quantity_point; +explicit quantity_point(Rep) -> quantity_point; + +template +explicit quantity_point(Q) -> quantity_point; template -quantity_point(Q) -> quantity_point::dimension, +explicit quantity_point(Q) -> quantity_point::dimension, typename quantity_like_traits::unit, typename quantity_like_traits::rep>; template diff --git a/src/core/include/units/quantity_point_kind.h b/src/core/include/units/quantity_point_kind.h index e315ff40..213de447 100644 --- a/src/core/include/units/quantity_point_kind.h +++ b/src/core/include/units/quantity_point_kind.h @@ -60,32 +60,28 @@ public: quantity_point_kind(const quantity_point_kind&) = default; quantity_point_kind(quantity_point_kind&&) = default; - template Value> - requires std::is_constructible_v - constexpr explicit quantity_point_kind(const Value& v) : qk_(v) {} + template + requires std::constructible_from + constexpr explicit quantity_point_kind(T&& t) : qk_(std::forward(t)) {} - constexpr explicit quantity_point_kind(const quantity_type& q) : qk_{q} {} - - template - requires std::is_constructible_v - constexpr explicit quantity_point_kind(const Q& q) : qk_{q} {} + constexpr explicit quantity_point_kind(const quantity_point& qp) : qk_(qp.relative()) {} + constexpr explicit quantity_point_kind(quantity_point&& qp) : qk_(std::move(qp).relative()) {} template - requires std::is_constructible_v, QP> - constexpr explicit quantity_point_kind(const QP& qp) : qk_{quantity_point_like_traits::relative(qp)} {} - - constexpr explicit quantity_point_kind(const quantity_point& qp) : qk_{qp.relative()} {} - - constexpr explicit quantity_point_kind(const quantity_kind_type& qk) : qk_{qk} {} + requires std::constructible_from, QP> + constexpr explicit quantity_point_kind(const QP& qp) : qk_(quantity_point_like_traits::relative(qp)) {} template QPK2> - requires std::is_convertible_v - constexpr explicit(false) quantity_point_kind(const QPK2& qpk) : qk_{qpk.relative()} {} + requires std::convertible_to + constexpr explicit(false) quantity_point_kind(const QPK2& qpk) : qk_(qpk.relative()) {} quantity_point_kind& operator=(const quantity_point_kind&) = default; quantity_point_kind& operator=(quantity_point_kind&&) = default; - [[nodiscard]] constexpr quantity_kind_type relative() const noexcept { return qk_; } + [[nodiscard]] constexpr quantity_kind_type& relative() & noexcept { return qk_; } + [[nodiscard]] constexpr const quantity_kind_type& relative() const & noexcept { return qk_; } + [[nodiscard]] constexpr quantity_kind_type&& relative() && noexcept { return std::move(qk_); } + [[nodiscard]] constexpr const quantity_kind_type&& relative() const && noexcept { return std::move(qk_); } [[nodiscard]] static constexpr quantity_point_kind min() noexcept requires requires { quantity_kind_type::min(); } diff --git a/test/unit_test/static/quantity_kind_test.cpp b/test/unit_test/static/quantity_kind_test.cpp index 42c4485d..1dc9a5f2 100644 --- a/test/unit_test/static/quantity_kind_test.cpp +++ b/test/unit_test/static/quantity_kind_test.cpp @@ -475,9 +475,9 @@ static_assert(same(width(2. * m) - width(3 * m), widt static_assert(same(width(2e3 * m) - width(3 * km), width(-1e3 * m))); static_assert(is_same_v< - decltype((width(0 * m) + width(0 * m)).common().number()), int>); + decltype((width(0 * m) + width(0 * m)).common().number()), int&&>); static_assert(is_same_v< - decltype((width(0 * m) - width(0 * m)).common().number()), int>); + decltype((width(0 * m) - width(0 * m)).common().number()), int&&>); static_assert((width(128 * m) + width(128 * m)).common().number() == std::uint8_t(128) + std::uint8_t(128)); static_assert((width(0 * m) - width(1 * m)).common().number() == @@ -646,7 +646,7 @@ static_assert(same(width(3 * m) % width(2 * m), width(0 * m) % width(0 * m)).common().number()), - decltype(std::uint8_t(0) % std::uint8_t(0))>); + decltype(std::uint8_t(0) % std::uint8_t(0))&&>); static_assert(!std::is_invocable_v, reference, width>); static_assert(!std::is_invocable_v, width, height>); diff --git a/test/unit_test/static/quantity_test.cpp b/test/unit_test/static/quantity_test.cpp index 507c6382..6c16f0f0 100644 --- a/test/unit_test/static/quantity_test.cpp +++ b/test/unit_test/static/quantity_test.cpp @@ -269,7 +269,7 @@ static_assert([](auto v) { auto vv = ++v; return std::pair(v, vv); }(123_q_m) == static_assert([](auto v) { auto vv = v--; return std::pair(v, vv); }(123_q_m) == std::pair(122_q_m, 123_q_m)); static_assert([](auto v) { auto vv = --v; return std::pair(v, vv); }(123_q_m) == std::pair(122_q_m, 122_q_m)); -static_assert(is_same_v); +static_assert(is_same_v); //////////////////////// @@ -406,13 +406,13 @@ static_assert(compare>); static_assert(compare>); static_assert(compare(1) / 1_q_s), frequency, std::int64_t>>); -static_assert(is_same_v); -static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); static_assert((std::uint8_t(128) * m + std::uint8_t(128) * m).number() == std::uint8_t(128) + std::uint8_t(128)); static_assert((std::uint8_t(0) * m - std::uint8_t(1) * m).number() == std::uint8_t(0) - std::uint8_t(1)); static_assert(is_same_v); + decltype(std::uint8_t(0) % std::uint8_t(0))&&>); // different representation types static_assert(is_same_v>); @@ -595,14 +595,14 @@ static_assert(quantity(1) - 2.3 == quantity(1 - 2.3)); static_assert(1.2 + quantity(3) == quantity(1.2 + 3)); static_assert(1.2 - quantity(3) == quantity(1.2 - 3)); -static_assert(is_same_v); -static_assert(is_same_v); +static_assert(is_same_v); +static_assert(is_same_v); static_assert((quantity{std::uint8_t(128)} + quantity{std::uint8_t(128)}).number() == std::uint8_t(128) + std::uint8_t(128)); static_assert((quantity{std::uint8_t(0)} - quantity{std::uint8_t(1)}).number() == std::uint8_t(0) - std::uint8_t(1)); static_assert(is_same_v); + decltype(std::uint8_t(0) % std::uint8_t(0))&&>); static_assert(quantity{2} * (1 * m) == 2_q_m); static_assert(quantity{2} / (1 * m) == 2 / 1_q_m);